Files
llamamod/docs/strats/reading-scripts.md
T

4.9 KiB
Raw Blame History

Reading scripts

LlamaMod shows every strat in two forms: the Script view, a readable reconstruction, and the Assembly listing, the exact instructions. Both are in the level editor's Script panel (View → Panels → Script, Ctrl+Shift+K); the user-level walkthrough is manual chapter 22.

The Script panel with Bucky's script

Code: StratListing (assembly), StratPseudo (script view), OpTable (names and help texts).

Example: the Coin

Script view of the village coin:

strat Coin:
setModel(model:5)
collRadius(409r)
onEvent ev_0000, 0  // event type 4 → L_0084
if (v1) { collisionOn<32768>() ... }
if (v0) {
    if (self.floorMaterial == -1.0) { skipArgs … } else {
        self.y = self.floorHeight + 204r
        self.rotY = rnd(4096.0)
    }
}
loop { turnLeft(5.625deg); yield }

Line by line:

Line Meaning
setModel(model:5) show model 5 of this level's STPC (the coin)
collRadius(409r) collision radius 409/4096 ≈ 0.1 cell
onEvent ev_0000, 0 install the handler table entry ev_0000 in slot 0: event type 4 (touched) jumps to L_0084, the pick-up code
if (v1) … parameter 1 switches collision on
if (v0) … parameter 0 (snapToFloor in the editor) puts the coin 204/4096 ≈ 0.05 above the floor under it and turns it randomly – unless there is no floor (floorMaterial == -1)
loop { turnLeft(5.625deg); yield } spin 5.625° per frame, forever

Changing 204r to 1.5 makes every snapping coin float 1.5 cells high – that is a constant edit (Customising strats).

Script view conventions

You see It means
self.x, player.y, parent.v3 property or variable of this strat, the player, the spawner
v0, snapToFloor variable 0; named when the editor knows the type's parameter
g12 global variable 12
1.0, 5.625deg, 204r fixed point (1.0 = one cell), an angle, a raw integer (204/4096)
op<a, b>(x, y) instruction op with inline operands a, b and stack arguments x, y
loop { … yield } runs once per frame
while, do … while, switch, break, continue, break name rebuilt from the jumps
a && b, a || b short-circuit conditions (chains of conditional jumps)
goto L_xxxx jumps that do not form nested blocks – 31 places in the whole game, all one pattern in the llama's script

The script view is a reading aid and is not compiled back. Edits happen on the assembly (or in the script language for new types).

The assembly listing

One instruction per line, exactly as stored:

Coin:
        debugName "Coin"
        address model:5                      ; model
        setModel
        onEvent ev_0000, 0                   ; event type 4 → L_0084
        pushVar snapToFloor                  ; v0 (alias from the object schema)
        jz L_018c
        ...
L_0218:
        push 5.625deg                        ; = 64.0
        turnLeft
        jmpYield L_0218
        end
  • Short opcodes (below 0x45) carry a signed 16-bit operand: pushVar v3, pushShort 1.5, jz label. Long opcodes take inline words: spawn 3, 6, 0, 0, 0.
  • Directives: .unit, .alias, .word, .string, .event, .switch / .case, .at.
  • Disassemble → assemble is byte-identical for all 1461 units of the game; no instruction is emitted as raw words.

Full syntax: notes/strat-language.md. Every opcode with its stack effect and meaning: notes/strat-opcodes.md.

Finding things

  • Which script runs this object? Select it with Follow selection on.
  • Who spawns this type? The side panel lists the units that reference it.
  • What does this instruction do? Select the line; the side panel shows the opcode's semantics, stack effect, Argonaut name and confidence.
  • Where is this variable used? Uses lists every line with the selected operand.
  • Outside the editor: tools/strats.py level.wad --all lists every named strat of a level with code offsets and type fields; notes/strat_types_table.md shows which level has which type.

Typical patterns

Pattern Meaning
v1 * 30 seconds → frames
self.distToPlayerSqXZ < 25 player within 5 cells (squared distance)
turnTowardAngleY(self.angleToPlayer, 2deg) turn towards the player, 2° per frame
if (!self.animPlaying) animPlay(anim:N) loop an animation
wpFirst(), wpNext(), self.wpParam walk the waypoint chain; per-node parameter
g95 = g95 | (1 << (v - 1)) set an event bit that guards wait for