From 82ce2f3052014ab4b3c872a35e0e40a8fe6877d2 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 25 Jul 2026 03:58:51 +0200 Subject: [PATCH] [Fix] Improve HP Damage Multiplier Active Effect (#2110) --- module/data/fields/action/damageField.mjs | 3 +-- module/dice/damageRoll.mjs | 20 +++++++++++++++- module/dice/dhRoll.mjs | 29 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 05d9f664..8e0cc9d4 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -105,9 +105,8 @@ export default class DamageField extends fields.SchemaField { const configDamage = config.damage.clone(); configDamage.main &&= configDamage.main.toJSON(); if (configDamage.main) { - const multiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1; const takenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier; - configDamage.main.total = Math.ceil(config.damage.main.total * multiplier * takenMultiplier); + configDamage.main.total = Math.ceil(configDamage.main.total * takenMultiplier); } damagePromises.push( diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 722b05f6..de63ecf3 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -131,7 +131,9 @@ export default class DamageRoll extends DHRoll { getActionChangeKeys() { const type = this.options.messageType ?? (this.options.hasHealing ? 'healing' : 'damage'); - const changeKeys = []; + const changeKeys = [ + 'system.rules.attack.damage.hpDamageMultiplier' + ]; for (const damageType of this.options.damageFormula?.damageTypes?.values?.() ?? []) { changeKeys.push(`system.bonuses.${type}.${damageType}`); @@ -210,6 +212,22 @@ export default class DamageRoll extends DHRoll { formulaData.roll.terms.push(...this.formatModifier(total)); } } + + const damageTakenMultiplier = this.getTotalBonus('system.rules.attack.damage.hpDamageMultiplier'); + if (damageTakenMultiplier && damageTakenMultiplier !== 1) { + // The fully built up roll needs to be set inside of a paranthetical term, so we build the dice anew with all the pushed in terms. + // We clone it to avoid infinite recursion. + formulaData.roll = Roll.fromTerms(formulaData.roll.terms); + + formulaData.roll.terms = [ + new foundry.dice.terms.ParentheticalTerm({ + roll: formulaData.roll.clone(), + term: formulaData.formula + }), + new foundry.dice.terms.OperatorTerm({ operator: '*' }), + new foundry.dice.terms.NumericTerm({ number: damageTakenMultiplier }) + ]; + } } formulaData.roll._formula = this.constructor.getFormula(formulaData.roll.terms); diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 68185984..0e1401f3 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -248,6 +248,35 @@ export default class DHRoll extends BaseRoll { }); } + /** + * Sums the values of all instances of ActiveEffect.change values from the toggleable bonusEffects of the roll + * that match a given change.key partial path. Only for use on ActiveEffects.change with strictly numerical values. + * @param {string} path The full or partial effect.change key + * @returns {number} + */ + getTotalBonus(path) { + return Object.values(this.options.bonusEffects).reduce((acc, effect) => { + if (!effect.selected) return acc; + return acc + effect.changes.reduce((acc, change) => { + if (!change.key.includes(path)) return acc; + const changeValue = game.system.api.documents.DhActiveEffect.getChangeValue( + this.data, + change, + effect.origEffect + ); + + return Number.isNumeric(changeValue) ? acc + changeValue : acc; + }, 0); + }, 0); + } + + /** + * Grabs all instances of ActiveEffect.change values from the toggleable bonusEffects of the roll + * that match a given change.key partial path. + * @param {string} path The full or partial effect.change key + * @param {string} label The label to give the modifiers + * @returns {[{ label: string, value: any} ]} + */ getBonus(path, label) { const modifiers = []; for (const effect of Object.values(this.options.bonusEffects)) {