diff --git a/module/applications/sheets-configs/action-base-config.mjs b/module/applications/sheets-configs/action-base-config.mjs index 46e75ba7..920cb6d0 100644 --- a/module/applications/sheets-configs/action-base-config.mjs +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -159,7 +159,8 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) context.tabs = this._getTabs(this.constructor.TABS); context.config = CONFIG.DH; if (this.action.damage) { - context.allDamageTypesUsed = !this.#getUnusedDamageTypes().length; + const allKeys = Object.keys(CONFIG.DH.GENERAL.healingTypes); + context.allDamageTypesUsed = allKeys.every(k => k in this.action._source.damage.resources); if (this.action.damage?.main?.hasOwnProperty('includeBase') && this.action.type === 'attack') context.hasBaseDamage = !!this.action.parent.attack; } @@ -232,23 +233,6 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) return filtered; } - /** - * Gets unused resource types of the damage field - * @returns {{ value: string; label: string }[]} - */ - #getUnusedDamageTypes() { - const usedKeys = Object.keys(this.action._source.damage.resources); - return Object.keys(CONFIG.DH.GENERAL.healingTypes).reduce((acc, key) => { - if (!usedKeys.includes(key)) - acc.push({ - value: key, - label: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[key].label) - }); - - return acc; - }, []); - } - _prepareSubmitData(_event, formData) { const submitData = foundry.utils.expandObject(formData.object); @@ -317,6 +301,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } + /** @this DHActionBaseConfig */ static #onAddDamage() { if (!this.action.damage || this.action.damage?.main) return; @@ -329,6 +314,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } + /** @this DHActionBaseConfig */ static #onRemoveDamage() { if (!this.action.damage?.main) return; const data = this.action.toObject(); @@ -340,50 +326,46 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) static #onAddDamageResource(_event) { if (!this.action.damage) return; - const choices = this.#getUnusedDamageTypes(); + const allKeys = Object.keys(CONFIG.DH.GENERAL.healingTypes); + const unused = allKeys.filter(k => !(k in this.action._source.damage.resources)); + const choices = unused.map(k => ({ value: k, label: _loc(CONFIG.DH.GENERAL.healingTypes[k].label) })); const content = new foundry.data.fields.StringField({ - label: game.i18n.localize('Damage Type'), + label: _loc('DAGGERHEART.GENERAL.damageType'), choices, required: true - }).toFormGroup( - {}, - { - name: 'type', - localize: true, - nameAttr: 'value', - labelAttr: 'label' - } - ).outerHTML; + }).toFormGroup({}, { + name: 'type', + localize: true, + nameAttr: 'value', + labelAttr: 'label' + }).outerHTML; const callback = (_, button) => { const data = this.action.toObject(); const type = choices[button.form.elements.type.value].value; - const part = this.action.schema.fields.damage.fields.resources.element.getInitialValue(); - part.applyTo = type; - if (type === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) - part.type = this.action.schema.fields.damage.fields.resources.element.fields.type.element.initial; - - data.damage.resources[type] = part; + data.damage.resources[type] = { + ...this.action.schema.fields.damage.fields.resources.element.getInitialValue(), + applyTo: type + }; this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); }; const typeDialog = new foundry.applications.api.DialogV2({ buttons: [ - foundry.utils.mergeObject( - { - action: 'ok', - label: 'Confirm', - icon: 'fas fa-check', - default: true - }, - { callback: callback } - ) + { + action: 'ok', + label: 'Confirm', + icon: 'fas fa-check', + default: true, + callback + } ], content: content, rejectClose: false, modal: false, window: { - title: game.i18n.localize('Add Damage') + /** @todo localize */ + title: 'Add Damage' }, position: { width: 300 } }); @@ -391,6 +373,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) typeDialog.render(true); } + /** @this DHActionBaseConfig */ static #onRemoveDamageResource(_event, button) { if (!this.action.damage?.resources) return; const data = this.action.toObject(); diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index ff3f3039..c5f036ed 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -1,3 +1,4 @@ +import { DHDamageData } from '../../data/fields/action/damageField.mjs'; import DHBaseActorSettings from '../sheets/api/actor-setting.mjs'; /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ @@ -8,8 +9,10 @@ export default class DHAdversarySettings extends DHBaseActorSettings { classes: ['adversary-settings'], position: { width: 455, height: 'auto' }, actions: { - addExperience: DHAdversarySettings.#addExperience, - removeExperience: DHAdversarySettings.#removeExperience + addExperience: DHAdversarySettings.#onAddExperience, + removeExperience: DHAdversarySettings.#onRemoveExperience, + addDamage: this.#onAddDamage, + removeDamage: this.#onRemoveDamage } }; @@ -71,7 +74,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { * Adds a new experience entry to the actor. * @type {ApplicationClickAction} */ - static async #addExperience() { + static async #onAddExperience() { const newExperience = { name: 'Experience', modifier: 0 @@ -83,7 +86,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { * Removes an experience entry from the actor. * @type {ApplicationClickAction} */ - static async #removeExperience(_, target) { + static async #onRemoveExperience(_, target) { const experience = this.actor.system.experiences[target.dataset.experience]; const confirmed = await foundry.applications.api.DialogV2.confirm({ window: { @@ -98,4 +101,28 @@ export default class DHAdversarySettings extends DHBaseActorSettings { await this.actor.update({ [`system.experiences.${target.dataset.experience}`]: _del }); } + + /** + * @this DHAdversarySettings + * @type {ApplicationClickAction} + */ + static #onAddDamage() { + this.actor.update({ + 'system.attack.damage.main': { + ...DHDamageData.schema.getInitialValue(), + applyTo: 'hitPoints', + type: 'physical' + } + }); + } + + /** + * @this DHAdversarySettings + * @type {ApplicationClickAction} + */ + static #onRemoveDamage() { + this.actor.update({ + 'system.attack.damage.main': null + }); + } } diff --git a/module/data/action/attackAction.mjs b/module/data/action/attackAction.mjs index a931f040..6c205de6 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -82,7 +82,7 @@ export default class DHAttackAction extends DHDamageAction { x: game.i18n.localize('DAGGERHEART.GENERAL.damage') }); - const icons = Array.from(type) + const icons = Array.from(type ?? []) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) .filter(Boolean); diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 4a272b76..499b16c0 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -232,7 +232,7 @@ export default class DHWeapon extends AttachableItem { const parts = value.custom.enabled ? [game.i18n.localize('DAGGERHEART.GENERAL.custom')] : [value.dice]; if (!value.custom.enabled && value.bonus) parts.push(value.bonus.signedString()); - if (type.size > 0) { + if (type?.size) { const typeTags = Array.from(type) .map(t => game.i18n.localize(`DAGGERHEART.CONFIG.DamageType.${t}.abbreviation`)) .join(' | '); @@ -259,7 +259,7 @@ export default class DHWeapon extends AttachableItem { for (const { value, type } of [damage.main, ...damage.resources].filter(d => !!d)) { const str = Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {}); - const icons = Array.from(type) + const icons = Array.from(type ?? []) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) .filter(Boolean); diff --git a/templates/actionTypes/damage.hbs b/templates/actionTypes/damage.hbs index 88786850..f315f8a1 100644 --- a/templates/actionTypes/damage.hbs +++ b/templates/actionTypes/damage.hbs @@ -24,47 +24,53 @@ {{formField baseFields.main.fields.groupAttack value=source.main.groupAttack name=(concat path "damage.main.groupAttack") localize=true classes="select"}} {{/if}} - {{> damageData data=source.main fields=fields.main.fields basePath=(concat path "damage.main")}} + {{> damageData damage=source.main fields=fields.main.fields basePath=(concat path "damage.main")}} + {{#if horde}} + {{> hordeDamage source=source.main fields=fields.main.fields basePath=(concat path "damage.main")}} + {{/if}} {{#if (ne @root.source.type 'healing')}} {{formField fields.main.fields.type value=source.main.type name=(concat path "damage.main.type") localize=true}} {{/if}} {{/if}} -
+{{#unless (eq path 'system.attack.')}} + {{! In the future, consider allowing this even on NPCs}} +