Files
llamamod/README.md
T
2026-11-07 12:49:23 +01:00

269 lines
13 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.
# levelbau – level modding kit for *The Emperor's New Groove* (PC, 2000)
German title: *Ein Königreich für ein Lama*. PC port by Argonaut, built on the Croc 2 engine.
This kit came out of an AI-assisted reverse-engineering project. It contains:
* **Format documentation** for the level files (`*.wad`): geometry, collision, object
placement, textures, waypoints, visibility zones, and what makes the level exit work.
* **Python tools** that read, export and rebuild those files byte-exactly.
* **A level builder** (`tools/levelbuild.py`). You describe a level as a short Python script
(boxes, ramps, stairs, fences, trees, sea, objects) and it writes a complete, playable WAD.
* **An example level, "Testwelt"** (`levels/testwelt.py`). It goes into the hidden, empty
*TestLevel* slot (world 9, chapter 1) and has its own geometry, a gallery with every
object type on pedestals, an animal pen and a small parkour with a working exit.
* **A debug patch generator** (`tools/debugviz.py`). It makes collision visible in every
level, including invisible walls, along with invisible trigger and camera objects.
* **An automated in-game tester** (`tools/lamatest.py`). On Linux it runs the game under
Wine on a virtual display, loads the test level, takes screenshots and detects crashes.
Nothing from the game itself is included: no game files, no executable, no decompiled
code, no built WADs. Every tool works on **your own copy** of the game.
> The notes in `notes/` are detailed and technical. Handing them to an AI assistant is the
> recommended way to use this kit (see the last section).
---
## Requirements
* Your own copy of the game. Development used the **German CD version**. Other language
versions should use the same format, but this hasn't been tested.
* Python 3.8+ with `numpy` and `Pillow`. Optional: `capstone` (disassembler helper).
* For the automated in-game tests only: Linux, Wine, Xvfb, xdotool, ImageMagick, tesseract
with German language data, and PulseAudio (`pactl`).
* Optional: Blender (preview renders), and Ghidra (to regenerate the decompile, see below).
The builder and the export tools are plain Python, so they should also work on Windows.
The test harness is Linux/Wine-only.
### Paths – adjust these
The tools were written for one Linux/Wine setup and some paths are hard-coded at the top of
the scripts:
| Script | Variable | Meaning |
|---|---|---|
| `tools/levelbuild.py` | `WADS` | folder with the original level WADs (the `wads` folder of the game CD) |
| `tools/levelbuild.py` | `MODWAD` | where `--install` puts the built level (`T1L9M001.wad`) |
| `tools/debugviz.py` | `CD_WADS` | same as `WADS` |
| `tools/lamatest.py` | `PREFIX`, `LAMA_MOD` | Wine prefix and the overlay script |
The game reads its level data from the CD drive, in the `wads` folder of the CD. To mod it,
make a copy of the CD data (or an overlay of symlinks, see `tools/lama-mod`), point the CD
drive or `CDPath` at that copy, and put modified WADs into its `wads` folder.
---
## Folder layout
```
README.md this file
notes/ format documentation and findings
geometry.md TRAK/MAP geometry, collision polygons, coordinate spaces, zones, limits
objects.md MAP chunk layout, strat (object) entries, waypoints, player start, exit
strat_types_table.md every object type in every original level, with counts
textures.md TEXT chunk: texture pages, RLE16, texture table, animations
levelbau.md how to use levelbuild.py, measured player physics, exit logic
testharness.md the automated Wine/Xvfb tester
debugviz.md debug patch: colour legend, what is shown, limits
img/ screenshots and preview renders
tools/
geomlib.py core library: WAD, TRAK, STPC models, MAP geometry, TEXT, collision
geom_export.py WAD -> OBJ/MTL (+ textures, vertex colours, collision.obj, objects.obj)
geom_import.py OBJ -> new geometry inside a WAD copy
mapchunk.py MAP chunk parser/writer (byte-exact on all original levels)
strats.py, strat_table.py, stpcwalk.py, map_dump.py object types and strat code helpers
textchunk.py, text_export.py, texsheet.py textures: export/import PNG, contact sheets
levelbuild.py the level builder (see notes/levelbau.md)
debugviz.py debug patch generator (collision/trigger visualisation)
lamatest.py automated in-game test on a virtual display (Linux/Wine)
lama-mod shell script: builds a CD overlay with modded WADs (Wine setup)
vorschau/ Blender preview render scripts
disx86.py small disassembler helper for groove.exe (needs capstone)
wadtool.py minimal WAD chunk lister/extractor/replacer (used by several tools)
cor2png.py, png2cor.py loading/concept pictures (*.COR, LZ-compressed 640x480) <-> PNG
asf2wav.py music (*.ASF, 4-bit ADPCM) -> WAV
levels/
testwelt.py the example test world
testwelt_parkour.seq scripted run through the parkour (used with lamatest.py)
sprunglabor.py "jump lab": test lanes used to measure jump height/width
re/ghidra_scripts/
DumpAll.java Ghidra headless script: decompiles every function to one C file
```
---
## Quick start
```bash
# export a level to OBJ (+ collision and object markers)
python3 tools/geom_export.py /path/to/cd/wads/t1l1m001.wad out_village --collision --objects
# -> level.obj/.mtl, texture pages, collision.obj, objects.obj, preview images
# build the example test world
python3 tools/levelbuild.py levels/testwelt.py testwelt.wad
python3 tools/levelbuild.py --types # object types you can place
python3 tools/levelbuild.py --textures tex.png # texture sheet with the names you can use
# build the debug patch for all levels
python3 tools/debugviz.py --help
```
### Playing the test level
The game has a hidden world 9, *TestLevel*, with 49 chapter slots, but the retail game ships
no data for it. Put your built WAD into the CD's `wads` folder as `T1L9M001.wad`. Also add a
loading picture `T191.COR`, for example a copy of another `T1xx.COR`.
To reach world 9, edit a save file (`king0.ksv`…`king2.ksv`, 256 bytes):
* `+0x04/+0x05` = map cursor (world, chapter)
* `+0x3f/+0x40` = current world/chapter
* `+0x42/+0x43` = highest unlocked world/chapter
Set them to world 9, chapter 1.
When you leave through the exit, the game unlocks the next chapter. `levelbuild.py --install`
therefore links chapters 2–49 to the same file, so that picking one on the map doesn't crash.
### Debug patch: visible collision and invisible walls
```bash
python3 tools/debugviz.py --all debug_wads --src /path/to/cd/wads # all 33 level WADs
python3 tools/debugviz.py t1l1m001.wad t1l1m001_debug.wad # a single level
python3 tools/debugviz_check.py debug_wads /path/to/cd/wads # offline sanity check
```
Put the resulting WADs into the CD's `wads` folder in place of the originals, keeping the
same file names. On the Wine setup, `lama-mod debug an|aus` toggles them. The patch only
adds render geometry. Collision, objects, waypoints and zones stay byte-identical, so
gameplay is unchanged.
Legend (full version in `notes/debugviz.md`):
| Colour | Meaning |
|---|---|
| green / yellow-green wireframe | walkable floor / slope |
| blue | wall |
| orange | ceiling / overhang |
| **red, semi-transparent fill** | **invisible collision**: invisible walls and floors |
| magenta lines | death plane ("no floor") |
| violet fill | level exit floor (material 16) |
| other colours | special collision materials |
| Marker | Meaning |
|---|---|
| white arrow | player start |
| violet cube | exit |
| turquoise cube | checkpoint |
| cyan cube | camera |
| yellow cube | trigger / cutscene |
| orange cube | force or special zone |
| gold cube | secret zone |
| grey cube | other invisible helper object |
| pink wire box | ambience / music / fog zone |
Cubes sit on a stick, and a horizontal line shows the object's facing. Wire boxes show
trigger areas.
Status: 19 of 33 levels were loaded in the game without problems. The rest
(catacombs/roller coaster world 7, lab world 8, two others) passed the offline check only.
Collision of moving objects (platforms, doors) is not shown.
---
## LlamaMod and the level editor
Besides the Python kit, this repository contains **LlamaMod** (Java 25, Swing; `src/`), a
one-click mod manager for the game on **Windows and Linux**, and a full **3D level editor**
built into it. Nothing from the game is included: the wizard installs the game from your own
CD/ISO into LlamaMod's data folder, and all mods are built from that copy.
* **Mods** – tick mods, click *Apply*/*Play*: debug wireframe, Test World, randomizer, fog,
mirror mode, intro skip, cheats, practice tools, free camera, *boot to level* … Mods may change
level files and `groove.exe` (code caves); the original files are never touched.
Developer notes: `notes/llamamod-app.md`, one `notes/mod-*.md` per mod.
* **Level editor** (*Level Editor* button, or `LlamaMod --editor`): create new levels from
templates, brushes and the base level's tile models and objects, or edit the original
levels; import OBJ/glTF meshes and PNG/JPG textures (texture manager, paint-on-faces,
animations); waypoints, zones, fog, lights, visibility regions; **Play (F5)** builds the
level and starts the game directly in it (Escape returns to the editor).
* **Sharing**: a level is a small `.llamalevel` file with only your changes. Others import it in
LlamaMod (*Mods → Levels → Import level*) and it is built from their own game copy; new levels
appear in the hidden *TestLevel* world (chapters 1–49).
User guide (English): **`notes/editor-guide.md`**. In the editor: *Help → Getting started*
and *Help → Shortcut sheet*. Technical notes: `notes/editor-design.md`, `editor-api.md`,
`editor-format.md`, `editor-render.md`, `editor-ui.md`, `editor-tools-*.md`,
`editor-playtest.md`.
```bash
./gradlew build fatJar # tests + build/libs/llamamod-<ver>-all.jar
./gradlew packageLinux # build/dist/LlamaMod-<ver>-full-linux-x64.tar.gz (own Java runtime)
./gradlew packageWindows # build/dist/LlamaMod-<ver>-full-windows-x64.zip (LlamaMod.exe + runtime)
./gradlew packageAll # both systems, full and launcher (no editor) edition
java -jar build/libs/llamamod-*-all.jar # LlamaMod
java -jar build/libs/llamamod-*-all.jar --editor # the level editor alone
```
![The level editor](notes/img/editor/ui_select_move.jpg)
---
## Key facts
* **The world is made of tiles.** TRAK holds about 100–650 small models: render triangles
plus collision polygons. MAP places them on a W×H grid (96×96 in the village) with height
and rotation. MAP also stores baked vertex colours and a 32-zone visibility table. There is
no BSP and no single world mesh.
* **Objects are "strats".** These are compiled scripts in the STPC chunk. In MAP, an object's
type is simply its **byte offset into STPC**. A level can therefore only use the object
types its own STPC contains. The builder uses the village (`t1l1m001`) as its base.
* **Coordinates and scale.** y points up. Fixed point 20.12 for objects, 4096 = 360° for
angles, and render space vs. game space have z mirrored. The llama is about 0.6 units
tall, runs about 1.1 units/s, can step up at most about 0.35 and jumps about 1.3 units
far with a run-up.
* **The level exit (LevelDoor)** is an invisible trigger. It fires only when the llama
stands in its grid cell **on floor with collision material 16**. Its parameters are
(tribe, world, chapter) of the next level.
* **Texture pixels** are PS1-style 15-bit BGR, RLE16-compressed, on 256×256 pages. The
value 0x0000 means transparent.
The parsers rebuild every original WAD byte-for-byte, so they can be trusted as format
specs.
---
## Building on this with an AI assistant
This whole kit was made by an AI coding agent (Claude Code) working through the steps
below. Any capable assistant that can run code should be able to continue.
1. **Give it the notes first.** Ask it to read `notes/*.md`. They contain offsets, field meanings, confidence levels and pitfalls.
2. **Regenerate the decompile** for questions about game logic. Install Ghidra and a full
JDK (version 25 for Ghidra 12.x), then run
`analyzeHeadless <projdir> groove -import groove.exe -scriptPath re/ghidra_scripts -postScript DumpAll.java groove_decomp.c`.
This writes all functions as C (about 2 MB) for the assistant to search with grep.
Loader functions worth knowing: MAP `0x42ac50`, TRAK `0x42aac0`, STPC `0x42ab50`, strat
interpreter `0x54d180`.
3. **Always test in the game.** Have the assistant load and screenshot every build. On
Linux, `tools/lamatest.py run <wad> <outdir>` does this unattended in about 75 s. On
Windows, test by hand or adapt the script.
4. **Change one thing at a time** and keep the original WADs untouched. The game crashes on
inconsistent data: tiles outside the grid, a vertex-colour block that doesn't match the
vertex counts, or missing chapters.
### Ideas for what to try next
* Use object types from other levels. You would have to merge and relocate their STPC
code and their textures.
* ~~Import custom textures~~ – done in the level editor (texture manager, import, painting).
* ~~Make a real visual editor~~ – done: the LlamaMod level editor (see above).
* Add custom music or sounds (SMPC/AMPC/SRPC are sound banks).
---
This is a non-commercial fan project, not affiliated with Disney or Argonaut. Please share
only tools and your own content, not the game's files.