A passive or charge-based mystical power associated with a character or object.

Mysteries represent supernatural gifts, blessings, and connections that influence a character's capabilities. Unlike Mystical Abilities (which are actively cast), mysteries are often passive or limited-use powers that enhance skills, grant re-rolls, or provide divine favor.

A Mystery models what a character is — a standing condition, pool, or blessing — so it carries no "use it" action of its own: there is no universal meaning to using a Mystery. Anything a character actively invokes is a Mystical Ability, which has its own action and roll; a subtype that should be spent down is driven by whatever consumes it.

Each mystery tracks a level and optional charges (value and max); a null charge value denotes infinite uses. A mystery may name an associated Skill (e.g. the skill a boon or boost affects).

Subtypes (MysterySubType):

  • Boon — a flat ±N modifier to an associated skill's mastery level, from any source.
  • Boost — one or more temporary Mastery Boosts to an associated skill (the Mastery Boost table).
  • Fate — quantifies the ability to alter destiny or fate (the stored fate pool). The "Fate" invocation is a Divination Mystical Ability; a per-skill fate bonus is modelled with Active Effects, and a fate-point bonus is not yet modelled.
  • Grace — quantifies the ability to call effectually on divine favour.
  • Other — a mechanically inert carrier whose entire effect lives in its Active Effects; a birthsign (a passive standing influence on associated skills) is authored this way.
  • Piety — quantifies devotion to a religion.

A Boon or Boost mystery names its target skill via MysteryData.assocSkillCode and, while active (a present, non-zero level), contributes a live delta onto that skill's mastery level in finalize. The mystery's level carries the effect's magnitude — ±N for a Boon, the boost count N for a Boost.

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 mystery draws its standing from, resolved during evaluate from MysteryData.assocAffiliationCode, or undefined when the mystery names no Affiliation, the item is not on an actor, or the shortcode matches none. This is separate from the associated skill: a religion, arcane or alchemical school, or ancestor/totem/spirit whose membership confers the mystery (the source of a Piety or Grace pool, say). 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 MysteryData.assocSkillCode, or undefined when the mystery names no skill.

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

The mystery's charge tracking. Both value and max are always sohl.entity.modifier.ValueModifiers; a null source value leaves the corresponding modifier disabled, which the sheet reads to pick the ×/∞ display:

  • max disabled (source max === null) → mystery does not use charges, shown as "×".
  • value disabled (source value === null) → infinite charges remaining, shown as "∞".
  • max.effective === 0 → infinite charges available, shown as "value/∞".
  • otherwise → "value/max".

Type declaration

The mystery's level as a sohl.entity.modifier.ValueModifier, seeded from MysteryData.levelBase. Disabled when the mystery has no level (levelBase === null).

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 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 typeLabel(): string
  • Localized type (and sub-type, when present) label for the owning document.

    Returns string

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

  • When this Boost names a skill the actor does not have, offer to add that skill — resolved from the world/compendiums by its shortcode — as an unlearned embedded skill (mastery level base 0). Once present, the Boost opens it at its Skill Base and boosts it (see the boost-contribution logic in contributeSkillEffect); should the Boost later lapse, the skill simply sits at ML 0 (harmless) until its owner deletes it.

    This is the only way an absent-skill Boost arises: an embedded mystery's assocSkillCode is picked from the actor's own skills, so a code the actor lacks can only come from a world/compendium Boost dropped onto the actor — which is exactly the human-initiated moment this offer belongs to (the consent model: offer at a behest, never act unbidden). Driven from MysteryDataModel._onCreate, on the initiating client only.

    No-op unless this is a boost naming a skill absent from the actor; a shortcode resolving to no skill anywhere is reported, not offered. #981.

    Returns Promise<void>

    Resolves once the offer — and any resulting skill creation — settles.

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

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