From aa2714e02136a29d1a79d7b1fbfc1df73a58d2f9 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Tue, 15 Jul 2025 15:59:01 +0200 Subject: [PATCH] [Fix] Automation Fixes (#342) * Initial * Split HopeFear automation by GM and Players * Fixed ActionToken automation --- daggerheart.mjs | 3 +- lang/en.json | 7 ++- module/applications/hud/tokenHUD.mjs | 2 +- .../applications/sheets/actors/character.mjs | 5 +- module/applications/ui/combatTracker.mjs | 17 +++++- module/applications/ui/countdowns.mjs | 59 +++++++------------ module/config/_module.mjs | 1 - module/config/generalConfig.mjs | 6 +- module/config/hooksConfig.mjs | 4 -- module/config/system.mjs | 2 - module/data/action/attackAction.mjs | 9 +++ module/data/countdowns.mjs | 10 +++- module/data/settings/Automation.mjs | 22 +++---- module/dice/dhRoll.mjs | 9 +-- templates/settings/automation-settings.hbs | 7 ++- 15 files changed, 87 insertions(+), 76 deletions(-) delete mode 100644 module/config/hooksConfig.mjs diff --git a/daggerheart.mjs b/daggerheart.mjs index a1742641..aeae0dc6 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -5,7 +5,7 @@ import * as documents from './module/documents/_module.mjs'; import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs'; import { DhDualityRollEnricher, DhTemplateEnricher } from './module/enrichers/_module.mjs'; import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; -import { NarrativeCountdowns, registerCountdownApplicationHooks } from './module/applications/ui/countdowns.mjs'; +import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs'; import { DualityRollColor } from './module/data/settings/Appearance.mjs'; import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/dice/_module.mjs'; import { renderDualityButton } from './module/enrichers/DualityRollEnricher.mjs'; @@ -168,7 +168,6 @@ Hooks.on('ready', () => { registerCountdownHooks(); socketRegistration.registerSocketHooks(); - registerCountdownApplicationHooks(); registerRollDiceHooks(); registerDHActorHooks(); }); diff --git a/lang/en.json b/lang/en.json index 1adf4bc6..3bf99e3a 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1337,9 +1337,10 @@ "hint": "Automatically increase the GM's fear pool on a fear duality roll result." }, "FIELDS": { - "hope": { - "label": "Hope", - "hint": "Automatically increase a character's hope on a hope duality roll result." + "hopeFear": { + "label": "Hope & Fear", + "gm": { "label": "GM" }, + "players": { "label": "Players" } }, "actionPoints": { "label": "Action Points", diff --git a/module/applications/hud/tokenHUD.mjs b/module/applications/hud/tokenHUD.mjs index 9a58bab2..572b03f9 100644 --- a/module/applications/hud/tokenHUD.mjs +++ b/module/applications/hud/tokenHUD.mjs @@ -1,4 +1,4 @@ -export default class DHTokenHUD extends TokenHUD { +export default class DHTokenHUD extends foundry.applications.hud.TokenHUD { static DEFAULT_OPTIONS = { classes: ['daggerheart'] }; diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index fcd92842..139a1369 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -669,10 +669,7 @@ export default class CharacterSheet extends DHBaseActorSheet { } else if (item instanceof ActiveEffect) { item.toChat(this); } else { - const wasUsed = await item.use(event); - if (wasUsed && item.type === 'weapon') { - Hooks.callAll(CONFIG.DH.HOOKS.characterAttack, {}); - } + item.use(event); } } diff --git a/module/applications/ui/combatTracker.mjs b/module/applications/ui/combatTracker.mjs index f9f49ad1..b3348fe2 100644 --- a/module/applications/ui/combatTracker.mjs +++ b/module/applications/ui/combatTracker.mjs @@ -66,6 +66,11 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C } async setCombatantSpotlight(combatantId) { + const update = { + system: { + 'spotlight.requesting': false + } + }; const combatant = this.viewed.combatants.get(combatantId); const toggleTurn = this.viewed.combatants.contents @@ -73,10 +78,18 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C .map(x => x.id) .indexOf(combatantId); - if (this.viewed.turn !== toggleTurn) Hooks.callAll(CONFIG.DH.HOOKS.spotlight, {}); + if (this.viewed.turn !== toggleTurn) { + const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns; + await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.spotlight.id); + + const autoPoints = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).actionPoints; + if (autoPoints) { + update.system.actionTokens = Math.max(combatant.system.actionTokens - 1, 0); + } + } await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn }); - await combatant.update({ 'system.spotlight.requesting': false }); + await combatant.update(update); } static async requestSpotlight(_, target) { diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index c229cda1..5e3ad1ab 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -1,4 +1,3 @@ -import { countdownTypes } from '../../config/generalConfig.mjs'; import { GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import constructHTMLButton from '../../helpers/utils.mjs'; import OwnershipSelection from '../dialogs/ownershipSelection.mjs'; @@ -328,43 +327,29 @@ export class EncounterCountdowns extends Countdowns { }; } -export const registerCountdownApplicationHooks = () => { - const updateCountdowns = async shouldProgress => { - if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).countdowns) { - const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); - for (let countdownCategoryKey in countdownSetting) { - const countdownCategory = countdownSetting[countdownCategoryKey]; - for (let countdownKey in countdownCategory.countdowns) { - const countdown = countdownCategory.countdowns[countdownKey]; - - if (shouldProgress(countdown)) { - await countdownSetting.updateSource({ - [`${countdownCategoryKey}.countdowns.${countdownKey}.progress.current`]: - countdown.progress.current - 1 - }); - await game.settings.set( - CONFIG.DH.id, - CONFIG.DH.SETTINGS.gameSettings.Countdowns, - countdownSetting - ); - foundry.applications.instances.get(`${countdownCategoryKey}-countdowns`)?.render(); - } +export async function updateCountdowns(progressType) { + const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); + const update = Object.keys(countdownSetting).reduce((update, typeKey) => { + return foundry.utils.mergeObject( + update, + Object.keys(countdownSetting[typeKey].countdowns).reduce((acc, countdownKey) => { + const countdown = countdownSetting[typeKey].countdowns[countdownKey]; + if (countdown.progress.current > 0 && countdown.progress.type.value === progressType) { + acc[`${typeKey}.countdowns.${countdownKey}.progress.current`] = countdown.progress.current - 1; } - } - } - }; - Hooks.on(CONFIG.DH.HOOKS.characterAttack, async () => { - updateCountdowns(countdown => { - return ( - countdown.progress.type.value === countdownTypes.characterAttack.id && countdown.progress.current > 0 - ); - }); - }); + return acc; + }, {}) + ); + }, {}); - Hooks.on(CONFIG.DH.HOOKS.spotlight, async () => { - updateCountdowns(countdown => { - return countdown.progress.type.value === countdownTypes.spotlight.id && countdown.progress.current > 0; - }); + await countdownSetting.updateSource(update); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, countdownSetting); + + const data = { refreshType: RefreshType.Countdown }; + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data }); -}; + Hooks.callAll(socketEvent.Refresh, data); +} diff --git a/module/config/_module.mjs b/module/config/_module.mjs index 88003595..99069dda 100644 --- a/module/config/_module.mjs +++ b/module/config/_module.mjs @@ -4,7 +4,6 @@ export * as domainConfig from './domainConfig.mjs'; export * as effectConfig from './effectConfig.mjs'; export * as flagsConfig from './flagsConfig.mjs'; export * as generalConfig from './generalConfig.mjs'; -export * as hooksConfig from './hooksConfig.mjs'; export * as itemConfig from './itemConfig.mjs'; export * as settingsConfig from './settingsConfig.mjs'; export * as systemConfig from './system.mjs'; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 3522b41a..54430860 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -376,15 +376,15 @@ export const abilityCosts = { export const countdownTypes = { spotlight: { id: 'spotlight', - label: 'DAGGERHEART.CONFIG.CountdownTypes.Spotlight' + label: 'DAGGERHEART.CONFIG.CountdownType.spotlight' }, characterAttack: { id: 'characterAttack', - label: 'DAGGERHEART.CONFIG.CountdownTypes.CharacterAttack' + label: 'DAGGERHEART.CONFIG.CountdownType.characterAttack' }, custom: { id: 'custom', - label: 'DAGGERHEART.CONFIG.CountdownTypes.Custom' + label: 'DAGGERHEART.CONFIG.CountdownType.custom' } }; export const rollTypes = { diff --git a/module/config/hooksConfig.mjs b/module/config/hooksConfig.mjs deleted file mode 100644 index 8410c0de..00000000 --- a/module/config/hooksConfig.mjs +++ /dev/null @@ -1,4 +0,0 @@ -export const hooks = { - characterAttack: 'characterAttackHook', - spotlight: 'spotlightHook' -}; diff --git a/module/config/system.mjs b/module/config/system.mjs index 6ad0e689..e72667b1 100644 --- a/module/config/system.mjs +++ b/module/config/system.mjs @@ -3,7 +3,6 @@ import * as DOMAIN from './domainConfig.mjs'; import * as ACTOR from './actorConfig.mjs'; import * as ITEM from './itemConfig.mjs'; import * as SETTINGS from './settingsConfig.mjs'; -import { hooks as HOOKS } from './hooksConfig.mjs'; import * as EFFECTS from './effectConfig.mjs'; import * as ACTIONS from './actionConfig.mjs'; import * as FLAGS from './flagsConfig.mjs'; @@ -17,7 +16,6 @@ export const SYSTEM = { ACTOR, ITEM, SETTINGS, - HOOKS, EFFECTS, ACTIONS, FLAGS diff --git a/module/data/action/attackAction.mjs b/module/data/action/attackAction.mjs index 137879b8..e17c0e9d 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -38,6 +38,15 @@ export default class DHAttackAction extends DHDamageAction { }; } + async use(event, ...args) { + const result = await super.use(event, args); + + const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns; + await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.characterAttack.id); + + return result; + } + // get modifiers() { // return []; // } diff --git a/module/data/countdowns.mjs b/module/data/countdowns.mjs index e9649f6e..881ecf20 100644 --- a/module/data/countdowns.mjs +++ b/module/data/countdowns.mjs @@ -102,7 +102,7 @@ class DhCountdown extends foundry.abstract.DataModel { value: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.countdownTypes, - initial: CONFIG.DH.GENERAL.countdownTypes.spotlight.id, + initial: CONFIG.DH.GENERAL.countdownTypes.custom.id, label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.type.value.label' }), label: new fields.StringField({ @@ -132,7 +132,13 @@ class DhCountdown extends foundry.abstract.DataModel { export const registerCountdownHooks = () => { Hooks.on(socketEvent.Refresh, ({ refreshType, application }) => { if (refreshType === RefreshType.Countdown) { - foundry.applications.instances.get(application)?.render(); + if (application) { + foundry.applications.instances.get(application)?.render(); + } else { + foundry.applications.instances.get('narrative-countdowns').render(); + foundry.applications.instances.get('encounter-countdowns').render(); + } + return false; } }); diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index 4e375919..4291423b 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -4,20 +4,22 @@ export default class DhAutomation extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; return { - hope: new fields.BooleanField({ - required: true, - initial: false, - label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hope.label' - }), // Label need to be updated into something like "Duality Roll Auto Gain" + a hint + hopeFear: new fields.SchemaField({ + gm: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.gm.label' + }), + players: new fields.BooleanField({ + required: true, + initial: false, + label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.players.label' + }) + }), actionPoints: new fields.BooleanField({ required: true, initial: false, label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.actionPoints.label' - }), - countdowns: new fields.BooleanField({ - requireD: true, - initial: false, - label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.countdowns.label' }) }; } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 1bd9a6e5..22f5bb28 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -175,9 +175,10 @@ export default class DHRoll extends Roll { export const registerRollDiceHooks = () => { Hooks.on(`${CONFIG.DH.id}.postRollDuality`, async (config, message) => { + const hopeFearAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hopeFear; if ( !config.source?.actor || - !game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hope || + (game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) || config.roll.type === 'reaction' ) return; @@ -185,9 +186,9 @@ export const registerRollDiceHooks = () => { const actor = await fromUuid(config.source.actor), updates = []; if (!actor) return; - if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ type: 'hope', value: 1 }); - if (config.roll.isCritical) updates.push({ type: 'stress', value: -1 }); - if (config.roll.result.duality === -1) updates.push({ type: 'fear', value: 1 }); + if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ key: 'hope', value: 1 }); + if (config.roll.isCritical) updates.push({ key: 'stress', value: -1 }); + if (config.roll.result.duality === -1) updates.push({ key: 'fear', value: 1 }); if (updates.length) actor.modifyResource(updates); diff --git a/templates/settings/automation-settings.hbs b/templates/settings/automation-settings.hbs index 7a637d08..87a48c06 100644 --- a/templates/settings/automation-settings.hbs +++ b/templates/settings/automation-settings.hbs @@ -1,5 +1,10 @@
- {{formGroup settingFields.schema.fields.hope value=settingFields._source.hope localize=true}} +
+ + {{formGroup settingFields.schema.fields.hopeFear.fields.gm value=settingFields._source.hopeFear.gm localize=true}} + {{formGroup settingFields.schema.fields.hopeFear.fields.players value=settingFields._source.hopeFear.players localize=true}} + +
{{formGroup settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints localize=true}} {{formGroup settingFields.schema.fields.countdowns value=settingFields._source.countdowns localize=true}}