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 01/15] 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 02/15] [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 03/15] 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 04/15] 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 05/15] 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 06/15] 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 07/15] 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 08/15] 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 09/15] 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" From 4685ec3c778398fe3499939bf4de3a1000cbaba5 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 May 2026 21:58:10 +0200 Subject: [PATCH 10/15] Added event.stopPropagation to avoid double matches and therefore double drops on drag/drop (#1860) --- module/applications/sheets-configs/adversary-settings.mjs | 1 + module/applications/sheets-configs/environment-settings.mjs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index 6593f23d..57405675 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -110,6 +110,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { } async _onDrop(event) { + event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const item = await fromUuid(data.uuid); diff --git a/module/applications/sheets-configs/environment-settings.mjs b/module/applications/sheets-configs/environment-settings.mjs index bc0efef2..6d74f9c6 100644 --- a/module/applications/sheets-configs/environment-settings.mjs +++ b/module/applications/sheets-configs/environment-settings.mjs @@ -121,6 +121,7 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings { } async _onDrop(event) { + event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const item = await fromUuid(data.uuid); if (data.fromInternal && item?.parent?.uuid === this.actor.uuid) return; @@ -138,8 +139,4 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings { this.render(); } } - - async _onDropItem(event, item) { - console.log(item); - } } From 94e93222a49e4eba5f63aa8a145da161698c2671 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 May 2026 22:01:16 +0200 Subject: [PATCH 11/15] [Fix] Downtime Use Reset RollData (#1857) --- module/applications/dialogs/downtime.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/applications/dialogs/downtime.mjs b/module/applications/dialogs/downtime.mjs index 989e4625..367540bf 100644 --- a/module/applications/dialogs/downtime.mjs +++ b/module/applications/dialogs/downtime.mjs @@ -259,7 +259,9 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV const resetValue = increasing ? 0 : feature.system.resource.max - ? new Roll(Roll.replaceFormulaData(feature.system.resource.max, this.actor)).evaluateSync().total + ? new Roll( + Roll.replaceFormulaData(feature.system.resource.max, this.actor.getRollData()) + ).evaluateSync().total : 0; await feature.update({ 'system.resource.value': resetValue }); From 516928f92be81cb646d98a85d216c56b5e2acd2a Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 May 2026 22:02:57 +0200 Subject: [PATCH 12/15] Fixed a data path error in character._preUpdate when scars are changed by an update (#1856) --- module/data/actor/character.mjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index d42f2f64..a1cd13e8 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -836,10 +836,10 @@ export default class DhCharacter extends DhCreature { /* Scars can alter the amount of current hope */ if (changes.system?.scars) { - const diff = this.system.scars - changes.system.scars; - const newHopeMax = this.system.resources.hope.max + diff; - const newHopeValue = Math.min(newHopeMax, this.system.resources.hope.value); - if (newHopeValue != this.system.resources.hope.value) { + const diff = this.scars - changes.system.scars; + const newHopeMax = this.resources.hope.max + diff; + const newHopeValue = Math.min(newHopeMax, this.resources.hope.value); + if (newHopeValue != this.resources.hope.value) { if (!changes.system.resources.hope) changes.system.resources.hope = { value: 0 }; changes.system.resources.hope = { From 54d1b2bdc061a95be702d8f6c201e6348c85106f Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 May 2026 22:04:52 +0200 Subject: [PATCH 13/15] [Fix] 1854 - Delete Scene Environments (#1858) --- module/applications/scene/sceneConfigSettings.mjs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/module/applications/scene/sceneConfigSettings.mjs b/module/applications/scene/sceneConfigSettings.mjs index ce312a45..0a999506 100644 --- a/module/applications/scene/sceneConfigSettings.mjs +++ b/module/applications/scene/sceneConfigSettings.mjs @@ -120,12 +120,6 @@ export default class DhSceneConfigSettings extends foundry.applications.sheets.S foundry.utils.fromUuidSync(x) ); - for (const key of Object.keys(this.document._source.flags.daggerheart?.sceneEnvironments ?? {})) { - if (!submitData.flags.daggerheart.sceneEnvironments[key]) { - submitData.flags.daggerheart.sceneEnvironments[key] = _del; - } - } - super._processSubmitData(event, form, submitData, options); } } From edbf5aa55f09acdce4d7d611d793923daf9081c6 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 May 2026 22:34:53 +0200 Subject: [PATCH 14/15] [Fix] Player Created Regions (#1855) * Fixed so that creating regions without behaviors work for players. Fixed so that creating regions with behaviors works via GmEmit for players * Updated previous uses of emitAsGM to emitGMUpdate * Fixed linting * Update module/documents/chatMessage.mjs Co-authored-by: Carlos Fernandez --------- Co-authored-by: Carlos Fernandez --- lang/en.json | 3 +- .../applications/dialogs/groupRollDialog.mjs | 4 +- module/applications/dialogs/tagTeamDialog.mjs | 4 +- module/applications/ui/countdownEdit.mjs | 4 +- module/applications/ui/countdowns.mjs | 8 +-- module/applications/ui/fearTracker.mjs | 4 +- module/applications/ui/sceneNavigation.mjs | 4 +- module/canvas/placeables/regionLayer.mjs | 12 ++-- module/data/fields/action/countdownField.mjs | 4 +- module/data/fields/action/effectsField.mjs | 4 +- module/documents/actor.mjs | 6 +- module/documents/chatMessage.mjs | 66 ++++++++++++------- module/systemRegistration/socket.mjs | 54 ++++++++++----- 13 files changed, 108 insertions(+), 69 deletions(-) diff --git a/lang/en.json b/lang/en.json index b4b1410e..817fc355 100755 --- a/lang/en.json +++ b/lang/en.json @@ -3220,7 +3220,8 @@ "domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used", "knowTheTide": "Know The Tide gained a token", "lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}", - "noTokenTargeted": "No token is targeted" + "noTokenTargeted": "No token is targeted", + "behaviorRegionRequiresGM": "Creating a Region with an attached Behavior requires an online GM" }, "Progress": { "migrationLabel": "Performing system migration. Please wait and do not close Foundry." diff --git a/module/applications/dialogs/groupRollDialog.mjs b/module/applications/dialogs/groupRollDialog.mjs index 48110e4c..bd45fe91 100644 --- a/module/applications/dialogs/groupRollDialog.mjs +++ b/module/applications/dialogs/groupRollDialog.mjs @@ -1,5 +1,5 @@ import { ResourceUpdateMap } from '../../data/action/baseAction.mjs'; -import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import Party from '../sheets/actors/party.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -242,7 +242,7 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat }); }; - await emitAsGM( + await emitGMUpdate( GMUpdateEvent.UpdateDocument, gmUpdate, update, diff --git a/module/applications/dialogs/tagTeamDialog.mjs b/module/applications/dialogs/tagTeamDialog.mjs index 325cc445..e06cbe48 100644 --- a/module/applications/dialogs/tagTeamDialog.mjs +++ b/module/applications/dialogs/tagTeamDialog.mjs @@ -1,6 +1,6 @@ import { MemberData } from '../../data/tagTeamData.mjs'; import { getCritDamageBonus } from '../../helpers/utils.mjs'; -import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import Party from '../sheets/actors/party.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -259,7 +259,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio }); }; - await emitAsGM( + await emitGMUpdate( GMUpdateEvent.UpdateDocument, gmUpdate, update, diff --git a/module/applications/ui/countdownEdit.mjs b/module/applications/ui/countdownEdit.mjs index 8bb9fc1d..b418107c 100644 --- a/module/applications/ui/countdownEdit.mjs +++ b/module/applications/ui/countdownEdit.mjs @@ -1,6 +1,6 @@ import { DhCountdown } from '../../data/countdowns.mjs'; import { waitForDiceSoNice } from '../../helpers/utils.mjs'; -import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -114,7 +114,7 @@ export default class CountdownEdit extends HandlebarsApplicationMixin(Applicatio } await this.data.updateSource(update); - await emitAsGM(GMUpdateEvent.UpdateCountdowns, this.gmSetSetting.bind(this.data), this.data, null, { + await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, this.gmSetSetting.bind(this.data), this.data, null, { refreshType: RefreshType.Countdown }); diff --git a/module/applications/ui/countdowns.mjs b/module/applications/ui/countdowns.mjs index 79a59a07..052564cc 100644 --- a/module/applications/ui/countdowns.mjs +++ b/module/applications/ui/countdowns.mjs @@ -1,5 +1,5 @@ import { waitForDiceSoNice } from '../../helpers/utils.mjs'; -import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -204,7 +204,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application start: newMax } }); - await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { + await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { refreshType: RefreshType.Countdown }); } @@ -218,7 +218,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application ? Math.min(countdown.progress.current + 1, countdown.progress.start) : Math.max(countdown.progress.current - 1, 0); await settings.updateSource({ [`countdowns.${target.id}.progress.current`]: newCurrent }); - await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { + await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { refreshType: RefreshType.Countdown }); } @@ -277,7 +277,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application return acc; }, {}) }; - await emitAsGM(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { + await emitGMUpdate(GMUpdateEvent.UpdateCountdowns, DhCountdowns.gmSetSetting.bind(settings), settings, null, { refreshType: RefreshType.Countdown }); } diff --git a/module/applications/ui/fearTracker.mjs b/module/applications/ui/fearTracker.mjs index 4e5e1132..8c247f79 100644 --- a/module/applications/ui/fearTracker.mjs +++ b/module/applications/ui/fearTracker.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -104,7 +104,7 @@ export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV } async updateFear(value) { - return emitAsGM( + return emitGMUpdate( GMUpdateEvent.UpdateFear, game.settings.set.bind(game.settings, CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), value diff --git a/module/applications/ui/sceneNavigation.mjs b/module/applications/ui/sceneNavigation.mjs index a0005fc7..982063e7 100644 --- a/module/applications/ui/sceneNavigation.mjs +++ b/module/applications/ui/sceneNavigation.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent } from '../../systemRegistration/socket.mjs'; export default class DhSceneNavigation extends foundry.applications.ui.SceneNavigation { /** @inheritdoc */ @@ -68,7 +68,7 @@ export default class DhSceneNavigation extends foundry.applications.ui.SceneNavi 1 )[0]; newEnvironments.unshift(newFirst); - emitAsGM( + emitGMUpdate( GMUpdateEvent.UpdateDocument, scene.update.bind(scene), { 'flags.daggerheart.sceneEnvironments': newEnvironments }, diff --git a/module/canvas/placeables/regionLayer.mjs b/module/canvas/placeables/regionLayer.mjs index c53cf782..684fdd5e 100644 --- a/module/canvas/placeables/regionLayer.mjs +++ b/module/canvas/placeables/regionLayer.mjs @@ -57,14 +57,14 @@ export default class DhRegionLayer extends foundry.canvas.layers.RegionLayer { } async placeRegion(data, options = {}) { - const preConfirm = ({ _event, document, _create, _options }) => { - const shape = document.shapes[0]; + const preConfirm = data => { + const shape = data.document.shapes[0]; const isEmanation = shape.type === 'emanation'; if (isEmanation) { const token = this.#findTokenInBounds(shape.base.origin); - if (!token) return options.preConfirm?.() ?? true; + if (!token) return options.preConfirm?.(data) ?? true; const shapeData = shape.toObject(); - document.updateSource({ + data.document.updateSource({ shapes: [ { ...shapeData, @@ -80,10 +80,10 @@ export default class DhRegionLayer extends foundry.canvas.layers.RegionLayer { }); } - return options?.preConfirm?.() ?? true; + return options?.preConfirm?.(data) ?? true; }; - super.placeRegion(data, { ...options, preConfirm }); + return await super.placeRegion(data, { ...options, preConfirm }); } /** Searches for token at origin point, returning null if there are no tokens or multiple overlapping tokens */ diff --git a/module/data/fields/action/countdownField.mjs b/module/data/fields/action/countdownField.mjs index 719ca749..990f8ef1 100644 --- a/module/data/fields/action/countdownField.mjs +++ b/module/data/fields/action/countdownField.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent, RefreshType, socketEvent } from '../../../systemRegistration/socket.mjs'; const fields = foundry.data.fields; @@ -78,7 +78,7 @@ export default class CountdownField extends fields.ArrayField { ); } - await emitAsGM( + await emitGMUpdate( GMUpdateEvent.UpdateCountdowns, async () => { const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); diff --git a/module/data/fields/action/effectsField.mjs b/module/data/fields/action/effectsField.mjs index 9a4ffc31..1053e51d 100644 --- a/module/data/fields/action/effectsField.mjs +++ b/module/data/fields/action/effectsField.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent } from '../../../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent } from '../../../systemRegistration/socket.mjs'; const fields = foundry.data.fields; @@ -34,7 +34,7 @@ export default class EffectsField extends fields.ArrayField { } if (EffectsField.getAutomation() || force) { targets ??= (message.system?.targets ?? config.targets).filter(t => !config.hasRoll || t.hit); - await emitAsGM(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid); + await emitGMUpdate(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid); // EffectsField.applyEffects.call(this, config.targets.filter(t => !config.hasRoll || t.hit)); } } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index eb57a186..5df87b6c 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; +import { emitGMUpdate, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; import { createScrollText, damageKeyToNumber, getDamageKey, createShallowProxy } from '../helpers/utils.mjs'; @@ -827,7 +827,7 @@ export default class DhpActor extends Actor { const u = updates[key]; if (key === 'items') { Object.values(u).forEach(async item => { - await emitAsGM( + await emitGMUpdate( GMUpdateEvent.UpdateDocument, item.target.update.bind(item.target), item.resources, @@ -836,7 +836,7 @@ export default class DhpActor extends Actor { }); } else { if (Object.keys(u.resources).length > 0) { - await emitAsGM( + await emitGMUpdate( GMUpdateEvent.UpdateDocument, u.target.update.bind(u.target), u.resources, diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 2e20fb87..78bab016 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -1,4 +1,4 @@ -import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; +import { emitGMUpdate, emitGMCreate, GMUpdateEvent } from '../systemRegistration/socket.mjs'; export default class DhpChatMessage extends foundry.documents.ChatMessage { targetHook = null; @@ -214,7 +214,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const action = this.system.action; if (!action || !action?.hasSave) return; game.system.api.fields.ActionFields.SaveField.rollSave.call(action, token.actor, event).then(result => - emitAsGM( + emitGMUpdate( GMUpdateEvent.UpdateSaveMessage, game.system.api.fields.ActionFields.SaveField.updateSaveMessage.bind( action, @@ -259,27 +259,47 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { const { shape: type, size: range } = selectedArea; const shapeData = CONFIG.Canvas.layers.regions.layerClass.getTemplateShape({ type, range }); - await canvas.regions.placeRegion( - { - name: selectedArea.name, - shapes: [shapeData], - restriction: { enabled: false, type: 'move', priority: 0 }, - behaviors: [ - { - name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'), - type: 'applyActiveEffect', - system: { - effects: effects - } - } - ], - displayMeasurements: true, - locked: false, - ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE }, - visibility: CONST.REGION_VISIBILITY.ALWAYS - }, - { create: true } - ); + const scene = game.scenes.get(game.user.viewedScene); + const level = scene.levels.find(x => x.isView); + + const regionData = { + name: selectedArea.name, + levels: level ? [level.id] : [], + shapes: [shapeData], + restriction: { enabled: false, type: 'move', priority: 0 }, + behaviors: + effects.length > 0 + ? [ + { + name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'), + type: 'applyActiveEffect', + system: { + effects: effects + } + } + ] + : [], + displayMeasurements: true, + locked: false, + ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE }, + visibility: CONST.REGION_VISIBILITY.ALWAYS + }; + const placeRegion = data => { + canvas.regions.placeRegion(data, { create: true }); + }; + + // Regions with effects must be placed by the GM + if (effects.length > 0 && !game.user.isGM) { + if (!game.users.activeGM) + return ui.notifications.error( + game.i18n.localize('DAGGERHEART.UI.Notifications.behaviorRegionRequiresGM') + ); + + const region = await canvas.regions.placeRegion(regionData, { create: false }); + emitGMCreate('Region', placeRegion, region, scene.id); + } else { + placeRegion(regionData); + } }; if (this.system.action.areas.length === 1) createArea(this.system.action.areas[0]); diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index 8fed346d..de9bf00c 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -6,6 +6,9 @@ export function handleSocketEvent({ action = null, data = {} } = {}) { case socketEvent.GMUpdate: Hooks.callAll(socketEvent.GMUpdate, data); break; + case socketEvent.GMCreate: + Hooks.callAll(socketEvent.GMCreate, data); + break; case socketEvent.DhpFearUpdate: Hooks.callAll(socketEvent.DhpFearUpdate); break; @@ -25,6 +28,7 @@ export function handleSocketEvent({ action = null, data = {} } = {}) { export const socketEvent = { GMUpdate: 'DhGMUpdate', + GMCreate: 'DhGMCreate', Refresh: 'DhRefresh', DhpFearUpdate: 'DhFearUpdate', DowntimeTrigger: 'DowntimeTrigger', @@ -56,14 +60,14 @@ export const registerSocketHooks = () => { const document = data.uuid ? await fromUuid(data.uuid) : null; switch (data.action) { case GMUpdateEvent.UpdateDocument: - if (document && data.update) await document.update(data.update); + if (document && data.data) await document.update(data.data); break; case GMUpdateEvent.UpdateEffect: - if (document && data.update) - await game.system.api.fields.ActionFields.EffectsField.applyEffects.call(document, data.update); + if (document && data.data) + await game.system.api.fields.ActionFields.EffectsField.applyEffects.call(document, data.data); break; case GMUpdateEvent.UpdateSetting: - await game.settings.set(CONFIG.DH.id, data.uuid, data.update); + await game.settings.set(CONFIG.DH.id, data.uuid, data.data); break; case GMUpdateEvent.UpdateFear: await game.settings.set( @@ -73,22 +77,22 @@ export const registerSocketHooks = () => { 0, Math.min( game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear, - data.update + data.data ) ) ); break; case GMUpdateEvent.UpdateCountdowns: - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data.update); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, data.data); Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); break; case GMUpdateEvent.UpdateSaveMessage: - const message = game.messages.get(data.update.message); + const message = game.messages.get(data.data.message); if (!message) return; game.system.api.fields.ActionFields.SaveField.updateSaveMessage( - data.update.result, + data.data.result, message, - data.update.token + data.data.token ); break; } @@ -102,6 +106,17 @@ export const registerSocketHooks = () => { } } }); + + Hooks.on(socketEvent.GMCreate, async ({ data, documentType, scene }) => { + if (!game.user.isGM) return; + + switch (documentType) { + default: + const cls = getDocumentClass(documentType); + cls.create(data, { parent: game.scenes.get(scene) }); + break; + } + }); }; export const registerUserQueries = () => { @@ -109,18 +124,21 @@ export const registerUserQueries = () => { CONFIG.queries.reactionRoll = game.system.api.fields.ActionFields.SaveField.rollSaveQuery; }; -export const emitAsGM = async (eventName, callback, update, uuid = null, refresh = null) => { +export const emitGMUpdate = async (eventName, callback, update, uuid = null, refresh = null) => { + return await emitAsGM(socketEvent.GMUpdate, { action: eventName, callback, data: update, uuid, refresh }); +}; + +export const emitGMCreate = async (documentType, callback, data, scene) => { + return await emitAsGM(socketEvent.GMCreate, { documentType, callback, data, scene }); +}; + +export const emitAsGM = async (event, data = { callback: () => {}, data: {} }) => { if (!game.user.isGM) { return await game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.GMUpdate, - data: { - action: eventName, - uuid, - update, - refresh - } + action: event, + data: data }); - } else return callback(update); + } else return data.callback(data.data); }; export const emitAsOwner = (eventName, userId, args) => { From 85ca7efc6de317ca52c30fbea50531a8f917f90a Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sat, 2 May 2026 23:02:24 +0200 Subject: [PATCH 15/15] Raised version --- system.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system.json b/system.json index deb30b53..ac581343 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.2", + "version": "2.2.3", "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.2/system.zip", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.3/system.zip", "authors": [ { "name": "WBHarry"