From e8c541c0020cbbaeeb3753d16f7db01278d60f45 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:00:40 +0100 Subject: [PATCH] Added damage reduction rules (#1491) --- module/data/actor/adversary.mjs | 22 ++-------- module/data/actor/base.mjs | 30 ++++++++++--- module/data/actor/character.mjs | 77 +++++++++++++++------------------ module/documents/actor.mjs | 15 ++++++- 4 files changed, 77 insertions(+), 67 deletions(-) diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 32f5c979..16e7e37a 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -1,6 +1,6 @@ import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs'; import { ActionField } from '../fields/actionField.mjs'; -import BaseDataActor from './base.mjs'; +import BaseDataActor, { commonActorRules } from './base.mjs'; import { resourceField, bonusField } from '../fields/actorField.mjs'; export default class DhpAdversary extends BaseDataActor { @@ -56,25 +56,11 @@ export default class DhpAdversary extends BaseDataActor { }) }), resources: new fields.SchemaField({ - hitPoints: resourceField( - 0, - 0, - 'DAGGERHEART.GENERAL.HitPoints.plural', - true - ), - stress: resourceField( - 0, - 0, - 'DAGGERHEART.GENERAL.stress', - true - ) + hitPoints: resourceField(0, 0, 'DAGGERHEART.GENERAL.HitPoints.plural', true), + stress: resourceField(0, 0, 'DAGGERHEART.GENERAL.stress', true) }), rules: new fields.SchemaField({ - conditionImmunities: new fields.SchemaField({ - hidden: new fields.BooleanField({ initial: false }), - restrained: new fields.BooleanField({ initial: false }), - vulnerable: new fields.BooleanField({ initial: false }) - }) + ...commonActorRules() }), attack: new ActionField({ initial: { diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 29b0af28..b90361e2 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -2,21 +2,23 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs import DHItem from '../../documents/item.mjs'; import { getScrollTextData } from '../../helpers/utils.mjs'; +const fields = foundry.data.fields; + const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) => - new foundry.data.fields.SchemaField({ - resistance: new foundry.data.fields.BooleanField({ + new fields.SchemaField({ + resistance: new fields.BooleanField({ initial: false, label: `${resistanceLabel}.label`, hint: `${resistanceLabel}.hint`, isAttributeChoice: true }), - immunity: new foundry.data.fields.BooleanField({ + immunity: new fields.BooleanField({ initial: false, label: `${immunityLabel}.label`, hint: `${immunityLabel}.hint`, isAttributeChoice: true }), - reduction: new foundry.data.fields.NumberField({ + reduction: new fields.NumberField({ integer: true, initial: 0, label: `${reductionLabel}.label`, @@ -24,6 +26,25 @@ const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) => }) }); +/* Common rules applying to Characters and Adversaries */ +export const commonActorRules = (extendedData = { damageReduction: {} }) => ({ + conditionImmunities: new fields.SchemaField({ + hidden: new fields.BooleanField({ initial: false }), + restrained: new fields.BooleanField({ initial: false }), + vulnerable: new fields.BooleanField({ initial: false }) + }), + damageReduction: new fields.SchemaField({ + thresholdImmunities: new fields.SchemaField({ + minor: new fields.BooleanField({ initial: false }) + }), + reduceSeverity: new fields.SchemaField({ + magical: new fields.NumberField({ initial: 0, min: 0 }), + physical: new fields.NumberField({ initial: 0, min: 0 }) + }), + ...extendedData.damageReduction + }) +}); + /** * Describes metadata about the actor data model type * @typedef {Object} ActorDataModelMetadata @@ -54,7 +75,6 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { /** @inheritDoc */ static defineSchema() { - const fields = foundry.data.fields; const schema = {}; if (this.metadata.hasAttribution) { diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 5bce5c55..eba46f10 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -1,7 +1,7 @@ import { burden } from '../../config/generalConfig.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import DhLevelData from '../levelData.mjs'; -import BaseDataActor from './base.mjs'; +import BaseDataActor, { commonActorRules } from './base.mjs'; import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs'; import { ActionField } from '../fields/actionField.mjs'; import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs'; @@ -217,44 +217,41 @@ export default class DhCharacter extends BaseDataActor { }), companion: new ForeignDocumentUUIDField({ type: 'Actor', nullable: true, initial: null }), rules: new fields.SchemaField({ - damageReduction: new fields.SchemaField({ - maxArmorMarked: new fields.SchemaField({ - value: new fields.NumberField({ - required: true, + ...commonActorRules({ + damageReduction: { + magical: new fields.BooleanField({ initial: false }), + physical: new fields.BooleanField({ initial: false }), + maxArmorMarked: new fields.SchemaField({ + value: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus' + }), + stressExtra: new fields.NumberField({ + required: true, + integer: true, + initial: 0, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.hint' + }) + }), + stressDamageReduction: new fields.SchemaField({ + severe: stressDamageReductionRule( + 'DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe' + ), + major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'), + minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor'), + any: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.any') + }), + increasePerArmorMark: new fields.NumberField({ integer: true, initial: 1, - label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedBonus' + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint' }), - stressExtra: new fields.NumberField({ - required: true, - integer: true, - initial: 0, - label: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.label', - hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.maxArmorMarkedStress.hint' - }) - }), - stressDamageReduction: new fields.SchemaField({ - severe: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.severe'), - major: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.major'), - minor: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.minor'), - any: stressDamageReductionRule('DAGGERHEART.GENERAL.Rules.damageReduction.stress.any') - }), - increasePerArmorMark: new fields.NumberField({ - integer: true, - initial: 1, - label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label', - hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint' - }), - magical: new fields.BooleanField({ initial: false }), - physical: new fields.BooleanField({ initial: false }), - thresholdImmunities: new fields.SchemaField({ - minor: new fields.BooleanField({ initial: false }) - }), - reduceSeverity: new fields.SchemaField({ - magical: new fields.NumberField({ initial: 0, min: 0 }), - physical: new fields.NumberField({ initial: 0, min: 0 }) - }), - disabledArmor: new fields.BooleanField({ intial: false }) + disabledArmor: new fields.BooleanField({ intial: false }) + } }), attack: new fields.SchemaField({ damage: new fields.SchemaField({ @@ -283,11 +280,6 @@ export default class DhCharacter extends BaseDataActor { }) }) }), - conditionImmunities: new fields.SchemaField({ - hidden: new fields.BooleanField({ initial: false }), - restrained: new fields.BooleanField({ initial: false }), - vulnerable: new fields.BooleanField({ initial: false }) - }), runeWard: new fields.BooleanField({ initial: false }), burden: new fields.SchemaField({ ignore: new fields.BooleanField() @@ -453,8 +445,7 @@ export default class DhCharacter extends BaseDataActor { if ( 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.specialization && subclassState >= 2) || (item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3) ) { return true; diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 6080eb87..f6666a5e 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,7 +1,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; -import { createScrollText, damageKeyToNumber } from '../helpers/utils.mjs'; +import { createScrollText, damageKeyToNumber, getDamageKey } from '../helpers/utils.mjs'; import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs'; import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; @@ -631,6 +631,19 @@ export default class DhpActor extends Actor { } } } + if (this.type === 'adversary') { + const reducedSeverity = hpDamage.damageTypes.reduce((value, curr) => { + return Math.max(this.system.rules.damageReduction.reduceSeverity[curr], value); + }, 0); + hpDamage.value = Math.max(hpDamage.value - reducedSeverity, 0); + + if ( + hpDamage.value && + this.system.rules.damageReduction.thresholdImmunities[getDamageKey(hpDamage.value)] + ) { + hpDamage.value -= 1; + } + } } updates.forEach(