From 6448666579f4cca9a3f72c15db9cbe2e049d3208 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 1 Jun 2026 19:47:06 +0200 Subject: [PATCH 1/7] Updated combat contextmenu --- module/applications/ui/combatTracker.mjs | 44 ++++++++++++++++--- .../ui/combatTracker/combatTrackerHeader.hbs | 5 +++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/module/applications/ui/combatTracker.mjs b/module/applications/ui/combatTracker.mjs index 8dd76850..25f3e06b 100644 --- a/module/applications/ui/combatTracker.mjs +++ b/module/applications/ui/combatTracker.mjs @@ -84,19 +84,49 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C }); } + /** + * Open the dialog used to edit the name of the currently viewed Combat encounter. + * @this {CombatTracker} + * @returns {Promise} + */ + static async #onEditName() { + const combat = this.viewed; + if (!combat || !game.user.isGM) return null; + const field = combat.schema.fields.name; + const inputHTML = field.toFormGroup({}, { name: 'name', value: combat.name, autofocus: true }).outerHTML; + const formData = await foundry.applications.api.DialogV2.input({ + window: { icon: 'fa-solid fa-tag', title: 'COMBAT.ACTIONS.EditNameTitle' }, + position: { width: 480 }, + content: inputHTML + }); + await combat.update({ name: formData.name || '' }); + } + _getCombatContextOptions() { return [ { - label: 'COMBAT.ClearMovementHistories', - icon: '', - visible: () => game.user.isGM && this.viewed?.combatants.size > 0, - callback: () => this.viewed.clearMovementHistories() + label: 'COMBAT.ACTIONS.EditName', + icon: 'fa-solid fa-tag', + visible: () => game.user.isGM && !!this.viewed, + onClick: () => DhCombatTracker.#onEditName.call(this) }, { - label: 'COMBAT.Delete', - icon: '', + label: 'COMBAT.ACTIONS.LinkToScene', + icon: '', + visible: () => game.user.isGM && !this.scene, + onClick: () => this.viewed.toggleSceneLink() + }, + { + label: 'COMBAT.ACTIONS.UnlinkFromScene', + icon: '', + visible: () => game.user.isGM && !!this.scene, + onClick: () => this.viewed.toggleSceneLink() + }, + { + label: 'COMBAT.End', + icon: 'fa-solid fa-xmark', visible: () => game.user.isGM && !!this.viewed, - callback: () => this.viewed.endCombat() + onClick: () => this.viewed.endCombat() } ]; } diff --git a/templates/ui/combatTracker/combatTrackerHeader.hbs b/templates/ui/combatTracker/combatTrackerHeader.hbs index 803286ab..9f5a7561 100644 --- a/templates/ui/combatTracker/combatTrackerHeader.hbs +++ b/templates/ui/combatTracker/combatTrackerHeader.hbs @@ -50,6 +50,11 @@ {{/if}} + {{!-- Encounter Name --}} + {{#if combat.name}} +

{{ combat.name }}

+ {{/if}} +
{{!-- Combat Status --}} From 646ebc8bdf0fa6bcb18a2997c76802bff44a59a1 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:52:27 +0200 Subject: [PATCH 2/7] Added a temp fix for status effect rows (#1965) --- styles/less/hud/token-hud/token-hud.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/styles/less/hud/token-hud/token-hud.less b/styles/less/hud/token-hud/token-hud.less index 3cb94e1e..3b998f4e 100644 --- a/styles/less/hud/token-hud/token-hud.less +++ b/styles/less/hud/token-hud/token-hud.less @@ -38,6 +38,9 @@ } .status-effects { + // TODO: Remove when the issue https://github.com/foundryvtt/foundryvtt/issues/14410 is resolved and Foundry handles it cleanly themselves. + grid-template-rows: min-content; + .effect-control-container { position: relative; From df4a2c5d57c3592d3c15550c1f2fadc36bdba655 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:53:28 +0200 Subject: [PATCH 3/7] Fixed Countdown.migrationData assuming an array when it's actually an object (#1962) --- module/data/action/countdownAction.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/data/action/countdownAction.mjs b/module/data/action/countdownAction.mjs index abcc6b40..cb141637 100644 --- a/module/data/action/countdownAction.mjs +++ b/module/data/action/countdownAction.mjs @@ -36,7 +36,7 @@ export default class DhCountdownAction extends DHBaseAction { /** @inheritDoc */ static migrateData(source) { - for (const countdown of source.countdown) { + for (const countdown of Object.values(source.countdown)) { if (countdown.progress.max) { countdown.progress.startFormula = countdown.progress.max; countdown.progress.start = 1; From bcf274f1d05819cf9148ab597e558962e270a2e2 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:59:44 +0200 Subject: [PATCH 4/7] [Fix] ChatMessage Saves Pending Confirmation (#1963) --- lang/en.json | 6 +++--- module/documents/chatMessage.mjs | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lang/en.json b/lang/en.json index 9ce515d9..3a1340e0 100755 --- a/lang/en.json +++ b/lang/en.json @@ -711,9 +711,9 @@ }, "PendingReactionsDialog": { "title": "Pending Reaction Rolls Found", - "unfinishedRolls": "Some Tokens still need to roll their Reaction Roll.", - "confirmation": "Are you sure you want to continue ?", - "warning": "Undone reaction rolls will be considered as failed" + "unfinishedRolls": "Some Tokens have not finished their Reaction Rolls.", + "warning": "Unfinished reaction rolls will be considered as failed.", + "confirmation": "Are you sure you want to continue?" }, "ReactionRoll": { "title": "Reaction Roll: {trait}" diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 78bab016..893e6e5c 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -183,7 +183,11 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { if (pendingingSaves.length) { const confirm = await foundry.applications.api.DialogV2.confirm({ window: { title: game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.title') }, - content: `

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

` + content: ` +

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

+

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

+

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

+ ` }); if (!confirm) return; } @@ -247,8 +251,24 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const targets = this.filterPermTargets(this.system.hitTargets), config = foundry.utils.deepClone(this.system); config.event = event; + if (targets.length === 0) - ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm')); + return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm')); + else if (config.hasSave) { + const pendingingSaves = targets.filter(t => t.saved.success === null); + if (pendingingSaves.length) { + const confirm = await foundry.applications.api.DialogV2.confirm({ + window: { title: game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.title') }, + content: ` +

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.unfinishedRolls')}

+

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.warning')}

+

${game.i18n.localize('DAGGERHEART.APPLICATIONS.PendingReactionsDialog.confirmation')}

+ ` + }); + if (!confirm) return; + } + } + this.consumeOnSuccess(); this.system.action?.workflow.get('effects')?.execute(config, targets, true); } From 3c36c5747d477a831d6b0d5a653a414073f6f39c Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:02:42 +0200 Subject: [PATCH 5/7] [Fix] Base Attack Context Menu (#1961) * Fixed Adversary standard attack context menu * Fixed Character base attack context menu * Fixed Companion base attack context menu --- .../applications/sheets/actors/adversary.mjs | 10 +++++ .../applications/sheets/actors/character.mjs | 8 ++++ .../applications/sheets/actors/companion.mjs | 12 +++++- module/applications/sheets/api/base-actor.mjs | 37 +++++++++++++++++++ module/data/action/attackAction.mjs | 7 +++- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/module/applications/sheets/actors/adversary.mjs b/module/applications/sheets/actors/adversary.mjs index 04be3efb..06dd4a0f 100644 --- a/module/applications/sheets/actors/adversary.mjs +++ b/module/applications/sheets/actors/adversary.mjs @@ -31,6 +31,16 @@ export default class AdversarySheet extends DHBaseActorSheet { dragSelector: '[data-item-id][draggable="true"], [data-item-id] [draggable="true"]', dropSelector: null } + ], + contextMenus: [ + { + handler: DHBaseActorSheet.getBaseAttackContextOptions, + selector: '[data-item-uuid][data-type="attack"]', + options: { + parentClassHooks: false, + fixed: true + } + } ] }; diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 19b82712..e4d0e6d9 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -65,6 +65,14 @@ export default class CharacterSheet extends DHBaseActorSheet { fixed: true } }, + { + handler: DHBaseActorSheet.getBaseAttackContextOptions, + selector: '[data-item-uuid][data-type="attack"]', + options: { + parentClassHooks: false, + fixed: true + } + }, { handler: CharacterSheet.#getDomainCardContextOptions, selector: '[data-item-uuid][data-type="domainCard"]', diff --git a/module/applications/sheets/actors/companion.mjs b/module/applications/sheets/actors/companion.mjs index b30b9c07..a01b4a64 100644 --- a/module/applications/sheets/actors/companion.mjs +++ b/module/applications/sheets/actors/companion.mjs @@ -11,7 +11,17 @@ export default class DhCompanionSheet extends DHBaseActorSheet { toggleStress: DhCompanionSheet.#toggleStress, actionRoll: DhCompanionSheet.#actionRoll, levelManagement: DhCompanionSheet.#levelManagement - } + }, + contextMenus: [ + { + handler: DHBaseActorSheet.getBaseAttackContextOptions, + selector: '[data-item-uuid][data-type="attack"]', + options: { + parentClassHooks: false, + fixed: true + } + } + ] }; static PARTS = { diff --git a/module/applications/sheets/api/base-actor.mjs b/module/applications/sheets/api/base-actor.mjs index 5cd0f6a5..7b820822 100644 --- a/module/applications/sheets/api/base-actor.mjs +++ b/module/applications/sheets/api/base-actor.mjs @@ -189,6 +189,43 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) { return this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true }); } + /** + * Get the set of ContextMenu options for the base attack. + * @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance + * @this {CharacterSheet} + * @protected + */ + static getBaseAttackContextOptions() { + /**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */ + return [ + { + label: 'DAGGERHEART.CONFIG.RollTypes.attack.name', + icon: 'fa-solid fa-burst', + onClick: async (event, target) => (await getDocFromElement(target)).use(event) + }, + { + label: 'DAGGERHEART.GENERAL.damage', + icon: 'fa-solid fa-explosion', + onClick: async (event, target) => { + const doc = await getDocFromElement(target), + action = doc?.system?.attack ?? doc; + const config = action.prepareConfig(event); + config.effects = await game.system.api.data.actions.actionsTypes.base.getEffects( + this.document, + doc + ); + config.hasRoll = false; + return action && action.workflow.get('damage').execute(config, null, true); + } + }, + { + label: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat', + icon: 'fa-solid fa-message', + onClick: async (_, target) => (await getDocFromElement(target)).toChat(this.document.uuid) + } + ]; + } + /* -------------------------------------------- */ /* Application Listener Actions */ /* -------------------------------------------- */ diff --git a/module/data/action/attackAction.mjs b/module/data/action/attackAction.mjs index c4d07c25..1f7e1c92 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -75,7 +75,12 @@ export default class DHAttackAction extends DHDamageAction { const useAltDamage = this.actor?.effects?.find(x => x.type === 'horde')?.active; for (const { value, valueAlt, type } of damage.parts) { const usedValue = useAltDamage ? valueAlt : value; - const str = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); + const damageString = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); + const str = damageString + ? damageString + : game.i18n.format('DAGGERHEART.GENERAL.missingX', { + x: game.i18n.localize('DAGGERHEART.GENERAL.damage') + }); const icons = Array.from(type) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) From d98a7c951e5363ce1980b1540767bad923385e64 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 1 Jun 2026 22:20:06 +0200 Subject: [PATCH 6/7] [Fix] Tooltip Color Scope (#1964) * Added DH style to tooltips * Setting dh-style for ResourceManagementTooltip and ArmorManagementTooltip --- module/applications/sheets/actors/character.mjs | 4 ++-- module/documents/tooltipManager.mjs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index e4d0e6d9..5d0e7144 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -1053,7 +1053,7 @@ export default class CharacterSheet extends DHBaseActorSheet { game.tooltip.activate(target, { html, locked: true, - cssClass: 'bordered-tooltip', + cssClass: 'bordered-tooltip dh-style', direction: 'DOWN' }); @@ -1149,7 +1149,7 @@ export default class CharacterSheet extends DHBaseActorSheet { game.tooltip.activate(target, { html, locked: true, - cssClass: 'bordered-tooltip', + cssClass: 'bordered-tooltip dh-style', direction: 'DOWN', noOffset: true }); diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index 18c03169..3e3f4a16 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -3,7 +3,6 @@ import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounter export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager { #wide = false; #bordered = false; - #active = false; async activate(element, options = {}) { const { TextEditor } = foundry.applications.ux; From 5dbcd9448064f97d202abb541cd5b4c5072fe544 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 1 Jun 2026 22:22:50 +0200 Subject: [PATCH 7/7] Raised version --- system.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system.json b/system.json index 5994c576..588ceafe 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "2.3.0", + "version": "2.3.1", "compatibility": { "minimum": "14.361", "verified": "14.363", @@ -10,7 +10,7 @@ }, "url": "https://github.com/Foundryborne/daggerheart", "manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json", - "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.3.0/system.zip", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.3.1/system.zip", "authors": [ { "name": "WBHarry"