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:

  • Spirit Rite: Perform a spirit rite on target(s)
  • Spirit Action: Spirit world interaction (Roaming, Sensing, Communing, etc.)
  • Spirit Power: Channel spirit power (Ancestor, Totem, or Energy)
  • Ritual Action: Perform a prescribed ritual to earn a deity's favour
  • Divine Incantation: Cast divine spells
  • Arcane Incantation: Cast arcane spells
  • Arcane Talent: Intrinsic spell-like arcane powers
  • Spirit Talent: Intrinsic spell-like spirit powers
  • Alchemy: Create alchemical elixirs or perform alchemical actions
  • Divination: Foretell the future

Type Parameters

Hierarchy (View Summary)

Indexable

  • [key: symbol]: true

Constructors

Properties

actions: SohlMap<string, sohl.entity.action.SohlAction>

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).

affiliation?: AffiliationLogic

The 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.

assocSkill?: SkillLogic

The 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.

assocSpiritPower?: MysticalAbilityLogic

The 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).

charges: {
    max: sohl.entity.modifier.ValueModifier;
    value: sohl.entity.modifier.ValueModifier;
}

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).

Type declaration

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.

Accessors

  • get actor(): null | SohlActor
  • The owning SohlActor — the document itself when it is an actor, otherwise its owning actor (for an item, combatant, or effect), or null.

    Returns null | SohlActor

  • get actorLogic(): null | SohlActorLogic<any>
  • 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.

    Returns null | SohlActorLogic<any>

    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.

  • get data(): TData
  • 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.

    Returns TData

    Convenience accessor for parent.

  • get document(): TData["parent"]
  • The owning document — the actor or item this logic is embedded in.

    Returns TData["parent"]

  • get isExhausted(): boolean
  • 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.

    Returns boolean

  • get item(): SohlItem
  • The owning SohlItem.

    Returns SohlItem

    If this logic is not embedded in an item.

  • get kind(): string
  • The owning document's kind (its actor or item type id).

    Returns string

  • get sdrSkillBase(): number
  • 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.

    Returns number

  • get typeLabel(): string
  • Localized type (and sub-type, when present) label for the owning document.

    Returns string

  • get usesOwnMasteryLevel(): boolean
  • 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).

    Returns boolean

  • get usesSpiritPower(): boolean
  • 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.

    Returns boolean

  • get uuid(): string
  • The owning document's UUID — the opaque identity token from the data port.

    Returns string

Methods

  • Compute derived values that depend on sibling items being initialized.

    Returns void

    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.

  • Resolve cross-item dependencies that require all items to have been evaluated.

    Returns void

    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.

    Returns ContextMenuEntry[]

    The available context-menu entries.

    One entry per action whose visible predicate currently passes (an action's trigger / domain preconditions can hide it); SCRIPT actions are additionally permission-gated when executed. Use this to discover which actions can be performed on the document.

  • Set up base state from persisted data: create ValueModifiers, set base values.

    Returns void

    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.

  • 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.

    Parameters

    • context: sohl.entity.action.SohlActionContext<
          {
              priorTestResult?: sohl.entity.result.SuccessTestResult;
              rollMode?: string;
              situationalModifier?: number;
              successLevelMod?: number;
          },
      >

      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.

    Returns Promise<undefined | sohl.entity.result.SuccessTestResult>

    The re-evaluated result, or undefined when refused (non-GM), cancelled (dialog dismissed), or unchanged (no-op).

  • 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.

    Parameters

    Returns Promise<undefined | false | sohl.entity.result.SuccessTestResult>

    The test result, undefined if cancelled/blocked, or false on error.

  • Serialize this logic to a plain reference.

    Returns PlainObject

    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.