diff --git a/lang/en.json b/lang/en.json index 8096036c81..1046518012 100644 --- a/lang/en.json +++ b/lang/en.json @@ -2306,6 +2306,10 @@ "label": "Additional Items", "hint": "These additional items will be added to the creature when one of its items is enchanted, and will be removed if the enchantment is ever removed." } + }, + "static": { + "label": "Static", + "hint": "Prevent this enchantment from being removed via the item context menu." } }, "enchant": { diff --git a/module/applications/components/inventory.mjs b/module/applications/components/inventory.mjs index bfe44a249d..58f6a438b6 100644 --- a/module/applications/components/inventory.mjs +++ b/module/applications/components/inventory.mjs @@ -375,9 +375,16 @@ export default class InventoryElement extends (foundry.applications.elements.Ado }, { label: "DND5E.ConcentrationBreak", icon: '', - group: "state", + group: "destructive", visible: () => this.actor?.concentration?.items.has(item), onClick: () => this.actor?.endConcentration(item) + }, { + label: "DND5E.ENCHANTMENT.Action.Remove", + icon: '', + group: "destructive", + visible: () => item.isOwner && !compendiumLocked + && item.effects.some(e => e.isAppliedEnchantment && !e.getFlag("dnd5e", "static")), + onClick: (event, target) => this._onAction(target, "removeEnchantment", { event }) }, { label: `DND5E.ContextMenuAction${item.system.attuned ? "Unattune" : "Attune"}`, icon: '', @@ -479,6 +486,7 @@ export default class InventoryElement extends (foundry.applications.elements.Ado case "identify": return this._onToggleIdentify(item); case "prepare": return this._onTogglePrepared(item); case "recharge": return this._onRollRecharge(activity ?? item, { event }); + case "removeEnchantment": return this._onRemoveEnchantment(item); case "toggleCharge": return this._onToggleCharge(item); case "toggleExpand": return this._onToggleExpand(target, { item }); case "toggleFavorite": return this._onToggleFavorite(item); @@ -630,6 +638,21 @@ export default class InventoryElement extends (foundry.applications.elements.Ado /* -------------------------------------------- */ + /** + * Handle removing all applied enchantments from an item. + * @param {Item5e} item The item. + * @returns {Promise} + * @protected + */ + _onRemoveEnchantment(item) { + const ids = item.effects + .filter(e => e.isAppliedEnchantment && !e.getFlag("dnd5e", "static")) + .map(e => e.id); + return item.deleteEmbeddedDocuments("ActiveEffect", ids); + } + + /* -------------------------------------------- */ + /** * Handle recharging an item. * @param {Item5e|Activity} entry The entity being recharged. diff --git a/module/data/activity/enchant-data.mjs b/module/data/activity/enchant-data.mjs index 56649995a6..1f36ee43fa 100644 --- a/module/data/activity/enchant-data.mjs +++ b/module/data/activity/enchant-data.mjs @@ -24,7 +24,8 @@ export default class BaseEnchantActivityData extends BaseActivityData { activity: new SetField(new DocumentIdField()), effect: new SetField(new DocumentIdField()), item: new SetField(new DocumentUUIDField({ type: "Item" })) - }) + }), + static: new BooleanField() })), enchant: new SchemaField({ self: new BooleanField() diff --git a/module/documents/activity/enchant.mjs b/module/documents/activity/enchant.mjs index e13fd45d09..e7e004381a 100644 --- a/module/documents/activity/enchant.mjs +++ b/module/documents/activity/enchant.mjs @@ -172,6 +172,7 @@ export default class EnchantActivity extends ActivityMixin(BaseEnchantActivityDa const flags = { enchantmentProfile: profile }; if ( concentration ) flags.dependentOn = concentration.uuid; + if ( this.effects.find(e => e._id === profile)?.static ) flags.static = true; const enchantmentData = effect.clone({ origin: this.uuid, "flags.dnd5e": flags }).toObject(); /** diff --git a/templates/activity/parts/enchant-enchantments.hbs b/templates/activity/parts/enchant-enchantments.hbs index 948bad98eb..b5cca01147 100644 --- a/templates/activity/parts/enchant-enchantments.hbs +++ b/templates/activity/parts/enchant-enchantments.hbs @@ -61,6 +61,8 @@

{{ localize "DND5E.ENCHANT.FIELDS.effects.element.level.hint" }}

+ {{ formField fields.static name=(concat prefix "static") value=data.static + input=@root.inputs.createCheckboxInput rootId=@root.partId }} {{#with fields.riders.fields as |fields|}} {{ formField fields.activity name=(concat ../prefix "riders.activity") options=../activityOptions rootId=@root.partId }}