diff --git a/module/applications/sidebar/tabs/daggerheartMenu.mjs b/module/applications/sidebar/tabs/daggerheartMenu.mjs index b29437bf..26ae484b 100644 --- a/module/applications/sidebar/tabs/daggerheartMenu.mjs +++ b/module/applications/sidebar/tabs/daggerheartMenu.mjs @@ -1,4 +1,4 @@ -import { refreshIsAllowed } from '../../../helpers/utils.mjs'; +import { RefreshFeatures } from '../../../helpers/utils.mjs'; const { HandlebarsApplicationMixin } = foundry.applications.api; const { AbstractSidebarTab } = foundry.applications.sidebar; @@ -54,73 +54,6 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract return context; } - async getRefreshables(types) { - const refreshedActors = {}; - for (let actor of game.actors) { - if (['character', 'adversary'].includes(actor.type) && actor.prototypeToken.actorLink) { - const updates = {}; - for (let item of actor.items) { - if (item.system.metadata?.hasResource && refreshIsAllowed(types, item.system.resource?.recovery)) { - if (!refreshedActors[actor.id]) - refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() }; - refreshedActors[actor.id].refreshed.add( - game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[item.system.resource.recovery].label) - ); - - if (!updates[item.id]?.system) updates[item.id] = { system: {} }; - - const increasing = - item.system.resource.progression === CONFIG.DH.ITEM.itemResourceProgression.increasing.id; - updates[item.id].system = { - ...updates[item.id].system, - 'resource.value': increasing - ? 0 - : Roll.replaceFormulaData(item.system.resource.max, actor.getRollData()) - }; - } - if (item.system.metadata?.hasActions) { - const refreshTypes = new Set(); - const actions = item.system.actions.filter(action => { - if (refreshIsAllowed(types, action.uses.recovery)) { - refreshTypes.add(action.uses.recovery); - return true; - } - - return false; - }); - if (actions.length === 0) continue; - - if (!refreshedActors[actor.id]) - refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() }; - refreshedActors[actor.id].refreshed.add( - ...refreshTypes.map(type => game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[type].label)) - ); - - if (!updates[item.id]?.system) updates[item.id] = { system: {} }; - - updates[item.id].system = { - ...updates[item.id].system, - ...actions.reduce( - (acc, action) => { - acc.actions[action.id] = { 'uses.value': 0 }; - return acc; - }, - { actions: updates[item.id].system.actions ?? {} } - ) - }; - } - } - - for (let key in updates) { - const update = updates[key]; - await actor.items.get(key).update(update); - } - } - } - - return refreshedActors; - } - /* -------------------------------------------- */ /* Application Clicks Actions */ /* -------------------------------------------- */ @@ -133,30 +66,9 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract static async #refreshActors() { const refreshKeys = Object.keys(this.refreshSelections).filter(key => this.refreshSelections[key].selected); - await this.getRefreshables(refreshKeys); - const types = refreshKeys.map(x => this.refreshSelections[x].label).join(', '); - ui.notifications.info( - game.i18n.format('DAGGERHEART.UI.Notifications.gmMenuRefresh', { - types: `[${types}]` - }) - ); + await RefreshFeatures(refreshKeys); + this.refreshSelections = DaggerheartMenu.defaultRefreshSelections(); - - const cls = getDocumentClass('ChatMessage'); - const msg = { - user: game.user.id, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/ui/chat/refreshMessage.hbs', - { - types: types - } - ), - title: game.i18n.localize('DAGGERHEART.UI.Chat.refreshMessage.title'), - speaker: cls.getSpeaker() - }; - - cls.create(msg); - this.render(); } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 57badd89..df007cdb 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -472,7 +472,7 @@ export function refreshIsAllowed(allowedTypes, typeToCheck) { case CONFIG.DH.GENERAL.refreshTypes.scene.id: case CONFIG.DH.GENERAL.refreshTypes.session.id: case CONFIG.DH.GENERAL.refreshTypes.longRest.id: - return allowedTypes.includes(typeToCheck); + return allowedTypes.includes?.(typeToCheck) ?? allowedTypes.has(typeToCheck); case CONFIG.DH.GENERAL.refreshTypes.shortRest.id: return allowedTypes.some( x => @@ -557,3 +557,114 @@ export function calculateExpectedValue(formulaOrTerms) { : [formulaOrTerms]; return terms.reduce((r, t) => r + (t.bonus ?? 0) + (t.diceQuantity ? (t.diceQuantity * (t.faces + 1)) / 2 : 0), 0); } + +/** + * Refreshes character and/or adversary resources. + * @param { string[] } refreshTypes Which type of features to refresh using IDs from CONFIG.DH.GENERAL.refreshTypes + * @param { string[] = ['character', 'adversary'] } actorTypes Which actor types should refresh their features. Defaults to character and adversary. + * @param { boolean = true } sendRefreshMessage If a chat message should be created detailing the refresh + * @return { Actor[] } The actors that had their features refreshed + */ +export async function RefreshFeatures( + refreshTypes = [], + actorTypes = ['character', 'adversary'], + sendNotificationMessage = true, + sendRefreshMessage = true +) { + const refreshedActors = {}; + for (let actor of game.actors) { + if (actorTypes.includes(actor.type) && actor.prototypeToken.actorLink) { + const updates = {}; + for (let item of actor.items) { + if ( + item.system.metadata?.hasResource && + refreshIsAllowed(refreshTypes, item.system.resource?.recovery) + ) { + if (!refreshedActors[actor.id]) + refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() }; + refreshedActors[actor.id].refreshed.add( + game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[item.system.resource.recovery].label) + ); + + if (!updates[item.id]?.system) updates[item.id] = { system: {} }; + + const increasing = + item.system.resource.progression === CONFIG.DH.ITEM.itemResourceProgression.increasing.id; + updates[item.id].system = { + ...updates[item.id].system, + 'resource.value': increasing + ? 0 + : game.system.api.documents.DhActiveEffect.effectSafeEval( + Roll.replaceFormulaData(item.system.resource.max, actor.getRollData()) + ) + }; + } + if (item.system.metadata?.hasActions) { + const usedTypes = new Set(); + const actions = item.system.actions.filter(action => { + if (refreshIsAllowed(refreshTypes, action.uses.recovery)) { + usedTypes.add(action.uses.recovery); + return true; + } + + return false; + }); + if (actions.length === 0) continue; + + if (!refreshedActors[actor.id]) + refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() }; + refreshedActors[actor.id].refreshed.add( + ...usedTypes.map(type => game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[type].label)) + ); + + if (!updates[item.id]?.system) updates[item.id] = { system: {} }; + + updates[item.id].system = { + ...updates[item.id].system, + ...actions.reduce( + (acc, action) => { + acc.actions[action.id] = { 'uses.value': 0 }; + return acc; + }, + { actions: updates[item.id].system.actions ?? {} } + ) + }; + } + } + + for (let key in updates) { + const update = updates[key]; + await actor.items.get(key).update(update); + } + } + } + + const types = refreshTypes.map(x => game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[x].label)).join(', '); + + if (sendNotificationMessage) { + ui.notifications.info( + game.i18n.format('DAGGERHEART.UI.Notifications.gmMenuRefresh', { + types: `[${types}]` + }) + ); + } + + if (sendRefreshMessage) { + const cls = getDocumentClass('ChatMessage'); + const msg = { + user: game.user.id, + content: await foundry.applications.handlebars.renderTemplate( + 'systems/daggerheart/templates/ui/chat/refreshMessage.hbs', + { + types: types + } + ), + title: game.i18n.localize('DAGGERHEART.UI.Chat.refreshMessage.title'), + speaker: cls.getSpeaker() + }; + + cls.create(msg); + } + + return refreshedActors; +}