Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SOUP property descriptors

Script property operands (Object.name, for example Player.hide or Me.pos.vx) are resolved through an engine descriptor table. Each descriptor names one property and gives the byte offset of its field and the field’s width. The [refs] names of SOUP386.DEF select descriptors by name, case-insensitively.

The table has 226 descriptors in the order below. Offsets are hexadecimal byte offsets from the start of the actor record. The tag column is the descriptor’s type letter: b, w and d are one-, two- and four-byte values. An uppercase tag (or x, o, A) marks a field that holds a pointer to, or the body of, a sub-record. The dotted names that follow such an entry (anim.*, size.*) address fields inside that sub-record, and their offsets are relative to the sub-record rather than the actor.

Several descriptors name state that other documents describe by function: fall_flag is the falling-state byte, extra_flag the living-state byte, torch_timer the burning-torch byte, id the low-word runtime identifier, attribute the pointer to the 256-byte attribute table, origin the retained fall origin Y, under_surface the support surface code, and pos.vx, pos.vy and pos.vz the local Q8 position. grip[0], grip[1], scabbard[0] and scabbard[1] are the four signed words the loader copies from RAEX before attachment queries. A script write replaces the stored word with the low sixteen bits of the value, and later attachment queries read the stored word.

NameOffsetTagWidth
address0x0x4
next0x0O4
list0x4O4
parent0x8O4
linked0xcO4
grid0x10d4
id0x14w2
name0x16A4
ftype0x1ab1
sflags0x1bb1
runtime_local_list0x1cD4
runtime_locals0xc1b1
extra0x21D4
object_data0x25o156
static_data0xc1b1
loaded_matrix0xc2b1
data0xc3B4
header0xc7B4
pos.vx0xcbd4
pos.vy0xcfd4
pos.vz0xd3d4
slave_pos.vx0xd7d4
slave_pos.vy0xdbd4
slave_pos.vz0xdfd4
last_slave_pos.vx0xe3d4
last_slave_pos.vy0xe7d4
last_slave_pos.vz0xebd4
start_pos.vx0xefd4
start_pos.vy0xf3d4
start_pos.vz0xf7d4
last_pos.vx0xfbd4
last_pos.vy0xffd4
last_pos.vz0x103d4
last_valid_flag0x107b1
last_valid_pos.vx0x108d4
last_valid_pos.vy0x10cd4
last_valid_pos.vz0x110d4
angle.vx0x120d4
angle.vy0x124d4
angle.vz0x128d4
slave_angle.vx0x12cd4
slave_angle.vy0x130d4
slave_angle.vz0x134d4
last_slave_angle.vx0x138d4
last_slave_angle.vy0x13cd4
last_slave_angle.vz0x140d4
start_angle.vx0x144d4
start_angle.vy0x148d4
start_angle.vz0x14cd4
last_angle.vx0x150d4
last_angle.vy0x154d4
last_angle.vz0x158d4
move.vx0x15cd4
move.vy0x160d4
move.vz0x164d4
ov.vx0x168d4
ov.vy0x16cd4
ov.vz0x170d4
size0x174Z4
location0x1a5D4
yangle_change0x1a9w2
rope0x1abR4
rope_id0x1afb1
rope_wait0x1b0b1
slide_flag0x1b1b1
fall_flag0x1b2b1
jump_flag0x1b3b1
extra_flag0x1b4b1
extra_time0x1b5b1
action_flag0x1b6d4
action0x1bad4
action_time0x1beb1
arms_time0x1bfb1
jump_time0x1c0b1
jump_height0x1c1b1
origin0x1c2d4
origin_time0x1c6b1
origin_accum0x1c7d4
last_direction0x1cbb1
move_counter0x1ccb1
last_collide0x1cdb1
last_collide_count0x1d1b1
under_object0x1d4O4
under_surface0x1dcb1
surface_time0x1ddb1
ai_type0x1deb1
ai_mode0x1dfb1
ai_delay0x1e0b1
ai_var10x1e1w2
ai_var20x1e3w2
ai_length0x1e5d4
node_map0x1e9N4
node0x1edd4
dnode0x1f1d4
fdnode0x1f9d4
weapon_drawn0x1fdb1
torch_timer0x1feb1
hand_item0x200b1
hand_pos.vx0x201d4
hand_pos.vy0x205d4
hand_pos.vz0x209d4
hand_angle.vx0x20dd4
hand_angle.vy0x211d4
hand_angle.vz0x215d4
grip[0]0x219w2
grip[1]0x21bw2
scabbard[0]0x21dw2
scabbard[1]0x21fw2
sphere_object0x221S4
fsphere_heap0x229D4
fspheres0x22dw2
active0x237b1
hide0x238b1
dead0x239b1
invisible0x23ab1
combat0x23bC4
light0x23fL4
flat0x243F4
anim0x247M4
anim_list0x24bW4
frame0x24fw2
handle0x251w2
last_frame0x253w2
last_handle0x255w2
panic_group0x257w2
message_index0x259b1
broadcast_index0x25ab1
anchor0x25bb1
hook_data0x25cB4
script_data0x260B4
script_int0x264B4
script_pc0x268B4
script_return0x26cB4
script_rv0x270b1
script_ret_rv0x271b1
attribute0x272B4
local_index0x276d4
string_index0x27ad4
disable_script0x27eb1
task[0]0x27fB4
task[1]0x283B4
task[2]0x287B4
task[3]0x28bB4
task[4]0x28fB4
task[5]0x293B4
task_variable[0]0x297d4
task_variable[1]0x29bd4
task_variable[2]0x29fd4
task_variable[3]0x2a3d4
task_variable[4]0x2a7d4
task_variable[5]0x2abd4
task_status[0]0x2afb1
task_status[1]0x2b0b1
task_status[2]0x2b1b1
task_status[3]0x2b2b1
task_status[4]0x2b3b1
task_status[5]0x2b4b1
task_pause[0]0x2b5b1
task_pause[1]0x2b6b1
task_pause[2]0x2b7b1
task_pause[3]0x2b8b1
task_pause[4]0x2b9b1
task_pause[5]0x2bab1
task_timer[0]0x2bbw2
task_timer[1]0x2bdw2
task_timer[2]0x2bfw2
task_timer[3]0x2c1w2
task_timer[4]0x2c3w2
task_timer[5]0x2c5w2
task_variable2[0]0x2c7d4
task_variable2[1]0x2cbd4
task_variable2[2]0x2cfd4
task_variable2[3]0x2d3d4
task_variable2[4]0x2d7d4
task_variable2[5]0x2dbd4
task_variable3[0]0x2dfd4
task_variable3[1]0x2e3d4
task_variable3[2]0x2e7d4
task_variable3[3]0x2ebd4
task_variable3[4]0x2efd4
task_variable3[5]0x2f3d4
task_variable4[0]0x2f7d4
task_variable4[1]0x2fbd4
task_variable4[2]0x2ffd4
task_variable4[3]0x303d4
task_variable4[4]0x307d4
task_variable4[5]0x30bd4
anim.address0x0M4
anim.current0x0M2
anim.next0x2M2
anim.next_speed0x4M1
anim.frame0x5M2
anim.speed0x7M1
anim.speed_count0x8M1
anim.stop_flag0xaM1
anim.halt_flag0xbM1
anim.hold_flag0xcM1
anim.rep_count0xdM1
anim.rewind_flag0xeM1
anim.loop_count0xfM1
anim.sound_handle0x10M1
anim.real_frame0x11M1
anim.max_group0x12M1
anim.pos.vx0x13M2
anim.pos.vy0x15M2
anim.pos.vz0x17M2
anim.angle.vx0x19M2
anim.angle.vy0x1bM2
anim.angle.vz0x1dM2
anim.last_angle.vx0x1fM2
anim.last_angle.vy0x21M2
anim.last_angle.vz0x23M2
size.address0x0Z4
size.orientation0x0Z1
size.size.vx0x1Z4
size.size.vy0x5Z4
size.size.vz0x9Z4
size.pos.vx0xdZ4
size.pos.vy0x11Z4
size.pos.vz0x15Z4
size.psize.vx0x19Z4
size.psize.vy0x1dZ4
size.psize.vz0x21Z4
size.msize.vx0x25Z4
size.msize.vy0x29Z4
size.msize.vz0x2dZ4

Extra-time counter

extra_time is a receiver-owned unsigned byte. Script reads return values from 0 through 255; writes retain the low eight bits and change only that field. Actor allocation clears it with the rest of the actor record.

An admitted ordinary actor update leaves zero and 255 unchanged. Other values lose the nominal tick count, saturating at zero. This stage follows the early action and ledge work and precedes the ordinary motion-vector clear and the subsequent animation advance. Actors excluded from ordinary processing do not reach this countdown stage.

Successful torch-lighting and torch-dousing entry request their animation first, then assign their living state and clear extra_time. A refused entry leaves it unchanged.

Stored playback default

panic_group is the receiver actor’s stored playback default, separate from the installed PanicGroup attribute. Reads sign-extend its 16-bit word; writes retain the low 16 bits. A property write changes only the stored default. It does not request a group, replace the current or pending group, advance commands or dispatch animation sounds. Later request fallback and default comparisons consume the changed word. Ordinary default selection can overwrite it.

Actor allocation clears this word, including reuse of pooled records. Actor animation-control initialization also sets it to zero. The word belongs to the actor record even when no playback allocation exists. Object save records retain it in the packed actor image, and object restoration copies it back independently of the optional playback trailer.

Packed movement counter

move_counter is the actor’s unsigned packed movement-counter byte. Raw property writes retain the low eight bits and do not themselves request or advance animation or translate the actor. The forward startup phase occupies bits 4 and 5. A forward amount query below phase three performs its support admission before requesting animation. After animation admission it advances that phase, preserving the other bits. Phase three keeps the full amount and remains saturated. The byte clears with actor allocation, including reuse, and remains part of the saved actor body.

Vertical-motion timer

origin_time is the receiver actor’s retained queued/falling vertical-motion timer byte. Property reads are unsigned and writes retain the low eight bits. The vertical-motion consumers interpret that same byte as signed: queued motion uses it as the factor index and advances it with byte wrapping, while falling uses factor zero when the signed timer is nonpositive. A positive falling timer selects its factor and decreases by the sum of the two fine-tick increments, with byte wrapping. Model-controlled vertical motion skips these arithmetic updates. A property write does not initialize a fall or move the actor.

Actor allocation clears the byte, including reused pooled records. Jump entry initializes it to zero; ordinary fall entry initializes it to 30 when it records the fall origin. The timer remains part of the saved actor body, independently of playback allocation. It is distinct from the rope regrab countdown and extra_time.

Accumulated displacement

origin_accum is the receiver actor’s signed 32-bit accumulated displacement, shared by sliding and the pre-script queued/falling jump displacement. Property access retains the entire word and does not itself move the actor. Allocation clears it, including pooled reuse, and the saved actor body retains it. Jump initialization clears it; the first slide also clears it before adding the slide distance. Later slide responses add their distance with 32-bit wrapping.

The pre-script jump displacement compares this accumulator with its motion’s cap as a signed value. Below the cap, the candidate sum of accumulator and step wraps at 32 bits before the signed cap comparison. A clamped step is the cap minus the accumulator with 32-bit wrapping. When model-controlled motion does not suppress displacement, the selected step is added to the accumulator with 32-bit wrapping; only a positive step translates the actor. At or above the cap, the step is zero. Slide termination compares this same signed accumulator with the slide-hurt distance threshold.

Pending-action timer

action_time is the receiver actor’s unsigned byte timer for pending-action promotion, separate from the state-17 action-transition counter. Property reads are unsigned and writes retain the low eight bits. Allocation clears it, including pooled reuse, and the saved actor body retains it. The pending-action branch of SetAction clears it when it sets the pending directional bits.

The late jump-window stage adds the low byte of the nominal-tick increment with byte wrapping. A result greater than 36 merges the pending action word into the accepted word, clears the pending word and resets action_time to zero. A result of 36 does not promote. This timer update precedes the queued-motion and current animation gates that clear the directional low bits and decide jump entry. A raw property write does not perform promotion or start a jump.

Arms timer

arms_time is the receiver actor’s unsigned byte action-transition counter. Property reads are unsigned and writes retain the low eight bits. Allocation clears it, including pooled reuse, and the saved actor body retains it. The admitted state-17 transition assigns six after requesting its transition group.

The ordinary actor update consumes this byte using the signed-byte action-counter rule in SOUP.md: zero is unchanged; the early-clear test precedes wrapping tick subtraction and negative-result clamping. A raw property write does not request a transition group or change living state. This field is separate from the pending-action promotion timer action_time.

Pending directional action word

action_flag is the receiver actor’s pending directional action word. Property access preserves all 32 bits; the script integer carries the same bit pattern. Allocation clears the word, including pooled reuse, and the saved actor body retains it. A raw write does not reset action_time or execute an action.

The pending-action branch of SetAction sets its low two bits. The late jump-window promotion merges the entire pending word into the accepted action word, then clears the pending word. The later motion and animation gates clear only the low two directional bits, retaining the other bits. These words are separate from the queued-motion and falling-motion bytes.

Accepted directional action word

action is the receiver actor’s accepted directional action word, separate from pending action_flag. Property access preserves all 32 bits through the script integer’s bit pattern. Allocation clears it, including pooled reuse, and the saved actor body retains it. A raw write does not execute an action or reset the promotion timer.

The late jump-window stage consumes accepted low bits independently of whether the pending word was promoted on that update. A queued motion or a current group other than running or torch-running clears the low two bits of both words. Otherwise accepted bit zero selects running motion eight before bit one can select motion nine; consumption clears the low two bits in both words before jump admission. All higher bits remain unchanged. Promotion merges the entire pending word into the accepted word before these gates and consumption.

Runtime script-control property

disable_script is the receiver actor’s runtime script-control byte, shared by the enable and disable control natives. Property reads are unsigned and writes retain the low eight bits. The masks retain the independent script, hook, task, object and combat meanings documented in SOUP.md. The descriptor is distinct from sflags and from the actor’s attribute table.

Actor allocation clears this byte, including pooled reuse, and the saved actor body retains it. A raw property write stores the complete byte; control natives modify only their own mask and preserve the other bits. Ordinary stage admission reads this same byte.

Collision-metadata property

sflags is the receiver actor’s retained collision-metadata byte. Reads are unsigned and writes retain the low eight bits. It is independent of the runtime script-control byte disable_script and the actor’s attribute table.

Allocation clears the byte, including reuse of pooled actors, and the saved actor body retains it. On the static model-load path, a matching named ROB segment supplies its collision byte. The MPOB static-model fallback performs the same copy. Without a matching segment, that copy is skipped rather than assigning a new value. Live static face candidates retain this actor byte as support metadata. See actor model initialization for the model-load lifecycle.

AI lifecycle-selector property

ai_type is the receiver actor’s lifecycle-selector byte, shared by MyAiType and SetAiType. Reads are unsigned and writes retain the low eight bits. A raw property write replaces only this byte; it does not change the adjacent AI mode, health, the killed flag, or script-control masks.

Actor allocation clears the byte, including pooled reuse, and the saved actor body retains it. Combat entry uses selector six, while the ordinary IsDead predicate tests selector eight. The selected player’s independent death override can also make IsDead succeed. The selector is distinct from the dead property. See receiver AI type and dead actor default selection.

AI mode property

ai_mode is the receiver actor’s unsigned AI-mode byte, shared by MyAiMode and SetAiMode. Writes retain the low eight bits and replace only this byte. The adjacent ai_type lifecycle selector, the independent dead property, health, and script-control masks are unchanged. A raw mode write does not invoke a lifecycle transition.

Actor allocation clears the byte, including pooled reuse, and the saved actor body retains it. endCombat clears this mode while setting the lifecycle selector to one. See AI mode query and setter and AI lifecycle-selector property.

AI delay property

ai_delay is the receiver actor’s unsigned AI-delay byte. Reads return values from zero through 255 and writes retain the low eight bits. It is separate from the adjacent AI mode and lifecycle selector and from extra_time. Actor allocation clears it, including pooled reuse, and the saved actor body retains it.

The AI delay update retains zero and 255. For any other value, it compares the unsigned byte with the shared nominal tick count. A smaller value becomes zero; otherwise the low byte of the tick count is subtracted. The update then continues into lifecycle-selector dispatch even when the delay was zero or 255. GoToLocation invokes this update after selecting lifecycle state four and storing the requested location word.

One AI admission branch requires delay zero as well as a mode other than eleven before invoking its candidate service. In the successful path-selection branch, a delay of 255 becomes 64; other delay values remain unchanged. The temporary AI-state save and restore pair retains this byte alongside the mode, length and AI-variable state. Raw property writes invoke none of those services.

Position and angle history properties

last_pos.vx, last_pos.vy and last_pos.vz are the actor’s previous local position (the triple SetPosition writes alongside the current position), start_pos.* its saved start position (the triple SetStartPosition restores from and DistanceFromStart measures against) and last_angle.* the angle history that SetRotation stores with the local angles. Each is a four-byte field read and written whole, without a matrix refresh or any movement service; a write to start_pos therefore changes what DistanceFromStart reports, and a write to last_pos or last_angle changes only the retained history.

Stable-position and creation-angle properties

last_valid_flag is a byte and last_valid_pos.vx, last_valid_pos.vy and last_valid_pos.vz are three four-byte fields: the actor’s stable ordinary position record, a validity byte followed by the Q8 local position it holds. The stable recovery runs only while the byte is nonzero and restores the position from the record. Raw writes change only the fields, so a script can arm a recovery by setting the position and then the flag, or disarm it by clearing the flag.

start_angle.vx, start_angle.vy and start_angle.vz are the actor’s creation angles, four-byte fields. The orientation setter that actor creation, the player placement and the player swap use masks the angles to 0 through 2047 and stores them in the current angles, the angle history and this triple before it rebuilds the matrix; ResetRotation restores a component from it. SetRotation does not change it. A property write stores the whole value with no matrix refresh.

Motion triple properties

move.vx, move.vy and move.vz are the actor’s retained motion components, three four-byte fields read and written whole. The fall start and obstacle interruption clear them. The rope release service stores the jump-off speed in move.vz (the installed jump-off speed, plus the node’s measured speed for a non-player receiver, negative for a backward jump) and queued motion 24 reads its sign and magnitude to displace the actor, so a script write to move.vz while that motion runs changes the jump. A property write moves no actor and runs no service.

Slave pose properties

slave_pos.vx, slave_pos.vy and slave_pos.vz are the actor’s attached position and slave_angle.vx, slave_angle.vy and slave_angle.vz its attached angles, the pose the family update composes for an actor attached to a master; last_slave_pos.* and last_slave_angle.* hold the values the previous family update published. Each is a four-byte field read and written whole, without a matrix refresh.

Every family update copies the current attached position and angles into the last_slave_* fields, then stores the new composed position and the composed angles (masked to 0 through 2047) in the slave_* fields. An actor with a nonzero attr_slave takes its effective position and angles for queries from slave_pos and slave_angle and every other actor from its local position and angles, so a property write changes what distance and placement queries see for an attached actor until the next family update replaces it, and changes nothing for an unattached one.

Task slot word properties

task_variable[n], task_variable2[n], task_variable3[n] and task_variable4[n] (n from 0 through 5) are the four 32-bit words that task slot n of the receiver retains for its native handler. The task resume pass copies them into the shared native command scratch before the handler runs and copies the scratch back afterwards, so a property write to a slot is what the next resumption of that slot sees, and a property read shows the state saved by its last resumption. The words are:

  • task_variable: the first native continuation word (the loaded image resource of AnimateGXA).
  • task_variable2: the pause countdown in nominal ticks that point-walk handlers decrement before doing any other work.
  • task_variable3: the third word, the second native continuation word of handlers such as FxPhase; point-walk handlers also hold the 32-bit command value here, which the wrapper copies to and from the actor’s AI length.
  • task_variable4: the packed command word (low 16 bits), phase byte (bits 16 to 23) and counter byte (bits 24 to 31).

Each is read and written whole. A property write moves no handler and clears no slot; a slot that is empty or paused keeps whatever the resume pass last stored for it.

Task slot control properties

task_status[n] and task_pause[n] are bytes and task_timer[n] a 16-bit word of the receiver’s task slot n (n from 0 through 5), kept in parallel arrays beside the slot’s call word. A property read zero-extends a byte and sign-extends the timer; a write keeps the low byte or word.

  • task_status is nonzero while the slot blocks its thread: allocation stores one for a blocking task and zero for a multitask. The task pass adds the status of every unpaused occupied slot, so a status of any nonzero value blocks.
  • task_pause pauses the slot while nonzero. TaskPause stores one, TaskResume zero, and the task pass skips a paused slot without invoking its handler or advancing its timer.
  • task_timer is the invocation counter. Allocation stores one; each pass invocation derives its elapsed input from the counter times the frame scale shifted right by eight, then increments it with 16-bit wrap.

A slot whose call word is zero is empty and is skipped whatever its three bytes hold. Completion of a handler clears the call word and the status and leaves the pause byte and the timer as they are. TaskStop clears the call word, status and pause of every matching slot and leaves the timer. Allocation overwrites all three. A property write changes only the field: it removes no call, runs no handler and cancels no native state.

Animation record properties

The anim.* properties address the receiver’s animation record. A property read extends a byte with zeros and a word with its sign; a write keeps the low byte or word, runs nothing and validates nothing until playback uses the value. An actor without an animation record reads zero. The fields the playback routines keep there are:

PropertyContents
anim.currentcurrent group, signed word, -1 for none
anim.nextpending group, signed word, -1 for none
anim.next_speedpending-speed byte: every request stores its speed modifier, then adds the countdown byte of the group it selected (a request that finds no group leaves just the modifier). Selecting the group reads it into anim.speed and leaves it in place, so it stays readable with no request pending; writing anim.next changes only the pending group, which a later selection then runs with the stored byte
anim.framesigned command cursor of the current group
anim.speedcountdown reload byte, taken from anim.next_speed when the group is selected
anim.speed_countframe countdown byte; the cursor advances when a tick finds it zero, and it reloads from anim.speed before dropping once
anim.stop_flagexit marker
anim.halt_flagBreakPoint translation suppression: one after a BreakPoint, cleared again by every cursor step
anim.hold_flagwait byte: zero runs, 255 holds indefinitely, other values lose the tick input per update before playback resumes
anim.loop_countfinite loop countdown byte
anim.rewind_flagreverse playback when the byte is one
anim.sound_handleremembered sound slot, 255 for none
anim.real_framewrapping frame-progress byte

Selecting a group clears the cursor, progress byte, stop, halt, hold, loop and rewind bytes and the repetition byte, sets the sound slot to 255 and the countdown to the reload byte. A property write therefore changes only the written field: a script that writes anim.speed_count to zero makes the next tick with nonzero input advance the cursor and count one frame, and writing anim.hold_flag to 255 stops all playback until it is cleared. anim.current is the group whose command table the playback interprets: each advance reads the table and the type byte of the group the word names, so a write switches both while the cursor, countdowns, loop, repeat and markers stay, like a ChangeAnimGroup that keeps the cursor. The word -1 leaves no current group, and the next advance selects any pending request. A group without a table is dereferenced at the next advance. anim.max_group is the low byte of the RAHD anim_control_prefix field, stored when the animation record is built. anim.rep_count is the repeat byte of the ConditionalDelay and LoopControl commands, and anim.pos.* and anim.angle.* are the 16-bit translation and rotation words those and the translation commands retain until the next frame step; they are read sign-extended. anim.last_angle.* are the three rotation words the model refresh copied from anim.angle.* the last time it ran for the actor: the refresh applies the difference of the two to the model’s orientation and then stores the current words as the history, whenever the record has a current or a pending group. A script write replaces a history word like any other field.

Rope wait property

rope_wait is the byte at record offset 0x1b0. A rope attachment clears it; a rope release sets it to 24. The per-update rope grab check counts it down by the update’s nominal ticks, and when the count reaches zero it also clears the byte that names the last rope (rope_id); while it is nonzero the grab skips the rope that byte names. The late collision stage reads it as a recovery window (values within 3 of 24) and the fall clears it. The weapon routines leave it as it is.

Heading change property

yangle_change is a signed word the model refresh stores for an actor that is not attached to a rope: the Y angle minus the Y angle the ordinary update saved when it began (the last_angle history), truncated to sixteen bits. The family composition of an attached actor stores its composed history angle instead. Nothing in the executable reads the word; scripts may read and write it like any other field.

Frame properties

frame is the frame index the last selected ShowFrame command names inside its model (the second of the two fields the loader patches into the command), a signed word that is -1 until a group selection reaches its first frame. last_frame is the same word as it stood when the actor’s last ordinary update began. The word that precedes them, handle, is the runtime model handle from the command’s first patched field.

Killed, weapon-drawn and invisible properties

dead, weapon_drawn and invisible are bytes of the receiver’s actor record. dead is the killed marker: KillMe sets it, Resurrect clears it, and the ordinary update loops test it before running a receiver, so a script that writes it nonzero is no longer updated. It is distinct from the ai_type lifecycle selector. weapon_drawn is the byte the equipped-weapon draw and cleanup routines set and clear and that the weapon predicates test. A property read returns the unsigned byte and a write keeps the low eight bits, without running any of those routines.

invisible is a separate byte that only the draw stage reads. The world render loop still updates the frame and refreshes the model of an actor whose invisible byte is nonzero, and skips the calls that draw its body, so scripts, animation and collision continue while the body is not drawn. The hide byte, by contrast, removes the actor from the whole block.

Runtime identifier property

id is the receiver’s low-word runtime identifier, the signed 16-bit value MyId returns. A property read sign-extends it to the script integer width. The identifier is the key name lookup, route-node ownership and the saved-actor identity check use, so a script that stores to it changes which actor those services find.

Held-item and surface-time properties

hand_item is the byte HandItem assigns (see held-item assignment), zero when no item was ever assigned. A script write replaces the whole byte, so a stored value reads back as its low eight bits, zero-extended; the weapon draw and item-use checks test the byte for zero and for the item numbers they name.

surface_time, jump_time, jump_height and anchor are plain bytes: no engine routine reads or writes the actor-record bytes they name (the jump_time and jump_height attributes are separate fields). Each is zero until a script stores to it and then keeps the low eight bits of the stored value.

Message selection properties

message_index and broadcast_index are the receiver actor’s unsigned selection bytes for its message channel and for the broadcast channel: the cursors the message natives (ReceiveMessage, DeleteMessage, IsMessageWaiting, GetMessageSender and its identifier form) and the broadcast natives (ReceiveBroadcast, DeleteBroadcast, IsBroadcastWaiting, GetBroadcastSender and its identifier form, ReplyBroadcastSender) read and advance. Property reads are unsigned and writes retain the low eight bits, with no clamp to the entry count: a stored value outside the queue is used unchecked by the natives. Actor allocation clears both bytes, including pooled reuse. A raw write moves no cursor service and changes no entry.

AI record properties

ai_var1 and ai_var2 are two-byte fields and ai_length a four-byte field in the actor record’s AI block next to ai_delay. A property read sign-extends a two-byte field and returns a four-byte field whole; a write keeps the low sixteen bits of a two-byte field and all of a four-byte one. Actor allocation zeroes the record and then sets ai_var1 to minus one (the word 0xffff), leaving ai_var2 and ai_length zero, including for pooled reuse. GoToLocation stores the low sixteen bits of its location argument in ai_var1, and its sentinel test reads that word back as a signed value.

node, dnode and fdnode are the actor’s held current, next and final-destination walk-node indices, and node_map the walk map they index; the previous-next record sits between dnode and fdnode. Allocation sets the three indices to minus one and node_map to null. Assigning the current node first copies a held next node into the previous-next record; the next-node assignment and the walk code move the held values between the fields. A raw property write stores the value without claiming or releasing a node reservation.

The HeaderHook diagnostic prints node, dnode, ai_length as signed integers and both variables as signed sixteen-bit values. The temporary AI-state save and restore pair retains ai_length and ai_var1 with the mode and delay. Raw property writes invoke no AI service.