# Alligator Arena (`arena`, LEVELS) Package `mods/arena`: `ArenaMod` (writes `wads/T1L9M0nn.wad` + loading picture `T19n.COR`), `Arena` (level script, village base like the test world), `ArenaScripts` (the strat scripts, script language 2), `ArenaImport` (compile against a source level + `StpcMerge` import). Registered in `ModRegistry` (one line). Test-only: `ArenaTestMod` (src/test, script options). | Option | Default | Meaning | |---|---|---| | `lives` | 5 (1–10) | hits per alligator | | `waves` | 3 (1–5) | wave n has min(n, 2) alligators (3 waves = 5 alligators) | | `energy` | 4 (1–5) | llama energy cap (5 = game normal) | | `coins` | 1 (0–5) | EnemyCoins per hit (+5 on defeat, +5 bonus at the exit) | | `chapter` | 49 (32–49) | TestLevel chapter; a chapter already written by another mod → apply error; a stored 2–8 falls back to 49 | Only chapters 32–49: the coin counter `0x584F1C[world·6 + chapter]` and the flag byte `0x584EC8[…]` of world-9 chapters 2–31 overwrite other globals (chapter 8 = last played map, chapter 9 = furthest progress – verified, see [testlevel-chapters.md](testlevel-chapters.md)). The tally total (LNFO) is 2 placed coins + alligators · ((lives − 1) · coins + 5) + 5 bonus. Script options (`Arena`, tests/`ArenaTestMod`): `probe=true` (event probe 1.6 ahead of the llama), `master=false` (no alligators), `start=x,z,rot`, `debug=true` (HUD coin counter shows kills·100 + wave·10 + alive). ## Layout Island 10..30 in sea (death plane). Pit x/z 16..24 (sand), walls 1.1 high, corner towers. Llama (20.5, 18) facing +z, start camera node 1.6 behind (inside the pit). CheckPointPost (16.8, 16.8). Exit pad 1×1 cell at (20.5, 23.5), material 16, gate on the north wall; **ArenaMaster** stands on it. Alligator spawn spots (20.5, 22.2), (18, 21.8), (23, 21.8). Two Coins at the side walls. ## How it works `ArenaImport.append` compiles the units with `StratCompiler` and appends them to the STPC of **t1l4m002** (Jungle by day 2, has the Alligator), so `model:47`, `anim:98–104`, `sound:58–62` and `unit:56+0xf0` (EnemyCoin) / `unit:36+0x28` (Sparkles) are that level's. A unit may refer to an earlier one as `unit:@Name` (→ `unit:N+off`; the compiler has no `@label` references). `merge` imports the units into the village base like the editor's cross import (models, animations, textures, 3 sound samples, EnemyCoin/Sparkles shared), adds one prototype MAP record per type (nVars/slots/typeFlags/extra), then `LevelBuilder` builds the level. * **ArenaMaster** (12 vars, no model): `g104/g105 = −1`, 2 s, then per wave: move to a spawn spot, **yield**, `spawn<0, 16, 5, 0xC400, 3>(ArenaGator)`, `alive += 1`; waits until `alive == 0` (gators do `parent.v3 −= 1`), 1.5 s pause. Win: `g101..g103` = door target (1, 9, chapter), `g104/g105` = its cell (the llama's own material-16 check then ends the level too), 5 EnemyCoins, Sparkles every 8 frames, `endLevel` when the llama stands on the pad (as LevelDoor). Each frame `player.health2` is capped at `energy` (also after a respawn). * **ArenaGator** (spawned, 16 vars): the Alligator's model, collision (0x4000, 3 bones), particles and animations. `hitDamage = 1793` (1 | 256 | 512 | 1024). `on touched`: if `damageTaken & 1792` (kick 256, dive 512, charge 1024) → hit flag, else → "bit" flag. Main loop (switch state): 0 watch (turn to the player, after a timer snap if within 5 units and on the same floor ±0.4), 1 snap anim, 2 chase (speed up to 0.03 + 0.006·wave), 4/5 lunge and slow down (original numbers), 3 back off. Hit: lives −1, sound, green puff, `coins` EnemyCoins, blink 45 frames (alpha 0.25 + red ambient every 4 frames, no further hits), back off. Bite: back off and rest 90 frames. Clamped to the pit, y = floor. Last life: the original death (shrink, puffs, 5 EnemyCoins), `parent.v3 −= 1`, remove. The `aim` sub (ported L_03d0) writes g17..g20 so the llama's dive homes in on it. Fade-in on spawn (setAmbient 0→63). ## Engine facts found * **Compiled `on touched` handlers fire** (event type 4): probe in game – the llama walks into it, it removes itself and three EnemyCoins pop out and are collected (coin counter 3). * Contact: each side's `hitDamage` is copied into the other's `damageTaken`, both get event 4. Llama: kick = 256 (Action on the ground, anim 28, hind-leg collision bones), dive = 512 (Action while jumping: homes in on the target in g17..g19 that enemies' scripts publish, best distance g20), charge = 1024. The llama counts a contact as its hit if `damageTaken & hitDamage ≠ 0`, else `damageTaken & 127 == 1` → `loseHeart` + knock-back (the original Alligator has 513 = only the dive hurts it, a kick gets you bitten). * `spawn`: same fields as a MAP record (FUN_0054bfc0); `extra` = words for collision bones. A MAP-placed type that uses `collisionOn` needs collision type flags (0x28000 like Coin) – with 0 the game crashed (page fault in the heap allocator FUN_0041ae20). * `spawn` copies the strat's matrix/translation block, not `x/y/z`: after `self.x = …` the child appears at the old place unless the spawner yields first. * Energy 0: the game's "Weiter / Beenden" screen; Weiter restarts the level (all strats fresh). * The level tally after the exit showed "Münzen gesammelt 0 / 55" on chapter 8: 0 = the coin slot after endLevel wrote the last played map into it, 55 = LNFO of the Village base. Fixed: chapter 32–49 and recounted LNFO ("2 / 12" for 1 alligator with 1 life). ## Verified in game (apptest :24, Wine 6, load 3–9, 2026-11-07) * Probe (`probe=true;master=false`): handler fires, coins collected (counter 3). * Default options (energy 5 and 4 runs): alligator fades in, watches, snaps, chases, bites (HUD energy drops), backs off. Kicks (Z) hit: puff, blink, coins pop out, counter rises (1 → 13 over two waves); defeat with puff and coins; wave 2 brings two alligators (debug counter 122 = 1 kill, wave 2, 2 alive). Blind kicking dies in wave 2 → Weiter restarts the arena with energy capped again. * Win (`lives=1, waves=1, start=20.5,21,0`): one kick defeats it, bonus coins + sparkles on the pad, walking onto it → tally screen with the arena loading picture. * Not verified separately: the dive (jump + Action) as the hit (sequences mixed kicks and dives), the charge, waves 4–5, coins option values other than 1. ![fight](img/mods/arena_fight.jpg) ![defeat](img/mods/arena_defeat.jpg) ![win: bonus coins on the exit pad, tally](img/mods/arena_win.jpg) ## Tests `ArenaTest`: scripts compile for all option corners (EnemyCoin spawns = coins + 5, gator spawns = alligators, energy cap code only below 5); wave sizes; settings validation; registered; built level (CD): Llama, master on the exit cell with its vars, checkpoint, 2 coins, no LevelDoor, merged code decodes, master spawns the gator unit, gator spawns EnemyCoin, `lives` in the code; another mod's chapter → IOException; probe option. ## Issues / limits * Loading picture and tally use the TestLevel texts ("TestLevel Kapitel 49"). * The exit target is the arena itself (1, 9, chapter): it restarts after the tally. * Exiting chapter 49 unlocks "chapter 50" (progress 9/50); the map caps the cursor at 49 (checked).