From 85ca0e6b603659a4ba53cc9a6b334e433e34ce16 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 11 Jul 2025 18:09:06 +0200 Subject: [PATCH 1/6] Fixed so companion damage uses partner proficiency for scaling (#319) --- module/data/actor/companion.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 1203cc96..88b149e3 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -66,10 +66,9 @@ export default class DhCompanion extends BaseDataActor { damage: { parts: [ { - multiplier: 'flat', value: { dice: 'd6', - multiplier: 'flat' + multiplier: 'prof' } } ] @@ -87,6 +86,12 @@ export default class DhCompanion extends BaseDataActor { }; } + get proficiency() { + return { + total: this.partner?.system?.proficiency?.total ?? 1 + }; + } + prepareBaseData() { const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main; const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.total; From d4cc8e5a49e3d574d70b9df49dff9e164ad1c8e4 Mon Sep 17 00:00:00 2001 From: IrkTheImp <41175833+IrkTheImp@users.noreply.github.com> Date: Fri, 11 Jul 2025 14:50:08 -0500 Subject: [PATCH 2/6] set to use dh ranges by default and made setting world, not client. (#323) --- module/data/settings/RangeMeasurement.mjs | 2 +- module/systemRegistration/settings.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/data/settings/RangeMeasurement.mjs b/module/data/settings/RangeMeasurement.mjs index 71fb7787..552963f0 100644 --- a/module/data/settings/RangeMeasurement.mjs +++ b/module/data/settings/RangeMeasurement.mjs @@ -2,7 +2,7 @@ export default class DhRangeMeasurement extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; return { - enabled: new fields.BooleanField({ required: true, initial: false, label: 'DAGGERHEART.GENERAL.enabled' }), + enabled: new fields.BooleanField({ required: true, initial: true, label: 'DAGGERHEART.GENERAL.enabled' }), melee: new fields.NumberField({ required: true, initial: 5, label: 'DAGGERHEART.CONFIG.Range.melee.name' }), veryClose: new fields.NumberField({ required: true, diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index a4ed05c8..fea12acd 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -60,7 +60,7 @@ const registerMenuSettings = () => { }); game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement, { - scope: 'client', + scope: 'world', config: false, type: DhRangeMeasurement }); From 5b9db88d501f4ee664a269ee7a33967727788cc0 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:53:22 +0200 Subject: [PATCH 3/6] Added a separation of system effects and generic effects on token status effects. Can be turned off in settings. (#317) --- daggerheart.mjs | 14 ++-- lang/en.json | 8 ++- module/applications/_module.mjs | 1 + module/applications/hud/_module.mjs | 1 + module/applications/hud/tokenHUD.mjs | 84 ++++++++++++++++++++++ module/data/settings/Appearance.mjs | 4 ++ styles/daggerheart.less | 2 + styles/less/hud/index.less | 1 + styles/less/hud/token-hud/token-hud.less | 10 +++ templates/hud/tokenHUD.hbs | 78 ++++++++++++++++++++ templates/settings/appearance-settings.hbs | 1 + 11 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 module/applications/hud/_module.mjs create mode 100644 module/applications/hud/tokenHUD.mjs create mode 100644 styles/less/hud/index.less create mode 100644 styles/less/hud/token-hud/token-hud.less create mode 100644 templates/hud/tokenHUD.hbs diff --git a/daggerheart.mjs b/daggerheart.mjs index 4f411b0f..5a6d8193 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -41,10 +41,14 @@ Hooks.once('init', () => { ] ); - CONFIG.statusEffects = Object.values(SYSTEM.GENERAL.conditions).map(x => ({ - ...x, - name: game.i18n.localize(x.name) - })); + CONFIG.statusEffects = [ + ...CONFIG.statusEffects, + ...Object.values(SYSTEM.GENERAL.conditions).map(x => ({ + ...x, + name: game.i18n.localize(x.name), + systemEffect: true + })) + ]; CONFIG.Dice.daggerheart = { DualityDie: DualityDie, @@ -108,6 +112,8 @@ Hooks.once('init', () => { } ); + CONFIG.Token.hudClass = applications.hud.DHTokenHUD; + CONFIG.Combat.dataModels = { base: models.DhCombat }; diff --git a/lang/en.json b/lang/en.json index 02ea41eb..db420652 100755 --- a/lang/en.json +++ b/lang/en.json @@ -279,6 +279,11 @@ } } }, + "HUD": { + "tokenHUD": { + "genericEffects": "Foundry Effects" + } + }, "Levelup": { "actions": { "creatureComfort": { @@ -1180,7 +1185,8 @@ "SETTINGS": { "Appearance": { "FIELDS": { - "displayFear": { "label": "Fear Display" } + "displayFear": { "label": "Fear Display" }, + "showGenericStatusEffects": { "label": "Show Foundry Status Effects" } }, "fearDisplay": { "token": "Tokens", diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index 82c2866c..d4ceb229 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -1,5 +1,6 @@ export * as characterCreation from './characterCreation/_module.mjs'; export * as dialogs from './dialogs/_module.mjs'; +export * as hud from './hud/_module.mjs'; export * as levelup from './levelup/_module.mjs'; export * as settings from './settings/_module.mjs'; export * as sheets from './sheets/_module.mjs'; diff --git a/module/applications/hud/_module.mjs b/module/applications/hud/_module.mjs new file mode 100644 index 00000000..70edaf8f --- /dev/null +++ b/module/applications/hud/_module.mjs @@ -0,0 +1 @@ +export { default as DHTokenHUD } from './tokenHud.mjs'; diff --git a/module/applications/hud/tokenHUD.mjs b/module/applications/hud/tokenHUD.mjs new file mode 100644 index 00000000..9a58bab2 --- /dev/null +++ b/module/applications/hud/tokenHUD.mjs @@ -0,0 +1,84 @@ +export default class DHTokenHUD extends TokenHUD { + static DEFAULT_OPTIONS = { + classes: ['daggerheart'] + }; + + /** @override */ + static PARTS = { + hud: { + root: true, + template: 'systems/daggerheart/templates/hud/tokenHUD.hbs' + } + }; + + async _prepareContext(options) { + const context = await super._prepareContext(options); + context.systemStatusEffects = Object.keys(context.statusEffects).reduce((acc, key) => { + const effect = context.statusEffects[key]; + if (effect.systemEffect) acc[key] = effect; + + return acc; + }, {}); + + const useGeneric = game.settings.get( + CONFIG.DH.id, + CONFIG.DH.SETTINGS.gameSettings.appearance + ).showGenericStatusEffects; + context.genericStatusEffects = useGeneric + ? Object.keys(context.statusEffects).reduce((acc, key) => { + const effect = context.statusEffects[key]; + if (!effect.systemEffect) acc[key] = effect; + + return acc; + }, {}) + : null; + + return context; + } + + _getStatusEffectChoices() { + // Include all HUD-enabled status effects + const choices = {}; + for (const status of CONFIG.statusEffects) { + if ( + status.hud === false || + (foundry.utils.getType(status.hud) === 'Object' && + status.hud.actorTypes?.includes(this.document.actor.type) === false) + ) { + continue; + } + choices[status.id] = { + _id: status._id, + id: status.id, + systemEffect: status.systemEffect, + title: game.i18n.localize(status.name ?? /** @deprecated since v12 */ status.label), + src: status.img ?? /** @deprecated since v12 */ status.icon, + isActive: false, + isOverlay: false + }; + } + + // Update the status of effects which are active for the token actor + const activeEffects = this.actor?.effects || []; + for (const effect of activeEffects) { + for (const statusId of effect.statuses) { + const status = choices[statusId]; + if (!status) continue; + if (status._id) { + if (status._id !== effect.id) continue; + } else { + if (effect.statuses.size !== 1) continue; + } + status.isActive = true; + if (effect.getFlag('core', 'overlay')) status.isOverlay = true; + break; + } + } + + // Flag status CSS class + for (const status of Object.values(choices)) { + status.cssClass = [status.isActive ? 'active' : null, status.isOverlay ? 'overlay' : null].filterJoin(' '); + } + return choices; + } +} diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index 8b04f558..d8b4c687 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -40,6 +40,10 @@ export default class DhAppearance extends foundry.abstract.DataModel { outline: new fields.ColorField({ required: true, initial: '#ffffff' }), edge: new fields.ColorField({ required: true, initial: '#000000' }) }) + }), + showGenericStatusEffects: new fields.BooleanField({ + initial: true, + label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showGenericStatusEffects.label' }) }; } diff --git a/styles/daggerheart.less b/styles/daggerheart.less index 86b504b2..a48131c3 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -3,6 +3,8 @@ @import './less/dialog/index.less'; +@import './less//hud/index.less'; + @import './less/utils/colors.less'; @import './less/utils/fonts.less'; diff --git a/styles/less/hud/index.less b/styles/less/hud/index.less new file mode 100644 index 00000000..459f8fd7 --- /dev/null +++ b/styles/less/hud/index.less @@ -0,0 +1 @@ +@import './token-hud/token-hud.less'; diff --git a/styles/less/hud/token-hud/token-hud.less b/styles/less/hud/token-hud/token-hud.less new file mode 100644 index 00000000..7d231e8c --- /dev/null +++ b/styles/less/hud/token-hud/token-hud.less @@ -0,0 +1,10 @@ +.daggerheart.placeable-hud { + .col.right { + .palette { + .palette-category-title { + grid-column: span var(--effect-columns); + font-weight: bold; + } + } + } +} diff --git a/templates/hud/tokenHUD.hbs b/templates/hud/tokenHUD.hbs new file mode 100644 index 00000000..58d13267 --- /dev/null +++ b/templates/hud/tokenHUD.hbs @@ -0,0 +1,78 @@ +