diff --git a/module/applications/dialogs/damageDialog.mjs b/module/applications/dialogs/damageDialog.mjs index 8b37cf2d..46d3d41f 100644 --- a/module/applications/dialogs/damageDialog.mjs +++ b/module/applications/dialogs/damageDialog.mjs @@ -51,11 +51,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application const context = await super._prepareContext(_options); context.config = CONFIG.DH; context.title = this.config.title ?? this.title; - - const { damageFormula, resourceFormulas } = this.roll.constructFormulas(this.config); - context.damageFormula = damageFormula; - context.resourceFormulas = resourceFormulas; - + context.formula = this.roll.constructFormula(this.config); context.hasHealing = this.config.hasHealing; context.directDamage = this.config.directDamage; context.selectedMessageMode = this.config.selectedMessageMode; @@ -77,8 +73,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application static updateRollConfiguration(_event, _, formData) { const data = foundry.utils.expandObject(formData.object); - foundry.utils.mergeObject(this.config.damageFormula, data.damageFormula); - foundry.utils.mergeObject(this.config.resourceFormulas, data.resourceFormulas); + foundry.utils.mergeObject(this.config.roll, data.roll); foundry.utils.mergeObject(this.config.modifiers, data.modifiers); this.config.selectedMessageMode = data.selectedMessageMode; diff --git a/module/applications/sheets-configs/action-base-config.mjs b/module/applications/sheets-configs/action-base-config.mjs index 920cb6d0..b65e1cdf 100644 --- a/module/applications/sheets-configs/action-base-config.mjs +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -1,4 +1,4 @@ -import { DHDamageData } from '../../data/fields/action/damageField.mjs'; +import { getUnusedDamageTypes } from '../../helpers/utils.mjs'; import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; const { ApplicationV2 } = foundry.applications.api; @@ -31,10 +31,8 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) removeElement: this.removeElement, removeTransformActor: this.removeTransformActor, editEffect: this.editEffect, - addDamage: this.#onAddDamage, - removeDamage: this.#onRemoveDamage, - addDamageResource: this.#onAddDamageResource, - removeDamageResource: this.#onRemoveDamageResource, + addDamage: this.addDamage, + removeDamage: this.removeDamage, editDoc: this.editDoc, addTrigger: this.addTrigger, removeTrigger: this.removeTrigger, @@ -159,9 +157,9 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) context.tabs = this._getTabs(this.constructor.TABS); context.config = CONFIG.DH; if (this.action.damage) { - 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.allDamageTypesUsed = !getUnusedDamageTypes(this.action.damage.parts).length; + + if (this.action.damage.hasOwnProperty('includeBase') && this.action.type === 'attack') context.hasBaseDamage = !!this.action.parent.attack; } @@ -301,71 +299,53 @@ 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; + static addDamage(_event) { + if (!this.action.damage.parts) return; - const data = this.action.toObject(); - data.damage.main = { - ...DHDamageData.schema.getInitialValue(), - applyTo: 'hitPoints', - type: 'physical' - }; - 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(); - data.damage.main = null; - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - /** @this DHActionBaseConfig */ - static #onAddDamageResource(_event) { - if (!this.action.damage) return; - - 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 choices = getUnusedDamageTypes(this.action._source.damage.parts); const content = new foundry.data.fields.StringField({ - label: _loc('DAGGERHEART.GENERAL.damageType'), + label: game.i18n.localize('Damage Type'), 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; - data.damage.resources[type] = { - ...this.action.schema.fields.damage.fields.resources.element.getInitialValue(), - applyTo: type - }; + const part = this.action.schema.fields.damage.fields.parts.element.getInitialValue(); + part.applyTo = type; + if (type === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) + part.type = this.action.schema.fields.damage.fields.parts.element.fields.type.element.initial; + + data.damage.parts[type] = part; this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); }; const typeDialog = new foundry.applications.api.DialogV2({ buttons: [ - { - action: 'ok', - label: 'Confirm', - icon: 'fas fa-check', - default: true, - callback - } + foundry.utils.mergeObject( + { + action: 'ok', + label: 'Confirm', + icon: 'fas fa-check', + default: true + }, + { callback: callback } + ) ], content: content, rejectClose: false, modal: false, window: { - /** @todo localize */ - title: 'Add Damage' + title: game.i18n.localize('Add Damage') }, position: { width: 300 } }); @@ -373,12 +353,12 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) typeDialog.render(true); } - /** @this DHActionBaseConfig */ - static #onRemoveDamageResource(_event, button) { - if (!this.action.damage?.resources) return; + static removeDamage(_event, button) { + if (!this.action.damage.parts) return; const data = this.action.toObject(); const key = button.dataset.key; - data.damage.resources[key] = _del; + delete data.damage.parts[key]; + data.damage.parts[`${key}`] = _del; this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); } diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs index c5f036ed..ff3f3039 100644 --- a/module/applications/sheets-configs/adversary-settings.mjs +++ b/module/applications/sheets-configs/adversary-settings.mjs @@ -1,4 +1,3 @@ -import { DHDamageData } from '../../data/fields/action/damageField.mjs'; import DHBaseActorSettings from '../sheets/api/actor-setting.mjs'; /**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */ @@ -9,10 +8,8 @@ export default class DHAdversarySettings extends DHBaseActorSettings { classes: ['adversary-settings'], position: { width: 455, height: 'auto' }, actions: { - addExperience: DHAdversarySettings.#onAddExperience, - removeExperience: DHAdversarySettings.#onRemoveExperience, - addDamage: this.#onAddDamage, - removeDamage: this.#onRemoveDamage + addExperience: DHAdversarySettings.#addExperience, + removeExperience: DHAdversarySettings.#removeExperience } }; @@ -74,7 +71,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { * Adds a new experience entry to the actor. * @type {ApplicationClickAction} */ - static async #onAddExperience() { + static async #addExperience() { const newExperience = { name: 'Experience', modifier: 0 @@ -86,7 +83,7 @@ export default class DHAdversarySettings extends DHBaseActorSettings { * Removes an experience entry from the actor. * @type {ApplicationClickAction} */ - static async #onRemoveExperience(_, target) { + static async #removeExperience(_, target) { const experience = this.actor.system.experiences[target.dataset.experience]; const confirmed = await foundry.applications.api.DialogV2.confirm({ window: { @@ -101,28 +98,4 @@ 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 6c205de6..1988b1d8 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -73,7 +73,7 @@ export default class DHAttackAction extends DHDamageAction { if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`)); const useAltDamage = this.actor?.effects?.find(x => x.type === 'horde')?.active; - for (const { value, valueAlt, type } of [damage.main, ...damage.resources].filter(d => !!d)) { + for (const { value, valueAlt, type } of damage.parts) { const usedValue = useAltDamage ? valueAlt : value; const damageString = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); const str = damageString @@ -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/action/baseAction.mjs b/module/data/action/baseAction.mjs index f773ae32..944d373b 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -429,11 +429,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel } get hasDamage() { - return this.type !== 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length); + return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type !== 'healing'; } get hasHealing() { - return this.type === 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length); + return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type === 'healing'; } get hasSave() { @@ -470,11 +470,10 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel }, {}); } - if (source.damage?.parts && !source.damage.resources && !source.damage.main) { - source.damage.main = null; + if (source.damage && source.damage.resources === undefined) { source.damage.resources = {}; for (const [partKey, part] of Object.entries(source.damage.parts)) { - if (partKey === 'hitPoints' && source.type !== 'healing') { + if (partKey === 'hitPoints') { source.damage.main = { ...part, includeBase: source.damage.includeBase, @@ -485,8 +484,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel source.damage.resources[partKey] = part; } } - - delete source.damage.parts; } } } diff --git a/module/data/action/damageAction.mjs b/module/data/action/damageAction.mjs index 15135e0d..51735543 100644 --- a/module/data/action/damageAction.mjs +++ b/module/data/action/damageAction.mjs @@ -8,8 +8,11 @@ export default class DHDamageAction extends DHBaseAction { * @returns Formula string */ getDamageFormula() { - if (!this.damage.main) return ''; + const strings = []; + for (const { value } of this.damage.parts) { + strings.push(Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {})); + } - return Roll.replaceFormulaData(this.damage.main.value.getFormula(), this.actor?.getRollData() ?? {}); + return strings.join(' + '); } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 2640211f..ae17c128 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -84,11 +84,13 @@ export default class DhpAdversary extends DhCreature { type: 'attack' }, damage: { - main: { - type: ['physical'], - applyTo: 'hitPoints', - value: { - multiplier: 'flat' + parts: { + hitPoints: { + type: ['physical'], + applyTo: 'hitPoints', + value: { + multiplier: 'flat' + } } } } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 8ff50a5d..53581e79 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -104,13 +104,15 @@ export default class DhCharacter extends DhCreature { trait: 'strength' }, damage: { - main: { - type: ['physical'], - applyTo: 'hitPoints', - value: { - custom: { - enabled: true, - formula: '@profd4' + parts: { + hitPoints: { + type: ['physical'], + applyTo: 'hitPoints', + value: { + custom: { + enabled: true, + formula: '@profd4' + } } } } diff --git a/module/data/chat-message/actorRoll.mjs b/module/data/chat-message/actorRoll.mjs index 2d578a0f..0b5d2678 100644 --- a/module/data/chat-message/actorRoll.mjs +++ b/module/data/chat-message/actorRoll.mjs @@ -188,28 +188,19 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { } static migrateData(source) { - if (source.hasDamage && !source.damage.resources === undefined) { - const getRoll = key => { - const damageData = source.damage[key]; - const oldRoll = damageData.parts[0]?.roll; - return oldRoll ? { - ...oldRoll, - options: { - ...oldRoll.options, - damageTypes: damageData.parts[0].damageTypes ?? [] - } - } : null; - }; - + if (source.hasDamage && !source.damage.types) { source.damage = { - main: source.damage.hitPoints ? getRoll('hitPoints') : null, - resources: Object.keys(source.damage).reduce((acc, key) => { - if (key === 'hitPoints') return acc; + types: Object.keys(source.damage).reduce((acc, key) => { + const damageData = source.damage[key]; + const oldRoll = damageData.parts[0]?.roll; + acc[key] = oldRoll ? { + ...oldRoll, + options: { + ...oldRoll.options, + damageTypes: damageData.parts[0].damageTypes ?? [] + } + } : null; - const roll = getRoll(key); - if (!roll) return acc; - - acc[key] = roll; return acc; }, {}) }; diff --git a/module/data/chat-message/chatDamageData.mjs b/module/data/chat-message/chatDamageData.mjs index c612729e..0de9ea9e 100644 --- a/module/data/chat-message/chatDamageData.mjs +++ b/module/data/chat-message/chatDamageData.mjs @@ -11,29 +11,27 @@ export class ChatDamageData extends foundry.abstract.DataModel { const fields = foundry.data.fields; return { - main: new fields.JSONField({ nullable: true, validate: ChatDamageData.#validateRoll}), + damage: new fields.JSONField({validate: ChatDamageData.#validateRoll}), resources: new fields.TypedObjectField(new fields.JSONField({validate: ChatDamageData.#validateRoll})) }; } get active() { - return !!this.main || Boolean(Object.keys(this.resources).length); + return Boolean(Object.keys(this.types).length); } static #validateRoll(rollJSON) { - if (rollJSON) { - const roll = JSON.parse(rollJSON); - if (!roll.evaluated) throw new Error('Roll objects added to ChatMessage documents must be evaluated'); - } + const roll = JSON.parse(rollJSON); + if (!roll.evaluated) throw new Error('Roll objects added to ChatMessage documents must be evaluated'); } _prepareRolls() { - if (this.main) { - this.main = Roll.fromData(this.main); - } - - for (const key of Object.keys(this.resources)) { - this.resources[key] = Roll.fromData(this.resources[key]); + for (const key of Object.keys(this.types)) { + const type = this.types[key]; + try { + this.types[key] = Roll.fromData(type); + this.types[key].options.modifierTotal = CONFIG.Dice.daggerheart.DHRoll.calculateTotalModifiers(type); + } catch {} } } diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 9f382b59..72933c60 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -12,10 +12,11 @@ export default class DamageField extends fields.SchemaField { /** @inheritDoc */ constructor(options, context = {}) { - super({ - main: new fields.EmbeddedDataField(DHDamageData, { nullable: true }), + const damageFields = { + main: new fields.EmbeddedDataField(DHDamageData), resources: new IterableTypedObjectField(DHResourceData) - }, options, context); + }; + super(damageFields, options, context); } /** @@ -31,23 +32,25 @@ export default class DamageField extends fields.SchemaField { this.hasRoll && DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id && !force - ) { + ) return; - } - const damageFormula = this.damage.main ? - DamageField.formatFormulas.call(this, [this.damage.main], config)[0] : null; - const resourceFormulas = DamageField.formatFormulas.call(this, this.damage.resources, config); + let formulas = this.damage.parts.map(p => ({ + formula: DamageField.getFormulaValue.call(this, p, config).getFormula(this.actor), + damageTypes: p.applyTo === 'hitPoints' && !p.type.size ? new Set(['physical']) : p.type, + applyTo: p.applyTo + })); - if (!damageFormula && !resourceFormulas.length) return false; + if (!formulas.length) return false; + + formulas = DamageField.formatFormulas.call(this, formulas, config); messageId = config.message?._id ?? messageId; const message = game.messages.get(messageId); const damageConfig = { dialog: {}, ...config, - damageFormula, - resourceFormulas, + roll: formulas, data: this.getRollData(), isCritical: Boolean(message?.system.roll?.isCritical) }; @@ -80,7 +83,7 @@ export default class DamageField extends fields.SchemaField { const targetDamage = []; const damagePromises = []; - for (const target of targets) { + for (let target of targets) { const actor = foundry.utils.fromUuidSync(target.actorId); if (!actor) continue; if (!config.hasHealing && config.onSave && target.saved?.success === true) { @@ -102,12 +105,14 @@ export default class DamageField extends fields.SchemaField { actor.takeHealing(config.damage.types).then(updates => targetDamage.push({ token, updates })) ); else { - const configDamage = config.damage.clone(); - configDamage.main &&= configDamage.main.toJSON(); - if (configDamage.main) { - const multiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1; - const takenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier; - configDamage.main.total = Math.ceil(configDamage.main.total * multiplier * takenMultiplier); + const configDamage = foundry.utils.deepClone(config.damage.types); + const hpDamageMultiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1; + const hpDamageTakenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier; + if (configDamage.hitPoints) { + configDamage.hitPoints = configDamage.hitPoints.toJSON(); + configDamage.hitPoints.total = Math.ceil( + configDamage.hitPoints.total * hpDamageMultiplier * hpDamageTakenMultiplier + ); } damagePromises.push( @@ -170,17 +175,11 @@ export default class DamageField extends fields.SchemaField { /** * Prepare formulas for Damage Roll * Must be called within Action context or similar. - * @param {DHResourceData[]} damageData Array of DHResourceData + * @param {object[]} formulas Array of formatted formulas object * @param {object} data Action getRollData * @returns */ - static formatFormulas(damageData, data) { - const formulas = damageData.map(x => ({ - formula: DamageField.getFormulaValue.call(this, x, data).getFormula(this.actor), - damageTypes: x.applyTo === 'hitPoints' && !x.type.size ? new Set(['physical']) : x.type, - applyTo: x.applyTo - })); - + static formatFormulas(formulas, data) { const formattedFormulas = []; formulas.forEach(formula => { if (isNaN(formula.formula)) @@ -191,7 +190,6 @@ export default class DamageField extends fields.SchemaField { if (same) same.formula += ` + ${formula.formula}`; else formattedFormulas.push(formula); }); - return formattedFormulas; } @@ -281,6 +279,17 @@ export class DHResourceData extends foundry.abstract.DataModel { static defineSchema() { return { base: new fields.BooleanField({ initial: false, readonly: true, label: 'Base' }), + type: new fields.SetField( + new fields.StringField({ + choices: CONFIG.DH.GENERAL.damageTypes, + initial: 'physical', + nullable: false, + required: true + }), + { + label: game.i18n.localize('DAGGERHEART.GENERAL.type') + } + ), applyTo: new fields.StringField({ choices: CONFIG.DH.GENERAL.healingTypes, required: true, @@ -312,18 +321,7 @@ export class DHDamageData extends DHResourceData { choices: CONFIG.DH.GENERAL.groupAttackRange, blank: true, label: 'DAGGERHEART.ACTIONS.Settings.groupAttack.label' - }), - type: new fields.SetField( - new fields.StringField({ - choices: CONFIG.DH.GENERAL.damageTypes, - initial: 'physical', - nullable: false, - required: true - }), - { - label: game.i18n.localize('DAGGERHEART.GENERAL.type') - } - ) + }) }; } } diff --git a/module/data/item/weapon.mjs b/module/data/item/weapon.mjs index 499b16c0..42326f93 100644 --- a/module/data/item/weapon.mjs +++ b/module/data/item/weapon.mjs @@ -67,11 +67,13 @@ export default class DHWeapon extends AttachableItem { type: 'attack' }, damage: { - main: { - type: ['physical'], - value: { - multiplier: 'prof', - dice: 'd8' + parts: { + hitPoints: { + type: ['physical'], + value: { + multiplier: 'prof', + dice: 'd8' + } } } } @@ -228,11 +230,11 @@ export default class DHWeapon extends AttachableItem { game.i18n.localize(`DAGGERHEART.CONFIG.Burden.${burden}`) ]; - for (const { value, type } of [attack.damage.main, ...attack.damage.resources]) { + for (const { value, type } of attack.damage.parts) { 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) { + if (type.size > 0) { const typeTags = Array.from(type) .map(t => game.i18n.localize(`DAGGERHEART.CONFIG.DamageType.${t}.abbreviation`)) .join(' | '); @@ -256,10 +258,10 @@ export default class DHWeapon extends AttachableItem { if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`)); if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`)); - for (const { value, type } of [damage.main, ...damage.resources].filter(d => !!d)) { + for (const { value, type } of damage.parts) { 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/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 64077e1f..8667d89f 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -13,27 +13,16 @@ export default class DamageRoll extends DHRoll { static DefaultDialog = DamageDialog; - static createRollInstance(config) { - return new this(undefined, config.data, config); - } - /** @inheritdoc */ static async buildEvaluate(roll, config = {}) { - if (config.dialog.configure === false) roll.constructFormulas(config); + if (config.dialog.configure === false) roll.constructFormula(config); - const evaluateRoll = async roll => { + for (const roll of config.roll) { await roll.roll.evaluate(); roll.roll.options = { damageTypes: roll.damageTypes ? [...roll.damageTypes] : [] }; - return roll.roll; - } - config.damage.main = await evaluateRoll(config.damageFormula); - config.damage.main.options = { damageTypes: - config.damageFormula.damageTypes ? [...config.damageFormula.damageTypes] : [] - }; - - for (const roll of config.resourceFormulas) { - config.damage.resources[roll.applyTo] = await evaluateRoll(roll); + if (!config.damage?.types) config.damage = { types: {} }; + config.damage.types[roll.applyTo] = roll.roll; } roll._evaluated = true; @@ -62,8 +51,7 @@ export default class DamageRoll extends DHRoll { if (config.source?.message) { chatMessage.update({ 'system.damage': { ...config.damage.toObject(), - main: config.damage.main, - resources: config.damage.resources + types: config.damage.types }}); } } @@ -137,72 +125,62 @@ export default class DamageRoll extends DHRoll { return changeKeys; } - constructFormulas(config) { - return { - damageFormula: this.constructFormula(this.options.damageFormula, config, true), - resourceFormulas: this.options.resourceFormulas.map(x => this.constructFormula(x, config)) - }; - } - - constructFormula(formulaData, config, isDamage) { + constructFormula(config) { this.options.isCritical = config.isCritical; - - const isHitpointPart = formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id; - formulaData.roll = new Roll(Roll.replaceFormulaData(formulaData.formula, config.data)); - formulaData.roll.terms = Roll.parse(formulaData.roll.formula, config.data); - if (formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - formulaData.modifiers = this.applyBaseBonus(formulaData); - this.addModifiers(formulaData); - formulaData.modifiers?.forEach(m => { - formulaData.roll.terms.push(...this.formatModifier(m.value)); - }); - } - - /* To Remove When Reaction System */ - if (isDamage && formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - for (const mod in config.modifiers) { - const modifier = config.modifiers[mod]; - if ( - modifier.beforeCrit === true && - (modifier.enabled || modifier.value) - ) modifier.callback(formulaData); + for (const [index, part] of this.options.roll.entries()) { + const isHitpointPart = part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id; + part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data)); + part.roll.terms = Roll.parse(part.roll.formula, config.data); + if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + part.modifiers = this.applyBaseBonus(part); + this.addModifiers(part); + part.modifiers?.forEach(m => { + part.roll.terms.push(...this.formatModifier(m.value)); + }); } - } - if (formulaData.extraFormula) { - formulaData.roll.terms.push( - new foundry.dice.terms.OperatorTerm({ operator: '+' }), - ...this.constructor.parse(formulaData.extraFormula, this.options.data) - ); - } - - if (config.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) { - const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm]; - for (const term of formulaData.roll.terms) { - if (damageTypes.some(type => term instanceof type)) { - term.number *= config.damageOptions.groupAttack.numAttackers; + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (modifier.beforeCrit === true && (modifier.enabled || modifier.value)) modifier.callback(part); } } - } - if (config.isCritical && isHitpointPart) { - const total = formulaData.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0); - if (total > 0) { - formulaData.roll.terms.push(...this.formatModifier(total)); + if (part.extraFormula) { + part.roll.terms.push( + new foundry.dice.terms.OperatorTerm({ operator: '+' }), + ...this.constructor.parse(part.extraFormula, this.options.data) + ); } - } - /* To Remove When Reaction System */ - if (isDamage && formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { - for (const mod in config.modifiers) { - const modifier = config.modifiers[mod]; - if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(formulaData); + if (config.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) { + const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm]; + for (const term of part.roll.terms) { + if (damageTypes.some(type => term instanceof type)) { + term.number *= config.damageOptions.groupAttack.numAttackers; + } + } } - } - formulaData.roll._formula = this.constructor.getFormula(formulaData.roll.terms); - - return formulaData; + if (config.isCritical && isHitpointPart) { + const total = part.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0); + if (total > 0) { + part.roll.terms.push(...this.formatModifier(total)); + } + } + + /* To Remove When Reaction System */ + if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) { + for (const mod in config.modifiers) { + const modifier = config.modifiers[mod]; + if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(part); + } + } + + part.roll._formula = this.constructor.getFormula(part.roll.terms); + } + return this.options.roll; } /* To Remove When Reaction System */ diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index c78caa4f..13408329 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -41,10 +41,6 @@ export default class DHRoll extends BaseRoll { return config; } - static createRollInstance(config) { - return new this(config.roll.formula, config.data, config); - } - /** * @param {Partial} config * @returns {Promise} @@ -62,7 +58,7 @@ export default class DHRoll extends BaseRoll { this.temporaryModifierBuilder(config); - let roll = this.createRollInstance(config); + let roll = new this(config.roll.formula, config.data, config); if (config.dialog.configure !== false) { // Open Roll Dialog const DialogClass = config.dialog?.class ?? this.DefaultDialog; diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 5048abef..d7733dd5 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -656,66 +656,62 @@ export default class DhpActor extends Actor { return; } - if (damages.main) { - damages.main.total = this.calculateDamage(damages.main.total, damages.main.damageTypes); - } + const updates = []; + + Object.entries(damages).forEach(([key, damage]) => { + if (key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) + damage.total = this.calculateDamage(damage.total, damage.damageTypes); + const update = updates.find(u => u.key === key); + if (update) { + update.value += damage.total; + update.damageTypes.add(...new Set(damage.damageTypes)); + } else updates.push({ value: damage.total, key, damageTypes: new Set(damage.damageTypes) }); + }); if (Hooks.call(`${CONFIG.DH.id}.postCalculateDamage`, this, damages) === false) return null; - // Convert deducted resources and damage to a record of updates, merging damage to hp with hp marked - const updates = []; - for (const [key, damage] of Object.entries(damages.resources)) { - updates.push({ key, value: damage.total }); - } - if (damages.main) { - const existing = updates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); - const value = this.convertDamageToThreshold(damages.main.total) + (existing?.value ?? 0); - const damageTypes = new Set(damages.main.options.damageTypes); - if (existing) { - existing.value = value; - existing.damageTypes = damageTypes; - } else { - updates.push({ value, damageTypes, key: CONFIG.DH.GENERAL.healingTypes.hitPoints.id }); - } - } - if (!updates.some(u => u.value !== 0)) return; // early return if nothing to do + if (!updates.length) return; const hpDamage = updates.find(u => u.key === CONFIG.DH.GENERAL.healingTypes.hitPoints.id); - if (hpDamage && this.type === 'character' && !isDirect && this.#canReduceDamage(hpDamage.total, hpDamage.damageTypes)) { - const armorSlotResult = await this.owner.query( - 'armorSlot', - { - actorId: this.uuid, - damage: hpDamage.value, - type: [...hpDamage.damageTypes] - }, - { - timeout: 30000 - } - ); - if (armorSlotResult) { - const { modifiedDamage, armorChanges, stressSpent } = armorSlotResult; - hpDamage.value = modifiedDamage; - for (const armorChange of armorChanges) { - updates.push({ value: armorChange.amount, key: 'armor', uuid: armorChange.uuid }); - } - if (stressSpent) { - const stressUpdate = updates.find(u => u.key === 'stress'); - if (stressUpdate) stressUpdate.value += stressSpent; - else updates.push({ value: stressSpent, key: 'stress' }); + if (hpDamage?.value) { + hpDamage.value = this.convertDamageToThreshold(hpDamage.value); + if (this.type === 'character' && !isDirect && this.#canReduceDamage(hpDamage.value, hpDamage.damageTypes)) { + const armorSlotResult = await this.owner.query( + 'armorSlot', + { + actorId: this.uuid, + damage: hpDamage.value, + type: [...hpDamage.damageTypes] + }, + { + timeout: 30000 + } + ); + if (armorSlotResult) { + const { modifiedDamage, armorChanges, stressSpent } = armorSlotResult; + updates.find(u => u.key === 'hitPoints').value = modifiedDamage; + for (const armorChange of armorChanges) { + updates.push({ value: armorChange.amount, key: 'armor', uuid: armorChange.uuid }); + } + if (stressSpent) { + const stressUpdate = updates.find(u => u.key === 'stress'); + if (stressUpdate) stressUpdate.value += stressSpent; + else updates.push({ value: stressSpent, key: 'stress' }); + } } } - } else if (hpDamage && this.type === 'adversary') { - const reducedSeverity = hpDamage.damageTypes.reduce((value, curr) => { - return Math.max(this.system.rules.damageReduction.reduceSeverity[curr], value); - }, 0); - hpDamage.value = Math.max(hpDamage.value - reducedSeverity, 0); + if (this.type === 'adversary') { + const reducedSeverity = hpDamage.damageTypes.reduce((value, curr) => { + return Math.max(this.system.rules.damageReduction.reduceSeverity[curr], value); + }, 0); + hpDamage.value = Math.max(hpDamage.value - reducedSeverity, 0); - if ( - hpDamage.value && - this.system.rules.damageReduction.thresholdImmunities[getDamageKey(hpDamage.value)] - ) { - hpDamage.value -= 1; + if ( + hpDamage.value && + this.system.rules.damageReduction.thresholdImmunities[getDamageKey(hpDamage.value)] + ) { + hpDamage.value -= 1; + } } } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index f600eae6..84bcacf2 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -700,6 +700,19 @@ export async function RefreshFeatures( return refreshedActors; } +export function getUnusedDamageTypes(parts) { + const usedKeys = Object.keys(parts); + 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; + }, []); +} + /** Returns resolved armor sources ordered by application order */ export function getArmorSources(actor) { const rawArmorSources = Array.from(actor.allApplicableEffects()).filter(x => x.system.armorData); diff --git a/templates/actionTypes/damage.hbs b/templates/actionTypes/damage.hbs index df8a71b1..03300840 100644 --- a/templates/actionTypes/damage.hbs +++ b/templates/actionTypes/damage.hbs @@ -1,114 +1,92 @@ -{{#unless (eq @root.source.type 'healing')}} -
- + +
+ + {{#if (eq @root.source.type 'healing')}} + {{localize "DAGGERHEART.GENERAL.healing"}} + {{else}} {{localize "DAGGERHEART.GENERAL.damage"}} - {{#if source.main}} - - {{else}} - - {{/if}} - - - {{#if source.main}} -
- {{#if @root.hasBaseDamage}} - {{formField @root.fields.damage.fields.main.fields.includeBase value=@root.source.damage.includeBase name="damage.main.includeBase" classes="checkbox" localize=true }} - {{/if}} - {{#unless (eq @root.source.type 'healing')}} - {{formField baseFields.main.fields.direct value=source.main.direct name=(concat path "damage.main.direct") localize=true classes="checkbox"}} - {{/unless}} - {{#if (and @root.isNPC (not (eq path 'system.attack.')))}} - {{formField baseFields.main.fields.groupAttack value=source.main.groupAttack name=(concat path "damage.main.groupAttack") localize=true classes="select"}} - {{/if}} -
- {{> 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}} + {{#unless (eq path 'system.attack.')}}{{/unless}} +
+
+ {{#if @root.hasBaseDamage}} + {{formField @root.fields.damage.fields.includeBase value=@root.source.damage.includeBase name="damage.includeBase" classes="checkbox" localize=true }} + {{/if}} + {{#unless (eq @root.source.type 'healing')}} + {{formField baseFields.direct value=source.direct name=(concat path "damage.direct") localize=true classes="checkbox"}} + {{/unless}} + {{#if (and @root.isNPC (not (eq path 'system.attack.')))}} + {{formField baseFields.groupAttack value=source.groupAttack name=(concat path "damage.groupAttack") localize=true classes="select"}} + {{/if}} +
-{{#unless (eq path 'system.attack.')}} - {{! In the future, consider allowing this even on NPCs}} -
- - {{#if (eq @root.source.type 'healing')}} - {{localize "DAGGERHEART.GENERAL.healing"}} - {{else}} - {{localize "DAGGERHEART.GENERAL.Resource.plural"}} - {{/if}} - {{#unless @root.allDamageTypesUsed}}{{/unless}} - - {{#each source.resources as |dmg key|}} -
- - - {{localize (concat "DAGGERHEART.CONFIG.HealingType." dmg.applyTo ".name")}} - {{#unless (or dmg.base ../path)}} - - {{/unless}} - - {{> damageData damage=dmg fields=../fields.resources.element.fields basePath=(concat ../path "damage.resources." dmg.applyTo)}} -
- - {{/each}} -
-{{/unless}} + {{!-- Handlebars uses Symbol.Iterator to produce index|key. This isn't compatible with our parts object, so we instead use applyTo, which is the same value --}} + {{#each source.parts as |dmg key|}} +
+ + + {{localize (concat "DAGGERHEART.CONFIG.HealingType." dmg.applyTo ".name")}} + {{#unless (or dmg.base ../path)}} + + {{/unless}} + + + {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base))}} + {{formField ../fields.resultBased value=dmg.resultBased name=(concat "damage.parts." dmg.applyTo ".resultBased") localize=true classes="checkbox"}} + {{/if}} + {{#if (and (not @root.isNPC) @root.hasRoll (not dmg.base) dmg.resultBased)}} +
+
+ {{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}} + {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}} +
+
+ {{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}} + {{> formula fields=../fields.valueAlt.fields type=../fields.type dmg=dmg source=dmg.valueAlt target="valueAlt" key=dmg.applyTo path=../path}} +
+
+ {{else}} + {{> formula fields=../fields.value.fields type=../fields.type dmg=dmg source=dmg.value target="value" key=dmg.applyTo path=../path}} + {{/if}} + + {{#if (and (eq dmg.applyTo 'hitPoints') (ne @root.source.type 'healing'))}} + {{formField ../fields.type value=dmg.type name=(concat ../path "damage.parts." dmg.applyTo ".type") localize=true}} + {{/if}} + + {{#if ../horde}} +
+ {{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}} +
+ + {{formField ../fields.valueAlt.fields.flatMultiplier value=dmg.valueAlt.flatMultiplier name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} + {{formField ../fields.valueAlt.fields.dice value=dmg.valueAlt.dice name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.dice") classes="inline-child" localize=true}} + {{formField ../fields.valueAlt.fields.bonus value=dmg.valueAlt.bonus name=(concat ../path "damage.parts." dmg.applyTo ".valueAlt.bonus") localize=true classes="inline-child"}} +
+
+ {{/if}} + + +
+ {{/each}} + {{#*inline "formula"}} - {{#unless isBase}} - {{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat basePath ".custom.enabled") classes="checkbox" localize=true}} - {{/unless}} - {{#if source.custom.enabled}} - {{formField fields.custom.fields.formula value=source.custom.formula name=(concat basePath ".custom.formula") localize=true}} - {{else}} -
- {{#unless @root.isNPC}} - {{formField fields.multiplier value=source.multiplier name=(concat basePath ".multiplier") localize=true}} - {{/unless}} - {{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat basePath ".flatMultiplier") localize=true }}{{/if}} - {{formField fields.dice value=source.dice name=(concat basePath ".dice") localize=true}} - {{formField fields.bonus value=source.bonus name=(concat basePath ".bonus") localize=true}} -
- {{/if}} - {{#if @root.isNPC}} - - {{/if}} -{{/inline}} - -{{#*inline "damageData"}} - {{#if (and (not @root.isNPC) @root.hasRoll (not damage.base))}} - {{formField fields.resultBased value=damage.resultBased name=(concat basePath ".resultBased") localize=true classes="checkbox"}} - {{/if}} - {{#if (and (not @root.isNPC) @root.hasRoll (not damage.base) damage.resultBased)}} -
-
- {{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.hope")}} - {{> formula key=damage.applyTo fields=fields.value.fields type=fields.type isBase=damage.base source=damage.value basePath=(concat basePath ".value")}} -
-
- {{localize "DAGGERHEART.GENERAL.withThing" thing=(localize "DAGGERHEART.GENERAL.fear")}} - {{> formula key=damage.applyTo fields=fields.valueAlt.fields type=fields.type isBase=damage.base source=damage.valueAlt basePath=(concat basePath ".valueAlt")}} -
-
- {{else}} - {{> formula key=damage.applyTo fields=fields.value.fields type=fields.type isBase=damage.base source=damage.value basePath=(concat basePath ".value")}} - {{/if}} - -{{/inline}} - -{{#*inline "hordeDamage"}} -
- {{localize "DAGGERHEART.ACTORS.Adversary.hordeDamage"}} -
- - {{formField fields.valueAlt.fields.flatMultiplier value=source.valueAlt.flatMultiplier name=(concat basePath ".valueAlt.flatMultiplier") label="DAGGERHEART.ACTIONS.Settings.multiplier" classes="inline-child" localize=true }} - {{formField fields.valueAlt.fields.dice value=source.valueAlt.dice name=(concat basePath ".valueAlt.dice") classes="inline-child" localize=true}} - {{formField fields.valueAlt.fields.bonus value=source.valueAlt.bonus name=(concat basePath ".valueAlt.bonus") localize=true classes="inline-child"}} -
-
+ {{#unless dmg.base}} + {{formField fields.custom.fields.enabled value=source.custom.enabled name=(concat path "damage.parts." key "." target ".custom.enabled") classes="checkbox" localize=true}} + {{/unless}} + {{#if source.custom.enabled}} + {{formField fields.custom.fields.formula value=source.custom.formula name=(concat path "damage.parts." key "." target ".custom.formula") localize=true}} + {{else}} +
+ {{#unless @root.isNPC}} + {{formField fields.multiplier value=source.multiplier name=(concat path "damage.parts." key "." target ".multiplier") localize=true}} + {{/unless}} + {{#if (eq source.multiplier 'flat')}}{{formField fields.flatMultiplier value=source.flatMultiplier name=(concat path "damage.parts." key "." target ".flatMultiplier") localize=true }}{{/if}} + {{formField fields.dice value=source.dice name=(concat path "damage.parts." key "." target ".dice") localize=true}} + {{formField fields.bonus value=source.bonus name=(concat path "damage.parts." key "." target ".bonus") localize=true}} +
+ {{/if}} + {{#if @root.isNPC}} + + {{/if}} {{/inline}} \ No newline at end of file diff --git a/templates/dialogs/dice-roll/damageSelection.hbs b/templates/dialogs/dice-roll/damageSelection.hbs index cc12e26f..7bcd7063 100644 --- a/templates/dialogs/dice-roll/damageSelection.hbs +++ b/templates/dialogs/dice-roll/damageSelection.hbs @@ -16,10 +16,31 @@ {{/if}} - {{> formula @root.damageFormula path="damageFormula"}} - - {{#each @root.resourceFormulas}} - {{> formula path=(concat "resourceFormulas." @key)}} + {{#each @root.formula}} +
+ {{localize "DAGGERHEART.GENERAL.formula"}}: {{roll.formula}} + + {{#with (lookup @root.config.GENERAL.healingTypes applyTo)}} + {{localize label}} + {{/with}} + {{#unless @root.hasHealing}} + {{#if damageTypes}} + {{#each damageTypes as | type | }} + {{#with (lookup @root.config.GENERAL.damageTypes type)}} + + {{/with}} + {{/each}} + {{/if}} + {{/unless}} + +
+
+ + +
{{/each}} {{#if damageOptions.groupAttack}} @@ -66,31 +87,4 @@ {{localize "DAGGERHEART.GENERAL.roll"}} - - -{{#*inline "formula"}} -
- {{localize "DAGGERHEART.GENERAL.formula"}}: {{roll.formula}} - - {{#with (lookup @root.config.GENERAL.healingTypes applyTo)}} - {{localize label}} - {{/with}} - {{#unless @root.hasHealing}} - {{#if damageTypes}} - {{#each damageTypes as | type | }} - {{#with (lookup @root.config.GENERAL.damageTypes type)}} - - {{/with}} - {{/each}} - {{/if}} - {{/unless}} - -
-
- - -
-{{/inline}} \ No newline at end of file + \ No newline at end of file diff --git a/templates/sheets-settings/action-settings/effect.hbs b/templates/sheets-settings/action-settings/effect.hbs index 67017a5a..567cb81c 100644 --- a/templates/sheets-settings/action-settings/effect.hbs +++ b/templates/sheets-settings/action-settings/effect.hbs @@ -5,7 +5,7 @@ > {{#if fields.roll}}{{> 'systems/daggerheart/templates/actionTypes/roll.hbs' fields=fields.roll.fields source=source.roll}}{{/if}} {{#if fields.save}}{{> 'systems/daggerheart/templates/actionTypes/save.hbs' fields=fields.save.fields source=source.save}}{{/if}} - {{#if fields.damage}}{{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=fields.damage.fields source=source.damage baseFields=fields.damage.fields }}{{/if}} + {{#if fields.damage}}{{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=fields.damage.fields.parts.element.fields source=source.damage baseFields=fields.damage.fields }}{{/if}} {{#if fields.macro}}{{> 'systems/daggerheart/templates/actionTypes/macro.hbs' fields=fields.macro source=source.macro}}{{/if}} {{#if fields.effects}}{{> 'systems/daggerheart/templates/actionTypes/effect.hbs' fields=fields.effects.element.fields source=source.effects}}{{/if}} {{#if fields.beastform}}{{> 'systems/daggerheart/templates/actionTypes/beastform.hbs' fields=fields.beastform.fields source=source.beastform}}{{/if}} diff --git a/templates/sheets-settings/adversary-settings/attack.hbs b/templates/sheets-settings/adversary-settings/attack.hbs index f81f0477..41960032 100644 --- a/templates/sheets-settings/adversary-settings/attack.hbs +++ b/templates/sheets-settings/adversary-settings/attack.hbs @@ -22,5 +22,5 @@ {{formGroup systemFields.criticalThreshold value=document._source.system.criticalThreshold label="DAGGERHEART.ACTIONS.Settings.criticalThreshold" name="system.criticalThreshold" localize=true}} - {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields source=document.system.attack.damage path="system.attack." baseFields=systemFields.attack.fields.damage.fields horde=(eq document._source.system.type 'horde')}} + {{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack." baseFields=systemFields.attack.fields.damage.fields horde=(eq document._source.system.type 'horde')}} \ No newline at end of file