From 2a294684d4d70a3d1984facac75a67c7f89acc46 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 28 Mar 2026 00:38:50 +0100 Subject: [PATCH] Remade branch (#1754) --- lang/en.json | 11 +- .../applications/dialogs/beastformDialog.mjs | 38 +++ .../sheets-configs/action-base-config.mjs | 19 +- module/data/fields/action/beastformField.mjs | 23 +- .../feature_Evolution_6rlxhrRwFaVgq9fe.json | 270 +----------------- styles/less/dialog/beastform/sheet.less | 38 +++ styles/less/sheets/actions/actions.less | 14 + templates/actionTypes/beastform.hbs | 16 +- templates/dialogs/beastform/modifications.hbs | 28 ++ 9 files changed, 182 insertions(+), 275 deletions(-) create mode 100644 templates/dialogs/beastform/modifications.hbs diff --git a/lang/en.json b/lang/en.json index 5dc09a1e..d341b4bf 100755 --- a/lang/en.json +++ b/lang/en.json @@ -89,9 +89,14 @@ }, "Config": { "beastform": { - "exact": "Beastform Max Tier", - "exactHint": "The Character's Tier is used if empty", - "label": "Beastform" + "exact": { "label": "Beastform Max Tier", "hint": "The Character's Tier is used if empty" }, + "modifications": { + "traitBonuses": { + "label": { "single": "Trait Bonus", "plural": "Trait Bonuses" }, + "hint": "Pick bonuses you apply to freely chosen traits at the time of transforming", + "bonus": "Bonus Amount" + } + } }, "countdown": { "defaultOwnership": "Default Ownership", diff --git a/module/applications/dialogs/beastformDialog.mjs b/module/applications/dialogs/beastformDialog.mjs index 09a9222b..8ae6d5fe 100644 --- a/module/applications/dialogs/beastformDialog.mjs +++ b/module/applications/dialogs/beastformDialog.mjs @@ -10,6 +10,12 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat this.selected = null; this.evolved = { form: null }; this.hybrid = { forms: {}, advantages: {}, features: {} }; + this.modifications = { + traitBonuses: configData.modifications.traitBonuses.map(x => ({ + trait: null, + bonus: x.bonus + })) + }; this._dragDrop = this._createDragDropHandlers(); } @@ -28,6 +34,7 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat selectBeastform: this.selectBeastform, toggleHybridFeature: this.toggleHybridFeature, toggleHybridAdvantage: this.toggleHybridAdvantage, + toggleTraitBonus: this.toggleTraitBonus, submitBeastform: this.submitBeastform }, form: { @@ -48,6 +55,7 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat tabs: { template: 'systems/daggerheart/templates/dialogs/beastform/tabs.hbs' }, beastformTier: { template: 'systems/daggerheart/templates/dialogs/beastform/beastformTier.hbs' }, advanced: { template: 'systems/daggerheart/templates/dialogs/beastform/advanced.hbs' }, + modifications: { template: 'systems/daggerheart/templates/dialogs/beastform/modifications.hbs' }, footer: { template: 'systems/daggerheart/templates/dialogs/beastform/footer.hbs' } }; @@ -146,6 +154,9 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat {} ); + context.modifications = this.modifications; + context.traits = CONFIG.DH.ACTOR.abilities; + context.tier = beastformTiers[this.tabGroups.primary]; context.tierKey = this.tabGroups.primary; @@ -155,6 +166,9 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } canSubmit() { + const modificationsFinished = this.modifications.traitBonuses.every(x => x.trait); + if (!modificationsFinished) return false; + if (this.selected) { switch (this.selected.system.beastformType) { case 'normal': @@ -261,6 +275,13 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat this.render(); } + static toggleTraitBonus(_, button) { + const { index, trait } = button.dataset; + this.modifications.traitBonuses[index].trait = + this.modifications.traitBonuses[index].trait === trait ? null : trait; + this.render(); + } + static async submitBeastform() { await this.close({ submitted: true }); } @@ -292,6 +313,23 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } } + const beastformEffect = selected.effects.find(x => x.type === 'beastform'); + for (const traitBonus of app.modifications.traitBonuses) { + const existingChange = beastformEffect.changes.find( + x => x.key === `system.traits.${traitBonus.trait}.value` + ); + if (existingChange) { + existingChange.value = Number.parseInt(existingChange.value) + traitBonus.bonus; + } else { + beastformEffect.changes.push({ + key: `system.traits.${traitBonus.trait}.value`, + mode: 2, + priority: null, + value: traitBonus.bonus + }); + } + } + resolve({ selected: selected, evolved: { ...app.evolved, form: evolved }, diff --git a/module/applications/sheets-configs/action-base-config.mjs b/module/applications/sheets-configs/action-base-config.mjs index 05a3177d..0ae39477 100644 --- a/module/applications/sheets-configs/action-base-config.mjs +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -36,7 +36,9 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) editDoc: this.editDoc, addTrigger: this.addTrigger, removeTrigger: this.removeTrigger, - expandTrigger: this.expandTrigger + expandTrigger: this.expandTrigger, + addBeastformTraitBonus: this.addBeastformTraitBonus, + removeBeastformTraitBonus: this.removeBeastformTraitBonus }, form: { handler: this.updateForm, @@ -412,6 +414,21 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) } } + static async addBeastformTraitBonus() { + const data = this.action.toObject(); + data.beastform.modifications.traitBonuses = [ + ...data.beastform.modifications.traitBonuses, + this.action.schema.fields.beastform.fields.modifications.fields.traitBonuses.element.getInitialValue() + ]; + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static async removeBeastformTraitBonus(_event, button) { + const data = this.action.toObject(); + data.beastform.modifications.traitBonuses.splice(button.dataset.index, 1); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + updateSummonCount(event) { event.stopPropagation(); const wrapper = event.target.closest('.summon-count-wrapper'); diff --git a/module/data/fields/action/beastformField.mjs b/module/data/fields/action/beastformField.mjs index e19807c7..e3be9937 100644 --- a/module/data/fields/action/beastformField.mjs +++ b/module/data/fields/action/beastformField.mjs @@ -28,8 +28,21 @@ export default class BeastformField extends fields.SchemaField { { 1: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') } ); }, - hint: 'DAGGERHEART.ACTIONS.Config.beastform.exactHint' + label: 'DAGGERHEART.ACTIONS.Config.beastform.exact.label', + hint: 'DAGGERHEART.ACTIONS.Config.beastform.exact.hint' }) + }), + modifications: new fields.SchemaField({ + traitBonuses: new fields.ArrayField( + new fields.SchemaField({ + bonus: new fields.NumberField({ + integer: true, + initial: 1, + min: 1, + label: 'DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.bonus' + }) + }) + ) }) }; super(beastformFields, options, context); @@ -66,15 +79,9 @@ export default class BeastformField extends fields.SchemaField { ) ?? 1; config.tierLimit = this.beastform.tierAccess.exact ?? actorTier; + config.modifications = this.beastform.modifications; } - /** - * TODO by Harry - * @param {*} selectedForm - * @param {*} evolvedData - * @param {*} hybridData - * @returns - */ static async transform(selectedForm, evolvedData, hybridData) { const formData = evolvedData?.form ?? selectedForm; const beastformEffect = formData.effects.find(x => x.type === 'beastform'); diff --git a/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json b/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json index 46380fe8..421063a4 100644 --- a/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json +++ b/src/packs/classes/feature_Evolution_6rlxhrRwFaVgq9fe.json @@ -5,7 +5,7 @@ "_id": "6rlxhrRwFaVgq9fe", "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", "system": { - "description": "
Spend 3 Hope to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.
Note: Toggle one of the Evolution Traits in the effects tab to raise a trait by 1, e.g. Evolution: Agility
Spend 3 Hope to transform into a Beastform without marking a Stress. When you do, choose one trait to raise by +1 until you drop out of that Beastform.
", "resource": null, "actions": { "bj4m9E8ObFT0xDQ4": { @@ -31,6 +31,13 @@ "beastform": { "tierAccess": { "exact": null + }, + "modifications": { + "traitBonuses": [ + { + "bonus": 1 + } + ] } }, "name": "Beastform", @@ -46,266 +53,7 @@ "artist": "" } }, - "effects": [ - { - "name": "Evolution: Agility", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "vQOqLZAxOltAzsVv", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.agility.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Agility when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.vQOqLZAxOltAzsVv" - }, - { - "name": "Evolution: Strength", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "cwEsO1NZpkQHuoTT", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.strength.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Strength when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.cwEsO1NZpkQHuoTT" - }, - { - "name": "Evolution: Finesse", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "8P0nwRHNsVnHVPjq", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.finesse.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Finesse when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.8P0nwRHNsVnHVPjq" - }, - { - "name": "Evolution: Instinct", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "i2GhNGo5TnGtLuA0", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.instinct.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Instinct when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.i2GhNGo5TnGtLuA0" - }, - { - "name": "Evolution: Presence", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "APQF1in1LXjBZh9n", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.presence.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Presence when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.APQF1in1LXjBZh9n" - }, - { - "name": "Evolution: Knowledge", - "type": "base", - "system": { - "rangeDependence": { - "enabled": false, - "type": "withinRange", - "target": "hostile", - "range": "melee" - } - }, - "_id": "WwOvGJYJb4d37cOy", - "img": "icons/magic/nature/wolf-paw-glow-large-orange.webp", - "changes": [ - { - "key": "system.traits.knowledge.value", - "mode": 2, - "value": "1", - "priority": null - } - ], - "disabled": true, - "duration": { - "startTime": null, - "combat": null, - "seconds": null, - "rounds": null, - "turns": null, - "startRound": null, - "startTurn": null - }, - "description": "Toggle this for +1 to Knowledge when using Evolution. Turn it off when you leave Beastform.
", - "origin": null, - "tint": "#ffffff", - "transfer": true, - "statuses": [], - "sort": 0, - "flags": {}, - "_stats": { - "compendiumSource": null - }, - "_key": "!items.effects!6rlxhrRwFaVgq9fe.WwOvGJYJb4d37cOy" - } - ], + "effects": [], "sort": 100000, "ownership": { "default": 0, diff --git a/styles/less/dialog/beastform/sheet.less b/styles/less/dialog/beastform/sheet.less index 9e87f53b..0e1fe746 100644 --- a/styles/less/dialog/beastform/sheet.less +++ b/styles/less/dialog/beastform/sheet.less @@ -204,6 +204,44 @@ } } + .modifications-container { + display: flex; + flex-direction: column; + gap: 16px; + + .trait-bonuses-container { + display: flex; + flex-direction: column; + gap: 8px; + + .bonus-separator { + background: light-dark(@dark-blue, @golden); + mask-image: linear-gradient(270deg, transparent 0%, black 50%, transparent 100%); + height: 2px; + width: calc(100% - 10px); + } + + .trait-bonus-container { + display: flex; + gap: 4px; + + .trait-card { + border: 1px solid light-dark(@dark-blue, @golden); + border-radius: 6px; + padding: 2px; + opacity: 0.4; + flex: 1; + white-space: nowrap; + text-align: center; + + &.selected { + opacity: 1; + } + } + } + } + } + footer { margin-top: 8px; display: flex; diff --git a/styles/less/sheets/actions/actions.less b/styles/less/sheets/actions/actions.less index 5c21dc60..5a18d622 100644 --- a/styles/less/sheets/actions/actions.less +++ b/styles/less/sheets/actions/actions.less @@ -133,4 +133,18 @@ height: 300px; } } + + .deletable-row { + display: flex; + align-items: end; + gap: 8px; + + input { + flex: 1; + } + + a { + padding-bottom: 7px; + } + } } diff --git a/templates/actionTypes/beastform.hbs b/templates/actionTypes/beastform.hbs index b9bea445..885038a1 100644 --- a/templates/actionTypes/beastform.hbs +++ b/templates/actionTypes/beastform.hbs @@ -1,4 +1,16 @@ +{{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}} + \ No newline at end of file diff --git a/templates/dialogs/beastform/modifications.hbs b/templates/dialogs/beastform/modifications.hbs new file mode 100644 index 00000000..2563ea13 --- /dev/null +++ b/templates/dialogs/beastform/modifications.hbs @@ -0,0 +1,28 @@ +