From d86c7b96cef4f8f46523a3290f7507e7c137de34 Mon Sep 17 00:00:00 2001 From: nsalyzyn Date: Wed, 17 Dec 2025 11:31:15 -0700 Subject: [PATCH] Creating a new method to update range dependent effects that uses the players targets --- daggerheart.mjs | 84 +++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/daggerheart.mjs b/daggerheart.mjs index 86bdcb02..a072ea2a 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -248,54 +248,70 @@ Hooks.on('chatMessage', (_, message) => { } }); -Hooks.on('moveToken', async (movedToken, data) => { - const effectsAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).effects; - if (!effectsAutomation.rangeDependent) return; +const updateActorsRangeDependentEffects = async (token) => { + const rangeMeasurement = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.variantRules + ).rangeMeasurement; - const allEffects = [...movedToken.actor.allApplicableEffects()]; - const rangeDependantEffects = allEffects.filter(effect => effect.system.rangeDependence?.enabled); + for (let effect of token.actor.allApplicableEffects()) { + if (!effect.system.rangeDependence?.enabled) continue; + const { target, range, type } = effect.system.rangeDependence; - const updateEffects = async (disposition, token, effects, effectUpdates) => { - const rangeMeasurement = game.settings.get( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.variantRules - ).rangeMeasurement; - - for (let effect of effects.filter(x => x.system.rangeDependence?.enabled)) { - const { target, range, type } = effect.system.rangeDependence; - if ((target === 'friendly' && disposition !== 1) || (target === 'hostile' && disposition !== -1)) - return false; + // If there are no targets, assume false. Otherwise, start with the effect enabled. + let enabledEffect = game.user.targets.size !== 0; + // Expect all targets to meet the rangeDependence requirements + for (let userTarget of game.user.targets) { + const disposition = userTarget.document.disposition; + if ((target === 'friendly' && disposition !== 1) || (target === 'hostile' && disposition !== -1)) { + enabledEffect = false; + break; + } const distanceBetween = canvas.grid.measurePath([ - { ...movedToken.toObject(), x: data.destination.x, y: data.destination.y }, + // TODO: missing { ...movedToken.toObject(), x: data.destination.x, y: data.destination.y } + userTarget.document, token ]).distance; const distance = rangeMeasurement[range]; const reverse = type === CONFIG.DH.GENERAL.rangeInclusion.outsideRange.id; - const newDisabled = reverse ? distanceBetween <= distance : distanceBetween > distance; - const oldDisabled = effectUpdates[effect.uuid] ? effectUpdates[effect.uuid].disabled : newDisabled; - effectUpdates[effect.uuid] = { - disabled: oldDisabled || newDisabled, - value: effect - }; - } - }; - - const effectUpdates = {}; - for (let token of game.scenes.find(x => x.active).tokens) { - if (token.id !== movedToken.id) { - await updateEffects(token.disposition, token, rangeDependantEffects, effectUpdates); + if (reverse ? distanceBetween <= distance : distanceBetween > distance) { + enabledEffect = false; + break; + } } - if (token.actor) - await updateEffects(movedToken.disposition, token, [...token.actor.allApplicableEffects()], effectUpdates); + await effect.update({ disabled: !enabledEffect }); } +} - for (let key in effectUpdates) { - const effect = effectUpdates[key]; - await effect.value.update({ disabled: effect.disabled }); +const updateAllRangeDependentEffects = async () => { + const effectsAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).effects; + if (!effectsAutomation.rangeDependent) return; + + // Only consider tokens on the active scene + const tokens = game.scenes.find(x => x.active).tokens; + if (game.user.character) { + // The character updates their character's token. There can be only one token. + const characterToken = tokens.find(x => x.actor === game.user.character); + updateActorsRangeDependentEffects(characterToken); + } else if (game.user.isGM) { + // The GM is responsible for all other tokens. + const playerCharacters = game.users.players.filter(x => x.active).map(x => x.character); + for (let token of tokens.filter(x => !playerCharacters.includes(x.actor))) { + updateActorsRangeDependentEffects(token); + } } +}; + +Hooks.on('targetToken', async (user, token, targeted) => { + // TODO: There is a bug when you untarget one token and retarget a new one + await updateAllRangeDependentEffects(); +}); + +Hooks.on('moveToken', async (movedToken, data) => { + await updateAllRangeDependentEffects(); }); Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));