From 481ce46edf326da9828c5c43d3f064505c560896 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 16 Nov 2025 01:52:19 +0100 Subject: [PATCH] [Fix] Party Fixes (#1284) * Fixed deletion of characters in the world locking up the party actor * . * Fixed so leader in group roll gains resourcse * Fixed so party.inventory has the right controls * Corrected for added character purning * . --- lang/en.json | 5 +- module/applications/sheets/actors/party.mjs | 24 ++++--- module/applications/ui/chatLog.mjs | 14 +++- module/data/actor/character.mjs | 4 +- module/data/actor/party.mjs | 2 +- module/systemRegistration/migrations.mjs | 2 + .../less/sheets/actors/party/resources.less | 2 +- system.json | 4 +- .../sheets/actors/party/party-members.hbs | 1 + templates/sheets/actors/party/resources.hbs | 68 ++++++++++--------- .../partials/inventory-fieldset-items-V2.hbs | 1 + .../global/partials/inventory-item-V2.hbs | 44 ++++++------ 12 files changed, 104 insertions(+), 67 deletions(-) diff --git a/lang/en.json b/lang/en.json index 86f0359e..eb736f5e 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2624,7 +2624,7 @@ "cardTooHighLevel": "The card is too high level!", "duplicateCard": "You cannot select the same card more than once.", "duplicateCharacter": "This actor is already registered in the party members list.", - "onlyCharactersInPartySheet": "You can drag only characters to a party sheet.", + "onlyCharactersInPartySheet": "You can only drag characters, companions and adverasries to the party sheet.", "notPrimary": "The weapon is not a primary weapon!", "notSecondary": "The weapon is not a secondary weapon!", "itemTooHighTier": "The item must be from Tier1", @@ -2661,7 +2661,8 @@ "subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.", "gmRequired": "This action requires an online GM", "gmOnly": "This can only be accessed by the GM", - "noActorOwnership": "You do not have permissions for this character" + "noActorOwnership": "You do not have permissions for this character", + "documentIsMissing": "The {documentType} is missing from the world." }, "Sidebar": { "daggerheartMenu": { diff --git a/module/applications/sheets/actors/party.mjs b/module/applications/sheets/actors/party.mjs index a622dcec..8d009778 100644 --- a/module/applications/sheets/actors/party.mjs +++ b/module/applications/sheets/actors/party.mjs @@ -7,6 +7,7 @@ import { socketEvent } from '../../../systemRegistration/socket.mjs'; import GroupRollDialog from '../../dialogs/group-roll-dialog.mjs'; import DhpActor from '../../../documents/actor.mjs'; import DHItem from '../../../documents/item.mjs'; +import DhParty from '../../../data/actor/party.mjs'; export default class Party extends DHBaseActorSheet { constructor(options) { @@ -79,6 +80,9 @@ export default class Party extends DHBaseActorSheet { } }; + static ALLOWED_ACTOR_TYPES = ['character', 'companion', 'adversary']; + static DICE_ROLL_ACTOR_TYPES = ['character']; + async _onRender(context, options) { await super._onRender(context, options); this._createFilterMenus(); @@ -277,13 +281,17 @@ export default class Party extends DHBaseActorSheet { } static async #tagTeamRoll() { - new game.system.api.applications.dialogs.TagTeamDialog(this.document.system.partyMembers).render({ + new game.system.api.applications.dialogs.TagTeamDialog( + this.document.system.partyMembers.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) + ).render({ force: true }); } - static async #groupRoll(params) { - new GroupRollDialog(this.document.system.partyMembers).render({ force: true }); + static async #groupRoll(_params) { + new GroupRollDialog( + this.document.system.partyMembers.filter(x => Party.DICE_ROLL_ACTOR_TYPES.includes(x.type)) + ).render({ force: true }); } /** @@ -453,17 +461,17 @@ export default class Party extends DHBaseActorSheet { event.stopPropagation(); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - const item = await foundry.utils.fromUuid(data.uuid); + const document = await foundry.utils.fromUuid(data.uuid); - if (item instanceof DhpActor) { + if (document instanceof DhpActor && Party.ALLOWED_ACTOR_TYPES.includes(document.type)) { const currentMembers = this.document.system.partyMembers.map(x => x.uuid); if (currentMembers.includes(data.uuid)) { return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.duplicateCharacter')); } - await this.document.update({ 'system.partyMembers': [...currentMembers, item.uuid] }); - } else if (item instanceof DHItem) { - this.document.createEmbeddedDocuments('Item', [item.toObject()]); + await this.document.update({ 'system.partyMembers': [...currentMembers, document.uuid] }); + } else if (document instanceof DHItem) { + this.document.createEmbeddedDocuments('Item', [document.toObject()]); } else { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.onlyCharactersInPartySheet')); } diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 6b05fe74..c62affeb 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -192,9 +192,18 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo async groupRollButton(event, message) { const path = event.currentTarget.dataset.path; + const isLeader = path === 'leader'; const { actor: actorData, trait } = foundry.utils.getProperty(message.system, path); const actor = game.actors.get(actorData._id); + if (!actor) { + return ui.notifications.error( + game.i18n.format('DAGGERHEART.UI.Notifications.documentIsMissing', { + documentType: game.i18n.localize('TYPES.Actor.character') + }) + ); + } + if (!actor.testUserPermission(game.user, 'OWNER')) { return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.noActorOwnership')); } @@ -214,7 +223,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo hasRoll: true, skips: { createMessage: true, - resources: true + resources: !isLeader } }; const result = await actor.diceRoll({ @@ -225,6 +234,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo }) }); + if (!result) return; + await game.system.api.fields.ActionFields.CostField.execute.call({ actor }, result); + const newMessageData = foundry.utils.deepClone(message.system); foundry.utils.setProperty(newMessageData, `${path}.result`, result.roll); const renderData = { system: new game.system.api.models.chatMessages.config.groupRoll(newMessageData) }; diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 1cf082f7..645a50da 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -675,6 +675,8 @@ export default class DhCharacter extends BaseDataActor { } _getTags() { - return [this.class.value?.name, this.class.subclass?.name, this.community?.name, this.ancestry?.name].filter((t) => !!t); + return [this.class.value?.name, this.class.subclass?.name, this.community?.name, this.ancestry?.name].filter( + t => !!t + ); } } diff --git a/module/data/actor/party.mjs b/module/data/actor/party.mjs index 77b17045..06731246 100644 --- a/module/data/actor/party.mjs +++ b/module/data/actor/party.mjs @@ -41,7 +41,7 @@ export default class DhParty extends BaseDataActor { // Clear this party from all members that aren't deleted for (const member of this.partyMembers) { - member.parties?.delete(this.parent); + member?.parties?.delete(this.parent); } } } diff --git a/module/systemRegistration/migrations.mjs b/module/systemRegistration/migrations.mjs index e3777a94..00b07dc1 100644 --- a/module/systemRegistration/migrations.mjs +++ b/module/systemRegistration/migrations.mjs @@ -4,6 +4,7 @@ export async function runMigrations() { let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion); if (!lastMigrationVersion) lastMigrationVersion = game.system.version; + //#region old migrations if (foundry.utils.isNewerVersion('1.1.0', lastMigrationVersion)) { const lockedPacks = []; const compendiumActors = []; @@ -190,6 +191,7 @@ export async function runMigrations() { lastMigrationVersion = '1.2.0'; } + //#endregion await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion); } diff --git a/styles/less/sheets/actors/party/resources.less b/styles/less/sheets/actors/party/resources.less index fc7e0110..4db254bf 100644 --- a/styles/less/sheets/actors/party/resources.less +++ b/styles/less/sheets/actors/party/resources.less @@ -32,7 +32,7 @@ body.game:is(.performance-low, .noblur) { background: light-dark(@dark-blue-40, @dark-golden-40); border-radius: 6px; border: 1px solid light-dark(@dark-blue, @golden); - max-width: 230px; + width: 230px; height: -webkit-fill-available; .actor-name { diff --git a/system.json b/system.json index a7c79226..467e9f7d 100644 --- a/system.json +++ b/system.json @@ -2,10 +2,10 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.2.1", + "version": "1.2.2", "compatibility": { "minimum": "13", - "verified": "13.350", + "verified": "13.351", "maximum": "13" }, "authors": [ diff --git a/templates/sheets/actors/party/party-members.hbs b/templates/sheets/actors/party/party-members.hbs index a34959fd..b5903cfc 100644 --- a/templates/sheets/actors/party/party-members.hbs +++ b/templates/sheets/actors/party/party-members.hbs @@ -28,6 +28,7 @@ item=actor type='character' isActor=true + hideContextMenu=true }} {{/each}} diff --git a/templates/sheets/actors/party/resources.hbs b/templates/sheets/actors/party/resources.hbs index edb58248..74f94806 100644 --- a/templates/sheets/actors/party/resources.hbs +++ b/templates/sheets/actors/party/resources.hbs @@ -22,19 +22,21 @@

{{actor.name}}

-
-
- {{#times actor.system.resources.hitPoints.max}} - - - {{/times}} + {{#unless (eq actor.type 'companion') }} +
+
+ {{#times actor.system.resources.hitPoints.max}} + + + {{/times}} +
+
+ {{localize "DAGGERHEART.GENERAL.HitPoints.short"}} + {{actor.system.resources.hitPoints.value}} / {{actor.system.resources.hitPoints.max}} +
-
- {{localize "DAGGERHEART.GENERAL.HitPoints.short"}} - {{actor.system.resources.hitPoints.value}} / {{actor.system.resources.hitPoints.max}} -
-
+ {{/unless}}
@@ -71,26 +73,30 @@
{{/if}} + {{#unless (or (eq actor.type 'companion') (eq actor.type 'adversary')) }} +
+

{{localize "DAGGERHEART.GENERAL.hope"}}

+ {{#times actor.system.resources.hope.max}} + + {{#if (gte actor.system.resources.hope.value (add this 1))}} + + {{else}} + + {{/if}} + + {{/times}} +
+ {{/unless}} -
-

{{localize "DAGGERHEART.GENERAL.hope"}}

- {{#times actor.system.resources.hope.max}} - - {{#if (gte actor.system.resources.hope.value (add this 1))}} - - {{else}} - - {{/if}} - - {{/times}} -
-
-

{{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}

-

{{actor.system.damageThresholds.major}}

-

{{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}

-

{{actor.system.damageThresholds.severe}}

-

{{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}

-
+ {{#unless (eq actor.type 'companion')}} +
+

{{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}

+

{{actor.system.damageThresholds.major}}

+

{{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}

+

{{actor.system.damageThresholds.severe}}

+

{{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}

+
+ {{/unless}}
{{/each}} diff --git a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs index e97bfd80..d2534a5a 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs @@ -10,6 +10,7 @@ Parameters: - isGlassy {boolean} : If true, applies the 'glassy' class to the fieldset. - cardView {boolean} : If true and type is 'domainCard', renders using domain card layout. - isActor {boolean} : Passed through to inventory-item partials. +- isItem {boolean} : Passed through to inventory-item partials - actorType {boolean} : The actor type of the parent actor - canCreate {boolean} : If true, show createDoc anchor on legend - inVault {boolean} : If true, the domainCard is created with inVault=true diff --git a/templates/sheets/global/partials/inventory-item-V2.hbs b/templates/sheets/global/partials/inventory-item-V2.hbs index 37c53dcc..2d8eb560 100644 --- a/templates/sheets/global/partials/inventory-item-V2.hbs +++ b/templates/sheets/global/partials/inventory-item-V2.hbs @@ -4,6 +4,7 @@ Parameters: - type {string} : The type of items in the list - isActor {boolean} : Passed through to inventory-item partials. +- isItem {boolean} : Passed through to inventory-item partials - actorType {boolean} : The actor type of the parent actor - categoryAdversary {string} : Category adversary id. - noExtensible {boolean} : If true, the inventory-item-content would be collapsable/extendible else it always be showed @@ -18,7 +19,7 @@ Parameters:
  • -
    +
    {{!-- Image --}}
    - {{#if isActor}} + {{#if isActor}} @@ -81,7 +82,7 @@ Parameters: {{/if}} - {{else}} + {{else}} {{#unless (eq actorType 'party')}} {{#if (eq type 'weapon')}} {{/if}} + {{#if (eq type 'domainCard')}} + + + + {{else if (eq type 'effect')}} + + + + {{/if}} + {{#if (hasProperty item "toChat")}} + + + + {{/if}} {{else}} + + + {{/unless}} - {{#if (eq type 'domainCard')}} - - - - {{else if (eq type 'effect')}} - - - - {{/if}} - {{#if (and (hasProperty item "toChat") (not (eq actorType 'party')))}} - - - - {{/if}} {{#unless hideContextMenu}} @@ -122,7 +126,7 @@ Parameters: {{/unless}} {{/if}}
    - {{/unless}} + {{/unless}}
    {{!-- Description --}}