From f657cfc740b3bc88b4d0a57829cea160ff3d1f1c Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 17:27:59 +0200 Subject: [PATCH 1/8] #2288 --- module/applications/actor/character-sheet.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/module/applications/actor/character-sheet.mjs b/module/applications/actor/character-sheet.mjs index 6c6a76da9f..d8498481cc 100644 --- a/module/applications/actor/character-sheet.mjs +++ b/module/applications/actor/character-sheet.mjs @@ -78,10 +78,10 @@ export default class ActorSheet5eCharacter extends ActorSheet5e { ctx.isExpanded = this._expanded.has(item.id); // Item usage - ctx.hasUses = uses && (uses.max > 0); + ctx.hasUses = item.hasLimitedUses; ctx.isOnCooldown = recharge && !!recharge.value && (recharge.charged === false); - ctx.isDepleted = ctx.isOnCooldown && (uses.per && (uses.value > 0)); - ctx.hasTarget = !!target && !(["none", ""].includes(target.type)); + ctx.isDepleted = ctx.isOnCooldown && ctx.hasUses && (uses.value > 0); + ctx.hasTarget = item.hasAreaTarget || item.hasIndividualTarget; // Item toggle state this._prepareItemToggleState(item, ctx); From c40375ad7107beb7803c05460e5995a9b0b8ce5c Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 17:28:38 +0200 Subject: [PATCH 2/8] add isActive getter for item activation --- module/data/item/feat.mjs | 2 +- module/data/item/templates/activated-effect.mjs | 16 ++++++++++++---- module/documents/item.mjs | 10 +++++++++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/module/data/item/feat.mjs b/module/data/item/feat.mjs index cf26241f31..31e2bb025f 100644 --- a/module/data/item/feat.mjs +++ b/module/data/item/feat.mjs @@ -88,6 +88,6 @@ export default class FeatData extends SystemDataModel.mixin( /** @inheritdoc */ get hasLimitedUses() { - return !!this.recharge.value || super.hasLimitedUses; + return this.isActive && (!!this.recharge.value || super.hasLimitedUses); } } diff --git a/module/data/item/templates/activated-effect.mjs b/module/data/item/templates/activated-effect.mjs index 8f80f39f5d..90d0f9a888 100644 --- a/module/data/item/templates/activated-effect.mjs +++ b/module/data/item/templates/activated-effect.mjs @@ -205,12 +205,20 @@ export default class ActivatedEffectTemplate extends foundry.abstract.DataModel /* -------------------------------------------- */ + /** + * Is this Item an activatable item? + * @type {boolean} + */ + get isActive() { + return !!this.activation.type; + } + /** * Does the Item have an area of effect target? * @type {boolean} */ get hasAreaTarget() { - return this.target.type in CONFIG.DND5E.areaTargetTypes; + return this.isActive && (this.target.type in CONFIG.DND5E.areaTargetTypes); } /* -------------------------------------------- */ @@ -220,7 +228,7 @@ export default class ActivatedEffectTemplate extends foundry.abstract.DataModel * @type {boolean} */ get hasIndividualTarget() { - return this.target.type in CONFIG.DND5E.individualTargetTypes; + return this.isActive && (this.target.type in CONFIG.DND5E.individualTargetTypes); } /* -------------------------------------------- */ @@ -230,7 +238,7 @@ export default class ActivatedEffectTemplate extends foundry.abstract.DataModel * @type {boolean} */ get hasLimitedUses() { - return !!this.uses.per && (this.uses.max > 0); + return this.isActive && (!!this.uses.per && (this.uses.max > 0)); } /* -------------------------------------------- */ @@ -270,7 +278,7 @@ export default class ActivatedEffectTemplate extends foundry.abstract.DataModel * @type {boolean} */ get hasTarget() { - return !["", null].includes(this.target.type); + return this.isActive && !["", null].includes(this.target.type); } } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 54925c8ad6..f440cf1e38 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -20,6 +20,14 @@ export default class Item5e extends Item { /* Item Properties */ /* -------------------------------------------- */ + /** + * Is this Item an activatable item? + * @type {boolean} + */ + get isActive() { + return this.system.isActive ?? false; + } + /** * Which ability score modifier is used by this item? * @type {string|null} @@ -784,7 +792,7 @@ export default class Item5e extends Item { consumeResource: !!resource.target && (!item.hasAttack || (resource.type !== "ammo")), consumeSpellLevel: requireSpellSlot ? is.preparation.mode === "pact" ? "pact" : is.level : null, consumeSpellSlot: requireSpellSlot, - consumeUsage: !!is.uses?.per && (is.uses?.max > 0) + consumeUsage: item.isActive && !!is.uses?.per && (is.uses?.max > 0) }, config); // Display a configuration dialog to customize the usage From 51b81cf365cca49dd8e483c0771d8826ceb67925 Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 17:29:26 +0200 Subject: [PATCH 3/8] remove uses from actor sheet if no uses.per set --- templates/actors/parts/actor-spellbook.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/actors/parts/actor-spellbook.hbs b/templates/actors/parts/actor-spellbook.hbs index 735a9e3d0a..5682b9126c 100644 --- a/templates/actors/parts/actor-spellbook.hbs +++ b/templates/actors/parts/actor-spellbook.hbs @@ -74,7 +74,7 @@

{{item.name}}

- {{#if item.system.uses.per }} + {{#if (and item.hasLimitedUses item.system.uses.per) }}
Uses {{item.system.uses.value}} / {{item.system.uses.max}}
{{/if}}
From 5a29d7a9abd6db94e1971ad4e61f2133f5bb816e Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 17:30:16 +0200 Subject: [PATCH 4/8] remove `uses.value` and `uses.max` from item sheet if `uses.per` is not set. Also adds 'None' to the `select`. --- templates/items/parts/item-activation.hbs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/items/parts/item-activation.hbs b/templates/items/parts/item-activation.hbs index d9e9fbd65e..84ce8f0f8b 100644 --- a/templates/items/parts/item-activation.hbs +++ b/templates/items/parts/item-activation.hbs @@ -121,14 +121,16 @@
+ {{#if system.uses.per}} {{localize "DND5E.of"}} {{localize "DND5E.per"}} + {{/if}}
From 2283e147060603268b272a9021e3dde16c4229fd Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 18:32:45 +0200 Subject: [PATCH 5/8] Prevent `consume` from prompting configuration if no activation type or no target or type set --- module/data/item/templates/activated-effect.mjs | 8 ++++++++ module/documents/item.mjs | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/module/data/item/templates/activated-effect.mjs b/module/data/item/templates/activated-effect.mjs index 90d0f9a888..433919f781 100644 --- a/module/data/item/templates/activated-effect.mjs +++ b/module/data/item/templates/activated-effect.mjs @@ -241,6 +241,14 @@ export default class ActivatedEffectTemplate extends foundry.abstract.DataModel return this.isActive && (!!this.uses.per && (this.uses.max > 0)); } + /** + * Does this Item draw from a resource? + * @type {boolean} + */ + get hasResource() { + return this.isActive && this.consume.target && this.consume.type && (!this.hasAttack || (this.consume.type !== "ammo")); + } + /* -------------------------------------------- */ /** diff --git a/module/documents/item.mjs b/module/documents/item.mjs index f440cf1e38..2de743da1d 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -125,6 +125,15 @@ export default class Item5e extends Item { return this.system.hasLimitedUses ?? false; } + /** + * Does this Item draw from a resource? + * @type {boolean} + * @see {@link ActivatedEffectTemplate#hasResource} + */ + get hasResource() { + return this.system.hasResource ?? false; + } + /* -------------------------------------------- */ /** @@ -780,7 +789,6 @@ export default class Item5e extends Item { }, options); // Reference aspects of the item data necessary for usage - const resource = is.consume || {}; // Resource consumption const isSpell = item.type === "spell"; // Does the item require a spell slot? const requireSpellSlot = isSpell && (is.level > 0) && CONFIG.DND5E.spellUpcastModes.includes(is.preparation.mode); @@ -789,7 +797,7 @@ export default class Item5e extends Item { createMeasuredTemplate: item.hasAreaTarget, consumeQuantity: is.uses?.autoDestroy ?? false, consumeRecharge: !!is.recharge?.value, - consumeResource: !!resource.target && (!item.hasAttack || (resource.type !== "ammo")), + consumeResource: item.hasResource, consumeSpellLevel: requireSpellSlot ? is.preparation.mode === "pact" ? "pact" : is.level : null, consumeSpellSlot: requireSpellSlot, consumeUsage: item.isActive && !!is.uses?.per && (is.uses?.max > 0) From 23978eecdafccd496125d341748e751b21af0a2d Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 18:34:11 +0200 Subject: [PATCH 6/8] Remove checkbox from abilityUseDialog when type is not set --- module/applications/item/ability-use-dialog.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/applications/item/ability-use-dialog.mjs b/module/applications/item/ability-use-dialog.mjs index a52c04d70c..7c4ffdcd49 100644 --- a/module/applications/item/ability-use-dialog.mjs +++ b/module/applications/item/ability-use-dialog.mjs @@ -45,7 +45,7 @@ export default class AbilityUseDialog extends Dialog { note: this._getAbilityUseNote(item, uses, recharge), consumeSpellSlot: false, consumeRecharge: recharges, - consumeResource: resource.target && (!item.hasAttack || (resource.type !== "ammo")), + consumeResource: resource.target && resource.type && (!item.hasAttack || (resource.type !== "ammo")), consumeUses: uses.per && (uses.max > 0), canUse: recharges ? recharge.charged : sufficientUses, createTemplate: game.user.can("TEMPLATE_CREATE") && item.hasAreaTarget, From 59deb0127b79779e5d17a560cf270ff8f246d6a0 Mon Sep 17 00:00:00 2001 From: Kenneth B Date: Fri, 26 May 2023 18:49:42 +0200 Subject: [PATCH 7/8] don't show recharge prompt when not active item --- module/documents/item.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 2de743da1d..40777d3771 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -796,7 +796,7 @@ export default class Item5e extends Item { config = foundry.utils.mergeObject({ createMeasuredTemplate: item.hasAreaTarget, consumeQuantity: is.uses?.autoDestroy ?? false, - consumeRecharge: !!is.recharge?.value, + consumeRecharge: is.recharge?.value && item.isActive, consumeResource: item.hasResource, consumeSpellLevel: requireSpellSlot ? is.preparation.mode === "pact" ? "pact" : is.level : null, consumeSpellSlot: requireSpellSlot, From a9e8a5ae402a0319648fb830bb36326813fb92c6 Mon Sep 17 00:00:00 2001 From: Zhell Date: Mon, 16 Oct 2023 09:00:37 +0200 Subject: [PATCH 8/8] clean up target, uses, and range labels on item --- module/data/item/templates/activated-effect.mjs | 5 +++-- module/documents/item.mjs | 11 +++++++---- templates/actors/parts/actor-spellbook.hbs | 6 ++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/module/data/item/templates/activated-effect.mjs b/module/data/item/templates/activated-effect.mjs index d16cfea946..3ed2b4c85e 100644 --- a/module/data/item/templates/activated-effect.mjs +++ b/module/data/item/templates/activated-effect.mjs @@ -243,7 +243,7 @@ export default class ActivatedEffectTemplate extends SystemDataModel { * @type {boolean} */ get hasLimitedUses() { - return this.isActive && (!!this.uses.per && (this.uses.max > 0)); + return this.isActive && (this.uses.per in CONFIG.DND5E.limitedUsePeriods) && (this.uses.max > 0); } /** @@ -251,7 +251,8 @@ export default class ActivatedEffectTemplate extends SystemDataModel { * @type {boolean} */ get hasResource() { - return this.isActive && this.consume.target && this.consume.type && (!this.hasAttack || (this.consume.type !== "ammo")); + const consume = this.consume; + return this.isActive && !!consume.target && !!consume.type && (!this.hasAttack || (consume.type !== "ammo")); } /* -------------------------------------------- */ diff --git a/module/documents/item.mjs b/module/documents/item.mjs index c521bb40cd..6bca1b5be1 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -438,15 +438,18 @@ export default class Item5e extends Item { if ( ["none", ""].includes(tgt.type) ) tgt.type = null; // Backwards compatibility if ( [null, "self"].includes(tgt.type) ) tgt.value = tgt.units = null; else if ( tgt.units === "touch" ) tgt.value = null; - this.labels.target = tgt.type - ? [tgt.value, C.distanceUnits[tgt.units], C.targetTypes[tgt.type]].filterJoin(" ") : ""; + + if ( this.hasTarget ) { + this.labels.target = [tgt.value, C.distanceUnits[tgt.units], C.targetTypes[tgt.type]].filterJoin(" "); + } // Range Label let rng = this.system.range ?? {}; if ( ["none", ""].includes(rng.units) ) rng.units = null; // Backwards compatibility if ( [null, "touch", "self"].includes(rng.units) ) rng.value = rng.long = null; - this.labels.range = rng.units - ? [rng.value, rng.long ? `/ ${rng.long}` : null, C.distanceUnits[rng.units]].filterJoin(" ") : ""; + if ( this.isActive && rng.units ) { + this.labels.range = [rng.value, rng.long ? `/ ${rng.long}` : null, C.distanceUnits[rng.units]].filterJoin(" "); + } else this.labels.range = game.i18n.localize("DND5E.None"); // Recharge Label let chg = this.system.recharge ?? {}; diff --git a/templates/actors/parts/actor-spellbook.hbs b/templates/actors/parts/actor-spellbook.hbs index d641ff14c4..4fad3dc1c0 100644 --- a/templates/actors/parts/actor-spellbook.hbs +++ b/templates/actors/parts/actor-spellbook.hbs @@ -73,8 +73,10 @@

{{item.name}}

- {{#if (and item.hasLimitedUses item.system.uses.per) }} -
Uses {{item.system.uses.value}} / {{item.system.uses.max}}
+ {{#if item.hasLimitedUses}} +
+ {{localize "DND5E.Uses"}} {{#if item.system.uses.value}}{{item.system.uses.value}}{{else}}0{{/if}} / {{item.system.uses.max}} +
{{/if}}
{{#each item.labels.components.all}}