# Strats: how objects work Every object in the game – a coin, a squirrel, a moving platform, a camera, the llama itself – is driven by a small program called a **strat** (Argonaut's "strategy" scripts, inherited from Croc). The programs are compiled bytecode for a virtual machine in `groove.exe` (`FUN_0054d180`). LlamaMod can read every one of them, change their numbers, write new ones and move them between levels. | Page | For | |---|---| | this page | how the VM works: units, instances, frames, variables, events, spawning, collision | | [Reading scripts](reading-scripts.md) | the editor's Script view and the assembly listing, with a worked example | | [The script language](script-language.md) | writing new behaviour in LlamaMod's structured language | | [Customising strats](custom-types.md) | changing constants, cloning types, custom types in the editor and in mods | | [Example: the Alligator Arena](arena.md) | a complete minigame written in the script language, explained step by step | | [Example: the roller coaster](roller-coaster.md) | a new ride for the original coaster cart: how the ride works, track and waypoint data, speed patch | Lab notes and tables: [notes/strat-opcodes.md](../../notes/strat-opcodes.md) (all 434 opcodes with semantics, confidence and Argonaut names), [notes/strat-language.md](../../notes/strat-language.md) (complete syntax), [notes/editor-object-schemas.md](../../notes/editor-object-schemas.md) (parameters of individual types). Machine-readable tables, used by the editor and the compiler: [`ops.tsv`](../../src/main/resources/com/eliasmueller/llamamod/format/strat/ops.tsv), [`props.tsv`](../../src/main/resources/com/eliasmueller/llamamod/format/strat/props.tsv). ## Code units and types The strat code of a level sits at the end of its STPC chunk as a list of **code units**: `u32 nUnits`, then per unit `u32 nWords` and the words. A unit is one compiled source file and can contain several strats plus their name strings and data (for example `Spider` + `RopeForSpider`). The village has 53 units, Lab 1 has 65. A **type** is just an entry point into this code: a MAP record or a `spawn` instruction names a byte offset in STPC, and the code there starts with `debugName "Name"`. Code refers to models, animation sets and other code by **absolute STPC offsets** – which is why STPC cannot be rearranged without relocating every reference, and why each level carries its own copy of the code of every type it uses. LlamaMod's disassembler covers the code of all 34 level WADs (1461 units, 670 555 words) and assembles every unit back **byte-identically**. ## One frame in the life of a strat The VM is a **stack machine** that runs every live strat once per frame (30 frames per second): 1. The strat continues where it stopped last frame. 2. It executes instructions – push values, compute, read and write properties, play animations, move – until it reaches a **yield** (`jmpYield`, `jzYield`, `callYield` …). 3. At the yield its turn ends; the next strat runs. Next frame it continues after the yield. So a typical object is "set up, then `loop { …; yield }`", and anything that takes time is a loop that counts frames. Speeds and turn rates in scripts are **per frame**. `end` / `remove` deletes the strat; `return` returns from a `call`. ## Data a strat works with | Kind | Syntax | What it is | |---|---|---| | **variables** | `v0`, `v1`, … (or an alias name) | the strat's own variables (count = the type's *nVars*). The first *n* hold the instance's **MAP parameters** | | **properties** | `self.x`, `self.rotY`, `self.floorHeight`, `self.damageTaken` … | 194 named engine fields of the strat: position, rotation, floor under it, distance to the player, animation state, alpha, collision damage … | | other strats' properties | `player.x`, `parent.v3`, `camera.…`, `target.…`, `boss.…`, `dialog.…` | the player, the strat that spawned this one (`parent`), the camera and a few registered special strats | | **globals** | `g0` … | shared by all strats; the engine itself never reads most of them – their meaning comes from how scripts use them (e.g. g95 = event bits, g101–g105 = exit target and cell, g17–g20 = dive target) | | **numbers** | `1.0`, `90deg`, `204r` | 20.12 fixed point (4096 = 1.0 = one cell); angles 0x1000000 = 360°; `r` marks a raw integer | Binary operators pop *b* (top) then *a* and push `a op b`; comparisons push 0/1; `mul` = a·b >> 12. ## Events A strat registers **event handlers** in its slots (`onEvent`, in the script language `on touched { … }` / `on event(type, param) { … }`). When the event fires, the handler runs like a subroutine. Known event types: | Type | Fires when | |---|---| | 4 | **touched**: contact with another strat (pick-ups, enemies). Needs collision (`collisionOn` + `collRadius`) | | 0x40 | timer | | 0x80 / 0x100 | player distance | ## Spawning `spawn(arguments…, unit:N+offset)` creates a new strat from code: the five inline values are exactly the type fields of a MAP record ([Objects](../reference/objects.md#strat-record-58-bytes-certain-unless-noted)), the stack arguments become the child's parameters, and the child's `parent` is the spawner. Facts found the hard way (by the arena): * The child appears at the spawner's **matrix position** of the last frame, not at its current `x/y/z`: after `self.x = …` the spawner must **yield** before spawning. * A type that uses collision needs collision type flags (e.g. 0x28000 like Coin) and enough `extra` words for its collision bones – otherwise the game crashes in the heap allocator. * The strat pool must have room for every spawned strat (`poolExtra`). ## Collision and damage On contact, each side's `hitDamage` is copied into the other's `damageTaken`, and both get event 4. The llama's attacks set bits in its `hitDamage`: **256** kick (Action on the ground), **512** dive (Action in the air; it homes in on the target an enemy publishes in g17–g19), **1024** charge. The llama counts a contact as *its* hit if the other's `hitDamage` shares a bit with its own, otherwise `damageTaken & 127 == 1` costs it a heart and knocks it back. The original Alligator has 513 (= 512 | 1): only the dive hurts it, a kick gets you bitten. ## References to level data Some operands are indices into the level's own data and differ between levels; the cross-level import rewrites exactly these: | Operand | Points to | |---|---| | `model:N`, `anim:N`, `unit:N[+off]` (`address`, opcode 0xb2) | a model, an animation set, code of a unit; negative = shared animations in `DEFANIM.WAD` | | `sound:N` (opcode 0xd7) | a sample of the level's sound bank | | `text:N` (opcodes 0xf0, 0xfa) | a dialogue line in LGPC | | `tex:N` (pushed before texture opcodes) | a texture entry (shadows, sprites, particles) | ## How the names were found All 434 opcodes (0x000–0x1b1) were named by decompiling every handler with Ghidra; 252 of them match Argonaut's own names from the Croc 2 PlayStation demo's jump table and the Croc 1 decompilation (knowledge only, no code used – see the sources in [notes/strat-opcodes.md](../../notes/strat-opcodes.md#sources)). Confidence: 353 high, 79 medium, 2 low; high-confidence opcodes cover 97 % of all instructions in the levels. The names of rarely used opcodes and properties can still be wrong.