Files
llamamod/notes/mod-freecam.md

7.8 KiB
Raw Permalink Blame History

Mod "freecam" – Free camera & noclip (CHEATS)

Package mods.freecam (FreeCamMod, FreeCamPatch); uses mods.practice.Asm/Hotkeys. Version 3.

Options and controls

Key Default Meaning
camKey F7 toggle free camera
noclipKey F9 toggle noclip
freeze true stop all strats (objects, llama, camera strat) while the free camera is on
camSpeed 3 (1–32) free camera speed, 1/32 tile per logic tick (30 ticks/s)
noclipSpeed 2 (1–32) noclip speed, 1/32 tile per tick

The controls are the game's own (default bindings below; remapped keys and joysticks work, because the mod reads the game's control bits, not raw keys):

Game control (default key) Free camera Noclip
Up / Down (arrows) fly forward / back (horizontal, along the view) llama away from / towards the camera
Left / Right (arrows) strafe left / right llama screen-left / screen-right
Camera left / right (A / S) turn left / right orbit the camera around the llama
Jump (X) / Action (Z) up / down llama up / down
PgUp / PgDn look up / down (±88°) –
Power (Space) or Shift ×4 speed ×4 speed

While the free camera is on, the game gets no movement input (pads cleared, only pause kept), so with freeze off the game keeps running but the llama stands still; Escape/P still opens the pause menu (no camera movement while it is open). In noclip the llama still gets the input (walk/jump animations), but its position is the mod's. Toggles (F7/F9) and Shift use GetAsyncKeyState. Both toggles are switched off when a level (re)starts.

How it works

Site Original Cave
0x54b5fd call FUN_00427c40 (right after the frame's input read FUN_00419e00/FUN_0041a220) copy control bits for the free camera; while it is on: clear pads, rerun FUN_004256c0
0x54b79f / 0x54b7e0 call FUN_0054bad0 (running / paused frame) call it, then toggles + free camera or noclip chase camera
0x54b614 / 0x54b7a4 / 0x54b7e5 call FUN_0041e020 (region mask from the camera cell) with free cam/noclip on: run it with the llama's x/z as camera cell
0x54b783 call FUN_004287c0 (particles, after each tick's strat update) noclip, then jmp to the original
0x54c4a0 entry of FUN_0054c4a0 55 8B EC 83 EC 4C ret while the free camera is on (only with freeze)
0x54d0d5 mov [0x6d9e40], edi in FUN_0054d0d0 (strat system reset at level start) clear both toggles

Input facts: FUN_00419e00 ORs, for each of the 14 bindings (DIK codes at 0x584758, order Left, Right, Up, Down, A, S, Space, X, Return, P, PgUp, PgDn, Z, O), the bit from table 0x572100 into the u16 pad word *(0x5fcf70) (12-byte pad structs, count 0x5fcf6c; +2/+3 stick). FUN_004256c0 turns the pads into the held control bits 0x5fcf20 (Up 0x10, Right 0x20, Down 0x40, Left 0x80, A 0x400, S 0x800, Return 0x1000, Z 0x2000, X 0x4000, Space 0x8000, pause 0x8; PgUp/PgDn 0x100/0x200 are not copied there, the mod reads them from the keyboard pad word), stick magnitude 0x5fcefc and direction; FUN_00425bb0/FUN_00425c00 derive the edge bits the strats use.

Camera facts: the game camera is a strat (*(0x6d9e28)). FUN_0054bad0 copies its position to 0x6d9d20.. and 0x5790b0/b4/b8 and computes yaw/pitch (0x5790a4/0x5790a0, 0..4095, pitch < 0 = looking down) from the position and the look-at target 0x6d9d80/84/88. The renderer FUN_0041a920(&0x5790a0, &0x6d9d70) recomputes the angles from position → target (and writes them into the camera strat +0x20/+0x24), so position + target are what count. Forward = (sin yaw · cos pitch, sin pitch, cos yaw · cos pitch) from the sine table 0x574318 (s32[4096], 4096 = 1.0); screen-right on the ground = (−cos yaw, sin yaw). FUN_0041e020 takes the camera's cell, looks up its region (MAP grid +0x48) and sets the region mask 0x58642c (which rooms/tiles/strats are drawn; 0xffffffff outside the grid). A free camera in a cell of another region got mask 1 in Village 1, so the whole level vanished and only the static backdrop was left – that is why the free camera "only froze the game" for the user. The mod now computes the mask from the llama's cell.

Noclip: after every tick's strat update the player strat (*(0x6d9e1c)) gets the noclip position at +0x30.. (current), +0x50.. (previous tick, so the next wall sweep starts there) and +0x94.. (render copy), and its collision flags +0xe8 & 0x48000 (0x8000 floor check FUN_00403020, 0x40000 wall check FUN_00403ee0) are cleared, so it neither falls nor dies over the void. The camera strat does not follow a llama moved this way (it stays where it was and only turns), so while noclip is on (and the free camera off) the mod drives a chase camera: target = llama + (target − llama) and camera = target + (camera − target), both offsets taken when noclip is switched on; A/S rotate the camera offset around the llama (64/4096 per tick ≈ the game's 90° per 0.5 s). Switching noclip off ORs the collision bits back (same player strat only) and hands the camera back to the camera strat.

Fix history (version 3, 2026-11-06)

User report (Village 1/TestLevel, with testworld, cheats, fog 500 %/off, intro-skip):

  1. "Free camera just freezes the game": the camera did move, but I (forward) flew along the pitched view into the ground within a second, and outside the llama's region the region mask hid the whole level (only the backdrop stayed). Fixed: region mask from the llama's cell; arrows move horizontally, X/Z change height.
  2. Noclip camera did not follow: the camera strat ignores the teleported llama → chase camera.
  3. Noclip left/right swapped: right vector was (cos, −sin), correct is (−cos, sin).
  4. Free camera J/L turned the wrong way (L = +yaw = left); now S (camera right) = −yaw. During noclip the camera strat's own turning fought with the llama → replaced by the orbiting chase cam. Also: controls switched from I/K/J/L/T/G/U/H (GetAsyncKeyState) to the game's own controls, input is swallowed while the free camera is on.

Verified in game (2026-11-06, apptest, user's mod set: testworld, cheats, fog 500/off, intro-skip)

  • TestLevel (world 9), freeze on (img/mods/freecam-fix-controls.jpg): F7, Up flies forward, S turns right, Right strafes right, X rises, PgDn looks down, A turns left, Z sinks; F7 off → normal camera behind the llama.
  • TestLevel noclip (img/mods/freecam-fix-noclip.jpg): Up/Right/Left move the llama away/screen- right/screen-left with the camera following, A orbits, X lifts it, F9 off → it lands and the game camera takes over.
  • TestLevel, freeze off: the game runs while the camera flies; arrows/X/Z/A/S do not move or turn the llama; after F7 off it walks normally.
  • Village 1 (img/mods/freecam-fix-village.jpg): flying up and back shows the village from above (before the fix: only backdrop); noclip over the cliff edge with chase camera; pause menu with the free camera on (menu navigation does not move the camera), no crash.
  • Values checked with winedbg (attach, x /4x): control bits, camera/target, region mask.
  • FreeCamModTest (practice + freecam on the real exe) passes; PracticeMod untouched.

Limits

  • After switching noclip off in the air, the llama falls to the floor below as usual.
  • Enemies, water and triggers still work during noclip (a trigger may start a cutscene/dialog).
  • F7/F9/Shift react even when the game window is not focused (GetAsyncKeyState).
  • The region mask follows the llama: flying far into another room may show it without its own region's objects, or the backdrop only where the level has no geometry (open sea around islands).
  • A cutscene camera set via 0x57f8bc in the render function still wins over the free camera.
  • No mouse look.

Hotkeys are checked together with the other mods' hotkeys (mods/Hotkeys.conflicts): applying fails with a clear message if two enabled hotkey options share a key.