From ce37bd9c60a667e24ca2d8729d8ac1dea16a109a Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Sat, 18 Jul 2026 01:06:58 -0400 Subject: [PATCH] Fix taking damage and start fixing healing --- .../sheets-configs/adversary-settings.mjs | 4 +- module/data/action/baseAction.mjs | 4 +- module/data/chat-message/chatDamageData.mjs | 5 +- module/data/fields/action/damageField.mjs | 22 ++++---- module/dice/damageRoll.mjs | 1 + module/documents/actor.mjs | 55 +++++++++---------- .../dialogs/dice-roll/damageSelection.hbs | 4 +- 7 files changed, 45 insertions(+), 50 deletions(-) diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index c5f036ed..0bf18ee6 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -9,8 +9,8 @@ export default class DHAdversarySettings extends DHBaseActorSettings { classes: ['adversary-settings'], position: { width: 455, height: 'auto' }, actions: { - addExperience: DHAdversarySettings.#onAddExperience, - removeExperience: DHAdversarySettings.#onRemoveExperience, + addExperience: this.#onAddExperience, + removeExperience: this.#onRemoveExperience, addDamage: this.#onAddDamage, removeDamage: this.#onRemoveDamage } diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index f773ae32..8789c859 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -429,11 +429,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel } get hasDamage() { - return this.type !== 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length); + return this.type !== 'healing' && (Boolean(this.damage.main) || !foundry.utils.isEmpty(this.damage.resources)); } get hasHealing() { - return this.type === 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length); + return this.type === 'healing' && !foundry.utils.isEmpty(this.damage.resources); } get hasSave() { diff --git a/module/data/chat-message/chatDamageData.mjs b/module/data/chat-message/chatDamageData.mjs index c612729e..b7679ee1 100644 --- a/module/data/chat-message/chatDamageData.mjs +++ b/module/data/chat-message/chatDamageData.mjs @@ -28,10 +28,7 @@ export class ChatDamageData extends foundry.abstract.DataModel { } _prepareRolls() { - if (this.main) { - this.main = Roll.fromData(this.main); - } - + this.main &&= Roll.fromData(this.main); for (const key of Object.keys(this.resources)) { this.resources[key] = Roll.fromData(this.resources[key]); } diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 4edc2533..4fe38aca 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -80,7 +80,7 @@ export default class DamageField extends fields.SchemaField { const targetDamage = []; const damagePromises = []; - for (let target of targets) { + for (const target of targets) { const actor = foundry.utils.fromUuidSync(target.actorId); if (!actor) continue; if (!config.hasHealing && config.onSave && target.saved?.success === true) { @@ -102,14 +102,12 @@ export default class DamageField extends fields.SchemaField { actor.takeHealing(config.damage.types).then(updates => targetDamage.push({ token, updates })) ); else { - const configDamage = foundry.utils.deepClone(config.damage.types); - const hpDamageMultiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1; - const hpDamageTakenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier; - if (configDamage.hitPoints) { - configDamage.hitPoints = configDamage.hitPoints.toJSON(); - configDamage.hitPoints.total = Math.ceil( - configDamage.hitPoints.total * hpDamageMultiplier * hpDamageTakenMultiplier - ); + 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(configDamage.main.total * multiplier * takenMultiplier); } damagePromises.push( @@ -179,12 +177,12 @@ export default class DamageField extends fields.SchemaField { static formatFormulas(damageData, data) { const formulas = damageData.map(x => ({ formula: DamageField.getFormulaValue.call(this, x, data).getFormula(this.actor), - damageTypes: x.applyTo === 'hitPoints' && !x.type.size ? new Set(['physical']) : x.type, + damageTypes: x.type ?? new Set(), applyTo: x.applyTo })); const formattedFormulas = []; - formulas.forEach(formula => { + for (const formula of formulas) { if (isNaN(formula.formula)) formula.formula = Roll.replaceFormulaData(formula.formula, this.getRollData(data)); const same = formattedFormulas.find( @@ -192,7 +190,7 @@ export default class DamageField extends fields.SchemaField { ); if (same) same.formula += ` + ${formula.formula}`; else formattedFormulas.push(formula); - }); + } return formattedFormulas; } diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 64077e1f..b5e8b29e 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -145,6 +145,7 @@ export default class DamageRoll extends DHRoll { } constructFormula(formulaData, config, isDamage) { + if (!formulaData) return null; this.options.isCritical = config.isCritical; const isHitpointPart = formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id; diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index d7733dd5..ec2d8348 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -656,26 +656,30 @@ export default class DhpActor extends Actor { return; } - const updates = []; - - Object.entries(damages).forEach(([key, damage]) => { - if (key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) - damage.total = this.calculateDamage(damage.total, damage.damageTypes); - const update = updates.find(u => u.key === key); - if (update) { - update.value += damage.total; - update.damageTypes.add(...new Set(damage.damageTypes)); - } else updates.push({ value: damage.total, key, damageTypes: new Set(damage.damageTypes) }); - }); + if (damages.main) { + damages.main.total = this.calculateDamage(damages.main.total, damages.main.damageTypes); + } if (Hooks.call(`${CONFIG.DH.id}.postCalculateDamage`, this, damages) === false) return null; - if (!updates.length) return; + // Convert deducted resources and damage to a record of updates, merging damage to hp with hp marked + const updates = Object.entries(damages.resources).map(([key, damage]) => ({ key, value: damage.total })); + if (damages.main) { + const existing = updates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); + const value = this.convertDamageToThreshold(damages.main.total); + const damageTypes = new Set(damages.main.options.damageTypes); + if (existing) { + existing.value += value; + existing.damageTypes = damageTypes; + } else { + updates.push({ value, damageTypes, key: CONFIG.DH.GENERAL.healingTypes.hitPoints.id }); + } + } + if (!updates.some(u => u.value)) return; // early return if nothing to do const hpDamage = updates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); if (hpDamage?.value) { - hpDamage.value = this.convertDamageToThreshold(hpDamage.value); - if (this.type === 'character' && !isDirect && this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes)) { + if (this.type === 'character' && !isDirect && this.#canReduceDamage(hpDamage.total, hpDamage.damageTypes)) { const armorSlotResult = await this.owner.query( 'armorSlot', { @@ -689,7 +693,7 @@ export default class DhpActor extends Actor { ); if (armorSlotResult) { const { modifiedDamage, armorChanges, stressSpent } = armorSlotResult; - updates.find(u => u.key === 'hitPoints').value = modifiedDamage; + hpDamage.value = modifiedDamage; for (const armorChange of armorChanges) { updates.push({ value: armorChange.amount, key: 'armor', uuid: armorChange.uuid }); } @@ -699,18 +703,13 @@ export default class DhpActor extends Actor { else updates.push({ value: stressSpent, key: 'stress' }); } } - } - if (this.type === 'adversary') { + } else 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; + if (this.system.rules.damageReduction.thresholdImmunities[getDamageKey(hpDamage.value)]) { + hpDamage.value = Math.max(0, hpDamage.value - 1); } } } @@ -727,12 +726,10 @@ export default class DhpActor extends Actor { for (var result of results) resourceMap.addResources(result.updates); resourceMap.updateResources(); } - - updates.forEach( - u => - (u.value = - u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false ? u.value * -1 : u.value) - ); + + for (const u of updates) { + u.value = u.key === 'fear' || this.system?.resources?.[u.key]?.isReversed === false ? u.value * -1 : u.value; + } await this.modifyResource(updates); diff --git a/templates/dialogs/dice-roll/damageSelection.hbs b/templates/dialogs/dice-roll/damageSelection.hbs index cc12e26f..b12b78cb 100644 --- a/templates/dialogs/dice-roll/damageSelection.hbs +++ b/templates/dialogs/dice-roll/damageSelection.hbs @@ -16,7 +16,9 @@ {{/if}} - {{> formula @root.damageFormula path="damageFormula"}} + {{#if @root.damageFormula}} + {{> formula @root.damageFormula path="damageFormula"}} + {{/if}} {{#each @root.resourceFormulas}} {{> formula path=(concat "resourceFormulas." @key)}}