From 2d6c7b66ea7d2f195aef4fb987d8550b48f3ec1c Mon Sep 17 00:00:00 2001 From: phBalance Date: Thu, 17 Oct 2024 20:27:51 -0600 Subject: [PATCH 1/8] refactor(form data): correct dataset property names --- module/item/item-attack-application.mjs | 2 +- module/item/item-attack.mjs | 45 ++++++++--------- .../attack/item-mindscan-target-card.hbs | 12 ++--- templates/chat/item-damage-card.hbs | 50 +++++++++---------- templates/chat/item-toHit-card.hbs | 13 ++--- templates/chat/item-toHitAoe-card.hbs | 2 +- 6 files changed, 59 insertions(+), 65 deletions(-) diff --git a/module/item/item-attack-application.mjs b/module/item/item-attack-application.mjs index 9154de87..ef9705e0 100644 --- a/module/item/item-attack-application.mjs +++ b/module/item/item-attack-application.mjs @@ -254,7 +254,7 @@ export class ItemAttackFormApplication extends FormApplication { data.action = Attack.getActionInfo( data.item, data.targets, - data.formData, // use formdata to include player options from the form + data.formData, // use formData to include player options from the form ); // the title seems to be fixed when the form is initialized, // and doesn't change afterwards even if we come through here again diff --git a/module/item/item-attack.mjs b/module/item/item-attack.mjs index 81bcfc21..a7aacd3d 100644 --- a/module/item/item-attack.mjs +++ b/module/item/item-attack.mjs @@ -1201,8 +1201,8 @@ export async function _onRollAoeDamage(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kluge to fix. const options = { ...button.dataset }; - const item = fromUuidSync(options.itemid); - return AttackToHit(item, JSON.parse(options.formdata)); + const item = fromUuidSync(options.itemId); + return AttackToHit(item, JSON.parse(options.formData)); } export async function _onRollKnockback(event) { @@ -1495,14 +1495,14 @@ export async function _onRollDamage(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kluge to fix. const toHitData = { ...button.dataset }; - const item = fromUuidSync(toHitData.itemid); + const item = fromUuidSync(toHitData.itemId); const actor = item?.actor; if (!actor) { return ui.notifications.error(`Attack details are no longer available.`); } - const action = JSON.parse(toHitData.actiondata); + const action = JSON.parse(toHitData.actionData); let effectiveItem = item; @@ -1703,7 +1703,7 @@ export async function _onRollMindScan(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kluge to fix. const toHitData = { ...button.dataset }; - const item = fromUuidSync(event.currentTarget.dataset.itemid); + const item = fromUuidSync(event.currentTarget.dataset.itemId); const template2 = `systems/${HEROSYS.module}/templates/attack/item-mindscan-target-card.hbs`; @@ -1757,7 +1757,7 @@ export async function _onRollMindScanEffectRoll(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kluge to fix. const toHitData = { ...button.dataset }; - const item = fromUuidSync(event.currentTarget.dataset.itemid); + const item = fromUuidSync(event.currentTarget.dataset.itemId); const actor = item?.actor; if (!actor) { @@ -1926,18 +1926,16 @@ export async function _onRollMindScanEffectRoll(event) { // Notice the chatListeners function in this file. export async function _onApplyDamage(event) { const button = event.currentTarget; - button.blur(); // The button remains highlighted for some reason; kluge to fix. - const toHitData = { ...button.dataset }; - const item = fromUuidSync(event.currentTarget.dataset.itemid); + button.blur(); // The button remains highlighted for some reason; kludge to fix. + const damageData = { ...button.dataset }; // Single target - if (toHitData.targetTokenId) { - return _onApplyDamageToSpecificToken(event, toHitData.targetTokenId); - } - - // All targets - if (toHitData.targetIds) { - const targetsArray = toHitData.targetIds.split(","); + if (damageData.targetTokenId) { + return _onApplyDamageToSpecificToken(damageData, damageData.targetTokenId); + } else if (damageData.targetIds) { + // All targets + const item = fromUuidSync(event.currentTarget.dataset.itemId); + const targetsArray = damageData.targetIds.split(","); // If AOE then sort by distance from center if (item.hasExplosionAdvantage()) { @@ -1954,7 +1952,7 @@ export async function _onApplyDamage(event) { for (const id of targetsArray) { console.log(game.scenes.current.tokens.get(id).name); - await _onApplyDamageToSpecificToken(event, id); + await _onApplyDamageToSpecificToken(damageData, id); } return; } @@ -1965,14 +1963,12 @@ export async function _onApplyDamage(event) { } for (const token of canvas.tokens.controlled) { - _onApplyDamageToSpecificToken(event, token.id); + _onApplyDamageToSpecificToken(damageData, token.id); } } -export async function _onApplyDamageToSpecificToken(event, tokenId) { - const button = event.currentTarget; - const damageData = { ...button.dataset }; - const item = fromUuidSync(damageData.itemid); +export async function _onApplyDamageToSpecificToken(damageData, tokenId) { + const item = fromUuidSync(damageData.itemId); const heroRoller = HeroRoller.fromJSON(damageData.roller); @@ -1990,7 +1986,7 @@ export async function _onApplyDamageToSpecificToken(event, tokenId) { if (!item) { // This typically happens when the attack id stored in the damage card no longer exists on the actor. // For example if the attack item was deleted or the HDC was uploaded again. - console.warn(damageData.itemid); + console.warn(damageData.itemId); return ui.notifications.error(`Attack details are no longer available.`); } @@ -3529,7 +3525,8 @@ function calculateRequiredEnd(item, effectiveStr) { endToUse = itemEndurance; - // TODO: May want to get rid of this so we can support HKA with 0 STR (weird but possible?) + // TODO: May want to get rid of this so we can support HKA with 0 STR (weird but possible?) or + // attacks such as TK or EB which have no STR component. if (item.system.usesStrength || item.system.usesTk) { const strPerEnd = item.actor.system.isHeroic && game.settings.get(HEROSYS.module, "StrEnd") === "five" ? 5 : 10; diff --git a/templates/attack/item-mindscan-target-card.hbs b/templates/attack/item-mindscan-target-card.hbs index b231ab7e..baaffac2 100644 --- a/templates/attack/item-mindscan-target-card.hbs +++ b/templates/attack/item-mindscan-target-card.hbs @@ -17,14 +17,14 @@
- -
- -
- -
- {{#each targetTokens as |target id|}} - + {{/each}} {{#if targetIds}} - + {{/if}}
diff --git a/templates/chat/item-toHit-card.hbs b/templates/chat/item-toHit-card.hbs index 0de48068..bf3f1dff 100644 --- a/templates/chat/item-toHit-card.hbs +++ b/templates/chat/item-toHit-card.hbs @@ -119,15 +119,13 @@ The Game Master is reviewing the target to confirm it is within the Mind Scan area and that your attack score exceeded the target's DMCV. - - From 05264c716e8dabcabe8e9fb5e4fcdcdf0bb44320 Mon Sep 17 00:00:00 2001 From: phBalance Date: Thu, 17 Oct 2024 20:39:17 -0600 Subject: [PATCH 2/8] refactor(data form): cleanup dataset properties --- module/item/item-attack.mjs | 8 ++++---- templates/chat/item-damage-card.hbs | 4 ++-- templates/chat/item-toHit-card.hbs | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/module/item/item-attack.mjs b/module/item/item-attack.mjs index a7aacd3d..2bdd778d 100644 --- a/module/item/item-attack.mjs +++ b/module/item/item-attack.mjs @@ -1587,7 +1587,7 @@ export async function _onRollDamage(event) { // Apply Damage button for specific targets let targetTokens = []; - for (const id of toHitData.targetids.split(",")) { + for (const id of toHitData.targetIds.split(",")) { let token = canvas.scene.tokens.get(id); if (token) { const entangleAE = token.actor?.temporaryEffects?.find((o) => o.flags?.XMLID === "ENTANGLE"); @@ -1639,7 +1639,7 @@ export async function _onRollDamage(event) { // If there is only 1 target then get rid of targetIds (which is used for Apply Damage ALL) if (targetTokens.length <= 1) { - delete toHitData.targetids; + delete toHitData.targetIds; } const cardData = { @@ -1671,7 +1671,7 @@ export async function _onRollDamage(event) { roller: damageRoller.toJSON(), // misc - targetIds: toHitData.targetids, + targetIds: toHitData.targetIds, targetEntangle: toHitData.targetEntangle, tags: tags, @@ -1895,7 +1895,7 @@ export async function _onRollMindScanEffectRoll(event) { roller: damageRoller.toJSON(), // misc - targetIds: toHitData.targetids, + targetIds: toHitData.targetIds, tags: tags, attackTags: getAttackTags(item), diff --git a/templates/chat/item-damage-card.hbs b/templates/chat/item-damage-card.hbs index 254c7649..89d14f8d 100644 --- a/templates/chat/item-damage-card.hbs +++ b/templates/chat/item-damage-card.hbs @@ -43,7 +43,7 @@ @@ -134,8 +134,8 @@ {{#each targetData as |target|}} {{#if (eq target.result.hit "Hit")}} {{/if}} @@ -144,8 +144,8 @@
{{#each targetTokens as |target id|}} {{/if}} From 9c27b0099bdb97687fd3602f4bf0c4707e58caeb Mon Sep 17 00:00:00 2001 From: Peter Hunnisett <29824554+phBalance@users.noreply.github.com> Date: Sun, 15 Dec 2024 12:24:04 -0700 Subject: [PATCH 6/8] refactor(damage): rework roll damage to only do that - no calculations --- module/item/item-attack.mjs | 211 ++++++++++++---------------- module/utility/dice.mjs | 8 ++ templates/chat/item-damage-card.hbs | 42 +++--- 3 files changed, 117 insertions(+), 144 deletions(-) diff --git a/module/item/item-attack.mjs b/module/item/item-attack.mjs index 350046b9..fc0f3979 100644 --- a/module/item/item-attack.mjs +++ b/module/item/item-attack.mjs @@ -1488,9 +1488,13 @@ async function _rollApplyKnockback(token, knockbackDice) { token.actor.addActiveEffect(HeroSystem6eActorActiveEffects.statusEffectsObj.proneEffect); } -// Event handler for when the Roll Damage button is -// clicked on item-attack-card2.hbs -// Notice the chatListeners function in this file. +/** + * Event handler for when the Roll Damage button is clicked. Should only roll damage. The effects of damage + * are calculated later in the sequence when the apply buttons are pushed. + * + * @param {Event} event + * @returns + */ export async function _onRollDamage(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kludge to fix. @@ -1518,6 +1522,10 @@ export async function _onRollDamage(event) { } } + // Coerce type to boolean + toHitData.targetEntangle = + toHitData.targetEntangle === true || toHitData.targetEntangle.match(/true/i) ? true : false; + const adjustment = getPowerInfo({ item: item, })?.type?.includes("adjustment"); @@ -1567,82 +1575,46 @@ export async function _onRollDamage(event) { await damageRoller.roll(); - // Kludge for SIMPLIFIED HEALING - const isSimpleHealing = item.system.XMLID === "HEALING" && item.system.INPUT.match(/simplified/i); - - const damageRenderedResult = isSimpleHealing - ? await (await damageRoller.cloneWhileModifyingType(HeroRoller.ROLL_TYPE.NORMAL)).render() - : await damageRoller.render(); - - const damageDetail = await _calcDamage(damageRoller, effectiveItem, toHitData); - - const aoeTemplate = - game.scenes.current.templates.find((o) => o.flags.itemId === item.id) || - game.scenes.current.templates.find((o) => o.author.id === game.user.id); - const explosion = item.hasExplosionAdvantage(); - - // Coerce type to boolean - toHitData.targetEntangle = - toHitData.targetEntangle === true || toHitData.targetEntangle.match(/true/i) ? true : false; - - // Apply Damage button for specific targets - let targetTokens = []; + // Build list of who to target? + const targetTokens = []; for (const id of toHitData.targetIds.split(",")) { - let token = canvas.scene.tokens.get(id); + const token = canvas.scene.tokens.get(id); if (token) { const entangleAE = token.actor?.temporaryEffects?.find((o) => o.flags?.XMLID === "ENTANGLE"); - let targetToken = { + const targetToken = { token, - roller: damageRoller.toJSON(), subTarget: toHitData.targetEntangle && entangleAE ? `${token.name} [${entangleAE.flags.XMLID}]` : null, }; - // TODO: Add in explosion handling (or flattening) - if (explosion) { - // Distance from center - if (aoeTemplate) { - // Explosion - // Simple rules is to remove the hightest dice term for each - // hex distance from center. Works fine when radius = dice, - // but that isn't always the case. - - // Remove highest terms based on distance - const distance = calculateDistanceBetween(aoeTemplate, token.object.center); - const pct = distance / aoeTemplate.distance; - - // TODO: This assumes that the number of terms equals the DC/5 AP. This is - // true for normal attacks but not always. - // This ignores explosion modifiers for DC falloff. - const termsToRemove = Math.floor(pct * (damageRoller.getBaseTerms().length - 1)); - - const heroRollerClone = damageRoller.clone(); - heroRollerClone.removeNHighestRankTerms(termsToRemove); - - targetToken = { - ...targetToken, - distance, - roller: heroRollerClone.toJSON(), - }; - } - } targetTokens.push(targetToken); } } - // PERSONALIMMUNITY - // NOTE: We may want to reintroduce this code (CHANGE ENVIRONMENT or large scale MENTAL) at some point. - // However at the moment AOE is the primary mechanism to target multiple tokens. - // const PERSONALIMMUNITY = item.findModsByXmlid("PERSONALIMMUNITY"); - // if (PERSONALIMMUNITY && targetTokens) { - // targetTokens = targetTokens.filter((o) => o.token.actor.id != actor.id); + // Kludge for SIMPLIFIED HEALING + const isSimpleHealing = item.system.XMLID === "HEALING" && item.system.INPUT.match(/simplified/i); + + const damageRenderedResult = isSimpleHealing + ? await (await damageRoller.cloneWhileModifyingType(HeroRoller.ROLL_TYPE.NORMAL)).render() + : await damageRoller.render(); + + // // PERSONALIMMUNITY + // // NOTE: We may want to reintroduce this code (CHANGE ENVIRONMENT or large scale MENTAL) at some point. + // // However at the moment AOE is the primary mechanism to target multiple tokens. + // // const PERSONALIMMUNITY = item.findModsByXmlid("PERSONALIMMUNITY"); + // // if (PERSONALIMMUNITY && targetTokens) { + // // targetTokens = targetTokens.filter((o) => o.token.actor.id !== actor.id); + // // } + + // // If there is only 1 target then get rid of targetIds (which is used for Apply Damage ALL) + // if (targetTokens.length <= 1) { + // delete toHitData.targetIds; // } - // If there is only 1 target then get rid of targetIds (which is used for Apply Damage ALL) - if (targetTokens.length <= 1) { - delete toHitData.targetIds; - } + // PH: TODO: Continue to simplify the card and HBS const cardData = { + user: game.user, + item: item, nonDmgEffect: adjustment || isBodyBasedEffectRoll(item) || isStunBasedEffectRoll(item) || item.baseInfo?.nonDmgEffect, @@ -1650,35 +1622,19 @@ export async function _onRollDamage(event) { // dice rolls renderedDamageRoll: damageRenderedResult, - renderedStunMultiplierRoll: damageDetail.renderedStunMultiplierRoll, + rollerJSON: damageRoller.toJSON(), // hit locations - useHitLoc: damageDetail.useHitLoc, - hitLocText: damageDetail.hitLocText, - hitLocation: damageDetail.hitLocation, - - // body - bodyDamage: damageDetail.bodyDamage, - bodyDamageEffective: damageDetail.body, - - // stun - stunDamage: damageDetail.stunDamage, - stunDamageEffective: damageDetail.stun, - hasRenderedDamageRoll: true, - stunMultiplier: damageDetail.stunMultiplier, - hasStunMultiplierRoll: damageDetail.hasStunMultiplierRoll, - - roller: damageRoller.toJSON(), + useHitLoc: damageRoller.hitLocationValid(), + hitLocText: damageRoller.getHitLocation().fullName, // misc targetIds: toHitData.targetIds, - targetEntangle: toHitData.targetEntangle, tags: tags, attackTags: getAttackTags(item), targetTokens: targetTokens, - user: game.user, - actionData: JSON.stringify(action), + actionDataJSON: JSON.stringify(action), }; // render card @@ -1921,15 +1877,15 @@ export async function _onRollMindScanEffectRoll(event) { return; } -// Event handler for when the Apply Damage button is -// clicked on item-damage-card.hbs -// Notice the chatListeners function in this file. +/** + * Event handler for when the Apply Damage button is clicked on item-damage-card.hbsNotice the chatListeners function in this file. + */ export async function _onApplyDamage(event) { const button = event.currentTarget; button.blur(); // The button remains highlighted for some reason; kludge to fix. const damageData = { ...button.dataset }; - - const targetTokens = JSON.parse(damageData.tokenData); + const toHitData = damageData.toHitData; + const targetTokens = JSON.parse(damageData.targetTokens); if (targetTokens.length === 0) { // Check to make sure we have a selected token @@ -1937,27 +1893,19 @@ export async function _onApplyDamage(event) { return ui.notifications.warn(`You must select at least one token before applying damage.`); } - // PH: TODO: How to get the damageData information for this? - // PH: TODO: Need to figure out how to rebuild an attack for a random token since we could have damage that is related to range (explosion or reduced by range) ... call calcDamage again? for (const token of canvas.tokens.controlled) { - _onApplyDamageToSpecificToken(damageData, null /* PH: TODO: will fail */, token.id); + await _onApplyDamageToSpecificToken(toHitData, damageData, token.id); } } else { - // Apply to all targets + // Apply to all provided targets for (const targetToken of targetTokens) { const id = targetToken.token._id; - await _onApplyDamageToSpecificToken(damageData, targetToken.roller, id); + await _onApplyDamageToSpecificToken(toHitData, damageData, id); } } } -export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) { - const item = fromUuidSync(damageData.itemId); - - // TODO: Figure out how to remove damageData.bodyDamage, damageData.bodyDamageEffective, damageData.stunDamage, damageData.stunDamageEffective - - const heroRoller = HeroRoller.fromJSON(roller || damageData.roller); // PH: TODO: kludge only until null roller is resolved - +export async function _onApplyDamageToSpecificToken(toHitData, damageData, tokenId) { const token = canvas.tokens.get(tokenId); if (!token) { return ui.notifications.warn(`You must select at least one token before applying damage.`); @@ -1969,6 +1917,7 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) ); } + const item = fromUuidSync(damageData.itemId); if (!item) { // This typically happens when the attack id stored in the damage card no longer exists on the actor. // For example if the attack item was deleted or the HDC was uploaded again. @@ -1976,12 +1925,44 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) return ui.notifications.error(`Attack details are no longer available.`); } - const originalRoll = heroRoller.clone(); + // PH: TODO: Why are we cloning heroRoller here? + const originalRoll = HeroRoller.fromJSON(damageData.roller); + const heroRoller = originalRoll.clone(); + + // PH: TODO: Move this around. Should be near the top but there are some tweaks to do. + // PH: TODO: Do we need to call _calcDamage here? Seems to be done below. Does this mean we don't need toHitData? + // const damageDetail = await _calcDamage(heroRoller, effectiveItem, toHitData); + + const aoeTemplate = + game.scenes.current.templates.find((o) => o.flags.itemId === item.id) || + game.scenes.current.templates.find((o) => o.author.id === game.user.id); + const explosion = item.hasExplosionAdvantage(); + if (explosion) { + // Distance from center + if (aoeTemplate) { + // Explosion + // Simple rules is to remove the hightest dice term for each + // hex distance from center. Works fine when radius = dice, + // but that isn't always the case. + + // Remove highest terms based on distance + const distance = calculateDistanceBetween(aoeTemplate, token.object.center); + const pct = distance / aoeTemplate.distance; + + // TODO: This assumes that the number of terms equals the DC/5 AP. This is + // true for normal attacks but not always. + // TODO: This ignores explosion modifiers for DC falloff. + const termsToRemove = Math.floor(pct * (heroRoller.getBaseTerms().length - 1)); + + heroRoller.removeNHighestRankTerms(termsToRemove); + } + } + const automation = game.settings.get(HEROSYS.module, "automation"); const action = damageData.actionData ? JSON.parse(damageData.actionData) : null; if (item.system.XMLID === "ENTANGLE") { - return _onApplyEntangleToSpecificToken(item, token, originalRoll, action); + return _onApplyEntangleToSpecificToken(item, token, heroRoller, action); } // Target ENTANGLE @@ -1991,7 +1972,7 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) let targetEntangle = damageData.targetEntangle === "true" || damageData.targetEntangle === true; // If they clicked "Apply Damage" then prompt - if (!button.textContent.includes("[ENTANGLE]")) { + if (heroRoller.getType === HeroRoller.ROLL_TYPE.ENTANGLE) { console.log("do something"); targetEntangle = await Dialog.wait({ title: `Confirm Target`, @@ -2014,7 +1995,7 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) } if (targetEntangle && entangleAE) { - return _onApplyDamageToEntangle(item, token, originalRoll, entangleAE, action); + return _onApplyDamageToEntangle(item, token, heroRoller, entangleAE, action); } } @@ -2074,22 +2055,6 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) defenseTags, } = getActorDefensesVsAttack(token.actor, item, { ignoreDefenseIds }); - // if (defenseValue != _defenseValue && !["FLASHDEFENSE"].includes(item.attackDefenseVs) && !item.isKilling) { - // console.warn("defenseValue mismatch", defenseValue, _defenseValue); - // } - - // if (resistantValue != _resistantValue && !["FLASHDEFENSE"].includes(item.attackDefenseVs) && !item.isKilling) { - // console.warn("resistantValue mismatch", resistantValue, _resistantValue); - // } - - // if ( - // knockbackResistanceValue != _knockbackResistanceValue && - // !["FLASHDEFENSE"].includes(item.attackDefenseVs) && - // !item.isKilling - // ) { - // console.warn("knockbackResistance mismatch", knockbackResistanceValue, _knockbackResistanceValue); - // } - if (damageNegationValue > 0) { defense += "Damage Negation " + damageNegationValue + "DC(s); "; } @@ -2105,10 +2070,8 @@ export async function _onApplyDamageToSpecificToken(damageData, roller, tokenId) damageData.impenetrableValue = impenetrableValue; damageData.damageReductionValue = damageReductionValue; damageData.damageNegationValue = damageNegationValue; - //damageData.knockbackResistanceValue = knockbackResistanceValue; damageData.defenseAvad = - defenseValue + resistantValue + impenetrableValue + damageReductionValue + damageNegationValue; // + - //knockbackResistanceValue; + defenseValue + resistantValue + impenetrableValue + damageReductionValue + damageNegationValue; damageData.targetToken = token; // VULNERABILITY diff --git a/module/utility/dice.mjs b/module/utility/dice.mjs index 97e00aec..dab459d2 100644 --- a/module/utility/dice.mjs +++ b/module/utility/dice.mjs @@ -848,6 +848,14 @@ export class HeroRoller { return this._hitLocation; } + /** + * + * @returns {boolean} + */ + hitLocationValid() { + return this._useHitLocation; + } + /** * Make a copy of this existing roller that can be modified without affecting the original. * diff --git a/templates/chat/item-damage-card.hbs b/templates/chat/item-damage-card.hbs index c57d0401..0da0deff 100644 --- a/templates/chat/item-damage-card.hbs +++ b/templates/chat/item-damage-card.hbs @@ -40,11 +40,13 @@
- {{#each targetTokens as |target id|}} - {{/each}} - {{#if targetIds}} - @@ -80,7 +80,7 @@ data-item-id="{{item.uuid}}" data-action-data="{{actionDataJSON}}" data-roller="{{rollerJSON}}" - data-tokens="{{toJSON targetTokens}}" + data-target-tokens="{{toJSON targetTokens}}" > {{#if nonDmgEffect}} Apply {{item.system.XMLID}} to ALL From 446238f10f06b1140525ae88794c2c5bb808adc3 Mon Sep 17 00:00:00 2001 From: phBalance <29824554+phBalance@users.noreply.github.com> Date: Sun, 15 Dec 2024 17:24:47 -0700 Subject: [PATCH 8/8] fix(explosion): only show actual damage and not theoretical max damage --- module/item/item-attack.mjs | 38 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/module/item/item-attack.mjs b/module/item/item-attack.mjs index 9ae35f92..c3ae8f00 100644 --- a/module/item/item-attack.mjs +++ b/module/item/item-attack.mjs @@ -1926,13 +1926,7 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe return ui.notifications.error(`Attack details are no longer available.`); } - // PH: TODO: Why are we cloning heroRoller here? - const originalRoll = HeroRoller.fromJSON(damageData.roller); - const heroRoller = originalRoll.clone(); - - // PH: TODO: Move this around. Should be near the top but there are some tweaks to do. - // PH: TODO: Do we need to call _calcDamage here? Seems to be done below. Does this mean we don't need toHitData? - // const damageDetail = await _calcDamage(heroRoller, effectiveItem, toHitData); + const damageRoller = HeroRoller.fromJSON(damageData.roller); const aoeTemplate = game.scenes.current.templates.find((o) => o.flags.itemId === item.id) || @@ -1953,17 +1947,21 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe // TODO: This assumes that the number of terms equals the DC/5 AP. This is // true for normal attacks but not always. // TODO: This ignores explosion modifiers for DC falloff. - const termsToRemove = Math.floor(pct * (heroRoller.getBaseTerms().length - 1)); + const termsToRemove = Math.floor(pct * (damageRoller.getBaseTerms().length - 1)); - heroRoller.removeNHighestRankTerms(termsToRemove); + damageRoller.removeNHighestRankTerms(termsToRemove); } } + // This the raw damage received by the target before any defenses (i.e. after explosion and other range effects). + // You probably don't want to use it - use damageRoller instead. + const baseDamageRoller = damageRoller.clone(); + const automation = game.settings.get(HEROSYS.module, "automation"); const action = damageData.actionData ? JSON.parse(damageData.actionData) : null; if (item.system.XMLID === "ENTANGLE") { - return _onApplyEntangleToSpecificToken(item, token, heroRoller, action); + return _onApplyEntangleToSpecificToken(item, token, damageRoller, action); } // Target ENTANGLE @@ -1973,7 +1971,7 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe let targetEntangle = targetToken.targetEntangle; // If they clicked "Apply Damage" then prompt - if (heroRoller.getType === HeroRoller.ROLL_TYPE.ENTANGLE) { + if (damageRoller.getType === HeroRoller.ROLL_TYPE.ENTANGLE) { console.log("do something"); targetEntangle = await Dialog.wait({ title: `Confirm Target`, @@ -1996,11 +1994,11 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe } if (targetEntangle && entangleAE) { - return _onApplyDamageToEntangle(item, token, heroRoller, entangleAE, action); + return _onApplyDamageToEntangle(item, token, damageRoller, entangleAE, action); } } - if (heroRoller.getHitLocation().item) { + if (damageRoller.getHitLocation().item) { return ui.notifications.error(`Damaging FOCI is not currently supported.`); } @@ -2139,10 +2137,10 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe } } - heroRoller.removeNDC(damageData.damageNegationValue); + damageRoller.removeNDC(damageData.damageNegationValue); // We need to recalculate damage to account for possible Damage Negation - const damageDetail = await _calcDamage(heroRoller, item, damageData); + const damageDetail = await _calcDamage(damageRoller, item, damageData); // TRANSFORMATION const transformation = @@ -2227,7 +2225,7 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe } } - const damageRenderedResult = await heroRoller.render(); + const damageRenderedResult = await damageRoller.render(); // Attack may have additional effects, such as those from martial arts let effectsFinal = foundry.utils.deepClone(damageDetail.effects); @@ -2245,11 +2243,11 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe item: item, // Incoming Damage Information - incomingDamageSummary: originalRoll.getTotalSummary(), - incomingAnnotatedDamageTerms: originalRoll.getAnnotatedTermsSummary(), + incomingDamageSummary: baseDamageRoller.getTotalSummary(), + incomingAnnotatedDamageTerms: baseDamageRoller.getAnnotatedTermsSummary(), // dice rolls - roller: heroRoller, + roller: damageRoller, renderedDamageRoll: damageRenderedResult, renderedStunMultiplierRoll: damageDetail.renderedStunMultiplierRoll, knockbackRoll: damageDetail.knockbackRoller, @@ -2266,7 +2264,7 @@ export async function _onApplyDamageToSpecificToken(toHitData, damageData, targe hasStunMultiplierRoll: damageDetail.hasStunMultiplierRoll, // damage info - damageString: heroRoller.getTotalSummary(), + damageString: baseDamageRoller.getTotalSummary(), useHitLoc: damageDetail.useHitLoc, hitLocText: damageDetail.hitLocText,