From 735ed4c2140f5a6e49e6001387cfc1a6fc475072 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 4 Feb 2026 07:11:18 +0100 Subject: [PATCH 01/51] [Fix] RollMessage Order (#1626) * Fixed so that the description message always comes first with the action workflow * Changed to instead render the description in the roll message * Made the action config title not get changed in d20rolldialog if it's not a trait roll * Initial chat message description design change * Revert "Initial chat message description design change" This reverts commit f4f5fd6c24d05c6967615fe8498a34aee739b1b3. * . --- module/applications/dialogs/d20RollDialog.mjs | 7 +- module/data/action/baseAction.mjs | 8 +- module/data/chat-message/actorRoll.mjs | 1 + module/data/fields/action/damageField.mjs | 2 + module/data/settings/Appearance.mjs | 2 +- module/dice/dhRoll.mjs | 15 +- module/documents/chatMessage.mjs | 2 + module/systemRegistration/handlebars.mjs | 1 + styles/less/ui/chat/action.less | 118 -------------- styles/less/ui/chat/chat.less | 153 ++++++++++++++++++ templates/ui/chat/parts/description-part.hbs | 11 ++ templates/ui/chat/roll.hbs | 8 +- 12 files changed, 201 insertions(+), 127 deletions(-) create mode 100644 templates/ui/chat/parts/description-part.hbs diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 4a4b1556..8e79ba58 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -165,9 +165,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio } if (rest.hasOwnProperty('trait')) { this.config.roll.trait = rest.trait; - this.config.title = game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { - ability: game.i18n.localize(abilities[this.config.roll.trait]?.label) - }); + if (!this.config.source.item) + this.config.title = game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { + ability: game.i18n.localize(abilities[this.config.roll.trait]?.label) + }); } this.config.extraFormula = rest.extraFormula; this.render(); diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index e843027b..f6ffe75f 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -229,7 +229,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return; - if (this.chatDisplay) await this.toChat(); + if (this.chatDisplay && !config.actionChatMessageHandled) await this.toChat(); return config; } @@ -240,9 +240,13 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel * @returns {object} */ prepareBaseConfig(event) { + const isActor = this.item instanceof CONFIG.Actor.documentClass; + const actionTitle = game.i18n.localize(this.name); + const itemTitle = isActor || this.item.name === actionTitle ? '' : `${this.item.name} - `; + const config = { event, - title: `${this.item instanceof CONFIG.Actor.documentClass ? '' : `${this.item.name}: `}${game.i18n.localize(this.name)}`, + title: `${itemTitle}${actionTitle}`, source: { item: this.item._id, originItem: this.originItem, diff --git a/module/data/chat-message/actorRoll.mjs b/module/data/chat-message/actorRoll.mjs index 61262529..1ea7ff93 100644 --- a/module/data/chat-message/actorRoll.mjs +++ b/module/data/chat-message/actorRoll.mjs @@ -31,6 +31,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { static defineSchema() { return { title: new fields.StringField(), + actionDescription: new fields.HTMLField(), roll: new fields.ObjectField(), targets: targetsField(), hasRoll: new fields.BooleanField({ initial: false }), diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index ef91c64e..56eb51e5 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -68,6 +68,8 @@ export default class DamageField extends fields.SchemaField { const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig); if (!damageResult) return false; + if (damageResult.actionChatMessageHandled) config.actionChatMessageHandled = true; + config.damage = damageResult.damage; config.message ??= damageConfig.message; } diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index d7a638d7..cd98d6f9 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -37,7 +37,7 @@ export default class DhAppearance extends foundry.abstract.DataModel { extendEnvironmentDescriptions: new BooleanField(), extendItemDescriptions: new BooleanField(), expandRollMessage: new SchemaField({ - desc: new BooleanField(), + desc: new BooleanField({ initial: true }), roll: new BooleanField(), damage: new BooleanField(), target: new BooleanField() diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 1977c7ea..d8e5f6dd 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -96,6 +96,19 @@ export default class DHRoll extends Roll { } static async toMessage(roll, config) { + const item = config.data.parent?.items?.get?.(config.source.item) ?? null; + const action = item ? item.system.actions.get(config.source.action) : null; + let actionDescription = null; + if (action?.chatDisplay) { + actionDescription = action + ? await foundry.applications.ux.TextEditor.implementation.enrichHTML(action.description, { + relativeTo: config.data, + rollData: config.data.getRollData?.() ?? {} + }) + : null; + config.actionChatMessageHandled = true; + } + const cls = getDocumentClass('ChatMessage'), msgData = { type: this.messageType, @@ -103,7 +116,7 @@ export default class DHRoll extends Roll { title: roll.title, speaker: cls.getSpeaker({ actor: roll.data?.parent }), sound: config.mute ? null : CONFIG.sounds.dice, - system: config, + system: { ...config, actionDescription }, rolls: [roll] }; diff --git a/module/documents/chatMessage.mjs b/module/documents/chatMessage.mjs index 1d2c6c41..668ad06b 100644 --- a/module/documents/chatMessage.mjs +++ b/module/documents/chatMessage.mjs @@ -110,6 +110,8 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage { } else if (s.classList.contains('damage-section')) s.classList.toggle('expanded', autoExpandRoll.damage); else if (s.classList.contains('target-section')) s.classList.toggle('expanded', autoExpandRoll.target); + else if (s.classList.contains('description-section')) + s.classList.toggle('expanded', autoExpandRoll.desc); }); if (itemDesc && autoExpandRoll.desc) itemDesc.setAttribute('open', ''); } diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index 97769181..ad8c741a 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -39,6 +39,7 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/dialogs/downtime/activities.hbs', 'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs', 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs', + 'systems/daggerheart/templates/ui/chat/parts/description-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs', diff --git a/styles/less/ui/chat/action.less b/styles/less/ui/chat/action.less index a3d2f3cc..6eeb7a52 100644 --- a/styles/less/ui/chat/action.less +++ b/styles/less/ui/chat/action.less @@ -38,124 +38,6 @@ flex-direction: column; align-items: center; - details[open] { - .fa-chevron-down { - transform: rotate(180deg); - transition: all 0.3s ease; - } - } - - .action-move { - width: 100%; - - .fa-chevron-down { - transition: all 0.3s ease; - margin-left: auto; - } - - .action-section { - display: flex; - flex-direction: row; - align-items: center; - margin: 8px 8px 0; - padding-bottom: 5px; - width: -webkit-fill-available; - gap: 5px; - border-bottom: 1px solid @golden; - - &:hover { - background: @golden-10; - cursor: pointer; - transition: all 0.3s ease; - } - - .action-img { - width: 40px; - height: 40px; - border-radius: 3px; - object-fit: cover; - } - - .action-header { - display: flex; - flex-direction: column; - gap: 5px; - color: @beige; - - .title { - font-size: var(--font-size-20); - color: @golden; - font-weight: 700; - } - - .label { - font-size: var(--font-size-12); - color: @beige; - margin: 0; - } - } - } - } - - .description { - padding: 8px; - - .summons-header { - font-size: var(--font-size-14); - text-align: center; - display: flex; - align-items: center; - justify-content: center; - - span { - width: 100%; - } - - &:before, - &:after { - content: ' '; - height: 1px; - width: 100%; - } - - &:before { - background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); - } - - &:after { - background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); - } - } - - .summons-container { - display: flex; - flex-direction: column; - gap: 4px; - - .summon-container { - display: flex; - align-items: center; - justify-content: space-between; - - .summon-label-container { - flex: 1; - display: flex; - align-items: center; - gap: 4px; - - img { - height: 32px; - } - - label { - display: flex; - flex-wrap: wrap; - } - } - } - } - } - .ability-card-footer { display: flex; flex-wrap: wrap; diff --git a/styles/less/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 494af5f1..8728fbda 100644 --- a/styles/less/ui/chat/chat.less +++ b/styles/less/ui/chat/chat.less @@ -228,6 +228,15 @@ font-size: var(--font-size-12); padding: 0 20px; + .roll-part-title { + text-align: center; + font-family: @font-subtitle; + font-size: var(--font-size-18); + font-weight: bold; + color: var(--text-color); + margin-bottom: -2px; + } + > .roll-part-header { font-size: var(--font-size-14); } @@ -286,6 +295,7 @@ > :first-child:not(.target-selector) { margin-top: 5px; + text-align: center; } > :last-child { @@ -573,6 +583,30 @@ } } + .chat-roll .description-section { + .roll-part-content { + .dice-tooltip { + .wrapper { + i { + margin: 0; + + :first-child { + margin-top: 0; + } + + :last-child { + margin-bottom: 0; + } + } + + > :first-child:not(.target-selector) { + margin: 0; + } + } + } + } + } + .roll-buttons { display: flex; gap: 5px; @@ -590,5 +624,124 @@ .dice-roll .dice-tooltip fieldset { margin-bottom: 5px; } + + details[open] { + .fa-chevron-down { + transform: rotate(180deg); + transition: all 0.3s ease; + } + } + + .action-move { + width: 100%; + + .fa-chevron-down { + transition: all 0.3s ease; + margin-left: auto; + } + + .action-section { + display: flex; + flex-direction: row; + align-items: center; + margin: 8px 8px 0; + padding-bottom: 5px; + width: -webkit-fill-available; + gap: 5px; + border-bottom: 1px solid @golden; + + &:hover { + background: @golden-10; + cursor: pointer; + transition: all 0.3s ease; + } + + .action-img { + width: 40px; + height: 40px; + border-radius: 3px; + object-fit: cover; + } + + .action-header { + display: flex; + flex-direction: column; + gap: 5px; + color: @beige; + + .title { + font-size: var(--font-size-20); + color: @golden; + font-weight: 700; + margin: 0; + } + + .label { + font-size: var(--font-size-12); + color: @beige; + margin: 0; + } + } + } + } + + .description { + padding: 8px; + + .summons-header { + font-size: var(--font-size-14); + text-align: center; + display: flex; + align-items: center; + justify-content: center; + + span { + width: 100%; + } + + &:before, + &:after { + content: ' '; + height: 1px; + width: 100%; + } + + &:before { + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); + } + + &:after { + background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); + } + } + + .summons-container { + display: flex; + flex-direction: column; + gap: 4px; + + .summon-container { + display: flex; + align-items: center; + justify-content: space-between; + + .summon-label-container { + flex: 1; + display: flex; + align-items: center; + gap: 4px; + + img { + height: 32px; + } + + label { + display: flex; + flex-wrap: wrap; + } + } + } + } + } } } diff --git a/templates/ui/chat/parts/description-part.hbs b/templates/ui/chat/parts/description-part.hbs new file mode 100644 index 00000000..2e73a753 --- /dev/null +++ b/templates/ui/chat/parts/description-part.hbs @@ -0,0 +1,11 @@ +
+
{{localize "DAGGERHEART.GENERAL.description"}}
+ +
+
+
+ {{{actionDescription}}} +
+
+
+
\ No newline at end of file diff --git a/templates/ui/chat/roll.hbs b/templates/ui/chat/roll.hbs index be51969f..c7b17b21 100644 --- a/templates/ui/chat/roll.hbs +++ b/templates/ui/chat/roll.hbs @@ -1,6 +1,10 @@
-
{{title}}
- {{#if hasRoll}}{{> 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs'}}{{/if}} +
{{title}}
+ {{#if actionDescription}}{{> 'systems/daggerheart/templates/ui/chat/parts/description-part.hbs'}}{{/if}} + {{#if hasRoll}} +
{{localize "Result"}}
+ {{> 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs'}} + {{/if}} {{#if (or hasDamage hasHealing)}}{{> 'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs'}}{{/if}} {{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
From cab185df66ada3519618c5bdf2653b7c6e6b1e28 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:36:49 +0100 Subject: [PATCH 02/51] Made gridless distances lean towards being in the lower range (#1639) --- module/canvas/placeables/token.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index bc5c2a01..068f21e1 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -1,4 +1,4 @@ -import DhMeasuredTemplate from "./measuredTemplate.mjs"; +import DhMeasuredTemplate from './measuredTemplate.mjs'; export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { /** @inheritdoc */ @@ -63,7 +63,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { const originRadius = (this.bounds.width * boundsCorrection) / 2; const targetRadius = (target.bounds.width * boundsCorrection) / 2; const distance = canvas.grid.measurePath([originPoint, destinationPoint]).distance; - return distance - originRadius - targetRadius + canvas.grid.distance; + return Math.floor(distance - originRadius - targetRadius + canvas.grid.distance); } // Compute what the closest grid space of each token is, then compute that distance @@ -85,7 +85,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { // Check if the setting is enabled const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).showTokenDistance; - if (setting === "never" || (setting === "encounters" && !game.combat?.started)) return; + if (setting === 'never' || (setting === 'encounters' && !game.combat?.started)) return; // Check if this token isn't invisible and is actually being hovered const isTokenValid = From 0d2495c143729f07248751f639a5acf0ee9d107b Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 6 Feb 2026 00:36:52 +0100 Subject: [PATCH 03/51] Fixed fumigation and bold presence (#1638) --- .../adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json | 2 +- .../domains/domainCard_Bold_Presence_tdsL00yTSLNgZWs6.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json b/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json index 6594cbbe..8b553c83 100644 --- a/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json +++ b/src/packs/adversaries/adversary_Assassin_Poisoner_h5RuhzGL17dW5FBT.json @@ -388,7 +388,7 @@ "name": "Fumigation", "type": "feature", "system": { - "description": "

Drop a smoke bomb that fi lls the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.

@Template[type:emanation|range:c]

", + "description": "

Drop a smoke bomb that fills the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.

@Template[type:emanation|range:c]

", "resource": null, "actions": { "sp7RfJRQJsEUm09m": { diff --git a/src/packs/domains/domainCard_Bold_Presence_tdsL00yTSLNgZWs6.json b/src/packs/domains/domainCard_Bold_Presence_tdsL00yTSLNgZWs6.json index 08110cca..aaf070fc 100644 --- a/src/packs/domains/domainCard_Bold_Presence_tdsL00yTSLNgZWs6.json +++ b/src/packs/domains/domainCard_Bold_Presence_tdsL00yTSLNgZWs6.json @@ -110,7 +110,7 @@ "startRound": null, "startTurn": null }, - "description": "

Add your Strength to the presence roll roll.

", + "description": "

Add your Strength to the presence roll.

", "tint": "#ffffff", "statuses": [], "sort": 0, From c1f78665945adb9686a8aa2e7953a1b5580d417e Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 6 Feb 2026 11:32:33 +0100 Subject: [PATCH 04/51] [Fix] 1633 - ActiveEffect Autocomplete (#1636) * Improved the autocomplete typing experience * Made it work. But I hate it. * Revert "Made it work. But I hate it." This reverts commit d2fc9fd6486c44eac6067994ba564227fece714d. * Actually nice solution instead O_O --- daggerheart.mjs | 32 ++++++++ lang/en.json | 1 + .../dialogs/attributionDialog.mjs | 6 +- .../dialogs/group-roll-dialog.mjs | 12 ++- .../sheets-configs/activeEffectConfig.mjs | 48 ++++++++---- .../setting-active-effect-config.mjs | 6 +- module/data/actor/adversary.mjs | 9 ++- module/data/actor/character.mjs | 21 +++--- module/data/fields/actorField.mjs | 24 +++--- module/data/levelData.mjs | 7 +- module/documents/token.mjs | 74 ++++--------------- styles/less/ux/autocomplete/autocomplete.less | 1 - 12 files changed, 139 insertions(+), 102 deletions(-) diff --git a/daggerheart.mjs b/daggerheart.mjs index f75ff1da..49ed7049 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -242,6 +242,38 @@ Hooks.on('setup', () => { systemEffect: true })) ]; + + const actorCommon = { + bar: ['resources.stress'], + value: [] + }; + const damageThresholds = ['damageThresholds.major', 'damageThresholds.severe']; + const traits = Object.keys(game.system.api.data.actors.DhCharacter.schema.fields.traits.fields).map( + trait => `traits.${trait}.value` + ); + CONFIG.Actor.trackableAttributes = { + character: { + bar: [...actorCommon.bar, 'resources.hitPoints', 'resources.hope'], + value: [ + ...actorCommon.value, + ...traits, + ...damageThresholds, + 'proficiency', + 'evasion', + 'armorScore', + 'scars', + 'levelData.level.current' + ] + }, + adversary: { + bar: [...actorCommon.bar, 'resources.hitPoints'], + value: [...actorCommon.value, ...damageThresholds, 'criticalThreshold'] + }, + companion: { + bar: [...actorCommon.bar], + value: [...actorCommon.value, 'evasion', 'levelData.level.current'] + } + }; }); Hooks.on('ready', async () => { diff --git a/lang/en.json b/lang/en.json index 0186ae3e..86b4323c 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2152,6 +2152,7 @@ "continue": "Continue", "criticalSuccess": "Critical Success", "criticalShort": "Critical", + "currentLevel": "Current Level", "custom": "Custom", "d20Roll": "D20 Roll", "damage": "Damage", diff --git a/module/applications/dialogs/attributionDialog.mjs b/module/applications/dialogs/attributionDialog.mjs index 99ff261a..7f3f8bb2 100644 --- a/module/applications/dialogs/attributionDialog.mjs +++ b/module/applications/dialogs/attributionDialog.mjs @@ -54,7 +54,11 @@ export default class AttributionDialog extends HandlebarsApplicationMixin(Applic const after = label.slice(matchIndex + search.length, label.length); const element = document.createElement('li'); - element.innerHTML = `${beforeText}${matchText ? `${matchText}` : ''}${after}`; + element.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); if (item.hint) { element.dataset.tooltip = game.i18n.localize(item.hint); } diff --git a/module/applications/dialogs/group-roll-dialog.mjs b/module/applications/dialogs/group-roll-dialog.mjs index 2cb79563..8a3c43d6 100644 --- a/module/applications/dialogs/group-roll-dialog.mjs +++ b/module/applications/dialogs/group-roll-dialog.mjs @@ -70,7 +70,11 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat element.appendChild(img); const label = document.createElement('span'); - label.innerHTML = `${beforeText}${matchText ? `${matchText}` : ''}${after}`; + label.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); element.appendChild(label); return element; @@ -119,7 +123,11 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat element.appendChild(img); const label = document.createElement('span'); - label.innerHTML = `${beforeText}${matchText ? `${matchText}` : ''}${after}`; + label.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); element.appendChild(label); return element; diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index d7b1b536..9b8edd8a 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -4,20 +4,34 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac constructor(options) { super(options); - const ignoredActorKeys = ['config', 'DhEnvironment']; + const ignoredActorKeys = ['config', 'DhEnvironment', 'DhParty']; this.changeChoices = Object.keys(game.system.api.models.actors).reduce((acc, key) => { - if (!ignoredActorKeys.includes(key)) { - const model = game.system.api.models.actors[key]; - const attributes = CONFIG.Token.documentClass.getTrackedAttributes(model); - // As per DHToken._getTrackedAttributesFromSchema, attributes.bar have a max version as well. - const maxAttributes = attributes.bar.map(x => [...x, 'max']); - attributes.value.push(...maxAttributes); - const group = game.i18n.localize(model.metadata.label); - const choices = CONFIG.Token.documentClass - .getTrackedAttributeChoices(attributes, model) - .map(x => ({ ...x, group: group })); - acc.push(...choices); - } + if (ignoredActorKeys.includes(key)) return acc; + + const model = game.system.api.models.actors[key]; + const group = game.i18n.localize(model.metadata.label); + const attributes = CONFIG.Token.documentClass.getTrackedAttributes(model.metadata.type); + + const getLabel = path => { + const label = model.schema.getField(path)?.label; + return label ? game.i18n.localize(label) : path; + }; + + const bars = attributes.bar.flatMap(x => { + const joined = `${x.join('.')}.max`; + const label = + joined === 'resources.hope.max' + ? 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxHope.label' + : getLabel(joined); + return { value: joined, label, group }; + }); + const values = attributes.value.flatMap(x => { + const joined = x.join('.'); + return { value: joined, label: getLabel(joined), group }; + }); + + acc.push(...bars, ...values); + return acc; }, []); } @@ -68,14 +82,18 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac }, render: function (item, search) { const label = game.i18n.localize(item.label); - const matchIndex = label.toLowerCase().indexOf(search); + const matchIndex = label.toLowerCase().indexOf(search.toLowerCase()); const beforeText = label.slice(0, matchIndex); const matchText = label.slice(matchIndex, matchIndex + search.length); const after = label.slice(matchIndex + search.length, label.length); const element = document.createElement('li'); - element.innerHTML = `${beforeText}${matchText ? `${matchText}` : ''}${after}`; + element.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); if (item.hint) { element.dataset.tooltip = game.i18n.localize(item.hint); } diff --git a/module/applications/sheets-configs/setting-active-effect-config.mjs b/module/applications/sheets-configs/setting-active-effect-config.mjs index ca0d56e3..fe36e37f 100644 --- a/module/applications/sheets-configs/setting-active-effect-config.mjs +++ b/module/applications/sheets-configs/setting-active-effect-config.mjs @@ -103,7 +103,11 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi const after = label.slice(matchIndex + search.length, label.length); const element = document.createElement('li'); - element.innerHTML = `${beforeText}${matchText ? `${matchText}` : ''}${after}`; + element.innerHTML = + `${beforeText}${matchText ? `${matchText}` : ''}${after}`.replaceAll( + ' ', + ' ' + ); if (item.hint) { element.dataset.tooltip = game.i18n.localize(item.hint); } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 16e7e37a..f2c38090 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -40,7 +40,14 @@ export default class DhpAdversary extends BaseDataActor { integer: true, label: 'DAGGERHEART.GENERAL.hordeHp' }), - criticalThreshold: new fields.NumberField({ required: true, integer: true, min: 1, max: 20, initial: 20 }), + criticalThreshold: new fields.NumberField({ + required: true, + integer: true, + min: 1, + max: 20, + initial: 20, + label: 'DAGGERHEART.ACTIONS.Settings.criticalThreshold' + }), damageThresholds: new fields.SchemaField({ major: new fields.NumberField({ required: true, diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 8af4c74c..3913d426 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -35,15 +35,18 @@ export default class DhCharacter extends BaseDataActor { 'DAGGERHEART.ACTORS.Character.maxHPBonus' ), stress: resourceField(6, 0, 'DAGGERHEART.GENERAL.stress', true), - hope: new fields.SchemaField({ - value: new fields.NumberField({ - initial: 2, - min: 0, - integer: true, - label: 'DAGGERHEART.GENERAL.hope' - }), - isReversed: new fields.BooleanField({ initial: false }) - }) + hope: new fields.SchemaField( + { + value: new fields.NumberField({ + initial: 2, + min: 0, + integer: true, + label: 'DAGGERHEART.GENERAL.hope' + }), + isReversed: new fields.BooleanField({ initial: false }) + }, + { label: 'DAGGERHEART.GENERAL.hope' } + ) }), traits: new fields.SchemaField({ agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'), diff --git a/module/data/fields/actorField.mjs b/module/data/fields/actorField.mjs index f9eeeb90..db1faad4 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -7,16 +7,20 @@ const attributeField = label => }); const resourceField = (max = 0, initial = 0, label, reverse = false, maxLabel) => - new fields.SchemaField({ - value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }), - max: new fields.NumberField({ - initial: max, - integer: true, - label: - maxLabel ?? game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) }) - }), - isReversed: new fields.BooleanField({ initial: reverse }) - }); + new fields.SchemaField( + { + value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }), + max: new fields.NumberField({ + initial: max, + integer: true, + label: + maxLabel ?? + game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) }) + }), + isReversed: new fields.BooleanField({ initial: reverse }) + }, + { label } + ); const stressDamageReductionRule = localizationPath => new fields.SchemaField({ diff --git a/module/data/levelData.mjs b/module/data/levelData.mjs index 669077ee..4f55d9ee 100644 --- a/module/data/levelData.mjs +++ b/module/data/levelData.mjs @@ -6,7 +6,12 @@ export default class DhLevelData extends foundry.abstract.DataModel { return { level: new fields.SchemaField({ - current: new fields.NumberField({ required: true, integer: true, initial: 1 }), + current: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.GENERAL.currentLevel' + }), changed: new fields.NumberField({ required: true, integer: true, initial: 1 }), bonuses: new fields.TypedObjectField(new fields.NumberField({ integer: true, nullable: false })) }), diff --git a/module/documents/token.mjs b/module/documents/token.mjs index b9507c2f..6fd931d6 100644 --- a/module/documents/token.mjs +++ b/module/documents/token.mjs @@ -1,78 +1,30 @@ export default class DHToken extends CONFIG.Token.documentClass { - /** - * Inspect the Actor data model and identify the set of attributes which could be used for a Token Bar. - * @param {object} attributes The tracked attributes which can be chosen from - * @returns {object} A nested object of attribute choices to display - */ - static getTrackedAttributeChoices(attributes, model) { + /**@inheritdoc */ + static getTrackedAttributeChoices(attributes, typeKey) { attributes = attributes || this.getTrackedAttributes(); const barGroup = game.i18n.localize('TOKEN.BarAttributes'); const valueGroup = game.i18n.localize('TOKEN.BarValues'); + const actorModel = typeKey ? game.system.api.data.actors[`Dh${typeKey.capitalize()}`] : null; + const getLabel = path => { + const label = actorModel.schema.getField(path)?.label; + return label ? game.i18n.localize(label) : path; + }; const bars = attributes.bar.map(v => { const a = v.join('.'); - const modelLabel = model ? game.i18n.localize(model.schema.getField(`${a}.value`).label) : null; - return { group: barGroup, value: a, label: modelLabel ? modelLabel : a }; + return { group: barGroup, value: a, label: getLabel(a) }; }); - bars.sort((a, b) => a.label.compare(b.label)); + bars.sort((a, b) => a.value.compare(b.value)); - const invalidAttributes = [ - 'gold', - 'levelData', - 'actions', - 'biography', - 'class', - 'multiclass', - 'companion', - 'notes', - 'partner', - 'description', - 'impulses', - 'tier', - 'type' - ]; - const values = attributes.value.reduce((acc, v) => { + const values = attributes.value.map(v => { const a = v.join('.'); - if (invalidAttributes.some(x => a.startsWith(x))) return acc; - - const field = model ? model.schema.getField(a) : null; - const modelLabel = field ? game.i18n.localize(field.label) : null; - const hint = field ? game.i18n.localize(field.hint) : null; - acc.push({ group: valueGroup, value: a, label: modelLabel ? modelLabel : a, hint: hint }); - - return acc; - }, []); - values.sort((a, b) => a.label.compare(b.label)); + return { group: valueGroup, value: a, label: getLabel(a) }; + }); + values.sort((a, b) => a.value.compare(b.value)); return bars.concat(values); } - static _getTrackedAttributesFromSchema(schema, _path = []) { - const attributes = { bar: [], value: [] }; - for (const [name, field] of Object.entries(schema.fields)) { - const p = _path.concat([name]); - if (field instanceof foundry.data.fields.NumberField) attributes.value.push(p); - if (field instanceof foundry.data.fields.BooleanField && field.options.isAttributeChoice) - attributes.value.push(p); - if (field instanceof foundry.data.fields.StringField) attributes.value.push(p); - if (field instanceof foundry.data.fields.ArrayField) attributes.value.push(p); - const isSchema = field instanceof foundry.data.fields.SchemaField; - const isModel = field instanceof foundry.data.fields.EmbeddedDataField; - - if (isSchema || isModel) { - const schema = isModel ? field.model.schema : field; - const isBar = schema.has && schema.has('value') && schema.has('max'); - if (isBar) attributes.bar.push(p); - else { - const inner = this.getTrackedAttributes(schema, p); - attributes.bar.push(...inner.bar); - attributes.value.push(...inner.value); - } - } - } - return attributes; - } - _shouldRecordMovementHistory() { return false; } diff --git a/styles/less/ux/autocomplete/autocomplete.less b/styles/less/ux/autocomplete/autocomplete.less index 08854a53..7f799449 100644 --- a/styles/less/ux/autocomplete/autocomplete.less +++ b/styles/less/ux/autocomplete/autocomplete.less @@ -32,7 +32,6 @@ li[role='option'] { display: flex; align-items: center; - gap: 10px; font-size: var(--font-size-14); padding: 0 10px; cursor: pointer; From c3653e1b30ff35f2d8649788f9c898eaf2cf05ba Mon Sep 17 00:00:00 2001 From: alterNERDtive <53827887+alterNERDtive@users.noreply.github.com> Date: Sat, 7 Feb 2026 19:02:28 +0000 Subject: [PATCH 05/51] feat(dev): adds editorconfig (#1644) --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..8bbc2b52 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_size = 4 +indent_style = spaces From cad3f533ad20ba8192658a1b6ff8c3e27e528ff4 Mon Sep 17 00:00:00 2001 From: alterNERDtive <53827887+alterNERDtive@users.noreply.github.com> Date: Sat, 7 Feb 2026 22:14:17 +0000 Subject: [PATCH 06/51] fix: restricts target amount for downtime actions (#1645) --- module/config/generalConfig.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index ae49c73e..5e5eecfb 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -236,6 +236,7 @@ export const defaultRestOptions = { actionType: 'action', chatDisplay: false, target: { + amount: 1, type: 'friendly' }, damage: { @@ -304,6 +305,7 @@ export const defaultRestOptions = { actionType: 'action', chatDisplay: false, target: { + amount: 1, type: 'friendly' }, damage: { @@ -349,6 +351,7 @@ export const defaultRestOptions = { actionType: 'action', chatDisplay: false, target: { + amount: 1, type: 'friendly' }, damage: { @@ -417,6 +420,7 @@ export const defaultRestOptions = { actionType: 'action', chatDisplay: false, target: { + amount: 1, type: 'friendly' }, damage: { From 5e7201bfe990a4c4df8eb91d4c12cae66bb59cd4 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 8 Feb 2026 17:59:08 +0100 Subject: [PATCH 07/51] [Fix]Environment Attack Error (#1647) * Fixed so that environment attacks don't error * Fixed for companion aswell --- module/data/fields/action/damageField.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 56eb51e5..efad726c 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -109,8 +109,8 @@ export default class DamageField extends fields.SchemaField { ); else { const configDamage = foundry.utils.deepClone(config.damage); - const hpDamageMultiplier = config.actionActor?.system.rules.attack.damage.hpDamageMultiplier ?? 1; - const hpDamageTakenMultiplier = actor.system.rules.attack.damage.hpDamageTakenMultiplier; + const hpDamageMultiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1; + const hpDamageTakenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier; if (configDamage.hitPoints) { for (const part of configDamage.hitPoints.parts) { part.total = Math.ceil(part.total * hpDamageMultiplier * hpDamageTakenMultiplier); From 202e624a068718757088cf5a013499c748ce7fce Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:00:09 +0100 Subject: [PATCH 08/51] Fixed so that SecondWind has a decreasing resource (#1642) --- src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json b/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json index a8a21ec3..8dc535cc 100644 --- a/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json +++ b/src/packs/domains/domainCard_Second_Wind_ffPbSEvLuFrFsMxl.json @@ -170,7 +170,8 @@ "value": 1, "recovery": "shortRest", "max": "1", - "icon": "" + "icon": "", + "progression": "decreasing" }, "attribution": { "source": "Daggerheart SRD", From 44131d21a6170879a4cc6418c562636ea4a5cbee Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:01:30 +0100 Subject: [PATCH 09/51] [Fix] Beastform Effects (#1635) * Fixed so that beastform items always have a beastformEffect on them that can't be removed * Fixed so that you can drag an active effect onto a character --- .../sheets/api/application-mixin.mjs | 8 ++++++-- module/data/item/beastform.mjs | 16 ++++++++++++++++ module/documents/activeEffect.mjs | 5 +++-- .../sheets/global/partials/inventory-item-V2.hbs | 2 +- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index 3c0444eb..49f7dcf0 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -433,7 +433,7 @@ export default function DHApplicationMixin(Base) { icon: 'fa-solid fa-lightbulb', condition: target => { const doc = getDocFromElementSync(target); - return doc && !doc.disabled; + return doc && !doc.disabled && doc.type !== 'beastform'; }, callback: async target => (await getDocFromElement(target)).update({ disabled: true }) }, @@ -442,7 +442,7 @@ export default function DHApplicationMixin(Base) { icon: 'fa-regular fa-lightbulb', condition: target => { const doc = getDocFromElementSync(target); - return doc && doc.disabled; + return doc && doc.disabled && doc.type !== 'beastform'; }, callback: async target => (await getDocFromElement(target)).update({ disabled: false }) } @@ -536,6 +536,10 @@ export default function DHApplicationMixin(Base) { options.push({ name: 'CONTROLS.CommonDelete', icon: 'fa-solid fa-trash', + condition: target => { + const doc = getDocFromElementSync(target); + return doc && doc.type !== 'beastform'; + }, callback: async (target, event) => { const doc = await getDocFromElement(target); if (event.shiftKey) return doc.delete(); diff --git a/module/data/item/beastform.mjs b/module/data/item/beastform.mjs index dd491169..3a41aa7e 100644 --- a/module/data/item/beastform.mjs +++ b/module/data/item/beastform.mjs @@ -253,4 +253,20 @@ export default class DHBeastform extends BaseDataItem { return false; } + + _onCreate(_data, _options, userId) { + if (!this.actor && game.user.id === userId) { + const hasBeastformEffect = this.parent.effects.some(x => x.type === 'beastform'); + if (!hasBeastformEffect) + this.parent.createEmbeddedDocuments('ActiveEffect', [ + { + type: 'beastform', + name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'), + img: 'icons/creatures/abilities/paw-print-pair-purple.webp' + } + ]); + + return; + } + } } diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 5e9b0c3b..d0e329ff 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -61,14 +61,15 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { update.img = 'icons/magic/life/heart-cross-blue.webp'; } + const statuses = Object.keys(data.statuses ?? {}); const immuneStatuses = - data.statuses?.filter( + statuses.filter( status => this.parent.system.rules?.conditionImmunities && this.parent.system.rules.conditionImmunities[status] ) ?? []; if (immuneStatuses.length > 0) { - update.statuses = data.statuses.filter(x => !immuneStatuses.includes(x)); + update.statuses = statuses.filter(x => !immuneStatuses.includes(x)); const conditions = CONFIG.DH.GENERAL.conditions(); const scrollingTexts = immuneStatuses.map(status => ({ text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', { diff --git a/templates/sheets/global/partials/inventory-item-V2.hbs b/templates/sheets/global/partials/inventory-item-V2.hbs index dbacd1e4..76e13a5c 100644 --- a/templates/sheets/global/partials/inventory-item-V2.hbs +++ b/templates/sheets/global/partials/inventory-item-V2.hbs @@ -113,7 +113,7 @@ Parameters: data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}"> - {{else if (eq type 'effect')}} + {{else if (and (eq type 'effect') (not (eq item.type 'beastform')))}} From f7e4c5346effe775250db51770cf4a6ae22cfb5d Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:03:35 +0100 Subject: [PATCH 10/51] [Fix] ActiveEffect Autocomplete (#1641) * Added rules and bonuses to ActiveEffect-autocomplete * . --- lang/en.json | 49 +++++++++++++++++++ .../sheets-configs/activeEffectConfig.mjs | 23 ++++++++- module/data/actor/base.mjs | 43 +++++++++++++--- module/data/actor/character.mjs | 25 +++++++--- module/data/actor/companion.mjs | 15 ++++-- 5 files changed, 137 insertions(+), 18 deletions(-) diff --git a/lang/en.json b/lang/en.json index 86b4323c..81408c66 100755 --- a/lang/en.json +++ b/lang/en.json @@ -192,6 +192,9 @@ }, "age": "Age", "backgroundQuestions": "Backgrounds", + "burden": { + "ignore": { "label": "Burden: Ignore", "hint": "Ignore burden rules" } + }, "companionFeatures": "Companion Features", "connections": "Connections", "contextMenu": { @@ -214,6 +217,12 @@ "maxEvasionBonus": "Max Evasion Increase", "maxHPBonus": "Max HP Increase", "pronouns": "Pronouns", + "roll": { + "guaranteedCritical": { + "label": "Guaranteed Critical", + "hint": "Set to 1 to always roll a critical" + } + }, "story": { "backgroundTitle": "Background", "characteristics": "Characteristics", @@ -1840,6 +1849,16 @@ "singular": "Adversary", "plural": "Adversaries" }, + "Attack": { + "hpDamageMultiplier": { + "label": "HP Damage Multiplier", + "hint": "Multiply any damage you deal by this number" + }, + "hpDamageTakenMultiplier": { + "label": "HP Damage Taken Multiplier", + "hint": "Multiply any damage dealt to you by this number" + } + }, "Bonuses": { "rest": { "downtimeAction": "Downtime Action", @@ -2024,16 +2043,40 @@ "reaction": "Reaction Roll" }, "Rules": { + "conditionImmunities": { + "hidden": "Condition Immunity: Hidden", + "restrained": "Condition Immunity: Restrained", + "vulnerable": "Condition Immunity: Vulnerable" + }, "damageReduction": { + "disabledArmor": { "label": "Disabled Armorslots" }, "increasePerArmorMark": { "label": "Damage Reduction per Armor Slot", "hint": "A used armor slot normally reduces damage by one step. This value increases the number of steps damage is reduced by." }, + "magical": { + "label": "Daamge Reduction: Only Magical", + "hint": "Armor can only be used to reduce magical damage" + }, "maxArmorMarkedBonus": "Max Armor Used", "maxArmorMarkedStress": { "label": "Max Armor Used With Stress", "hint": "If this value is set you can use up to that much stress to spend additional Armor Marks beyond your normal maximum." }, + "reduceSeverity": { + "magical": { + "label": "Reduce Damage Severity: Magical", + "hint": "Lowers any magical damage received by the set amount of severity degrees" + }, + "physical": { + "label": "Reduce Damage Severity: Physical", + "hint": "Lowers any physical damage received by the set amount of severity degrees" + } + }, + "physical": { + "label": "Damage Reduction: Only Physical", + "hint": "Armor can only be used to reduce physical damage" + }, "stress": { "any": { "label": "Stress Damage Reduction: Any", @@ -2051,6 +2094,12 @@ "label": "Stress Damage Reduction: Minor", "hint": "The cost in stress you can pay to reduce minor damage to none." } + }, + "thresholdImmunities": { + "minor": { + "label": "Threshold Immunities: Minor", + "hint": "Automatically ignores minor damage" + } } }, "attack": { diff --git a/module/applications/sheets-configs/activeEffectConfig.mjs b/module/applications/sheets-configs/activeEffectConfig.mjs index 9b8edd8a..8abc0b79 100644 --- a/module/applications/sheets-configs/activeEffectConfig.mjs +++ b/module/applications/sheets-configs/activeEffectConfig.mjs @@ -5,6 +5,24 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac super(options); const ignoredActorKeys = ['config', 'DhEnvironment', 'DhParty']; + + const getAllLeaves = (root, group, parentPath = '') => { + const leaves = []; + const rootKey = `${parentPath ? `${parentPath}.` : ''}${root.name}`; + for (const field of Object.values(root.fields)) { + if (field instanceof foundry.data.fields.SchemaField) + leaves.push(...getAllLeaves(field, group, rootKey)); + else + leaves.push({ + value: `${rootKey}.${field.name}`, + label: game.i18n.localize(field.label), + hint: game.i18n.localize(field.hint), + group + }); + } + + return leaves; + }; this.changeChoices = Object.keys(game.system.api.models.actors).reduce((acc, key) => { if (ignoredActorKeys.includes(key)) return acc; @@ -30,7 +48,10 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac return { value: joined, label: getLabel(joined), group }; }); - acc.push(...bars, ...values); + const bonuses = getAllLeaves(model.schema.fields.bonuses, group); + const rules = getAllLeaves(model.schema.fields.rules, group); + + acc.push(...bars, ...values, ...rules, ...bonuses); return acc; }, []); diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 08308eab..5e16bac9 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -29,17 +29,40 @@ const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) => /* Common rules applying to Characters and Adversaries */ export const commonActorRules = (extendedData = { damageReduction: {}, attack: { damage: {} } }) => ({ conditionImmunities: new fields.SchemaField({ - hidden: new fields.BooleanField({ initial: false }), - restrained: new fields.BooleanField({ initial: false }), - vulnerable: new fields.BooleanField({ initial: false }) + hidden: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.hidden' + }), + restrained: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.restrained' + }), + vulnerable: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable' + }) }), damageReduction: new fields.SchemaField({ thresholdImmunities: new fields.SchemaField({ - minor: new fields.BooleanField({ initial: false }) + minor: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.thresholdImmunities.minor.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.thresholdImmunities.minor.hint' + }) }), reduceSeverity: new fields.SchemaField({ - magical: new fields.NumberField({ initial: 0, min: 0 }), - physical: new fields.NumberField({ initial: 0, min: 0 }) + magical: new fields.NumberField({ + initial: 0, + min: 0, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.magical.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.magical.hint' + }), + physical: new fields.NumberField({ + initial: 0, + min: 0, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.physical.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.physical.hint' + }) }), ...(extendedData.damageReduction ?? {}) }), @@ -49,12 +72,16 @@ export const commonActorRules = (extendedData = { damageReduction: {}, attack: { hpDamageMultiplier: new fields.NumberField({ required: true, nullable: false, - initial: 1 + initial: 1, + label: 'DAGGERHEART.GENERAL.Attack.hpDamageMultiplier.label', + hint: 'DAGGERHEART.GENERAL.Attack.hpDamageMultiplier.hint' }), hpDamageTakenMultiplier: new fields.NumberField({ required: true, nullable: false, - initial: 1 + initial: 1, + label: 'DAGGERHEART.GENERAL.Attack.hpDamageTakenMultiplier.label', + hint: 'DAGGERHEART.GENERAL.Attack.hpDamageTakenMultiplier.hint' }), ...(extendedData.attack?.damage ?? {}) }) diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 3913d426..c79bb078 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -225,8 +225,16 @@ export default class DhCharacter extends BaseDataActor { rules: new fields.SchemaField({ ...commonActorRules({ damageReduction: { - magical: new fields.BooleanField({ initial: false }), - physical: new fields.BooleanField({ initial: false }), + magical: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.magical.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.magical.hint' + }), + physical: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.physical.label', + hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.physical.hint' + }), maxArmorMarked: new fields.SchemaField({ value: new fields.NumberField({ required: true, @@ -256,7 +264,10 @@ export default class DhCharacter extends BaseDataActor { label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label', hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint' }), - disabledArmor: new fields.BooleanField({ intial: false }) + disabledArmor: new fields.BooleanField({ + intial: false, + label: 'DAGGERHEART.GENERAL.Rules.damageReduction.disabledArmor.label' + }) }, attack: { damage: { @@ -304,12 +315,14 @@ export default class DhCharacter extends BaseDataActor { label: 'DAGGERHEART.ACTORS.Character.defaultFearDice' }) }), - runeWard: new fields.BooleanField({ initial: false }), burden: new fields.SchemaField({ - ignore: new fields.BooleanField() + ignore: new fields.BooleanField({ label: 'DAGGERHEART.ACTORS.Character.burden.ignore.label' }) }), roll: new fields.SchemaField({ - guaranteedCritical: new fields.BooleanField() + guaranteedCritical: new fields.BooleanField({ + label: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.label', + hint: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.hint' + }) }) }) }; diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 1c25b48c..40cece72 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -53,9 +53,18 @@ export default class DhCompanion extends BaseDataActor { ), rules: new fields.SchemaField({ conditionImmunities: new fields.SchemaField({ - hidden: new fields.BooleanField({ initial: false }), - restrained: new fields.BooleanField({ initial: false }), - vulnerable: new fields.BooleanField({ initial: false }) + hidden: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.hidden' + }), + restrained: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.restrained' + }), + vulnerable: new fields.BooleanField({ + initial: false, + label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable' + }) }) }), attack: new ActionField({ From 4ad8b960b53cf23f8e56e1906aafb5050cbb46c6 Mon Sep 17 00:00:00 2001 From: alterNERDtive <53827887+alterNERDtive@users.noreply.github.com> Date: Sun, 8 Feb 2026 17:30:32 +0000 Subject: [PATCH 11/51] fix: adds actions to prepare downtime actions (#1646) --- lang/en.json | 8 +++ module/config/generalConfig.mjs | 102 +++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/lang/en.json b/lang/en.json index 81408c66..0eab2dbc 100755 --- a/lang/en.json +++ b/lang/en.json @@ -455,6 +455,10 @@ "description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.", "name": "Prepare" }, + "prepareWithFriends": { + "description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.", + "name": "Prepare (with Friends)" + }, "repairArmor": { "description": "Describe how you spend time repairing your armor and clear all of its Armor Slots. You may also do this to an ally's armor instead.", "name": "Repair Armor" @@ -486,6 +490,10 @@ "prepare": { "name": "Prepare", "description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope." + }, + "prepareWithFriends": { + "name": "Prepare (with Friends)", + "description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope." } }, "refreshable": { diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 5e5eecfb..a38d1c8a 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -331,7 +331,56 @@ export const defaultRestOptions = { icon: 'fa-solid fa-dumbbell', img: 'icons/skills/trades/academics-merchant-scribe.webp', description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.description'), - actions: {}, + actions: { + prepare: { + type: 'healing', + systemPath: 'restMoves.shortRest.moves.prepare.actions', + name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.name'), + img: 'icons/skills/trades/academics-merchant-scribe.webp', + actionType: 'action', + chatDisplay: false, + target: { + type: 'self' + }, + damage: { + parts: [ + { + applyTo: healingTypes.hope.id, + value: { + custom: { + enabled: true, + formula: '1' + } + } + } + ] + } + }, + prepareWithFriends: { + type: 'healing', + systemPath: 'restMoves.shortRest.moves.prepare.actions', + name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepareWithFriends.name'), + img: 'icons/skills/trades/academics-merchant-scribe.webp', + actionType: 'action', + chatDisplay: false, + target: { + type: 'self' + }, + damage: { + parts: [ + { + applyTo: healingTypes.hope.id, + value: { + custom: { + enabled: true, + formula: '2' + } + } + } + ] + } + } + }, effects: [] } }), @@ -446,7 +495,56 @@ export const defaultRestOptions = { icon: 'fa-solid fa-dumbbell', img: 'icons/skills/trades/academics-merchant-scribe.webp', description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.description'), - actions: {}, + actions: { + prepare: { + type: 'healing', + systemPath: 'restMoves.longRest.moves.prepare.actions', + name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.name'), + img: 'icons/skills/trades/academics-merchant-scribe.webp', + actionType: 'action', + chatDisplay: false, + target: { + type: 'self' + }, + damage: { + parts: [ + { + applyTo: healingTypes.hope.id, + value: { + custom: { + enabled: true, + formula: '1' + } + } + } + ] + } + }, + prepareWithFriends: { + type: 'healing', + systemPath: 'restMoves.longRest.moves.prepare.actions', + name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepareWithFriends.name'), + img: 'icons/skills/trades/academics-merchant-scribe.webp', + actionType: 'action', + chatDisplay: false, + target: { + type: 'self' + }, + damage: { + parts: [ + { + applyTo: healingTypes.hope.id, + value: { + custom: { + enabled: true, + formula: '2' + } + } + } + ] + } + } + }, effects: [] }, workOnAProject: { From 78012be6e42a5ee53726684235dde9bf41b8b2ce Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sun, 8 Feb 2026 19:14:04 +0100 Subject: [PATCH 12/51] Added delete confirmation to homebrew items --- lang/en.json | 2 ++ module/applications/settings/homebrewSettings.mjs | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lang/en.json b/lang/en.json index 0eab2dbc..9b2b4872 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2613,6 +2613,8 @@ "resetMovesTitle": "Reset {type} Downtime Moves", "resetItemFeaturesTitle": "Reset {type}", "resetMovesText": "Are you sure you want to reset?", + "deleteItemTitle": "Delete Homebrew Item", + "deleteItemText": "Are you sure you want to delete the item?", "FIELDS": { "maxFear": { "label": "Max Fear" }, "maxHope": { "label": "Max Hope" }, diff --git a/module/applications/settings/homebrewSettings.mjs b/module/applications/settings/homebrewSettings.mjs index add3c9e1..51bf439e 100644 --- a/module/applications/settings/homebrewSettings.mjs +++ b/module/applications/settings/homebrewSettings.mjs @@ -103,6 +103,12 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli ? { id: this.selected.adversaryType, ...this.settings.adversaryTypes[this.selected.adversaryType] } : null; break; + case 'downtime': + context.restOptions = { + shortRest: CONFIG.DH.GENERAL.defaultRestOptions.shortRest(), + longRest: CONFIG.DH.GENERAL.defaultRestOptions.longRest() + }; + break; } return context; @@ -225,6 +231,15 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli } static async removeItem(_, target) { + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.localize(`DAGGERHEART.SETTINGS.Homebrew.deleteItemTitle`) + }, + content: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.deleteItemText') + }); + + if (!confirmed) return; + const { type, id } = target.dataset; const isDowntime = ['shortRest', 'longRest'].includes(type); const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`; From f9f252c7a6f9d6de4d86d19c9990dd8d18b38daa Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 8 Feb 2026 19:22:48 +0100 Subject: [PATCH 13/51] Fixed so that node start can accept escaped spaces in the path (#1649) --- tools/run-start.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run-start.mjs b/tools/run-start.mjs index e620d13f..3f6b25cb 100644 --- a/tools/run-start.mjs +++ b/tools/run-start.mjs @@ -18,7 +18,7 @@ const foundryPath = process.env.FOUNDRY_MAIN_PATH || '../../../../FoundryDev/mai const dataPath = process.env.FOUNDRY_DATA_PATH || '../../../'; // Run the original command with proper environment -const args = ['rollup -c --watch', `node "${foundryPath}" --dataPath="${dataPath}" --noupnp`, 'gulp']; +const args = ['rollup -c --watch', `node "\"${foundryPath}\"" --dataPath="${dataPath}" --noupnp`, 'gulp']; spawn('npx', ['concurrently', ...args.map(arg => `"${arg}"`)], { stdio: 'inherit', From d96e72505a7941e991d3771e5fd07d1e43fb10e2 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sun, 8 Feb 2026 22:21:36 +0100 Subject: [PATCH 14/51] Fixed Armor/Weapon sheet showing double 'Configure Attribution' options --- module/applications/sheets/api/item-attachment-sheet.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/module/applications/sheets/api/item-attachment-sheet.mjs b/module/applications/sheets/api/item-attachment-sheet.mjs index 2898f5ac..bcf2fc3c 100644 --- a/module/applications/sheets/api/item-attachment-sheet.mjs +++ b/module/applications/sheets/api/item-attachment-sheet.mjs @@ -1,7 +1,6 @@ export default function ItemAttachmentSheet(Base) { return class extends Base { static DEFAULT_OPTIONS = { - ...super.DEFAULT_OPTIONS, dragDrop: [ ...(super.DEFAULT_OPTIONS.dragDrop || []), { dragSelector: null, dropSelector: '.attachments-section' } From 5413730108f4efbc5824347948a4855dd80d41a6 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 9 Feb 2026 00:25:18 +0100 Subject: [PATCH 15/51] Corrected experience value display to handle negative values aswell --- templates/dialogs/dice-roll/rollSelection.hbs | 2 +- templates/sheets/actors/character/sidebar.hbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/dialogs/dice-roll/rollSelection.hbs b/templates/dialogs/dice-roll/rollSelection.hbs index f31a4fa8..5139c58a 100644 --- a/templates/dialogs/dice-roll/rollSelection.hbs +++ b/templates/dialogs/dice-roll/rollSelection.hbs @@ -118,7 +118,7 @@ {{#if name}}
- {{name}} +{{value}} + {{name}} {{numberFormat value sign=true}}
{{/if}} {{/each}} diff --git a/templates/sheets/actors/character/sidebar.hbs b/templates/sheets/actors/character/sidebar.hbs index 24e68e02..b2757b55 100644 --- a/templates/sheets/actors/character/sidebar.hbs +++ b/templates/sheets/actors/character/sidebar.hbs @@ -145,7 +145,7 @@ {{#each document.system.experiences as |experience id|}}
- +{{experience.value}} + {{numberFormat experience.value sign=true}} {{experience.name}}
From c7431d16a75dfab7a55dee592ecbdafc59dc7e45 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 9 Feb 2026 01:02:59 +0100 Subject: [PATCH 16/51] Improved the Reaction toggle in dice rolls (#1643) --- .../less/dialog/dice-roll/roll-selection.less | 27 ++++++++++++++++++- templates/dialogs/dice-roll/header.hbs | 19 +++++-------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/styles/less/dialog/dice-roll/roll-selection.less b/styles/less/dialog/dice-roll/roll-selection.less index 0f082460..7fdae77a 100644 --- a/styles/less/dialog/dice-roll/roll-selection.less +++ b/styles/less/dialog/dice-roll/roll-selection.less @@ -17,7 +17,9 @@ .dialog-header-inner { display: flex; - justify-content: center; + flex-direction: column; + align-items: center; + gap: 2px; } h1 { @@ -45,6 +47,29 @@ } } + .reaction-chip { + display: flex; + align-items: center; + border-radius: 5px; + width: fit-content; + gap: 5px; + cursor: pointer; + padding: 5px; + background: light-dark(@dark-blue-10, @golden-10); + color: light-dark(@dark-blue, @golden); + + .label { + font-style: normal; + font-weight: 400; + font-size: var(--font-size-14); + line-height: 17px; + } + + &.selected { + background: light-dark(@dark-blue-40, @golden-40); + } + } + .tag-team-controller { display: flex; align-items: center; diff --git a/templates/dialogs/dice-roll/header.hbs b/templates/dialogs/dice-roll/header.hbs index 21967655..0cb58a01 100644 --- a/templates/dialogs/dice-roll/header.hbs +++ b/templates/dialogs/dice-roll/header.hbs @@ -1,17 +1,12 @@
-

- {{#if reactionOverride}} - {{localize "DAGGERHEART.CONFIG.FeatureForm.reaction"}} - {{else}} - {{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}} - {{/if}} - {{#if showReaction}} - - {{/if}} -

+

{{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}}

+ {{#if showReaction}} +
+ + {{localize "DAGGERHEART.GENERAL.reactionRoll"}} +
+ {{/if}}
{{#if (and @root.hasRoll @root.activeTagTeamRoll)}}
From 7c86417752a00630fce52d16da558e211cef310d Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 9 Feb 2026 12:41:13 +0100 Subject: [PATCH 17/51] Added _applyLegacy parse logic for ActiveEffect --- module/documents/activeEffect.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index d0e329ff..dd5f1b55 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -114,6 +114,11 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { super.applyField(model, change, field); } + _applyLegacy(actor, change, changes) { + change.value = DhActiveEffect.getChangeValue(actor, change, change.effect); + super._applyLegacy(actor, change, changes); + } + /** */ static getChangeValue(model, change, effect) { let value = change.value; From b23b6c75fb5651883b72db178992ed7d03e77e64 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Mon, 9 Feb 2026 12:42:00 +0100 Subject: [PATCH 18/51] [Feature] Browser Compendium Handling (#1648) * Initial version * . * Fixed so that CompendiumSetting saving refreshes the CompendiumBrowser for all users * . * Improved design * Fixed max height * Fixed local reload * Added GM restriction * Raised version * Fixed tooltip * Raised verison to 1.7.0 --- lang/en.json | 12 +- .../dialogs/CompendiumBrowserSettings.mjs | 136 ++++++++++++++++++ module/applications/dialogs/_module.mjs | 1 + module/applications/ui/itemBrowser.mjs | 43 +++++- module/config/settingsConfig.mjs | 1 + module/data/_module.mjs | 1 + module/data/compendiumBrowserSettings.mjs | 35 +++++ module/systemRegistration/settings.mjs | 8 +- module/systemRegistration/socket.mjs | 3 +- .../compendiumBrowserPackDialog/sheet.less | 105 ++++++++++++++ styles/less/dialog/index.less | 2 + styles/less/global/elements.less | 8 ++ styles/less/ui/chat/chat.less | 2 +- system.json | 2 +- .../footer.hbs | 3 + .../compendiumBrowserSettingsDialog/packs.hbs | 36 +++++ templates/ui/itemBrowser/sidebar.hbs | 3 +- 17 files changed, 392 insertions(+), 9 deletions(-) create mode 100644 module/applications/dialogs/CompendiumBrowserSettings.mjs create mode 100644 module/data/compendiumBrowserSettings.mjs create mode 100644 styles/less/dialog/compendiumBrowserPackDialog/sheet.less create mode 100644 templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs create mode 100644 templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs diff --git a/lang/en.json b/lang/en.json index 9b2b4872..b1883221 100755 --- a/lang/en.json +++ b/lang/en.json @@ -352,6 +352,11 @@ "requestSpotlight": "Request The Spotlight", "openCountdowns": "Countdowns" }, + "CompendiumBrowserSettings": { + "title": "Enable Compendiums", + "enableSource": "Enable Source", + "disableSource": "Disable Source" + }, "ContextMenu": { "disableEffect": "Disable Effect", "enableEffect": "Enable Effect", @@ -2177,7 +2182,9 @@ "configuration": "Configuration", "base": "Base", "triggers": "Triggers", - "deathMoves": "Deathmoves" + "deathMoves": "Deathmoves", + "sources": "Sources", + "packs": "Packs" }, "Tiers": { "singular": "Tier", @@ -2846,6 +2853,7 @@ "ItemBrowser": { "title": "Daggerheart Compendium Browser", "hint": "Select a Folder in sidebar to start browsing through the compendium", + "browserSettings": "Browser Settings", "searchPlaceholder": "Search...", "columnName": "Name", "tooltipFilters": "Filters", @@ -3002,7 +3010,7 @@ "rulesOn": "Rules On", "rulesOff": "Rules Off", "remainingUses": "Uses refresh on {type}", - "rightClickExtand": "Right-Click to extand", + "rightClickExtend": "Right-Click to extend", "companionPartnerLevelBlock": "The companion needs an assigned partner to level up.", "configureAttribution": "Configure Attribution", "deleteItem": "Delete Item", diff --git a/module/applications/dialogs/CompendiumBrowserSettings.mjs b/module/applications/dialogs/CompendiumBrowserSettings.mjs new file mode 100644 index 00000000..42d0e256 --- /dev/null +++ b/module/applications/dialogs/CompendiumBrowserSettings.mjs @@ -0,0 +1,136 @@ +const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; + +export default class CompendiumBrowserSettings extends HandlebarsApplicationMixin(ApplicationV2) { + constructor() { + super(); + + this.browserSettings = game.settings + .get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings) + .toObject(); + } + + static DEFAULT_OPTIONS = { + tag: 'div', + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'compendium-brower-settings'], + window: { + icon: 'fa-solid fa-book', + title: 'DAGGERHEART.APPLICATIONS.CompendiumBrowserSettings.title' + }, + position: { + width: 500 + }, + actions: { + toggleSource: CompendiumBrowserSettings.#toggleSource, + finish: CompendiumBrowserSettings.#finish + } + }; + + /** @override */ + static PARTS = { + packs: { + id: 'packs', + template: 'systems/daggerheart/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs' + }, + footer: { template: 'systems/daggerheart/templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs' } + }; + + static #browserPackTypes = ['Actor', 'Item']; + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + for (const element of htmlElement.querySelectorAll('.pack-checkbox')) + element.addEventListener('change', this.toggleTypedPack.bind(this)); + } + + /**@inheritdoc */ + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + + const excludedSourceData = this.browserSettings.excludedSources; + const excludedPackData = this.browserSettings.excludedPacks; + context.typePackCollections = game.packs.reduce((acc, pack) => { + const { type, label, packageType, packageName, id } = pack.metadata; + if (packageType === 'world' || !CompendiumBrowserSettings.#browserPackTypes.includes(type)) return acc; + + const sourceChecked = + !excludedSourceData[packageName] || + !excludedSourceData[packageName].excludedDocumentTypes.includes(type); + const sourceLabel = game.modules.get(packageName)?.title ?? game.system.title; + if (!acc[type]) acc[type] = { label: game.i18n.localize(`DOCUMENT.${type}s`), sources: {} }; + if (!acc[type].sources[packageName]) + acc[type].sources[packageName] = { label: sourceLabel, checked: sourceChecked, packs: [] }; + + const checked = !excludedPackData[id] || !excludedPackData[id].excludedDocumentTypes.includes(type); + + acc[type].sources[packageName].packs.push({ + pack: id, + type, + label: id === game.system.id ? game.system.title : game.i18n.localize(label), + checked: checked + }); + + return acc; + }, {}); + + return context; + } + + static #toggleSource(event, button) { + event.stopPropagation(); + + const { type, source } = button.dataset; + const currentlyExcluded = this.browserSettings.excludedSources[source] + ? this.browserSettings.excludedSources[source].excludedDocumentTypes.includes(type) + : false; + + if (!this.browserSettings.excludedSources[source]) + this.browserSettings.excludedSources[source] = { excludedDocumentTypes: [] }; + this.browserSettings.excludedSources[source].excludedDocumentTypes = currentlyExcluded + ? this.browserSettings.excludedSources[source].excludedDocumentTypes.filter(x => x !== type) + : [...(this.browserSettings.excludedSources[source]?.excludedDocumentTypes ?? []), type]; + + const toggleIcon = button.querySelector('a > i'); + toggleIcon.classList.toggle('fa-toggle-off'); + toggleIcon.classList.toggle('fa-toggle-on'); + button.closest('.source-container').querySelector('.checks-container').classList.toggle('collapsed'); + } + + toggleTypedPack(event) { + event.stopPropagation(); + + const { type, pack } = event.target.dataset; + const currentlyExcluded = this.browserSettings.excludedPacks[pack] + ? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.includes(type) + : false; + + if (!this.browserSettings.excludedPacks[pack]) + this.browserSettings.excludedPacks[pack] = { excludedDocumentTypes: [] }; + this.browserSettings.excludedPacks[pack].excludedDocumentTypes = currentlyExcluded + ? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.filter(x => x !== type) + : [...(this.browserSettings.excludedPacks[pack]?.excludedDocumentTypes ?? []), type]; + + this.render(); + } + + static async #finish() { + const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings); + await settings.updateSource(this.browserSettings); + await game.settings.set( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, + settings.toObject() + ); + + this.updated = true; + this.close(); + } + + static async configure() { + return new Promise(resolve => { + const app = new this(); + app.addEventListener('close', () => resolve(app.updated), { once: true }); + app.render({ force: true }); + }); + } +} diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index 4eda8579..a479100a 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -16,3 +16,4 @@ export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs'; export { default as GroupRollDialog } from './group-roll-dialog.mjs'; export { default as TagTeamDialog } from './tagTeamDialog.mjs'; export { default as RiskItAllDialog } from './riskItAllDialog.mjs'; +export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs'; diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index b35573f7..2d882eba 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -1,3 +1,5 @@ +import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; + const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; /** @@ -17,6 +19,15 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig; this.presets = {}; this.compendiumBrowserTypeKey = 'compendiumBrowserDefault'; + + this.setupHooks = Hooks.on(socketEvent.Refresh, ({ refreshType }) => { + if (refreshType === RefreshType.CompendiumBrowser) { + if (this.rendered) { + this.render(); + this.loadItems(); + } + } + }); } /** @inheritDoc */ @@ -35,7 +46,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { selectFolder: this.selectFolder, expandContent: this.expandContent, resetFilters: this.resetFilters, - sortList: this.sortList + sortList: this.sortList, + openSettings: this.openSettings }, position: { left: 100, @@ -157,6 +169,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { context.formatChoices = this.formatChoices; context.items = this.items; context.presets = this.presets; + context.isGM = game.user.isGM; + return context; } @@ -214,6 +228,10 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { loadItems() { let loadTimeout = this.toggleLoader(true); + const browserSettings = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings + ); const promises = []; game.packs.forEach(pack => { @@ -227,7 +245,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { Promise.all(promises).then(async result => { this.items = ItemBrowser.sortBy( - result.flatMap(r => r), + result.flatMap(r => r).filter(r => !browserSettings.isEntryExcluded.bind(browserSettings)(r)), 'name' ); @@ -512,6 +530,22 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { itemListContainer.replaceChildren(...newOrder); } + static async openSettings() { + const settingsUpdated = await game.system.api.applications.dialogs.CompendiumBrowserSettingsDialog.configure(); + if (settingsUpdated) { + if (this.rendered) { + this.render(); + this.loadItems(); + } + await game.socket.emit(`system.${CONFIG.DH.id}`, { + action: socketEvent.Refresh, + data: { + refreshType: RefreshType.CompendiumBrowser + } + }); + } + } + _createDragProcess() { new foundry.applications.ux.DragDrop.implementation({ dragSelector: '.item-container', @@ -571,4 +605,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { headerActions.append(button); } } + + async close(options = {}) { + Hooks.off(socketEvent.Refresh, this.setupHooks); + await super.close(options); + } } diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 3d993949..d3f752bb 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -30,6 +30,7 @@ export const gameSettings = { LastMigrationVersion: 'LastMigrationVersion', TagTeamRoll: 'TagTeamRoll', SpotlightRequestQueue: 'SpotlightRequestQueue', + CompendiumBrowserSettings: 'CompendiumBrowserSettings' }; export const actionAutomationChoices = { diff --git a/module/data/_module.mjs b/module/data/_module.mjs index f7e25a4e..52fa689e 100644 --- a/module/data/_module.mjs +++ b/module/data/_module.mjs @@ -3,6 +3,7 @@ export { default as DhCombatant } from './combatant.mjs'; export { default as DhTagTeamRoll } from './tagTeamRoll.mjs'; export { default as DhRollTable } from './rollTable.mjs'; export { default as RegisteredTriggers } from './registeredTriggers.mjs'; +export { default as CompendiumBrowserSettings } from './compendiumBrowserSettings.mjs'; export * as countdowns from './countdowns.mjs'; export * as actions from './action/_module.mjs'; diff --git a/module/data/compendiumBrowserSettings.mjs b/module/data/compendiumBrowserSettings.mjs new file mode 100644 index 00000000..9e8025dd --- /dev/null +++ b/module/data/compendiumBrowserSettings.mjs @@ -0,0 +1,35 @@ +export default class CompendiumBrowserSettings extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + excludedSources: new fields.TypedObjectField( + new fields.SchemaField({ + excludedDocumentTypes: new fields.ArrayField( + new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES }) + ) + }) + ), + excludedPacks: new fields.TypedObjectField( + new fields.SchemaField({ + excludedDocumentTypes: new fields.ArrayField( + new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES }) + ) + }) + ) + }; + } + + isEntryExcluded(item) { + const pack = game.packs.get(item.pack); + if (!pack) return false; + + const excludedSourceData = this.excludedSources[pack.metadata.packageName]; + if (excludedSourceData && excludedSourceData.excludedDocumentTypes.includes(pack.metadata.type)) return true; + + const excludedPackData = this.excludedPacks[item.pack]; + if (excludedPackData && excludedPackData.excludedDocumentTypes.includes(pack.metadata.type)) return true; + + return false; + } +} diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index 053325a8..49361877 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -7,7 +7,7 @@ import { DhHomebrewSettings, DhVariantRuleSettings } from '../applications/settings/_module.mjs'; -import { DhTagTeamRoll } from '../data/_module.mjs'; +import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs'; export const registerDHSettings = () => { registerMenuSettings(); @@ -142,6 +142,12 @@ const registerNonConfigSettings = () => { config: false, type: DhTagTeamRoll }); + + game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, { + scope: 'client', + config: false, + type: CompendiumBrowserSettings + }); }; /** diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index a9e86917..173ef02b 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -38,7 +38,8 @@ export const RefreshType = { Countdown: 'DhCoundownRefresh', TagTeamRoll: 'DhTagTeamRollRefresh', EffectsDisplay: 'DhEffectsDisplayRefresh', - Scene: 'DhSceneRefresh' + Scene: 'DhSceneRefresh', + CompendiumBrowser: 'DhCompendiumBrowserRefresh' }; export const registerSocketHooks = () => { diff --git a/styles/less/dialog/compendiumBrowserPackDialog/sheet.less b/styles/less/dialog/compendiumBrowserPackDialog/sheet.less new file mode 100644 index 00000000..dfe375b5 --- /dev/null +++ b/styles/less/dialog/compendiumBrowserPackDialog/sheet.less @@ -0,0 +1,105 @@ +.daggerheart.dialog.dh-style.views.compendium-brower-settings { + --text-color: light-dark(@dark-blue, @beige); + color: var(--text-color); + + .window-content { + justify-content: space-between; + + > div { + overflow: auto; + display: flex; + flex-direction: column; + max-height: 440px; + } + } + + .types-container { + display: flex; + flex-direction: column; + gap: 8px; + + .type-container { + display: flex; + flex-direction: column; + gap: 8px; + + > label { + display: flex; + align-items: center; + font-size: var(--font-size-16); + font-family: @font-subtitle; + font-weight: bold; + + &::before { + content: ''; + flex: 1; + height: 2px; + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%); + margin-right: 8px; + } + &::after { + content: ''; + flex: 1; + height: 2px; + background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%); + margin-left: 8px; + } + } + + .sources-container { + display: flex; + flex-direction: column; + gap: 8px; + + .source-container { + display: flex; + flex-direction: column; + gap: 2px; + + .source-inner-container { + display: flex; + justify-content: space-between; + + .source-inner-label-container { + width: 100%; + display: flex; + gap: 8px; + + i { + font-size: 18px; + // color: light-dark(@dark-blue, @golden); + } + } + } + } + } + } + } + + .checks-container { + padding-left: 24px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4px; + transition: height 0.4s ease-in-out; + overflow: hidden; + + &.collapsed { + height: 0px; + } + + .check-container { + display: flex; + align-items: center; + } + } + + footer { + margin-top: 8px; + display: flex; + + button { + flex: 1; + } + } +} diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 733cdd1c..0c70df9f 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -43,3 +43,5 @@ @import './risk-it-all/sheet.less'; @import './character-reset/sheet.less'; + +@import './compendiumBrowserPackDialog/sheet.less'; diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 713a4481..98c05348 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -52,6 +52,14 @@ } } + input[type='checkbox'] { + &:indeterminate { + &::before { + content: '\f0fe'; + } + } + } + input[type='checkbox'], input[type='radio'] { height: 20px; diff --git a/styles/less/ui/chat/chat.less b/styles/less/ui/chat/chat.less index 8728fbda..1e723ed7 100644 --- a/styles/less/ui/chat/chat.less +++ b/styles/less/ui/chat/chat.less @@ -233,7 +233,7 @@ font-family: @font-subtitle; font-size: var(--font-size-18); font-weight: bold; - color: var(--text-color); + color: light-dark(@dark-blue, var(--text-color)); margin-bottom: -2px; } diff --git a/system.json b/system.json index fd0d7e1c..b753b540 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.6.4", + "version": "1.7.0", "compatibility": { "minimum": "13.346", "verified": "13.351", diff --git a/templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs b/templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs new file mode 100644 index 00000000..9dc61cbe --- /dev/null +++ b/templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs b/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs new file mode 100644 index 00000000..dcda8108 --- /dev/null +++ b/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs @@ -0,0 +1,36 @@ +
\ No newline at end of file diff --git a/templates/ui/itemBrowser/sidebar.hbs b/templates/ui/itemBrowser/sidebar.hbs index 28a34a22..a829f8c5 100644 --- a/templates/ui/itemBrowser/sidebar.hbs +++ b/templates/ui/itemBrowser/sidebar.hbs @@ -1,7 +1,8 @@
+ {{#if isGM}}{{/if}}
{{#each compendiums}} -
{{label}}
+
{{label}}
{{#if folders.length}}
From a65514b1c1856de0cfdf97e7d71a1f33564033fc Mon Sep 17 00:00:00 2001 From: WBHarry Date: Mon, 9 Feb 2026 14:25:56 +0100 Subject: [PATCH 19/51] Improved Downtime Prepare translation --- lang/en.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lang/en.json b/lang/en.json index b1883221..618beefc 100755 --- a/lang/en.json +++ b/lang/en.json @@ -457,12 +457,12 @@ "name": "Clear Stress" }, "prepare": { - "description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.", + "description": "Describe how you are preparing for the next day's adventure, then gain a Hope.", "name": "Prepare" }, "prepareWithFriends": { - "description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.", - "name": "Prepare (with Friends)" + "description": "You prepare with one or more members of your party, and you each gain 2 Hope.", + "name": "Prepare (together)" }, "repairArmor": { "description": "Describe how you spend time repairing your armor and clear all of its Armor Slots. You may also do this to an ally's armor instead.", @@ -494,11 +494,11 @@ }, "prepare": { "name": "Prepare", - "description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope." + "description": "Describe how you prepare yourself for the path ahead, then gain a Hope." }, "prepareWithFriends": { - "name": "Prepare (with Friends)", - "description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope." + "name": "Prepare (together)", + "description": "You prepare with one or more members of your party, and you each gain 2 Hope." } }, "refreshable": { From 17ec77a3490cdad17abb86e09dbf17368f5cb5b9 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Wed, 11 Feb 2026 00:31:45 +0100 Subject: [PATCH 20/51] Fixed not being able to open the tokenConfig of actor-less tokens --- module/documents/token.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/documents/token.mjs b/module/documents/token.mjs index 6fd931d6..4ee7ce05 100644 --- a/module/documents/token.mjs +++ b/module/documents/token.mjs @@ -6,7 +6,7 @@ export default class DHToken extends CONFIG.Token.documentClass { const valueGroup = game.i18n.localize('TOKEN.BarValues'); const actorModel = typeKey ? game.system.api.data.actors[`Dh${typeKey.capitalize()}`] : null; const getLabel = path => { - const label = actorModel.schema.getField(path)?.label; + const label = actorModel?.schema.getField(path)?.label; return label ? game.i18n.localize(label) : path; }; From fa1933986867f6d531b639d5f026567f6217c0d4 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Wed, 11 Feb 2026 23:34:10 +0100 Subject: [PATCH 21/51] Fixed better sceneNavigation compatability --- .../ui/scene-navigation/scene-navigation.less | 55 ++++++++++--------- .../ui/sceneNavigation/scene-navigation.hbs | 30 +++++----- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/styles/less/ui/scene-navigation/scene-navigation.less b/styles/less/ui/scene-navigation/scene-navigation.less index 6b97ddec..38768658 100644 --- a/styles/less/ui/scene-navigation/scene-navigation.less +++ b/styles/less/ui/scene-navigation/scene-navigation.less @@ -1,36 +1,39 @@ #ui-left #ui-left-column-2 { flex: 0 0 230px; - .scene-navigation { - .scene-wrapper { - display: flex; - gap: 2px; - height: var(--control-size); - width: 100%; + .scene-wrapper { + display: flex; + gap: 2px; + height: var(--control-size); + width: 100%; - .scene-environment { - padding: 0; + > ul { + margin: 0; + padding: 0; + } - img { - border-radius: 4px; - } + .scene-environment { + padding: 0; + + img { + border-radius: 4px; } } + } - .scene { - justify-content: center; - align-content: center; - background: var(--control-bg-color); - border: 1px solid var(--control-border-color); - border-radius: 4px; - color: var(--control-icon-color); - pointer-events: all; - transition: - border 0.25s, - color 0.25s; - text-shadow: none; - width: 200px; - max-width: 200px; - } + .scene { + justify-content: center; + align-content: center; + background: var(--control-bg-color); + border: 1px solid var(--control-border-color); + border-radius: 4px; + color: var(--control-icon-color); + pointer-events: all; + transition: + border 0.25s, + color 0.25s; + text-shadow: none; + width: 200px; + max-width: 200px; } } diff --git a/templates/ui/sceneNavigation/scene-navigation.hbs b/templates/ui/sceneNavigation/scene-navigation.hbs index 41e9e3e8..0bd59465 100644 --- a/templates/ui/sceneNavigation/scene-navigation.hbs +++ b/templates/ui/sceneNavigation/scene-navigation.hbs @@ -7,17 +7,19 @@ {{#each scenes.active as |scene|}}
  • -
    - {{scene.name}} - {{#if scene.users}} -
      - {{#each scene.users as |user|}} -
    • {{user.letter}}
    • - {{/each}} -
    - {{/if}} -
    +
      +
    • + {{scene.name}} + {{#if scene.users}} +
        + {{#each scene.users as |user|}} +
      • {{user.letter}}
      • + {{/each}} +
      + {{/if}} +
    • +
    {{#if scene.hasEnvironments}} {{/if}} @@ -27,9 +29,11 @@ {{#each scenes.inactive as |scene|}}
  • -
    +
      +
    • {{scene.name}} -
    +
  • +
  • {{/each}}
    From 95d4003045e4451181831c93ecdcdcce8140aee7 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:56:35 +0100 Subject: [PATCH 22/51] Fixed so that messages auto expand the description (#1650) --- module/applications/dialogs/deathMove.mjs | 1 - module/applications/dialogs/downtime.mjs | 6 +++++- module/data/fields/actionField.mjs | 5 ++++- system.json | 2 +- templates/ui/chat/action.hbs | 2 +- templates/ui/chat/deathMove.hbs | 2 +- templates/ui/chat/downtime.hbs | 2 +- 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/module/applications/dialogs/deathMove.mjs b/module/applications/dialogs/deathMove.mjs index a9141158..69ff758e 100644 --- a/module/applications/dialogs/deathMove.mjs +++ b/module/applications/dialogs/deathMove.mjs @@ -200,7 +200,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV description: game.i18n.localize(this.selectedMove.description), result: result, open: autoExpandDescription ? 'open' : '', - chevron: autoExpandDescription ? 'fa-chevron-up' : 'fa-chevron-down', showRiskItAllButton: this.showRiskItAllButton, riskItAllButtonLabel: this.riskItAllButtonLabel, riskItAllHope: this.riskItAllHope diff --git a/module/applications/dialogs/downtime.mjs b/module/applications/dialogs/downtime.mjs index 9a9a9ddb..4c01c2a9 100644 --- a/module/applications/dialogs/downtime.mjs +++ b/module/applications/dialogs/downtime.mjs @@ -196,6 +196,9 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV .filter(x => x.testUserPermission(game.user, 'LIMITED')) .filter(x => x.uuid !== this.actor.uuid); + const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance) + .expandRollMessage?.desc; + const cls = getDocumentClass('ChatMessage'); const msg = { user: game.user.id, @@ -216,7 +219,8 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV actor: { name: this.actor.name, img: this.actor.img }, moves: moves, characters: characters, - selfId: this.actor.uuid + selfId: this.actor.uuid, + open: autoExpandDescription ? 'open' : '' } ), flags: { diff --git a/module/data/fields/actionField.mjs b/module/data/fields/actionField.mjs index 4cadeac4..89c3c287 100644 --- a/module/data/fields/actionField.mjs +++ b/module/data/fields/actionField.mjs @@ -262,6 +262,9 @@ export function ActionMixin(Base) { } async toChat(origin) { + const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance) + .expandRollMessage?.desc; + const cls = getDocumentClass('ChatMessage'); const systemData = { title: game.i18n.localize('DAGGERHEART.CONFIG.FeatureForm.action'), @@ -290,7 +293,7 @@ export function ActionMixin(Base) { system: systemData, content: await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/ui/chat/action.hbs', - systemData + { ...systemData, open: autoExpandDescription ? 'open' : '' } ), flags: { daggerheart: { diff --git a/system.json b/system.json index b753b540..96636bab 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.7.0", + "version": "1.7.1", "compatibility": { "minimum": "13.346", "verified": "13.351", diff --git a/templates/ui/chat/action.hbs b/templates/ui/chat/action.hbs index 65bb0762..2854795c 100644 --- a/templates/ui/chat/action.hbs +++ b/templates/ui/chat/action.hbs @@ -1,5 +1,5 @@
    -
    +
    diff --git a/templates/ui/chat/deathMove.hbs b/templates/ui/chat/deathMove.hbs index 7c677fe3..4df53404 100644 --- a/templates/ui/chat/deathMove.hbs +++ b/templates/ui/chat/deathMove.hbs @@ -7,7 +7,7 @@

    {{this.title}}

    {{localize 'DAGGERHEART.UI.Chat.deathMove.title'}}
    - +
    {{{this.description}}} diff --git a/templates/ui/chat/downtime.hbs b/templates/ui/chat/downtime.hbs index 373724dc..d7152955 100644 --- a/templates/ui/chat/downtime.hbs +++ b/templates/ui/chat/downtime.hbs @@ -1,7 +1,7 @@