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).
The being's body — its
anatomy, weight, reach, and body-scale, derived from system.body.
Constructed directly in initialize (no embedded item, no
cross-document registration). An incorporeal being has an empty body
structure (sohl.document.actor.logic.BodyLogic.isIncorporeal).
Running total of carried-gear weight (pounds) as a sohl.entity.modifier.ValueModifier,
accumulated ground-up: each carried gear item adds a delta of its
weight × quantity during its own evaluate() phase (see
sohl.document.item.logic.GearLogic.evaluate). Reset to an empty modifier at the start of
initialize and fully populated (read via carriedWeight.effective)
by the time the being's own evaluate()/finalize() and the sheet read it.
The being's encumbrance, as a sohl.entity.modifier.ValueModifier.
Derived in finalize from the active movement profile's
encumbrance expression of the being's carriedWeight.
The being's Fatigue Penalty as a sohl.entity.modifier.ValueModifier
— the total Fatigue Levels across every fatigue-subtype
trauma (windedness /
weariness / weakness are recorded as separate instances because each
recovers at its own rate). It penalizes all tests and Move rate. Seeded in
finalize once traumas are prepared; there is no persisted field.
The actor's tactical move (feet per combat round) as a sohl.entity.modifier.ValueModifier so runtime modifiers (haste, encumbrance, etc.) can layer on. Seeded from the active moveProfile when it is enabled.
The being's Healing Base as a sohl.entity.modifier.ValueModifier — the mastery-level factor governing recovery, seeded in evaluate to the average of the being's Endurance and Will scores (rounded up when END > WIL, else down; see healingBaseFor) and open to trait and treatment deltas on top. Multiplied by a Healing Rate, it is the target of nearly every recovery test in the system. An empty modifier (base 0) when the being lacks an Endurance or Will attribute (e.g. an incorporeal being).
The actor's overland travel speed (leagues per watch) as a sohl.entity.modifier.ValueModifier. Seeded from the active moveProfile when it is enabled.
The active movement profile, selected during initialize by this actor's SohlActorData.currentMoveMedium. A disabled MOVEMENT_MEDIUM.NONE profile when the actor has no matching profile (a non-mover).
The being's pull score, determining whether it can draw certain bow weapons.
The being's strength modifier to encumbrance, as a
sohl.entity.modifier.ValueModifier. Derived in evaluate
from the active movement profile's strMod expression of the being's
strength.
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 logic instances of every embedded item — the logic-layer analogue of Foundry's foundry.documents.Actor#allItems.
One SohlItemLogic per embedded item, in items order.
The strike modes currently available to this being:
minParts limbs.Reads each strike mode's already-prepared data, so it should be read after item preparation. Returns an empty array when no mode is available.
This being's combatant in the active combat encounter.
Returns the first combatant of game.combat whose token is one of this
being's tokens on the active scene, or null when there is no
active combat or no such combatant.
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.
The being's current fear state (#558) — the most severe (most-failed)
sohl.utils.FEAR_CATEGORY across its active fear-source traumas, or
NONE when it carries none. "When several fear sources are present, only
the most severe state affects the victim" (Fear rules).
Whether the actor is owned by at least one player (non-GM) user.
The qualitative health band (Excellent…Dead) for this being's current
SohlActorData.health value. Impairment-based — driven by impaired
body parts, not a points pool. Recomputed from the derived health.value
written in finalize via deriveHealth.
The owning document's id.
This being's size-scaled injury-level thresholds — delegated to the body. Read by sohl.entity.body.BodyStructure.injuryTable (which reaches it through this being, the structure's parent).
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.
Every item's logic instance grouped by item kind — the logic-layer analogue of Foundry's foundry.documents.Actor#itemTypes.
A record of item kind → that kind's logic instances.
Every ItemKind key is present; kinds with no items map to an empty
array. Each group is typed to the concrete logic for that kind, so
logicTypes.skill is SkillLogic[].
The being's current morale state (#559) — the most severe (most-failed)
sohl.utils.MORALE_CATEGORY across its active morale-failure traumas, or
NONE when it carries none.
The owning document's name.
The being's accrued Pall Stress Levels (PSL) (#561) — the level of its
single pall-subtype trauma (the Pall Cloud), or 0 when it carries none.
The being's melee reach (feet): the greatest reach among its currently available melee strike modes.
minParts limbs (a body part that
canHoldItem).Returns 0 when no melee mode is available (e.g. an unarmed being with
no combat techniques). Reads each strike mode's already-evaluated
reach, so it should be read after item preparation.
The being's current shock state as an ascending severity level —
NONE (0), STUNNED (1), INCAPACITATED (2), UNCONSCIOUS (3), DEAD
(4) — derived from the active shock status effects (there is no
persisted field). Reports the highest active one (see
sohl.document.actor.logic.SHOCK_STATE); change it through
setShockState / advanceShockState, never by toggling the
statuses directly.
A SohlSpeaker for the owning actor/item (a blank speaker if neither resolves).
This being's tokens on the world's active scene.
Returns an empty array when there is no active scene or no matching token.
Localized type (and sub-type, when present) label for the owning document.
The owning document's UUID — the opaque identity token from the data port.
Accept an ally's Rally — the open Rally card's
button runs this on the accepting player's own character. Self-gates: only a
shaken (Withdrawing/Routed/Catatonic) character responds. A steady rally
(CS) makes them Steady immediately; a reaction rally (MS) triggers their
Reaction Test.
The action context; scope.mode is "steady" or
"reaction".
A promise that resolves once the rally is applied.
Advance (or, with a negative steps, improve) the being's
shockState by steps severity levels from its current state,
clamped to [NONE, DEAD]. A convenience over setShockState for
effects that read the current state and move it (blood loss, an injury
shock result, a shock re-test).
Levels to move (positive worsens, negative improves).
A promise that resolves once the shock state has been updated.
Record a permanent impairment (#554) on the body part containing
locationShortcode, worsening its persisted permanentImpairment to at
most magnitude (the worse — more negative — of the two). A no-op for a
non-negative magnitude, an unknown location, or when it would not worsen
the existing value. The whole parts array is rewritten (an element-by-
index write corrupts the array — see the Runtime Contracts).
Called when an eligible injury heals to level 0 (see the Injury rules — Permanent Impairment); the magnitude comes from sohl.entity.body.permanentImpairmentFor.
The healed injury's body-location shortcode.
The permanent impairment to apply (a non-positive number).
A promise that resolves once the impairment is persisted.
The derived BodyPartImpairment of each given body part — the per-part view behind the held-limb gating for weapon strike modes (#628), as opposed to the role-aggregated unusableRoles / impairedRolePenalties. Each part is scored against the being's active injuries (only its own locations match) plus its permanent impairment/unusable flags, so a caller passes the being's own parts — e.g. the limbs holding a weapon, from sohl.document.item.logic.GearLogic.heldBy.
One impairment per input part, in order (empty when parts is empty).
Apply the impact of an attack or effect to this being, calculating the resulting location and damage. If armor or other defenses are unable to fully mitigate the impact, this will return the resulting damage and location so it can then be used to apply damage to the being's body roles and parts.
Action context carrying the impact result in its scope
(scope.priorTestResult / scope.impactModifier).
The impact result, or null if no impact occurred.
Intrinsic-action executor for contagionCheck (#1183) — the *Check half
of contagion.
A *Check offers, and does nothing else: it posts a card whose button
invites this being's controller to make one contagionTest. Nothing
is rolled and nothing is written, so it imposes nothing and carries no
ownership gate — anyone may initiate a Contagion Check on anyone,
which is the point: exposure is something the world does to a character,
but catching it is the character's own roll to make.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Contagion Test (#1183) — the *Test
half of contagion, and the roll that decides whether this being catches
something they were exposed to.
The dialog asks which affliction (a dropdown keyed by shortcode), a
Situational Modifier and Success Level Modifier for the roll, and whether a
contracted affliction is added to the character sheet — that checkbox
defaulting from the recordTrauma world setting.
The roll is a d100 test against Contagion Index × Endurance, and
failing it means the affliction is caught
(sohl.document.actor.logic.isContracted). How fast it takes hold
depends on how badly the roll went: a critical failure halves the rolled
onsetFormula (rounded down), a marginal failure uses it as-is, and 0
days means onset is immediate
(sohl.document.actor.logic.onsetDaysFor).
A contracted affliction is created with its contract date set to now and its incubation set to the rolled value — but only when the checkbox was ticked. Nothing ever offers to schedule another contagion test: exposure is not a recurring condition.
The action context for the test.
The success test result, or null when the being has no Endurance
attribute or the dialog was dismissed.
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 a Fear Test (#558) — a test against Will — against a frightening source, and record the resulting fearState.
A self-sufficient action on the affected being: it rolls the being's Will
headlessly (adding the Brave bonus if active), maps
the result to a sohl.utils.FEAR_CATEGORY
(sohl.document.actor.logic.fearStateFromTest — the CF0/CF5 split
decides Catatonic vs Terrified), and applies it: a fearful result records
(or worsens) a fear-subtype trauma for the source and inflicts any Psyche
Stress; a success clears the source (Steady) or grants the Brave bonus.
The action context; scope.sourceName names the fear
source (defaults to a generic label).
The Fear-test result, or null if the roll could not be run.
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.
Roll the being's Fumble test (#852) — an "avoid dropping / mishandling"
check a combat mishap can flag (ATTACK_MISHAP.FUMBLE_TEST /
DEFEND_MISHAP.FUMBLE_TEST). Rolls the better of the being's Dexterity
attribute and its Legerdemain skill and posts a result card whose bespoke
keep-grip text comes from a keepControlTable passed in scope.
Offered, never auto-performed: it runs only when its controlling player picks the action (the mishap surfaces on the attack card as a prompt).
The action context for the test.
The success test result, or null if the test could not be run.
The context-menu options — the actions currently available — for this logic's document.
The available context-menu entries.
Find an embedded item's logic by its shortcode and item kind.
The item kind, inferred from the type argument.
The matching item's logic typed for type, or undefined if
no item matches.
Both arguments are required: a shortcode is only unique within a given
item kind, so matching the type as well prevents returning an
unexpected item that happens to share the shortcode. The item kind also
drives the return type — the concrete logic for that kind is resolved
from ItemLogicByKind, so no cast is needed at the call site:
const stealth = actor.logic.getItemLogic("stealth", ITEM_KIND.SKILL);
// ^? SkillLogic | undefined
Find an embedded item's logic by its id.
The item's id.
The matching item's logic or undefined if no item matches.
Return the usable strike modes for this weapon.
Filter criteria for the strike mode query.
if true, direct strike modes are allowed, otherwise not.
if specified, the distance from the weapon holder to the target, used to consider reach and/or range.
if true, melee strike modes are allowed, otherwise not.
if true, volley strike modes are allowed, otherwise not.
array of strike modes on this weapon that are currently usable that meet the criteria.
Handle a trigger dispatched by the SoHL event queue. Override in subclasses to implement actor-specific trigger handling.
Subscription kind identifier
Trigger context (discriminated by context.name)
Optional_payload: Record<string, unknown>Optional context data attached when subscribing
Each body-part role the being can still use but is impaired in, mapped
to the worst (most negative) −5 (minor) / −10 (serious) indefinite-impairment
penalty among the usable parts carrying that role (#568). A test whose
governing skill or attribute lists any of these roles in its
impairedByRoles takes that penalty on its effective mastery level.
Unusable parts are excluded — a grievous injury forces an automatic Critical Failure (see unusableRoles) rather than a numeric penalty — so the two views never both cover the same part.
Role → worst penalty (≤ 0); empty for an incorporeal being or one
with no impaired parts.
Select the active movement profile from SohlActorData.currentMoveMedium and seed the feetPerRound / leaguesPerWatch modifiers.
Movement is a universal actor capability, so it is derived on the
base actor logic. Subclasses that layer encumbrance/strength effects onto
the selected profile (e.g. Being) must call super.initialize() first.
See sohl.core.logic.SohlLogic.initialize for the lifecycle phase.
Resolve the Injury Shock Test (#555) for a wound just taken, worsening the being's shockState accordingly.
Intrinsic handler for the injury card's Shock Roll button — a specialization
of the general shockTest, with the base Shock State Index computed
from the wound. The card's scope carries the wound's precomputed shock
contribution (shockIndex = body-location Shock Value + Injury Level,
already including the glancing-blow point) and a shockBonus (the +10
glancing-blow roll bonus). The shared resolveShockRoll core rolls a
headless Shock test (fatigue applies, the glancing bonus is added, and
injury-impairment penalties do not); its result maps to a shock state, and
the being is worsened to it (shock only ever worsens here — an improving
Re-Test is #556). The state is applied directly — the player's click on
the injury card's Shock Roll button was the consent — and the Re-Test
reminder is then offered.
The action context; its scope carries shockIndex and
an optional shockBonus.
The Shock-test result, or null if the roll could not be run.
Set this actor's SohlActorData.currentMoveMedium — the active movement profile — to the medium carried in the action scope.
Intrinsic-action executor for the makeDefaultMedium action.
The action context; context.scope.medium names the
MovementMedium to make current. Absent, the medium is chosen in
a dialog unless skipDialog forbids one.
Resolves once the actor update completes, or immediately when no medium was chosen.
The Profile-tab star names the medium in scope and applies it directly. Invoked any other way — from the Actions menu, a macro, a script — there is no medium to apply, so the action offers the choice (the prefer-dialog rule) rather than returning silently as it once did (#1098). The prompt lists the no-movement medium plus every medium this actor authors a profile for, preselected at the current one. A caller that suppressed the dialog cannot be prompted, so it gets a notice instead of an unexplained no-op.
Resolve a Morale Test (#559) — a test of the Initiative skill — against a morale-failure source, recording the resulting moraleState.
A self-sufficient action on the affected being: it rolls Initiative
headlessly (adding the Brave bonus if active) and maps the result to a
sohl.utils.MORALE_CATEGORY (the CF0/CF5 split decides Catatonic vs
Routed). A shaken result records or worsens a morale-subtype trauma and
inflicts any Psyche Stress; a success clears the source (Steady) or grants
the Brave bonus.
The action context; scope.sourceName names the source.
The Morale-test result, or null if the roll could not be run.
Offer to schedule (or, when it no longer applies, clear) the being's Shock Re-Test reminder for its current state (#569) — the being-level timing half of #556, routed through the shared offerSchedule consent step so nothing auto-arms (Prime Directive: offer, remind, perform).
While in ordinary shock the reminder rides the state's cadence: an
Incapacitated victim re-tests at the end of each combat turn (an
event-driven turnEnd schedule), an Unconscious one ten minutes later
(a time schedule). Any other state — recovered, merely Stunned, or already
in a lasting Extended Shock / Coma (whose recovery is a Course Test, not a
Re-Test) — clears the reminder. When due, the event queue posts an
owner-gated [Perform] card; the Re-Test runs only on the controller's
click.
The action context; scope.schedule pre-answers the offer
and skipDialog suppresses the prompt (scripted callers).
A promise that resolves once the reminder is armed or cleared.
GM re-edit of a settled opposed contest (#1082) — the edit pencil in the Opposed Action Result card's header, and the two-sided counterpart to the standard card's sohl.document.item.logic.SohlItemBaseLogic.resultEdit (#856).
Re-opens the standard test dialog for each side in turn, pre-filled
with that side's current situational and success-level modifiers, applies
the new values, re-evaluates the contest on both frozen rolls (never a
re-roll, no Fate cost), and reposts the Opposed Action Result card. The
settled contest rides in context.scope.opposedTestResult — the whole
result serialized into the pencil's data-scope and revived by the
chat-card dispatcher — so the edit acts on that contest.
The contest lives only in the chat log, never on a document, so an edit mutates nothing persistent: it posts a new, corrected card and leaves the original standing (see the action-card consent model). Dismissing either side's dialog cancels the whole edit — no re-evaluation, no repost.
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.opposedTestResult is
the settled contest. When skipDialog is set, each side's new
situationalModifier / successLevelMod are taken from
context.scope.source / context.scope.target instead of the dialogs.
The re-evaluated contest, or undefined when refused (non-GM),
missing a contest, or cancelled (a dialog dismissed).
Resolve a Resist the Pall test (#561) — a Spirit test with a Pall
Depth penalty of 5 × total PAL — at the start of the being's turn while in
an affected area.
A self-sufficient action on the affected being: it rolls Spirit headlessly
(a spirit skill, falling back to the Aura attribute), applies the Pall
Depth penalty from scope.totalPal, and maps the result to a
sohl.document.actor.logic.PALL_STATE. A failure (Disturbed/Terrified/
Catatonic) accrues Pall Stress Levels on the being's Pall Cloud trauma; a
success (Resist/Immune) grants temporary immunity.
The action context; scope.totalPal is the total Pall
Strength affecting the being.
The Spirit-test result, or null if the roll could not be run.
Perform a Treatment Success Value test for an affliction (#1183) — the
physician's half of the affliction treatment exchange, run from a Treatment
Requested card's open @self button or by hand.
Self-gates: only a Physician-skilled character answers. Rolls this physician's own Physician skill as a success-value test, and posts a result card whose owner-gated Accept button relays the earned Success Stars to the patient's affliction as its Course Bonus — nothing is applied until the patient presses it.
Treatment for an affliction is mostly ineffectual by design: the bonus improves the odds on subsequent Course Tests, it does not cure anything.
The action context; scope.afflictionUuid targets the
affliction being treated.
The earned Success Stars and physician name, or undefined if it
aborts.
Perform a Blood Stoppage Test for a bleeding character (#547) — the
physician's step of the interactive flow, run from a Request Blood
Stoppage card's open @self button (or by hand). Self-gates: only a
Physician-skilled character answers. Rolls this physician's own
Physician skill (plus any +10 carried from a prior Marginal-Failure
stoppage) and posts a Blood Stoppage Result card whose owner-gated Accept
button relays the outcome
back to the bleeding injury.
The action context; scope.injuryUuid targets the
bleeding injury and scope.stoppageBonus carries the +10 next-test bonus.
The outcome kind and physician name, or undefined if it aborts.
The Perform Treatment Test action — this being (the physician) rolls their own Physician skill against a wound and posts the result. It is fully self-sufficient, so it is the same action however it is triggered:
scope.injuryUuid with skipDialog; the responder is the clicking
player's own game.user.character.When a real wound is identified it posts a Treatment Result card whose owner-gated Accept button records the proposed Healing Rate on that wound (via sohl.document.item.logic.TraumaLogic.treatInjury) — the physician never touches the patient's wound; the patient's own click does. A GM-directed test with no target wound posts an informational result with no button (someone runs Treat Injury by hand).
Self-gating: with no Physician skill it aborts with a notice and returns
undefined, so an open request card stays live for a qualified physician.
The action context; scope.injuryUuid names the wound when
pre-filled, else the dialog gathers the target.
The proposed { healingRate, physicianName }, or undefined when
the physician cannot perform it (no skill / unresolved / healed / cancel).
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.
Resolve a Rally Test (#559) — a leader's Command/Initiative test, made once per round as a free action, that steadies Routed and Withdrawing allies (sohl.document.actor.logic.rallyOutcome). Under the Prime Directive a rally is offered, not imposed: on a success this posts an open action card that any shaken ally's controller may accept to steady their own character (CS) or make a Reaction Test (MS). A failure posts an informational card noting the lockout.
The action context for the test.
The Rally-test result, or null if the roll could not be run.
Resolve a Reaction Test (#559) — an Initiative test a shaken combatant
makes to shake off a compromised morale state (or in response to an ally's
Rally). On success a Catatonic victim improves to Routed
and any other shaken victim snaps back to Steady
(sohl.document.actor.logic.reactionOutcome); on failure the state
persists. A no-op (returns null) when the being is not shaken.
The action context for the test.
The Reaction-test result, or null when no reaction applies.
Resolve Injury — generate a wound on this being from a blow, the single
entry point behind the intrinsic action, the combat cards' injury buttons,
and the sheet's Add Injury. The action's scope seeds the parameters (a
combat button forwards impact/aspect plus an aimed targetPart +
spread; the manual paths start from defaults); unless skipDialog, a
dialog lets a human confirm and tune them.
The flow (see the Injury rules): resolve the hit location (an explicit
bodyLocationCode, else derived from the target body part — a random
VITAL part when unspecified — and the strike spread); subtract armor
(an armorReduction applies only to a piercing aspect) to get the injury
level and severity; judge bleeding on a separately-boosted impact
(bleedImpactPenalty); and for a G5 edged wound at an amputable location,
roll a Strength test whose result may sever the location (fatal if it
is vital), make it bleed, or penalize the Shock Roll. It then records the
Trauma (when autoAddInjury) with the given treatment modifier and posts
the Resolve Injury card. Nothing is recorded for a no-injury result.
Dispatched as a normal chat-card action through the shared sohl.document.chat.dispatchChatCardAction chokepoint (issue #572).
The action context; its scope seeds the injury
parameters and skipDialog bypasses the configuration dialogs.
Set the being's shockState to level, the single entry point for
shock transitions. Clears every shock status effect and then applies
only the one for level (none for NONE) — so transitions are clean in
both directions and any stray multi-status situation is repaired. Only the
statuses that actually change are toggled.
The target shock-state level; clamped to [NONE, DEAD].
A promise that resolves once the statuses have been updated.
Sets up the intrinsic actions for this actor.
The action context to use for setup.
Resolve a Shock Re-Test (#556) for an Incapacitated or Unconscious being, attempting to shake off ordinary shock.
Rolls the being's Shock skill headlessly at −20 (the being's fatigue
penalty also applies; injury-impairment penalties do not) and applies the
result (shockReTestOutcome): a critical success recovers from all
shock, a marginal success improves to Stunned, and a failure drops the
victim into Extended Shock (a shock-subtype trauma at Healing Rate
4/5) — or, for an Unconscious victim on a critical failure, a Coma (a
coma-subtype trauma whose Healing Rate is 12 − Location Shock Value − Injury Level of the worst active wound). Both lasting-shock traumas then
recover through their own Course Test (see
sohl.document.item.logic.TraumaLogic.courseCheck).
A no-op (returns null) unless the being is Incapacitated or Unconscious.
The re-test is offered on the state's own cadence by
offerShockReTest (end of the being's own turn for Incapacitated,
ten minutes later for Unconscious): when due the event queue posts an
owner-gated [Perform] card, and the re-test runs only on the
controller's click — nothing auto-fires (Prime Directive: offer, remind,
perform).
The action context for the test; forwarded to the course-check schedule offer for any Extended Shock / Coma created.
The Shock re-test result, or null when no re-test applies.
Roll a Shock skill test (#850) — the general shock primitive. Shock is
not specific to injury: blood loss, fear, and other systemic or
psychological forces all drive a shock test by supplying a base Shock
State Index (SSI). The base SSI comes from context.scope
(shockIndex/baseShockIndex) for a scripted cause, or is collected via a
dialog when the action is run by hand.
The Shock skill is rolled without the body-part impairment penalty (the being's fatigue penalty still applies); the result adjusts the SSI (CF +2 / MF +1 / MS 0 / CS −1), which maps to a shock state (shockStateFromIndex). A base SSI below 5 is No Shock and above 10 is immediate Dead, with no roll (shockRollNeeded). The being is then offered the resulting state (worsen-only — a fresh shock never improves an already-worse state; recovery is the shockReTest, #556), and, if it enters ordinary shock, offered the Re-Test reminder.
The action context; scope.shockIndex/baseShockIndex
supplies the base SSI and scope.applyShockState pre-answers the
set-state offer.
The Shock-test result, or null when no roll was made or the
action was dismissed.
Roll the being's Stumble test (#851) — a "keep your footing" check a
combat mishap can flag (ATTACK_MISHAP.STUMBLE_TEST /
DEFEND_MISHAP.STUMBLE_TEST). Rolls the better of the being's Agility
attribute and its Acrobatics skill and posts a result card whose bespoke
keep-footing text comes from a keepControlTable passed in scope.
Offered, never auto-performed: it runs only when its controlling player picks the action (the mishap surfaces on the attack card as a prompt).
The action context for the test.
The success test result, or null if the test could not be run.
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.
The set of body-part roles the being currently cannot use — the roles
of every body part that is unusable (a grievous
injury or a permanent-unusable flag). A test whose governing skill or
attribute lists any of these roles in its impairedByRoles automatically
Critically Fails (#568).
The roles of every unusable body part (empty for an incorporeal being).
StaticdefineDefine and return all intrinsic actions for this logic type.
A map of action shortcodes to their definitions
A single person, creature, or NPC.
A Being is the most detailed actor type in SoHL, representing an individual entity with a full anatomy model (body roles, body parts, body locations), skills, traits, injuries, afflictions, gear, and mystical abilities. Beings are the primary participants in combat, skill tests, and social interactions.
The being's physical body — anatomy, body weight, reach, body-scale — lives on its own body sub-object (
system.body), dissolved from the former Corpus item into the Being (#535). Movement (feetPerRound/leaguesPerWatch/moveProfile) is a universal actor capability on sohl.document.actor.logic.SohlActorBaseLogic.BeingLogicadditionally derives movement's strengthModifier / encumbrance from its strength and carried weight, and being-owned state (healthBand plus the numericsystem.healthit writes, healingBase, shockState, pull, carriedWeight). An incorporeal being is one with an empty body structure (see sohl.document.actor.logic.BodyLogic).