From cc0766fc20c91d4b8f02423a9ac155f126523f6a Mon Sep 17 00:00:00 2001 From: WBHarry Date: Wed, 28 May 2025 19:49:22 +0200 Subject: [PATCH] Fixed data handling in the LevelUp view --- module/applications/levelup.mjs | 434 ++++---------------------------- module/data/levelTier.mjs | 10 + module/data/levelup.mjs | 116 +++++++-- module/data/pc.mjs | 31 ++- styles/daggerheart.css | 17 +- styles/levelup.less | 20 +- templates/sheets/pc/pc.hbs | 4 +- templates/views/levelup.hbs | 11 +- 8 files changed, 231 insertions(+), 412 deletions(-) diff --git a/module/applications/levelup.mjs b/module/applications/levelup.mjs index e5747488..26010f09 100644 --- a/module/applications/levelup.mjs +++ b/module/applications/levelup.mjs @@ -10,7 +10,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) this.levelTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers); const playerLevelupData = actor.system.levelData; - this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData)); + this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData, actor.system.level)); } get title() { @@ -23,11 +23,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) window: { resizable: true }, - actions: {}, - form: { - handler: this.updateForm, - submitOnChange: true, - closeOnSubmit: false + actions: { + save: this.save } }; @@ -45,380 +42,57 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2) return context; } - static async updateForm(event, _, formData) { - await this.document.update(formData.object); + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + $(htmlElement).find('.selection-checkbox').on('change', this.selectionClick.bind(this)); + } + + async selectionClick(event) { + const button = event.currentTarget; + + if (!button.checked) { + await this.levelup.updateSource({ + [`tiers.${button.dataset.tier}.levels.${button.dataset.level}.optionSelections.${button.dataset.option}.-=${button.dataset.checkboxNr}`]: + null + }); + } else { + const levelSelections = this.levelup.levelSelections; + if (levelSelections.total >= this.levelup.maxSelections) { + // Notification? + this.render(); + return; + } + + const tier = this.levelup.tiers[button.dataset.tier]; + const tierLevels = Object.keys(tier.levels).map(level => Number(level)); + const lowestLevelChoice = Object.keys(levelSelections.selections).reduce((currentLowest, key) => { + const level = Number(key); + if (tierLevels.includes(level)) { + if (!currentLowest || level < currentLowest) return level; + } + + return currentLowest; + }, null); + + if (!lowestLevelChoice) { + // Notification? + this.render(); + return; + } + + await this.levelup.updateSource({ + [`tiers.${button.dataset.tier}.levels.${lowestLevelChoice}.optionSelections.${button.dataset.option}.${button.dataset.checkboxNr}`]: true + }); + } + this.render(); } + + static async save() { + await this.actor.update({ + 'system.levelData.selections': [{ tier: 1, level: 2, type: 'hitPoint', checkboxNr: 1 }] + }); + + this.close(); + } } - -// import SelectDialog from '../dialogs/selectDialog.mjs'; -// import { getTier } from '../helpers/utils.mjs'; -// import DhpMulticlassDialog from './multiclassDialog.mjs'; - -// const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; - -// export default class DhpLevelup extends HandlebarsApplicationMixin(ApplicationV2) { -// constructor(actor) { -// super({}); - -// this.actor = actor; -// this.data = foundry.utils.deepClone(actor.system.levelData); -// this.activeLevel = actor.system.levelData.currentLevel + 1; -// } - -// get title() { -// return `${this.actor.name} - Level Up`; -// } - -// static DEFAULT_OPTIONS = { -// classes: ['daggerheart', 'views', 'levelup'], -// position: { width: 1200, height: 'auto' }, -// window: { -// resizable: true -// }, - -// actions: { -// toggleBox: this.toggleBox, -// advanceLevel: this.advanceLevel, -// finishLevelup: this.finishLevelup -// } -// }; - -// static PARTS = { -// form: { -// id: 'levelup', -// template: 'systems/daggerheart/templates/views/levelup.hbs' -// } -// }; - -// async _prepareContext(_options) { -// let selectedChoices = 0, -// multiclassing = {}, -// subclassing = {}; -// const leveledTiers = Object.keys(this.data.levelups).reduce( -// (acc, levelKey) => { -// const levelData = this.data.levelups[levelKey]; -// ['tier1', 'tier2', 'tier3'].forEach(tierKey => { -// let tierUpdate = {}; -// const tierData = levelData[tierKey]; -// if (tierData) { -// tierUpdate = Object.keys(tierData).reduce((acc, propertyKey) => { -// const values = tierData[propertyKey]; -// const level = Number.parseInt(levelKey); - -// acc[propertyKey] = Object.values(values).map(value => { -// if (value && level === this.activeLevel) selectedChoices++; -// if (propertyKey === 'multiclass') multiclassing[levelKey] = true; -// if (propertyKey === 'subclass') subclassing[tierKey] = true; - -// return { level: level, value: value }; -// }); - -// return acc; -// }, {}); -// } - -// Object.keys(tierUpdate).forEach(propertyKey => { -// const property = tierUpdate[propertyKey]; -// const propertyValues = foundry.utils.getProperty(acc, `${tierKey}.${propertyKey}`) ?? []; -// foundry.utils.setProperty(acc, `${tierKey}.${propertyKey}`, [...propertyValues, ...property]); -// }); -// }); - -// return acc; -// }, -// { tier1: {}, tier2: {}, tier3: {} } -// ); - -// const activeTier = getTier(this.activeLevel); -// const data = Object.keys(SYSTEM.ACTOR.levelupData).reduce((acc, tierKey) => { -// const tier = SYSTEM.ACTOR.levelupData[tierKey]; -// acc[tierKey] = { -// label: game.i18n.localize(tier.label), -// info: game.i18n.localize(tier.info), -// pretext: game.i18n.localize(tier.pretext), -// postext: game.i18n.localize(tier.posttext), -// active: tierKey <= activeTier, -// choices: Object.keys(tier.choices).reduce((acc, propertyKey) => { -// const property = tier.choices[propertyKey]; -// acc[propertyKey] = { description: property.description, cost: property.cost ?? 1, values: [] }; -// for (var i = 0; i < property.maxChoices; i++) { -// const leveledValue = leveledTiers[tierKey][propertyKey]?.[i]; -// const subclassLock = -// propertyKey === 'subclass' && -// Object.keys(multiclassing).find(x => getTier(Number.parseInt(x)) === tierKey); -// const subclassMulticlassLock = propertyKey === 'multiclass' && subclassing[tierKey]; -// const multiclassLock = -// propertyKey === 'multiclass' && -// Object.keys(multiclassing).length > 0 && -// !( -// leveledValue && -// Object.keys(multiclassing).find(x => Number.parseInt(x) === leveledValue.level) -// ); -// const locked = -// (leveledValue && leveledValue.level !== this.activeLevel) || -// subclassLock || -// subclassMulticlassLock || -// multiclassLock; -// const disabled = -// tierKey > activeTier || -// (selectedChoices === 2 && !(leveledValue && leveledValue.level === this.activeLevel)) || -// locked; - -// acc[propertyKey].values.push({ -// selected: leveledValue?.value !== undefined, -// path: `levelups.${this.activeLevel}.${tierKey}.${propertyKey}.${i}`, -// description: game.i18n.localize(property.description), -// disabled: disabled, -// locked: locked -// }); -// } - -// return acc; -// }, {}) -// }; - -// return acc; -// }, {}); - -// return { -// data: data, -// activeLevel: this.activeLevel, -// changedLevel: this.actor.system.levelData.changedLevel, -// completedSelection: selectedChoices === 2 -// }; -// } - -// static async toggleBox(_, button) { -// const path = button.dataset.path; -// if (foundry.utils.getProperty(this.data, path)) { -// const pathParts = path.split('.'); -// const arrayPart = pathParts.slice(0, pathParts.length - 1).join('.'); -// let array = foundry.utils.getProperty(this.data, arrayPart); -// if (button.dataset.levelAttribute === 'multiclass') { -// array = []; -// } else { -// delete array[Number.parseInt(pathParts[pathParts.length - 1])]; -// } -// foundry.utils.setProperty(this.data, arrayPart, array); -// } else { -// const updates = [{ path: path, value: { level: this.activeLevel } }]; -// const levelChoices = SYSTEM.ACTOR.levelChoices[button.dataset.levelAttribute]; -// if (button.dataset.levelAttribute === 'subclass') { -// if (!this.actor.system.multiclassSubclass) { -// updates[0].value.value = { -// multiclass: false, -// feature: this.actor.system.subclass.system.specializationFeature.unlocked -// ? 'mastery' -// : 'specialization' -// }; -// } else { -// const choices = [ -// { name: this.actor.system.subclass.name, value: this.actor.system.subclass.uuid }, -// { -// name: this.actor.system.multiclassSubclass.name, -// value: this.actor.system.multiclassSubclass.uuid -// } -// ]; -// const indexes = await SelectDialog.selectItem({ -// actor: this.actor, -// choices: choices, -// title: levelChoices.title, -// nrChoices: 1 -// }); -// if (indexes.length === 0) { -// this.render(); -// return; -// } -// const multiclassSubclass = choices[indexes[0]].name === this.actor.system.multiclassSubclass.name; -// updates[0].value.value = { -// multiclass: multiclassSubclass, -// feature: this.actor.system.multiclassSubclass.system.specializationFeature.unlocked -// ? 'mastery' -// : 'specialization' -// }; -// } -// } else if (button.dataset.levelAttribute === 'multiclass') { -// const multiclassAwait = new Promise(resolve => { -// new DhpMulticlassDialog(this.actor.name, this.actor.system.class, resolve).render(true); -// }); -// const multiclassData = await multiclassAwait; -// if (!multiclassData) { -// this.render(); -// return; -// } - -// const pathParts = path.split('.'); -// const arrayPart = pathParts.slice(0, pathParts.length - 1).join('.'); -// updates[0] = { -// path: [arrayPart, '0'].join('.'), -// value: { -// level: this.activeLevel, -// value: { -// class: multiclassData.class, -// subclass: multiclassData.subclass, -// domain: multiclassData.domain, -// level: this.activeLevel -// } -// } -// }; -// updates[1] = { -// path: [arrayPart, '1'].join('.'), -// value: { -// level: this.activeLevel, -// value: { -// class: multiclassData.class, -// subclass: multiclassData.subclass, -// domain: multiclassData.domain, -// level: this.activeLevel -// } -// } -// }; -// } else { -// if (levelChoices.choices.length > 0) { -// if (typeof levelChoices.choices === 'string') { -// const choices = foundry.utils -// .getProperty(this.actor, levelChoices.choices) -// .map(x => ({ name: x.description, value: x.id })); -// const indexes = await SelectDialog.selectItem({ -// actor: this.actor, -// choices: choices, -// title: levelChoices.title, -// nrChoices: levelChoices.nrChoices -// }); -// if (indexes.length === 0) { -// this.render(); -// return; -// } -// updates[0].value.value = choices -// .filter((_, index) => indexes.includes(index)) -// .map(x => x.value); -// } else { -// const indexes = await SelectDialog.selectItem({ -// actor: this.actor, -// choices: levelChoices.choices, -// title: levelChoices.title, -// nrChoices: levelChoices.nrChoices -// }); -// if (indexes.length === 0) { -// this.render(); -// return; -// } -// updates[0].value.value = levelChoices.choices[indexes[0]].path; -// } -// } -// } - -// const update = updates.reduce((acc, x) => { -// acc[x.path] = x.value; - -// return acc; -// }, {}); - -// this.data = foundry.utils.mergeObject(this.data, update); -// } - -// this.render(); -// } - -// static advanceLevel() { -// this.activeLevel += 1; -// this.render(); -// } - -// static async finishLevelup() { -// this.data.currentLevel = this.data.changedLevel; -// let multiclass = null; -// for (var level in this.data.levelups) { -// for (var tier in this.data.levelups[level]) { -// for (var category in this.data.levelups[level][tier]) { -// for (var value in this.data.levelups[level][tier][category]) { -// if (category === 'multiclass') { -// multiclass = this.data.levelups[level][tier][category][value].value; -// this.data.levelups[level][tier][category][value] = true; -// } else { -// this.data.levelups[level][tier][category][value] = -// this.data.levelups[level][tier][category][value].value ?? true; -// } -// } -// } -// } -// } - -// const tiersMoved = -// getTier(this.actor.system.levelData.changedLevel, true) - -// getTier(this.actor.system.levelData.currentLevel, true); -// const experiences = Array.from(Array(tiersMoved), (_, index) => ({ -// id: foundry.utils.randomID(), -// level: this.actor.system.experiences.length + index * 3, -// description: '', -// value: 1 -// })); - -// await this.actor.update( -// { -// system: { -// levelData: this.data, -// experiences: [...this.actor.system.experiences, ...experiences] -// } -// }, -// { diff: false } -// ); - -// if (!this.actor.multiclass && multiclass) { -// const multiclassClass = (await fromUuid(multiclass.class.uuid)).toObject(); -// multiclassClass.system.domains = [multiclass.domain.id]; -// multiclassClass.system.multiclass = multiclass.level; - -// const multiclassFeatures = []; -// for (var i = 0; i < multiclassClass.system.features.length; i++) { -// const feature = (await fromUuid(multiclassClass.system.features[i].uuid)).toObject(); -// feature.system.multiclass = multiclass.level; -// multiclassFeatures.push(feature); -// } - -// const multiclassSubclass = (await fromUuid(multiclass.subclass.uuid)).toObject(); -// multiclassSubclass.system.multiclass = multiclass.level; - -// const multiclassSubclassFeatures = {}; -// const features = [ -// multiclassSubclass.system.foundationFeature, -// multiclassSubclass.system.specializationFeature, -// multiclassSubclass.system.masteryFeature -// ]; -// for (var i = 0; i < features.length; i++) { -// const path = i === 0 ? 'foundationFeature' : i === 1 ? 'specializationFeature' : 'masteryFeature'; -// const feature = features[i]; -// for (var ability of feature.abilities) { -// const data = (await fromUuid(ability.uuid)).toObject(); -// if (i > 0) data.system.disabled = true; -// data.system.multiclass = multiclass.level; -// if (!multiclassSubclassFeatures[path]) multiclassSubclassFeatures[path] = [data]; -// else multiclassSubclassFeatures[path].push(data); -// // data.uuid = feature.uuid; - -// // const abilityData = await this._onDropItemCreate(data); -// // ability.uuid = abilityData[0].uuid; - -// // createdItems.push(abilityData); -// } -// } - -// for (let subclassFeaturesKey in multiclassSubclassFeatures) { -// const values = multiclassSubclassFeatures[subclassFeaturesKey]; -// const abilityResults = await this.actor.createEmbeddedDocuments('Item', values); -// for (var i = 0; i < abilityResults.length; i++) { -// multiclassSubclass.system[subclassFeaturesKey].abilities[i].uuid = abilityResults[i].uuid; -// } -// } - -// await this.actor.createEmbeddedDocuments('Item', [ -// multiclassClass, -// ...multiclassFeatures, -// multiclassSubclass -// ]); -// } - -// this.close(); -// } -// } diff --git a/module/data/levelTier.mjs b/module/data/levelTier.mjs index 7eb316e6..12a6d5ca 100644 --- a/module/data/levelTier.mjs +++ b/module/data/levelTier.mjs @@ -6,6 +6,16 @@ export class DhLevelTiers extends foundry.abstract.DataModel { tiers: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelTier)) }; } + + get availableChoicesPerLevel() { + return Object.values(this.tiers).reduce((acc, tier) => { + for (var level = tier.levels.start; level < tier.levels.end + 1; level++) { + acc[level] = tier.availableOptions; + } + + return acc; + }, {}); + } } class DhLevelTier extends foundry.abstract.DataModel { diff --git a/module/data/levelup.mjs b/module/data/levelup.mjs index 93bc6491..3f1dfc8b 100644 --- a/module/data/levelup.mjs +++ b/module/data/levelup.mjs @@ -1,13 +1,28 @@ import { LevelOptionType } from './levelTier.mjs'; export class DhLevelup extends foundry.abstract.DataModel { - static initializeData(levelTierData, levelChoices) { + static initializeData(levelTierData, pcLevelData) { + const availableChoicesPerLevel = levelTierData.availableChoicesPerLevel; + return { tiers: Object.keys(levelTierData.tiers).reduce((acc, key) => { - acc[key] = DhLevelupTier.initializeData(levelTierData.tiers[key]); + acc[key] = DhLevelupTier.initializeData( + levelTierData.tiers[key], + pcLevelData.selections.filter(x => x.tier === key), + pcLevelData.level.changed + ); return acc; - }, {}) + }, {}), + maxSelections: [...Array(pcLevelData.level.changed).keys()].reduce((acc, index) => { + const level = index + 1; + const availableChoices = availableChoicesPerLevel[level]; + if (level > 1 && availableChoices) { + acc += availableChoices; + } + + return acc; + }, 0) }; } @@ -15,33 +30,73 @@ export class DhLevelup extends foundry.abstract.DataModel { const fields = foundry.data.fields; return { - tiers: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupTier)) + tiers: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupTier)), + maxSelections: new fields.NumberField({ required: true, integer: true }) }; } - get totalSelections() { - return Object.values(this.tiers).reduce((acc, tier) => acc + tier.nrSelections, 0); + get levelSelections() { + return Object.values(this.tiers).reduce( + (acc, tier) => { + acc.total += tier.selections.total; + for (var key in tier.selections.selections) { + const nrSelections = tier.selections.selections[key]; + + if (acc.selections[key]) acc.selections[key] += nrSelections; + else acc.selections[key] = nrSelections; + } + + return acc; + }, + { total: 0, selections: {} } + ); + } + + get playerData() { + return Object.keys(this.tiers).flatMap(tierKey => { + const tier = this.tiers[tierKey]; + return Object.keys(tier.levels).flatMap(levelKey => { + const level = tier.levels[levelKey]; + return Object.keys(level.optionSelections).flatMap(optionSelectionKey => { + const selection = level.optionSelections[optionSelectionKey]; + const optionSelect = tier.options[optionSelectionKey]; + + return Object.keys(selection).map(checkboxNr => ({ + tier: Number(tierKey), + level: Number(levelKey), + optionKey: optionSelectionKey, + type: optionSelect.type, + checkboxNr: Number(checkboxNr), + value: optionSelect.value, + amount: optionSelect.amount + })); + }); + }); + }); } } class DhLevelupTier extends foundry.abstract.DataModel { - static initializeData(levelTier, levelChoices) { + static initializeData(levelTier, pcLevelData, pcLevel) { const levels = {}; const levelEndCap = levelTier.levels.end + 1; for (var level = levelTier.levels.start; level < levelEndCap; level++) { - levels[level] = DhLevelupLevel.initializeData(levelTier.availableOptions, levelTier.options); + levels[level] = DhLevelupLevel.initializeData( + levelTier.availableOptions, + pcLevelData.filter(x => x.level === level) + ); } return { tier: levelTier.tier, name: levelTier.name, + active: pcLevel >= levelTier.levels.start, options: Object.keys(levelTier.options).reduce((acc, key) => { acc[key] = levelTier.options[key]; return acc; }, {}), - levels: levels, - maxSelections: levelTier.availableOptions * (levelEndCap - levelTier.levels.start) + levels: levels }; } @@ -51,14 +106,22 @@ class DhLevelupTier extends foundry.abstract.DataModel { return { tier: new fields.NumberField({ required: true, integer: true }), name: new fields.StringField({ required: true }), + active: new fields.BooleanField({ required: true, initial: true }), options: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupTierOption)), - levels: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupLevel)), - maxSelections: new fields.NumberField({ required: true, integer: true }) + levels: new fields.TypedObjectField(new fields.EmbeddedDataField(DhLevelupLevel)) }; } - get nrSelections() { - return Object.values(this.levels).reduce((acc, level) => acc + level.nrSelections, 0); + get selections() { + const allSelections = Object.keys(this.levels).reduce((acc, key) => { + acc[key] = this.levels[key].nrSelections; + + return acc; + }, {}); + return { + selections: allSelections, + total: Object.values(allSelections).reduce((acc, nr) => acc + nr, 0) + }; } /* Data to render all options in a Tier from */ @@ -69,14 +132,17 @@ class DhLevelupTier extends foundry.abstract.DataModel { label: game.i18n.localize(option.label), checkboxes: [...Array(option.checkboxQuantity).keys()].map(checkboxNr => { const levelId = Object.keys(this.levels).find(levelKey => { - Object.values(this.levels[levelKey].optionSelections).some(nr => nr === checkboxNr); + const optionSelect = this.levels[levelKey].optionSelections; + return Object.keys(optionSelect) + .filter(key => key === optionKey) + .some(optionKey => optionSelect[optionKey][checkboxNr]); }); return { ...option, tier: this.tier, level: levelId, selected: Boolean(levelId), - optionkey: optionKey, + optionKey: optionKey, checkboxNr: checkboxNr }; }) @@ -101,10 +167,15 @@ class DhLevelupTierOption extends foundry.abstract.DataModel { } class DhLevelupLevel extends foundry.abstract.DataModel { - static initializeData(maxSelections, levelOptions, levelChoices) { + static initializeData(maxSelections, levelData) { return { maxSelections: maxSelections, - optionSelections: {} // collate levelOption and levelChoices, + optionSelections: levelData.reduce((acc, data) => { + if (!acc[data.optionkey]) acc[data.optionKey] = {}; + acc[data.optionKey][data.checkboxNr] = true; + + return acc; + }, {}) }; } @@ -114,14 +185,15 @@ class DhLevelupLevel extends foundry.abstract.DataModel { return { maxSelections: new fields.NumberField({ required: true, integer: true }), optionSelections: new fields.TypedObjectField( - new fields.SchemaField({ - checkboxNr: new fields.NumberField({ required: true, integer: true }) - }) + new fields.TypedObjectField(new fields.BooleanField({ required: true, initial: true })) ) }; } get nrSelections() { - return this.optionSelections.length; + return Object.keys(this.optionSelections).reduce( + (acc, optionKey) => acc + Object.keys(this.optionSelections[optionKey]).length, + 0 + ); } } diff --git a/module/data/pc.mjs b/module/data/pc.mjs index 74cff93b..6ef81f4b 100644 --- a/module/data/pc.mjs +++ b/module/data/pc.mjs @@ -1,4 +1,5 @@ import { getPathValue, getTier } from '../helpers/utils.mjs'; +import { LevelOptionType } from './levelTier.mjs'; const fields = foundry.data.fields; @@ -97,8 +98,8 @@ export default class DhpPC extends foundry.abstract.TypeDataModel { armorMarks: new fields.SchemaField({ max: new fields.NumberField({ initial: 6, integer: true }), value: new fields.NumberField({ initial: 0, integer: true }) - }) - // levelUpData: new fields.TypeDataModel(DhpLevelUpData), + }), + levelData: new fields.EmbeddedDataField(DhPCLevelData) }; } @@ -509,3 +510,29 @@ export default class DhpPC extends foundry.abstract.TypeDataModel { else return 0; } } + +class DhPCLevelData extends foundry.abstract.DataModel { + static defineSchema() { + return { + level: new fields.SchemaField({ + current: new fields.NumberField({ required: true, integer: true, initial: 1 }), + changed: new fields.NumberField({ required: true, integer: true, initial: 1 }) + }), + selections: new fields.ArrayField( + new fields.SchemaField({ + tier: new fields.NumberField({ required: true, integer: true }), + level: new fields.NumberField({ required: true, integer: true }), + optionKey: new fields.StringField({ required: true }), + type: new fields.StringField({ required: true, choices: LevelOptionType }), + checkboxNr: new fields.NumberField({ required: true, integer: true }), + value: new fields.NumberField({ integer: true }), + amount: new fields.NumberField({ integer: true }) + }) + ) + }; + } + + get canLevelUp() { + return this.level.current < this.level.updated; + } +} diff --git a/styles/daggerheart.css b/styles/daggerheart.css index 74d3b2f4..01387025 100755 --- a/styles/daggerheart.css +++ b/styles/daggerheart.css @@ -2797,18 +2797,33 @@ div.daggerheart.views.multiclass { gap: 8px; background-image: url('../assets/parchments/dh-parchment-dark.png'); } +.daggerheart.levelup .tiers-container .tier-container.inactive { + opacity: 0.4; + pointer-events: none; +} .daggerheart.levelup .tiers-container .tier-container legend { margin-left: auto; margin-right: auto; + font-size: 22px; + font-weight: bold; + padding: 0 12px; } .daggerheart.levelup .tiers-container .tier-container .checkbox-group-container { display: grid; - grid-template-columns: 3fr 1fr; + grid-template-columns: 1fr 2.3fr; gap: 4px; } .daggerheart.levelup .tiers-container .tier-container .checkbox-group-container .checkboxes-container { display: flex; gap: 4px; + justify-content: end; +} +.daggerheart.levelup .tiers-container .tier-container .checkbox-group-container .checkbox-group-label { + font-size: 14px; + font-style: italic; +} +.daggerheart.levelup .levelup-footer { + display: flex; } .application.sheet.daggerheart.dh-style.feature .item-sheet-header { display: flex; diff --git a/styles/levelup.less b/styles/levelup.less index 0d3e07db..9da3cf21 100644 --- a/styles/levelup.less +++ b/styles/levelup.less @@ -13,14 +13,22 @@ gap: 8px; background-image: url('../assets/parchments/dh-parchment-dark.png'); + &.inactive { + opacity: 0.4; + pointer-events: none; + } + legend { margin-left: auto; margin-right: auto; + font-size: 22px; + font-weight: bold; + padding: 0 12px; } .checkbox-group-container { display: grid; - grid-template-columns: 3fr 1fr; + grid-template-columns: 1fr 2.3fr; gap: 4px; .checkbox-group-container-title { @@ -29,8 +37,18 @@ .checkboxes-container { display: flex; gap: 4px; + justify-content: end; + } + + .checkbox-group-label { + font-size: 14px; + font-style: italic; } } } } + + .levelup-footer { + display: flex; + } } diff --git a/templates/sheets/pc/pc.hbs b/templates/sheets/pc/pc.hbs index 2505ad5f..a2eff2e4 100644 --- a/templates/sheets/pc/pc.hbs +++ b/templates/sheets/pc/pc.hbs @@ -43,8 +43,8 @@
- - {{#if document.system.canLevelUp}}
*
{{/if}} + + {{#if document.system.levelData.canLevelUp}}
*
{{/if}}
{{localize "DAGGERHEART.Sheets.PC.Level"}}
diff --git a/templates/views/levelup.hbs b/templates/views/levelup.hbs index 72394612..59899409 100644 --- a/templates/views/levelup.hbs +++ b/templates/views/levelup.hbs @@ -1,22 +1,25 @@
{{#each this.levelup.tiers as |tier key|}} -
+
{{tier.name}} {{#each tier.tierCheckboxGroups}}
- {{this.label}} -
+
{{#each this.checkboxes}} - + {{/each}}
+
{{this.label}}
{{/each}}
{{/each}}
+
+ +
{{!--