6.2 KiB
Object parameter schemas (strat bytecode analysis)
Registry in code: editor.tools.objects.Schemas (named, typed, documented parameters with ranges,
choices and waypoint meaning), statistics of all original instances:
src/main/resources/.../editor/tools/objects/type-stats.tsv (TypeStats). Types without a schema
fall back to raw values plus "values used in the original levels". Shown in the Inspector section
"Object parameters" and checked by the Problems panel (ObjectChecks).
How parameters reach the script
- MAP strat record: count n + index into the parameter pool. The level spawner FUN_0054cfc0 passes
a fake stack, FUN_0054bfc0 pops the n values into the new strat's variables 0..n−1
(
strat+0xF4= variable array). So parameter i = variable i of the strat code. - Values are 20.12 fixed point by convention (0x1000 = 1.0); booleans are 0 / 0x1000, counts and
world/chapter numbers
n << 12.
Strat VM (FUN_0054d180) – enough to disassemble
Word-coded: op = w & 0xFFFF. op < 0x45: table 0x5796BC, operand = signed high 16 bits, one
word. op ≥ 0x45: table 0x578FF4 + op·4 (up to 0x1F6), inline operand words read via the pc.
Inline lengths (found by decompiling all 337 handlers with headless Ghidra and following helper
calls): 1 word for 0x45 0xA5 0xA6 0xB1 0xB2 0xD0 0xD3 0xD7 0xDB 0x115 0x11C 0x14B 0x14D 0x162
0x167 0x175; 2 for 0xD4 (name: d4 ea rel); 5 for 0x94 and 0xE0 (spawn: FUN_00553170 reads
nParams + 4 type fields); 6 for 0x95 (spawn at offset); short 0x0C (event slot) has 2; 0x02/0x03
(debug print: count then items, 0x45/0xEA items have one extra word) are variable. A linear sweep
restarted at every d4 name site disassembles all 31 level WADs without desync and hits every MAP
strat entry (the entry is the name site). Strings live between strats.
| short op | meaning | short op | meaning |
|---|---|---|---|
| 04 n / 41 n | push / pop variable n | 06 n / 43 n | push / pop global n (0x6D9E8C) |
| 07 n / 40 n | push / pop own property n (FUN_00550E60 / FUN_005509F0) | 1C n / 37 n | player property |
| 44 v | push 16-bit constant | 14 / 15 / 16 | jz / jnz / jmp (pc+4+v·4) |
| 12 / 13 / 2B | jz / jnz / jmp + yield | 17 | switch (table at pc+4+v·4) |
Long ops used for the decoding: 45 push word, 49 add, 4A sub, 4B mul (fixed), 4C div, 4E eq,
4F lt, 53 gt, BC ne, BD/BE ge/le, AF not, B6 and-logical, B7/B8 bit or/and, 50/51 shl/shr,
AD/AE sin/cos (table 0x574318), AC floor, BF rand, 16E lerp, 54 set model, 8B radius (+0xFE),
83 +0xD2 (collision radius), A5/A6 set/clear strat flags (0x8000 floor collision, 0x40000 walls),
C2 update floor, 73/75/177 waypoint first/next/advance (+0x118 first, +0x120 current; next wraps
to the first node), FE move to waypoint, 178 "inside the box of the current and next waypoint
(x/z)", 192 level change (pops tribe, world, chapter), B4/8E die, E0/95 spawn.
Properties: 16 floor height, 17 floor material, 34–36 x/y/z, 37–39 rx/ry/rz, 3 waypoint
first/last bits, 4 waypoint field +26, 6–8 waypoint x/y/z, 9/10 waypoint rx/ry, 41 distance to
the player, 61–64 tribe/world/chapter/map, 202 distance to player (squared compare).
Camera globals: 47 horizontal distance, 48 height above the target, 29/44 yaw, 36–38 position
and 40–42 look-at of cut-scene cameras, 66 camera flag word, 95 progress bits.
Patterns: push var i; push 30; mul = seconds → frames; push var; push var; mul; pop var =
squared distance (radius).
Decoded types
Confidence: high = code read and behaviour seen in game; medium = code read; low = values only.
| Type | Parameters | Waypoints |
|---|---|---|
| Coin (high) | p0 snap to floor (drops onto floor, random spin), p1 falls (floor collision flag 0x8000), p2 no shadow | – |
| Coin5 (high) | p0 snap, p1 falls | – |
| Health | p0 snap, p1 no shadow, p2 falls | – |
| HealthFull, HealthGenerator, Wompy | p0 snap, p1 falls | – |
| Grapes, HealthBanana, ChargeBooster | p0 snap | – |
| RubyIdol | p0 falls, p1 snap | – |
| Secret (high) | p0 box mode (player inside the box of the 2 nodes, op 0x178) | box (2 nodes) |
| CoinLine / CoinCircle (low) | count (counted down), spacing / radius | – |
| Llama | p0 spawns a helper, p1 unused, p2 camera mode (global 107) | first node = camera start |
| CheckPointPost (high) | p0 collision radius (+0xD2, 0.2) | 1 node = respawn position + yaw (98 of 102) |
| LevelDoor (high) | tribe, world, chapter of the next level (7,7,7 = world finished); fires on material-16 floor of a tile in its cell (any height; often only in the swap model a RubyIdolDoor/other door object switches to when it opens) | – |
| CameraSide | p0 height (g48), p1 distance (g47), p2 yaw mode (1 node yaw, 2 node yaw or ±180°), p3 only below node y, p4 flag 0x10000, p10 several boxes, p11 height offset, p12/p13 alt. height/distance | box pairs, node 0 yaw = camera yaw |
| CameraLift | p0 yaw source (1 object, 2 player), p1 box test on helper strat, p3 smooth (g97), p4 height limit, p5 flag | box |
| CameraSetDistance | g82, g68, g83, height g48, g73 (each with a flag bit in g66) | – |
| CameraFocusPoint | radius², min height², max angle, height limit, 3 flags, blend factor | – |
| CutSceneCameraDirectional | p0 event bit (1..31), p1 mode, p2 wait, p3 disabled, p5 end mode | camera nodes: position, yaw/pitch = view (globals 36–42) |
| CutSceneTrigger | p0 character (floor snap, g72 counter), p2 radius², p3 event bit (skip if set in g95), p5 height check, p6 bits (1 face player, 2 not skippable) | camera path |
| ForcePlayerMovement | p0 active, p1 radius², p2 game state, p3 lock, p4 align yaw | target points |
| ObjectDontDropInBox, FallOffNoHurt | box mode (+ game state) | box |
| WaterReboundPoints | active | rebound points |
| RubyIdolDoor | p1 idols needed, p4 sign offset | – |
| CityGuard | p0 view range², p1 chase range², p2 event bit, p3 wall collision | patrol (wraps) |
| JumpingBeetleBlue, Spider, Bunny | times in seconds (×30), ranges² | patrol path |
The rest (~150 placed types) shows raw values with the original statistics. Next candidates: PressurePadDoor (bit field), TargetRopePlatform, CataSwingingBlade (speeds/angles), RiverLog. Tooling used (not in the repo): Ghidra script decompiling the handler table, a Python sweep disassembler with an op-name table, "parameter use" context dumps per type.