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

Core Runtime State

This chapter defines the portable state shared by the behavior in later chapters. It describes values and lifetimes, not a required memory layout.

Unless a version profile says otherwise, the rules in this chapter currently apply to the AGI 2.936 profile.

Byte variables

The game has 256 variables, numbered v0 through v255. Each stores an unsigned 8-bit value.

The common numeric operations have these value rules:

  • increment saturates at 255;
  • decrement saturates at 0;
  • addition and subtraction retain the low 8 bits;
  • multiplication retains the low 8 bits of the product;
  • division stores the unsigned 8-bit quotient; and
  • indirect operations use a variable’s value as the index of another variable.

Unsigned variable comparisons compare values in the range 0..255. Division by zero is outside the valid-bytecode contract until a defined observable result is added to this specification.

Some variables also have engine-defined roles. Those roles do not change the fact that scripts may read and write the same byte. In the current profile, v0 identifies the current room and v10 controls cycle pacing.

Flags

The game has 256 Boolean flags, numbered f0 through f255. Operations may set, clear, toggle, or test a flag directly, or use a byte variable as the flag number.

Some flags also carry engine-defined state. For example, sound playback tests f9, and room entry logic commonly tests a new-room flag. A subsystem chapter defines the observable meaning whenever an engine operation assigns one.

Strings and parsed words

The current profile exposes twelve string slots, numbered s0 through s11. Each slot has 40 bytes of storage. Operations that edit, copy, compare, or parse a slot define their own truncation and normalization rules.

Parsed input is distinct from string storage. The parser produces at most ten nonzero dictionary word identifiers, an optional unknown-word position, and parser status flags. Words whose dictionary identifier is zero do not occupy a parsed-word slot. Conditions that match parsed input consume this parsed state, not the original string bytes.

Logic activations

A loaded logic resource consists of bytecode, messages, and resumable execution state. The engine tracks a current logic activation containing at least:

  • the logic resource number;
  • the bytecode start;
  • the current instruction position; and
  • the resource’s message table.

Logic 0 is invoked once per top-level engine cycle. A logic may call another logic. Nested calls preserve the caller’s current activation and restore it when the callee returns.

Loading and executing are separate operations. A logic may remain loaded after execution, while a logic loaded only for a nested call may be discarded when that call returns. Explicit resume-position operations may save the current instruction position and later restore the logic’s entry position.

Resource lifecycle

Each resource family has an independent loaded-resource set keyed by resource number. The portable lifecycle is:

StateMeaning
UnloadedThe resource has no payload available to consumers.
LoadedDirectory lookup, volume reading, and expansion have produced the typed resource payload.
SelectedA logic activation, picture operation, object, or sound operation is using the loaded resource.
DiscardedThe resource is no longer loaded; a later use requires another load.

Loading an already loaded resource does not create a second game-visible identity or change its retention order. Successful first loads within each picture or view family establish an order. Discarding one of those resources also discards every resource loaded later in the same family. For example, if views 4, 9, and 12 were first loaded in that order, discarding view 9 leaves only view 4 retained. Views 9 and 12 must be loaded again before later use.

A valid discard names a retained resource that is not still selected by a live object or in-progress picture operation. Behavior that continues to use a discarded payload is outside the valid lifecycle contract. A family reset invalidates every retained resource in that family.

Room changes clear transient resource and object state, load the destination logic, update the current-room variables, and establish new-room state. The resource-event replay used by restore is specified separately from ordinary loading because replay must rebuild selected resources without recursively recording the replay itself.

Objects and inventory items

Persistent drawable objects are identified by an unsigned byte index. Their portable state includes:

  • current and previous position;
  • selected view, loop, and cel;
  • cel width and height;
  • step size and direction;
  • animation interval and animation mode;
  • motion mode and mode-specific parameters;
  • priority and control behavior;
  • participation in update and draw processing; and
  • collision, horizon, cycling, and direction-selection options.

The original storage representation is not part of this specification. Object operations are defined in terms of the fields and transitions above.

Inventory items have an item number, display name, and one-byte location or state value. Location value 0xff means the item is carried for the inventory selection operation.

Logical graphics state

The full-EGA target uses a logical picture area 160 cells wide and 168 cells high. Each cell has two independent four-bit values:

  • a visual color in 0..15; and
  • a priority/control value in 0..15.

Picture commands may modify either or both values. View cels contribute visual color and object priority according to the drawing rules. Normal display output shows the visual values; diagnostic priority display exposes the priority/control values.

The logical resolution is the compatibility coordinate system. A display backend may scale those cells to physical pixels as long as the resulting logical image and input coordinate behavior are preserved.

Top-level cycle order

Timer and sound ticks are asynchronous inputs to the cycle rather than an ordered substep inside it. Timer ticks advance the elapsed-time state and the cycle-pacing counter. While sound is active, sound ticks advance the playback state specified in the sound chapter. A deterministic conformance test must therefore supply the same tick and input-event sequence relative to cycle boundaries; an implementation does not have to reproduce interrupt delivery between individual bytecode instructions.

At each synchronous cycle boundary, the engine performs this observable order:

  1. Wait until the pacing counter reaches v10, then clear that counter for the next accumulation period.
  2. Clear all transient mapped-event status values and clear f2 and f4.
  3. Update due timed input sources, then process pending input and any requested modal menu interaction. This input phase clears the previous raw-key byte v19 and parser count/error byte v9 before consuming events. Mapped status events produced here remain visible to logic for the rest of the cycle.
  4. Apply the configured object-0/global-direction mirror.
  5. Perform the pre-logic autonomous-motion and configured-boundary pass for eligible objects.
  6. Remember the status-line values v3 and f9, then execute logic 0, including nested logic calls made by that bytecode.
  7. If logic execution requests immediate re-entry, clear v9, v4, v5, and f2, update the remembered v3 value, and invoke logic 0 again without repeating pacing, input, direction mirroring, or pre-logic motion. Repeat this rule until logic 0 completes normally.
  8. Restore object 0’s direction from the global direction byte. If v3 or f9 changed during logic execution and the status line is enabled, redraw the status line.
  9. Clear object event bytes v4 and v5 and cycle flags f5, f6, and f12. These values remain available to logic until this point.
  10. If alternate text mode is inactive, perform direction-based loop selection, animation timers, object movement, drawing, and dirty-region refresh. If alternate text mode is active, skip that entire post-logic object-update stage for this cycle.

v10 is the cycle-speed value. The pacing stage waits until at least that many timer increments have accumulated and then begins a new accumulation period. Lower values therefore permit faster logic cycles. A host may use a different clocking mechanism, but script-visible ordering and relative pacing must remain equivalent.

Calling the current room logic is not an implicit fifth engine stage. Games normally perform that dispatch from logic 0, commonly by calling the logic whose number is stored in v0.