diff --git a/module/apps/PlayerSheet.mjs b/module/apps/PlayerSheet.mjs index 4677de3..7ed89fe 100644 --- a/module/apps/PlayerSheet.mjs +++ b/module/apps/PlayerSheet.mjs @@ -37,6 +37,7 @@ export class PlayerSheet extends createEmbeddedItem: this.#createEmbeddedItem, configureSheet: this.#configureSheet, toggleExpand: this.#toggleExpand, + executeTrigger: this.#executeTrigger, }, }; @@ -462,5 +463,16 @@ export class PlayerSheet extends const item = await Item.create(data, { parent: this.actor }); item?.sheet?.render({ force: true }); }; + + /** + * Executes an embedded item's triggering Macro if it has one attached to it. + * + * @this {PlayerSheet} + */ + static async #executeTrigger(event, target) { + const { itemUuid } = target.closest(`[data-item-uuid]`)?.dataset ?? {}; + const item = await fromUuid(itemUuid); + await item?.system.execute?.(); + }; // #endregion Actions }; diff --git a/module/data/Item/attribute.mjs b/module/data/Item/attribute.mjs index 52894d4..0059667 100644 --- a/module/data/Item/attribute.mjs +++ b/module/data/Item/attribute.mjs @@ -5,7 +5,7 @@ import { clamp } from "../../utils/clamp.mjs"; const { getProperty, hasProperty, setProperty } = foundry.utils; export class AttributeItemData extends foundry.abstract.TypeDataModel { - // #region Schema + // MARK: Schema static defineSchema() { const fields = foundry.data.fields; return { @@ -43,7 +43,6 @@ export class AttributeItemData extends foundry.abstract.TypeDataModel { }), }; }; - // #endregion Schema // #region Lifecycle async _preCreate(data, options, user) { @@ -123,5 +122,30 @@ export class AttributeItemData extends foundry.abstract.TypeDataModel { }; return null; }; + + /** + * Executes the macro associated with this item, if the macro cannot be + * found or if the user does not permission to execute it, it will not be + * executed. This also provides some extra context into the roll data for chat + * macros, so that they can refer to the min/value/max properties of this + * specific item without actually needing to know which item called the macro. + */ + async execute() { + const macro = await fromUuid(this.trigger); + if (!macro || !macro.canExecute) { return }; + + // Provide the chat-specific context when required + if (macro.type === `chat`) { + Hooks.once(`taf.getRollData`, (data) => { + data.active = { + min: this.min, + value: this.value, + max: this.max, + }; + }); + }; + + await macro?.execute({ item }); + }; // #endregion Methods }; diff --git a/module/data/Item/generic.mjs b/module/data/Item/generic.mjs index cfd148d..a8f8490 100644 --- a/module/data/Item/generic.mjs +++ b/module/data/Item/generic.mjs @@ -1,6 +1,7 @@ import { toPrecision } from "../../utils/roundToPrecision.mjs"; export class GenericItemData extends foundry.abstract.TypeDataModel { + // MARK: Schema static defineSchema() { const fields = foundry.data.fields; return { @@ -35,6 +36,7 @@ export class GenericItemData extends foundry.abstract.TypeDataModel { }; }; + // #region Methods /** * Calculates the total weight of the item based on the quantity of it, this * rounds the number to the nearest 2 decimal places. @@ -43,4 +45,29 @@ export class GenericItemData extends foundry.abstract.TypeDataModel { const value = this.weight * this.quantity; return toPrecision(Math.max(value, 0), 2); }; + + /** + * Executes the macro associated with this item, if the macro cannot be + * found or if the user does not permission to execute it, it will not be + * executed. This also provides some extra context into the roll data for chat + * macros, so that they can refer to some properties of this specific item + * without actually needing to know which item called the macro. + */ + async execute() { + const macro = await fromUuid(this.trigger); + if (!macro || !macro.canExecute) { return }; + + // Provide the chat-specific context when required + if (macro.type === `chat`) { + Hooks.once(`taf.getRollData`, (data) => { + data.active = { + quantity: this.quantity, + equipped: this.equipped ? 1 : 0, + }; + }); + }; + + await macro?.execute({ item }); + }; + // #endregion Methods }; diff --git a/module/documents/Actor.mjs b/module/documents/Actor.mjs index ac58f4b..7a0f47c 100644 --- a/module/documents/Actor.mjs +++ b/module/documents/Actor.mjs @@ -66,28 +66,12 @@ export class TAFActor extends Actor { // #region Roll Data getRollData() { - /* - All properties assigned during this phase of the roll data prep can potentially - be overridden by users creating attributes of the same key, if users shouldn't - be able to override, assign the property before the return of this function. - */ const data = { carryCapacity: this.system.carryCapacity ?? null, + ...this.system.attr, }; - if (`attr` in this.system) { - for (const attrID in this.system.attr) { - const attr = this.system.attr[attrID]; - if (attr.isRange) { - data[attrID] = { - value: attr.value, - max: attr.max, - }; - } else { - data[attrID] = attr.value; - }; - }; - }; + Hooks.call(`taf.getRollData`, data, this); return data; }; diff --git a/templates/PlayerSheet/primary-attributes.hbs b/templates/PlayerSheet/primary-attributes.hbs index 1545d48..bb3d294 100644 --- a/templates/PlayerSheet/primary-attributes.hbs +++ b/templates/PlayerSheet/primary-attributes.hbs @@ -6,7 +6,16 @@ data-foreign-uuid="{{ attr.uuid }}" > - {{ attr.name }} + {{#if attr.system.trigger}} + + {{else}} + {{ attr.name }} + {{/if}}
{{#if attr.system.isRange }} diff --git a/templates/PlayerSheet/tabs/attributes/attribute.hbs b/templates/PlayerSheet/tabs/attributes/attribute.hbs index 7886b62..ac84637 100644 --- a/templates/PlayerSheet/tabs/attributes/attribute.hbs +++ b/templates/PlayerSheet/tabs/attributes/attribute.hbs @@ -5,6 +5,14 @@
{{ name }}
+ {{#if system.trigger}} + + {{/if}}