# Strat scripts: reading and changing object behaviour Every object in the game – a coin, a squirrel, a moving platform, a camera – is driven by a small program, its **strat** (Argonaut's "strategy" scripts). The level editor shows these programs in the **Script** panel, lets you change their numbers (speeds, heights, timers, damage) and lets you create **your own object types** by copying a script and editing it. ![The Script panel showing Bucky's script](img/strat_script_panel.jpg) ## The Script panel Open it with **View → Panels → Script** (**Ctrl+Shift+K**), the **Open script** button in the Inspector's *Script* section, or click its tab in the bottom dock. | Part | What it does | |---|---| | **Type** | the code unit to show. A unit is one compiled script file and can hold several strats (Bucky + ThrowAcorn). Custom types are marked *[custom]* | | **Script / Assembly** | *Script* is a readable view with expressions, `if`/`else` and `loop`; *Assembly* is the exact instruction list (the language you write new types in) | | **Follow selection** | shows the script of the object you select in the viewport or the Outliner | | **Find**, **Next** | search the text (Enter = next match) | | **Uses** | lists every line that uses the selected line's variable, property or label | | **Edit value…** | changes the numbers of the selected line (also: double-click) | | **Clone as new type…** | copies this type into a new, editable object type | The side panel explains the selected line: what the instruction does, how many values it takes from the stack, its Argonaut name where known, and what properties like `floorHeight` mean. With nothing selected it lists the unit's parameters, which other scripts **spawn or reference** this one, and how many objects of it are placed. ### Reading a script * `self.x`, `self.rotY`, `self.floorHeight` are properties of the object itself; `player.…`, `parent.…` (the object that spawned it) and `camera.…` those of others. * `v0`, `v1`, … are the object's variables. The first ones are the **parameters** you set in the Inspector (*Object parameters*): parameter 0 = `v0`. Where the editor knows a parameter's meaning, the script uses its name (`snapToFloor`). * `g12` is a global variable shared by all scripts. * Numbers are in game units: `1.0` = one cell (or "true"), angles are written like `5.625deg`. Speeds and turn rates are **per frame** (the game runs at 30 frames per second). * `yield` ends the object's turn for this frame; a `loop { … yield }` runs once per frame. * `onEvent` installs a handler, for example "when the player touches me" (event type 4). * `spawn<…>(…)` creates another object, `address model:5` names a 3D model of the level. ## Changing numbers Double-click a line with a number (or select it and press **Edit value…**). Lines whose numbers can be edited show a tooltip; edited lines turn **orange**. ![Editing a constant](img/strat_edit_constant.jpg) * Type the new value as `1.5` (fixed point), `90deg` (angle), `42` or `0x2a`. The dialog shows the value in all three readings and refuses impossible ones (a `pushShort` holds only −8.0 … 7.99). * The change can be undone (**Ctrl+Z**) like every other edit. * It applies to **every object of that type** in the level, also to objects other scripts spawn. * It is saved in the project and written into the level when you build or play. Example: in the Coin's script, `self.y = self.floorHeight + 204` puts snapping coins just above the floor. Changing `204` to `1.5` makes them float one and a half cells high: ![Original and edited Coin script in the game](img/strat_coin_constant_ab.jpg) ## Your own object types **Clone as new type…** in the Script panel (or **Level → New object type from script…** for an empty template) opens the type editor: ![Creating a custom type](img/strat_clone_dialog.jpg) 1. **Name** – the name of the new type (letters, digits, `_`). 2. **Entry label** – where the script starts (for clones: the renamed strat). 3. **Type fields / parameters from** – which existing type's settings (parameters, waypoints, flags) new objects of this type start with. 4. Edit the source. **Check** assembles it and verifies the result; errors name the line. 5. **Create type**. The type appears in **Assets → Objects** and can be placed like any other. The new script is added to the level's code; the original type is not changed. Custom types are stored in the project (as text) and rebuilt every time it is opened. ### Editing and deleting your types Select an object of a custom type (or pick the type in the Script panel's *Type* list): * **Edit type…** (Script panel or the Inspector's *Script* section) opens the type editor with its script. Change it, **Check**, then **Apply**. Objects of the type that are already placed keep their place and run the new script. **Ctrl+Z** undoes the change. * **Delete type…** removes the type. If objects in the level use it, the editor tells you how many and deletes them together with the type (also undoable). ### Writing a script instead of assembly Set **Language** in the type editor to **Script** to write the behaviour in a structured language that looks like the Script view: ``` strat Pulser { alias size = v0 setModel(model:5) size = 1.0 loop { while (size < 4.0) { // grow to four times the size size = size + 0.05 scale(size) yield // wait for the next frame } do { // and shrink back size = size - 0.05 scale(size) yield } while (size > 1.0) } } ``` * Statements: `x = value`, `x += value`, `if (…) { } else { }`, `while (…) { }`, `loop { }`, `do { } while (…)`, `break`, `continue`, `yield`, `end`, `call name` (for `sub name { … }`). * Any instruction can be called by name with its values in brackets: `turnLeft(4deg)`, `scale(size)`; values that are part of the instruction go in `<>`: `collisionOn<0x8000>()`. * Places: `v0`… (or a name given with `alias`), globals `g12`, properties `self.y`, `player.x`… * Numbers mean the same as in the assembly: write `10.0` for ten (a plain `10` is ten 1/4096 steps), angles as `90deg`. * **Check** compiles and verifies; errors name the line. Switching *Language* back to *Assembly* shows the generated instructions. The full reference is in `notes/strat-language.md`. Language reference: every instruction is one line, labels end with `:`, comments start with `;`. `push 4deg` / `turnLeft` pushes a number and lets an instruction use it; `jmpYield label` waits for the next frame and jumps. The full syntax and the list of all 434 instructions are in the LlamaMod notes (`notes/strat-language.md`, `notes/strat-opcodes.md`). ## Tutorial: make the squirrel run in a circle Bucky, the nut-throwing squirrel of *Jungle at Night*, can run in a circle in two ways. Both are in one test level below: on the left the waypoint way, on the right the script way. ![Two squirrels running in circles, eight frames](img/strat_bucky_circle.jpg) ### Find out how Bucky moves 1. Import Bucky (**Assets → All worlds**, search "Bucky", drag it into the level). 2. Select it and open the **Script** panel. The script shows `wpFirst()`, `wpNext()` and `wpTurnToY(v1)` / `moveForwardQ(215)`: Bucky **runs along its waypoint chain**, turning with the rate in parameter 1 and moving 215/4096 cells per frame. 3. At every node it reads `self.wpParam` (the node's field **+26**): the low part chooses run (`0`) or jump (`1.0`, `2.0`), the high part `128.0` means "run on", `64.0` "wait until the player comes close". At the end: `if (!(!v0 && (self.wpEndFlags & 2))) goto …` – with **parameter 0** set the chain repeats instead of ending. ### Way 1: a circular waypoint chain (no script change) 1. With Bucky selected, delete its imported path (**Delete path** in the Inspector) and draw a new one with the waypoint tool (**N**): 12 nodes on a circle (radius 1.5–3 cells). 2. Select all nodes of the chain and set **Field +26** to `524288` (= 128.0, "run on without waiting"). 3. Set Bucky's **Parameter 0** to `1.0` (repeat the chain). Parameter 1 is the turn rate (`64.0` = 5.6° per frame; larger turns faster). 4. Play. After the last node Bucky continues with the first one – forever. ### Way 2: a scripted circle (custom type) 1. Select Bucky, **Clone as new type…**, name it `BuckyCircle`. 2. In the source, find the label `L_05b0:` (the start of the main loop) and insert before it: ``` push 3.0 popVar v9 ; animation state: running push 3.0 popVar v22 circle: push 4deg ; turn 4° per frame turnLeft pushShort 215 ; forward speed per frame moveForwardQ forceCollision pushProp floorHeight ; stay on the ground popProp y call L_0180 ; Bucky's animation routine jmpYield circle ; next frame ``` 3. **Check**, **Create type**, place a BuckyCircle from **Assets → Objects** and play. The circle's size is speed ÷ turn rate: 215/4096 cells × 90 frames per turn ≈ 4.7 cells around. ## Limits * Custom types can't be edited or deleted right after importing object types from another level in the same session – save and reopen the project first. * Big structural changes are up to you: the editor checks that the code is well-formed and that every model/animation/code reference points somewhere valid, not that the object behaves well. * Names of rarely used instructions are educated guesses (the opcode list shows a confidence for each). * Small constants stored as short numbers only accept −8.0 … 7.99 (see *Changing numbers*). * The Script view shows `while`, `do … while`, `switch`, `break` and `continue` where it can and `goto` where the original jumps don't form nested blocks (a few hundred places in the whole game); the Assembly view is always exact. * In the clone dialog, renaming the type doesn't yet rename the entry label or the name inside the script text – edit those by hand if you want them to match.