# The script language LlamaMod's **script language** (version 2) is a small structured language in the style of the Script view. [`StratCompiler`](../../src/main/java/com/eliasmueller/llamamod/format/strat/StratCompiler.java) compiles it to strat assembly, and [`StratAssembler`](../../src/main/java/com/eliasmueller/llamamod/format/strat/StratAssembler.java) turns that into bytecode with the same checks as hand-written assembly. It is used by the editor's type editor (*Language: Script*) and by mods such as the [arena](arena.md). Complete reference: [notes/strat-language.md](../../notes/strat-language.md#script-language-stratcompiler--writing-new-behaviour); tests: `StratCompilerTest`. ## A first strat ``` // bobs one cell up and down and turns strat Bobber { alias base = v0 alias phase = v1 setModel(model:5) // any opcode: name(stack arguments) base = self.y + 1 // 1 = one cell phase = 0 on touched { // event handler (type 4), runs as a subroutine soundPlay(sound:6) } loop { phase = phase + 4deg self.y = base + sin(phase) turnLeft(4deg) yield // end of this frame } } sub wobble { // called with "call wobble", ends with return self.rotZ = sin(self.rotY) * 0.1 } ``` ## Building blocks | Construct | Notes | |---|---| | `strat Name { … }` | a type; its label `Name` is the entry point | | `sub name { … }`, `call name`, `return` | subroutines | | `alias name = v3` | a name for a variable; parameter names from the object schema are predefined | | `x = e`, `x += e`, `-=`, `*=`, `/=` | assignment; `x += 1` compiles to `inc` | | places | `vN`, alias, `gN`, `self.prop`, `player.prop`, `parent.prop`, `parent.vN`, `camera.` / `target.` / `boss.` / `dialog.prop` | | `if (c) { } else if (c) { } else { }` | | | `while (c) { }`, `loop { }`, `do { } while (c)` | a `yield` as the last statement of a loop becomes the loop's frame-ending back jump | | `switch (e) { case 1: … break default: … }` | C rules (fall through without `break`); case values are constants | | `break`, `continue`, `yield`, `end`, `remove` | | | `on touched { … }`, `on event(type[, param]) [slot n] { … }` | event handlers; touched needs `collisionOn<…>()` and `collRadius(…)` | | `op(e1, e2)` | **any opcode** by name: inline operands in `<>` (raw words), stack arguments in `()`; the count must match the opcode | ### Numbers * `10` and `10.0` are ten cells (fixed point); `1.5`, `90deg` as in assembly. * **Raw** integers: `215r` (= 215/4096) or hex `0x10`. Values inside `<…>` are always raw. * Operators over constants are folded at compile time with the VM's own fixed-point rules: `2 * 3 + 0.5` → `6.5`. * `use rawNumbers` switches to the version-1 rule (plain integers raw) – old scripts get it automatically. ### Operators (low → high precedence) `||` · `&&` · `|` · `&` · `==` `!=` · `<` `>` `<=` `>=` · `<<` `>>` · `+` `-` · `*` `/` · unary `-` `!`. In conditions `&&` / `||` short-circuit; in a value both sides are evaluated. ### References `model:N`, `anim:N`, `unit:N[+off]` or `unit:Name` (another custom type), `sound:N`, `tex:N` – indices into the level the code is compiled against. ## What the compiler does not do (yet) * no `for` loop, no typed variables (everything is a 32-bit word, fixed point by convention); * `spawn` takes raw type fields (`spawn<0, 16, 5, 0xC400, 3>(unit:…)`) – you must know the values the spawned type needs; * the Script view does not show event handlers as `on … { }` blocks. ## Tips * Look at an original type that does something similar first (Script panel) and copy its numbers – speeds, animation indices, sounds and type fields are level-specific. * Keep each frame's work small and always reach a `yield` in loops; a loop without a yield freezes the game. * Test in the game early: the compiler checks the code's form and references, not whether the object behaves well.