From 70239ec06a506558672859ccb17749bb4a449e95 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:28:51 +0200 Subject: [PATCH 01/12] [BUG] DiceSoNice fix (#312) * Fixed DiceSoNice integration again * PR fixes * Improved with tertiary --- module/dice/d20Roll.mjs | 8 +------- module/dice/dhRoll.mjs | 2 +- module/dice/dualityRoll.mjs | 4 +++- module/helpers/utils.mjs | 10 ++++------ 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/module/dice/d20Roll.mjs b/module/dice/d20Roll.mjs index c344231f..9c784084 100644 --- a/module/dice/d20Roll.mjs +++ b/module/dice/d20Roll.mjs @@ -1,5 +1,4 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; -import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs'; import DHRoll from './dhRoll.mjs'; export default class D20Roll extends DHRoll { @@ -137,12 +136,7 @@ export default class D20Roll extends DHRoll { static async buildEvaluate(roll, config = {}, message = {}) { if (config.evaluate !== false) await roll.evaluate(); - const advantageState = - config.roll.advantage == this.ADV_MODE.ADVANTAGE - ? true - : config.roll.advantage == this.ADV_MODE.DISADVANTAGE - ? false - : null; + this.postEvaluate(roll, config); } diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 13246ac9..46e7374e 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -154,7 +154,7 @@ export const registerRollDiceHooks = () => { if (updates.length) actor.modifyResource(updates); - if (!config.roll.hasOwnProperty('success') && !config.targets.length) return; + if (!config.roll.hasOwnProperty('success') && !config.targets?.length) return; const rollResult = config.roll.success || config.targets.some(t => t.hit), looseSpotlight = !rollResult || config.roll.result.duality === -1; diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 4d0e99a3..6c1d0fe4 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -1,5 +1,6 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; import D20Roll from './d20Roll.mjs'; +import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs'; export default class DualityRoll extends D20Roll { _advantageFaces = 6; @@ -80,7 +81,6 @@ export default class DualityRoll extends D20Roll { } static getHooks(hooks) { - return [...(hooks ?? []), 'Duality']; } @@ -142,5 +142,7 @@ export default class DualityRoll extends D20Roll { total: roll.dHope.total + roll.dFear.total, label: roll.totalLabel }; + + setDiceSoNiceForDualityRoll(roll, config.roll.advantage.type); } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 0bb2088e..8156736d 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -126,12 +126,10 @@ export const setDiceSoNiceForDualityRoll = (rollResult, advantageState) => { const diceSoNicePresets = getDiceSoNicePresets(); rollResult.dice[0].options = { appearance: diceSoNicePresets.hope }; rollResult.dice[1].options = { appearance: diceSoNicePresets.fear }; //diceSoNicePresets.fear; - if (rollResult.dice[2]) { - if (advantageState === true) { - rollResult.dice[2].options = { appearance: diceSoNicePresets.advantage }; - } else if (advantageState === false) { - rollResult.dice[2].options = { appearance: diceSoNicePresets.disadvantage }; - } + if (rollResult.dice[2] && advantageState) { + rollResult.dice[2].options = { + appearance: advantageState === 1 ? diceSoNicePresets.advantage : diceSoNicePresets.disadvantage + }; } }; From e6126d81045a85eebd37c52fe9ba77027b8e24d7 Mon Sep 17 00:00:00 2001 From: Dapoulp <74197441+Dapoulp@users.noreply.github.com> Date: Fri, 11 Jul 2025 17:36:51 +0200 Subject: [PATCH 02/12] Fix to make Cosmo happy (#318) --- module/data/action/baseAction.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index e193aefe..e2eafbf2 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -180,8 +180,8 @@ export default class DHBaseAction extends foundry.abstract.DataModel { const actorData = this.actor.getRollData(false); // Remove when included directly in Actor getRollData - actorData.prof = actorData.proficiency?.value ?? 1; - actorData.cast = actorData.spellcast?.value ?? 1; + actorData.prof = actorData.proficiency?.total ?? 1; + actorData.cast = actorData.spellcast?.total ?? 1; actorData.result = data.roll?.total ?? 1; /* actorData.scale = data.costs?.length ? data.costs.reduce((a, c) => { 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 03/12] 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 04/12] 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 05/12] 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 @@ +
+
+ + +
+ + + + + + {{#if canConfigure}} + + {{/if}} +
+ +
+
+ {{#if displayBar2}} + + {{/if}} +
+ +
+ {{#if displayBar1}} + + {{/if}} +
+
+ +
+ {{#if isGM}} + + {{/if}} + + +
+ {{#each systemStatusEffects as |status|}} + + {{/each}} + {{#if genericStatusEffects}} + + {{#each genericStatusEffects as |status|}} + + {{/each}} + {{/if}} +
+ + +
+ {{#each movementActions as |action|}} + + {{#if action.icon}}{{/if}} {{action.label}} + + {{/each}} +
+ + + + {{#if canToggleCombat}} + + {{/if}} +
diff --git a/templates/settings/appearance-settings.hbs b/templates/settings/appearance-settings.hbs index 5aa6d28d..da435c75 100644 --- a/templates/settings/appearance-settings.hbs +++ b/templates/settings/appearance-settings.hbs @@ -1,5 +1,6 @@
{{formGroup settingFields.schema.fields.displayFear value=settingFields._source.displayFear localize=true}} + {{formGroup settingFields.schema.fields.showGenericStatusEffects value=settingFields._source.showGenericStatusEffects localize=true}}
{{localize "DAGGERHEART.SETTINGS.Menu.appearance.duality"}} From 72436478c1f7bf13c8581f274b92fe5680799613 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 11 Jul 2025 21:54:18 +0200 Subject: [PATCH 06/12] Added buttons to features on characters, and actions on adversary/environment (#316) --- module/applications/sheets/actors/adversary.mjs | 1 + module/applications/sheets/actors/character.mjs | 15 +++++++++++++++ module/applications/sheets/actors/environment.mjs | 1 + styles/less/global/elements.less | 11 +++++++++++ .../global/partials/inventory-fieldset-items.hbs | 2 +- .../sheets/global/partials/inventory-item.hbs | 8 ++++++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/module/applications/sheets/actors/adversary.mjs b/module/applications/sheets/actors/adversary.mjs index 67f57781..0b01ebee 100644 --- a/module/applications/sheets/actors/adversary.mjs +++ b/module/applications/sheets/actors/adversary.mjs @@ -10,6 +10,7 @@ export default class AdversarySheet extends DHBaseActorSheet { actions: { reactionRoll: AdversarySheet.#reactionRoll, useItem: this.useItem, + useAction: this.useItem, toChat: this.toChat }, window: { diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index e70774f5..ae7ffbf9 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -24,6 +24,7 @@ export default class CharacterSheet extends DHBaseActorSheet { levelManagement: CharacterSheet.#levelManagement, toggleEquipItem: CharacterSheet.#toggleEquipItem, useItem: this.useItem, //TODO Fix this + useAction: this.useAction, toChat: this.toChat }, window: { @@ -620,6 +621,20 @@ export default class CharacterSheet extends DHBaseActorSheet { } } + /** + * Use an action + * @type {ApplicationClickAction} + */ + static async useAction(event, button) { + const item = this.getItem(button); + if (!item) return; + + const action = item.system.actions.find(x => x.id === button.dataset.actionId); + if (!action) return; + + action.use(event); + } + /** * Send item to Chat * @type {ApplicationClickAction} diff --git a/module/applications/sheets/actors/environment.mjs b/module/applications/sheets/actors/environment.mjs index 188d24b4..05958cf5 100644 --- a/module/applications/sheets/actors/environment.mjs +++ b/module/applications/sheets/actors/environment.mjs @@ -11,6 +11,7 @@ export default class DhpEnvironment extends DHBaseActorSheet { }, actions: { useItem: this.useItem, + useAction: this.useItem, toChat: this.toChat }, dragDrop: [{ dragSelector: '.action-section .inventory-item', dropSelector: null }] diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 03772bfb..7466ae8b 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -319,6 +319,17 @@ transform: translateY(-20px); transform-origin: top; } + + .item-buttons { + grid-column: span 3; + display: flex; + gap: 8px; + flex-wrap: wrap; + + button { + white-space: nowrap; + } + } } .application.setting.dh-style { diff --git a/templates/sheets/global/partials/inventory-fieldset-items.hbs b/templates/sheets/global/partials/inventory-fieldset-items.hbs index 92d3a8a6..65c52736 100644 --- a/templates/sheets/global/partials/inventory-fieldset-items.hbs +++ b/templates/sheets/global/partials/inventory-fieldset-items.hbs @@ -17,7 +17,7 @@ {{/each}} {{else}} {{#each values}} - {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=this type=../type hideControls=../hideControls }} + {{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=this type=../type hideControls=../hideControls featureType=true }} {{/each}} {{#each adversaries as |adversary|}} diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 135c3e3c..eae3dd5f 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -171,4 +171,12 @@ {{/unless}}
{{#unless isSidebar}}{{{item.system.description}}}{{/unless}}
+ + {{#if featureType}} +
+ {{#each item.system.actions as | action |}} + + {{/each}} +
+ {{/if}} \ No newline at end of file From b6195127fe629d0dd299eb579a1255774f59aa89 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:26:56 +0200 Subject: [PATCH 07/12] 199 - Tooltips (#311) * Set up templates for all 'advanced' tooltips * Fixed ItemFeature Header label * Fixed less import --- lang/en.json | 21 +++- module/config/actorConfig.mjs | 2 +- module/data/item/armor.mjs | 6 + module/data/item/weapon.mjs | 6 + module/documents/tooltipManager.mjs | 24 +++- module/helpers/handlebarsHelper.mjs | 56 ++++----- module/systemRegistration/handlebars.mjs | 3 +- styles/daggerheart.less | 2 + styles/less/ux/index.less | 1 + styles/less/ux/tooltip/tooltip.less | 106 ++++++++++++++++++ templates/sheets/global/tabs/tab-actions.hbs | 1 + templates/sheets/global/tabs/tab-features.hbs | 2 +- templates/sheets/items/feature/header.hbs | 2 +- templates/ui/tooltip/action.hbs | 83 ++++++++++++++ templates/ui/tooltip/adversary.hbs | 64 +++++++++++ templates/ui/tooltip/armor.hbs | 40 ++++++- templates/ui/tooltip/beastform.hbs | 6 - templates/ui/tooltip/consumable.hbs | 14 +++ templates/ui/tooltip/domainCard.hbs | 34 +++++- templates/ui/tooltip/feature.hbs | 8 ++ templates/ui/tooltip/miscellaneous.hbs | 7 ++ templates/ui/tooltip/parts/tooltipTags.hbs | 12 ++ templates/ui/tooltip/weapon.hbs | 59 +++++++++- 23 files changed, 505 insertions(+), 54 deletions(-) create mode 100644 styles/less/ux/index.less create mode 100644 styles/less/ux/tooltip/tooltip.less create mode 100644 templates/ui/tooltip/action.hbs create mode 100644 templates/ui/tooltip/adversary.hbs delete mode 100644 templates/ui/tooltip/beastform.hbs create mode 100644 templates/ui/tooltip/consumable.hbs create mode 100644 templates/ui/tooltip/feature.hbs create mode 100644 templates/ui/tooltip/miscellaneous.hbs create mode 100644 templates/ui/tooltip/parts/tooltipTags.hbs diff --git a/lang/en.json b/lang/en.json index db420652..f58cba35 100755 --- a/lang/en.json +++ b/lang/en.json @@ -973,6 +973,10 @@ "singular": "Character", "plural": "Characters" }, + "Cost": { + "single": "Cost", + "plural": "Costs" + }, "Damage": { "severe": "Severe", "major": "Major", @@ -1078,6 +1082,7 @@ "specialization": "Specialization", "mastery": "Mastery", "optional": "Optional", + "recovery": "Recovery", "setup": "Setup", "equipment": "Equipment" }, @@ -1099,6 +1104,8 @@ "burden": "Burden", "check": "{check} Check", "criticalSuccess": "Critical Success", + "damage": "Damage", + "damageType": "Damage Type", "description": "Description", "duality": "Duality", "dualityRoll": "Duality Roll", @@ -1111,17 +1118,25 @@ "inactiveEffects": "Inactive Effects", "inventory": "Inventory", "level": "Level", + "max": "Max", "modifier": "Modifier", "multiclass": "Multiclass", + "none": "None", "quantity": "Quantity", "range": "Range", + "recovery": "Recovery", + "scalable": "Scalable", "stress": "Stress", "take": "Take", "target": "Target", "title": "Title", + "true": "True", "type": "Type", "unarmored": "Unarmored", - "use": "Use" + "use": "Use", + "used": "Used", + "uses": "Uses", + "value": "Value" }, "ITEMS": { "Armor": { @@ -1178,6 +1193,7 @@ "spellcastingTrait": "Spellcasting Trait" }, "Weapon": { + "weaponType": "Weapon Type", "primaryWeapon": "Primary Weapon", "secondaryWeapon": "Secondary Weapon" } @@ -1386,7 +1402,8 @@ "unequip": "Unequip", "sendToVault": "Send to Vault", "sendToLoadout": "Send to Loadout", - "makeDeathMove": "Make a Death Move" + "makeDeathMove": "Make a Death Move", + "rangeAndTarget": "Range & Target" } } } diff --git a/module/config/actorConfig.mjs b/module/config/actorConfig.mjs index 7a179308..02cfd4a9 100644 --- a/module/config/actorConfig.mjs +++ b/module/config/actorConfig.mjs @@ -113,7 +113,7 @@ export const adversaryTypes = { }, social: { id: 'social', - label: 'DAGGERHEART.CONFIG.AdversaryTypee.social.label', + label: 'DAGGERHEART.CONFIG.AdversaryType.social.label', description: 'DAGGERHEART.ACTORS.Adversary.social.description' }, solo: { diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index 696a95a2..bf2bf73e 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -44,6 +44,12 @@ export default class DHArmor extends BaseDataItem { }; } + get customActions() { + return this.actions.filter( + action => !this.armorFeatures.some(feature => feature.actionIds.includes(action.id)) + ); + } + async _preUpdate(changes, options, user) { const allowed = await super._preUpdate(changes, options, user); if (allowed === false) return false; diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index e1370395..80c8271d 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -73,6 +73,12 @@ export default class DHWeapon extends BaseDataItem { return [this.attack, ...this.actions]; } + get customActions() { + return this.actions.filter( + action => !this.weaponFeatures.some(feature => feature.actionIds.includes(action.id)) + ); + } + async _preUpdate(changes, options, user) { const allowed = await super._preUpdate(changes, options, user); if (allowed === false) return false; diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index 2e660cff..d9444207 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -2,15 +2,33 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti async activate(element, options = {}) { let html = options.html; if (element.dataset.tooltip?.startsWith('#item#')) { - const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6)); + const splitValues = element.dataset.tooltip.slice(6).split('#action#'); + const itemUuid = splitValues[0]; + const actionId = splitValues.length > 1 ? splitValues[1] : null; + + const baseItem = await foundry.utils.fromUuid(itemUuid); + const item = actionId ? baseItem.system.actions.find(x => x.id === actionId) : baseItem; if (item) { + const type = actionId ? 'action' : item.type; html = await foundry.applications.handlebars.renderTemplate( - `systems/daggerheart/templates/ui/tooltip/${item.type}.hbs`, - item + `systems/daggerheart/templates/ui/tooltip/${type}.hbs`, + { + item: item, + config: CONFIG.DH + } ); + + this.tooltip.innerHTML = html; + options.direction = this._determineItemTooltipDirection(element); } } super.activate(element, { ...options, html: html }); } + + _determineItemTooltipDirection(element) { + const pos = element.getBoundingClientRect(); + const dirs = this.constructor.TOOLTIP_DIRECTIONS; + return dirs[pos.x - this.tooltip.offsetWidth < 0 ? 'DOWN' : 'LEFT']; + } } diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index 6db51225..feeebbd2 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -1,47 +1,49 @@ -import { getWidthOfText } from './utils.mjs'; - export default class RegisterHandlebarsHelpers { static registerHelpers() { Handlebars.registerHelper({ - times: this.times, - join: this.join, add: this.add, - subtract: this.subtract, includes: this.includes, - case: this.case + times: this.times, + damageFormula: this.damageFormula, + damageSymbols: this.damageSymbols, + tertiary: this.tertiary, + signedNumber: this.signedNumber }); } - static times(nr, block) { - var accum = ''; - for (var i = 0; i < nr; ++i) accum += block.fn(i); - return accum; - } - - static join(...options) { - return options.slice(0, options.length - 1); - } - static add(a, b) { const aNum = Number.parseInt(a); const bNum = Number.parseInt(b); return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum); } - static subtract(a, b) { - const aNum = Number.parseInt(a); - const bNum = Number.parseInt(b); - return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum); - } - static includes(list, item) { return list.includes(item); } - static case(value, options) { - if (value == this.switch_value) { - this.switch_break = true; - return options.fn(this); - } + static times(nr, block) { + var accum = ''; + for (var i = 0; i < nr; ++i) accum += block.fn(i); + return accum; + } + + static damageFormula(attack, actor) { + const traitTotal = actor.system.traits?.[attack.roll.trait]?.total; + const instances = [ + attack.damage.parts.map(x => Roll.replaceFormulaData(x.value.getFormula(), actor)).join(' + '), + traitTotal + ].filter(x => x); + + return instances.join(traitTotal > 0 ? ' + ' : ' - '); + } + + static damageSymbols(damageParts) { + const symbols = new Set(); + damageParts.forEach(part => symbols.add(...CONFIG.DH.GENERAL.damageTypes[part.type].icon)); + return new Handlebars.SafeString(Array.from(symbols).map(symbol => ``)); + } + + static tertiary(a, b) { + return a ?? b; } } diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index 75a5aff6..e4cc1a2c 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -22,6 +22,7 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/actionTypes/beastform.hbs', 'systems/daggerheart/templates/settings/components/settings-item-line.hbs', 'systems/daggerheart/templates/ui/chat/parts/damage-chat.hbs', - 'systems/daggerheart/templates/ui/chat/parts/target-chat.hbs' + 'systems/daggerheart/templates/ui/chat/parts/target-chat.hbs', + 'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs' ]); }; diff --git a/styles/daggerheart.less b/styles/daggerheart.less index a48131c3..c2127681 100755 --- a/styles/daggerheart.less +++ b/styles/daggerheart.less @@ -12,4 +12,6 @@ @import './less/ui/index.less'; +@import './less/ux/index.less'; + @import '../node_modules/@yaireo/tagify/dist/tagify.css'; diff --git a/styles/less/ux/index.less b/styles/less/ux/index.less new file mode 100644 index 00000000..ff645288 --- /dev/null +++ b/styles/less/ux/index.less @@ -0,0 +1 @@ +@import './tooltip/tooltip.less'; diff --git a/styles/less/ux/tooltip/tooltip.less b/styles/less/ux/tooltip/tooltip.less new file mode 100644 index 00000000..38502d09 --- /dev/null +++ b/styles/less/ux/tooltip/tooltip.less @@ -0,0 +1,106 @@ +.daggerheart.dh-style.tooltip { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + + .tooltip-title { + margin: 0; + text-align: center; + } + + .tooltip-image { + height: 180px; + width: 180px; + } + + .tooltip-description { + font-style: italic; + } + + .tooltip-sub-title { + margin: 0; + color: light-dark(@dark-blue, @beige); + } + + .tooltip-information-section { + width: 100%; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4px; + + &.triple { + grid-template-columns: 1fr 1fr 1fr; + } + + &.border { + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + padding: 2px; + } + + .tooltip-information { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + + &.full-width { + grid-column: span 2; + } + + label { + font-weight: bold; + } + + label, + div { + white-space: nowrap; + } + } + } + + .tooltip-tags { + width: 100%; + display: flex; + flex-direction: column; + gap: 4px; + + .tooltip-tag { + width: 100%; + display: grid; + grid-template-columns: 80px 1fr; + align-items: start; + gap: 8px; + padding: 4px; + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + + .tooltip-tag-label-container { + display: flex; + align-items: center; + flex-direction: column; + gap: 2px; + + .tooltip-tag-image { + width: 40px; + height: 40px; + } + } + + .tooltip-tag-label { + font-weight: bold; + text-align: center; + } + + .tooltip-tag-description { + display: flex; + flex-wrap: wrap; + } + } + } + + .spaced { + margin-bottom: 4px; + } +} diff --git a/templates/sheets/global/tabs/tab-actions.hbs b/templates/sheets/global/tabs/tab-actions.hbs index 54345bed..ed71c45f 100644 --- a/templates/sheets/global/tabs/tab-actions.hbs +++ b/templates/sheets/global/tabs/tab-actions.hbs @@ -10,6 +10,7 @@
{{action.name}} diff --git a/templates/sheets/global/tabs/tab-features.hbs b/templates/sheets/global/tabs/tab-features.hbs index 71f6f1f1..eced83d7 100644 --- a/templates/sheets/global/tabs/tab-features.hbs +++ b/templates/sheets/global/tabs/tab-features.hbs @@ -11,7 +11,7 @@ data-action="editFeature" id="{{feature.id}}" > - + {{feature.name}}
diff --git a/templates/sheets/items/feature/header.hbs b/templates/sheets/items/feature/header.hbs index e6a11503..e603c0f7 100755 --- a/templates/sheets/items/feature/header.hbs +++ b/templates/sheets/items/feature/header.hbs @@ -4,7 +4,7 @@

-

{{localize (concat 'TYPES.Item.feature' source.system.type)}}

+

{{localize 'TYPES.Item.feature'}}

\ No newline at end of file diff --git a/templates/ui/tooltip/action.hbs b/templates/ui/tooltip/action.hbs new file mode 100644 index 00000000..c101ee68 --- /dev/null +++ b/templates/ui/tooltip/action.hbs @@ -0,0 +1,83 @@ +
+

{{item.name}}

+ +
{{{item.description}}}
+ + {{#if item.uses.max}} +

{{localize "DAGGERHEART.GENERAL.uses"}}

+
+
+ +
{{item.uses.value}}
+
+
+ +
{{item.uses.max}}
+
+
+ + {{#with (lookup config.GENERAL.refreshTypes item.uses.recovery) as | type |}} +
{{localize type.label}}
+ {{/with}} +
+
+ {{/if}} + + {{#if (gt item.cost.length 0)}} +

{{localize "DAGGERHEART.GENERAL.Cost.plural"}}

+ {{#each item.cost as | cost |}} +
+
+ + {{#with (lookup @root.config.GENERAL.abilityCosts cost.type) as | type |}} +
{{localize type.label}}
+ {{/with}} +
+
+ +
{{cost.value}}
+
+ {{#if cost.scalable}} +
+ +
{{localize "DAGGERHEART.GENERAL.true"}}
+
+
+ +
{{cost.step}}
+
+ {{/if}} +
+ {{/each}} + {{/if}} + + {{#if (or item.range item.target)}} +

{{localize "DAGGERHEART.UI.Tooltip.rangeAndTarget"}}

+
+
+ +
+ {{#if item.range}} + {{#with (lookup @root.config.GENERAL.range item.range) as | range |}} +
{{localize range.label}}
+ {{/with}} + {{else}} +
{{localize "DAGGERHEART.GENERAL.none"}}
+ {{/if}} +
+
+
+ +
+ {{#if item.target.type}} + {{#with (lookup @root.config.ACTIONS.targetTypes item.target.type) as | target |}} +
{{@root.item.target.amount}} {{localize target.label}}
+ {{/with}} + {{else}} +
{{localize "DAGGERHEART.GENERAL.none"}}
+ {{/if}} +
+
+
+ {{/if}} +
\ No newline at end of file diff --git a/templates/ui/tooltip/adversary.hbs b/templates/ui/tooltip/adversary.hbs new file mode 100644 index 00000000..5fa559ff --- /dev/null +++ b/templates/ui/tooltip/adversary.hbs @@ -0,0 +1,64 @@ +
+

{{item.name}}

+ +
{{{item.system.description}}}
+ +
+
+ + {{#with (lookup config.GENERAL.tiers item.system.tier) as | tier |}} +
{{localize tier.label}}
+ {{/with}} +
+
+ + {{#with (lookup config.ACTOR.adversaryTypes item.system.type) as | type |}} +
{{localize type.label}}
+ {{/with}} +
+
+ +
{{item.system.difficulty}}
+
+
+
+
+ +
{{item.system.resources.hitPoints.max}}
+
+
+ +
{{item.system.resources.stress.max}}
+
+
+ +
{{item.system.damageThresholds.major}}
+
+
+ +
{{item.system.damageThresholds.severe}}
+
+
+ +
{{numberFormat item.system.attack.roll.bonus sign=true}}
+
+
+ +
{{damageFormula item.system.attack item}}
+
+
+ + {{localize "DAGGERHEART.GENERAL.Experience.plural"}} + {{#each item.system.experiences as | experience |}} +
{{experience.name}} {{numberFormat experience.total sign=true}}
+ {{/each}} + +
+
+ +
{{item.system.motivesAndTactics}}
+
+
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.features }} +
\ No newline at end of file diff --git a/templates/ui/tooltip/armor.hbs b/templates/ui/tooltip/armor.hbs index c2972700..456fb226 100644 --- a/templates/ui/tooltip/armor.hbs +++ b/templates/ui/tooltip/armor.hbs @@ -1,5 +1,37 @@ -
-
{{name}}
- -
{{{system.description}}}
+
+

{{item.name}}

+ +
{{{item.system.description}}}
+ +
+
+ +
{{item.system.baseScore}}
+
+ +
+ +
{{item.system.baseThresholds.major}}
+
+
+ +
{{item.system.baseThresholds.severe}}
+
+
+ + {{#if (gt item.system.armorFeatures.length 0)}}

{{localize "DAGGERHEART.GENERAL.features"}}

{{/if}} +
+ {{#each item.system.armorFeatures}} + {{#with (lookup ../config.ITEM.armorFeatures this.value) as | feature | }} +
+
+
{{localize feature.label}}
+
+
{{{localize feature.description}}}
+
+ {{/with}} + {{/each}} +
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions label=(localize "DAGGERHEART.GENERAL.Action.plural")}}
\ No newline at end of file diff --git a/templates/ui/tooltip/beastform.hbs b/templates/ui/tooltip/beastform.hbs deleted file mode 100644 index 3af49969..00000000 --- a/templates/ui/tooltip/beastform.hbs +++ /dev/null @@ -1,6 +0,0 @@ -
-
{{name}}
- -
{{{system.examples}}}
-
{{system.advantageOn}}
-
\ No newline at end of file diff --git a/templates/ui/tooltip/consumable.hbs b/templates/ui/tooltip/consumable.hbs new file mode 100644 index 00000000..2c998b1d --- /dev/null +++ b/templates/ui/tooltip/consumable.hbs @@ -0,0 +1,14 @@ +
+

{{item.name}}

+ +
{{{item.system.description}}}
+ +
+
+ +
{{item.system.quantity}}
+
+
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }} +
\ No newline at end of file diff --git a/templates/ui/tooltip/domainCard.hbs b/templates/ui/tooltip/domainCard.hbs index c2972700..dad00b1b 100644 --- a/templates/ui/tooltip/domainCard.hbs +++ b/templates/ui/tooltip/domainCard.hbs @@ -1,5 +1,31 @@ -
-
{{name}}
- -
{{{system.description}}}
+
+

{{item.name}}

+ +
{{{item.system.description}}}
+ +
+
+ + {{#with (lookup config.DOMAIN.domains item.system.domain) as | domain |}} +
{{localize domain.label}}
+ {{/with}} +
+ +
+ + {{#with (lookup config.DOMAIN.cardTypes item.system.type) as | type |}} +
{{localize type.label}}
+ {{/with}} +
+
+ +
{{item.system.level}}
+
+
+ +
{{item.system.recallCost}}
+
+
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
\ No newline at end of file diff --git a/templates/ui/tooltip/feature.hbs b/templates/ui/tooltip/feature.hbs new file mode 100644 index 00000000..17ff2db6 --- /dev/null +++ b/templates/ui/tooltip/feature.hbs @@ -0,0 +1,8 @@ +
+

{{item.name}}

+ +
{{{item.system.description}}}
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }} + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.effects label=(localize "DAGGERHEART.GENERAL.Effect.plural") }} +
\ No newline at end of file diff --git a/templates/ui/tooltip/miscellaneous.hbs b/templates/ui/tooltip/miscellaneous.hbs new file mode 100644 index 00000000..83014a88 --- /dev/null +++ b/templates/ui/tooltip/miscellaneous.hbs @@ -0,0 +1,7 @@ +
+

{{item.name}}

+ +
{{{item.system.description}}}
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.actions label=(localize "DAGGERHEART.GENERAL.Action.plural") }} +
\ No newline at end of file diff --git a/templates/ui/tooltip/parts/tooltipTags.hbs b/templates/ui/tooltip/parts/tooltipTags.hbs new file mode 100644 index 00000000..a02a729a --- /dev/null +++ b/templates/ui/tooltip/parts/tooltipTags.hbs @@ -0,0 +1,12 @@ +{{#if (gt features.length 0)}}

{{label}}

{{/if}} +
+ {{#each features as | feature |}} +
+
+
{{localize feature.name}}
+ {{#if feature.img}}{{/if}} +
+
{{{localize (tertiary feature.description feature.system.description)}}}
+
+ {{/each}} +
\ No newline at end of file diff --git a/templates/ui/tooltip/weapon.hbs b/templates/ui/tooltip/weapon.hbs index c2972700..963b0714 100644 --- a/templates/ui/tooltip/weapon.hbs +++ b/templates/ui/tooltip/weapon.hbs @@ -1,5 +1,56 @@ -
-
{{name}}
- -
{{{system.description}}}
+
+

{{item.name}}

+ +
{{{item.system.description}}}
+ +
+
+ +
{{#if item.system.secondaryWeapon}}{{localize "DAGGERHEART.ITEMS.Weapon.secondaryWeapon"}}{{else}}{{localize "DAGGERHEART.ITEMS.Weapon.primaryWeapon"}}{{/if}}
+
+
+ + {{#with (lookup config.GENERAL.burden item.system.burden) as | burden |}} +
{{localize burden.label}}
+ {{/with}} +
+ {{#if item.system.attack.roll.trait}} +
+ + {{#with (lookup config.ACTOR.abilities item.system.attack.roll.trait) as | trait |}} +
{{localize trait.label}}
+ {{/with}} +
+ {{/if}} +
+ + {{#with (lookup config.GENERAL.range item.system.attack.range) as | range |}} +
{{localize range.label}}
+ {{/with}} +
+
+ +
{{{damageFormula item.system.attack item.parent}}}
+
+
+ +
{{{damageSymbols item.system.attack.damage.parts}}}
+
+
+ + {{#if (gt item.system.weaponFeatures.length 0)}}

{{localize "DAGGERHEART.GENERAL.features"}}

{{/if}} +
+ {{#each item.system.weaponFeatures}} + {{#with (lookup ../config.ITEM.weaponFeatures this.value) as | feature | }} +
+
+
{{localize feature.label}}
+
+
{{{localize feature.description}}}
+
+ {{/with}} + {{/each}} +
+ + {{> "systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs" features=item.system.customActions label=(localize "DAGGERHEART.GENERAL.Action.plural") }}
\ No newline at end of file From dee398347fd392cfd418295ecd3cbe10f5cbb81d Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 12 Jul 2025 09:44:14 -0300 Subject: [PATCH 08/12] fix style problems in bottom sheets and enhance damage and action dialogs (#325) --- lang/en.json | 4 ++ .../dialogs/costSelectionDialog.mjs | 2 +- module/applications/dialogs/damageDialog.mjs | 13 +++++- .../dialogs/damageSelectionDialog.mjs | 2 +- module/applications/sheets/items/feature.mjs | 9 +++- module/documents/item.mjs | 8 +++- styles/less/dialog/actions/action-list.less | 19 +++++++++ .../less/dialog/damage-selection/sheet.less | 20 +++++++++ .../less/dialog/dice-roll/roll-selection.less | 10 ----- styles/less/dialog/index.less | 4 ++ styles/less/global/dialog.less | 16 +++++++ styles/less/global/elements.less | 9 ++-- styles/less/global/sheet.less | 6 ++- .../adversary-settings/experiences.less | 1 + .../adversary-settings/features.less | 1 + .../environment-settings/adversaries.less | 1 + .../environment-settings/features.less | 1 + styles/less/utils/colors.less | 2 + templates/actionTypes/actionType.hbs | 15 ++++--- templates/dialogs/actionSelect.hbs | 14 +++---- .../dialogs/dice-roll/damageSelection.hbs | 42 +++++-------------- 21 files changed, 129 insertions(+), 70 deletions(-) create mode 100644 styles/less/dialog/actions/action-list.less create mode 100644 styles/less/dialog/damage-selection/sheet.less diff --git a/lang/en.json b/lang/en.json index f58cba35..e14a3bc3 100755 --- a/lang/en.json +++ b/lang/en.json @@ -677,6 +677,10 @@ "name": "Dice Set" } }, + "SelectAction": { + "selectType": "Select Action Type", + "selectAction": "Select Action" + }, "Traits": { "agility": { "name": "Agility", diff --git a/module/applications/dialogs/costSelectionDialog.mjs b/module/applications/dialogs/costSelectionDialog.mjs index 026aac46..abb79e6a 100644 --- a/module/applications/dialogs/costSelectionDialog.mjs +++ b/module/applications/dialogs/costSelectionDialog.mjs @@ -11,7 +11,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl static DEFAULT_OPTIONS = { tag: 'form', - classes: ['daggerheart', 'views', 'damage-selection'], + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'damage-selection'], position: { width: 400, height: 'auto' diff --git a/module/applications/dialogs/damageDialog.mjs b/module/applications/dialogs/damageDialog.mjs index 442a1491..4030d7a7 100644 --- a/module/applications/dialogs/damageDialog.mjs +++ b/module/applications/dialogs/damageDialog.mjs @@ -11,11 +11,14 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application static DEFAULT_OPTIONS = { tag: 'form', id: 'roll-selection', - classes: ['daggerheart', 'views', 'damage-selection'], + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'damage-selection'], position: { width: 400, height: 'auto' }, + window: { + icon: 'fa-solid fa-dice' + }, actions: { submitRoll: this.submitRoll }, @@ -34,9 +37,15 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application } }; + get title() { + return game.i18n.localize('DAGGERHEART.EFFECTS.ApplyLocations.damageRoll.name'); + } + async _prepareContext(_options) { const context = await super._prepareContext(_options); - context.title = this.config.title; + context.title = this.config.title + ? this.config.title + : game.i18n.localize('DAGGERHEART.EFFECTS.ApplyLocations.damageRoll.name'); context.extraFormula = this.config.extraFormula; context.formula = this.roll.constructFormula(this.config); return context; diff --git a/module/applications/dialogs/damageSelectionDialog.mjs b/module/applications/dialogs/damageSelectionDialog.mjs index 5248e81d..547ba87c 100644 --- a/module/applications/dialogs/damageSelectionDialog.mjs +++ b/module/applications/dialogs/damageSelectionDialog.mjs @@ -23,7 +23,7 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap static DEFAULT_OPTIONS = { tag: 'form', - classes: ['daggerheart', 'views', 'damage-selection'], + classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'damage-selection'], position: { width: 400, height: 'auto' diff --git a/module/applications/sheets/items/feature.mjs b/module/applications/sheets/items/feature.mjs index a54c3bcb..3d13d7de 100644 --- a/module/applications/sheets/items/feature.mjs +++ b/module/applications/sheets/items/feature.mjs @@ -61,12 +61,17 @@ export default class FeatureSheet extends DHBaseItemSheet { static async selectActionType() { const content = await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/actionTypes/actionType.hbs', - { types: CONFIG.DH.ACTIONS.actionTypes } + { + types: CONFIG.DH.ACTIONS.actionTypes, + itemName: game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectType') + } ), - title = 'Select Action Type'; + title = game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectType'); + console.log(this.document); return foundry.applications.api.DialogV2.prompt({ window: { title }, + classes: ['daggerheart', 'dh-style'], content, ok: { label: title, diff --git a/module/documents/item.mjs b/module/documents/item.mjs index db34fa49..6c3732db 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -80,12 +80,16 @@ export default class DHItem extends foundry.documents.Item { async selectActionDialog(prevEvent) { const content = await foundry.applications.handlebars.renderTemplate( 'systems/daggerheart/templates/dialogs/actionSelect.hbs', - { actions: this.system.actionsList } + { + actions: this.system.actionsList, + itemName: this.name + } ), - title = 'Select Action'; + title = game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectAction'); return foundry.applications.api.DialogV2.prompt({ window: { title }, + classes: ['daggerheart', 'dh-style'], content, ok: { label: title, diff --git a/styles/less/dialog/actions/action-list.less b/styles/less/dialog/actions/action-list.less new file mode 100644 index 00000000..800f7d8e --- /dev/null +++ b/styles/less/dialog/actions/action-list.less @@ -0,0 +1,19 @@ +@import '../../utils/fonts.less'; + +.application.daggerheart.dh-style { + .actions-list { + display: flex; + flex-direction: column; + gap: 10px; + + .action-item { + display: flex; + align-items: center; + gap: 5px; + + .label { + font-family: @font-body; + } + } + } +} diff --git a/styles/less/dialog/damage-selection/sheet.less b/styles/less/dialog/damage-selection/sheet.less new file mode 100644 index 00000000..43e4f4d2 --- /dev/null +++ b/styles/less/dialog/damage-selection/sheet.less @@ -0,0 +1,20 @@ +@import '../../utils/colors.less'; + +.daggerheart.dialog.dh-style.views.damage-selection { + .damage-section-container { + display: flex; + flex-direction: column; + gap: 12px; + + input[type='text'], + input[type='number'] { + color: light-dark(@dark, @beige); + outline: 2px solid transparent; + transition: all 0.3s ease; + + &:hover { + outline: 2px solid light-dark(@dark, @beige); + } + } + } +} diff --git a/styles/less/dialog/dice-roll/roll-selection.less b/styles/less/dialog/dice-roll/roll-selection.less index b2f05dc2..575b7ce9 100644 --- a/styles/less/dialog/dice-roll/roll-selection.less +++ b/styles/less/dialog/dice-roll/roll-selection.less @@ -114,15 +114,5 @@ } } } - - .formula-label { - font-family: @font-body; - font-style: normal; - font-weight: 500; - font-size: 14px; - line-height: 17px; - - color: light-dark(@dark, @beige); - } } } diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 40280270..545ce2e1 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -4,6 +4,10 @@ @import './level-up/summary-container.less'; @import './level-up/tiers-container.less'; +@import './actions/action-list.less'; + +@import './damage-selection/sheet.less'; + @import './downtime/downtime-container.less'; @import './beastform/beastform-container.less'; diff --git a/styles/less/global/dialog.less b/styles/less/global/dialog.less index 3856facb..11a4eee9 100644 --- a/styles/less/global/dialog.less +++ b/styles/less/global/dialog.less @@ -1,5 +1,6 @@ @import '../utils/colors.less'; @import '../utils/fonts.less'; +@import '../utils/mixin.less'; .appTheme({ &.dialog { @@ -40,4 +41,19 @@ } } } + + .submit-btn { + width: 100%; + height: 38px; + } + + .formula-label { + font-family: @font-body; + font-style: normal; + font-weight: 500; + font-size: 14px; + line-height: 17px; + + color: light-dark(@dark, @beige); + } } diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 7466ae8b..84c90336 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -35,15 +35,16 @@ } } - input[type='checkbox'] { + input[type='checkbox'], + input[type='radio'] { &:checked::after { - color: light-dark(@dark, @golden); + color: light-dark(@dark-40, @golden); } &:checked::before { - color: light-dark(transparent, @dark-blue); + color: light-dark(@dark-40, @golden-40); } &::before { - color: light-dark(@dark, @beige); + color: light-dark(@dark-40, @golden-40); } } diff --git a/styles/less/global/sheet.less b/styles/less/global/sheet.less index 1e44d7a0..1a00239a 100755 --- a/styles/less/global/sheet.less +++ b/styles/less/global/sheet.less @@ -4,8 +4,8 @@ // Theme handling .appTheme({ - background: @semi-transparent-dark-blue; - backdrop-filter: blur(9px); + background: @dark-blue-60; + backdrop-filter: blur(10px); }, { background: url('../assets/parchments/dh-parchment-light.png') no-repeat center; }); @@ -44,6 +44,8 @@ top: -36px; min-height: -webkit-fill-available; transition: opacity 0.3s ease; + padding-bottom: 20px; + margin-bottom: -36px; .tab { padding: 0 10px; diff --git a/styles/less/sheets-settings/adversary-settings/experiences.less b/styles/less/sheets-settings/adversary-settings/experiences.less index 89a7c2d9..05595ed4 100644 --- a/styles/less/sheets-settings/adversary-settings/experiences.less +++ b/styles/less/sheets-settings/adversary-settings/experiences.less @@ -5,6 +5,7 @@ .tab.experiences { .add-experience-btn { width: 100%; + height: 38px; margin-bottom: 12px; } diff --git a/styles/less/sheets-settings/adversary-settings/features.less b/styles/less/sheets-settings/adversary-settings/features.less index 5798bfa9..037a08ea 100644 --- a/styles/less/sheets-settings/adversary-settings/features.less +++ b/styles/less/sheets-settings/adversary-settings/features.less @@ -10,6 +10,7 @@ .add-feature-btn { width: 100%; + height: 38px; margin-bottom: 12px; } diff --git a/styles/less/sheets-settings/environment-settings/adversaries.less b/styles/less/sheets-settings/environment-settings/adversaries.less index ba8cc8e4..8dc12c87 100644 --- a/styles/less/sheets-settings/environment-settings/adversaries.less +++ b/styles/less/sheets-settings/environment-settings/adversaries.less @@ -10,6 +10,7 @@ .add-action-btn { width: 100%; + height: 38px; margin-bottom: 12px; } diff --git a/styles/less/sheets-settings/environment-settings/features.less b/styles/less/sheets-settings/environment-settings/features.less index e4bb039f..f2a9583a 100644 --- a/styles/less/sheets-settings/environment-settings/features.less +++ b/styles/less/sheets-settings/environment-settings/features.less @@ -10,6 +10,7 @@ .add-feature-btn { width: 100%; + height: 38px; margin-bottom: 12px; } diff --git a/styles/less/utils/colors.less b/styles/less/utils/colors.less index 3e72b743..622480a7 100755 --- a/styles/less/utils/colors.less +++ b/styles/less/utils/colors.less @@ -25,10 +25,12 @@ @dark-blue-10: #18162e10; @dark-blue-40: #18162e40; @dark-blue-50: #18162e50; +@dark-blue-60: #18162e60; @semi-transparent-dark-blue: rgba(24, 22, 46, 0.33); @dark: #222; @dark-15: #22222215; +@dark-40: #22222240; @deep-black: #0e0d15; diff --git a/templates/actionTypes/actionType.hbs b/templates/actionTypes/actionType.hbs index fdffaabe..1cd912e9 100644 --- a/templates/actionTypes/actionType.hbs +++ b/templates/actionTypes/actionType.hbs @@ -1,13 +1,12 @@
-
    +
    +

    {{itemName}}

    +
    +
      {{#each types}} -
    • - +
    • + + {{localize name}}
    • {{/each}}
    diff --git a/templates/dialogs/actionSelect.hbs b/templates/dialogs/actionSelect.hbs index 2ea76cae..200ef29c 100644 --- a/templates/dialogs/actionSelect.hbs +++ b/templates/dialogs/actionSelect.hbs @@ -1,12 +1,12 @@ -
      +
      +

      {{itemName}}

      +
      +
        {{#each actions}} -
      • - +
      • + + {{ name }}
      • {{/each}}
      diff --git a/templates/dialogs/dice-roll/damageSelection.hbs b/templates/dialogs/dice-roll/damageSelection.hbs index 988b852e..0286990e 100644 --- a/templates/dialogs/dice-roll/damageSelection.hbs +++ b/templates/dialogs/dice-roll/damageSelection.hbs @@ -1,33 +1,13 @@ -
      +
      +
      +

      {{title}}

      +
      + Formula: {{@root.formula}}
      - -
      - {{!-- --}} -
      {{@root.formula}}
      -
      -
      - -
      +
      - {{!-- {{#each bonusDamage as |damage index|}} -
      - -
      - - - {{#if (and damage.initiallySelected damage.hopeIncrease)}} - - -
      - -
      {{damage.hopeUses}}
      - -
      - {{/if}} -
      -
      - {{/each}} --}} -
      - -
      -
      \ No newline at end of file + + \ No newline at end of file From 3f4c8849740fce0208b05dc8414cc438f997770e Mon Sep 17 00:00:00 2001 From: Murilo Brito <91566541+moliloo@users.noreply.github.com> Date: Sat, 12 Jul 2025 14:14:44 -0300 Subject: [PATCH 09/12] fix firefox problems (#329) --- styles/less/sheets/actors/adversary/sheet.less | 1 + styles/less/sheets/actors/adversary/sidebar.less | 3 ++- styles/less/sheets/actors/character/sheet.less | 1 + styles/less/sheets/actors/character/sidebar.less | 3 ++- styles/less/sheets/actors/companion/header.less | 6 +++++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/styles/less/sheets/actors/adversary/sheet.less b/styles/less/sheets/actors/adversary/sheet.less index af7918c6..286351c9 100644 --- a/styles/less/sheets/actors/adversary/sheet.less +++ b/styles/less/sheets/actors/adversary/sheet.less @@ -9,6 +9,7 @@ gap: 15px 0; height: 100%; width: 100%; + padding-bottom: 0; .adversary-sidebar-sheet { grid-row: 1 / span 2; diff --git a/styles/less/sheets/actors/adversary/sidebar.less b/styles/less/sheets/actors/adversary/sidebar.less index e50ba0c9..c1bd1856 100644 --- a/styles/less/sheets/actors/adversary/sidebar.less +++ b/styles/less/sheets/actors/adversary/sidebar.less @@ -110,10 +110,11 @@ justify-content: space-evenly; .status-bar { + display: flex; + justify-content: center; position: relative; width: 100px; height: 40px; - justify-items: center; .status-label { position: relative; diff --git a/styles/less/sheets/actors/character/sheet.less b/styles/less/sheets/actors/character/sheet.less index f2c9bb1a..8afd7404 100644 --- a/styles/less/sheets/actors/character/sheet.less +++ b/styles/less/sheets/actors/character/sheet.less @@ -9,6 +9,7 @@ gap: 15px 0; height: 100%; width: 100%; + padding-bottom: 0; overflow: auto; .character-sidebar-sheet { diff --git a/styles/less/sheets/actors/character/sidebar.less b/styles/less/sheets/actors/character/sidebar.less index d6ceab46..f46a9628 100644 --- a/styles/less/sheets/actors/character/sidebar.less +++ b/styles/less/sheets/actors/character/sidebar.less @@ -70,10 +70,11 @@ justify-content: space-evenly; .status-bar { + display: flex; + justify-content: center; position: relative; width: 100px; height: 40px; - justify-items: center; .status-label { position: relative; diff --git a/styles/less/sheets/actors/companion/header.less b/styles/less/sheets/actors/companion/header.less index fac32ea5..832a6050 100644 --- a/styles/less/sheets/actors/companion/header.less +++ b/styles/less/sheets/actors/companion/header.less @@ -45,7 +45,9 @@ justify-content: center; .status-number { - justify-items: center; + display: flex; + flex-direction: column; + align-items: center; .status-value { position: relative; @@ -85,6 +87,8 @@ } .status-bar { + display: flex; + justify-content: center; position: relative; width: 100px; height: 40px; From 812a5e8dd7f646698ac8dbb1881c8bf5851a798d Mon Sep 17 00:00:00 2001 From: Dapoulp <74197441+Dapoulp@users.noreply.github.com> Date: Sat, 12 Jul 2025 20:13:09 +0200 Subject: [PATCH 10/12] Feature/167 damage types and resistances (#330) * Add Resistances * Relocate Damage Reduction * Damage Types * dmg type fallback * Actor getRollData * Remove comments --- lang/en.json | 5 ++ .../dialogs/damageReductionDialog.mjs | 2 +- .../sheets-configs/action-config.mjs | 6 +-- module/applications/ui/chatLog.mjs | 2 +- module/config/generalConfig.mjs | 4 +- module/config/itemConfig.mjs | 2 +- module/data/action/actionDice.mjs | 27 +++++----- module/data/action/baseAction.mjs | 11 +--- module/data/action/damageAction.mjs | 8 ++- module/data/actor/adversary.mjs | 9 +++- module/data/actor/base.mjs | 20 +++++-- module/data/actor/character.mjs | 5 +- module/data/actor/companion.mjs | 2 + module/data/actor/environment.mjs | 5 +- module/data/item/weapon.mjs | 1 + module/dice/damageRoll.mjs | 4 ++ module/dice/dhRoll.mjs | 2 +- module/documents/actor.mjs | 54 ++++++++++++------- module/helpers/utils.mjs | 27 +++------- styles/less/global/elements.less | 34 ++++++++++++ templates/actionTypes/damage.hbs | 2 +- templates/sheets/actors/adversary/sidebar.hbs | 8 +-- .../sheets/global/partials/inventory-item.hbs | 18 ++++--- templates/sheets/items/weapon/header.hbs | 6 ++- 24 files changed, 167 insertions(+), 97 deletions(-) diff --git a/lang/en.json b/lang/en.json index e14a3bc3..2e938914 100755 --- a/lang/en.json +++ b/lang/en.json @@ -987,6 +987,11 @@ "minor": "Minor", "none": "None" }, + "DamageResistance": { + "none": "None", + "resistance": "Resistance", + "immunity": "Immunity" + }, "DamageThresholds": { "title": "Damage Thresholds", "minor": "Minor", diff --git a/module/applications/dialogs/damageReductionDialog.mjs b/module/applications/dialogs/damageReductionDialog.mjs index 0612089d..0a0ebce1 100644 --- a/module/applications/dialogs/damageReductionDialog.mjs +++ b/module/applications/dialogs/damageReductionDialog.mjs @@ -11,7 +11,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap this.actor = actor; this.damage = damage; - const canApplyArmor = actor.system.armorApplicableDamageTypes[damageType]; + const canApplyArmor = damageType.every(t => actor.system.armorApplicableDamageTypes[t] === true); const maxArmorMarks = canApplyArmor ? Math.min( actor.system.armorScore - actor.system.armor.system.marks.value, diff --git a/module/applications/sheets-configs/action-config.mjs b/module/applications/sheets-configs/action-config.mjs index 0beb8d79..8823fa07 100644 --- a/module/applications/sheets-configs/action-config.mjs +++ b/module/applications/sheets-configs/action-config.mjs @@ -56,10 +56,6 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { id: 'effect', template: 'systems/daggerheart/templates/sheets-settings/action-settings/effect.hbs' } - /* form: { - id: 'action', - template: 'systems/daggerheart/templates/config/action.hbs' - } */ }; static TABS = { @@ -161,7 +157,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { container = foundry.utils.getProperty(this.action.parent, this.action.systemPath); let newActions; if (Array.isArray(container)) { - newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way + newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); } else newActions = data; diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 71532733..e8f699e4 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -215,7 +215,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo if (message.system.onSave && message.system.targets.find(t => t.id === target.id)?.saved?.success === true) damage = Math.ceil(damage * (CONFIG.DH.ACTIONS.damageOnSave[message.system.onSave]?.mod ?? 1)); - target.actor.takeDamage(damage, message.system.roll.type); + target.actor.takeDamage(damage, message.system.damage.damageType); } }; diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 282a8c9c..94efec1b 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -59,13 +59,13 @@ export const damageTypes = { id: 'physical', label: 'DAGGERHEART.CONFIG.DamageType.physical.name', abbreviation: 'DAGGERHEART.CONFIG.DamageType.physical.abbreviation', - icon: ['fa-hand-fist'] + icon: 'fa-hand-fist' }, magical: { id: 'magical', label: 'DAGGERHEART.CONFIG.DamageType.magical.name', abbreviation: 'DAGGERHEART.CONFIG.DamageType.magical.abbreviation', - icon: ['fa-wand-sparkles'] + icon: 'fa-wand-sparkles' } }; diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index cdc8a235..ed77310c 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -395,7 +395,7 @@ export const armorFeatures = { img: 'icons/magic/defensive/barrier-shield-dome-pink.webp', changes: [ { - key: 'system.bonuses.damageReduction.magical', + key: 'system.resistance.magical.reduction', mode: 2, value: '@system.armorScore' } diff --git a/module/data/action/actionDice.mjs b/module/data/action/actionDice.mjs index 8b5bbe40..5cc2d10a 100644 --- a/module/data/action/actionDice.mjs +++ b/module/data/action/actionDice.mjs @@ -76,11 +76,7 @@ export class DHActionDiceData extends foundry.abstract.DataModel { }; } - getFormula(actor) { - /* const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : actor.system[this.multiplier]?.total; - return this.custom.enabled - ? this.custom.formula - : `${multiplier ?? 1}${this.dice}${this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''}`; */ + getFormula() { const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`, bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : ''; return this.custom.enabled ? this.custom.formula : `${multiplier ?? 1}${this.dice}${bonus}`; @@ -93,7 +89,6 @@ export class DHDamageField extends fields.SchemaField { parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)), includeBase: new fields.BooleanField({ initial: false }) }; - // if (hasBase) damageFields.includeBase = new fields.BooleanField({ initial: true }); super(damageFields, options, context); } } @@ -102,15 +97,19 @@ export class DHDamageData extends foundry.abstract.DataModel { /** @override */ static defineSchema() { return { - // ...super.defineSchema(), base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }), - type: new fields.StringField({ - choices: CONFIG.DH.GENERAL.damageTypes, - initial: 'physical', - label: 'Type', - nullable: false, - required: true - }), + type: new fields.SetField( + new fields.StringField({ + choices: CONFIG.DH.GENERAL.damageTypes, + initial: 'physical', + nullable: false, + required: true + }), + { + label: 'Type', + initial: 'physical', + } + ), resultBased: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ACTIONS.Settings.resultBased.label' diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index e2eafbf2..8fb15f50 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -179,16 +179,9 @@ export default class DHBaseAction extends foundry.abstract.DataModel { getRollData(data = {}) { const actorData = this.actor.getRollData(false); - // Remove when included directly in Actor getRollData - actorData.prof = actorData.proficiency?.total ?? 1; - actorData.cast = actorData.spellcast?.total ?? 1; + // Add Roll results to RollDatas actorData.result = data.roll?.total ?? 1; - /* actorData.scale = data.costs?.length - ? data.costs.reduce((a, c) => { - a[c.type] = c.value; - return a; - }, {}) - : 1; */ + actorData.scale = data.costs?.length // Right now only return the first scalable cost. ? (data.costs.find(c => c.scalable)?.total ?? 1) : 1; diff --git a/module/data/action/damageAction.mjs b/module/data/action/damageAction.mjs index 2dd88af4..3e840e60 100644 --- a/module/data/action/damageAction.mjs +++ b/module/data/action/damageAction.mjs @@ -10,7 +10,10 @@ export default class DHDamageAction extends DHBaseAction { } async rollDamage(event, data) { - let formula = this.damage.parts.map(p => this.getFormulaValue(p, data).getFormula(this.actor)).join(' + '); + let formula = this.damage.parts.map(p => this.getFormulaValue(p, data).getFormula(this.actor)).join(' + '), + damageTypes = [...new Set(this.damage.parts.reduce((a,c) => a.concat([...c.type]), []))]; + + damageTypes = !damageTypes.length ? ['physical'] : damageTypes; if (!formula || formula == '') return; let roll = { formula: formula, total: formula }, @@ -25,6 +28,7 @@ export default class DHDamageAction extends DHBaseAction { hasSave: this.hasSave, isCritical: data.system?.roll?.isCritical ?? false, source: data.system?.source, + damageTypes, event }; if (this.hasSave) config.onSave = this.save.damageMod; @@ -32,7 +36,7 @@ export default class DHDamageAction extends DHBaseAction { config.source.message = data._id; config.directDamage = false; } - + roll = CONFIG.Dice.daggerheart.DamageRoll.build(config); } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 9bb5d5f8..cf3669a1 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -5,6 +5,7 @@ import BaseDataActor from './base.mjs'; const resourceField = () => new foundry.data.fields.SchemaField({ value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }), max: new foundry.data.fields.NumberField({ initial: 0, integer: true }) }); @@ -22,6 +23,7 @@ export default class DhpAdversary extends BaseDataActor { static defineSchema() { const fields = foundry.data.fields; return { + ...super.defineSchema(), tier: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.tiers, @@ -32,7 +34,6 @@ export default class DhpAdversary extends BaseDataActor { choices: CONFIG.DH.ACTOR.adversaryTypes, initial: CONFIG.DH.ACTOR.adversaryTypes.standard.id }), - description: new fields.StringField(), motivesAndTactics: new fields.StringField(), notes: new fields.HTMLField(), difficulty: new fields.NumberField({ required: true, initial: 1, integer: true }), @@ -63,6 +64,7 @@ export default class DhpAdversary extends BaseDataActor { damage: { parts: [ { + type: ['physical'], value: { multiplier: 'flat' } @@ -93,4 +95,9 @@ export default class DhpAdversary extends BaseDataActor { get features() { return this.parent.items.filter(x => x.type === 'feature'); } + + prepareDerivedData() { + this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus; + this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus; + } } diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index 1b90968d..d7c7213e 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,5 +1,12 @@ import DHBaseActorSettings from "../../applications/sheets/api/actor-setting.mjs"; +const resistanceField = () => + new foundry.data.fields.SchemaField({ + resistance: new foundry.data.fields.BooleanField({ initial: false }), + immunity: new foundry.data.fields.BooleanField({ initial: false }), + reduction: new foundry.data.fields.NumberField({ integer: true, initial: 0 }) + }); + /** * Describes metadata about the actor data model type * @typedef {Object} ActorDataModelMetadata @@ -16,6 +23,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { type: 'base', isNPC: true, settingSheet: null, + hasResistances: true }; } @@ -27,10 +35,16 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { /** @inheritDoc */ static defineSchema() { const fields = foundry.data.fields; + const schema = {}; - return { - description: new fields.HTMLField({ required: true, nullable: true }) - }; + if(this.metadata.isNPC) + schema.description = new fields.HTMLField({ required: true, nullable: true }); + if(this.metadata.hasResistances) + schema.resistance = new fields.SchemaField({ + physical: resistanceField(), + magical: resistanceField() + }) + return schema; } /** diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 93926d9a..d26e368a 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -36,6 +36,7 @@ export default class DhCharacter extends BaseDataActor { const fields = foundry.data.fields; return { + ...super.defineSchema(), resources: new fields.SchemaField({ hitPoints: new fields.SchemaField({ value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), @@ -100,10 +101,6 @@ export default class DhCharacter extends BaseDataActor { levelData: new fields.EmbeddedDataField(DhLevelData), bonuses: new fields.SchemaField({ armorScore: new fields.NumberField({ integer: true, initial: 0 }), - damageReduction: new fields.SchemaField({ - physical: new fields.NumberField({ integer: true, initial: 0 }), - magical: new fields.NumberField({ integer: true, initial: 0 }) - }), damageThresholds: new fields.SchemaField({ severe: new fields.NumberField({ integer: true, initial: 0 }), major: new fields.NumberField({ integer: true, initial: 0 }) diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index 88b149e3..b1c41ea3 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -20,6 +20,7 @@ export default class DhCompanion extends BaseDataActor { const fields = foundry.data.fields; return { + ...super.defineSchema(), partner: new ForeignDocumentUUIDField({ type: 'Actor' }), resources: new fields.SchemaField({ stress: new fields.SchemaField({ @@ -66,6 +67,7 @@ export default class DhCompanion extends BaseDataActor { damage: { parts: [ { + type: ['physical'], value: { dice: 'd6', multiplier: 'prof' diff --git a/module/data/actor/environment.mjs b/module/data/actor/environment.mjs index 76990e88..2db1f039 100644 --- a/module/data/actor/environment.mjs +++ b/module/data/actor/environment.mjs @@ -9,20 +9,21 @@ export default class DhEnvironment extends BaseDataActor { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Actor.environment', type: 'environment', - settingSheet: DHEnvironmentSettings + settingSheet: DHEnvironmentSettings, + hasResistances: false }); } static defineSchema() { const fields = foundry.data.fields; return { + ...super.defineSchema(), tier: new fields.StringField({ required: true, choices: CONFIG.DH.GENERAL.tiers, initial: CONFIG.DH.GENERAL.tiers.tier1.id }), type: new fields.StringField({ choices: CONFIG.DH.ACTOR.environmentTypes }), - description: new fields.StringField(), impulses: new fields.StringField(), difficulty: new fields.NumberField({ required: true, initial: 11, integer: true }), potentialAdversaries: new fields.TypedObjectField( diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 80c8271d..8f580b6d 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -56,6 +56,7 @@ export default class DHWeapon extends BaseDataItem { damage: { parts: [ { + type: ['physical'], value: { multiplier: 'prof', dice: 'd8' diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index d9c4a61e..2182d3d0 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -14,6 +14,10 @@ export default class DamageRoll extends DHRoll { super.postEvaluate(roll, config); config.roll.type = config.type; config.roll.modifierTotal = this.calculateTotalModifiers(roll); + } + + static async buildPost(roll, config, message) { + await super.buildPost(roll, config, message); if (config.source?.message) { const chatMessage = ui.chat.collection.get(config.source.message); chatMessage.update({ 'system.damage': config }); diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 46e7374e..87c9401e 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -56,8 +56,8 @@ export default class DHRoll extends Roll { // Create Chat Message if (config.source?.message) { + if(game.modules.get('dice-so-nice')?.active) await game.dice3d.showForRoll(roll, game.user, true); } else { - const messageData = {}; config.message = await this.toMessage(roll, config); } } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index aba0e0fa..0bd45690 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -370,7 +370,10 @@ export default class DhpActor extends Actor { } getRollData() { - return this.system; + const rollData = super.getRollData(); + rollData.prof = this.system.proficiency?.total ?? 1; + rollData.cast = this.system.spellcast?.total ?? 1; + return rollData; } formatRollModifier(roll) { @@ -462,7 +465,7 @@ export default class DhpActor extends Actor { const canUseArmor = this.system.armor && this.system.armor.system.marks.value < this.system.armorScore && - this.system.armorApplicableDamageTypes[type]; + type.every(t => this.system.armorApplicableDamageTypes[t] === true); const canUseStress = Object.keys(this.system.rules.damageReduction.stressDamageReduction).reduce((acc, x) => { const rule = this.system.rules.damageReduction.stressDamageReduction[x]; if (damageKeyToNumber(x) <= hpDamage) return acc || (rule.enabled && availableStress >= rule.cost); @@ -480,11 +483,9 @@ export default class DhpActor extends Actor { return; } - const flatReduction = this.system.bonuses.damageReduction[type]; - const damage = Math.max(baseDamage - (flatReduction ?? 0), 0); - const hpDamage = this.convertDamageToThreshold(damage); + type = !Array.isArray(type) ? [type] : type; - if (Hooks.call(`${CONFIG.DH.id}.postDamageTreshold`, this, hpDamage, damage, type) === false) return null; + const hpDamage = this.calculateDamage(baseDamage, type); if (!hpDamage) return; @@ -511,6 +512,35 @@ export default class DhpActor extends Actor { if (Hooks.call(`${CONFIG.DH.id}.postTakeDamage`, this, damage, type) === false) return null; } + calculateDamage(baseDamage, type) { + if (Hooks.call(`${CONFIG.DH.id}.preCalculateDamage`, this, baseDamage, type) === false) return null; + + /* if(this.system.resistance[type]?.immunity) return 0; + if(this.system.resistance[type]?.resistance) baseDamage = Math.ceil(baseDamage / 2); */ + if(this.canResist(type, 'immunity')) return 0; + if(this.canResist(type, 'resistance')) baseDamage = Math.ceil(baseDamage / 2); + + // const flatReduction = this.system.resistance[type].reduction; + const flatReduction = this.getDamageTypeReduction(type); + const damage = Math.max(baseDamage - (flatReduction ?? 0), 0); + const hpDamage = this.convertDamageToThreshold(damage); + + if (Hooks.call(`${CONFIG.DH.id}.postCalculateDamage`, this, baseDamage, type) === false) return null; + + return hpDamage; + } + + canResist(type, resistance) { + if(!type) return 0; + return type.every(t => this.system.resistance[t]?.[resistance] === true); + } + + getDamageTypeReduction(type) { + if(!type) return 0; + const reduction = Object.entries(this.system.resistance).reduce((a, [index, value]) => type.includes(index) ? Math.min(value.reduction, a) : a, Infinity); + return reduction === Infinity ? 0 : reduction; + } + async takeHealing(resources) { resources.forEach(r => (r.value *= -1)); await this.modifyResource(resources); @@ -553,18 +583,6 @@ export default class DhpActor extends Actor { u.resources, u.target.uuid ); - /* if (game.user.isGM) { - await u.target.update(u.resources); - } else { - await game.socket.emit(`system.${CONFIG.DH.id}`, { - action: socketEvent.GMUpdate, - data: { - action: GMUpdateEvent.UpdateDocument, - uuid: u.target.uuid, - update: u.resources - } - }); - } */ } }); } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 8156736d..40a71ac7 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -236,16 +236,7 @@ Roll.replaceFormulaData = function (formula, data = {}, { missing, warn = false }; export const getDamageKey = damage => { - switch (damage) { - case 3: - return 'severe'; - case 2: - return 'major'; - case 1: - return 'minor'; - case 0: - return 'none'; - } + return ['none', 'minor', 'major', 'severe'][damage]; }; export const getDamageLabel = damage => { @@ -253,16 +244,12 @@ export const getDamageLabel = damage => { }; export const damageKeyToNumber = key => { - switch (key) { - case 'severe': - return 3; - case 'major': - return 2; - case 'minor': - return 1; - case 'none': - return 0; - } + return { + 'none': 0, + 'minor': 1, + 'major': 2, + 'severe': 3 + }[key]; }; export default function constructHTMLButton({ diff --git a/styles/less/global/elements.less b/styles/less/global/elements.less index 84c90336..ab519a1c 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -104,6 +104,40 @@ } } + multi-select { + position: relative; + height: 34px; + .tags { + justify-content: flex-start; + margin: 5px; + height: inherit; + .tag { + box-shadow: 0 0 0 1.1em #E5E5E5 inset; + vertical-align: top; + box-sizing: border-box; + max-width: 100%; + padding: 0.3em 0 0.3em 0.5em; + color: black; + border-radius: 3px; + white-space: nowrap; + transition: .13s ease-out; + height: 22px; + font-size: .9rem; + gap: 0.5em; + z-index: 1; + .remove { + font-size: 10px; + margin-inline: auto 4.6666666667px; + } + } + } + select { + position: absolute; + height: inherit; + outline: initial; + } + } + p { margin: 0; } diff --git a/templates/actionTypes/damage.hbs b/templates/actionTypes/damage.hbs index 59519e6d..cbd1f503 100644 --- a/templates/actionTypes/damage.hbs +++ b/templates/actionTypes/damage.hbs @@ -46,7 +46,7 @@ {{> formula fields=../../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" realIndex=realIndex}}
{{/if}} - {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} + {{formField ../../fields.type value=dmg.type name=(concat "damage.parts." realIndex ".type") localize=true}} {{#unless dmg.base}}
{{/unless}} diff --git a/templates/sheets/actors/adversary/sidebar.hbs b/templates/sheets/actors/adversary/sidebar.hbs index b26c1b81..ad23ab25 100644 --- a/templates/sheets/actors/adversary/sidebar.hbs +++ b/templates/sheets/actors/adversary/sidebar.hbs @@ -10,12 +10,12 @@

/

-

{{source.system.resources.hitPoints.max}}

+

{{source.system.resources.hitPoints.maxTotal}}

HP

@@ -26,12 +26,12 @@

/

-

{{source.system.resources.stress.max}}

+

{{source.system.resources.stress.maxTotal}}

Stress

diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index eae3dd5f..117783a5 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -6,7 +6,7 @@ {{else}}
{{item.name}}
{{/if}} - {{#if (eq type 'weapon')}} + {{#if (eq type 'weapon')}}
{{#if isSidebar}}
@@ -16,11 +16,11 @@ - {{item.system.attack.damage.parts.0.value.dice}}{{#if item.system.attack.damage.parts.0.value.bonus}} + {{item.system.attack.damage.parts.0.value.bonus}}{{/if}} {{!-- ({{localize (concat 'DAGGERHEART.CONFIG.DamageType.' item.system.attack.damage.parts.0.type '.abbreviation')}}) --}} - {{#with (lookup @root.config.GENERAL.damageTypes item.system.attack.damage.parts.0.type)}} - {{#each icon}} - - {{/each}} - {{/with}} + {{#each item.system.attack.damage.parts.0.type as | type | }} + {{#with (lookup @root.config.GENERAL.damageTypes type)}} + + {{/with}} + {{/each}}
{{else}} @@ -32,7 +32,11 @@
{{item.system.attack.damage.parts.0.value.dice}}{{#if item.system.attack.damage.parts.0.value.bonus}} + {{item.system.attack.damage.parts.0.value.bonus}}{{/if}} - ({{localize (concat 'DAGGERHEART.CONFIG.DamageType.' item.system.attack.damage.parts.0.type '.abbreviation')}}) + ( + {{#each item.system.attack.damage.parts.0.type}} + {{localize (concat 'DAGGERHEART.CONFIG.DamageType.' this '.abbreviation')}} + {{/each}} + )
{{localize (concat 'DAGGERHEART.CONFIG.Burden.' item.system.burden)}} diff --git a/templates/sheets/items/weapon/header.hbs b/templates/sheets/items/weapon/header.hbs index 74613699..ee0198ba 100644 --- a/templates/sheets/items/weapon/header.hbs +++ b/templates/sheets/items/weapon/header.hbs @@ -15,7 +15,11 @@ {{localize (concat 'DAGGERHEART.CONFIG.Range.' source.system.attack.range '.name')}} - {{source.system.attack.damage.parts.0.value.dice}}{{#if source.system.attack.damage.parts.0.value.bonus}} + {{source.system.attack.damage.parts.0.value.bonus}}{{/if}} - ({{localize (concat 'DAGGERHEART.CONFIG.DamageType.' source.system.attack.damage.parts.0.type '.abbreviation')}}) + ( + {{#each source.system.attack.damage.parts.0.type}} + {{localize (concat 'DAGGERHEART.CONFIG.DamageType.' this '.abbreviation')}} + {{/each}} + ) - {{localize (concat 'DAGGERHEART.CONFIG.Burden.' source.system.burden)}} From 687500f191557f0112fdbd1348c46c1e8552ae13 Mon Sep 17 00:00:00 2001 From: Psitacus <59754077+Psitacus@users.noreply.github.com> Date: Sat, 12 Jul 2025 19:07:22 -0600 Subject: [PATCH 11/12] Iss4 - create a way to attach attach items to armor and weapons (#310) * add basic drag drop window * add better field * make effects copy onto actor on attachment * make items from inventory draggable * working drop from inventory * remove duplication issue * add attachment only flag and logic * add weapons to attachables * remove debug logs * try to make it drier * remove unecessary try catch * remove extra configs * remove superfluous comments * remove spurious defenses * make drier * remove unecessary code * deduplicate and simplify * its a desert * standardize to be more similar to class item code * fix bug of duplicate effects being created * fix localization string * fix bug of item equiping and un equiping * remove this since were not going to be using attachmentonly * update attachment tab with comments * remove attachment only logic in favor of just transfer * change flags * change armor and weapon to be attachableItem * change armor and weapon to be attachableItem * change weapon to use mixin * add mixin to armor * move everything to mixin sheet * refactor code for review comments * cleanup and somehow git is ignoring some changes * see if this picks up the changes now * Import/Export updates --------- Co-authored-by: psitacus Co-authored-by: WBHarry --- lang/en.json | 8 +- .../applications/sheets/actors/character.mjs | 22 ++- module/applications/sheets/api/_modules.mjs | 1 + .../sheets/api/item-attachment-sheet.mjs | 90 +++++++++++ module/applications/sheets/items/armor.mjs | 7 +- module/applications/sheets/items/weapon.mjs | 8 +- module/config/flagsConfig.mjs | 2 + module/data/item/_module.mjs | 3 + module/data/item/armor.mjs | 5 +- module/data/item/attachableItem.mjs | 152 ++++++++++++++++++ module/data/item/weapon.mjs | 6 +- module/documents/activeEffect.mjs | 30 +++- styles/less/global/index.less | 1 + styles/less/global/tab-attachments.less | 7 + templates/sheets/activeEffect/details.hbs | 2 +- .../sheets/global/partials/inventory-item.hbs | 2 +- .../sheets/global/tabs/tab-attachments.hbs | 29 ++++ templates/sheets/items/weapon/attachments.hbs | 0 18 files changed, 357 insertions(+), 18 deletions(-) create mode 100644 module/applications/sheets/api/item-attachment-sheet.mjs create mode 100644 module/data/item/attachableItem.mjs create mode 100644 styles/less/global/tab-attachments.less create mode 100644 templates/sheets/global/tabs/tab-attachments.hbs create mode 100644 templates/sheets/items/weapon/attachments.hbs diff --git a/lang/en.json b/lang/en.json index 2e938914..5497d5e6 100755 --- a/lang/en.json +++ b/lang/en.json @@ -389,6 +389,7 @@ "default": "Default Ownership" } }, + "CONFIG": { "ActionType": { "passive": "Passive", @@ -958,6 +959,10 @@ "stress": { "name": "Stress" } + }, + "Attachments": { + "attachHint": "Drop items here to attach them", + "transferHint": "If checked, this effect will be applied to any actor that owns this Effect's parent Item. The effect is always applied if this Item is attached to another one." } }, "GENERAL": { @@ -1093,7 +1098,8 @@ "optional": "Optional", "recovery": "Recovery", "setup": "Setup", - "equipment": "Equipment" + "equipment": "Equipment", + "attachments": "Attachments" }, "Tiers": { "singular": "Tier", diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index ae7ffbf9..5f0199f3 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -30,7 +30,12 @@ export default class CharacterSheet extends DHBaseActorSheet { window: { resizable: true }, - dragDrop: [], + dragDrop: [ + { + dragSelector: '[data-item-id][draggable="true"]', + dropSelector: null + } + ], contextMenus: [ { handler: CharacterSheet._getContextMenuOptions, @@ -665,11 +670,24 @@ export default class CharacterSheet extends DHBaseActorSheet { } } - async _onDragStart(_, event) { + async _onDragStart(event) { + const item = this.getItem(event); + + const dragData = { + type: item.documentName, + uuid: item.uuid + }; + + event.dataTransfer.setData('text/plain', JSON.stringify(dragData)); + super._onDragStart(event); } async _onDrop(event) { + // Prevent event bubbling to avoid duplicate handling + event.preventDefault(); + event.stopPropagation(); + super._onDrop(event); this._onDropItem(event, TextEditor.getDragEventData(event)); } diff --git a/module/applications/sheets/api/_modules.mjs b/module/applications/sheets/api/_modules.mjs index cb7eee62..e6caece1 100644 --- a/module/applications/sheets/api/_modules.mjs +++ b/module/applications/sheets/api/_modules.mjs @@ -1,5 +1,6 @@ export { default as DHApplicationMixin } from './application-mixin.mjs'; export { default as DHBaseItemSheet } from './base-item.mjs'; export { default as DHHeritageSheet } from './heritage-sheet.mjs'; +export { default as DHItemAttachmentSheet } from './item-attachment-sheet.mjs'; export { default as DHBaseActorSheet } from './base-actor.mjs'; export { default as DHBaseActorSettings } from './actor-setting.mjs'; diff --git a/module/applications/sheets/api/item-attachment-sheet.mjs b/module/applications/sheets/api/item-attachment-sheet.mjs new file mode 100644 index 00000000..e89c7cba --- /dev/null +++ b/module/applications/sheets/api/item-attachment-sheet.mjs @@ -0,0 +1,90 @@ + +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' } + ], + actions: { + ...super.DEFAULT_OPTIONS.actions, + removeAttachment: this.#removeAttachment + } + }; + + static PARTS = { + ...super.PARTS, + attachments: { + template: 'systems/daggerheart/templates/sheets/global/tabs/tab-attachments.hbs', + scrollable: ['.attachments'] + } + }; + + static TABS = { + ...super.TABS, + primary: { + ...super.TABS?.primary, + tabs: [ + ...(super.TABS?.primary?.tabs || []), + { id: 'attachments' } + ], + initial: super.TABS?.primary?.initial || 'description', + labelPrefix: super.TABS?.primary?.labelPrefix || 'DAGGERHEART.GENERAL.Tabs' + } + }; + + async _preparePartContext(partId, context) { + await super._preparePartContext(partId, context); + + if (partId === 'attachments') { + context.attachedItems = await prepareAttachmentContext(this.document); + } + + return context; + } + + async _onDrop(event) { + const data = TextEditor.getDragEventData(event); + + const attachmentsSection = event.target.closest('.attachments-section'); + if (!attachmentsSection) return super._onDrop(event); + + event.preventDefault(); + event.stopPropagation(); + + const item = await Item.implementation.fromDropData(data); + if (!item) return; + + // Call the data model's public method + await this.document.system.addAttachment(item); + } + + + static async #removeAttachment(event, target) { + // Call the data model's public method + await this.document.system.removeAttachment(target.dataset.uuid); +} + + async _preparePartContext(partId, context) { + await super._preparePartContext(partId, context); + + if (partId === 'attachments') { + // Keep this simple UI preparation in the mixin + const attachedUUIDs = this.document.system.attached; + context.attachedItems = await Promise.all( + attachedUUIDs.map(async uuid => { + const item = await fromUuid(uuid); + return { + uuid: uuid, + name: item?.name || 'Unknown Item', + img: item?.img || 'icons/svg/item-bag.svg' + }; + }) + ); + } + + return context; + } + }; +} \ No newline at end of file diff --git a/module/applications/sheets/items/armor.mjs b/module/applications/sheets/items/armor.mjs index 21fbfea8..a6413cf0 100644 --- a/module/applications/sheets/items/armor.mjs +++ b/module/applications/sheets/items/armor.mjs @@ -1,10 +1,10 @@ import DHBaseItemSheet from '../api/base-item.mjs'; +import ItemAttachmentSheet from '../api/item-attachment-sheet.mjs'; -export default class ArmorSheet extends DHBaseItemSheet { +export default class ArmorSheet extends ItemAttachmentSheet(DHBaseItemSheet) { /**@inheritdoc */ static DEFAULT_OPTIONS = { classes: ['armor'], - dragDrop: [{ dragSelector: null, dropSelector: null }], tagifyConfigs: [ { selector: '.features-input', @@ -26,7 +26,8 @@ export default class ArmorSheet extends DHBaseItemSheet { settings: { template: 'systems/daggerheart/templates/sheets/items/armor/settings.hbs', scrollable: ['.settings'] - } + }, + ...super.PARTS, }; /**@inheritdoc */ diff --git a/module/applications/sheets/items/weapon.mjs b/module/applications/sheets/items/weapon.mjs index 77396998..e89c3dce 100644 --- a/module/applications/sheets/items/weapon.mjs +++ b/module/applications/sheets/items/weapon.mjs @@ -1,6 +1,7 @@ import DHBaseItemSheet from '../api/base-item.mjs'; +import ItemAttachmentSheet from '../api/item-attachment-sheet.mjs'; -export default class WeaponSheet extends DHBaseItemSheet { +export default class WeaponSheet extends ItemAttachmentSheet(DHBaseItemSheet) { /**@inheritdoc */ static DEFAULT_OPTIONS = { classes: ['weapon'], @@ -25,12 +26,13 @@ export default class WeaponSheet extends DHBaseItemSheet { settings: { template: 'systems/daggerheart/templates/sheets/items/weapon/settings.hbs', scrollable: ['.settings'] - } + }, + ...super.PARTS, }; /**@inheritdoc */ async _preparePartContext(partId, context) { - super._preparePartContext(partId, context); + await super._preparePartContext(partId, context); switch (partId) { case 'settings': context.features = this.document.system.weaponFeatures.map(x => x.value); diff --git a/module/config/flagsConfig.mjs b/module/config/flagsConfig.mjs index 252863f1..0c112231 100644 --- a/module/config/flagsConfig.mjs +++ b/module/config/flagsConfig.mjs @@ -7,3 +7,5 @@ export const encounterCountdown = { simple: 'countdown-encounter-simple', position: 'countdown-encounter-position' }; + +export const itemAttachmentSource = 'attachmentSource'; \ No newline at end of file diff --git a/module/data/item/_module.mjs b/module/data/item/_module.mjs index a29d1595..bed18eb5 100644 --- a/module/data/item/_module.mjs +++ b/module/data/item/_module.mjs @@ -1,5 +1,6 @@ import DHAncestry from './ancestry.mjs'; import DHArmor from './armor.mjs'; +import DHAttachableItem from './attachableItem.mjs'; import DHClass from './class.mjs'; import DHCommunity from './community.mjs'; import DHConsumable from './consumable.mjs'; @@ -13,6 +14,7 @@ import DHBeastform from './beastform.mjs'; export { DHAncestry, DHArmor, + DHAttachableItem, DHClass, DHCommunity, DHConsumable, @@ -27,6 +29,7 @@ export { export const config = { ancestry: DHAncestry, armor: DHArmor, + attachableItem: DHAttachableItem, class: DHClass, community: DHCommunity, consumable: DHConsumable, diff --git a/module/data/item/armor.mjs b/module/data/item/armor.mjs index bf2bf73e..7a8b06c0 100644 --- a/module/data/item/armor.mjs +++ b/module/data/item/armor.mjs @@ -1,8 +1,9 @@ -import BaseDataItem from './base.mjs'; +import AttachableItem from './attachableItem.mjs'; import ActionField from '../fields/actionField.mjs'; import { armorFeatures } from '../../config/itemConfig.mjs'; +import { actionsTypes } from '../action/_module.mjs'; -export default class DHArmor extends BaseDataItem { +export default class DHArmor extends AttachableItem { /** @inheritDoc */ static get metadata() { return foundry.utils.mergeObject(super.metadata, { diff --git a/module/data/item/attachableItem.mjs b/module/data/item/attachableItem.mjs new file mode 100644 index 00000000..2b0608eb --- /dev/null +++ b/module/data/item/attachableItem.mjs @@ -0,0 +1,152 @@ +import BaseDataItem from './base.mjs'; + +export default class AttachableItem extends BaseDataItem { + static defineSchema() { + const fields = foundry.data.fields; + return { + ...super.defineSchema(), + attached: new fields.ArrayField(new fields.DocumentUUIDField({ type: "Item", nullable: true })) + }; + } + + async _preUpdate(changes, options, user) { + const allowed = await super._preUpdate(changes, options, user); + if (allowed === false) return false; + + // Handle equipped status changes for attachment effects + if (changes.system?.equipped !== undefined && changes.system.equipped !== this.equipped) { + await this.#handleAttachmentEffectsOnEquipChange(changes.system.equipped); + } + } + + async #handleAttachmentEffectsOnEquipChange(newEquippedStatus) { + const actor = this.parent.parent?.type === 'character' ? this.parent.parent : this.parent.parent?.parent; + const parentType = this.parent.type; + + if (!actor || !this.attached?.length) { + return; + } + + if (newEquippedStatus) { + // Item is being equipped - add attachment effects + for (const attachedUuid of this.attached) { + const attachedItem = await fromUuid(attachedUuid); + if (attachedItem && attachedItem.effects.size > 0) { + await this.#copyAttachmentEffectsToActor({ + attachedItem, + attachedUuid, + parentType + }); + } + } + } else { + // Item is being unequipped - remove attachment effects + await this.#removeAllAttachmentEffects(parentType); + } + } + + async #copyAttachmentEffectsToActor({ attachedItem, attachedUuid, parentType }) { + const actor = this.parent.parent; + if (!actor || !attachedItem.effects.size > 0 || !this.equipped) { + return []; + } + + const effectsToCreate = []; + for (const effect of attachedItem.effects) { + const effectData = effect.toObject(); + effectData.origin = `${this.parent.uuid}:${attachedUuid}`; + + const attachmentSource = { + itemUuid: attachedUuid, + originalEffectId: effect.id + }; + attachmentSource[`${parentType}Uuid`] = this.parent.uuid; + + effectData.flags = { + ...effectData.flags, + [CONFIG.DH.id]: { + ...effectData.flags?.[CONFIG.DH.id], + [CONFIG.DH.FLAGS.itemAttachmentSource]: attachmentSource + } + }; + effectsToCreate.push(effectData); + } + + if (effectsToCreate.length > 0) { + return await actor.createEmbeddedDocuments('ActiveEffect', effectsToCreate); + } + + return []; + } + + async #removeAllAttachmentEffects(parentType) { + const actor = this.parent.parent; + if (!actor) return; + + const parentUuidProperty = `${parentType}Uuid`; + const effectsToRemove = actor.effects.filter(effect => { + const attachmentSource = effect.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.itemAttachmentSource); + return attachmentSource && attachmentSource[parentUuidProperty] === this.parent.uuid; + }); + + if (effectsToRemove.length > 0) { + await actor.deleteEmbeddedDocuments('ActiveEffect', effectsToRemove.map(e => e.id)); + } + } + + /** + * Public method for adding an attachment + */ + async addAttachment(droppedItem) { + const newUUID = droppedItem.uuid; + + if (this.attached.includes(newUUID)) { + ui.notifications.warn(`${droppedItem.name} is already attached to this ${this.parent.type}.`); + return; + } + + const updatedAttached = [...this.attached, newUUID]; + await this.parent.update({ + 'system.attached': updatedAttached + }); + + // Copy effects if equipped + if (this.equipped && droppedItem.effects.size > 0) { + await this.#copyAttachmentEffectsToActor({ + attachedItem: droppedItem, + attachedUuid: newUUID, + parentType: this.parent.type + }); + } + } + + /** + * Public method for removing an attachment + */ + async removeAttachment(attachedUuid) { + await this.parent.update({ + 'system.attached': this.attached.filter(uuid => uuid !== attachedUuid) + }); + + // Remove effects + await this.#removeAttachmentEffects(attachedUuid); + } + + async #removeAttachmentEffects(attachedUuid) { + const actor = this.parent.parent; + if (!actor) return; + + const parentType = this.parent.type; + const parentUuidProperty = `${parentType}Uuid`; + const effectsToRemove = actor.effects.filter(effect => { + const attachmentSource = effect.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.itemAttachmentSource); + return attachmentSource && + attachmentSource[parentUuidProperty] === this.parent.uuid && + attachmentSource.itemUuid === attachedUuid; + }); + + if (effectsToRemove.length > 0) { + await actor.deleteEmbeddedDocuments('ActiveEffect', effectsToRemove.map(e => e.id)); + } + } +} \ No newline at end of file diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 8f580b6d..82b4ba80 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -1,8 +1,8 @@ -import BaseDataItem from './base.mjs'; +import AttachableItem from './attachableItem.mjs'; import { actionsTypes } from '../action/_module.mjs'; import ActionField from '../fields/actionField.mjs'; -export default class DHWeapon extends BaseDataItem { +export default class DHWeapon extends AttachableItem { /** @inheritDoc */ static get metadata() { return foundry.utils.mergeObject(super.metadata, { @@ -37,7 +37,7 @@ export default class DHWeapon extends BaseDataItem { actionIds: new fields.ArrayField(new fields.StringField({ required: true })) }) ), - attack: new ActionField({ + attack: new ActionField({ initial: { name: 'Attack', img: 'icons/skills/melee/blood-slash-foam-red.webp', diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 1abc2d17..03ac73bc 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -1,16 +1,42 @@ export default class DhActiveEffect extends ActiveEffect { get isSuppressed() { - if (['weapon', 'armor'].includes(this.parent.type)) { + // If this is a copied effect from an attachment, never suppress it + // (These effects have attachmentSource metadata) + if (this.flags?.daggerheart?.attachmentSource) { + return false; + } + + // Then apply the standard suppression rules + if (['weapon', 'armor'].includes(this.parent?.type)) { return !this.parent.system.equipped; } - if (this.parent.type === 'domainCard') { + if (this.parent?.type === 'domainCard') { return this.parent.system.inVault; } return super.isSuppressed; } + /** + * Check if the parent item is currently attached to another item + * @returns {boolean} + */ + get isAttached() { + if (!this.parent || !this.parent.parent) return false; + + // Check if this item's UUID is in any actor's armor or weapon attachment lists + const actor = this.parent.parent; + if (!actor || !actor.items) return false; + + return actor.items.some(item => { + return (item.type === 'armor' || item.type === 'weapon') && + item.system?.attached && + Array.isArray(item.system.attached) && + item.system.attached.includes(this.parent.uuid); + }); + } + async _preCreate(data, options, user) { const update = {}; if (!data.img) { diff --git a/styles/less/global/index.less b/styles/less/global/index.less index 0559c7ff..932e48ab 100644 --- a/styles/less/global/index.less +++ b/styles/less/global/index.less @@ -12,3 +12,4 @@ @import './inventory-fieldset-items.less'; @import './prose-mirror.less'; @import './filter-menu.less'; +@import './tab-attachments.less'; diff --git a/styles/less/global/tab-attachments.less b/styles/less/global/tab-attachments.less new file mode 100644 index 00000000..c283269e --- /dev/null +++ b/styles/less/global/tab-attachments.less @@ -0,0 +1,7 @@ +.daggerheart.dh-style { + .tab.attachments { + .attached-items { + width: 100%; + } + } +} \ No newline at end of file diff --git a/templates/sheets/activeEffect/details.hbs b/templates/sheets/activeEffect/details.hbs index 8ff72b98..8a862c53 100644 --- a/templates/sheets/activeEffect/details.hbs +++ b/templates/sheets/activeEffect/details.hbs @@ -7,7 +7,7 @@ {{formGroup fields.origin value=source.origin rootId=rootId disabled=true}} {{/if}} {{#if isItemEffect}} - {{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=legacyTransfer.hint}} + {{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=(localize "DAGGERHEART.EFFECTS.Attachments.transferHint")}} {{/if}} {{formGroup fields.statuses value=source.statuses options=statuses rootId=rootId classes="statuses"}} diff --git a/templates/sheets/global/partials/inventory-item.hbs b/templates/sheets/global/partials/inventory-item.hbs index 117783a5..21b7de61 100644 --- a/templates/sheets/global/partials/inventory-item.hbs +++ b/templates/sheets/global/partials/inventory-item.hbs @@ -1,4 +1,4 @@ -
  • +
  • {{#if isCompanion}} diff --git a/templates/sheets/global/tabs/tab-attachments.hbs b/templates/sheets/global/tabs/tab-attachments.hbs new file mode 100644 index 00000000..f7f8b716 --- /dev/null +++ b/templates/sheets/global/tabs/tab-attachments.hbs @@ -0,0 +1,29 @@ +
    +
    + {{localize tabs.attachments.label}} + + {{#if attachedItems}} +
    + {{#each attachedItems as |item|}} +
    + {{item.name}} +
    +
    {{item.name}}
    +
    +
    + +
    +
    + {{/each}} +
    + {{/if}} + +
    + {{localize "DAGGERHEART.EFFECTS.Attachments.attachHint"}} +
    +
    +
    diff --git a/templates/sheets/items/weapon/attachments.hbs b/templates/sheets/items/weapon/attachments.hbs new file mode 100644 index 00000000..e69de29b From 0fd62c610d8a79827e90b698143373ff04ac315b Mon Sep 17 00:00:00 2001 From: Dapoulp <74197441+Dapoulp@users.noreply.github.com> Date: Sun, 13 Jul 2025 18:39:23 +0200 Subject: [PATCH 12/12] actors datas max/total rework (#332) * actors datas max/total rework * Removed unused translation --------- Co-authored-by: WBHarry --- lang/en.json | 2 +- .../dialogs/damageReductionDialog.mjs | 4 +- .../applications/levelup/characterLevelup.mjs | 20 ++-- .../applications/levelup/companionLevelup.mjs | 8 +- module/applications/levelup/levelup.mjs | 20 ++-- .../applications/sheets/actors/adversary.mjs | 2 +- .../applications/sheets/actors/character.mjs | 2 +- .../applications/sheets/actors/companion.mjs | 2 +- module/config/itemConfig.mjs | 52 +++++------ module/data/action/baseAction.mjs | 10 +- module/data/actor/adversary.mjs | 11 +-- module/data/actor/character.mjs | 75 +++++---------- module/data/actor/companion.mjs | 34 ++----- module/data/item/subclass.mjs | 6 +- module/dice/d20Roll.mjs | 2 +- module/dice/dualityRoll.mjs | 2 +- module/documents/actor.mjs | 93 +------------------ module/helpers/handlebarsHelper.mjs | 2 +- templates/dialogs/damageReduction.hbs | 2 +- .../adversary-settings/experiences.hbs | 2 +- .../companion-settings/details.hbs | 2 +- templates/sheets/actors/adversary/sidebar.hbs | 12 +-- templates/sheets/actors/character/header.hbs | 8 +- templates/sheets/actors/character/sidebar.hbs | 14 +-- templates/sheets/actors/companion/header.hbs | 6 +- .../sheets/actors/companion/tempMain.hbs | 44 --------- templates/ui/tooltip/adversary.hbs | 2 +- 27 files changed, 133 insertions(+), 306 deletions(-) delete mode 100644 templates/sheets/actors/companion/tempMain.hbs diff --git a/lang/en.json b/lang/en.json index 5497d5e6..bb67b6c2 100755 --- a/lang/en.json +++ b/lang/en.json @@ -389,7 +389,7 @@ "default": "Default Ownership" } }, - + "CONFIG": { "ActionType": { "passive": "Passive", diff --git a/module/applications/dialogs/damageReductionDialog.mjs b/module/applications/dialogs/damageReductionDialog.mjs index 0a0ebce1..984106d7 100644 --- a/module/applications/dialogs/damageReductionDialog.mjs +++ b/module/applications/dialogs/damageReductionDialog.mjs @@ -110,7 +110,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap ? { value: this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress, - maxTotal: this.actor.system.resources.stress.maxTotal + max: this.actor.system.resources.stress.max } : null; @@ -197,7 +197,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap : 0; const currentStress = this.actor.system.resources.stress.value + selectedStressMarks.length + stressReductionStress; - if (currentStress + stressReduction.cost > this.actor.system.resources.stress.maxTotal) { + if (currentStress + stressReduction.cost > this.actor.system.resources.stress.max) { ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.notEnoughStress')); return; } diff --git a/module/applications/levelup/characterLevelup.mjs b/module/applications/levelup/characterLevelup.mjs index 6dc6f4c3..d6bbe2db 100644 --- a/module/applications/levelup/characterLevelup.mjs +++ b/module/applications/levelup/characterLevelup.mjs @@ -223,8 +223,8 @@ export default class DhCharacterLevelUp extends LevelUpBase { context.achievements = { proficiency: { - old: this.actor.system.proficiency.total, - new: this.actor.system.proficiency.total + achivementProficiency, + old: this.actor.system.proficiency, + new: this.actor.system.proficiency + achivementProficiency, shown: achivementProficiency > 0 }, damageThresholds: { @@ -332,16 +332,16 @@ export default class DhCharacterLevelUp extends LevelUpBase { new: context.achievements.proficiency.new + (advancement.proficiency ?? 0) }, hitPoints: { - old: this.actor.system.resources.hitPoints.maxTotal, - new: this.actor.system.resources.hitPoints.maxTotal + (advancement.hitPoint ?? 0) + old: this.actor.system.resources.hitPoints.max, + new: this.actor.system.resources.hitPoints.max + (advancement.hitPoint ?? 0) }, stress: { - old: this.actor.system.resources.stress.maxTotal, - new: this.actor.system.resources.stress.maxTotal + (advancement.stress ?? 0) + old: this.actor.system.resources.stress.max, + new: this.actor.system.resources.stress.max + (advancement.stress ?? 0) }, evasion: { - old: this.actor.system.evasion.total, - new: this.actor.system.evasion.total + (advancement.evasion ?? 0) + old: this.actor.system.evasion, + new: this.actor.system.evasion + (advancement.evasion ?? 0) } }, traits: Object.keys(this.actor.system.traits).reduce((acc, traitKey) => { @@ -349,8 +349,8 @@ export default class DhCharacterLevelUp extends LevelUpBase { if (!acc) acc = {}; acc[traitKey] = { label: game.i18n.localize(abilities[traitKey].label), - old: this.actor.system.traits[traitKey].total, - new: this.actor.system.traits[traitKey].total + advancement.trait[traitKey] + old: this.actor.system.traits[traitKey].max, + new: this.actor.system.traits[traitKey].max + advancement.trait[traitKey] }; } return acc; diff --git a/module/applications/levelup/companionLevelup.mjs b/module/applications/levelup/companionLevelup.mjs index de411572..2fcc42a0 100644 --- a/module/applications/levelup/companionLevelup.mjs +++ b/module/applications/levelup/companionLevelup.mjs @@ -122,12 +122,12 @@ export default class DhCompanionLevelUp extends BaseLevelUp { context.advancements = { statistics: { stress: { - old: this.actor.system.resources.stress.maxTotal, - new: this.actor.system.resources.stress.maxTotal + (advancement.stress ?? 0) + old: this.actor.system.resources.stress.max, + new: this.actor.system.resources.stress.max + (advancement.stress ?? 0) }, evasion: { - old: this.actor.system.evasion.total, - new: this.actor.system.evasion.total + (advancement.evasion ?? 0) + old: this.actor.system.evasion, + new: this.actor.system.evasion + (advancement.evasion ?? 0) } }, experiences: diff --git a/module/applications/levelup/levelup.mjs b/module/applications/levelup/levelup.mjs index 93910fe7..141a0a06 100644 --- a/module/applications/levelup/levelup.mjs +++ b/module/applications/levelup/levelup.mjs @@ -157,8 +157,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) context.achievements = { proficiency: { - old: this.actor.system.proficiency.total, - new: this.actor.system.proficiency.total + achivementProficiency, + old: this.actor.system.proficiency, + new: this.actor.system.proficiency + achivementProficiency, shown: achivementProficiency > 0 }, damageThresholds: { @@ -265,16 +265,16 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) new: context.achievements.proficiency.new + (advancement.proficiency ?? 0) }, hitPoints: { - old: this.actor.system.resources.hitPoints.maxTotal, - new: this.actor.system.resources.hitPoints.maxTotal + (advancement.hitPoint ?? 0) + old: this.actor.system.resources.hitPoints.max, + new: this.actor.system.resources.hitPoints.max + (advancement.hitPoint ?? 0) }, stress: { - old: this.actor.system.resources.stress.maxTotal, - new: this.actor.system.resources.stress.maxTotal + (advancement.stress ?? 0) + old: this.actor.system.resources.stress.max, + new: this.actor.system.resources.stress.max + (advancement.stress ?? 0) }, evasion: { - old: this.actor.system.evasion.total, - new: this.actor.system.evasion.total + (advancement.evasion ?? 0) + old: this.actor.system.evasion, + new: this.actor.system.evasion + (advancement.evasion ?? 0) } }, traits: Object.keys(this.actor.system.traits).reduce((acc, traitKey) => { @@ -282,8 +282,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) if (!acc) acc = {}; acc[traitKey] = { label: game.i18n.localize(abilities[traitKey].label), - old: this.actor.system.traits[traitKey].total, - new: this.actor.system.traits[traitKey].total + advancement.trait[traitKey] + old: this.actor.system.traits[traitKey].value, + new: this.actor.system.traits[traitKey].value + advancement.trait[traitKey] }; } return acc; diff --git a/module/applications/sheets/actors/adversary.mjs b/module/applications/sheets/actors/adversary.mjs index 0b01ebee..af89abe6 100644 --- a/module/applications/sheets/actors/adversary.mjs +++ b/module/applications/sheets/actors/adversary.mjs @@ -93,7 +93,7 @@ export default class AdversarySheet extends DHBaseActorSheet { const cls = getDocumentClass('ChatMessage'); const systemData = { name: game.i18n.localize('DAGGERHEART.GENERAL.Experience.single'), - description: `${experience.name} ${experience.total.signedString()}` + description: `${experience.name} ${experience.value.signedString()}` }; const msg = new cls({ type: 'abilityUse', diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 5f0199f3..8a18dd22 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -650,7 +650,7 @@ export default class CharacterSheet extends DHBaseActorSheet { const cls = getDocumentClass('ChatMessage'); const systemData = { name: game.i18n.localize('DAGGERHEART.GENERAL.Experience.single'), - description: `${experience.name} ${experience.total < 0 ? experience.total : `+${experience.total}`}` + description: `${experience.name} ${experience.value.signedString()}` }; const msg = new cls({ type: 'abilityUse', diff --git a/module/applications/sheets/actors/companion.mjs b/module/applications/sheets/actors/companion.mjs index 042a4bfa..a1d00d96 100644 --- a/module/applications/sheets/actors/companion.mjs +++ b/module/applications/sheets/actors/companion.mjs @@ -59,7 +59,7 @@ export default class DhCompanionSheet extends DHBaseActorSheet { const cls = getDocumentClass('ChatMessage'); const systemData = { name: game.i18n.localize('DAGGERHEART.GENERAL.Experience.single'), - description: `${experience.name} ${experience.total < 0 ? experience.total : `+${experience.total}`}` + description: `${experience.name} ${experience.value.signedString()}` }; const msg = new cls({ type: 'abilityUse', diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index ed77310c..1d6b96b8 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -41,37 +41,37 @@ export const armorFeatures = { img: 'icons/magic/control/buff-flight-wings-red.webp', changes: [ { - key: 'system.traits.agility.bonus', + key: 'system.traits.agility.value', mode: 2, value: '-1' }, { - key: 'system.traits.strength.bonus', + key: 'system.traits.strength.value', mode: 2, value: '-1' }, { - key: 'system.traits.finesse.bonus', + key: 'system.traits.finesse.value', mode: 2, value: '-1' }, { - key: 'system.traits.instinct.bonus', + key: 'system.traits.instinct.value', mode: 2, value: '-1' }, { - key: 'system.traits.presence.bonus', + key: 'system.traits.presence.value', mode: 2, value: '-1' }, { - key: 'system.traits.knowledge.bonus', + key: 'system.traits.knowledge.value', mode: 2, value: '-1' }, { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' } @@ -89,7 +89,7 @@ export const armorFeatures = { img: 'icons/magic/movement/abstract-ribbons-red-orange.webp', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '1' } @@ -125,7 +125,7 @@ export const armorFeatures = { img: 'icons/magic/control/control-influence-crown-gold.webp', changes: [ { - key: 'system.traits.presence.bonus', + key: 'system.traits.presence.value', mode: 2, value: '1' } @@ -143,7 +143,7 @@ export const armorFeatures = { img: 'icons/commodities/metal/ingot-worn-iron.webp', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' } @@ -372,12 +372,12 @@ export const armorFeatures = { img: 'icons/commodities/metal/ingot-stamped-steel.webp', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-2' }, { - key: 'system.traits.agility.bonus', + key: 'system.traits.agility.value', mode: 2, value: '-1' } @@ -413,7 +413,7 @@ export const weaponFeatures = { { changes: [ { - key: 'system.bonuses.armorScore', + key: 'system.armorScore', mode: 2, value: 'ITEM.@system.tier + 1' } @@ -422,7 +422,7 @@ export const weaponFeatures = { { changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' } @@ -474,7 +474,7 @@ export const weaponFeatures = { { changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' } @@ -529,7 +529,7 @@ export const weaponFeatures = { img: 'icons/magic/lightning/claws-unarmed-strike-teal.webp', changes: [ { - key: 'system.proficiency.bonus', + key: 'system.proficiency', mode: 2, value: '1' } @@ -569,7 +569,7 @@ export const weaponFeatures = { img: 'icons/commodities/metal/mail-plate-steel.webp', changes: [ { - key: 'system.traits.finesse.bonus', + key: 'system.traits.finesse.value', mode: 2, value: '-1' } @@ -615,7 +615,7 @@ export const weaponFeatures = { img: 'icons/skills/melee/hand-grip-sword-strike-orange.webp', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '@system.armorScore' } @@ -645,7 +645,7 @@ export const weaponFeatures = { img: 'icons/skills/melee/strike-flail-spiked-pink.webp', changes: [ { - key: 'system.traits.agility.bonus', + key: 'system.traits.agility.value', mode: 2, value: '-1' } @@ -683,7 +683,7 @@ export const weaponFeatures = { img: 'icons/skills/melee/sword-shield-stylized-white.webp', changes: [ { - key: 'system.bonuses.armorScore', + key: 'system.armorScore', mode: 2, value: '1' }, @@ -777,7 +777,7 @@ export const weaponFeatures = { img: 'icons/commodities/currency/coins-crown-stack-gold.webp', changes: [ { - key: 'system.proficiency.bonus', + key: 'system.proficiency', mode: 2, value: '1' } @@ -819,7 +819,7 @@ export const weaponFeatures = { img: 'icons/commodities/metal/ingot-worn-iron.webp', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' } @@ -941,7 +941,7 @@ export const weaponFeatures = { img: '', changes: [ { - key: 'system.evasion.bonus', + key: 'system.evasion', mode: 2, value: '-1' }, @@ -1031,7 +1031,7 @@ export const weaponFeatures = { img: 'icons/magic/control/hypnosis-mesmerism-eye.webp', changes: [ { - key: 'system.traits.presence.bonus', + key: 'system.traits.presence.value', mode: 2, value: '2' } @@ -1088,7 +1088,7 @@ export const weaponFeatures = { img: 'icons/skills/melee/shield-block-gray-orange.webp', changes: [ { - key: 'system.bonuses.armorScore', + key: 'system.armorScore', mode: 2, value: '1' } @@ -1218,7 +1218,7 @@ export const weaponFeatures = { { key: 'system.bonuses.damage.primaryWeapon.bonus', mode: 2, - value: '@system.traits.agility.total' + value: '@system.traits.agility.value' } ] } diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 8fb15f50..ae70bf21 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -331,7 +331,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel { .filter(c => c.enabled !== false) .map(c => { const resource = this.actor.system.resources[c.type]; - return { type: c.type, value: (c.total ?? c.value) * (resource.hasOwnProperty('maxTotal') ? 1 : -1) }; + return { type: c.type, value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1) }; }); await this.actor.modifyResource(resources); @@ -384,12 +384,12 @@ export default class DHBaseAction extends foundry.abstract.DataModel { return false; } - /* maxTotal is a sign that the resource is inverted, IE it counts upwards instead of down */ + /* isReversed is a sign that the resource is inverted, IE it counts upwards instead of down */ const resources = this.actor.system.resources; return realCosts.reduce( (a, c) => - a && resources[c.type].hasOwnProperty('maxTotal') - ? resources[c.type].value + (c.total ?? c.value) <= resources[c.type].maxTotal + a && resources[c.type].isReversed + ? resources[c.type].value + (c.total ?? c.value) <= resources[c.type].max : resources[c.type]?.value >= (c.total ?? c.value), true ); @@ -432,7 +432,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel { name: actor.actor.name, img: actor.actor.img, difficulty: actor.actor.system.difficulty, - evasion: actor.actor.system.evasion?.total + evasion: actor.actor.system.evasion }; } /* TARGET */ diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index cf3669a1..78e08323 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -5,8 +5,8 @@ import BaseDataActor from './base.mjs'; const resourceField = () => new foundry.data.fields.SchemaField({ value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), - bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }), - max: new foundry.data.fields.NumberField({ initial: 0, integer: true }) + max: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + isReversed: new foundry.data.fields.BooleanField({ initial: true }) }); export default class DhpAdversary extends BaseDataActor { @@ -76,7 +76,7 @@ export default class DhpAdversary extends BaseDataActor { experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField(), - total: new fields.NumberField({ required: true, integer: true, initial: 1 }) + value: new fields.NumberField({ required: true, integer: true, initial: 1 }) }) ), bonuses: new fields.SchemaField({ @@ -95,9 +95,4 @@ export default class DhpAdversary extends BaseDataActor { get features() { return this.parent.items.filter(x => x.type === 'feature'); } - - prepareDerivedData() { - this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus; - this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus; - } } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index d26e368a..d8fc2b5c 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -5,16 +5,15 @@ import BaseDataActor from './base.mjs'; const attributeField = () => new foundry.data.fields.SchemaField({ - value: new foundry.data.fields.NumberField({ initial: null, integer: true }), - bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }), + value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), tierMarked: new foundry.data.fields.BooleanField({ initial: false }) }); -const resourceField = max => +const resourceField = (max, reverse = false) => new foundry.data.fields.SchemaField({ value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), - bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }), - max: new foundry.data.fields.NumberField({ initial: max, integer: true }) + max: new foundry.data.fields.NumberField({ initial: max, integer: true }), + isReversed: new foundry.data.fields.BooleanField({ initial: reverse }) }); const stressDamageReductionRule = () => @@ -38,11 +37,8 @@ export default class DhCharacter extends BaseDataActor { return { ...super.defineSchema(), resources: new fields.SchemaField({ - hitPoints: new fields.SchemaField({ - value: new foundry.data.fields.NumberField({ initial: 0, integer: true }), - bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true }) - }), - stress: resourceField(6), + hitPoints: resourceField(0, true), + stress: resourceField(6, true), hope: resourceField(6), tokens: new fields.ObjectField(), dice: new fields.ObjectField() @@ -55,18 +51,17 @@ export default class DhCharacter extends BaseDataActor { presence: attributeField(), knowledge: attributeField() }), - proficiency: new fields.SchemaField({ - value: new fields.NumberField({ initial: 1, integer: true }), - bonus: new fields.NumberField({ initial: 0, integer: true }) - }), - evasion: new fields.SchemaField({ - bonus: new fields.NumberField({ initial: 0, integer: true }) + proficiency: new fields.NumberField({ initial: 1, integer: true }), + evasion: new fields.NumberField({ initial: 0, integer: true }), + armorScore: new fields.NumberField({ integer: true, initial: 0 }), + damageThresholds: new fields.SchemaField({ + severe: new fields.NumberField({ integer: true, initial: 0 }), + major: new fields.NumberField({ integer: true, initial: 0 }) }), experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField(), - value: new fields.NumberField({ integer: true, initial: 0 }), - bonus: new fields.NumberField({ integer: true, initial: 0 }) + value: new fields.NumberField({ integer: true, initial: 0 }) }) ), gold: new fields.SchemaField({ @@ -100,11 +95,6 @@ export default class DhCharacter extends BaseDataActor { }), levelData: new fields.EmbeddedDataField(DhLevelData), bonuses: new fields.SchemaField({ - armorScore: new fields.NumberField({ integer: true, initial: 0 }), - damageThresholds: new fields.SchemaField({ - severe: new fields.NumberField({ integer: true, initial: 0 }), - major: new fields.NumberField({ integer: true, initial: 0 }) - }), roll: new fields.SchemaField({ attack: new fields.NumberField({ integer: true, initial: 0 }), primaryWeapon: new fields.SchemaField({ @@ -303,7 +293,7 @@ export default class DhCharacter extends BaseDataActor { get deathMoveViable() { return ( - this.resources.hitPoints.maxTotal > 0 && this.resources.hitPoints.value >= this.resources.hitPoints.maxTotal + this.resources.hitPoints.max > 0 && this.resources.hitPoints.value >= this.resources.hitPoints.max ); } @@ -347,32 +337,32 @@ export default class DhCharacter extends BaseDataActor { for (let levelKey in this.levelData.levelups) { const level = this.levelData.levelups[levelKey]; - this.proficiency.bonus += level.achievements.proficiency; + this.proficiency += level.achievements.proficiency; for (let selection of level.selections) { switch (selection.type) { case 'trait': selection.data.forEach(data => { - this.traits[data].bonus += 1; + this.traits[data].value += 1; this.traits[data].tierMarked = selection.tier === currentTier; }); break; case 'hitPoint': - this.resources.hitPoints.bonus += selection.value; + this.resources.hitPoints.max += selection.value; break; case 'stress': - this.resources.stress.bonus += selection.value; + this.resources.stress.max += selection.value; break; case 'evasion': - this.evasion.bonus += selection.value; + this.evasion += selection.value; break; case 'proficiency': - this.proficiency.bonus = selection.value; + this.proficiency = selection.value; break; case 'experience': Object.keys(this.experiences).forEach(key => { const experience = this.experiences[key]; - experience.bonus += selection.value; + experience.value += selection.value; }); break; } @@ -380,7 +370,7 @@ export default class DhCharacter extends BaseDataActor { } const armor = this.armor; - this.armorScore = this.armor ? this.armor.system.baseScore + (this.bonuses.armorScore ?? 0) : 0; // Bonuses to armorScore won't have been applied yet. Need to solve in documentPreparation somehow + this.armorScore = armor ? armor.system.baseScore : 0; this.damageThresholds = { major: armor ? armor.system.baseThresholds.major + this.levelData.level.current @@ -389,29 +379,12 @@ export default class DhCharacter extends BaseDataActor { ? armor.system.baseThresholds.severe + this.levelData.level.current : this.levelData.level.current * 2 }; + this.resources.hope.max -= Object.keys(this.scars).length; + this.resources.hitPoints.max = this.class.value?.system?.hitPoints ?? 0; } prepareDerivedData() { - this.resources.hope.max -= Object.keys(this.scars).length; this.resources.hope.value = Math.min(this.resources.hope.value, this.resources.hope.max); - - for (var traitKey in this.traits) { - var trait = this.traits[traitKey]; - trait.total = (trait.value ?? 0) + trait.bonus; - } - - for (var experienceKey in this.experiences) { - var experience = this.experiences[experienceKey]; - experience.total = experience.value + experience.bonus; - } - - this.rules.damageReduction.maxArmorMarked.total = - this.rules.damageReduction.maxArmorMarked.value + this.rules.damageReduction.maxArmorMarked.bonus; - - this.resources.hitPoints.maxTotal = (this.class.value?.system?.hitPoints ?? 0) + this.resources.hitPoints.bonus; - this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus; - this.evasion.total = (this.class?.evasion ?? 0) + this.evasion.bonus; - this.proficiency.total = this.proficiency.value + this.proficiency.bonus; } getRollData() { diff --git a/module/data/actor/companion.mjs b/module/data/actor/companion.mjs index b1c41ea3..ea417bd8 100644 --- a/module/data/actor/companion.mjs +++ b/module/data/actor/companion.mjs @@ -25,20 +25,16 @@ export default class DhCompanion extends BaseDataActor { resources: new fields.SchemaField({ stress: new fields.SchemaField({ value: new fields.NumberField({ initial: 0, integer: true }), - bonus: new fields.NumberField({ initial: 0, integer: true }), - max: new fields.NumberField({ initial: 3, integer: true }) + max: new fields.NumberField({ initial: 3, integer: true }), + isReversed: new foundry.data.fields.BooleanField({ initial: true }) }), hope: new fields.NumberField({ initial: 0, integer: true }) }), - evasion: new fields.SchemaField({ - value: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }), - bonus: new fields.NumberField({ initial: 0, integer: true }) - }), + evasion: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }), experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField({}), - value: new fields.NumberField({ integer: true, initial: 0 }), - bonus: new fields.NumberField({ integer: true, initial: 0 }) + value: new fields.NumberField({ integer: true, initial: 0 }) }), { initial: { @@ -84,19 +80,17 @@ export default class DhCompanion extends BaseDataActor { get traits() { return { - instinct: { total: this.attack.roll.bonus } + instinct: { value: this.attack.roll.bonus } }; } get proficiency() { - return { - total: this.partner?.system?.proficiency?.total ?? 1 - }; + return this.partner?.system?.proficiency ?? 1; } prepareBaseData() { const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main; - const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.total; + const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.value; this.attack.roll.bonus = spellcastingModifier ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing; for (let levelKey in this.levelData.levelups) { @@ -114,15 +108,15 @@ export default class DhCompanion extends BaseDataActor { } break; case 'stress': - this.resources.stress.bonus += selection.value; + this.resources.stress.max += selection.value; break; case 'evasion': - this.evasion.bonus += selection.value; + this.evasion += selection.value; break; case 'experience': Object.keys(this.experiences).forEach(key => { const experience = this.experiences[key]; - experience.bonus += selection.value; + experience.value += selection.value; }); break; } @@ -131,17 +125,9 @@ export default class DhCompanion extends BaseDataActor { } prepareDerivedData() { - for (var experienceKey in this.experiences) { - var experience = this.experiences[experienceKey]; - experience.total = experience.value + experience.bonus; - } - if (this.partner) { this.partner.system.resources.hope.max += this.resources.hope; } - - this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus; - this.evasion.total = this.evasion.value + this.evasion.bonus; } async _preDelete() { diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index 3c47841d..265c2566 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -32,9 +32,9 @@ export default class DHSubclass extends BaseDataItem { get features() { return [ - { ...this.foundationFeature.toObject(), identifier: 'foundationFeature' }, - { ...this.specializationFeature.toObject(), identifier: 'specializationFeature' }, - { ...this.masteryFeature.toObject(), identifier: 'masteryFeature' } + { ...this.foundationFeature?.toObject(), identifier: 'foundationFeature' }, + { ...this.specializationFeature?.toObject(), identifier: 'specializationFeature' }, + { ...this.masteryFeature?.toObject(), identifier: 'masteryFeature' } ]; } diff --git a/module/dice/d20Roll.mjs b/module/dice/d20Roll.mjs index 9c784084..c9e9d428 100644 --- a/module/dice/d20Roll.mjs +++ b/module/dice/d20Roll.mjs @@ -97,7 +97,7 @@ export default class D20Roll extends DHRoll { if (this.options.data.experiences?.[m]) this.options.roll.modifiers.push({ label: this.options.data.experiences[m].name, - value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value + value: this.options.data.experiences[m].value }); }); diff --git a/module/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 6c1d0fe4..1044b93a 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -123,7 +123,7 @@ export default class DualityRoll extends D20Roll { if (!this.options.roll.trait) return; this.options.roll.modifiers.push({ label: `DAGGERHEART.CONFIG.Traits.${this.options.roll.trait}.name`, - value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data) + value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.value`, this.data) }); } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 0bd45690..d8d75461 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -371,96 +371,13 @@ export default class DhpActor extends Actor { getRollData() { const rollData = super.getRollData(); - rollData.prof = this.system.proficiency?.total ?? 1; - rollData.cast = this.system.spellcast?.total ?? 1; + rollData.prof = this.system.proficiency ?? 1; + rollData.cast = this.system.spellcast ?? 1; return rollData; } - formatRollModifier(roll) { - const modifier = roll.modifier !== null ? Number.parseInt(roll.modifier) : null; - return modifier !== null - ? [ - { - value: modifier, - label: roll.label - ? modifier >= 0 - ? `${roll.label} +${modifier}` - : `${roll.label} ${modifier}` - : null, - title: roll.label - } - ] - : []; - } - - async damageRoll(title, damage, targets, shiftKey) { - let rollString = damage.value; - let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? []; - if (!shiftKey) { - const dialogClosed = new Promise((resolve, _) => { - new DamageSelectionDialog(rollString, bonusDamage, resolve).render(true); - }); - const result = await dialogClosed; - bonusDamage = result.bonusDamage; - rollString = result.rollString; - - const automateHope = await game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation.Hope); - if (automateHope && result.hopeUsed) { - await this.update({ - 'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed - }); - } - } - - const roll = new Roll(rollString); - let rollResult = await roll.evaluate(); - - const dice = []; - const modifiers = []; - for (var i = 0; i < rollResult.terms.length; i++) { - const term = rollResult.terms[i]; - if (term.faces) { - dice.push({ - type: `d${term.faces}`, - rolls: term.results.map(x => x.result), - total: term.results.reduce((acc, x) => acc + x.result, 0) - }); - } else if (term.operator) { - } else if (term.number) { - const operator = i === 0 ? '' : rollResult.terms[i - 1].operator; - modifiers.push({ value: term.number, operator: operator }); - } - } - - const cls = getDocumentClass('ChatMessage'); - const systemData = { - title: game.i18n.format('DAGGERHEART.UI.Chat.damageRoll.title', { damage: title }), - roll: rollString, - damage: { - total: rollResult.total, - type: damage.type - }, - dice: dice, - modifiers: modifiers, - targets: targets - }; - const msg = new cls({ - type: 'damageRoll', - user: game.user.id, - sound: CONFIG.sounds.dice, - system: systemData, - content: await foundry.applications.handlebars.renderTemplate( - 'systems/daggerheart/templates/ui/chat/damage-roll.hbs', - systemData - ), - rolls: [roll] - }); - - cls.create(msg.toObject()); - } - #canReduceDamage(hpDamage, type) { - const availableStress = this.system.resources.stress.maxTotal - this.system.resources.stress.value; + const availableStress = this.system.resources.stress.max - this.system.resources.stress.value; const canUseArmor = this.system.armor && @@ -568,7 +485,7 @@ export default class DhpActor extends Actor { updates.actor.resources[`system.resources.${r.type}.value`] = Math.max( Math.min( this.system.resources[r.type].value + r.value, - this.system.resources[r.type].maxTotal ?? this.system.resources[r.type].max + this.system.resources[r.type].max ), 0 ); @@ -600,7 +517,7 @@ export default class DhpActor extends Actor { convertStressDamageToHP(resources) { const stressDamage = resources.find(r => r.type === 'stress'), newValue = this.system.resources.stress.value + stressDamage.value; - if (newValue <= this.system.resources.stress.maxTotal) return; + if (newValue <= this.system.resources.stress.max) return; const hpDamage = resources.find(r => r.type === 'hitPoints'); if (hpDamage) hpDamage.value++; else diff --git a/module/helpers/handlebarsHelper.mjs b/module/helpers/handlebarsHelper.mjs index feeebbd2..b3b46dcb 100644 --- a/module/helpers/handlebarsHelper.mjs +++ b/module/helpers/handlebarsHelper.mjs @@ -28,7 +28,7 @@ export default class RegisterHandlebarsHelpers { } static damageFormula(attack, actor) { - const traitTotal = actor.system.traits?.[attack.roll.trait]?.total; + const traitTotal = actor.system.traits?.[attack.roll.trait]?.value; const instances = [ attack.damage.parts.map(x => Roll.replaceFormulaData(x.value.getFormula(), actor)).join(' + '), traitTotal diff --git a/templates/dialogs/damageReduction.hbs b/templates/dialogs/damageReduction.hbs index 4c30bbfc..43f55e86 100644 --- a/templates/dialogs/damageReduction.hbs +++ b/templates/dialogs/damageReduction.hbs @@ -8,7 +8,7 @@ {{#if this.stress}}

    {{localize "DAGGERHEART.APPLICATIONS.DamageReduction.stress"}}

    -
    {{this.stress.value}}/{{this.stress.maxTotal}}
    +
    {{this.stress.value}}/{{this.stress.max}}
    {{/if}}
    diff --git a/templates/sheets-settings/adversary-settings/experiences.hbs b/templates/sheets-settings/adversary-settings/experiences.hbs index c15bf6b9..5fe2ab36 100644 --- a/templates/sheets-settings/adversary-settings/experiences.hbs +++ b/templates/sheets-settings/adversary-settings/experiences.hbs @@ -13,7 +13,7 @@ {{#each document.system.experiences as |experience key|}}
  • - +
  • {{/each}} diff --git a/templates/sheets-settings/companion-settings/details.hbs b/templates/sheets-settings/companion-settings/details.hbs index 2811377d..97b04b24 100644 --- a/templates/sheets-settings/companion-settings/details.hbs +++ b/templates/sheets-settings/companion-settings/details.hbs @@ -6,7 +6,7 @@
    {{localize 'DAGGERHEART.GENERAL.basics'}}
    - {{formGroup systemFields.evasion.fields.value value=document.system.evasion.value localize=true}} + {{formGroup systemFields.evasion value=document.system.evasion localize=true}} {{formGroup systemFields.resources.fields.stress.fields.value value=document.system.resources.stress.value label='Current Stress'}} {{formGroup systemFields.resources.fields.stress.fields.max value=document.system.resources.stress.max label='Max Stress'}}
    diff --git a/templates/sheets/actors/adversary/sidebar.hbs b/templates/sheets/actors/adversary/sidebar.hbs index ad23ab25..4ba2360b 100644 --- a/templates/sheets/actors/adversary/sidebar.hbs +++ b/templates/sheets/actors/adversary/sidebar.hbs @@ -1,5 +1,5 @@