diff --git a/scss/components/actor/_checks.scss b/scss/components/actor/_checks.scss index 704a428e..51f6fe52 100644 --- a/scss/components/actor/_checks.scss +++ b/scss/components/actor/_checks.scss @@ -7,7 +7,7 @@ .ds4-checks { column-gap: 2em; display: grid; - grid-template-columns: repeat(auto-fit, minmax(11em, 1fr)); + grid-template-columns: 1fr 1fr 1fr; row-gap: 0.25em; white-space: nowrap; } diff --git a/src/documents/actor/actor-data-properties-base.ts b/src/documents/actor/actor-data-properties-base.ts index 70abd07c..b39dff51 100644 --- a/src/documents/actor/actor-data-properties-base.ts +++ b/src/documents/actor/actor-data-properties-base.ts @@ -15,6 +15,7 @@ export interface DS4ActorDataPropertiesDataBase { combatValues: DS4ActorDataPropertiesDataCombatValues; rolling: DS4ActorDataPropertiesDataRolling; checks: DS4ActorDataPropertiesDataChecks; + armorValueSpellMalus: number; } type DS4ActorDataPropertiesDataAttributes = { diff --git a/src/documents/actor/actor.ts b/src/documents/actor/actor.ts index 0b1be492..08af79f1 100644 --- a/src/documents/actor/actor.ts +++ b/src/documents/actor/actor.ts @@ -32,7 +32,7 @@ export class DS4Actor extends Actor { this.data.reset(); this.prepareBaseData(); this.prepareEmbeddedDocuments(); - this.applyActiveEffectsToItems(); + this.prepareIntermediateData(); this.applyActiveEffectsToBaseData(); this.prepareDerivedData(); this.applyActiveEffectsToDerivedData(); @@ -58,7 +58,20 @@ export class DS4Actor extends Actor { ); } - private get actorEffects() { + override prepareEmbeddedDocuments() { + super.prepareEmbeddedDocuments(); + this.applyActiveEffectsToItems(); + } + + /** + * Apply transformations to the Actor data after embedded documents have been prepared, but before effects have been + * applied to the Actor. + */ + prepareIntermediateData() { + this.data.data.armorValueSpellMalus = this.armorValueSpellMalusOfEquippedItems; + } + + protected get actorEffects() { return this.effects.filter((effect) => !effect.data.flags.ds4?.itemEffectConfig?.applyToItems); } @@ -93,7 +106,7 @@ export class DS4Actor extends Actor { }); } - private static replaceFormulaData(formula: string, data: object): string | undefined { + protected static replaceFormulaData(formula: string, data: object): string | undefined { const dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi); try { return formula.replace(dataRgx, (_, term) => { @@ -163,6 +176,7 @@ export class DS4Actor extends Actor { * Apply transformations to the Actor data after effects have been applied to the base data. */ override prepareDerivedData(): void { + this.data.data.armorValueSpellMalus = Math.max(this.data.data.armorValueSpellMalus, 0); this.prepareCombatValues(); this.prepareChecks(); } @@ -232,20 +246,18 @@ export class DS4Actor extends Actor { */ protected prepareCombatValues(): void { const data = this.data.data; - const armorValueOfEquippedItems = this.calculateArmorValueOfEquippedItems(); - const spellMalusOfEquippedItems = this.calculateSpellMaluesOfEquippedItems(); data.combatValues.hitPoints.base = data.attributes.body.total + data.traits.constitution.total + 10; data.combatValues.defense.base = - data.attributes.body.total + data.traits.constitution.total + armorValueOfEquippedItems; + data.attributes.body.total + data.traits.constitution.total + this.armorValueOfEquippedItems; data.combatValues.initiative.base = data.attributes.mobility.total + data.traits.agility.total; data.combatValues.movement.base = data.attributes.mobility.total / 2 + 1; data.combatValues.meleeAttack.base = data.attributes.body.total + data.traits.strength.total; data.combatValues.rangedAttack.base = data.attributes.mobility.total + data.traits.dexterity.total; data.combatValues.spellcasting.base = - data.attributes.mind.total + data.traits.aura.total - spellMalusOfEquippedItems; + data.attributes.mind.total + data.traits.aura.total - data.armorValueSpellMalus; data.combatValues.targetedSpellcasting.base = - data.attributes.mind.total + data.traits.dexterity.total - spellMalusOfEquippedItems; + data.attributes.mind.total + data.traits.dexterity.total - data.armorValueSpellMalus; Object.values(data.combatValues).forEach( (combatValue: ModifiableDataBaseTotal) => (combatValue.total = combatValue.base + combatValue.mod), @@ -253,19 +265,17 @@ export class DS4Actor extends Actor { } /** - * Calculates the total armor value of the equipped items. + * The total armor value of the equipped items. */ - protected calculateArmorValueOfEquippedItems(): number { - return this.getEquippedItemsWithArmor() - .map((item) => item.data.data.armorValue) - .reduce((a, b) => a + b, 0); + protected get armorValueOfEquippedItems(): number { + return this.equippedItemsWithArmor.map((item) => item.data.data.armorValue).reduce((a, b) => a + b, 0); } /** - * Calculates the spell malus from equipped items. + * The armor value spell malus from equipped items. */ - protected calculateSpellMaluesOfEquippedItems(): number { - return this.getEquippedItemsWithArmor() + protected get armorValueSpellMalusOfEquippedItems(): number { + return this.equippedItemsWithArmor .filter( (item) => !(item.data.type === "armor" && ["cloth", "natural"].includes(item.data.data.armorMaterialType)), @@ -274,7 +284,7 @@ export class DS4Actor extends Actor { .reduce((a, b) => a + b, 0); } - private getEquippedItemsWithArmor() { + protected get equippedItemsWithArmor() { return this.items .filter( (item): item is DS4Item & { data: DS4ArmorDataProperties | DS4ShieldDataProperties } =>