documentation for level builders: docs index, step-by-step guide, file format reference (wad, geometry, objects, textures, audio, testlevel chapters, engine limits), strat vm and script language with the arena as worked example, tools overview, developer notes; readme rewritten as project front page with screenshots; review notes moved to notes/dev
This commit is contained in:
1 parent
00b2880d67
commit
624718b893
41 files changed
+2175
-259
No files matched your search
@@ -1,268 +1,129 @@
|
||||
# levelbau – level modding kit for *The Emperor's New Groove* (PC, 2000)
|
||||
# LlamaMod – mods and a level editor 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:
|
||||
**LlamaMod** is a one-click mod manager and a full 3D **level editor** for the PC game, for
|
||||
**Windows and Linux**. It installs the game from your own CD or ISO into its own folder, applies
|
||||
mods without ever touching the original files, and lets you build new levels, edit the original
|
||||
ones and share them as small files. Everything is based on a complete reverse engineering of the
|
||||
game's level formats and its object scripts ("strats").
|
||||
|
||||
* **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.
|
||||
| | |
|
||||
|---|---|
|
||||
|  |  |
|
||||
| **Launcher**: mods with options, save-game editor, one-click play | **Level editor**: brushes, tiles, meshes, objects, textures, play-test with F5 |
|
||||
|  |  |
|
||||
| **Test World**: all 253 figures and objects of the game in one level | **Alligator Arena**: a minigame with new, scripted enemies |
|
||||
|  |  |
|
||||
| **Debug view**: collision and invisible objects in the running game | **glTF/OBJ** export and import for Blender |
|
||||
|
||||
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.
|
||||
## Features
|
||||
|
||||
> 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).
|
||||
* **Mods** – tick, *Apply*, *Play*: Test World, Alligator Arena, your own levels, Boot to level,
|
||||
Intro skip, Mirror mode, Practice tools (save/restore position, extra checkpoints), Randomizer,
|
||||
Draw distance, Built-in cheats, Debug wireframe, Free camera & noclip.
|
||||
* **Level editor** – new levels from templates or editing the original levels; brushes, the base
|
||||
level's tiles, OBJ/glTF meshes; textures (import, paint, animate); objects from **every world**;
|
||||
waypoints, cameras, triggers; fog, music, lights, visibility regions; strat scripts (read,
|
||||
change numbers, write new object types); checks for problems; **F5** starts the game directly in
|
||||
the level.
|
||||
* **Sharing** – a level is a small `.llamalevel` file with only your changes and no game data; the
|
||||
receiver's LlamaMod builds it from their own copy. New levels live in the hidden *TestLevel*
|
||||
world.
|
||||
* **Save games** – unlock worlds and chapters, coins, collectibles; backups before every change.
|
||||
* **Safe** – the original CD/ISO and files are never changed; *Restore original* switches all mods
|
||||
off.
|
||||
|
||||
---
|
||||
## Get it
|
||||
|
||||
## Requirements
|
||||
You need **your own copy of the game** (CD or ISO image). Development used the German CD; other
|
||||
language versions should work but are untested.
|
||||
|
||||
* 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 |
|
||||
| System | Package | Start |
|
||||
|---|---|---|
|
||||
| `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 |
|
||||
| Windows | `LlamaMod-<version>-full-windows-x64.zip` | unzip, start `LlamaMod.exe` (no installation, no admin rights) |
|
||||
| Linux | `LlamaMod-<version>-full-linux-x64.tar.gz` | unpack, start `./LlamaMod`; install **Wine** to run the game |
|
||||
|
||||
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.
|
||||
Both bring their own Java runtime; the editor needs OpenGL 3.3. A *launcher* edition without the
|
||||
editor is also built. What changed: [CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
---
|
||||
### Build from source
|
||||
|
||||
## Folder layout
|
||||
Needs a JDK 25 (toolchain) and Gradle running on Java 21 (for Spotless):
|
||||
|
||||
```
|
||||
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
|
||||
```bash
|
||||
./gradlew spotlessApply build fatJar # tests + build/libs/llamamod-<ver>-all.jar
|
||||
java -jar build/libs/llamamod-*-all.jar # LlamaMod
|
||||
java -jar build/libs/llamamod-*-all.jar --editor # the level editor alone
|
||||
./gradlew packageAll # Linux + Windows packages, full and launcher edition
|
||||
```
|
||||
|
||||
---
|
||||
Details: [For developers](docs/developers.md).
|
||||
|
||||
## Quick start
|
||||
## Documentation
|
||||
|
||||
**[docs/](docs/README.md)** – start there.
|
||||
|
||||
* **[Build your own level](docs/guide/README.md)** – a step-by-step guide for newcomers.
|
||||
* **[Level editor manual](docs/manual/index.md)** – every tool and dialog, with tutorials (also
|
||||
built into the editor: **F1**).
|
||||
* **[Reference](docs/reference/README.md)** – file formats (WAD, geometry, collision, objects,
|
||||
textures, music), TestLevel, engine limits.
|
||||
* **[Strats](docs/strats/README.md)** – how the game's object scripts work, the script language,
|
||||
custom object types, and the [Alligator Arena walkthrough](docs/strats/arena.md).
|
||||
* **[Tools](docs/tools.md)** – the app's command line, the Python kit, in-game test harnesses.
|
||||
* **[Lab notes](notes/README.md)** – the detailed engineering notebook.
|
||||
|
||||
## The Python kit
|
||||
|
||||
The project started as a Python reverse-engineering kit, which is still in [`tools/`](tools/):
|
||||
byte-exact parsers and writers for every level chunk, OBJ export/import, a script-driven level
|
||||
builder ([`tools/levelbuild.py`](tools/levelbuild.py), example [`levels/testwelt.py`](levels/testwelt.py)),
|
||||
texture and picture converters, a music decoder, the debug-view generator and an automated
|
||||
in-game tester for Linux/Wine. Python 3.8+ with `numpy` and `Pillow`.
|
||||
|
||||
```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
|
||||
# build the original test world from its script
|
||||
python3 tools/levelbuild.py levels/testwelt.py testwelt.wad --base /path/to/cd/wads/t1l1m001.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
|
||||
# music to WAV, loading picture to PNG
|
||||
python3 tools/asf2wav.py /path/to/cd/music/Village.asf village.wav
|
||||
python3 tools/cor2png.py /path/to/cd/t111.cor t111.png
|
||||
```
|
||||
|
||||
### Playing the test level
|
||||
Some scripts have hard-coded paths of the original Wine setup at the top (`WADS`, `MODWAD` in
|
||||
`levelbuild.py`, `CD_WADS` in `debugviz.py`, `PREFIX`/`LAMA_MOD` in `lamatest.py`) – adjust them or
|
||||
pass `--base`/`--src`. All tools: [docs/tools.md](docs/tools.md).
|
||||
|
||||
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`.
|
||||
### Key facts in one minute
|
||||
|
||||
To reach world 9, edit a save file (`king0.ksv`…`king2.ksv`, 256 bytes):
|
||||
* **The world is made of tiles.** TRAK holds 100–650 small models (render triangles + collision
|
||||
polygons); MAP places them on a W × H grid with height and rotation, plus baked vertex colours
|
||||
and a 32-region visibility table. No BSP, no single world mesh.
|
||||
* **Objects are "strats"**: compiled scripts in STPC. An object's type is its byte offset into
|
||||
STPC, so a level can only use the types its own STPC contains (or types merged in from other
|
||||
levels).
|
||||
* **Scale**: y up, one unit per grid cell; the llama is 0.6 tall, walks 1.1 units/s, steps up
|
||||
nothing and jumps ~1.3 far.
|
||||
* **The exit** fires only when the llama stands in the LevelDoor's grid cell **on floor with
|
||||
collision material 16**.
|
||||
* **Textures** are PlayStation-style 15-bit pixels on 256 × 256 pages; there are no free UVs.
|
||||
|
||||
* `+0x04/+0x05` = map cursor (world, chapter)
|
||||
* `+0x3f/+0x40` = current world/chapter
|
||||
* `+0x42/+0x43` = highest unlocked world/chapter
|
||||
More: [docs/reference](docs/reference/README.md).
|
||||
|
||||
Set them to world 9, chapter 1.
|
||||
### Building on this with an AI assistant
|
||||
|
||||
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.
|
||||
This whole project was made by an AI coding agent (Claude Code). To continue it, give an assistant
|
||||
the [lab notes](notes/README.md) first – they contain offsets, field meanings, confidence levels and
|
||||
pitfalls – and let it regenerate the decompile of `groove.exe` with Ghidra for questions about game
|
||||
logic (headless `DumpAll` script, see [Tools](docs/tools.md#reverse-engineering)). Always test in the
|
||||
game (`tools/apptest.py`) and change one thing at a time: the engine crashes on inconsistent data.
|
||||
|
||||
### Debug patch: visible collision and invisible walls
|
||||
## Legal
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
This is a non-commercial fan project, not affiliated with Disney Interactive or Argonaut Games.
|
||||
**No game files are included** – no executable, no level data, no music, no decompiled code. You
|
||||
need your own copy of the game; every tool works on that copy. Please share only tools and your own
|
||||
content (`.llamalevel` projects contain only your changes), not the game's files.
|
||||
Reference in new issue
Block a user