diff --git a/lang/en.json b/lang/en.json index e5163d42..c7feb674 100755 --- a/lang/en.json +++ b/lang/en.json @@ -167,6 +167,10 @@ "backgroundTitle": "Background", "characteristics": "Characteristics", "connectionsTitle": "Connections" + }, + "experienceDataRemoveConfirmation": { + "title": "Remove Experience Data", + "text": "The experience you are about to remove has levelup data linked to it (assumably because you did levelups with the 'levelupAuto' automation setting on). Removing it will remove this automation data aswell. Do you want to proceed?" } }, "Companion": { @@ -1859,6 +1863,7 @@ "levelUp": "Level Up", "loadout": "Loadout", "max": "Max", + "maxWithThing": "Max {thing}", "multiclass": "Multiclass", "newCategory": "New Category", "none": "None", diff --git a/module/applications/sheets-configs/_module.mjs b/module/applications/sheets-configs/_module.mjs index 49cc74b0..ed062163 100644 --- a/module/applications/sheets-configs/_module.mjs +++ b/module/applications/sheets-configs/_module.mjs @@ -1,4 +1,5 @@ export { default as ActionConfig } from './action-config.mjs'; +export { default as CharacterSettings } from './character-settings.mjs'; export { default as AdversarySettings } from './adversary-settings.mjs'; export { default as CompanionSettings } from './companion-settings.mjs'; export { default as DowntimeConfig } from './downtimeConfig.mjs'; diff --git a/module/applications/sheets-configs/character-settings.mjs b/module/applications/sheets-configs/character-settings.mjs index 13ef29c3..75c4e6b9 100644 --- a/module/applications/sheets-configs/character-settings.mjs +++ b/module/applications/sheets-configs/character-settings.mjs @@ -7,7 +7,10 @@ export default class DHCharacterSettings extends DHBaseActorSettings { static DEFAULT_OPTIONS = { classes: ['character-settings'], position: { width: 455, height: 'auto' }, - actions: {}, + actions: { + addExperience: DHCharacterSettings.#addExperience, + removeExperience: DHCharacterSettings.#removeExperience + }, dragDrop: [ { dragSelector: null, dropSelector: '.tab.features' }, { dragSelector: '.feature-item', dropSelector: null } @@ -18,33 +21,111 @@ export default class DHCharacterSettings extends DHBaseActorSettings { static PARTS = { header: { id: 'header', - template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/header.hbs' + template: 'systems/daggerheart/templates/sheets-settings/character-settings/header.hbs' }, tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, details: { id: 'details', - template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/details.hbs' - }, - attack: { - id: 'attack', - template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/attack.hbs' + template: 'systems/daggerheart/templates/sheets-settings/character-settings/details.hbs' }, experiences: { id: 'experiences', - template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/experiences.hbs' - }, - features: { - id: 'features', - template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/features.hbs' + template: 'systems/daggerheart/templates/sheets-settings/character-settings/experiences.hbs' } }; /** @override */ static TABS = { primary: { - tabs: [{ id: 'details' }, { id: 'attack' }, { id: 'experiences' }, { id: 'features' }], + tabs: [{ id: 'details' }, { id: 'experiences' }], initial: 'details', labelPrefix: 'DAGGERHEART.GENERAL.Tabs' } }; + + /**@inheritdoc */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + context.levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; + + return context; + } + + /* -------------------------------------------- */ + + /** + * Adds a new experience entry to the actor. + * @type {ApplicationClickAction} + */ + static async #addExperience() { + const newExperience = { + name: 'Experience', + modifier: 0 + }; + await this.actor.update({ [`system.experiences.${foundry.utils.randomID()}`]: newExperience }); + } + + /** + * Removes an experience entry from the actor. + * @type {ApplicationClickAction} + */ + static async #removeExperience(_, target) { + const experience = this.actor.system.experiences[target.dataset.experience]; + const updates = {}; + + const relinkData = Object.keys(this.actor.system.levelData.levelups).reduce((acc, key) => { + const level = this.actor.system.levelData.levelups[key]; + const selectionIndex = level.selections.findIndex( + x => x.optionKey === 'experience' && x.data[0] === target.dataset.experience + ); + if (selectionIndex !== -1) + acc.push({ levelKey: key, selectionIndex, experience: target.dataset.experience }); + + return acc; + }, []); + + if (relinkData.length > 0) { + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.localize('DAGGERHEART.ACTORS.Character.experienceDataRemoveConfirmation.title') + }, + content: game.i18n.localize('DAGGERHEART.ACTORS.Character.experienceDataRemoveConfirmation.text') + }); + if (!confirmed) return; + + relinkData.forEach(data => { + updates[`system.levelData.levelups.${data.levelKey}.selections`] = this.actor.system.levelData.levelups[ + data.levelKey + ].selections.reduce((acc, selection, index) => { + if ( + index === data.selectionIndex && + selection.optionKey === 'experience' && + selection.data.includes(data.experience) + ) { + acc.push({ ...selection, data: selection.data.filter(x => x !== data.experience) }); + } else { + acc.push(selection); + } + + return acc; + }, []); + }); + } else { + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', { + type: game.i18n.localize(`DAGGERHEART.GENERAL.Experience.single`), + name: experience.name + }) + }, + content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: experience.name }) + }); + if (!confirmed) return; + } + + await this.actor.update({ + ...updates, + [`system.experiences.-=${target.dataset.experience}`]: null + }); + } } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index e00ec843..1ef50b84 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -25,7 +25,6 @@ export default class CharacterSheet extends DHBaseActorSheet { toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleResourceDice: CharacterSheet.#toggleResourceDice, handleResourceDice: CharacterSheet.#handleResourceDice, - openConfig: CharacterSheet.#openConfig, useDowntime: this.useDowntime }, window: { @@ -717,20 +716,14 @@ export default class CharacterSheet extends DHBaseActorSheet { }); } - /** - * Open the character config sheet. - * @type {ApplicationClickAction} - */ - static async #openConfig() {} - /** * Open the downtime application. * @type {ApplicationClickAction} */ static useDowntime(_, button) { - new game.system.api.applications.dialogs.Downtime(this.document, button.dataset.type === 'shortRest').render( - true - ); + new game.system.api.applications.dialogs.Downtime(this.document, button.dataset.type === 'shortRest').render({ + force: true + }); } async _onDragStart(event) { diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 08455dd3..c67fc91d 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -87,7 +87,8 @@ export default class DhpAdversary extends BaseDataActor { experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField(), - value: new fields.NumberField({ required: true, integer: true, initial: 1 }) + value: new fields.NumberField({ required: true, integer: true, initial: 1 }), + description: new fields.StringField() }) ), bonuses: new fields.SchemaField({ diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index e39f4ae5..0c554855 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -4,6 +4,7 @@ import DhLevelData from '../levelData.mjs'; import BaseDataActor from './base.mjs'; import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs'; import { ActionField } from '../fields/actionField.mjs'; +import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs'; export default class DhCharacter extends BaseDataActor { static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character']; @@ -12,6 +13,7 @@ export default class DhCharacter extends BaseDataActor { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Actor.character', type: 'character', + settingSheet: DHCharacterSettings, isNPC: false }); } @@ -56,7 +58,8 @@ export default class DhCharacter extends BaseDataActor { experiences: new fields.TypedObjectField( new fields.SchemaField({ name: new fields.StringField(), - value: new fields.NumberField({ integer: true, initial: 0 }) + value: new fields.NumberField({ integer: true, initial: 0 }), + description: new fields.StringField() }) ), gold: new fields.SchemaField({ @@ -538,9 +541,9 @@ export default class DhCharacter extends BaseDataActor { this.proficiency += selection.value; break; case 'experience': - Object.keys(this.experiences).forEach(key => { - const experience = this.experiences[key]; - experience.value += selection.value; + selection.data.forEach(id => { + const experience = this.experiences[id]; + if (experience) experience.value += selection.value; }); break; } @@ -568,7 +571,7 @@ export default class DhCharacter extends BaseDataActor { this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait; this.resources.armor = { - value: this.armor.system.marks.value, + value: this.armor?.system?.marks?.value ?? 0, max: this.armorScore, isReversed: true }; diff --git a/module/data/fields/actorField.mjs b/module/data/fields/actorField.mjs index 5fde9394..743adb91 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -9,7 +9,11 @@ const attributeField = label => const resourceField = (max = 0, label, reverse = false) => new fields.SchemaField({ value: new fields.NumberField({ initial: 0, min: 0, integer: true, label }), - max: new fields.NumberField({ initial: max, integer: true }), + max: new fields.NumberField({ + initial: max, + integer: true, + label: game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) }) + }), isReversed: new fields.BooleanField({ initial: reverse }) }); diff --git a/styles/less/sheets-settings/adversary-settings/experiences.less b/styles/less/sheets-settings/adversary-settings/experiences.less index 05595ed4..438a9d67 100644 --- a/styles/less/sheets-settings/adversary-settings/experiences.less +++ b/styles/less/sheets-settings/adversary-settings/experiences.less @@ -9,21 +9,30 @@ margin-bottom: 12px; } - .experience-list { + .experience-item { display: flex; flex-direction: column; - gap: 10px; + gap: 5px; - .experience-item { + .experience-inner-item { display: grid; grid-template-columns: 3fr 1fr 30px; align-items: center; gap: 5px; + &.no-controls { + grid-template-columns: 3fr 1fr; + } + a { text-align: center; } } + + textarea { + width: 100%; + resize: none; + } } } } diff --git a/styles/less/sheets-settings/character-settings/sheet.less b/styles/less/sheets-settings/character-settings/sheet.less new file mode 100644 index 00000000..b563f2f4 --- /dev/null +++ b/styles/less/sheets-settings/character-settings/sheet.less @@ -0,0 +1,36 @@ +.application.daggerheart.dh-style.dialog { + .tab.details { + .traits-inner-container { + width: 100%; + display: flex; + align-items: center; + justify-content: space-evenly; + gap: 8px; + + .trait-container { + width: 60px; + height: 60px; + background: url(../assets/svg/trait-shield.svg) no-repeat; + display: flex; + flex-direction: column; + align-items: center; + + div { + filter: drop-shadow(0 0 3px black); + text-shadow: 0 0 3px black; + font-family: @font-body; + font-size: 12px; + } + + input { + text-align: center; + width: 32px; + height: 24px; + position: relative; + top: 2px; + padding: 0; + } + } + } + } +} diff --git a/styles/less/sheets-settings/index.less b/styles/less/sheets-settings/index.less index e7818326..f575f848 100644 --- a/styles/less/sheets-settings/index.less +++ b/styles/less/sheets-settings/index.less @@ -2,6 +2,7 @@ @import './adversary-settings/sheet.less'; @import './adversary-settings/experiences.less'; @import './adversary-settings/features.less'; +@import './character-settings/sheet.less'; @import './environment-settings/features.less'; @import './environment-settings/adversaries.less'; diff --git a/templates/sheets-settings/adversary-settings/experiences.hbs b/templates/sheets-settings/adversary-settings/experiences.hbs index 72d2a3c4..942fb238 100644 --- a/templates/sheets-settings/adversary-settings/experiences.hbs +++ b/templates/sheets-settings/adversary-settings/experiences.hbs @@ -12,9 +12,13 @@
diff --git a/templates/sheets-settings/character-settings/details.hbs b/templates/sheets-settings/character-settings/details.hbs new file mode 100644 index 00000000..b6bf53dc --- /dev/null +++ b/templates/sheets-settings/character-settings/details.hbs @@ -0,0 +1,34 @@ +