diff --git a/lang/en.json b/lang/en.json index 4032b6ed..fb487f0e 100755 --- a/lang/en.json +++ b/lang/en.json @@ -87,9 +87,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..6faa5586 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; @@ -156,11 +167,14 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat canSubmit() { if (this.selected) { + const modificationsFinished = + !this.modifications.traitBonuses.length || this.modifications.traitBonuses.every(x => x.trait); + switch (this.selected.system.beastformType) { case 'normal': - return true; + return modificationsFinished; case 'evolved': - return this.evolved.form; + return modificationsFinished && this.evolved.form; case 'hybrid': const selectedAdvantages = Object.values(this.hybrid.advantages).reduce( (acc, form) => acc + Object.values(form).length, @@ -173,7 +187,7 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat const advantagesSelected = selectedAdvantages === this.selected.system.hybrid.advantages; const featuresSelected = selectedFeatures === this.selected.system.hybrid.features; - return advantagesSelected && featuresSelected; + return modificationsFinished && advantagesSelected && featuresSelected; } } @@ -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,24 @@ export default class BeastformDialog extends HandlebarsApplicationMixin(Applicat } } + const beastformEffect = selected.effects.find(x => x.type === 'beastform'); + while (app.modifications.traitBonuses.length) { + const traitBonus = app.modifications.traitBonuses.pop(); + 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 ce0e7e24..a166c9c5 100644 --- a/module/applications/sheets-configs/action-base-config.mjs +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -35,7 +35,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, @@ -360,6 +362,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/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=""}} +
- {{localize "DAGGERHEART.ACTIONS.Config.beastform.label"}} - {{formGroup fields.tierAccess.fields.exact value=source.tierAccess.exact name="beastform.tierAccess.exact" labelAttr="label" valueAttr="key" localize=true blank=""}} + {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.plural"}} + + {{#if source.modifications.traitBonuses.length}} + {{#each source.modifications.traitBonuses as |traitBonus index|}} +
+ {{formGroup ../fields.modifications.fields.traitBonuses.element.fields.bonus value=traitBonus.bonus name=(concat "beastform.modifications.traitBonuses." index ".bonus") localize=true}} + +
+ {{/each}} + {{else}} + {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.hint"}} + {{/if}}
\ 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 @@ +
+ {{#if modifications.traitBonuses.length}} +
+ + {{#if (gt modifications.traitBonuses.length 1)}} + {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.plural"}} + {{else}} + {{localize "DAGGERHEART.ACTIONS.Config.beastform.modifications.traitBonuses.label.single"}} + {{/if}} + + +
+ {{#each modifications.traitBonuses as |traitBonus index|}} +
+ {{#each @root.traits as |trait|}} + + {{localize trait.label}} +{{traitBonus.bonus}} + + {{/each}} +
+ {{#unless @last}}
{{/unless}} + {{/each}} +
+
+ {{/if}} +
\ No newline at end of file