7.9 KiB
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) |
| 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.
Frog moonjump (PS second controller)
Question from speedrunners: is the frog moonjump (PS: needs a controller in port 2) reachable on PC? Answer: the logic is in the PC data, but its input can never be set on PC without patching.
Strat side (all 34 level WADs disassembled, 2026-11-08). Property 88 padAux (DAT_005FCF58) is read
only by Llama (23 WADs), LlamaChase (t1l2m003), KuscoBunny (t1l7m004, t1l8m001, t1l8m002), KuscoFrog
(t1l4m003, t1l8m003) and CheatTeleport (26 WADs, also padAuxPressed). Everything except the frog's
air handler is additionally gated by property 258 (0x102), which the exe getter hard-wires to 0
(jump table 0x552684[0x102] → 0x55231B push 0); CheatTeleport removes itself when it is 0.
KuscoFrog (t1l4m003 unit 44), airborne handler L_136c – no prop-258 check:
if (self.padAux & 0.5) { ; bit 0x800
g22 = 0.055 ; vertical speed upward, every frame while the bit is set
v31 = 1.0
}
self.y = max(self.y + g22, v44)
Ground handler L_1d6c (take-off): (padPressed & 4.0 /*jump*/) | ((padAux & 0.5) && prop258) → the
aux bit alone cannot start a jump, it only keeps the frog rising once it is in the air (= moonjump:
jump normally, then hold the aux button). Llama/Bunny/LlamaChase have the same code (Llama: g22 = 0.0698)
but behind prop258, so they never moon-jump.
Exe side: 0x5FCF58 is referenced exactly 3× in groove.exe (all 4-byte immediates scanned): 0x425B93
mov dword [0x5FCF58], 0 (end of the pad poll FUN_004256C0, only if pad count 0x5FCF6C > 1, i.e. a
DirectInput joystick is present), 0x425C1E (edge detect → 0x5FCF60 padAuxPressed), 0x551403 (strat
getter, prop 0x58). It lives in .bss → always 0. No keyboard key, joystick (1st or 2nd), debug key or
demo (.dem) playback writes it. Under Wine without a joystick: pad count 1, padAux 0 (read in game).
Verified in game (apptest :25, t1l4m003 Jungle day ch. 3, teleported onto PotionPadFrog → FrogPotion
→ frog): set {int}0x5FCF58 = 0x800 via the winedbg gdb proxy. Frog on the ground: nothing happens.
Frog jumps (X): it keeps rising – y 13460 → 41617 (~2 s) → 59842 (~4 s), far above the level; clearing
the bit makes it fall back. Same write as the llama: normal jump, no effect (prop 258 = 0).
img/mods/frog_moonjump.jpg (top: normal frog jump, bottom: bit 0x800 set).
To enable on PC a patch is required, e.g. make the pad poll map a key to padAux bit 0x800. Which PS button of pad 2 feeds bit 0x800 is not known (no PS binary analysed) – hypothesis only.