From a4fff56461a105bc5389a708f8c53ce4dd3aa115 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Wed, 25 Mar 2026 17:07:20 +0100 Subject: [PATCH 1/4] Fixed base resources getting their values capped to max at prepareDerivedData. Fixed effect autocomplete not having labels for baseResources. --- module/data/actor/character.mjs | 2 -- module/data/actor/creature.mjs | 10 ++++++++++ module/data/fields/actorField.mjs | 11 ++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 10d50301..cde7d280 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -660,7 +660,6 @@ export default class DhCharacter extends DhCreature { prepareDerivedData() { super.prepareDerivedData(); - let baseHope = this.resources.hope.value; if (this.companion) { for (let levelKey in this.companion.system.levelData.levelups) { const level = this.companion.system.levelData.levelups[levelKey]; @@ -675,7 +674,6 @@ export default class DhCharacter extends DhCreature { } this.resources.hope.max -= this.scars; - this.resources.hope.value = Math.min(baseHope, this.resources.hope.max); this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait; this.resources.armor = { diff --git a/module/data/actor/creature.mjs b/module/data/actor/creature.mjs index 601068ad..88646301 100644 --- a/module/data/actor/creature.mjs +++ b/module/data/actor/creature.mjs @@ -60,4 +60,14 @@ export default class DhCreature extends BaseDataActor { } } } + + prepareDerivedData() { + const minLimitResource = resource => { + if (resource) resource.value = Math.min(resource.value, resource.max); + }; + + minLimitResource(this.resources.stress); + minLimitResource(this.resources.hitPoints); + minLimitResource(this.resources.hope); + } } diff --git a/module/data/fields/actorField.mjs b/module/data/fields/actorField.mjs index 76c24319..a3c17281 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -83,19 +83,20 @@ class ResourcesField extends fields.TypedObjectField { return data; } - /** + /** * Foundry bar attributes are unable to handle finding the schema field nor the label normally. * This returns the element if its a valid resource key and overwrites the element's label for that retrieval. */ _getField(path) { - if ( path.length === 0 ) return this; + if (path.length === 0) return this; const first = path.shift(); if (first === this.element.name) return this.element_getField(path); - + const resources = CONFIG.DH.RESOURCE[this.actorType].all; if (first in resources) { - this.element.label = resources[first].label; - return this.element._getField(path); + const field = this.element._getField(path); + field.label = resources[first].label; + return field; } return undefined; From eb9e47c39d341f25328c51c2d809a1f0f7b11fa1 Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Thu, 26 Mar 2026 10:50:52 -0400 Subject: [PATCH 2/4] Refresh effects display after actor preparation (#1752) --- module/applications/ui/effectsDisplay.mjs | 1 - module/documents/actor.mjs | 12 ++++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/module/applications/ui/effectsDisplay.mjs b/module/applications/ui/effectsDisplay.mjs index 8c0c939c..e0fa7ae2 100644 --- a/module/applications/ui/effectsDisplay.mjs +++ b/module/applications/ui/effectsDisplay.mjs @@ -91,7 +91,6 @@ export default class DhEffectsDisplay extends HandlebarsApplicationMixin(Applica const effects = DhEffectsDisplay.getTokenEffects(); const effect = effects.find(x => x.id === element.dataset.effectId); await effect.delete(); - this.render(); } setupHooks() { diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 13843bb8..eea2e212 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -29,6 +29,18 @@ export default class DhpActor extends Actor { return this.system.metadata.isNPC; } + prepareData() { + super.prepareData(); + + // Update effects if it is the user's character or is controlled + if (canvas.ready) { + const controlled = canvas.tokens.controlled.some((t) => t.actor === this); + if (game.user.character === this || controlled) { + ui.effectsDisplay.render(); + } + } + } + /* -------------------------------------------- */ /** @inheritDoc */ From a4adbf8ac4cf90f73af5e4eaed1a4e57b49501de Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Thu, 26 Mar 2026 16:12:05 +0100 Subject: [PATCH 3/4] Added system keybind for spotlighting a combatant (#1749) --- daggerheart.mjs | 2 ++ lang/en.json | 14 ++++++++++++++ module/_module.mjs | 1 + module/config/settingsConfig.mjs | 4 ++++ module/macros/_modules.mjs | 1 + module/macros/spotlightCombatant.mjs | 21 +++++++++++++++++++++ module/systemRegistration/settings.mjs | 20 ++++++++++++++++++++ system.json | 2 +- 8 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 module/macros/_modules.mjs create mode 100644 module/macros/spotlightCombatant.mjs diff --git a/daggerheart.mjs b/daggerheart.mjs index 5960c6b1..abe12524 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -3,6 +3,7 @@ import * as applications from './module/applications/_module.mjs'; import * as data from './module/data/_module.mjs'; import * as models from './module/data/_module.mjs'; import * as documents from './module/documents/_module.mjs'; +import { macros } from './module/_module.mjs'; import * as collections from './module/documents/collections/_module.mjs'; import * as dice from './module/dice/_module.mjs'; import * as fields from './module/data/fields/_module.mjs'; @@ -93,6 +94,7 @@ Hooks.once('init', () => { data, models, documents, + macros, dice, fields }; diff --git a/lang/en.json b/lang/en.json index 4032b6ed..feeb65b2 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2486,6 +2486,14 @@ "secondaryWeapon": "Secondary Weapon" } }, + "MACROS": { + "Spotlight": { + "errors": { + "noActiveCombat": "There is no active encounter", + "noCombatantSelected": "A combatant token must be either selected or hovered to spotlight it" + } + } + }, "ROLLTABLES": { "FIELDS": { "formulaName": { "label": "Formula Name" } @@ -2725,6 +2733,12 @@ "setResourceIdentifier": "Set Resource Identifier" } }, + "Keybindings": { + "spotlight": { + "name": "Spotlight Combatant", + "hint": "Move the spotlight to a hovered or selected token that's present in an active encounter" + } + }, "Menu": { "title": "Daggerheart Game Settings", "automation": { diff --git a/module/_module.mjs b/module/_module.mjs index 2e1d6fb4..4a00e97c 100644 --- a/module/_module.mjs +++ b/module/_module.mjs @@ -7,3 +7,4 @@ export * as documents from './documents/_module.mjs'; export * as enrichers from './enrichers/_module.mjs'; export * as helpers from './helpers/_module.mjs'; export * as systemRegistration from './systemRegistration/_module.mjs'; +export * as macros from './macros/_modules.mjs'; diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 0b28f0ab..c19e6e26 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -1,3 +1,7 @@ +export const keybindings = { + spotlight: 'DHSpotlight' +}; + export const menu = { Automation: { Name: 'GameSettingsAutomation', diff --git a/module/macros/_modules.mjs b/module/macros/_modules.mjs new file mode 100644 index 00000000..d4a5599f --- /dev/null +++ b/module/macros/_modules.mjs @@ -0,0 +1 @@ +export { default as spotlightCombatant } from './spotlightCombatant.mjs'; diff --git a/module/macros/spotlightCombatant.mjs b/module/macros/spotlightCombatant.mjs new file mode 100644 index 00000000..68a26ff9 --- /dev/null +++ b/module/macros/spotlightCombatant.mjs @@ -0,0 +1,21 @@ +/** + * Spotlights a combatant. + * The combatant can be selected in a number of ways. If many are applied at the same time, the following order is used: + * 1) SelectedCombatant + * 2) HoveredCombatant + */ +const spotlightCombatant = () => { + if (!game.combat) + return ui.notifications.error(game.i18n.localize('DAGGERHEART.MACROS.Spotlight.errors.noActiveCombat')); + + const selectedCombatant = canvas.tokens.controlled.length > 0 ? canvas.tokens.controlled[0].combatant : null; + const hoveredCombatant = game.canvas.tokens.hover?.combatant; + + const combatant = selectedCombatant ?? hoveredCombatant; + if (!combatant) + return ui.notifications.error(game.i18n.localize('DAGGERHEART.MACROS.Spotlight.errors.noCombatantSelected')); + + ui.combat.setCombatantSpotlight(combatant.id); +}; + +export default spotlightCombatant; diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index e7ec37f5..94ad5da7 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -18,6 +18,7 @@ import { import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs'; export const registerDHSettings = () => { + registerKeyBindings(); registerMenuSettings(); registerMenus(); registerNonConfigSettings(); @@ -33,6 +34,25 @@ export const registerDHSettings = () => { }); }; +export const registerKeyBindings = () => { + game.keybindings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.keybindings.spotlight, { + name: game.i18n.localize('DAGGERHEART.SETTINGS.Keybindings.spotlight.name'), + hint: game.i18n.localize('DAGGERHEART.SETTINGS.Keybindings.spotlight.hint'), + uneditable: [], + editable: [ + { + key: 's', + modifiers: [] + } + ], + onDown: game.system.api.macros.spotlightCombatant, + onUp: () => {}, + restricted: true, + reservedModifiers: [], + precedence: CONST.KEYBINDING_PRECEDENCE.NORMAL + }); +}; + const registerMenuSettings = () => { game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules, { scope: 'world', diff --git a/system.json b/system.json index 44c26886..9242a24a 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.9.5", + "version": "1.9.6", "compatibility": { "minimum": "13.346", "verified": "13.351", From 94a2a5723b38015a6d4b8df5f3cc9733eff7bea8 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Thu, 26 Mar 2026 16:34:24 +0100 Subject: [PATCH 4/4] Removed default spotlight keybind key --- module/systemRegistration/settings.mjs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index 94ad5da7..17dab6f7 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -39,12 +39,7 @@ export const registerKeyBindings = () => { name: game.i18n.localize('DAGGERHEART.SETTINGS.Keybindings.spotlight.name'), hint: game.i18n.localize('DAGGERHEART.SETTINGS.Keybindings.spotlight.hint'), uneditable: [], - editable: [ - { - key: 's', - modifiers: [] - } - ], + editable: [], onDown: game.system.api.macros.spotlightCombatant, onUp: () => {}, restricted: true,