diff --git a/module/applications/sheets-configs/_module.mjs b/module/applications/sheets-configs/_module.mjs index a8a625d0..d3fb3c39 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 ActionSettingsConfig } from './action-settings-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'; diff --git a/module/applications/sheets-configs/action-base-config.mjs b/module/applications/sheets-configs/action-base-config.mjs new file mode 100644 index 00000000..70252642 --- /dev/null +++ b/module/applications/sheets-configs/action-base-config.mjs @@ -0,0 +1,236 @@ +import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; + +const { ApplicationV2 } = foundry.applications.api; +export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2) { + constructor(action) { + super({}); + + this.action = action; + this.openSection = null; + } + + get title() { + return `${game.i18n.localize('DAGGERHEART.GENERAL.Tabs.settings')}: ${this.action.name}`; + } + + static DEFAULT_OPTIONS = { + tag: 'form', + classes: ['daggerheart', 'dh-style', 'dialog', 'max-800'], + window: { + icon: 'fa-solid fa-wrench', + resizable: false + }, + position: { width: 600, height: 'auto' }, + actions: { + toggleSection: this.toggleSection, + addEffect: this.addEffect, + removeEffect: this.removeEffect, + addElement: this.addElement, + removeElement: this.removeElement, + editEffect: this.editEffect, + addDamage: this.addDamage, + removeDamage: this.removeDamage + }, + form: { + handler: this.updateForm, + submitOnChange: true, + closeOnSubmit: false + } + }; + + static PARTS = { + header: { + id: 'header', + template: 'systems/daggerheart/templates/sheets-settings/action-settings/header.hbs' + }, + tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, + base: { + id: 'base', + template: 'systems/daggerheart/templates/sheets-settings/action-settings/base.hbs' + }, + configuration: { + id: 'configuration', + template: 'systems/daggerheart/templates/sheets-settings/action-settings/configuration.hbs' + }, + effect: { + id: 'effect', + template: 'systems/daggerheart/templates/sheets-settings/action-settings/effect.hbs' + } + }; + + static TABS = { + base: { + active: true, + cssClass: '', + group: 'primary', + id: 'base', + icon: null, + label: 'DAGGERHEART.GENERAL.Tabs.base' + }, + config: { + active: false, + cssClass: '', + group: 'primary', + id: 'config', + icon: null, + label: 'DAGGERHEART.GENERAL.Tabs.configuration' + }, + effect: { + active: false, + cssClass: '', + group: 'primary', + id: 'effect', + icon: null, + label: 'DAGGERHEART.GENERAL.Tabs.effects' + } + }; + + static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects']; + + _getTabs(tabs) { + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; + v.cssClass = v.active ? 'active' : ''; + } + + return tabs; + } + + async _prepareContext(_options) { + const context = await super._prepareContext(_options, 'action'); + context.source = this.action.toObject(false); + context.openSection = this.openSection; + context.tabs = this._getTabs(this.constructor.TABS); + context.config = CONFIG.DH; + if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') + context.hasBaseDamage = !!this.action.parent.attack; + context.costOptions = this.getCostOptions(); + context.getRollTypeOptions = this.getRollTypeOptions(); + context.disableOption = this.disableOption.bind(this); + context.isNPC = this.action.actor?.isNPC; + context.baseSaveDifficulty = this.action.actor?.baseSaveDifficulty; + context.baseAttackBonus = this.action.actor?.system.attack?.roll.bonus; + context.hasRoll = this.action.hasRoll; + + const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers; + context.tierOptions = [ + { key: 1, label: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') }, + ...Object.values(settingsTiers).map(x => ({ key: x.tier, label: x.name })) + ]; + return context; + } + + static toggleSection(_, button) { + this.openSection = button.dataset.section === this.openSection ? null : button.dataset.section; + this.render(true); + } + + getCostOptions() { + const options = foundry.utils.deepClone(CONFIG.DH.GENERAL.abilityCosts); + const resource = this.action.parent.resource; + if (resource) { + options.resource = { + label: 'DAGGERHEART.GENERAL.itemResource', + group: 'Global' + }; + } + + if (this.action.parent.metadata?.isQuantifiable) { + options.quantity = { + label: 'DAGGERHEART.GENERAL.itemQuantity', + group: 'Global' + }; + } + + return options; + } + + getRollTypeOptions() { + const types = foundry.utils.deepClone(CONFIG.DH.GENERAL.rollTypes); + if (!this.action.actor) return types; + Object.values(types).forEach(t => { + if (this.action.actor.type !== 'character' && t.playerOnly) delete types[t.id]; + }); + return types; + } + + disableOption(index, costOptions, choices) { + const filtered = foundry.utils.deepClone(costOptions); + Object.keys(filtered).forEach(o => { + if (choices.find((c, idx) => c.type === o && index !== idx)) filtered[o].disabled = true; + }); + return filtered; + } + + _prepareSubmitData(_event, formData) { + const submitData = foundry.utils.expandObject(formData.object); + + const itemAbilityCostKeys = Object.keys(CONFIG.DH.GENERAL.itemAbilityCosts); + for (const keyPath of this.constructor.CLEAN_ARRAYS) { + const data = foundry.utils.getProperty(submitData, keyPath); + const dataValues = data ? Object.values(data) : []; + if (keyPath === 'cost') { + for (var value of dataValues) { + value.itemId = itemAbilityCostKeys.includes(value.key) ? this.action.parent.parent.id : null; + } + } + + if (data) foundry.utils.setProperty(submitData, keyPath, dataValues); + } + return submitData; + } + + static async updateForm(event, _, formData) { + const submitData = this._prepareSubmitData(event, formData), + data = foundry.utils.mergeObject(this.action.toObject(), submitData); + this.action = await this.action.update(data); + + this.sheetUpdate?.(this.action); + this.render(); + } + + static addElement(event) { + const data = this.action.toObject(), + key = event.target.closest('[data-key]').dataset.key; + if (!this.action[key]) return; + + data[key].push(this.action.defaultValues[key] ?? {}); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static removeElement(event, button) { + event.stopPropagation(); + const data = this.action.toObject(), + key = event.target.closest('[data-key]').dataset.key, + index = button.dataset.index; + data[key].splice(index, 1); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static addDamage(_event) { + if (!this.action.damage.parts) return; + const data = this.action.toObject(), + part = {}; + if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' }; + data.damage.parts.push(part); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static removeDamage(_event, button) { + if (!this.action.damage.parts) return; + const data = this.action.toObject(), + index = button.dataset.index; + data.damage.parts.splice(index, 1); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + /** Specific implementation in extending classes **/ + static async addEffect(_event) {} + static removeEffect(_event, _button) {} + static editEffect(_event) {} + + async close(options) { + this.tabGroups.primary = 'base'; + await super.close(options); + } +} diff --git a/module/applications/sheets-configs/action-config.mjs b/module/applications/sheets-configs/action-config.mjs index 81ade99b..0dbc377a 100644 --- a/module/applications/sheets-configs/action-config.mjs +++ b/module/applications/sheets-configs/action-config.mjs @@ -1,241 +1,32 @@ -import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs'; - -const { ApplicationV2 } = foundry.applications.api; -export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { - constructor(action, sheetUpdate) { - super({}); - - this.action = action; - this.sheetUpdate = sheetUpdate; - this.openSection = null; - } - - get title() { - return `${game.i18n.localize('DAGGERHEART.GENERAL.Tabs.settings')}: ${this.action.name}`; - } +import DHActionBaseConfig from './action-base-config.mjs'; +export default class DHActionConfig extends DHActionBaseConfig { static DEFAULT_OPTIONS = { - tag: 'form', - classes: ['daggerheart', 'dh-style', 'dialog', 'max-800'], - window: { - icon: 'fa-solid fa-wrench', - resizable: false - }, - position: { width: 600, height: 'auto' }, + ...DHActionBaseConfig.DEFAULT_OPTIONS, actions: { - toggleSection: this.toggleSection, + ...DHActionBaseConfig.DEFAULT_OPTIONS.actions, addEffect: this.addEffect, removeEffect: this.removeEffect, - addElement: this.addElement, - removeElement: this.removeElement, - editEffect: this.editEffect, - addDamage: this.addDamage, - removeDamage: this.removeDamage - }, - form: { - handler: this.updateForm, - submitOnChange: true, - closeOnSubmit: false + editEffect: this.editEffect } }; - static PARTS = { - header: { - id: 'header', - template: 'systems/daggerheart/templates/sheets-settings/action-settings/header.hbs' - }, - tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }, - base: { - id: 'base', - template: 'systems/daggerheart/templates/sheets-settings/action-settings/base.hbs' - }, - configuration: { - id: 'configuration', - template: 'systems/daggerheart/templates/sheets-settings/action-settings/configuration.hbs' - }, - effect: { - id: 'effect', - template: 'systems/daggerheart/templates/sheets-settings/action-settings/effect.hbs' - } - }; - - static TABS = { - base: { - active: true, - cssClass: '', - group: 'primary', - id: 'base', - icon: null, - label: 'DAGGERHEART.GENERAL.Tabs.base' - }, - config: { - active: false, - cssClass: '', - group: 'primary', - id: 'config', - icon: null, - label: 'DAGGERHEART.GENERAL.Tabs.configuration' - }, - effect: { - active: false, - cssClass: '', - group: 'primary', - id: 'effect', - icon: null, - label: 'DAGGERHEART.GENERAL.Tabs.effects' - } - }; - - static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects']; - - _getTabs(tabs) { - for (const v of Object.values(tabs)) { - v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active; - v.cssClass = v.active ? 'active' : ''; - } - - return tabs; - } - - async _prepareContext(_options) { - const context = await super._prepareContext(_options, 'action'); - context.source = this.action.toObject(false); - context.openSection = this.openSection; - context.tabs = this._getTabs(this.constructor.TABS); - context.config = CONFIG.DH; + async _prepareContext(options) { + const context = await super._prepareContext(options); if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id)); - if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack') - context.hasBaseDamage = !!this.action.parent.attack; context.getEffectDetails = this.getEffectDetails.bind(this); - context.costOptions = this.getCostOptions(); - context.getRollTypeOptions = this.getRollTypeOptions(); - context.disableOption = this.disableOption.bind(this); - context.isNPC = this.action.actor?.isNPC; - context.baseSaveDifficulty = this.action.actor?.baseSaveDifficulty; - context.baseAttackBonus = this.action.actor?.system.attack?.roll.bonus; - context.hasRoll = this.action.hasRoll; - const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers; - context.tierOptions = [ - { key: 1, label: game.i18n.localize('DAGGERHEART.GENERAL.Tiers.1') }, - ...Object.values(settingsTiers).map(x => ({ key: x.tier, label: x.name })) - ]; return context; } - static toggleSection(_, button) { - this.openSection = button.dataset.section === this.openSection ? null : button.dataset.section; - this.render(true); - } - - getCostOptions() { - const options = foundry.utils.deepClone(CONFIG.DH.GENERAL.abilityCosts); - const resource = this.action.parent.resource; - if (resource) { - options.resource = { - label: 'DAGGERHEART.GENERAL.itemResource', - group: 'Global' - }; - } - - if (this.action.parent.metadata?.isQuantifiable) { - options.quantity = { - label: 'DAGGERHEART.GENERAL.itemQuantity', - group: 'Global' - }; - } - - return options; - } - - getRollTypeOptions() { - const types = foundry.utils.deepClone(CONFIG.DH.GENERAL.rollTypes); - if (!this.action.actor) return types; - Object.values(types).forEach(t => { - if (this.action.actor.type !== 'character' && t.playerOnly) delete types[t.id]; - }); - return types; - } - - disableOption(index, costOptions, choices) { - const filtered = foundry.utils.deepClone(costOptions); - Object.keys(filtered).forEach(o => { - if (choices.find((c, idx) => c.type === o && index !== idx)) filtered[o].disabled = true; - }); - return filtered; - } - - getEffectDetails(id) { - return this.action.item.effects.get(id); - } - - _prepareSubmitData(_event, formData) { - const submitData = foundry.utils.expandObject(formData.object); - - const itemAbilityCostKeys = Object.keys(CONFIG.DH.GENERAL.itemAbilityCosts); - for (const keyPath of this.constructor.CLEAN_ARRAYS) { - const data = foundry.utils.getProperty(submitData, keyPath); - const dataValues = data ? Object.values(data) : []; - if (keyPath === 'cost') { - for (var value of dataValues) { - value.itemId = itemAbilityCostKeys.includes(value.key) ? this.action.parent.parent.id : null; - } - } - - if (data) foundry.utils.setProperty(submitData, keyPath, dataValues); - } - return submitData; - } - - static async updateForm(event, _, formData) { - const submitData = this._prepareSubmitData(event, formData), - data = foundry.utils.mergeObject(this.action.toObject(), submitData); - this.action = await this.action.update(data); - - this.sheetUpdate?.(this.action); - this.render(); - } - - static addElement(event) { - const data = this.action.toObject(), - key = event.target.closest('[data-key]').dataset.key; - if (!this.action[key]) return; - - data[key].push(this.action.defaultValues[key] ?? {}); - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - static removeElement(event, button) { - event.stopPropagation(); - const data = this.action.toObject(), - key = event.target.closest('[data-key]').dataset.key, - index = button.dataset.index; - data[key].splice(index, 1); - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - static addDamage(event) { - if (!this.action.damage.parts) return; - const data = this.action.toObject(), - part = {}; - if (this.action.actor?.isNPC) part.value = { multiplier: 'flat' }; - data.damage.parts.push(part); - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - static removeDamage(event, button) { - if (!this.action.damage.parts) return; - const data = this.action.toObject(), - index = button.dataset.index; - data.damage.parts.splice(index, 1); - this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); - } - - static async addEffect(event) { + static async addEffect(_event) { if (!this.action.effects) return; - const effectData = this._addEffectData.bind(this)(), - [created] = await this.action.item.createEmbeddedDocuments('ActiveEffect', [effectData], { render: false }), - data = this.action.toObject(); + const effectData = this._addEffectData.bind(this)(); + const data = this.action.toObject(); + + const [created] = await this.action.item.createEmbeddedDocuments('ActiveEffect', [effectData], { + render: false + }); data.effects.push({ _id: created._id }); this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); this.action.item.effects.get(created._id).sheet.render(true); @@ -255,6 +46,10 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { }; } + getEffectDetails(id) { + return this.action.item.effects.get(id); + } + static removeEffect(event, button) { if (!this.action.effects) return; const index = button.dataset.index, @@ -267,9 +62,4 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) { const id = event.target.closest('[data-effect-id]')?.dataset?.effectId; this.action.item.effects.get(id).sheet.render(true); } - - async close(options) { - this.tabGroups.primary = 'base'; - await super.close(options); - } } diff --git a/module/applications/sheets-configs/action-settings-config.mjs b/module/applications/sheets-configs/action-settings-config.mjs new file mode 100644 index 00000000..91b85802 --- /dev/null +++ b/module/applications/sheets-configs/action-settings-config.mjs @@ -0,0 +1,66 @@ +import DHActionBaseConfig from './action-base-config.mjs'; + +export default class DHActionSettingsConfig extends DHActionBaseConfig { + constructor(action, effects, sheetUpdate) { + super(action); + + this.effects = effects; + this.sheetUpdate = sheetUpdate; + } + + static DEFAULT_OPTIONS = { + ...DHActionBaseConfig.DEFAULT_OPTIONS, + actions: { + ...DHActionBaseConfig.DEFAULT_OPTIONS.actions, + addEffect: this.addEffect, + removeEffect: this.removeEffect, + editEffect: this.editEffect + } + }; + + async _prepareContext(options) { + const context = await super._prepareContext(options); + context.effects = this.effects; + context.getEffectDetails = this.getEffectDetails.bind(this); + + return context; + } + + getEffectDetails(id) { + return this.effects.find(x => x.id === id); + } + + static async addEffect(_event) { + if (!this.action.effects) return; + const effectData = game.system.api.data.activeEffects.BaseEffect.getDefaultObject(); + const data = this.action.toObject(); + + this.sheetUpdate(data, effectData); + this.effects = [...this.effects, effectData]; + data.effects.push({ _id: effectData.id }); + this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) }); + } + + static removeEffect(event, button) { + if (!this.action.effects) return; + const index = button.dataset.index, + effectId = this.action.effects[index]._id; + this.constructor.removeElement.bind(this)(event, button); + this.sheetUpdate( + this.action.toObject(), + this.effects.find(x => x.id === effectId), + true + ); + } + + static async editEffect(event) { + const id = event.target.closest('[data-effect-id]')?.dataset?.effectId; + const updatedEffect = await game.system.api.applications.sheetConfigs.SettingActiveEffectConfig.configure( + this.getEffectDetails(id) + ); + if (!updatedEffect) return; + + this.effects = await this.sheetUpdate(this.action.toObject(), { ...updatedEffect, id }); + this.render(); + } +} diff --git a/module/applications/sheets-configs/setting-active-effect-config.mjs b/module/applications/sheets-configs/setting-active-effect-config.mjs index 9b57b47a..ca0d56e3 100644 --- a/module/applications/sheets-configs/setting-active-effect-config.mjs +++ b/module/applications/sheets-configs/setting-active-effect-config.mjs @@ -23,7 +23,7 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi } static DEFAULT_OPTIONS = { - classes: ['daggerheart', 'sheet', 'dh-style', 'active-effect-config'], + classes: ['daggerheart', 'sheet', 'dh-style', 'active-effect-config', 'standard-form'], tag: 'form', position: { width: 560 @@ -131,6 +131,7 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi if (partId in context.tabs) context.tab = context.tabs[partId]; switch (partId) { case 'details': + context.statuses = CONFIG.statusEffects.map(s => ({ value: s.id, label: game.i18n.localize(s.name) })); context.isActorEffect = false; context.isItemEffect = true; const useGeneric = game.settings.get( @@ -138,10 +139,13 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi CONFIG.DH.SETTINGS.gameSettings.appearance ).showGenericStatusEffects; if (!useGeneric) { - context.statuses = Object.values(CONFIG.DH.GENERAL.conditions).map(status => ({ - value: status.id, - label: game.i18n.localize(status.name) - })); + context.statuses = [ + ...context.statuses, + Object.values(CONFIG.DH.GENERAL.conditions).map(status => ({ + value: status.id, + label: game.i18n.localize(status.name) + })) + ]; } break; case 'changes': @@ -157,7 +161,7 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi return context; } - static async #onSubmit(event, form, formData) { + static async #onSubmit(_event, _form, formData) { this.data = foundry.utils.expandObject(formData.object); this.close(); } @@ -193,11 +197,11 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi * @type {ApplicationClickAction} */ static async #addChange() { - const submitData = foundry.utils.expandObject(new FormDataExtended(this.form).object); - const changes = Object.values(submitData.changes ?? {}); - changes.push({}); + const { changes, ...rest } = foundry.utils.expandObject(new FormDataExtended(this.form).object); + const updatedChanges = Object.values(changes ?? {}); + updatedChanges.push({}); - this.effect.changes = changes; + this.effect = { ...rest, changes: updatedChanges }; this.render(); } @@ -208,12 +212,12 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi */ static async #deleteChange(event) { const submitData = foundry.utils.expandObject(new FormDataExtended(this.form).object); - const changes = Object.values(submitData.changes); + const updatedChanges = Object.values(submitData.changes); const row = event.target.closest('li'); const index = Number(row.dataset.index) || 0; - changes.splice(index, 1); + updatedChanges.splice(index, 1); - this.effect.changes = changes; + this.effect = { ...submitData, changes: updatedChanges }; this.render(); } diff --git a/module/applications/sheets-configs/setting-feature-config.mjs b/module/applications/sheets-configs/setting-feature-config.mjs index 920d658e..0f37e548 100644 --- a/module/applications/sheets-configs/setting-feature-config.mjs +++ b/module/applications/sheets-configs/setting-feature-config.mjs @@ -1,5 +1,5 @@ import { actionsTypes } from '../../data/action/_module.mjs'; -import DHActionConfig from './action-config.mjs'; +import ActionSettingsConfig from './action-settings-config.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -158,17 +158,26 @@ export default class SettingFeatureConfig extends HandlebarsApplicationMixin(App this.render(); } else { const action = this.move.actions.get(id); - await new DHActionConfig(action, async (updatedMove, effectData) => { - if (effectData?.length) { + await new ActionSettingsConfig(action, this.move.effects, async (updatedMove, effectData, deleteEffect) => { + let updatedEffects = null; + if (effectData) { const currentEffects = foundry.utils.getProperty(this.settings, `${this.movePath}.effects`); + const existingEffectIndex = currentEffects.findIndex(x => x.id === effectData.id); + + updatedEffects = deleteEffect + ? currentEffects.filter(x => x.id !== effectData.id) + : existingEffectIndex === -1 + ? [...currentEffects, effectData] + : currentEffects.with(existingEffectIndex, effectData); await this.settings.updateSource({ - [`${this.movePath}.effects`]: [...currentEffects, ...effectData] + [`${this.movePath}.effects`]: updatedEffects }); } await this.settings.updateSource({ [`${this.actionsPath}.${id}`]: updatedMove }); this.move = foundry.utils.getProperty(this.settings, this.movePath); this.render(); + return updatedEffects; }).render(true); } } diff --git a/module/config/itemConfig.mjs b/module/config/itemConfig.mjs index 0dd7c587..d4383760 100644 --- a/module/config/itemConfig.mjs +++ b/module/config/itemConfig.mjs @@ -459,7 +459,19 @@ export const allArmorFeatures = () => { ...armorFeatures, ...Object.keys(homebrewFeatures).reduce((acc, key) => { const feature = homebrewFeatures[key]; - acc[key] = { ...feature, label: feature.name }; + const actionEffects = []; + const actions = feature.actions.map(action => { + const effects = action.effects.map(effect => feature.effects.find(x => x.id === effect._id)); + actionEffects.push(...effects); + return { + ...action, + effects: effects, + type: action.type + }; + }); + const effects = feature.effects.filter(effect => !actionEffects.some(x => x.id === effect.id)); + + acc[key] = { ...feature, label: feature.name, effects, actions }; return acc; }, {}) }; @@ -1414,11 +1426,24 @@ export const weaponFeatures = { export const allWeaponFeatures = () => { const homebrewFeatures = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).itemFeatures .weaponFeatures; + return { ...weaponFeatures, ...Object.keys(homebrewFeatures).reduce((acc, key) => { const feature = homebrewFeatures[key]; - acc[key] = { ...feature, label: feature.name }; + const actionEffects = []; + const actions = feature.actions.map(action => { + const effects = action.effects.map(effect => feature.effects.find(x => x.id === effect._id)); + actionEffects.push(...effects); + return { + ...action, + effects: effects, + type: action.type + }; + }); + const effects = feature.effects.filter(effect => !actionEffects.some(x => x.id === effect.id)); + + acc[key] = { ...feature, label: feature.name, effects, actions }; return acc; }, {}) }; diff --git a/templates/sheets/activeEffect/details.hbs b/templates/sheets/activeEffect/details.hbs index 8a862c53..22c95a1e 100644 --- a/templates/sheets/activeEffect/details.hbs +++ b/templates/sheets/activeEffect/details.hbs @@ -4,10 +4,11 @@ {{formGroup fields.disabled value=source.disabled rootId=rootId}} {{#if isActorEffect}} - {{formGroup fields.origin value=source.origin rootId=rootId disabled=true}} + {{formGroup fields.origin value=source.origin rootId=rootId disabled=true}} {{/if}} + {{#if isItemEffect}} - {{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=(localize "DAGGERHEART.EFFECTS.Attachments.transferHint")}} + {{formGroup fields.transfer value=source.transfer rootId=rootId label=legacyTransfer.label hint=(localize "DAGGERHEART.EFFECTS.Attachments.transferHint")}} {{/if}} {{formGroup fields.statuses value=source.statuses options=statuses rootId=rootId classes="statuses"}}