initial commit: llamamod 0.2.0 – reverse-engineered level formats (wad, map, trak, text, stpc), python tools and notes, java mod manager (iso install, mod pipeline with exe patching, save editor, wine/windows launcher) with mods (test world, debug wireframe, mirror, randomizer, fog, cheats, intro skip, practice, free camera, boot to level, level projects) and the 3d level editor (geometry, objects, cross-world import, environment, textures, play-test, manual)
This commit is contained in:
commit
b36a366240
826 files changed
+105304
No files matched your search
@@ -0,0 +1,70 @@
|
||||
# Mod "Mirror mode" (`mods.mirror.MirrorMod`, id `mirror`, GAMEPLAY)
|
||||
|
||||
Mirrors every playable level left-right (x → W − x on the W×H tile grid), like the mirror mode of
|
||||
racing games. Controls are unchanged (the world is mirrored, not the input).
|
||||
Code: `mods/mirror/Mirror.java` (pure byte transform), `MirrorMod.java`; test `MirrorTest`.
|
||||
|
||||
## Options
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `worlds` | `all` | `all` or world numbers, e.g. `1,3` (9 = TestLevel / Test World) |
|
||||
| `readableTextures` | false | on: face flag 0x20 (mirror U) is toggled so writing reads normally, but textures that continue across faces get seams (fountain water rim in the village); off: true mirror image |
|
||||
| `objects` | false | also mirror rigid STPC object models (verts, face planes, collision); skinned characters never |
|
||||
|
||||
`order()` = 75: after `testworld` (50, so the Test World is mirrored too) and before
|
||||
`debug-wireframe` (100, so the overlay is built from the mirrored collision and lines up).
|
||||
Files: `wads/t1l<w>m<c>.wad` only (front end `t0*`, map `t6l6*` stay).
|
||||
|
||||
## What is transformed (all chunk sizes unchanged → STPC absolute offsets stay valid)
|
||||
|
||||
| Data | Transform |
|
||||
|---|---|
|
||||
| TRAK models (all, shared by tiles) | vertex x, normal x, face plane nx negated; bbox centre x negated, corner pairs (−x/+x) swapped + x negated; collision: i8 nx of all 5 planes negated (d unchanged; −128 → 127) |
|
||||
| Face winding | **kept**. groove.exe sets `D3DRENDERSTATE_CULLMODE = D3DCULL_NONE` once (decomp ~line 31587, Device3 vtable +0x58) and culls in software with the stored face plane. Reordering vertices would break the fixed UV corner patterns (pattern 0x800+0x10 has no odd permutation that keeps the UVs). |
|
||||
| MAP tiles (float A) | x → W − x, rot → (4096 − rot) & 0xfff |
|
||||
| MAP tiles (fixed B) | x → W·4096 − x, rot as above (A and B stay exactly consistent) |
|
||||
| Region grid, tile-swap block (cell x) | columns mirrored (cell → W − 1 − cell) |
|
||||
| Strats | x → W·4096 − 1 − x (keeps `floor(x)` in the mirrored cell: LevelDoor compares cells), ry and rz → −angle, rx kept |
|
||||
| Waypoints / camera nodes | same as strats (x, ry, rz) |
|
||||
| 90-byte "env zones" | really **teleport/respawn entries** (FUN_0054d560 / FUN_0054de00): f0..2 = trigger cell (x,y,z), f3..5 = target position (fixed), f7 bits 4..11 = facing angle (bits 0/1 = y compare flags). Mirrored: cell x, position x, angle. Default entry (pos 1,1,1) untouched. f11 (+0x2c) = sky model yaw offset, kept. |
|
||||
| LGHT (FUN_0042c180) | u32 n; per light u8 type, r, g, b; type 1 directional: 3 f32 → x negated; types 2/4 point: 3 f32 + 2 f32 + u8 → x → W − x |
|
||||
| STPC (option) | rigid models (nBones = 0) incl. WFPC&0x100 extra models, same as TRAK models |
|
||||
| Vertex colours | unchanged (vertex order unchanged) |
|
||||
|
||||
Rotation rule: mirroring x conjugates rotations; about y and z they become −angle, about x
|
||||
unchanged. 0 = facing +z, so facing (sin a, cos a) → (−sin a, cos a) = angle −a.
|
||||
|
||||
Mirroring twice gives the original WAD byte for byte (except LGHT float rounding and −128 normals) –
|
||||
checked in `MirrorTest`, together with: every render vertex and collision corner of every tile of
|
||||
t1l1m001 lands exactly at the mirrored world position, region per tile cell preserved.
|
||||
|
||||
## Not mirrored / known limits
|
||||
* Strat bytecode is untouched: hard-coded offsets/directions in scripts (if any) are not mirrored.
|
||||
Parameter-pool values are not interpreted (could contain coordinates/angles for some types).
|
||||
* Object models stay unmirrored by default (placed and turned mirrored, so their collision matches
|
||||
their own look). Skinned/animated characters are never mirrored (bone matrices and compressed
|
||||
vertex deltas of the anim sets would need conjugation).
|
||||
* Sky/background models (STPC, drawn camera-relative) are not mirrored.
|
||||
* Attract-mode demos (`*.DEM`, recorded input) desync in mirrored levels (harmless).
|
||||
* Textures are mirrored by default (true mirror); `readableTextures` flips them back per face,
|
||||
which breaks textures that are laid out across several faces.
|
||||
* **River intro fly-by (t1l3m001)**: the camera partly shows an empty grey view and the intro
|
||||
dialog starts earlier than in the original. No crash; after the intro the river plays normally.
|
||||
Most likely a hard-coded lateral camera offset in strat code (camera ends up in a cell whose
|
||||
visibility zone hides the river). The village fly-by is correct.
|
||||
|
||||
## In-game verification (apptest, display :7, 2026-11-06)
|
||||
* **Village t1l1m001**: same key sequence on original and mirrored – a perfect mirror image
|
||||
(house/fountain swapped sides), llama stands on the ground, walls/fountain rim block, coins
|
||||
collect (counter matches the original run), Pacha dialog triggers, camera rotate (A) works,
|
||||
intro fly-by (not skipped) correct. With `debug-wireframe` + `objects=true`: overlay lines up
|
||||
with the mirrored geometry, no crash.
|
||||
* **River t1l3m001**: loads, raft/tree floats on the mirrored river, auto-scroll and steering work,
|
||||
coins collected, wireframe lines up; fly-by see limits.
|
||||
* **City t1l6m001**: loads, intro cutscene with Pacha (cutscene cameras) fine, walls and crates
|
||||
block, wireframe lines up.
|
||||
* **Test World** (`testworld,mirror`, world 9): mirrored island (parkour stairs on the right),
|
||||
walking/jumping fine.
|
||||
* Images: `notes/img/mods/mirror_01_village.jpg` (original vs. mirror), `mirror_02_wireframe.jpg`
|
||||
(village + city with the debug wireframe), `mirror_03_river_testworld.jpg`.
|
||||
Reference in new issue
Block a user