From 35654c9fc1e88cf052205b8bce8110174d95450b Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Fri, 3 Jan 2025 19:47:32 +0100 Subject: [PATCH] fix: Improve persistent damage handling safety checks Added null and type checks to ensure more robust handling of persistent damage and healing scenarios. Adjusted logic to prevent errors with empty or invalid roll data and introduced error logging for asynchronous operations. --- src/module/feature/damageHandler/index.ts | 26 +++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/module/feature/damageHandler/index.ts b/src/module/feature/damageHandler/index.ts index 6526129cc..577e0691f 100644 --- a/src/module/feature/damageHandler/index.ts +++ b/src/module/feature/damageHandler/index.ts @@ -138,13 +138,15 @@ export async function noOrSuccessfulFlatcheck(message: ChatMessagePF2e): Promise return rollDamage; } -export function persistentDamageHealing(message: ChatMessagePF2e) { - if (!game.ready || !message.token || !message.actor || !message.isDamageRoll) return; +export function persistentDamageHealing(message: ChatMessagePF2e): void { + if (!message || !game.ready || !message.token || !message.actor || !message.isDamageRoll) return; - const rolls = message.rolls as Rolled[]; + const rolls = Array.isArray(message.rolls) ? (message.rolls as Rolled[]) : null; + if (!rolls) return; let dtype: "Damage" | "Healing" | undefined; - if (rolls[0]?.instances.some((i) => i.persistent && i.options.evaluatePersistent)) { + if (rolls.length === 0) return; + if (rolls[0]?.instances?.some((i) => i.persistent && i.options.evaluatePersistent)) { dtype = "Damage"; } else if ( rolls.some((r) => r.kinds.has("healing")) && @@ -161,7 +163,7 @@ export function persistentDamageHealing(message: ChatMessagePF2e) { if (dtype && game.settings.get(MODULENAME, `applyPersistent${dtype}`)) { const itemOptions = message.item?.getRollOptions("item") ?? []; const rollOptions = new Set([...itemOptions, ...message.actor.getSelfRollOptions()]); - const damage = dtype === "Damage" ? rolls[0] : -rolls.reduce((sum, current) => sum + (current.total || 1), 0); + const damage = dtype === "Damage" ? rolls[0] : -rolls.reduce((sum, current) => sum + (current.total ?? 1), 0); const apply = message.actor.applyDamage({ damage, token: message.token, @@ -172,11 +174,13 @@ export function persistentDamageHealing(message: ChatMessagePF2e) { if (dtype === "Damage" && game.settings.get(MODULENAME, "applyPersistentDamageRecoveryRoll")) { // Use .then() here so the damage taken message is in chat before the recovery roll. It works without, but the order // of the messages will be undetermined. - apply.then(() => { - if (message.item?.isOfType("condition")) { - message.item.rollRecovery(); - } - }); + apply + .then(() => { + if (message.item?.isOfType("condition")) { + message.item.rollRecovery(); + } + }) + .catch((error) => console.error("Error applying persistent healing/damage:", error)); } // TODO Update the message to remove the recovery roll button, instead include the result in the message (and remove the message the following line creates.) } @@ -342,7 +346,7 @@ async function handleNonSpell(actor, message, degreeOfSuccess: string) { } async function handleElementalBlastAttack(actor, message, degreeOfSuccess, checkContext) { - const roll = message.rolls.find((r) => r.options?.action === "elemental-blast"); + const roll = message.rolls?.find((r) => r.options?.action === "elemental-blast"); if (roll && actor.isOfType("character")) { const identifier = roll?.options.identifier; const [element, damageType, meleeOrRanged, actionCost]: (string | undefined)[] = identifier?.split(".") ?? [];