testlevel chapters 2-31 overwrite game memory (coin counter and flag rows end after world 8: progress, language, options): level projects, play-tests and the arena use chapters 1 and 32-49, old settings migrate; level tally counts the level's own coins and secrets

This commit is contained in:
MineTec committed 2026-11-07 15:27:08 +01:00
1 parent 987b0104fa
commit d6b852a1b6
35 files changed
+1015 -175

No files matched your search

+16 -6
View File
@@ -35,6 +35,16 @@ properties). Language/syntax: `notes/strat-language.md`. Disassembler/assembler:
getter FUN_00550e60 and setter FUN_005509f0 share the numbering; ids without a setter are read-only
(a write would go to address 0).
## Spawning and collision (engine facts, found by the arena, 2026-11-07)
* `spawn<params, vars, slots, typeFlags, extra>` (0xe0, FUN_0054bfc0) takes the same fields as a MAP
strat record: params = MAP parameter count, vars = local variables, slots, typeFlags = MAP type flags
(collision setup), `extra` = words of the collision-bone area.
* `spawn` copies the spawner's matrix/translation block (+0x20…), not its `x/y/z` properties: after
`self.x = …` the child still appears at the old place. Set the position, **yield**, then spawn.
* A MAP-placed type that uses `collisionOn` needs collision type flags in its MAP record (0x28000 like
Coin); with typeFlags 0 the game crashes (page fault in the heap allocator FUN_0041ae20).
## Sources
* groove.exe handler tables, decompiled with Ghidra 12.2 (headless, all 0x1b2 + 0x45 entries and
@@ -642,7 +652,7 @@ ops = operands (inline words for long ops, the 16-bit argument for short ops); p
| 143 | `camScale` | yes | yes | low | DAT_006D9D30, camera value initialised to 1.0 (zoom/fov factor?). |
| 144 | `levelHeaderC` | yes | no | low | Level header (DAT_00584648)+0x0C ushort << 12. |
| 145 | `slopeSteepness` | yes | no | medium | 1.0 - floor normal y (DAT_0057DDA4) << 12: 0 on flat ground (FUN_004054c0). |
| 147 | `levelTableByte` | yes | no | low | Byte table 0x585024[map + (chapter + tribe*10)*4] << 12 (per-level constant). |
| 147 | `levelTableByte` | yes | no | low | Byte table 0x585024[map + (world + tribe*10)*4] << 12 (FUN_0041af40(tribe, world, map)); bss, never written by the game (always 0) – but world-9 coin counters of TestLevel chapters 22–31 land in its tribe-1 part (see testlevel-chapters.md). |
| 149 | `flagEC_1` | yes | no | low | Flag +0xEC & 0x1. |
| 150 | `flagEC_8000000` | yes | no | low | Flag +0xEC & 0x8000000. |
| 151 | `cheat5` | yes | no | medium | Cheat toggle bits DAT_00584710 & 0x20 (button-sequence cheats, FUN_0041a0xx). |
@@ -660,10 +670,10 @@ ops = operands (inline words for long ops, the 16-bit argument for short ops); p
| 165 | `instanceData1` | yes | yes | low | Map-instance record (+0xF0)+0x28 -> word 1. |
| 166 | `floorCollisionOn` | yes | no | medium | Flag +0xEC & 0x8000 (floor collision, ops 0xa5/0xa6). |
| 169 | `lives` | yes | yes | low | DAT_00584E6C (fixed, starts at 5.0, saved per slot) - lives or max health. |
| 171 | `saveProgressA` | yes | no | low | DAT_00585008 << 12 (saved progress byte). |
| 172 | `progressWorld` | yes | no | low | DAT_0058500C << 12 (saved; world of the furthest/selected level, 8 = finale). |
| 173 | `progressChapter` | yes | no | low | DAT_00585010 << 12 (saved; chapter, 6 with world 8 = last level). |
| 174 | `saveProgressB` | yes | no | low | DAT_00585014 << 12 (saved progress byte). |
| 171 | `saveProgressA` | yes | no | low | DAT_00585008 << 12: last played tribe (KSV +0x3E, set by endLevel). |
| 172 | `progressWorld` | yes | no | low | DAT_0058500C << 12: last played world (KSV +0x3F, set by endLevel; 8 = finale). |
| 173 | `progressChapter` | yes | no | low | DAT_00585010 << 12: last played chapter (KSV +0x40; 6 with world 8 = last level). |
| 174 | `saveProgressB` | yes | no | low | DAT_00585014 << 12: last played map (KSV +0x41). |
| 175 | `unk_6da308` | yes | no | low | DAT_006DA308, no other reference. |
| 178 | `cheat4` | yes | no | medium | DAT_00584710 & 0x10 (cheat toggle). |
| 179 | `hudFlags` | yes | yes | medium | DAT_006DA2E0 HUD element enable mask (default 0x3F000; 0x2000 timer, 0x8000/0x10000/0x20000/0x40000 counters). |
@@ -676,7 +686,7 @@ ops = operands (inline words for long ops, the 16-bit argument for short ops); p
| 187 | `hitDamage` | yes | yes | medium | +0x140: damage dealt on contact (copied into the other strat's +0x144). |
| 188 | `damageTaken` | yes | no | medium | +0x144: damage received from the last contact (player cleared to 0 each frame). |
| 189 | `health2` | yes | yes | medium | DAT_00584E70 = health (same as 92, settable). |
| 190 | `levelRecord` | yes | yes | low | Per-level saved word DAT_00584F1C[chapter + world*6] (best/collected value for the current level; HUD shows it). |
| 190 | `levelRecord` | yes | yes | medium | Coin counter of the current level: u32 DAT_00584F1C[chapter + world*6] (coins << 12; HUD and tally show it, zeroed on level start, KSV keeps worlds 0–8 as u16). World 9 has no row: TestLevel chapter c hits 0x584FF4 + 4c (chapter 9 = furthest progress 0x585018) – only chapters 1 and 32–49 are free (testlevel-chapters.md). |
| 191 | `counterC` | yes | yes | low | DAT_00584FFC: persistent HUD counter (icon 0x150), saved. |
| 192 | `counterA` | yes | yes | low | DAT_00584FF4: persistent HUD counter (icon 0x184, displayed up to 999) - probably coins. |
| 201 | `distToPlayerSq` | yes | no | high | +0x148: cached squared distance to the player ((d>>6)^2 sum), updated each frame when tracking (op 0x30). |