From 1cece731ee151d3d0170e05294c7557b0df7c619 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 27 Apr 2026 16:06:33 +0200 Subject: [PATCH 01/10] Corrected Glowing Rings damage --- .../items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json b/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json index 8996dbc8..3879c599 100644 --- a/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json +++ b/src/packs/items/weapons/weapon_Glowing_Rings_wG9f5NpCwSbaLy8t.json @@ -45,7 +45,7 @@ "hitPoints": { "value": { "dice": "d10", - "bonus": 1, + "bonus": 2, "multiplier": "prof", "flatMultiplier": 1, "custom": { From ca32aa5d3529f407b1aafbbdbfd217dee4d90d13 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Tue, 28 Apr 2026 07:46:46 +0200 Subject: [PATCH 02/10] Fixed so that the delete option is available in the compendium (#1843) --- module/applications/sheets/api/application-mixin.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index e941931a..36477821 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -531,7 +531,7 @@ export default function DHApplicationMixin(Base) { visible: element => { const target = element.closest('[data-item-uuid]'); const doc = getDocFromElementSync(target); - return doc?.isOwner && target.dataset.itemType !== 'beastform'; + return doc?.isOwner !== false && target.dataset.itemType !== 'beastform'; }, callback: async (target, event) => { const doc = await getDocFromElement(target); From 118c52a996618e5be64fc6af91ea932c4ed9a9dc Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Tue, 28 Apr 2026 01:47:11 -0400 Subject: [PATCH 03/10] [Fix] console noise when starting a tag team dialog or group roll (#1842) --- daggerheart.mjs | 6 ++- .../applications/dialogs/groupRollDialog.mjs | 3 +- module/applications/dialogs/tagTeamDialog.mjs | 49 +++++++------------ templates/dialogs/tagTeamDialog/result.hbs | 38 ++++++++++++++ .../dialogs/tagTeamDialog/tagTeamRoll.hbs | 45 +++-------------- 5 files changed, 68 insertions(+), 73 deletions(-) create mode 100644 templates/dialogs/tagTeamDialog/result.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index e25f1b09..363430be 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -342,7 +342,8 @@ Hooks.on(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, async data => { const party = game.actors.get(data.partyId); if (!party) return; - const dialog = new game.system.api.applications.dialogs.TagTeamDialog(party); + const TagTeamDialog = game.system.api.applications.dialogs.TagTeamDialog; + const dialog = foundry.applications.instances.get(`TagTeamDialog-${party.id}`) ?? new TagTeamDialog(party); dialog.tabGroups.application = 'tagTeamRoll'; await dialog.render({ force: true }); } @@ -353,7 +354,8 @@ Hooks.on(CONFIG.DH.HOOKS.hooksConfig.groupRollStart, async data => { const party = game.actors.get(data.partyId); if (!party) return; - const dialog = new game.system.api.applications.dialogs.GroupRollDialog(party); + const GroupRollDialog = game.system.api.applications.dialogs.GroupRollDialog; + const dialog = foundry.applications.instances.get(`GroupRollDialog-${party.id}`) ?? new GroupRollDialog(party); dialog.tabGroups.application = 'groupRoll'; await dialog.render({ force: true }); } diff --git a/module/applications/dialogs/groupRollDialog.mjs b/module/applications/dialogs/groupRollDialog.mjs index df03a061..48110e4c 100644 --- a/module/applications/dialogs/groupRollDialog.mjs +++ b/module/applications/dialogs/groupRollDialog.mjs @@ -6,7 +6,7 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class GroupRollDialog extends HandlebarsApplicationMixin(ApplicationV2) { constructor(party) { - super(); + super({ id: `GroupRollDialog-${party.id}` }); this.party = party; this.partyMembers = party.system.partyMembers @@ -35,7 +35,6 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat static DEFAULT_OPTIONS = { tag: 'form', - id: 'GroupRollDialog', classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'group-roll-dialog'], position: { width: 390, height: 'auto' }, window: { diff --git a/module/applications/dialogs/tagTeamDialog.mjs b/module/applications/dialogs/tagTeamDialog.mjs index 026c4bc0..325cc445 100644 --- a/module/applications/dialogs/tagTeamDialog.mjs +++ b/module/applications/dialogs/tagTeamDialog.mjs @@ -7,7 +7,7 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class TagTeamDialog extends HandlebarsApplicationMixin(ApplicationV2) { constructor(party) { - super(); + super({ id: `TagTeamDialog-${party.id}` }); this.party = party; this.partyMembers = party.system.partyMembers @@ -36,7 +36,6 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio static DEFAULT_OPTIONS = { tag: 'form', - id: 'TagTeamDialog', classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'tag-team-dialog'], position: { width: 550, height: 'auto' }, actions: { @@ -60,13 +59,17 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio id: 'initialization', template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/initialization.hbs' }, + tagTeamRoll: { + id: 'tagTeamRoll', + template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs' + }, rollSelection: { id: 'rollSelection', template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/rollSelection.hbs' }, - tagTeamRoll: { - id: 'tagTeamRoll', - template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs' + result: { + id: 'result', + template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/result.hbs' } }; @@ -97,36 +100,15 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio } _configureRenderParts(options) { - const { initialization, rollSelection, tagTeamRoll } = super._configureRenderParts(options); - const augmentedParts = { initialization }; + const parts = super._configureRenderParts(options); for (const memberKey of Object.keys(this.party.system.tagTeam.members)) { - augmentedParts[memberKey] = { + parts[memberKey] = { id: memberKey, template: 'systems/daggerheart/templates/dialogs/tagTeamDialog/tagTeamMember.hbs' }; } - augmentedParts.rollSelection = rollSelection; - augmentedParts.tagTeamRoll = tagTeamRoll; - return augmentedParts; - } - - /**@inheritdoc */ - async _onRender(context, options) { - await super._onRender(context, options); - - // if (this.element.querySelector('.roll-selection')) { - // for (const element of this.element.querySelectorAll('.team-member-container')) { - // element.classList.add('select-padding'); - // } - // } - - if (this.element.querySelector('.team-container')) return; - const initializationPart = this.element.querySelector('.initialization-container'); - initializationPart.insertAdjacentHTML('afterend', '
'); - const teamContainer = this.element.querySelector('.team-container'); - for (const memberContainer of this.element.querySelectorAll('.team-member-container')) - teamContainer.appendChild(memberContainer); + return parts; } async _prepareContext(_options) { @@ -167,6 +149,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio partContext.initiatorDisabled = !selectedMembers.length; partContext.openForAllPlayers = this.openForAllPlayers; + break; + case 'tagTeamRoll': + partContext.memberKeys = Object.keys(this.party.system.tagTeam.members); break; case 'rollSelection': partContext.members = Object.keys(this.party.system.tagTeam.members).reduce((acc, key) => { @@ -175,7 +160,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio return acc; }, {}); break; - case 'tagTeamRoll': + case 'result': const selectedRoll = Object.values(this.party.system.tagTeam.members).find(member => member.selected); const critSelected = !selectedRoll ? undefined @@ -243,7 +228,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio } getUpdatingParts(target) { - const { initialization, rollSelection, tagTeamRoll } = this.constructor.PARTS; + const { initialization, rollSelection, result } = this.constructor.PARTS; const isInitialization = this.tabGroups.application === initialization.id; const updatingMember = target.closest('.team-member-container')?.dataset?.memberKey; @@ -251,7 +236,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio ...(isInitialization ? [initialization.id] : []), ...(updatingMember ? [updatingMember] : []), ...(!isInitialization ? [rollSelection.id] : []), - ...(!isInitialization ? [tagTeamRoll.id] : []) + ...(!isInitialization ? [result.id] : []) ]; } diff --git a/templates/dialogs/tagTeamDialog/result.hbs b/templates/dialogs/tagTeamDialog/result.hbs new file mode 100644 index 00000000..79b5138e --- /dev/null +++ b/templates/dialogs/tagTeamDialog/result.hbs @@ -0,0 +1,38 @@ +
+
+
+ {{localize "DAGGERHEART.GENERAL.result.plural"}} +
+ {{#if hintText}} +
{{localize hintText}}
+ {{else}} + {{#if joinedRoll.roll}} +
+ +
+
{{joinedRoll.roll.total}}
+
{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}
+
+
+ {{/if}} + {{#if joinedRoll.rollData.options.hasDamage}} +
+ + {{#each joinedRoll.rollData.options.damage as |damage key|}} +
+
{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}
+
{{damage.total}}
+
+ {{/each}} +
+ {{/if}} + {{/if}} +
+
+ +
+ + +
+
+
\ No newline at end of file diff --git a/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs b/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs index 79b5138e..1a4b974b 100644 --- a/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs +++ b/templates/dialogs/tagTeamDialog/tagTeamRoll.hbs @@ -1,38 +1,9 @@ -
-
-
- {{localize "DAGGERHEART.GENERAL.result.plural"}} -
- {{#if hintText}} -
{{localize hintText}}
- {{else}} - {{#if joinedRoll.roll}} -
- -
-
{{joinedRoll.roll.total}}
-
{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}
-
-
- {{/if}} - {{#if joinedRoll.rollData.options.hasDamage}} -
- - {{#each joinedRoll.rollData.options.damage as |damage key|}} -
-
{{localize (concat "DAGGERHEART.CONFIG.HealingType." key ".name")}}
-
{{damage.total}}
-
- {{/each}} -
- {{/if}} - {{/if}} -
-
- -
- - -
+
+
+ {{#each memberKeys as |key|}} +
+ {{/each}}
-
\ No newline at end of file +
+
+ From 20056cd950682297be0aea223865ddfe2abae184 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Wed, 29 Apr 2026 22:04:08 +0200 Subject: [PATCH 04/10] Corrected contributing link in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c2dabc3..f59143fd 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ You can find the documentation here: https://github.com/Foundryborne/daggerheart ## Contributing -Looking to contribute to the project? Look no further, check out our [contributing guide](contributing.md), and keep the [Code of Conduct](coc.md) in mind when working on things. +Looking to contribute to the project? Look no further, check out our [contributing guide](CONTRIBUTING.md), and keep the [Code of Conduct](coc.md) in mind when working on things. ## Disclaimer: From 404640a0a3fa23463101447768c61c4fd2edb3b9 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Fri, 1 May 2026 17:45:50 +0200 Subject: [PATCH 05/10] Fixed SRD DireBat experience value --- .../adversary_Dire_Bat_tBWHW00epmMnkawe.json | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json b/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json index c2064395..a1107f7c 100644 --- a/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json +++ b/src/packs/adversaries/adversary_Dire_Bat_tBWHW00epmMnkawe.json @@ -40,7 +40,8 @@ "experiences": { "ti3Z1mq2M92KK4GJ": { "name": "Bloodthirsty", - "description": "" + "description": "", + "value": 3 } }, "bonuses": { @@ -242,27 +243,24 @@ "type": "withinRange", "target": "hostile", "range": "melee" - } + }, + "changes": [ + { + "key": "system.difficulty", + "value": 3, + "priority": null, + "type": "add" + } + ] }, "_id": "qZfNiqw1iAIxeuYg", "img": "icons/commodities/biological/wing-lizard-brown.webp", - "changes": [ - { - "key": "system.difficulty", - "mode": 2, - "value": "3", - "priority": null - } - ], "disabled": false, "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null + "value": null, + "units": "seconds", + "expiry": null, + "expired": false }, "description": "

While flying, the Bat gains a +3 bonus to their Difficulty.

", "origin": null, @@ -274,6 +272,9 @@ "_stats": { "compendiumSource": null }, + "start": null, + "showIcon": 1, + "folder": null, "_key": "!actors.items.effects!tBWHW00epmMnkawe.gx22MpD8fWoi8klZ.qZfNiqw1iAIxeuYg" } ], From b22ce9697dd6c8d809b3cb4f336f4acd9b24a1e7 Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Fri, 1 May 2026 14:54:18 -0400 Subject: [PATCH 06/10] Fix detection of negative modifiers (#1847) --- module/dice/dhRoll.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 209631f6..83dbbaf2 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -257,7 +257,7 @@ export default class DHRoll extends Roll { if (!roll.terms[i].isDeterministic) continue; const termTotal = roll.terms[i].total; if (typeof termTotal === 'number') { - const multiplier = roll.terms[i - 1]?.operator === ' - ' ? -1 : 1; + const multiplier = roll.terms[i - 1]?.operator === '-' ? -1 : 1; modifierTotal += multiplier * termTotal; } } From 905d1f7e885fb91bcba255348620dac7a0a35d33 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Fri, 1 May 2026 20:58:21 +0200 Subject: [PATCH 07/10] Corrected a typo in Greater Earth Elemental and Huge Green Ooze --- ...rsary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json | 2 +- .../adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json b/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json index e59d2683..72ad8ae2 100644 --- a/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json +++ b/src/packs/adversaries/adversary_Greater_Earth_Elemental_dsfB3YhoL5SudvS2.json @@ -249,7 +249,7 @@ "name": "Crushing Blows", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefi ts (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", + "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefits (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", "resource": null, "actions": { "0sXciTiPc30v8czv": { diff --git a/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json b/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json index 1615dec8..183719f2 100644 --- a/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json +++ b/src/packs/adversaries/adversary_Huge_Green_Ooze_6hbqmxDXFOzZJDk4.json @@ -138,12 +138,9 @@ "src": "systems/daggerheart/assets/icons/documents/actors/dragon-head.svg", "anchorX": 0.5, "anchorY": 0.5, - "offsetX": 0, - "offsetY": 0, "fit": "contain", "scaleX": 1, "scaleY": 1, - "rotation": 0, "tint": "#ffffff", "alphaThreshold": 0.75 }, @@ -194,7 +191,7 @@ "saturation": 0, "contrast": 0 }, - "detectionModes": [], + "detectionModes": {}, "occludable": { "radius": 0 }, @@ -220,7 +217,8 @@ "flags": {}, "randomImg": false, "appendNumber": false, - "prependAdjective": false + "prependAdjective": false, + "depth": 1 }, "items": [ { @@ -257,7 +255,7 @@ "name": "Acidic Form", "type": "feature", "system": { - "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefi ts (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", + "description": "

When the @Lookup[@name] makes a successful attack, the target must mark an Armor Slot without receiving its benefits (they can still use armor to reduce the damage). If they can’t mark an Armor Slot, they must mark an additional HP.

", "resource": null, "actions": { "gtT2oHSyZg9OHHJD": { From d0c2c783f1fbf3ab1ab6057bbadf8febf828d865 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 1 May 2026 22:53:20 +0200 Subject: [PATCH 08/10] Improved armor source names (#1851) --- module/applications/dialogs/damageReductionDialog.mjs | 11 +++-------- module/helpers/utils.mjs | 5 ++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/module/applications/dialogs/damageReductionDialog.mjs b/module/applications/dialogs/damageReductionDialog.mjs index 930ca1a1..b916a5de 100644 --- a/module/applications/dialogs/damageReductionDialog.mjs +++ b/module/applications/dialogs/damageReductionDialog.mjs @@ -22,9 +22,10 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap ); const orderedArmorSources = getArmorSources(actor).filter(s => !s.disabled); - const armor = orderedArmorSources.reduce((acc, { document }) => { + const armor = orderedArmorSources.reduce((acc, { name, document }) => { const { current, max } = document.type === 'armor' ? document.system.armor : document.system.armorData; acc.push({ + name, effect: document, marks: [...Array(max).keys()].reduce((acc, _, index) => { const spent = index < current; @@ -152,14 +153,8 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap const armorSources = []; for (const source of this.marks.armor) { - const parent = source.effect.origin - ? await foundry.utils.fromUuid(source.effect.origin) - : source.effect.parent; - - const useEffectName = parent.type === 'armor' || parent instanceof Actor; - const label = useEffectName ? source.effect.name : parent.name; armorSources.push({ - label: label, + label: source.name, uuid: source.effect.uuid, marks: source.marks }); diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 1650b505..faa046ff 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -757,9 +757,12 @@ export function getArmorSources(actor) { // Get the origin item. Since the actor is already loaded, it should already be cached // Consider the relative function versions if this causes an issue const origin = doc.origin ? foundry.utils.fromUuidSync(doc.origin) : doc; + const useParentName = doc.parent && !(doc.parent instanceof Actor); + const name = doc.origin || !useParentName ? doc.name : doc.parent.name; + return { origin, - name: origin.name, + name, document: doc, data: doc.system.armor ?? doc.system.armorData, disabled: !!doc.disabled || !!doc.isSuppressed From c7159eff112154b3213e1b72a209ddff5942bb5c Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Fri, 1 May 2026 17:00:03 -0400 Subject: [PATCH 09/10] Fix retrieving parent documents when the model is null (#1853) --- module/documents/activeEffect.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 08463818..f9239a90 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -171,6 +171,7 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { /** Recursively finds the first parent document of the given object */ static #resolveParentDocument(model, documentClass) { + if (!model) return null; return model instanceof documentClass ? model : model.parent From 4558fbdcf618314c1460360377015b3229e17b0c Mon Sep 17 00:00:00 2001 From: WBHarry Date: Fri, 1 May 2026 23:09:45 +0200 Subject: [PATCH 10/10] Raised version --- system.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system.json b/system.json index 9b8a8403..deb30b53 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.2.1", + "version": "2.2.2", "compatibility": { "minimum": "14.359", "verified": "14.360", @@ -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.2.1/system.zip", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.2/system.zip", "authors": [ { "name": "WBHarry"