Builds a single body part from its persisted data, resolving its held item and deriving its selection weight and child locations.
Persisted part data.
Construction options
Construction options for a BodyPart instance.
Zero-based index of this part within the flat structure.parts array.
This part's locations, each paired with its flat locations index.
The Logic that owns the entity. Required (the constructor throws without it) and transient — held in memory, never written to JSON.
Owning body zone (supplies actor and body-owner logic).
ReadonlycanWhether this part is a limb capable of gripping an item.
Optional ReadonlyheldThe item currently held by this part, resolved from heldItemId, or undefined.
ReadonlyindexZero-based index of this part within the flat structure.parts array.
ReadonlylocationsHit locations contained within this part, in persisted order.
ReadonlynameDisplay name of this part (falls back to the shortcode).
ReadonlypermanentManually-set permanent impairment for this part — a non-positive floor
the derived impairment can never be milder than (0 = none).
ReadonlypermanentlyManually-set flag marking this part permanently unusable (a withered or fully-amputated limb). Unlike permanent impairment, this makes the part unusable regardless of tier.
ReadonlyprobSelection weight for this part within its zone, derived from the persisted BodyPart.Data.probWeight. Once a zone is rolled, its parts are drawn in proportion to this weight.
ReadonlyrolesFunctional roles this part fulfills; see BodyRole in constants.
ReadonlyshortcodeUnique part identifier within the body structure (e.g. "larm").
ReadonlyzoneBack-reference to the owning sohl.entity.body.BodyZone.
Convenience predicate: this part affects mobility if it carries any of the mobility-relevant roles (VITAL, CORE, or LOCOMOTOR). Pure MANIPULATOR-tagged parts (arms, hands) don't drop a creature when injured, so their injury doesn't impair mobility.
Whether this part is critical for overall health — it holds a VITAL or CORE role. Critical parts drive the harsher health-ceiling column (#470).
The serialization discriminator for this instance — the concrete class's static Kind. Written into the JSON by toJSON under the kind key and read back by sohl.utils.defaultFromJSON to select the constructor. Derived from the class, never stored per-instance.
This part's position among its zone's parts, as opposed to
index, its slot in the flat structure.parts array. Drag-to-sort
addresses a destination by position; storage addresses it by index.
The BodyStructure this part belongs to, via its zone.
The dot-notation path prefix for Foundry update() calls targeting
this part's persisted fields, e.g. "system.body.structure.parts.2".
Build an update() payload that appends a new location to this part,
stamping it with this part's shortcode. The location lands at the end of
the flat locations array — and so at the end of this part's locations.
Persisted data for the location to append; its
bodyPartCode is overwritten with this part's shortcode.
A complete-array update() payload appending the location.
Deep-copy this entity, re-parenting the copy under parent with no other
changes. Shorthand for clone({}, { parent }).
The Logic to own the cloned entity.
The cloned entity.
Deep-copy this entity, optionally overriding fields and clone options.
Field overrides applied to the clone.
Clone options (e.g. a new parent).
The cloned entity.
Find a location by shortcode, or undefined if not found.
Shortcode of the location to find.
The matching location, or undefined if none matches.
Find a location by its zero-based index, or undefined if out of range.
Zero-based index of the location within this part.
The location at that index, or undefined if out of range.
Select a random location within this part, weighted by each location's BodyLocation.probWeight.
The random source; defaults to the shared sohl.random singleton. Inject a seeded generator to make selection reproducible.
A randomly selected location.
Build an update() payload that removes one of this part's locations by
shortcode.
Shortcode of the location to remove.
A complete-array update() payload with the location removed,
or {} when this part has no such location.
Serialize this instance to a plain object suitable for JSON serialization.
A plain object representing this instance, consistent with the
Data interface of the subclass.
The base emits only the kind tag. A subclass that adds state
overrides this, chaining ...super.toJSON(), and emits keys matching its
own Data interface in persisted form (a uuid/shortcode where the live
object holds a resolved reference). The governing rule: toJSON() output
must be valid data for the constructor. The transient parent is
deliberately not emitted — it is re-supplied on revival.
A body part containing one or more hit locations — e.g., "Head" (containing Skull, Face), "Left Arm" (containing Upper Arm, Elbow, Forearm, Hand).
Each part is tagged with one or more
BodyRoles describing which functional roles it fulfills (VITAL, CORE, MANIPULATOR, LOCOMOTOR). Skills and attributes declare which roles impair them; injury at a part impairs every skill/attribute that lists any of the part's roles. Mishap behavior (fumble/stumble checks) is also role-driven; see BodyRole in constants.Persistence: parts are stored in the flat
body.structure.partsarray and declare their owning zone via BodyPart.Data.bodyZoneCode. A part does not nest its locations — locations name their part via sohl.entity.body.BodyLocation.Data.bodyPartCode, and BodyStructure assembles the hierarchy at construction.Lifecycle: Rebuilt from persisted schema data on every preparation cycle. May be mutated during the lifecycle (e.g., modifiers applied by active effects), but mutations are not persisted — they are recomputed on the next cycle.