From 1ebbad47973b631bb6779340e5cab85dd4532a7a Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Wed, 24 Jun 2026 17:37:00 -0400 Subject: [PATCH 1/3] [Fix] quirks involving expanding items and hovering over them (#2033) --- .../sheets/api/application-mixin.mjs | 2 +- module/data/action/baseAction.mjs | 4 + module/data/item/armor.mjs | 8 +- module/data/item/weapon.mjs | 8 +- module/documents/activeEffect.mjs | 4 + module/documents/item.mjs | 4 + styles/less/global/inventory-item.less | 28 +- .../global/partials/inventory-item-V2.hbs | 266 +++++++++--------- 8 files changed, 163 insertions(+), 161 deletions(-) diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 98f38f03..0168f46d 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -603,7 +603,7 @@ export default function DHApplicationMixin(Base) { const doc = await fromUuid(itemUuid); //get inventory-item description element - const descriptionElement = el.querySelector('.invetory-description'); + const descriptionElement = el.querySelector('.inventory-description'); if (!doc || !descriptionElement) continue; // localize the description (idk if it's still necessary) diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 27383b7a..f3008704 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -54,6 +54,10 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return {}; } + get hasDescription() { + return Boolean(this.description); + } + /** * Create a Map containing each Action step based on fields define in schema. Ordered by Fields order property. * diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index 21c56f9a..15bb620d 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -52,6 +52,10 @@ export default class DHArmor extends AttachableItem { ); } + get itemFeatures() { + return this.armorFeatures; + } + /**@inheritdoc */ async getDescriptionData() { const baseDescription = this.description; @@ -169,8 +173,4 @@ export default class DHArmor extends AttachableItem { const labels = [`${game.i18n.localize('DAGGERHEART.ITEMS.Armor.baseScore')}: ${this.armor.max}`]; return labels; } - - get itemFeatures() { - return this.armorFeatures; - } } diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 84e4de7f..39c0fc8e 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -113,6 +113,10 @@ export default class DHWeapon extends AttachableItem { ); } + get itemFeatures() { + return this.weaponFeatures; + } + /**@inheritdoc */ async getDescriptionData() { const baseDescription = this.description; @@ -269,8 +273,4 @@ export default class DHWeapon extends AttachableItem { return labels; } - - get itemFeatures() { - return this.weaponFeatures; - } } diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index cdfc9a52..4a9f3cc4 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -65,6 +65,10 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { ); } + get hasDescription() { + return Boolean(this.description); + } + /* -------------------------------------------- */ /* Event Handlers */ /* -------------------------------------------- */ diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 32543ebd..14717538 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -89,6 +89,10 @@ export default class DHItem extends foundry.documents.Item { return !pack?.locked && this.isOwner && isValidType && hasActions; } + get hasDescription() { + return Boolean(this.system.description) || Boolean(this.system.itemFeatures?.length); + } + /** @inheritdoc */ static async createDialog(data = {}, createOptions = {}, options = {}) { const { folders, types, template, context = {}, ...dialogOptions } = options; diff --git a/styles/less/global/inventory-item.less b/styles/less/global/inventory-item.less index 3a5a9321..fc73ba95 100644 --- a/styles/less/global/inventory-item.less +++ b/styles/less/global/inventory-item.less @@ -43,16 +43,19 @@ } } + .item-main { + border-radius: 5px; + padding: 2px; + margin: -2px; + } + &:hover { .inventory-item-header .item-label .item-name .expanded-icon { margin-left: 10px; display: inline-block; } - &:has(.inventory-item-content.extensible) { - .inventory-item-header, - .inventory-item-content { - background: light-dark(@dark-blue-40, @golden-40); - } + .item-main { + background: light-dark(@dark-blue-40, @golden-40); } &:has(.inventory-item-content.extended) { .inventory-item-header .item-label .item-name .expanded-icon { @@ -60,19 +63,6 @@ } } } - - &:has(.inventory-item-content.extensible) { - .inventory-item-header { - border-radius: 5px 5px 0 0; - } - .inventory-item-content { - border-radius: 0 0 5px 5px; - } - } - - &:not(:has(.inventory-item-content.extensible)) .inventory-item-header { - border-radius: 5px; - } } .inventory-item-header, @@ -171,7 +161,7 @@ grid-template-rows: 1fr; padding-top: 4px; } - .invetory-description { + .inventory-description { overflow: hidden; h1 { diff --git a/templates/sheets/global/partials/inventory-item-V2.hbs b/templates/sheets/global/partials/inventory-item-V2.hbs index f7d22a30..775690d4 100644 --- a/templates/sheets/global/partials/inventory-item-V2.hbs +++ b/templates/sheets/global/partials/inventory-item-V2.hbs @@ -25,146 +25,146 @@ Parameters: data-type="{{type}}" data-item-type="{{item.type}}" data-item-uuid="{{item.uuid}}" data-no-compendium-edit="{{noCompendiumEdit}}" > -
- {{!-- Image --}} -
- - {{#if (and item.usable (ne showActions false))}} - {{#if @root.isNPC}} - d20 - {{else}} - 2d12 - {{/if}} - {{/if}} -
- - {{!-- Name & Tags --}} -
- {{!-- Item Name --}} - {{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}{{/unless}} - - {{!-- Tags Start --}} - {{#if (not hideTags)}} - {{#> "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs" item}} - {{#if (eq ../type 'feature')}} - {{#if (and system.featureForm (ne @root.document.type "character"))}} -
- {{localize (concat "DAGGERHEART.CONFIG.FeatureForm." system.featureForm)}} -
+
+
+ {{!-- Image --}} +
+ + {{#if (and item.usable (ne showActions false))}} + {{#if @root.isNPC}} + d20 + {{else}} + 2d12 {{/if}} {{/if}} - {{/ "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs"}} - {{/if}} +
- {{!--Tags End --}} -
+ {{!-- Name & Tags --}} +
+ {{!-- Item Name --}} + {{localize item.name}} {{#unless (or noExtensible (not item.hasDescription))}}{{/unless}} - {{!-- Simple Resource --}} - {{#if (and (not hideResources) (not (eq item.system.resource.type 'diceValue')))}} - {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} - {{/if}} - {{#if (or isQuantifiable (or (eq item.system.quantity 0) (gt item.system.quantity 1)))}} -
- + {{!-- Tags Start --}} + {{#if (not hideTags)}} + {{#> "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs" item}} + {{#if (and (eq ../type 'feature') system.featureForm (ne @root.document.type "character"))}} +
+ {{localize (concat "DAGGERHEART.CONFIG.FeatureForm." system.featureForm)}} +
+ {{/if}} + {{/ "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs"}} + {{/if}} + + {{!--Tags End --}} +
+ + {{!-- Simple Resource --}} + {{#if (and (not hideResources) (not (eq item.system.resource.type 'diceValue')))}} + {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} + {{/if}} + {{#if (or isQuantifiable (or (eq item.system.quantity 0) (gt item.system.quantity 1)))}} +
+ +
+ {{/if}} + + {{!-- Controls --}} + {{#unless hideControls}} +
+ {{!-- Toggle/Equip buttons --}} + {{#if @root.editable}} + {{#if (and (eq actorType 'character') (eq type 'weapon'))}} + + + + {{/if}} + {{#if (and (eq actorType 'character') (eq type 'armor'))}} + + + + {{/if}} + {{#if (and (eq type 'domainCard'))}} + + + + {{/if}} + {{#if (and (and (eq type 'effect') (not (eq item.type 'beastform'))))}} + + + + {{/if}} + {{/if}} + + {{!-- Send to Chat --}} + {{#if (hasProperty item "toChat")}} + + + + {{/if}} + + {{!-- Document management buttons or context menu --}} + {{#if (and (not isActor) (not hideContextMenu))}} + + + + {{else if (and @root.editable (not hideModifyControls))}} + + + + {{#if (not isActor)}} + + + + {{else if (eq type 'adversary')}} + + + + {{/if}} + {{/if}} +
+ {{/unless}}
+ {{#unless hideDescription}} +
+ {{!-- Description --}} +
+
+ {{/unless}} +
+ {{!-- Dice Resource --}} + {{#if (and (not hideResources) (eq item.system.resource.type 'diceValue'))}} + {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} {{/if}} - - {{!-- Controls --}} - {{#unless hideControls}} -
- {{!-- Toggle/Equip buttons --}} - {{#if @root.editable}} - {{#if (and (eq actorType 'character') (eq type 'weapon'))}} - - - - {{/if}} - {{#if (and (eq actorType 'character') (eq type 'armor'))}} - - - - {{/if}} - {{#if (and (eq type 'domainCard'))}} - - - - {{/if}} - {{#if (and (and (eq type 'effect') (not (eq item.type 'beastform'))))}} - - - - {{/if}} + {{!-- Actions Buttons --}} + {{#if (and showActions item.system.actions.size)}} +
+ {{#each item.system.actions as | action |}} +
+ {{#if (and (eq action.type 'beastform') @root.beastformActive)}} + + {{else}} + {{/if}} - - {{!-- Send to Chat --}} - {{#if (hasProperty item "toChat")}} - - - - {{/if}} - - {{!-- Document management buttons or context menu --}} - {{#if (and (not isActor) (not hideContextMenu))}} - - - - {{else if (and @root.editable (not hideModifyControls))}} - - - - {{#if (not isActor)}} - - - - {{else if (eq type 'adversary')}} - - - - {{/if}} + {{#if action.uses.max}} +
+ {{/if}}
- {{/unless}} -
-
- {{!-- Description --}} - {{#unless hideDescription}} -
- {{/unless}} -
- {{!-- Dice Resource --}} - {{#if (and (not hideResources) (eq item.system.resource.type 'diceValue'))}} - {{> "systems/daggerheart/templates/sheets/global/partials/item-resource.hbs"}} - {{/if}} - {{!-- Actions Buttons --}} - {{#if (and showActions item.system.actions.size)}} -
- {{#each item.system.actions as | action |}} -
- {{#if (and (eq action.type 'beastform') @root.beastformActive)}} - - {{else}} - - {{/if}} - {{#if action.uses.max}} -
- - {{/if}} + {{/each}}
- {{/each}} -
- {{/if}} - \ No newline at end of file + {{/if}} + From 9c58f7058e3ba99af32bb6ebfbc4af26b59d91d6 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:22:12 +0200 Subject: [PATCH 2/3] [Fix] V13 Migration Fixes (#2044) * Fixed so that damageParts without an applyTo field is assumed to be hitPoints * Added the applyTo field to the basic attack for Adversaries and Companions * Tentative blindfix to issues of entities being null. Can't replicate it * Added some safety for missing things if someone was on a REALLY old system version and then updated all the way * Moved v13 countdown migration over to a migrateData * . --- module/data/action/baseAction.mjs | 8 +++ module/data/actor/adversary.mjs | 1 + module/data/actor/character.mjs | 1 + module/data/actor/companion.mjs | 1 + module/data/countdowns.mjs | 33 ++++++++++++ module/systemRegistration/migrations.mjs | 68 ++++++------------------ 6 files changed, 61 insertions(+), 51 deletions(-) diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index f3008704..58be672b 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -451,7 +451,15 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel static migrateData(source) { if (source.damage?.parts && Array.isArray(source.damage.parts)) { + let hitPointsExists = source.damage.parts.some(x => x.applyTo === 'hitPoints'); source.damage.parts = source.damage.parts.reduce((acc, part) => { + if (!part.applyTo && hitPointsExists) return acc; + + if (!part.applyTo) { + hitPointsExists = true; + part.applyTo = 'hitPoints'; + } + acc[part.applyTo] = part; return acc; }, {}); diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index d6d0dcdf..ae17c128 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -87,6 +87,7 @@ export default class DhpAdversary extends DhCreature { parts: { hitPoints: { type: ['physical'], + applyTo: 'hitPoints', value: { multiplier: 'flat' } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 3b12da6f..b39c64aa 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -107,6 +107,7 @@ export default class DhCharacter extends DhCreature { parts: { hitPoints: { type: ['physical'], + applyTo: 'hitPoints', value: { custom: { enabled: true, diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 300bd698..2ca7fd5b 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -102,6 +102,7 @@ export default class DhCompanion extends DhCreature { parts: { hitPoints: { type: ['physical'], + applyTo: 'hitPoints', value: { dice: 'd6', multiplier: 'prof' diff --git a/module/data/countdowns.mjs b/module/data/countdowns.mjs index 8e55ed31..ffe4d26b 100644 --- a/module/data/countdowns.mjs +++ b/module/data/countdowns.mjs @@ -28,6 +28,39 @@ export default class DhCountdowns extends foundry.abstract.DataModel { for (const countdownKey of changedCountdowns) foundry.ui.countdowns.changedCountdownsForAnimation.add(countdownKey); } + + static migrateData(source) { + const migrateOldCountdowns = (data, type) => { + for (const key of Object.keys(data.countdowns)) { + const countdown = data.countdowns[key]; + source.countdowns[key] = { + ...countdown, + type: type, + ownership: Object.keys(countdown.ownership.players).reduce((acc, key) => { + acc[key] = + countdown.ownership.players[key].type === 1 ? 2 : countdown.ownership.players[key].type; + return acc; + }, {}), + progress: { + ...countdown.progress, + type: countdown.progress.type.value + } + }; + } + + source[type] = null; + }; + + if (source.narrative) { + migrateOldCountdowns(source.narrative, 'narrative'); + } + + if (source.encounter) { + migrateOldCountdowns(source.encounter, 'encounter'); + } + + return super.migrateData(source); + } } export class DhCountdown extends foundry.abstract.DataModel { diff --git a/module/systemRegistration/migrations.mjs b/module/systemRegistration/migrations.mjs index ec546c92..6971c34c 100644 --- a/module/systemRegistration/migrations.mjs +++ b/module/systemRegistration/migrations.mjs @@ -1,5 +1,4 @@ import { defaultRestOptions } from '../config/generalConfig.mjs'; -import { RefreshType, socketEvent } from './socket.mjs'; export async function runMigrations() { let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion); @@ -153,61 +152,26 @@ export async function runMigrations() { await pack.configure({ locked: true }); } - /* Migrate old countdown structure */ - const countdownSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns); - const getCountdowns = (data, type) => { - return Object.keys(data.countdowns).reduce((acc, key) => { - const countdown = data.countdowns[key]; - acc[key] = { - ...countdown, - type: type, - ownership: Object.keys(countdown.ownership.players).reduce((acc, key) => { - acc[key] = - countdown.ownership.players[key].type === 1 ? 2 : countdown.ownership.players[key].type; - return acc; - }, {}), - progress: { - ...countdown.progress, - type: countdown.progress.type.value - } - }; - - return acc; - }, {}); - }; - - await countdownSettings.updateSource({ - countdowns: { - ...getCountdowns(countdownSettings.narrative, 'narrative'), - ...getCountdowns(countdownSettings.encounter, 'encounter') - } - }); - await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, countdownSettings); - - game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.Refresh, - data: { refreshType: RefreshType.Countdown } - }); - Hooks.callAll(socketEvent.Refresh, { refreshType: RefreshType.Countdown }); - lastMigrationVersion = '1.2.0'; } if (foundry.utils.isNewerVersion('1.2.7', lastMigrationVersion)) { - const tagTeam = game.settings.get(CONFIG.DH.id, 'TagTeamRoll'); - const initatorMissing = tagTeam.initiator && !game.actors.some(actor => actor.id === tagTeam.initiator); - const missingMembers = Object.keys(tagTeam.members).reduce((acc, id) => { - if (!game.actors.some(actor => actor.id === id)) { - acc[id] = _del; - } - return acc; - }, {}); + try { + const tagTeam = game.settings.get(CONFIG.DH.id, 'TagTeamRoll'); + const initatorMissing = tagTeam.initiator && !game.actors.some(actor => actor.id === tagTeam.initiator); + const missingMembers = Object.keys(tagTeam.members).reduce((acc, id) => { + if (!game.actors.some(actor => actor.id === id)) { + acc[id] = _del; + } + return acc; + }, {}); - await tagTeam.updateSource({ - initiator: initatorMissing ? null : tagTeam.initiator, - members: missingMembers - }); - await game.settings.set(CONFIG.DH.id, 'TagTeamRoll', tagTeam); + await tagTeam.updateSource({ + initiator: initatorMissing ? null : tagTeam.initiator, + members: missingMembers + }); + await game.settings.set(CONFIG.DH.id, 'TagTeamRoll', tagTeam); + } catch { } lastMigrationVersion = '1.2.7'; } @@ -303,6 +267,8 @@ export async function runMigrations() { /* Migrate existing effects modifying armor, creating new Armor Effects instead */ const migrateEffects = async entity => { + if (!entity?.effects) return; + for (const effect of entity.effects) { if (effect.system.changes.every(x => x.key !== 'system.armorScore')) continue; From 8c6a470d84d80ac70966e7b0c985daf396637c70 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 29 Jun 2026 14:25:16 +0200 Subject: [PATCH 3/3] Raised version --- system.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system.json b/system.json index 4660a196..0ecc2e75 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.4.1", + "version": "2.4.2", "compatibility": { "minimum": "14.364", "verified": "14.364", @@ -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.4.1/system.zip", + "download": "https://github.com/Foundryborne/daggerheart/releases/download/2.4.2/system.zip", "authors": [ { "name": "WBHarry"