The Trauma 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).
Effective seconds between blood-loss advances, as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.bloodLossAdvanceDurationBase.
The BodyLocation on the being's body that this trauma
affects, resolved from TraumaData.bodyLocationCode. When the
code is blank — or no matching location exists in the body — this
is undefined, indicating the trauma affects the whole body rather
than a specific location. Recomputed in evaluate.
Effective seconds between Extended Shock / Coma course checks, as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.courseDurationBase.
The target value of this trauma's Healing Test, as a
sohl.entity.modifier.ValueModifier — Healing Rate × Healing Base.
Active Effects keyed TRAUMA_EFFECT_KEY.HEALING (mod:logic.healing)
modify it, so what a wound is tested against is now open to influence
rather than an expression buried at the roll (#1181).
Effective seconds between healing checks, as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.healingCheckDurationBase.
How quickly the wound heals, as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.healingRateBase.
Trauma severity level (M1=1, S2=2, S3=3, G4=4, G5=5), as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.levelBase.
Treatment modifier for the trauma, as a sohl.entity.modifier.ValueModifier, seeded from TraumaData.treatmentModifierBase.
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.
Localized qualitative label for the current sub-category.
The category field is a sub-type-specific
enum: FEAR_CATEGORY for FEAR, MORALE_CATEGORY for MORALE,
FATIGUE_CATEGORY for FATIGUE, TRAUMA_PSYCOND_CATEGORY for
PSYCHOLOGICAL_CONDITION, TRAUMA_PHYSCOND_CATEGORY for
PHYSICAL_CONDITION — each mapped to its localized label. Other subtypes
(or an unrecognized value) return the raw category string, or an empty
string when unset.
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 the patient's injury healing is currently halted — true while
the owning actor carries any active infection-subtype trauma (an active
infection stops all Injury Healing Tests until every infection is defeated).
The owning document's id.
Whether the wound is actively bleeding. Derived (#482): true when the
blood-loss advance timer is armed — i.e. bloodLossAdvanceDurationBase
is set. A non-bleeding wound leaves that field null.
Whether the trauma has received medical treatment. Derived (#1148): true when a Healing Rate has been determined and a treatmentDate is set.
The Healing Rate is the source of truth. A null rate means no treatment
has established one, so the wound reads as untreated whatever date is on
record — a date cannot make a rate-less wound treated. A recorded rate of
0 is a real (catastrophic) rate, not an absent one.
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.
Localized qualitative label for the current effective level.
The graduated-level subtypes (Injury, Infection, Pall, Auralshock,
Fatigue, Psychological Condition) return the numeric level as a string.
Fear and Morale carry no numeric level — their qualitative state lives in
the category field, so they are labelled by categoryLabel.
The owning document's name.
The world time (in seconds) of this trauma's next scheduled recovery /
heal / course test, or undefined when none is scheduled.
This is a view-only derivation for the sheets — it reads the recurring
ScheduledAction the sub-type's recovery check runs on (mapped by
RECOVERY_ACTION_BY_SUBTYPE) from the generic system.scheduledActions
store and returns its anchor + interval. The
store is the source of truth: nothing is auto-armed (consent model,
issue #579), so an unscheduled trauma — or one whose only matching entry is
event-driven rather than time-based — reports undefined, which the sheets
render as an em-dash.
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.
The owning document's UUID — the opaque identity token from the data port.
Record a physician's Blood Stoppage Test result on this bleeding injury (#547) — run from the result card's owner-gated Accept button. The sohl.entity.body.BloodStoppageOutcome decides the effect: stop immediately (clear the bleeder), stop after the next advance (a flag the next bloodLossAdvanceCheck honors), continue +10 next (a bonus the next requestBloodStoppage applies), or continue.
The action context; scope.kind is the stoppage outcome
and scope.nextBonus the next-test bonus.
A promise that resolves once the outcome is recorded.
Intrinsic-action executor for the recurring auralShockRecovery — the *Check half
of this condition's cycle (#1181).
A *Check offers, and does nothing else: it posts a card whose button
invites the owner to perform one auralShockRecoveryTest. No roll is made and
nothing is written, so it imposes nothing and needs no ownership gate —
anyone may initiate a Aural Shock Recovery Check. The card carries this occurrence's due
time, so the test it offers can anchor its successor there rather than on
the moment the button happens to be pressed.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Aural Shock Recovery Test — the *Test half of
this condition's recovery cycle (#1181).
Rolls one headless Will test and applies its outcome; exactly one runs per invocation, however much world time has elapsed. The condition ends when its level reaches 0; otherwise the next test is offered, anchored on this occurrence's due time rather than on now.
The action context; scope.dueAt carries the occurrence's
due time and scope.schedule pre-answers the follow-on offer.
A promise that resolves once the outcome and schedule are persisted.
Intrinsic-action executor for the recurring bloodLossAdvanceCheck — the
*Check half of a bleeding wound's cycle (#1181).
Offers one bloodLossAdvanceTest and does nothing else: no blood is lost, no shock advances, nothing is written.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Blood Loss Advance Test (#487) — the
*Test half of a bleeding wound's cycle.
Applies one advance: Blood Loss Points accrue, the shock state advances one step per BLP, and 5 Fatigue Levels of weakness (anemia) are inflicted per BLP. Exactly one runs per invocation — a bleeding wound left unattended through several intervals costs one advance per consented test, not a silent cascade of them.
A physician's Marginal-Success Blood Stoppage stops the bleeding after the next advance (#547), so a pending stoppage is spent here. A wound that has stopped bleeding ends the recurrence; otherwise the next test is offered, anchored on this occurrence's due time.
The action context; scope.dueAt carries the occurrence's
due time and scope.schedule pre-answers the follow-on offer.
A promise that resolves once the outcome and schedule are persisted.
Intrinsic-action executor for the recurring courseCheck — the *Check half
of this condition's cycle (#1181).
A *Check offers, and does nothing else: it posts a card whose button
invites the owner to perform one courseTest. No roll is made and
nothing is written, so it imposes nothing and needs no ownership gate —
anyone may initiate a Course Check. The card carries this occurrence's due
time, so the test it offers can anchor its successor there rather than on
the moment the button happens to be pressed.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Course Test (#556/#557) — the *Test
half of an Extended Shock, Coma, or Infection's cycle.
Rolls one test, moves the condition's Healing Rate by the result, and settles the consequence: a rate of 0 or less is death (Extended Shock and Coma only — an infection's rate floors at 1 and never kills), 6 or better is recovery, and anything between leaves the course running and offers the next test anchored on this occurrence's due time.
A still-active infection saps the body by its Healing-Rate band each test (#557).
Exactly one test runs per invocation — a condition that can kill never resolves several rolls from a single click.
The action context; scope.dueAt carries the occurrence's
due time and scope.schedule pre-answers the follow-on offer.
A promise that resolves once the outcome and schedule are persisted.
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.
Re-arm this trauma's persisted schedules into the event queue on every
preparation, on every client (issue #588 generic store; #579 consent). The
recurrence anchor and interval now live in system.scheduledActions (the
retired bespoke last*Date anchors are gone); a reschedule update()
replicates, every client re-preps, and this generic re-arm restores the
queue — the active GM's included, which alone fires. The executors add,
offer to re-add, or clear those entries; finalize() never invents a
schedule of its own.
The context-menu options — the actions currently available — for this logic's document.
The available context-menu entries.
Intrinsic-action executor for the recurring healingCheck — the *Check
half of a wound's recovery cycle (#1181).
A *Check offers, and does nothing else: it posts a card whose button
invites the wound's controller to perform one healingTest. No roll
is made, no Injury Level changes, and nothing is written. Because it
imposes nothing it carries no ownership gate — anyone may initiate one.
The card carries the occurrence's due time in its scope, so the test it offers can anchor the next occurrence there rather than on the moment the button happens to be pressed.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Injury Healing Test (#486) — the
*Test half of the wound's recovery cycle, and the action that actually
mends a wound.
Rolls one test of Healing Base × Healing Rate — the healing
modifier, so an Active Effect can change it — and applies the result:
a marginal success reduces the Injury Level by 1 and a critical success by
2; a marginal failure makes no progress. A critical failure on an
infectable wound contracts an infection, which then halts all healing.
An untreated wound has no Healing Rate to test against, so its test resolves against a forced die rather than a cast one (#1148) — a Critical Failure every time, which by the same rule leaves it exposed to infection (UNTREATED, #1146).
Exactly one test runs per invocation: there is no catch-up over missed intervals. A wound that reaches Level 0 ends the recurrence and may leave a permanent impairment scaled by how long it took to heal (#554); otherwise the next test is offered, anchored on this occurrence's due time rather than on now.
The action context; scope.dueAt carries the occurrence's
due time (supplied by the check card) and scope.schedule pre-answers
the follow-on offer.
The resulting Injury Level, or null when the roll was refused.
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 executor for the recurring pallRecovery — the *Check half
of this condition's cycle (#1181).
A *Check offers, and does nothing else: it posts a card whose button
invites the owner to perform one pallRecoveryTest. No roll is made and
nothing is written, so it imposes nothing and needs no ownership gate —
anyone may initiate a Pall Recovery Check. The card carries this occurrence's due
time, so the test it offers can anchor its successor there rather than on
the moment the button happens to be pressed.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Pall Recovery Test — the *Test half of
this condition's recovery cycle (#1181).
Rolls one headless Will test and applies its outcome; exactly one runs per invocation, however much world time has elapsed. The condition ends when its level reaches 0; otherwise the next test is offered, anchored on this occurrence's due time rather than on now.
The action context; scope.dueAt carries the occurrence's
due time and scope.schedule pre-answers the follow-on offer.
A promise that resolves once the outcome and schedule are persisted.
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.
Intrinsic-action executor for the recurring psycheRecovery — the *Check half
of this condition's cycle (#1181).
A *Check offers, and does nothing else: it posts a card whose button
invites the owner to perform one psycheRecoveryTest. No roll is made and
nothing is written, so it imposes nothing and needs no ownership gate —
anyone may initiate a Psyche Stress Recovery Check. The card carries this occurrence's due
time, so the test it offers can anchor its successor there rather than on
the moment the button happens to be pressed.
The action context (unused; the check takes no input).
A promise that resolves once the check card is posted.
Intrinsic-action executor for the Psyche Stress Recovery Test (#560) —
the *Test half of a psychological condition's recovery.
Rolls one headless Will test (fatigue does not apply). MS/CS recover
−1/−2 PSY; a CF is a Grievous Stress — an indefinite condition becomes
permanent, or a permanent one gains +1 PSY. An indefinite condition
goes away when its PSY reaches 0; otherwise the next test is offered,
anchored on this occurrence's due time.
The action context; scope.dueAt carries the occurrence's
due time and scope.schedule pre-answers the follow-on offer.
A promise that resolves once the outcome and schedule are persisted.
Request a Blood Stoppage Test for this bleeding injury (#547) — the bleeder's owner posts an open action card that any Physician-skilled character's controller may answer. Mirrors requestTreatment; a no-op (warns) if the injury is not bleeding.
The action context (unused; entry point).
A promise that resolves once the request card is posted.
Intrinsic-action executor for requestTreatment — the injured character's
Request Treatment context-menu action. It posts an
action card bearing an open
Perform Treatment Test button (sohl.document.chat.SELF_HANDLER):
any player whose default character has the Physician skill may answer, and
the button pre-fills that physician's
sohl.document.actor.logic.BeingLogic.performTreatmentTest with this
wound's uuid. Nothing is rolled or recorded here — the card just invites a
physician; state lives in the posted card, so it may be ignored, answered
later, or superseded.
The action context (unused).
A promise that resolves once the request card is posted.
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).
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.
Record a treated Healing Rate on this wound — the Treat Injury action.
Self-sufficient: run from the wound's context menu it opens a dialog for the
Healing Rate; invoked from a physician's Treatment Result Accept button it
reads scope.healingRate with skipDialog, so the patient records the
physician's proposed rate with one click. A HEAL sentinel (only reachable
from a card) heals the wound outright.
Every value the dialog can yield is a Healing Rate — including 0, which
is the dire rate that leaves the wound making no progress, never a cure.
A wound whose rate is still undetermined (healingRateBase null) opens
the dialog blank rather than pre-filled with 0, and a blank
submission records nothing (issue #1087).
The action context; scope.healingRate supplies the rate
when present (card path), else the dialog gathers it.
The recorded Healing Rate, or undefined when none was supplied /
the dialog was cancelled or left blank.
Roll the Physician Treatment Test (#553), establishing this injury's Healing Rate and its special effects.
Intrinsic-action executor for the treatmenttest action. The wound's
aspect and severity band select the required treatment action and its
difficulty modifier (requiredTreatment); the owning being's
Physician skill is rolled headlessly at that modifier; and the result maps,
with the severity band, to the injury's
Healing Rate
(treatmentOutcome). A HEAL result heals the wound outright. The
resulting Healing Rate (with the aspect and any surgical mishap) then
determines the special injury effects — a bleeder (which arms the
blood-loss timer) and permanent-impairment eligibility.
With no owning being able to roll (a headless/GM context, until the interactive physician card of #547 exists), the treatment auto-resolves as though the Physician roll were a Critical Failure — the rule that "an untreated wound is resolved as though its treatment roll were a Critical Failure."
The action context for the test; forwarded to the blood-loss schedule offer when a treatment leaves the wound bleeding.
The success test result, or null for a non-injury/healed trauma
or a headless critical-failure resolution.
StaticdefineDefine and return all intrinsic actions for trauma logic, adding the treatment and healing test actions to those inherited from the base logic.
The intrinsic action definitions.
An instance of harm to a character.
Trauma represents wounds and damage sustained by a character. The subType discriminates the trauma's nature:
injury(bodily harm tied to a body location), or a mind/spirit/body condition —fear,morale,pall,psycond(psychological condition),auralshock,fatigue,infection,shock, orcoma.Each trauma tracks:
Trauma contributes to the character's overall shock state and (for physical subtype) interacts with the anatomy model (body roles, body parts, body locations) to determine hit location effects.
Trauma supports treatment and healing test actions.