The MysticalAbility data interface.
Binds this logic to its parent data model and builds the actions map from the parent's intrinsic and scripted action definitions, selecting a default action.
Reserved base data (unused by the base class).
Must provide options.parent, the data model this logic
is embedded in; the parent's actionDefs are used to build
actions.
Executable actions for this document, keyed by shortcode — context-menu entries, chat-card buttons, and lifecycle hooks. A script action shadows (wholly overrides) the intrinsic action of the same shortcode (see the constructor).
OptionalaffiliationThe faction/Affiliation (an AffiliationLogic) this ability
draws its standing from, resolved during evaluate from
MysticalAbilityData.assocAffiliationCode, or undefined when the
ability names no Affiliation, the item is not on an actor, or the
shortcode matches none. This is separate from the activating
skill: a religion, arcane or alchemical school, or
ancestor/totem/spirit whose membership confers an available area, level,
or capability. Surfaced as the Being sheet's Affiliation column; a subtype
may consult its rank to inform a
capability derivation.
OptionalassocThe associated skill (a SkillLogic) resolved during
evaluate from MysticalAbilityData.assocSkillCode, or
undefined if the ability uses its own mastery level. Only the
skill-governed subtypes resolve a skill; the spirit-power subtypes resolve assocSpiritPower instead.
OptionalassocThe associated Spirit Power (a SPIRITPOWER-subtype
MysticalAbilityLogic) resolved during evaluate for the
spirit-power subtypes (spiritrite /
spiritaction), from MysticalAbilityData.assocSkillCode — for
these subtypes the shortcode names a Spirit Power on the same actor rather
than a skill. undefined when the reference is blank or unresolved (which
leaves the ability disabled).
The ability's charge tracking. Both value and max are always
sohl.entity.modifier.ValueModifiers; a null source value leaves the corresponding
modifier disabled, driving the ×/∞ display (see the identical rules on
MysteryLogic.charges).
Maximum charges; disabled when the ability does not use charges (max === null).
Current charges; disabled when charges are infinite (value === null).
The ability's power level as a sohl.entity.modifier.ValueModifier, seeded from
MysticalAbilityData.levelBase. Disabled when levelBase is null
(shown as "×").
The mastery level as a sohl.entity.modifier.MasteryLevelModifier. When the ability has no associated skill (blank MysticalAbilityData.assocSkillCode) it is seeded from MysticalAbilityData.masteryLevelBase — the ability's internal mastery level. When a skill is associated, the base is left empty until finalize copies the assocSkill's mastery level in via addVM (so the ability's own custom modifiers still stack on top of the skill's).
For arcaneincantation and divineincantation subtypes, evaluate
adds a Level × 2 casting penalty as an auditable delta (higher-level
incantations are harder to cast); other subtypes carry no such penalty.
The owning SohlActor — the document itself when it is an actor,
otherwise its owning actor (for an item, combatant, or effect), or null.
The logic of the owning actor — the Foundry-free way to reach the actor
layer from any logic. For an actor's own logic this is itself; for an
item's logic it is the owning actor's logic; otherwise null.
Resolved through the SohlLogicData port, so logic code
can navigate to the actor (and iterate items via allLogics /
logicTypes / getItemLogic) without touching the Foundry document.
The association shown in the sheet's assoc column — the Spirit Power for
the spirit-power subtypes, otherwise the
assocSkill. undefined renders an ✕ in that column.
Whether the ability may be improved: true when the current user is a GM or owns the item, the mastery level is live, and the ability governs its own mastery level.
Mirrors SkillLogic.canImprove, with the extra association gate. Read while the Being sheet renders, so — like the skill's — it must not throw on a not-yet-initialized ability (#511 class).
This logic's typed data — its *Data interface (e.g. SkillData), the same
persisted object as document.system. Prefer document.logic.data when
reading a document's fields from a macro, Script Action, or module: it is the
typed, API-documented surface (autocomplete and reference links resolve),
whereas document.system is typed as the internal DataModel.
Convenience accessor for parent.
Whether a valid Spirit Power is associated — the reference resolved and is itself a SPIRITPOWER-subtype ability. Only meaningful for the spirit-power subtypes; a spirit-power ability with no valid Spirit Power is disabled.
The owning document's id.
Whether the ability cannot currently be invoked (its Being-sheet row is greyed out and its EML roll is blocked): either it is out of charges, or it is a spirit-power subtype without a valid Spirit Power.
Whether the ability uses finite, capped charges and none remain (#990).
An exhausted ability's Being-sheet row is greyed out and its EML roll is
blocked until it is recharged. This is distinct from an ability that does
not use charges (max disabled), one with infinite remaining charges
(value disabled), or one with no maximum cap (max effective 0, shown
as ∞) — none of which is ever exhausted.
The owning SohlItem.
The owning document's kind (its actor or item type id).
Localized display label combining the typeLabel and the document's name.
The owning document's name.
The amount by which improveWithSDR raises the base mastery level on success.
The Skill Base added to the SDR's 1d100. A Mystical Ability carries no
Skill Base of its own — the only abilities that can be improved are those
with no associated skill to borrow one from — so it improves on the raw
1d100 against its base mastery level.
A SohlSpeaker for the owning actor/item (a blank speaker if neither resolves).
Localized type (and sub-type, when present) label for the owning document.
Whether the ability's mastery level is its own — true exactly when no association shortcode is set, so initialize seeds masteryLevel from MysticalAbilityData.masteryLevelBase rather than finalize copying it in from an associated Skill or Spirit Power.
This is what makes improvement meaningful: only a self-governed ability has a mastery level of its own to raise. An ability drawing on a Skill (or a Spirit Power) improves when that item improves — so it shows no ☆ star and offers no improve actions (#1130).
Whether this ability's activation test is governed by a Spirit Power
rather than a skill — true for the spiritrite and spiritaction
subtypes. For these, the association shortcode names a Spirit Power (a
SPIRITPOWER Mystical Ability) on the actor, the sheet shows a "Spirit
Power" column, and the ability is disabled unless a valid one resolves.
The owning document's UUID — the opaque identity token from the data port.
Delete the owning document, after confirming with the user.
The action context; unused.
Open the sheet for the owning document.
The action context; unused.
Compute derived values that depend on sibling items being initialized.
Called on every item after ALL items have completed initialize.
Safe to access: sibling items' initialized state (e.g., reading trait attribute values for a skill base formula).
Not safe to access: sibling items' evaluated state — another item's
evaluate() may not have run yet. Dependencies on evaluated state
belong in finalize.
Example: a Skill reads trait attribute values to compute its skill
base; a gear item resolves its containerId to find its parent container.
Execute an action by shortcode, using the provided context or creating a new one.
The shortcode of the action to execute.
Optionalcontext: sohl.entity.action.SohlActionContextThe action context to use, if any.
The result of the action execution, or undefined if the action was not found or could not be executed.
Resolve cross-item dependencies that require all items to have been evaluated.
Called on every item after ALL items have completed evaluate.
Safe to access: all sibling items' initialized and evaluated state.
Example: fate mastery level (which depends on an already-evaluated Aura trait); encumbrance totals summed across all evaluated gear.
The context-menu options — the actions currently available — for this logic's document.
The available context-menu entries.
Attempts to improve the ability via a Skill Development Roll (SDR): rolls
1d100 against the current base mastery level and, on a success, raises
MysticalAbilityData.masteryLevelBase by sdrIncr. The
improve flag is cleared either way and the outcome is posted to chat.
Intrinsic-action executor for the improveWithSDR action; shares the
skill's exact seam. It is offered only on an ability that
governs its own mastery level; run against
one that draws on an associated Skill it changes only this ability's
unused masteryLevelBase, and never the associated Skill.
The action context whose speaker receives the chat card.
Resolves once the roll is evaluated, persisted, and the chat card is posted.
Set up base state from persisted data: create ValueModifiers, set base values.
Called on every item before any item's evaluate runs.
Safe to access: own persisted data fields (this.data.*).
Not safe to access: sibling items on the same actor — they may not have initialized yet. Cross-item reads belong in evaluate.
Example: a Skill creates its MasteryLevelModifier
from persisted fields; it does not yet read trait attribute values.
Post this item's description to the chat log — a human-triggered, informational card (no follow-up buttons) built by buildItemDescCardData. Assist, never act: this only shows the item's own text; it takes no action on any character.
The action context; unused.
Intrinsic action performed after finalize lifecycle stage. This is intended for modules to hook into (or ActionItems to override) to perform additional logic after the main lifecycle stages have completed.
The action context for the post-finalize hook.
GM result-edit for a posted test card (#856) — the higher-fidelity
counterpart to Fate. Re-opens the standard test dialog pre-filled with the
result's current situational and success-level modifiers; on submit it
applies the new modifiers and re-evaluates on the SAME frozen roll
(never a re-roll, no Fate cost), then reposts the card. The prior result
rides in context.scope.priorTestResult (the reconstruction seam), so this
works for any standard test card — skill, attribute, or combat strike mode.
Changing the situational modifier changes the effective target, so the base success level re-derives from the frozen roll; the success-level modifier is a flat offset applied after. Clicking OK without a change is a no-op (nothing re-evaluated, nothing reposted).
GM-only. The pencil is render-hidden from non-GMs (sohl.document.chat.gateEditActionPencil); this is the click-time half of that gate — a synthesized click from a non-GM is refused here.
The action context; context.scope.priorTestResult is the
result being edited. When skipDialog is set, the new
situationalModifier / successLevelMod / rollMode are taken from
context.scope instead of the dialog.
The re-evaluated result, or undefined when refused (non-GM),
cancelled (dialog dismissed), or unchanged (no-op).
Flags this ability for improvement via a Skill Development Roll.
Intrinsic-action executor for the setImproveFlag action; shares the
skill's exact seam. Writes only this ability's own system.improveFlag —
an associated Skill is never touched.
The action context (unused).
Resolves once the item update completes.
Performs a success test against this ability's mastery level (EML) — invoking the ability is the same roll-for-success-or-failure a skill makes, so this shares the skill's exact seam.
Intrinsic-action executor for the successTest action; delegates to
sohl.entity.modifier.MasteryLevelModifier.successTest. The system
rolls but does not adjudicate the ability's effect — the outcome is read
off the rulebook and applied by the player. Bespoke activation behavior is
left to author-supplied Script Actions rather than a built-in executor.
When the ability uses finite charges, invoking it consumes one: after a completed roll (a real result, not a cancel or error) the persisted charge count is decremented by one (#990). A disabled ability — one that is exhausted, or a spirit-power subtype without a valid Spirit Power — cannot be invoked at all: the roll is refused with a notice. Consumption is a direct consequence of the player's own roll, so it needs no separate consent.
The action context (speaker, scope) for the test.
The test result, undefined if cancelled/blocked, or false on error.
Toggles this ability's improvement flag — the executor behind the ☆ star on the Being sheet's Mysteries tab.
Intrinsic-action executor for the toggleImproveFlag action.
The action context (unused).
Resolves once the item update completes.
Serialize this logic to a plain reference.
A uuid-keyed reference to this logic.
A logic is a behavior wrapper over a live Foundry document; it is never
revived from its own JSON (its constructor needs that document). Wherever a
logic is persisted — a chat card, an action sohl.entity.action.SohlActionContext.scope
— it is re-resolved from its uuid (e.g. via fvttLogicFromUuidSync), not
rebuilt from a payload. So it serializes as a compact, resolvable reference
(name/kind are carried for display and debugging); the owning document
holds the actual persisted state.
Clears this ability's improvement flag.
Intrinsic-action executor for the unsetImproveFlag action.
The action context (unused).
Resolves once the item update completes.
StaticdefineDefine and return all intrinsic actions for mystical ability logic,
adding the successTest action to those inherited from the base logic.
The intrinsic action definitions.
An actively invoked supernatural power.
Mystical Abilities represent spells, rites, invocations, and other powers that a character actively uses. Unlike Mysteries (which are often passive), mystical abilities must be deliberately activated and their success is typically determined by a skill test.
Each ability is linked to an associated skill (via shortcode) that governs its activation test. Abilities track a level (power), charges (uses remaining), and track mastery level progression via sohl.entity.modifier.MasteryLevelModifier.
Supported subtypes: