From 459f87f24c0aea9efb7baf6c4e8b51c779dc35de Mon Sep 17 00:00:00 2001 From: nsalyzyn Date: Fri, 19 Dec 2025 10:15:53 -0700 Subject: [PATCH] Creating a shared method called isItemAvailable and using it in downtime --- module/applications/dialogs/downtime.mjs | 3 +- module/data/actor/base.mjs | 12 +++++++ module/data/actor/character.mjs | 44 +++++++++++++++--------- module/documents/activeEffect.mjs | 27 +++------------ 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/module/applications/dialogs/downtime.mjs b/module/applications/dialogs/downtime.mjs index 5241ae03..3d5b7f0f 100644 --- a/module/applications/dialogs/downtime.mjs +++ b/module/applications/dialogs/downtime.mjs @@ -93,8 +93,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV } getRefreshables() { - const actionItems = this.actor.items.reduce((acc, x) => { - // TODO(nsalyzyn): Eliminate items that the are part of the subclass the actor doesn't have access to. + const actionItems = this.actor.items.filter(x => this.actor.system.isItemAvailable(x)).reduce((acc, x) => { if (x.system.actions) { const recoverable = x.system.actions.reduce((acc, action) => { if (refreshIsAllowed([this.shortrest ? 'shortRest' : 'longRest'], action.uses.recovery)) { diff --git a/module/data/actor/base.mjs b/module/data/actor/base.mjs index c7f7ee75..f3662da2 100644 --- a/module/data/actor/base.mjs +++ b/module/data/actor/base.mjs @@ -1,4 +1,5 @@ import DHBaseActorSettings from '../../applications/sheets/api/actor-setting.mjs'; +import DHItem from '../../documents/item.mjs'; import { getScrollTextData } from '../../helpers/utils.mjs'; const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) => @@ -106,6 +107,17 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel { return data; } + /** + * Checks if an item is available for use, such as multiclass features being disabled + * on a character. + * + * @param {DHItem} item The item being checked for availability + * @return {boolean} whether the item is available + */ + isItemAvailable(item) { + return true; + } + async _preDelete() { /* Clear all partyMembers from tagTeam setting.*/ /* Revisit this when tagTeam is improved for many parties */ diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 13d4c97e..83dc3c16 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -435,6 +435,32 @@ export default class DhCharacter extends BaseDataActor { return attack; } + /** @inheritDoc */ + isItemAvailable(item) { + if (!super.isItemAvailable(this)) return false; + /** + * Preventing subclass features from being available if the chacaracter does not + * have the right subclass advancement + */ + if (item.system.originItemType !== CONFIG.DH.ITEM.featureTypes.subclass.id) { + return true; + } + if (this.class.subclass) { + const prop = item.system.multiclassOrigin ? 'multiclass' : 'class'; + const subclassState = this[prop].subclass?.system?.featureState; + if (!subclassState) return false; + + if ( + item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation || + (item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization && + subclassState >= 2) || + (item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3) + ) { + return true; + } + } + } + get sheetLists() { const ancestryFeatures = [], communityFeatures = [], @@ -443,7 +469,7 @@ export default class DhCharacter extends BaseDataActor { companionFeatures = [], features = []; - for (let item of this.parent.items) { + for (let item of this.parent.items.filter(x => this.isItemAvailable(x))) { if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.ancestry.id) { ancestryFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.community.id) { @@ -451,21 +477,7 @@ export default class DhCharacter extends BaseDataActor { } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.class.id) { classFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) { - // TODO(nsalyzyn): Reuse this code for elsewhere - if (this.class.subclass) { - const prop = item.system.multiclassOrigin ? 'multiclass' : 'class'; - const subclassState = this[prop].subclass?.system?.featureState; - if (!subclassState) continue; - - if ( - item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation || - (item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization && - subclassState >= 2) || - (item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3) - ) { - subclassFeatures.push(item); - } - } + subclassFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.companion.id) { companionFeatures.push(item); } else if (item.type === 'feature' && !item.system.type) { diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index 966e4852..cfb25332 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -194,29 +194,12 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { } prepareDerivedData() { - /* Preventing subclass features from transferring to actor if they do not have the right subclass advancement */ - if (this.parent?.type === 'feature') { - // TODO(nsalyzyn): Reuse this code for elsewhere - const origSubclassParent = this.parent.system.originItemType === 'subclass'; - if (origSubclassParent) { - const subclass = this.parent.parent.items.find( - x => - x.type === 'subclass' && - x.system.isMulticlass === (this.parent.system.identifier === 'multiclass') - ); - - if (subclass) { - const featureState = subclass.system.featureState; - - if ( - (this.parent.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization && - featureState < 2) || - (this.parent.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && featureState < 3) - ) { - this.transfer = false; - } - } + /* Check for item availability such as in the case of subclass advancement. */ + if (this.parent?.parent?.system?.isItemAvailable) { + if (!this.parent.parent.system.isItemAvailable(this.parent)) { + this.transfer = false } } + return; } }