diff --git a/lang/en.json b/lang/en.json index 6e04f5196f..d39de58b32 100644 --- a/lang/en.json +++ b/lang/en.json @@ -4233,6 +4233,7 @@ "Unlabeled": "Unlabeled Spellcasting" }, +"DND5E.SpellAvailable": "Available", "DND5E.SpellcastingClass": "{class} Spellcasting", "DND5E.SpellComponent": "Spell Component", "DND5E.SpellComponents": "Spell Components", diff --git a/module/applications/actor/api/base-actor-sheet.mjs b/module/applications/actor/api/base-actor-sheet.mjs index 79df33f1bd..499faafb29 100644 --- a/module/applications/actor/api/base-actor-sheet.mjs +++ b/module/applications/actor/api/base-actor-sheet.mjs @@ -395,6 +395,7 @@ export default class BaseActorSheet extends PrimarySheetMixin( { key: "reaction", label: "DND5E.Reaction" }, { key: "concentration", label: "DND5E.Concentration" }, { key: "ritual", label: "DND5E.Ritual" }, + { key: "available", label: "DND5E.SpellAvailable" }, { key: "prepared", label: "DND5E.Prepared" }, ...Object.entries(CONFIG.DND5E.spellSchools).map(([key, { label }]) => ({ key, label })) ], @@ -2066,6 +2067,7 @@ export default class BaseActorSheet extends PrimarySheetMixin( if ( schoolFilter.size && !schoolFilter.has(item.system.school) ) return false; if ( classFilter.size && !classFilter.has(item.system.classIdentifier) ) return false; if ( filters.has("prepared") ) return item.system.canPrepare && item.system.prepared; + if ( filters.has("available") ) return this.#spellAvailable(item); // Equipment-specific filters if ( filters.has("equipped") && (item.system.equipped !== true) ) return false; @@ -2084,6 +2086,20 @@ export default class BaseActorSheet extends PrimarySheetMixin( /* -------------------------------------------- */ + /** + * Determine whether a spell is available to cast, for the "available" filter. + * @param {Item5e} spell The spell item. + * @returns {boolean} + */ + #spellAvailable(spell) { + const { canPrepare, method, prepared } = spell.system; + if ( !canPrepare ) return (method === "innate") || (method === "atwill"); + // Prepared/always-prepared, or granted by an item (wands, scrolls) — those only show when castable. + return !!prepared || !!spell.getFlag("dnd5e", "cachedFor"); + } + + /* -------------------------------------------- */ + /** * Determine whether an Item will be shown based on the current set of filters. * @param {Item5e} item The item.