Files
llamamod/notes/mod-cheats.md
T

79 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Built-in cheats (`cheats`, CHEATS)
`mods/cheats/CheatsMod` – one groove.exe hook, no data changes.
## How the game does it
Main menu frame function 0x54B460 (state 2, table 0x579050): whenever a pad bit is held
(0x5FCF08 ≠ 0) it calls **FUN_0041a160(0)**, the sequence matcher:
```
for i in 0..5:
if newlyPressed(0x5FCF30) & seq[i][pos[i]]: pos[i] at 0x58483C + 4i
pos[i]++
if seq[i][pos[i]] == 0: sequence complete
if cheatFlags(0x584710) & (1<<i): clear bit (toggle off, no sound)
else: set bit, play sound (FUN_00546170(0,-127,8))
i == 2: next mode 0x584700 = 0x0A, 0x584638 = 4 (go to the credits)
pos[i] = 0
else pos[i] = 0 any other key resets this cheat
```
Sequence table **0x571FBC**, 6 × 9 dwords (8 steps + 0). Menu key bits (FUN_0041a220, raw DIK
state array 0x58226C + 4·DIK): ↑ 0x10, ↓ 0x40, ← 0x80, → 0x20; Return 0x4000, Space 0x8000,
C 0x2000, A 0x400, S 0x800, Esc 0x1000, Tab 0x08, backslash 0x01. Typing a sequence works
with arrows alone; no extra key has to be held (the "hold" is just that the matcher only runs while
some key is down). The flag word is never saved or reset (only bit 2 is cleared after the
credits), so cheats stay on until the game quits.
## Decoded cheat table
| Bit | Sequence | Read at | Effect | Option |
|---|---|---|---|---|
| 0 | ← → → → ↑ → → ↑ | 0x54F5C9, VM opcode 0xC0 "hurt player" (FUN_0054f5c0) | energy (0x584E70) is not decreased → no damage, no lost lives | `health` (default on) |
| 1 | ↓ ← → ↓ ↓ ← → ↓ | strat property 0xEA (0x5524F4), read by the Llama strat at chapter start | property 0xFA (0x584E60, pink idol counter, chapter collectible) = 50 | `collectibles` |
| 2 | ← ← ← ← → → → → | FUN_0041a160, 0x54A5F6 | plays the credits (CREDITS.dat) right away, then back to the main menu, bit cleared | – (one-shot, not a setting) |
| 3 | → → ↓ ↓ ↓ ↑ ↓ ↓ | 0x54D6F9 (chapter finished) | chapter flags `|= 3` (collectible + gold coin, KSV +0x08) | `rewards` |
| 4 | ↑ ↓ → ← ← ← ← ↓ | strat property 0xB2 (0x550EE1) | property 0xC0 (0x584FF4, purple fruit counter) = 500 instead of 0 | `fruit` |
| 5 | ↑ ← ↓ → ↓ ↓ ↑ ↑ | strat property 0x97 (0x55100C) | property 0xE8 (0x6DA304, charge bar) = 165 instead of 50 | `charge` |
Llama strat (t1l1m001 STPC 0x429536, same in all 23 level WADs) – VM short opcodes: 0x07 p =
push property p, 0x14 n = pop, skip n words if zero, 0x16 n = skip n words, 0x40 p = pop into
property p, 0x44 n = push n, long opcode 0x45 = push next word:
```
if prop[0x97]: prop[0xE8] = 0xA5000 else prop[0xE8] = 0x32000 ; 165 / 50 (20.12)
if prop[0xB2]: prop[0xC0] = 0x1F4000 else prop[0xC0] = 0 ; 500 / 0
if prop[0xEA]: prop[0xFA] = 0x32000 ; 50
```
Strat property switch: FUN_00550e60 (get, 0x10A cases, table 0x552684), FUN_005509f0 (address
for store, index table 0x550D64 → 0x550C78).
## Patch
`call FUN_0041c050` at 0x41D3EA in WinMain (right after the command line is parsed, before
DirectX init) → cave: `or dword [0x584710], mask` (+ `mov byte [0x5834D0], 1` for
diagnostics) → `jmp 0x41C050`. The cave writes only game globals, so it needs no data block.
## Hidden debug features found
| Feature | State | In the mod |
|---|---|---|
| `-display_diagnostics` (DAT_005834D0) | works: writes `<COMPUTER>.dispdiag` (DDraw/D3D enumeration) into the game folder; FUN_0040f4f0 opens **every display mode of every DirectDraw device × D3D device** (FUN_00410550/FUN_00410700 = mode switch, FUN_00411000), logs caps and texture formats, closes it again, then returns and the game starts normally. On Windows with two monitors both screens flashed black for 30+ s (tester, 2026-11); invisible under Wine | option `diagnostics`, label "Troubleshooting: write display diagnostics", off by default, warning in its description (tested: ELIASPC.dispdiag, 60 KB) |
| `c:\kingdom_dbg.txt` | dead: FUN_0040d2c0 (called from FUN_0043c220) only creates the file with "Logfile %s started now/today (write this code!)"; the 43 debug prints (FUN_00414600) go to OutputDebugStringA (0x6DC3E8), never to the file | no |
| FrameAdvanceDelay (FUN_0043cb40) | slide show `In\001.bmp…` + `In\In.wav` at start, `Out\…` at exit, delay from registry `FrameAdvanceDelay` (default 1.0 s); folders are empty | no (data, not a cheat) |
| F4 in game | requests state 0x0C (world map) – the normal "back to map" | no |
| F7 in game | toggles 0x584708 → start row of the strat debug print (0x6D9DB8 = 0x20 / 0x48); nothing visible in retail strats | no |
| F6 | screenshot `capture%d.tga` | no |
| `CheatTeleport`, `CheatCharge` strats | present in most level WADs; strat-only logic, not decoded | no |
Level select / unlock-all is the save editor's job (`--unlock`), not duplicated here.
## Verified in game (Wine 6, Xvfb :8, Village 1-1)
* All cheats on: chapter start shows the full charge bar, pink idol 50, purple fruit 500
(`img/mods/cheats_hud.jpg`, original on the left).
* Infinite health: running off the cliff into the sea three times – original loses an energy
segment per fall (HUD shows the red segment), with the cheat the energy HUD never appears, no
loss (`img/mods/cheats_fall.jpg`).
* `rewards` (bit 3) decoded only, not played through to a chapter end.
* Diagnostics: file written, game runs normally.