From 7af3f07a2652956b5342fa301572e3f0edd36c4d Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sun, 19 Apr 2026 20:58:34 +0200 Subject: [PATCH] Stuff --- lang/en.json | 8 ++ module/applications/dialogs/_module.mjs | 1 + .../dialogs/levelupOptionsDialog.mjs | 92 +++++++++++++++++++ .../applications/levelup/characterLevelup.mjs | 6 +- .../sheets/api/application-mixin.mjs | 21 ++++- module/data/actor/character.mjs | 24 ++++- module/data/item/class.mjs | 9 +- module/data/levelTier.mjs | 45 +++++++-- module/systemRegistration/handlebars.mjs | 3 +- styles/less/dialog/index.less | 1 + .../dialog/levelup-options-dialog/sheet.less | 32 +++++++ .../dialogs/levelupOptionsDialog/header.hbs | 3 + .../levelupOptionsDialog/parts/tier.hbs | 26 ++++++ .../dialogs/levelupOptionsDialog/tiers.hbs | 5 + 14 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 module/applications/dialogs/levelupOptionsDialog.mjs create mode 100644 styles/less/dialog/levelup-options-dialog/sheet.less create mode 100644 templates/dialogs/levelupOptionsDialog/header.hbs create mode 100644 templates/dialogs/levelupOptionsDialog/parts/tier.hbs create mode 100644 templates/dialogs/levelupOptionsDialog/tiers.hbs diff --git a/lang/en.json b/lang/en.json index 7b8b45c7..d6452d30 100755 --- a/lang/en.json +++ b/lang/en.json @@ -682,6 +682,9 @@ "title": "{actor} Level Up", "viewModeTitle": "{actor} Level Up (View Mode)" }, + "LevelupOptionsDialog": { + "title": "Levelup Options: {name}" + }, "MulticlassChoice": { "title": "Multiclassing - {actor}", "explanation": "You are adding {class} as your multiclass", @@ -1263,6 +1266,10 @@ "diceValue": "Dice Value", "die": "Die" }, + "LevelupData": { + "checkboxSelections": "Checkboxes", + "minCost": "Cost Per Checkbox" + }, "Range": { "self": { "name": "Self", @@ -3257,6 +3264,7 @@ "rightClickExtend": "Right-Click to extend", "companionPartnerLevelBlock": "The companion needs an assigned partner to level up.", "configureAttribution": "Configure Attribution", + "configureLevelupOptions": "Configure Levelup Options", "deleteItem": "Delete Item", "immune": "Immune", "middleClick": "[Middle Click] Keep tooltip view", diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index c866f1cd..044fdf03 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -17,3 +17,4 @@ export { default as TagTeamDialog } from './tagTeamDialog.mjs'; export { default as GroupRollDialog } from './groupRollDialog.mjs'; export { default as RiskItAllDialog } from './riskItAllDialog.mjs'; export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs'; +export { default as LevelupOptionsDialog } from './levelupOptionsDialog.mjs'; \ No newline at end of file diff --git a/module/applications/dialogs/levelupOptionsDialog.mjs b/module/applications/dialogs/levelupOptionsDialog.mjs new file mode 100644 index 00000000..afc247b3 --- /dev/null +++ b/module/applications/dialogs/levelupOptionsDialog.mjs @@ -0,0 +1,92 @@ +import { LevelOptionType } from "../../data/levelTier.mjs"; + +const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; + +export default class LevelupOptionsDialog extends HandlebarsApplicationMixin(ApplicationV2) { + constructor(item) { + super({}); + + this.item = item; + this.selectedOption = null; + } + + get title() { + return game.i18n.format('DAGGERHEART.APPLICATIONS.LevelupOptionsDialog.title', { name: this.item.name }); + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'levelup-options-dialog'], + position: { width: 480, height: 'auto' }, + window: { icon: 'fa-solid fa-angles-up fa-fw' }, + actions: { + addTierOption: LevelupOptionsDialog.#addTierOption, + removeTierOption: LevelupOptionsDialog.#removeTierOption, + }, + form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false } + }; + + static PARTS = { + header: { template: 'systems/daggerheart/templates/dialogs/levelupOptionsDialog/header.hbs' }, + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + tiers: { template: 'systems/daggerheart/templates/dialogs/levelupOptionsDialog/tiers.hbs' }, + }; + + /** @inheritdoc */ + static TABS = { + primary: { + tabs: [ + { id: 'tier2', label: 'DAGGERHEART.GENERAL.Tiers.2', tier: 2 }, + { id: 'tier3', label: 'DAGGERHEART.GENERAL.Tiers.3', tier: 3 }, + { id: 'tier4', label: 'DAGGERHEART.GENERAL.Tiers.4', tier: 4 } + ], + initial: 'tier2', + } + }; + + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + for(const element of htmlElement.querySelectorAll('.option-type-select')) + element.addEventListener('change', this.updateSelectedOption.bind(this)); + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options); + context.item = this.item; + context.fields = this.item.system.schema.fields.levelupOptionTiers.element.element.fields; + context.optionTypes = LevelOptionType; + context.selectedOption = this.selectedOption; + + return context; + } + + static async updateData(_event, _element, formData) { + const data = foundry.utils.expandObject(formData.object); + + this.render(); + } + + updateSelectedOption(event) { + this.selectedOption = event.target.value; + this.render(); + } + + static async #addTierOption(_event, button) { + const { tier } = button.dataset; + await this.item.update({ [`system.levelupOptionTiers.${tier}.${foundry.utils.randomID()}`]: { + label: LevelOptionType[this.selectedOption].label, + type: this.selectedOption + }}); + + this.selectedOption = null; + this.render(); + } + + static async #removeTierOption(_event, button) { + const { tier, key } = button.dataset; + + await this.item.update({ [`system.levelupOptionTiers.${tier}.${key}`]: _del }); + this.render(); + } +} diff --git a/module/applications/levelup/characterLevelup.mjs b/module/applications/levelup/characterLevelup.mjs index f7ef2ffa..13ae0d87 100644 --- a/module/applications/levelup/characterLevelup.mjs +++ b/module/applications/levelup/characterLevelup.mjs @@ -6,9 +6,7 @@ export default class DhCharacterLevelUp extends LevelUpBase { constructor(actor) { super(actor); - this.levelTiers = this.addBonusChoices( - game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers) - ); + this.levelTiers = this.addBonusChoices(actor.system.levelupTiers); const playerLevelupData = actor.system.levelData; this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData)); } @@ -366,7 +364,7 @@ export default class DhCharacterLevelUp extends LevelUpBase { advancement.experience?.flatMap(x => x.data.map(data => ({ name: data, modifier: x.value }))) ?? [], multiclass: advancement.multiclass, - subclass: advancement.subclass + subclass: advancement.subclass, }; context.advancements.statistics.proficiency.shown = diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index e93ce774..4555d9f0 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -99,7 +99,8 @@ export default function DHApplicationMixin(Base) { toggleExtended: DHSheetV2.#toggleExtended, addNewItem: DHSheetV2.#addNewItem, browseItem: DHSheetV2.#browseItem, - editAttribution: DHSheetV2.#editAttribution + editAttribution: DHSheetV2.#editAttribution, + configureLevelUpOptions: DHSheetV2.#configureLevelUpOptions, }, contextMenus: [ { @@ -119,6 +120,16 @@ export default function DHApplicationMixin(Base) { } } ], + window: { + controls: [ + { + icon: 'fa-solid fa-angles-up fa-fw', + label: 'DAGGERHEART.UI.Tooltip.configureLevelupOptions', + action: 'configureLevelUpOptions', + visible: DHSheetV2.#hasLevelUpOptions, + } + ], + }, dragDrop: [{ dragSelector: '.inventory-item[data-type="effect"]', dropSelector: null }], tagifyConfigs: [] }; @@ -142,6 +153,10 @@ export default function DHApplicationMixin(Base) { return frame; } + static #hasLevelUpOptions() { + return this.document.system.metadata.hasLevelUpOptions; + }; + /** * Refresh the custom parts of the application frame */ @@ -708,6 +723,10 @@ export default function DHApplicationMixin(Base) { new game.system.api.applications.dialogs.AttributionDialog(this.document).render({ force: true }); } + static async #configureLevelUpOptions() { + new game.system.api.applications.dialogs.LevelupOptionsDialog(this.document).render({ force: true }); + } + /** * Create an embedded document. * @type {ApplicationClickAction} diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index bf3d7bb8..3e85c139 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -303,7 +303,13 @@ export default class DhCharacter extends DhCreature { initial: null, label: 'DAGGERHEART.ACTORS.Character.defaultDisadvantageDice' }), - }) + }), + comboDieIndex: new fields.NumberField({ + integer: true, + min: 0, + max: 5, + initial: 0, + }) }) }; } @@ -447,6 +453,19 @@ export default class DhCharacter extends DhCreature { return attack; } + get levelupTiers() { + const tierData = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers); + for (const tierKey of Object.keys(this.class?.value?.system.levelupOptionTiers ?? {})) { + const tier = this.class.value.system.levelupOptionTiers[tierKey]; + for (const optionKey of Object.keys(tier)) { + const option = tier[optionKey]; + tierData.tiers[tierKey].options[optionKey] = option; + } + } + + return tierData; + } + /* All items are valid on characters */ isItemValid() { return true; @@ -745,6 +764,9 @@ export default class DhCharacter extends DhCreature { } }); break; + case 'comboStrikes': + this.rules.comboDieIndex += 1; + break; } } } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index d3738318..bb87fb88 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -3,6 +3,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs'; import { addLinkedItemsDiff, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs'; +import { DhLevelOption } from '../levelTier.mjs'; export default class DHClass extends BaseDataItem { /** @inheritDoc */ @@ -10,7 +11,8 @@ export default class DHClass extends BaseDataItem { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Item.class', type: 'class', - hasDescription: true + hasDescription: true, + hasLevelUpOptions: true, }); } @@ -51,7 +53,10 @@ export default class DHClass extends BaseDataItem { }), backgroundQuestions: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), connections: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), - isMulticlass: new fields.BooleanField({ initial: false }) + isMulticlass: new fields.BooleanField({ initial: false }), + levelupOptionTiers: new fields.TypedObjectField(new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelOption)), { + initial: { 2: {}, 3: {}, 4: {} } + }), }; } diff --git a/module/data/levelTier.mjs b/module/data/levelTier.mjs index 2252e4da..6a9c13f6 100644 --- a/module/data/levelTier.mjs +++ b/module/data/levelTier.mjs @@ -43,17 +43,40 @@ class DhLevelTier extends foundry.abstract.DataModel { } } -class DhLevelOption extends foundry.abstract.DataModel { +export class DhLevelOption extends foundry.abstract.DataModel { static defineSchema() { const fields = foundry.data.fields; return { - label: new fields.StringField({ required: true }), - checkboxSelections: new fields.NumberField({ required: true, integer: true, initial: 1 }), - minCost: new fields.NumberField({ required: true, integer: true, initial: 1 }), - type: new fields.StringField({ required: true, choices: LevelOptionType }), - value: new fields.NumberField({ integer: true }), - amount: new fields.NumberField({ integer: true }) + label: new fields.StringField({ + required: true, + label: 'DAGGERHEART.GENERAL.label' + }), + checkboxSelections: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.CONFIG.LevelupData.checkboxSelections' + }), + minCost: new fields.NumberField({ + required: true, + integer: true, + initial: 1, + label: 'DAGGERHEART.CONFIG.LevelupData.minCost' + }), + type: new fields.StringField({ + required: true, + choices: LevelOptionType, + label: 'DAGGERHEART.GENERAL.type' + }), + value: new fields.NumberField({ + integer: true, + label: 'DAGGERHEART.GENERAL.value' + }), + amount: new fields.NumberField({ + integer: true, + label: 'DAGGERHEART.GENERAL.amount' + }) }; } } @@ -113,6 +136,13 @@ export const CompanionLevelOptionType = { } }; +export const ClassLevelOptionTypes = { + comboStrikes: { + id: 'comboStrikes', + label: 'Increase your Combo Die size', + }, +}; + export const LevelOptionType = { trait: { id: 'trait', @@ -162,6 +192,7 @@ export const LevelOptionType = { id: 'multiclass', label: 'Multiclass' }, + ...ClassLevelOptionTypes, ...CompanionLevelOptionType }; diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index ebd65fa2..5a414c5a 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -51,6 +51,7 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs', 'systems/daggerheart/templates/scene/dh-config.hbs', 'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs', - 'systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs' + 'systems/daggerheart/templates/sheets/activeEffect/typeChanges/armorChange.hbs', + 'systems/daggerheart/templates/dialogs/levelupOptionsDialog/parts/tier.hbs' ]); }; diff --git a/styles/less/dialog/index.less b/styles/less/dialog/index.less index 947142ff..80e358af 100644 --- a/styles/less/dialog/index.less +++ b/styles/less/dialog/index.less @@ -51,3 +51,4 @@ @import './character-reset/sheet.less'; @import './compendiumBrowserPackDialog/sheet.less'; +@import './levelup-options-dialog/sheet.less'; \ No newline at end of file diff --git a/styles/less/dialog/levelup-options-dialog/sheet.less b/styles/less/dialog/levelup-options-dialog/sheet.less new file mode 100644 index 00000000..2b6886ed --- /dev/null +++ b/styles/less/dialog/levelup-options-dialog/sheet.less @@ -0,0 +1,32 @@ +.daggerheart.dh-style.dialog.levelup-options-dialog { + .dialog-title { + font-size: var(--font-size-32); + color: light-dark(@dark-blue, @golden); + text-align: center; + } + + .tier-tools { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; + + button { + white-space: nowrap; + } + } + + .tier-container { + padding: 0 4px; + display: flex; + flex-direction: column; + gap: 8px; + + .tier-title { + font-size: var(--font-size-18); + color: light-dark(@dark-blue, @golden); + margin-left: auto; + margin-right: auto; + } + } +} \ No newline at end of file diff --git a/templates/dialogs/levelupOptionsDialog/header.hbs b/templates/dialogs/levelupOptionsDialog/header.hbs new file mode 100644 index 00000000..2ea61486 --- /dev/null +++ b/templates/dialogs/levelupOptionsDialog/header.hbs @@ -0,0 +1,3 @@ +
+
{{localize "Tiers"}}
+
\ No newline at end of file diff --git a/templates/dialogs/levelupOptionsDialog/parts/tier.hbs b/templates/dialogs/levelupOptionsDialog/parts/tier.hbs new file mode 100644 index 00000000..906e3407 --- /dev/null +++ b/templates/dialogs/levelupOptionsDialog/parts/tier.hbs @@ -0,0 +1,26 @@ +
+
+ + +
+ {{#with (lookup item.system.levelupOptionTiers tab.tier)}} + {{#unless (empty this)}} + {{#each this as |option key|}} +
+ + +
+ {{formGroup @root.fields.label value=option.label name=(concat "system.levelOptionTiers." ../../tab.tier "." key ".label") localize=true }} + {{formGroup @root.fields.type value=option.type name=(concat "system.levelOptionTiers." ../../tab.tier "." key ".type") localize=true }} +
+ {{formGroup @root.fields.checkboxSelections value=option.checkboxSelections name=(concat "system.levelOptionTiers." ../../tab.tier "." key ".checkboxSelections") localize=true }} + {{formGroup @root.fields.minCost value=option.minCost name=(concat "system.levelOptionTiers." ../../tab.tier "." key ".minCost") localize=true }} +
+
+
+ {{/each}} + {{/unless}} + {{/with}} +
\ No newline at end of file diff --git a/templates/dialogs/levelupOptionsDialog/tiers.hbs b/templates/dialogs/levelupOptionsDialog/tiers.hbs new file mode 100644 index 00000000..aa2eb443 --- /dev/null +++ b/templates/dialogs/levelupOptionsDialog/tiers.hbs @@ -0,0 +1,5 @@ +
+ {{> "systems/daggerheart/templates/dialogs/levelupOptionsDialog/parts/tier.hbs" tab=tabs.tier2}} + {{> "systems/daggerheart/templates/dialogs/levelupOptionsDialog/parts/tier.hbs" tab=tabs.tier3}} + {{> "systems/daggerheart/templates/dialogs/levelupOptionsDialog/parts/tier.hbs" tab=tabs.tier4}} +
\ No newline at end of file