mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 19:51:08 +01:00
Merged with development
This commit is contained in:
commit
bd76e22e8d
1096 changed files with 11080 additions and 5102 deletions
|
|
@ -163,7 +163,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
const hasRoll = this.getUseHasRoll(byPass);
|
||||
return {
|
||||
event,
|
||||
title: `${this.item.name}: ${this.name}`,
|
||||
title: `${this.item.name}: ${game.i18n.localize(this.name)}`,
|
||||
source: {
|
||||
item: this.item._id,
|
||||
action: this._id,
|
||||
|
|
@ -209,15 +209,15 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
}
|
||||
|
||||
async consume(config, successCost = false) {
|
||||
const actor= this.actor.system.partner ?? this.actor,
|
||||
const actor = this.actor.system.partner ?? this.actor,
|
||||
usefulResources = {
|
||||
...foundry.utils.deepClone(actor.system.resources),
|
||||
fear: {
|
||||
value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||
max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear,
|
||||
reversed: false
|
||||
}
|
||||
};
|
||||
...foundry.utils.deepClone(actor.system.resources),
|
||||
fear: {
|
||||
value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||
max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear,
|
||||
reversed: false
|
||||
}
|
||||
};
|
||||
|
||||
for (var cost of config.costs) {
|
||||
if (cost.keyIsID) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: 'TYPES.Actor.adversary',
|
||||
type: 'adversary',
|
||||
settingSheet: DHAdversarySettings
|
||||
settingSheet: DHAdversarySettings,
|
||||
hasAttribution: true
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -26,7 +27,7 @@ export default class DhpAdversary extends BaseDataActor {
|
|||
}),
|
||||
type: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.ACTOR.adversaryTypes,
|
||||
choices: CONFIG.DH.ACTOR.allAdversaryTypes,
|
||||
initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id
|
||||
}),
|
||||
motivesAndTactics: new fields.StringField(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs';
|
||||
import { createScrollText, getScrollTextData } from '../../helpers/utils.mjs';
|
||||
import { getScrollTextData } from '../../helpers/utils.mjs';
|
||||
|
||||
const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) =>
|
||||
new foundry.data.fields.SchemaField({
|
||||
|
|
@ -39,7 +39,8 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
type: 'base',
|
||||
isNPC: true,
|
||||
settingSheet: null,
|
||||
hasResistances: true
|
||||
hasResistances: true,
|
||||
hasAttribution: false
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +54,13 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
const fields = foundry.data.fields;
|
||||
const schema = {};
|
||||
|
||||
if (this.metadata.hasAttribution) {
|
||||
schema.attribution = new fields.SchemaField({
|
||||
source: new fields.StringField(),
|
||||
page: new fields.NumberField(),
|
||||
artist: new fields.StringField()
|
||||
});
|
||||
}
|
||||
if (this.metadata.isNPC) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
if (this.metadata.hasResistances)
|
||||
schema.resistance = new fields.SchemaField({
|
||||
|
|
@ -78,6 +86,13 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
*/
|
||||
static DEFAULT_ICON = null;
|
||||
|
||||
get attributionLabel() {
|
||||
if (!this.attribution) return;
|
||||
|
||||
const { source, page } = this.attribution;
|
||||
return [source, page ? `pg ${page}.` : null].filter(x => x).join('. ');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
|
@ -133,6 +148,6 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
|||
_onUpdate(changes, options, userId) {
|
||||
super._onUpdate(changes, options, userId);
|
||||
|
||||
createScrollText(this.parent, options.scrollingTextData);
|
||||
if (options.scrollingTextData) this.parent.queueScrollText(options.scrollingTextData);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}),
|
||||
attack: new ActionField({
|
||||
initial: {
|
||||
name: 'Unarmed Attack',
|
||||
name: 'DAGGERHEART.GENERAL.unarmedAttack',
|
||||
img: 'icons/skills/melee/unarmed-punch-fist-yellow-red.webp',
|
||||
_id: foundry.utils.randomID(),
|
||||
systemPath: 'attack',
|
||||
|
|
@ -444,16 +444,12 @@ export default class DhCharacter extends BaseDataActor {
|
|||
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
|
||||
if (this.class.subclass) {
|
||||
const subclassState = this.class.subclass.system.featureState;
|
||||
const subclass =
|
||||
item.system.identifier === 'multiclass' ? this.multiclass.subclass : this.class.subclass;
|
||||
const featureType = subclass
|
||||
? (subclass.system.features.find(x => x.item?.uuid === item.uuid)?.type ?? null)
|
||||
: null;
|
||||
|
||||
if (
|
||||
featureType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
|
||||
(featureType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation ||
|
||||
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization &&
|
||||
subclassState >= 2) ||
|
||||
(item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
|
||||
) {
|
||||
subclassFeatures.push(item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ export default class DhEnvironment extends BaseDataActor {
|
|||
label: 'TYPES.Actor.environment',
|
||||
type: 'environment',
|
||||
settingSheet: DHEnvironmentSettings,
|
||||
hasResistances: false
|
||||
hasResistances: false,
|
||||
hasAttribution: true
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default class CostField extends fields.ArrayField {
|
|||
config.costs = CostField.calcCosts.call(this, costs);
|
||||
const hasCost = CostField.hasCost.call(this, config.costs);
|
||||
if (config.isFastForward && !hasCost)
|
||||
return ui.notifications.warn("You don't have the resources to use that action.");
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.insufficientResources'));
|
||||
return hasCost;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,14 +23,22 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
multiplier: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.multiplierTypes,
|
||||
initial: 'prof',
|
||||
label: 'Multiplier'
|
||||
label: 'DAGGERHEART.ACTIONS.Config.damage.multiplier'
|
||||
}),
|
||||
flatMultiplier: new fields.NumberField({ nullable: true, initial: 1, label: 'Flat Multiplier' }),
|
||||
dice: new fields.StringField({ choices: CONFIG.DH.GENERAL.diceTypes, initial: 'd6', label: 'Dice' }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'Bonus' }),
|
||||
flatMultiplier: new fields.NumberField({
|
||||
nullable: true,
|
||||
initial: 1,
|
||||
label: 'DAGGERHEART.ACTIONS.Config.damage.flatMultiplier'
|
||||
}),
|
||||
dice: new fields.StringField({
|
||||
choices: CONFIG.DH.GENERAL.diceTypes,
|
||||
initial: 'd6',
|
||||
label: 'DAGGERHEART.GENERAL.Dice.single'
|
||||
}),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, label: 'DAGGERHEART.GENERAL.bonus' }),
|
||||
custom: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({ label: 'Custom Formula' }),
|
||||
formula: new FormulaField({ label: 'Formula', initial: '' })
|
||||
enabled: new fields.BooleanField({ label: 'DAGGERHEART.ACTIONS.Config.general.customFormula' }),
|
||||
formula: new FormulaField({ label: 'DAGGERHEART.ACTIONS.Config.general.formula', initial: '' })
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ export default class UsesField extends fields.SchemaField {
|
|||
if (uses && !uses.value) uses.value = 0;
|
||||
config.uses = uses;
|
||||
const hasUses = UsesField.hasUses.call(this, config.uses);
|
||||
if (config.isFastForward && !hasUses) return ui.notifications.warn("That action doesn't have remaining uses.");
|
||||
if (config.isFastForward && !hasUses)
|
||||
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.actionNoUsesRemaining'));
|
||||
return hasUses;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
hasResource: false,
|
||||
isQuantifiable: false,
|
||||
isInventoryItem: false,
|
||||
hasActions: false
|
||||
hasActions: false,
|
||||
hasAttribution: true
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +38,13 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
|
||||
/** @inheritDoc */
|
||||
static defineSchema() {
|
||||
const schema = {};
|
||||
const schema = {
|
||||
attribution: new fields.SchemaField({
|
||||
source: new fields.StringField(),
|
||||
page: new fields.NumberField(),
|
||||
artist: new fields.StringField()
|
||||
})
|
||||
};
|
||||
|
||||
if (this.metadata.hasDescription) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
|
||||
|
|
@ -110,6 +117,13 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
return [];
|
||||
}
|
||||
|
||||
get attributionLabel() {
|
||||
if (!this.attribution) return;
|
||||
|
||||
const { source, page } = this.attribution;
|
||||
return [source, page ? `pg ${page}.` : null].filter(x => x).join('. ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a data object used to evaluate any dice rolls associated with this Item Type
|
||||
* @param {object} [options] - Options which modify the getRollData method.
|
||||
|
|
@ -144,50 +158,30 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
}
|
||||
|
||||
if (this.actor && this.actor.type === 'character' && this.features) {
|
||||
const featureUpdates = {};
|
||||
const features = [];
|
||||
for (let f of this.features) {
|
||||
const fBase = f.item ?? f;
|
||||
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
||||
const createData = foundry.utils.mergeObject(
|
||||
feature.toObject(),
|
||||
{
|
||||
system: {
|
||||
originItemType: this.parent.type,
|
||||
originId: data._id,
|
||||
identifier: this.isMulticlass ? 'multiclass' : null
|
||||
}
|
||||
},
|
||||
{ inplace: false }
|
||||
const multiclass = this.isMulticlass ? 'multiclass' : null;
|
||||
features.push(
|
||||
foundry.utils.mergeObject(
|
||||
feature.toObject(),
|
||||
{
|
||||
_stats: { compendiumSource: fBase.uuid },
|
||||
system: {
|
||||
originItemType: this.parent.type,
|
||||
identifier: multiclass ?? (f.item ? f.type : null)
|
||||
}
|
||||
},
|
||||
{ inplace: false }
|
||||
)
|
||||
);
|
||||
const [doc] = await this.actor.createEmbeddedDocuments('Item', [createData]);
|
||||
|
||||
if (!featureUpdates.features)
|
||||
featureUpdates.features = this.features.map(x => (x.item ? { ...x, item: x.item.uuid } : x.uuid));
|
||||
|
||||
if (f.item) {
|
||||
const existingFeature = featureUpdates.features.find(x => x.item === f.item.uuid);
|
||||
existingFeature.item = doc.uuid;
|
||||
} else {
|
||||
const replaceIndex = featureUpdates.features.findIndex(x => x === f.uuid);
|
||||
featureUpdates.features.splice(replaceIndex, 1, doc.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
await this.updateSource(featureUpdates);
|
||||
await this.actor.createEmbeddedDocuments('Item', features);
|
||||
}
|
||||
}
|
||||
|
||||
async _preDelete() {
|
||||
if (!this.actor || this.actor.type !== 'character') return;
|
||||
|
||||
const items = this.actor.items.filter(item => item.system.originId === this.parent.id);
|
||||
if (items.length > 0)
|
||||
await this.actor.deleteEmbeddedDocuments(
|
||||
'Item',
|
||||
items.map(x => x.id)
|
||||
);
|
||||
}
|
||||
|
||||
async _preUpdate(changed, options, userId) {
|
||||
const allowed = await super._preUpdate(changed, options, userId);
|
||||
if (allowed === false) return false;
|
||||
|
|
@ -207,6 +201,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
super._onUpdate(changed, options, userId);
|
||||
|
||||
updateLinkedItemApps(options, this.parent.sheet);
|
||||
createScrollText(this.parent?.parent, options.scrollingTextData);
|
||||
|
||||
if (this.parent?.parent && options.scrollingTextData)
|
||||
this.parent.parent.queueScrollText(options.scrollingTextData);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import BaseDataItem from './base.mjs';
|
||||
import { ActionField, ActionsField } from '../fields/actionField.mjs';
|
||||
|
||||
export default class DHFeature extends BaseDataItem {
|
||||
/** @inheritDoc */
|
||||
|
|
@ -30,24 +29,7 @@ export default class DHFeature extends BaseDataItem {
|
|||
nullable: true,
|
||||
initial: null
|
||||
}),
|
||||
originId: new fields.StringField({ nullable: true, initial: null }),
|
||||
identifier: new fields.StringField()
|
||||
};
|
||||
}
|
||||
|
||||
get spellcastingModifier() {
|
||||
let traitValue = 0;
|
||||
if (this.actor && this.originId && ['class', 'subclass'].includes(this.originItemType)) {
|
||||
if (this.originItemType === 'subclass') {
|
||||
traitValue =
|
||||
this.actor.system.traits[this.actor.items.get(this.originId).system.spellcastingTrait]?.value ?? 0;
|
||||
} else {
|
||||
const { value: multiclass, subclass } = this.actor.system.multiclass;
|
||||
const selectedSubclass = multiclass?.id === this.originId ? subclass : this.actor.system.class.subclass;
|
||||
traitValue = this.actor.system.traits[selectedSubclass.system.spellcastingTrait]?.value ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
return traitValue;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,8 +199,8 @@ export default class DHWeapon extends AttachableItem {
|
|||
];
|
||||
|
||||
for (const { value, type } of attack.damage.parts) {
|
||||
const parts = [value.dice];
|
||||
if (value.bonus) parts.push(value.bonus.signedString());
|
||||
const parts = value.custom.enabled ? [game.i18n.localize('DAGGERHEART.GENERAL.custom')] : [value.dice];
|
||||
if (!value.custom.enabled && value.bonus) parts.push(value.bonus.signedString());
|
||||
|
||||
if (type.size > 0) {
|
||||
const typeTags = Array.from(type)
|
||||
|
|
|
|||
|
|
@ -89,6 +89,11 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.expandRollMessageTarget.label'
|
||||
})
|
||||
}),
|
||||
hideAttribution: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.hideAttribution.label'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,13 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
}),
|
||||
description: new fields.HTMLField()
|
||||
})
|
||||
),
|
||||
adversaryTypes: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
id: new fields.StringField({ required: true }),
|
||||
label: new fields.StringField({ required: true, label: 'DAGGERHEART.GENERAL.label' }),
|
||||
description: new fields.StringField()
|
||||
})
|
||||
)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue