5.3 KiB
Mod "practice" – Practice tools (GAMEPLAY)
Package mods.practice (PracticeMod, SavePositionPatch, ExtraCheckpoints, plus the helpers
Asm (extra x86 encodings on top of exe/X86) and Hotkeys (key choices), also used by freecam).
Options
| Key | Default | Meaning |
|---|---|---|
saveKey |
F5 | store the llama's position (choices F1–F5, F7–F9, F11, F12, Insert, Delete, Home, End; F6 = game screenshot, F10 = system key are left out) |
loadKey |
F8 | put the llama back to the stored position |
checkpoints |
true | add extra CheckPointPost strats to the level WADs |
spacing |
10 (4–40) | minimum distance (tiles) between two checkpoints |
Save / restore position (exe)
Hook: call FUN_0054c4a0 (strat update) at 0x54b77e inside the tick loop of the frame function
FUN_0054b590 is redirected to a cave:
- poll
GetAsyncKeyState(viaimportAddress, the game does not import it) with edge detection; - save: player strat
*(0x6d9e1c)+0x30/+0x34/+0x38 (position, 20.12 fixed, z positive), +0x24 (yaw), and the current world/chapter0x584eb8/0x584ebc; - restore (only if a position was saved in the same world/chapter and the player exists): write position into +0x30.. and the previous-tick copy +0x50.. (the wall collision FUN_00403ee0 sweeps from previous to current position, so the jump must not look like movement), yaw into +0x24/+0x44;
- call the original strat update;
- for 4 ticks after a restore the position is written again after the update ("pin"), so the remaining fall speed of the llama script is used up on the floor collision instead of moving the llama away.
Strat structure facts used (0x154 bytes per strat, FUN_0054c4a0/FUN_0054bc30): +0x04 next, +0x20/24/28 rotation (angle<<12, 4096 = 360°), +0x30/34/38 position, +0x40..+0x5f copy of +0x20..+0x3f from the previous tick, +0x70 3×3 matrix, +0x94/98/9c render position copy, +0xc0 collision block, +0xe8 flags (0x8000 floor, 0x40000 wall collision). Velocity is not a fixed field – movement comes from strat-script opcodes (e.g. FUN_00550690 = move along yaw), so it lives in the llama's script variables.
The stored position survives deaths and restarts of the same level; it is ignored in another level. Keys are polled with GetAsyncKeyState, so they also react when the game window is not focused.
Extra checkpoints (WAD)
ExtraCheckpoints.process: for every t[1-8]l*m*.wad that already contains CheckPointPost
instances (STPC code + type constants available):
- candidates =
Coin/Coin5positions (the designers' route), sorted by distance fromLlama; - a candidate becomes a checkpoint if it is ≥
spacingfrom the start, every original and every added checkpoint, and walkable floor (collision polygon with ny ≥ 0.7, material ≠ 30/17) lies 0.8 below … 0.2 above the coin (Floor.below, world-space collision of all tiles); - new strat = copy of the first CheckPointPost (code, nVars 12, slots 1, flags 0x28000, extra 0,
parameter value 0x333 appended to the parameter pool), yaw = direction from the nearest previous
checkpoint,
poolExtra+1 per post (max 40 per level); - each original checkpoint owns exactly one path node = respawn point (position + yaw,
next0, ~0.3–0.5 tiles beside the post); new ones get a node 0.4 tiles ahead (or behind/sideways if there is no floor ahead).
The floor finder reproduces the height of 68 of 102 original posts within 0.05 (the rest stand on moving platforms/strat models). With spacing 10, 32 checkpoints are added in 17 levels (e.g. Village 1: +2, jungle day 3: +5). Levels without CheckPointPost (Village 3/4, river, chase, roller coaster, lab 2/6) are unchanged.
Tests
PracticeModTest: instruction encodings (checked against nasm), all WADs: original posts on
floor, strat/node/poolExtra counts after processing. FreeCamModTest applies practice + freecam
to the real exe (no overlapping patches) and writes build/tmp/practice-freecam.exe for objdump.
Verified in game (2026-11-06, Wine 6, apptest, Village 1 = t1l1m001)
- F5 → walk away → F8: the llama is back at the stored spot (
img/mods/practice-teleport.jpg); memory check with winedbg: player +0x30.. equals the stored position after F8. - After restoring, the camera is not snapped; it swings back behind the llama on its own (it may look from an unusual angle for a moment).
- Together with
freecam: no patch conflicts; pause menu, leaving to the map and re-entering the level, falling off the island (respawn) and game over → no crash; the stored position stays valid after the level is restarted. - Extra checkpoints: levels load with the added posts; a new post renders at its place
(
img/mods/practice-extra-checkpoint.jpg, Village 1, (42.91, 2.9, 50.84), seen with the free camera).
Limits / not verified
- Activation of an added checkpoint and respawning at its path node were not verified in game (falling off the island does not use checkpoints; reaching a real death in the test harness was not attempted). The strat record, parameter and node layout are copied 1:1 from the level's own CheckPointPost, so it is expected to behave like the original ones.
- Posts are placed at coins with floor below; a coin on a moving platform or behind a one-way section can give a post the llama only reaches from one side.