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)
No files matched your search
@@ -0,0 +1,16 @@
|
||||
# game data (copyrighted) - never commit
|
||||
re/groove.exe
|
||||
re/groove_decomp.c
|
||||
re/proj/
|
||||
re/ghidra.log
|
||||
out/
|
||||
*.wad
|
||||
*.WAD
|
||||
*.iso
|
||||
*.deb
|
||||
__pycache__/
|
||||
.~lock.*
|
||||
build/
|
||||
.gradle/
|
||||
.idea/
|
||||
*.iml
|
||||
@@ -0,0 +1,269 @@
|
||||
# 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.
|
||||
|
||||
> Most notes in `notes/` are written in **German**. Any AI assistant can read and translate
|
||||
> them, and that 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 (German)
|
||||
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
|
||||
```
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 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 are German; it can
|
||||
translate). 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.
|
||||
@@ -0,0 +1,289 @@
|
||||
plugins {
|
||||
id 'application'
|
||||
id 'com.diffplug.spotless' version '7.0.2'
|
||||
}
|
||||
|
||||
group = 'com.eliasmueller.llamamod'
|
||||
version = '0.2.0'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
def lwjglVersion = '3.4.2'
|
||||
def lwjglNatives = ['natives-linux', 'natives-windows']
|
||||
|
||||
dependencies {
|
||||
implementation 'com.formdev:flatlaf:3.5.4'
|
||||
implementation 'com.formdev:flatlaf-fonts-inter:4.1'
|
||||
// level editor viewport: LWJGL (OpenGL) inside Swing via lwjgl3-awt; natives for both packages
|
||||
implementation platform("org.lwjgl:lwjgl-bom:${lwjglVersion}")
|
||||
implementation('org.lwjglx:lwjgl3-awt:0.2.5') { transitive = false }
|
||||
implementation 'org.joml:joml:1.10.8'
|
||||
['lwjgl', 'lwjgl-opengl', 'lwjgl-jawt', 'lwjgl-egl'].each { m ->
|
||||
implementation "org.lwjgl:${m}"
|
||||
if (m in ['lwjgl', 'lwjgl-opengl']) {
|
||||
lwjglNatives.each { n -> runtimeOnly "org.lwjgl:${m}::${n}" }
|
||||
}
|
||||
}
|
||||
testImplementation platform('org.junit:junit-bom:5.11.4')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
def targetJavaVersion = 25
|
||||
java {
|
||||
toolchain.languageVersion = JavaLanguageVersion.of(targetJavaVersion)
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8'
|
||||
options.release.set(targetJavaVersion)
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = 'com.eliasmueller.llamamod.Main'
|
||||
}
|
||||
|
||||
// build-info.properties: version and a build id (hash of the compiled classes and resources, without
|
||||
// the edition switch, so an unchanged rebuild keeps the id and the mod cache stays valid)
|
||||
def buildInfoDir = layout.buildDirectory.dir('generated/buildinfo')
|
||||
tasks.register('buildInfo') {
|
||||
def classes = sourceSets.main.output.classesDirs
|
||||
def resources = fileTree('src/main/resources') { exclude 'com/eliasmueller/llamamod/edition.properties' }
|
||||
def ver = project.version.toString()
|
||||
def outDir = buildInfoDir
|
||||
inputs.files(classes).withPathSensitivity(PathSensitivity.RELATIVE)
|
||||
inputs.files(resources).withPathSensitivity(PathSensitivity.RELATIVE)
|
||||
inputs.property('version', ver)
|
||||
outputs.dir(outDir)
|
||||
doLast {
|
||||
def md = java.security.MessageDigest.getInstance('SHA-256')
|
||||
def add = { File root ->
|
||||
if (!root.exists()) {
|
||||
return
|
||||
}
|
||||
def files = []
|
||||
root.eachFileRecurse(groovy.io.FileType.FILES) { files << it }
|
||||
files.sort { root.toPath().relativize(it.toPath()).toString().replace('\\', '/') }.each { f ->
|
||||
if (f.name == 'edition.properties') {
|
||||
return
|
||||
}
|
||||
md.update(root.toPath().relativize(f.toPath()).toString().replace('\\', '/').getBytes('UTF-8'))
|
||||
md.update(f.bytes)
|
||||
}
|
||||
}
|
||||
classes.files.each(add)
|
||||
add(file('src/main/resources'))
|
||||
def id = md.digest().encodeHex().toString().substring(0, 10)
|
||||
def f = outDir.get().file('com/eliasmueller/llamamod/build-info.properties').asFile
|
||||
f.parentFile.mkdirs()
|
||||
f.text = "version=${ver}\nbuild=${id}\n"
|
||||
}
|
||||
}
|
||||
|
||||
// user manual (docs/manual, Markdown + images) bundled for the editor's Help → Manual window
|
||||
processResources {
|
||||
from('docs/manual') {
|
||||
into 'com/eliasmueller/llamamod/editor/tools/help/manual'
|
||||
}
|
||||
from(tasks.named('buildInfo'))
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
// golden tests: -Dllamamod.cd=<cd dir> -Dllamamod.ref=<python reference dir>
|
||||
systemProperty 'llamamod.cd', System.getProperty('llamamod.cd', "${System.getProperty('user.home')}/.wine-lama/iso-dk/Setup/Eng/Cd")
|
||||
systemProperty 'llamamod.ref', System.getProperty('llamamod.ref', '')
|
||||
// level builder references: python3 tools/levelbuild.py levels/testwelt.py <lbref>/testwelt.wad etc.
|
||||
systemProperty 'llamamod.lbref', System.getProperty('llamamod.lbref', '')
|
||||
maxHeapSize = '2g'
|
||||
}
|
||||
|
||||
// fat jars with all dependencies: full edition (fatJar) and launcher edition without the editor UI
|
||||
// (fatJarLauncher, edition.properties editor=false; the editor classes stay, mods need them)
|
||||
def editions = ['full', 'launcher']
|
||||
def launcherEditionDir = layout.buildDirectory.dir('generated/edition-launcher')
|
||||
tasks.register('launcherEdition') {
|
||||
def outDir = launcherEditionDir
|
||||
outputs.dir(outDir)
|
||||
doLast {
|
||||
def f = outDir.get().file('com/eliasmueller/llamamod/edition.properties').asFile
|
||||
f.parentFile.mkdirs()
|
||||
f.text = 'editor=false\n'
|
||||
}
|
||||
}
|
||||
editions.each { ed ->
|
||||
tasks.register(ed == 'full' ? 'fatJar' : 'fatJarLauncher', Jar) {
|
||||
archiveClassifier = ed == 'full' ? 'all' : 'launcher'
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
manifest {
|
||||
attributes 'Main-Class': application.mainClass, 'Implementation-Version': project.version, 'Multi-Release': 'true'
|
||||
}
|
||||
if (ed == 'full') {
|
||||
from sourceSets.main.output
|
||||
} else {
|
||||
from(tasks.named('launcherEdition'))
|
||||
from(sourceSets.main.output) { exclude 'com/eliasmueller/llamamod/edition.properties' }
|
||||
}
|
||||
dependsOn configurations.runtimeClasspath
|
||||
from { configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) } }
|
||||
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class', 'META-INF/versions/*/module-info.class'
|
||||
}
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target 'src/**/*.java'
|
||||
palantirJavaFormat()
|
||||
removeUnusedImports()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- packaging
|
||||
// Self-contained Linux folder (+ .tar.gz) and Windows zip (LlamaMod.exe + runtime), both built on
|
||||
// Linux. jlink cross-links using the Temurin jmods of the target platform; the jlink binary must
|
||||
// be the exact same JDK version (JDK 25 ships no jmods, so they are downloaded separately).
|
||||
// Downloads are cached in ~/opt (override: -Pllamamod.opt=<dir>).
|
||||
def runtimeVersion = '25.0.5+8'
|
||||
def optDir = file(findProperty('llamamod.opt') ?: "${System.getProperty('user.home')}/opt")
|
||||
def distDir = layout.buildDirectory.dir('dist').get().asFile
|
||||
// jdk.unsupported: sun.misc.Unsafe for LWJGL
|
||||
def runtimeModules = 'java.base,java.desktop,java.prefs,java.logging,jdk.charsets,jdk.zipfs,jdk.unsupported'
|
||||
def extraModules = [linux: '', windows: ',jdk.crypto.mscapi']
|
||||
|
||||
def adoptium = { String os, String imageType ->
|
||||
"https://api.adoptium.net/v3/binary/version/jdk-${runtimeVersion.replace('+', '%2B')}/${os}/x64/${imageType}/hotspot/normal/eclipse"
|
||||
}
|
||||
def sh = { List cmd ->
|
||||
def p = new ProcessBuilder(cmd.collect { it.toString() }).inheritIO().start()
|
||||
if (p.waitFor() != 0) {
|
||||
throw new GradleException("Command failed: ${cmd.join(' ')}")
|
||||
}
|
||||
}
|
||||
def download = { String url, File target ->
|
||||
if (!target.exists()) {
|
||||
target.parentFile.mkdirs()
|
||||
logger.lifecycle("Downloading ${url}")
|
||||
def tmp = new File(target.path + '.part')
|
||||
new URI(url).toURL().withInputStream { i -> tmp.withOutputStream { it << i } }
|
||||
tmp.renameTo(target)
|
||||
}
|
||||
target
|
||||
}
|
||||
|
||||
tasks.register('fetchJdk') {
|
||||
description = 'Downloads the Linux JDK (for jlink) and the jmods of both target platforms.'
|
||||
doLast {
|
||||
def jdk = new File(optDir, "jdk-${runtimeVersion}")
|
||||
if (!new File(jdk, 'bin/jlink').exists()) {
|
||||
def tgz = download(adoptium('linux', 'jdk'), new File(optDir, "dl/jdk-${runtimeVersion}-linux.tar.gz"))
|
||||
sh(['tar', 'xzf', tgz, '-C', optDir])
|
||||
}
|
||||
['linux': 'tar.gz', 'windows': 'zip'].each { os, ext ->
|
||||
def dir = new File(optDir, "jmods-${runtimeVersion}-${os}")
|
||||
if (!dir.exists()) {
|
||||
def arc = download(adoptium(os, 'jmods'), new File(optDir, "dl/jmods-${runtimeVersion}-${os}.${ext}"))
|
||||
def tmp = new File(optDir, "jmods-${runtimeVersion}-${os}.tmp")
|
||||
project.delete(tmp)
|
||||
tmp.mkdirs()
|
||||
if (ext == 'zip') {
|
||||
project.copy { from project.zipTree(arc); into tmp }
|
||||
} else {
|
||||
sh(['tar', 'xzf', arc, '-C', tmp])
|
||||
}
|
||||
// archives contain one top-level folder holding the *.jmod files
|
||||
def jmodDir = fileTree(tmp).matching { include '**/java.base.jmod' }.singleFile.parentFile
|
||||
jmodDir.renameTo(dir)
|
||||
project.delete(tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def jlinkTask = { String name, String os ->
|
||||
tasks.register(name) {
|
||||
dependsOn 'fetchJdk'
|
||||
def out = new File(layout.buildDirectory.get().asFile, "runtime-${os}")
|
||||
outputs.dir(out)
|
||||
doLast {
|
||||
project.delete(out)
|
||||
sh([new File(optDir, "jdk-${runtimeVersion}/bin/jlink").path,
|
||||
'--module-path', new File(optDir, "jmods-${runtimeVersion}-${os}").path,
|
||||
'--add-modules', runtimeModules + extraModules[os],
|
||||
'--strip-debug', '--no-header-files', '--no-man-pages',
|
||||
'--compress', 'zip-9',
|
||||
'--output', out.path])
|
||||
}
|
||||
}
|
||||
}
|
||||
jlinkTask('jlinkLinux', 'linux')
|
||||
jlinkTask('jlinkWindows', 'windows')
|
||||
|
||||
def jarTask = { String ed -> ed == 'full' ? 'fatJar' : 'fatJarLauncher' }
|
||||
def suffix = { String ed -> ed == 'full' ? '' : 'Launcher' }
|
||||
def packageName = { String ed, String os -> "LlamaMod-${project.version}-${ed}-${os}-x64" }
|
||||
|
||||
editions.each { ed ->
|
||||
def stage = new File(distDir, "${ed}/LlamaMod-linux-x64")
|
||||
tasks.register("linuxImage${suffix(ed)}", Sync) {
|
||||
dependsOn jarTask(ed), 'jlinkLinux'
|
||||
from(layout.buildDirectory.dir('runtime-linux')) { into 'runtime' }
|
||||
from(tasks.named(jarTask(ed))) { into 'lib'; rename { 'llamamod.jar' } }
|
||||
from('packaging/linux') { filePermissions { unix('rwxr-xr-x') }; include 'LlamaMod', '*.sh' }
|
||||
from('packaging/linux') { exclude 'LlamaMod', '*.sh' }
|
||||
from('src/main/resources/com/eliasmueller/llamamod/ui/icon-256.png') { rename { 'llamamod.png' } }
|
||||
into stage
|
||||
// jlink marks legal/ files read-only, so Sync cannot overwrite them
|
||||
doFirst { project.delete(stage) }
|
||||
}
|
||||
|
||||
tasks.register("packageLinux${suffix(ed)}") {
|
||||
description = "Self-contained Linux build (${ed} edition): build/dist/${packageName(ed, 'linux')}.tar.gz."
|
||||
dependsOn "linuxImage${suffix(ed)}"
|
||||
doLast {
|
||||
// system tar keeps the executable bits of the runtime (Gradle's Tar normalizes them)
|
||||
sh(['tar', 'czf', new File(distDir, "${packageName(ed, 'linux')}.tar.gz"), '-C', stage.parentFile, stage.name])
|
||||
}
|
||||
}
|
||||
|
||||
def exe = new File(layout.buildDirectory.get().asFile, "exe/${ed}/LlamaMod.exe")
|
||||
tasks.register("exeWindows${suffix(ed)}") {
|
||||
description = 'Wraps the fat jar into LlamaMod.exe with launch4j (Linux binary, downloaded to ~/opt).'
|
||||
dependsOn jarTask(ed)
|
||||
inputs.files(tasks.named(jarTask(ed)))
|
||||
inputs.dir('packaging/windows')
|
||||
outputs.file(exe)
|
||||
doLast {
|
||||
def l4j = new File(optDir, 'launch4j')
|
||||
if (!new File(l4j, 'launch4j.jar').exists()) {
|
||||
def tgz = download('https://sourceforge.net/projects/launch4j/files/launch4j-3/3.50/launch4j-3.50-linux-x64.tgz/download',
|
||||
new File(optDir, 'dl/launch4j-3.50-linux-x64.tgz'))
|
||||
sh(['tar', 'xzf', tgz, '-C', optDir])
|
||||
}
|
||||
exe.parentFile.mkdirs()
|
||||
def cfg = new File(exe.parentFile, 'launch4j.xml')
|
||||
cfg.text = file('packaging/windows/launch4j.xml.in').text
|
||||
.replace('@JAR@', tasks.named(jarTask(ed)).get().archiveFile.get().asFile.path)
|
||||
.replace('@OUT@', exe.path)
|
||||
.replace('@ICON@', file('packaging/icon.ico').path)
|
||||
.replace('@VERSION@', project.version.toString())
|
||||
sh([new File(optDir, "jdk-${runtimeVersion}/bin/java").path, '-jar', new File(l4j, 'launch4j.jar').path, cfg.path])
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("packageWindows${suffix(ed)}", Zip) {
|
||||
description = "Windows build (made on Linux, ${ed} edition): build/dist/${packageName(ed, 'windows')}.zip."
|
||||
dependsOn "exeWindows${suffix(ed)}", 'jlinkWindows'
|
||||
from(layout.buildDirectory.dir('runtime-windows')) { into 'LlamaMod/runtime' }
|
||||
from(exe) { into 'LlamaMod' }
|
||||
from('packaging/windows') { exclude '*.in'; into 'LlamaMod' }
|
||||
destinationDirectory = distDir
|
||||
archiveFileName = "${packageName(ed, 'windows')}.zip"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('packageAll') {
|
||||
description = 'Linux and Windows packages of both editions (full, launcher) in build/dist.'
|
||||
dependsOn editions.collectMany { ["packageLinux${suffix(it)}", "packageWindows${suffix(it)}"] }
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Dekodiert Argonaut-ASF-Musik (v2.1, 4-Bit-ADPCM) wie asfcodec.adl aus dem Spiel.
|
||||
|
||||
Nachgebaut aus der Disassembly von asfcodec.adl (Routinen 0x26e01969 / 0x26e01ca1):
|
||||
Filter 0: s = s1 + (n << shift)
|
||||
Filter 1: s = 2*s1 - s2 + (n << shift) (+ Übertrag aus 'adc', s. u.)
|
||||
- kein Clipping; Ausgabe wird als 16 Bit gespeichert (Überlauf = Wrap)
|
||||
- s1 läuft innerhalb eines Blocks ungekürzt im Register weiter,
|
||||
am Blockanfang wird es aus dem 16-Bit-Puffer gelesen
|
||||
- s2 wird immer aus dem 16-Bit-Puffer gelesen
|
||||
Aufruf: asf2wav.py eingabe.asf ausgabe.wav
|
||||
"""
|
||||
import array
|
||||
import struct
|
||||
import sys
|
||||
import wave
|
||||
|
||||
M32 = 0xFFFFFFFF
|
||||
|
||||
|
||||
def s32(x):
|
||||
x &= M32
|
||||
return x - (1 << 32) if x & 0x80000000 else x
|
||||
|
||||
|
||||
def wrap16(x):
|
||||
return ((x + 0x8000) & 0xFFFF) - 0x8000
|
||||
|
||||
|
||||
def decode(data):
|
||||
off = struct.unpack_from('<I', data, 12)[0]
|
||||
nblocks, _, _, rate, _, flags = struct.unpack_from('<IIIHHI', data, off)
|
||||
ch = 2 if flags & 2 else 1
|
||||
p = off + 20
|
||||
out = array.array('h', bytes(nblocks * 32 * ch * 2))
|
||||
mem = [[0, 0] for _ in range(ch)] # gespeicherte 16-Bit-Werte: [vorletztes, letztes]
|
||||
o = 0
|
||||
for _ in range(nblocks):
|
||||
for c in range(ch):
|
||||
ctl = data[p]
|
||||
blk = data[p + 1:p + 17]
|
||||
p += 17
|
||||
cl = (ctl >> 4) + 2
|
||||
prev2, prev1 = mem[c]
|
||||
eax = prev1 # Blockanfang: s1 aus dem Speicher
|
||||
k = o + c
|
||||
for byte in blk:
|
||||
for nib in (byte >> 4, byte & 15):
|
||||
n = nib - 16 if nib & 8 else nib
|
||||
edx = s32((n * 16) << cl)
|
||||
if ctl & 4:
|
||||
ebx = s32(eax << 7)
|
||||
a = s32(-prev2 << 6)
|
||||
carry = ((a & M32) + (edx & M32)) >> 32
|
||||
eax = s32(a + edx + ebx + carry) >> 6
|
||||
else:
|
||||
eax = s32((eax << 6) + edx) >> 6
|
||||
w = wrap16(eax)
|
||||
out[k] = w
|
||||
k += ch
|
||||
prev2, prev1 = prev1, w
|
||||
mem[c] = [prev2, prev1]
|
||||
o += 32 * ch
|
||||
return rate, ch, out
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
rate, ch, pcm = decode(open(sys.argv[1], 'rb').read())
|
||||
with wave.open(sys.argv[2], 'wb') as w:
|
||||
w.setnchannels(ch)
|
||||
w.setsampwidth(2)
|
||||
w.setframerate(rate)
|
||||
w.writeframes(pcm.tobytes())
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/bin/bash
|
||||
# Baut ein .deb für "Ein Königreich für ein Lama" aus einer intakten CD-ISO.
|
||||
# ./build.sh /pfad/zur/GROOVE.iso
|
||||
# Benötigt: 7z, ffmpeg (mit argo_asf/libmp3lame), wrestool, icotool, convert,
|
||||
# fakeroot, dpkg-deb
|
||||
set -euo pipefail
|
||||
umask 022
|
||||
|
||||
ISO=$(realpath "${1:?Aufruf: $0 /pfad/zur/cd.iso}")
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
PKG=ein-koenigreich-fuer-ein-lama
|
||||
VER=1.0-1
|
||||
WORK=$(mktemp -d)
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
ROOT="$WORK/root"
|
||||
OPT="$ROOT/opt/$PKG"
|
||||
|
||||
echo ">> ISO entpacken"
|
||||
mkdir -p "$WORK/iso"
|
||||
7z x -y -o"$WORK/iso" "$ISO" >/dev/null
|
||||
SRC="$WORK/iso/Setup/Eng"
|
||||
[ -f "$SRC/Hd/groove.exe" ] || { echo "groove.exe nicht gefunden – falsche ISO?" >&2; exit 1; }
|
||||
|
||||
echo ">> Integrität prüfen"
|
||||
python3 -I - "$SRC" <<'EOF'
|
||||
import sys, struct, os
|
||||
src = sys.argv[1]
|
||||
bad = []
|
||||
fe = open(os.path.join(src, 'Cd/wads/FESOUND.WAD'), 'rb').read()
|
||||
if struct.unpack('<I', fe[:4])[0] != len(fe) - 4: bad.append('FESOUND.WAD')
|
||||
for f in os.listdir(os.path.join(src, 'Cd/wads')):
|
||||
if f.lower().endswith('.wad') and f.upper() != 'FESOUND.WAD':
|
||||
d = open(os.path.join(src, 'Cd/wads', f), 'rb').read(8)
|
||||
if d[4:8] != b'OFNI': bad.append(f)
|
||||
cvs = open(os.path.join(src, 'Hd/music/english.cvs'), 'rb').read()
|
||||
if cvs[-4 * 1024 * 1024:].count(0) == 4 * 1024 * 1024: bad.append('english.cvs (Nullbereich am Ende)')
|
||||
if bad:
|
||||
sys.exit('Beschädigte Dateien: ' + ', '.join(bad))
|
||||
print(' ok')
|
||||
EOF
|
||||
|
||||
echo ">> Spieldaten"
|
||||
mkdir -p "$OPT"
|
||||
cp -r "$SRC/Cd" "$OPT/cd"
|
||||
cp -r "$SRC/Hd" "$OPT/hd"
|
||||
cp "$WORK/iso/GROOVE.HLP" "$OPT/" 2>/dev/null || true
|
||||
find "$OPT" -type d -exec chmod 755 {} +
|
||||
find "$OPT" -type f -exec chmod 644 {} +
|
||||
|
||||
echo ">> Startskript, Menüeintrag, Icon"
|
||||
install -Dm755 "$HERE/files/$PKG" "$ROOT/usr/games/$PKG"
|
||||
ln -s "$PKG" "$ROOT/usr/games/lama"
|
||||
install -Dm644 "$HERE/files/$PKG.desktop" "$ROOT/usr/share/applications/$PKG.desktop"
|
||||
wrestool -x -t 14 "$SRC/Hd/groove.exe" -o "$WORK/icon.ico"
|
||||
icotool -x -o "$WORK/icon.png" "$WORK/icon.ico" 2>/dev/null
|
||||
for s in 32 64 128; do
|
||||
mkdir -p "$ROOT/usr/share/icons/hicolor/${s}x${s}/apps"
|
||||
convert "$WORK/icon.png" -filter point -resize "${s}x${s}" \
|
||||
"$ROOT/usr/share/icons/hicolor/${s}x${s}/apps/$PKG.png"
|
||||
done
|
||||
|
||||
echo ">> Soundtrack nach MP3"
|
||||
OST="$ROOT/usr/share/$PKG/soundtrack"
|
||||
mkdir -p "$OST"
|
||||
# Nicht FFmpegs adpcm_argo verwenden: der klemmt den Prädiktor auf 16 Bit,
|
||||
# das Original lässt ihn überlaufen -> sonst massiver DC-Offset / Drift.
|
||||
# asf2wav.py dekodiert wie asfcodec.adl; Hochpass 10 Hz entfernt den Rest-DC
|
||||
# (steckt auch im Original), Pegel so, dass das MP3 nicht übersteuert.
|
||||
mkdir -p "$WORK/wav"
|
||||
ls "$SRC/Cd/music/"*.asf | xargs -P "$(nproc)" -I{} \
|
||||
sh -c 'python3 -I "$0" "$1" "$2/$(basename "$1" .asf).wav"' "$HERE/asf2wav.py" {} "$WORK/wav"
|
||||
peak() {
|
||||
ffmpeg -nostdin -v error -i "$1" -c:a pcm_f32le -f f32le - | python3 -I -c \
|
||||
'import sys,array; a=array.array("f",sys.stdin.buffer.read()); print(max(max(a),-min(a)))'
|
||||
}
|
||||
n=0
|
||||
while IFS= read -r f; do
|
||||
n=$((n + 1)); b=$(basename "$f" .wav); out="$OST/$(printf %02d "$n") - $b.mp3"
|
||||
for gain in -2 -4 -6; do
|
||||
ffmpeg -nostdin -hide_banner -loglevel error -y -i "$f" \
|
||||
-af "highpass=f=10:poles=2,volume=${gain}dB" -c:a libmp3lame -q:a 2 \
|
||||
-metadata title="$b" -metadata album="Ein Königreich für ein Lama (PC-Spiel)" \
|
||||
-metadata artist="Disney Interactive / Argonaut Games" -metadata date=2000 \
|
||||
-metadata track="$n" "$out"
|
||||
python3 -I -c 'import sys; sys.exit(float(sys.argv[1]) > 0.99)' "$(peak "$out")" && break
|
||||
done
|
||||
done < <(ls "$WORK/wav/"*.wav | sort -f)
|
||||
chmod 644 "$OST"/*.mp3
|
||||
|
||||
echo ">> Doku"
|
||||
DOC="$ROOT/usr/share/doc/$PKG"
|
||||
install -Dm644 "$HERE/files/README.Debian" "$DOC/README.Debian"
|
||||
install -Dm644 "$HERE/files/copyright" "$DOC/copyright"
|
||||
|
||||
echo ">> Paket bauen"
|
||||
find "$ROOT" -type d -exec chmod 755 {} +
|
||||
mkdir -p "$ROOT/DEBIAN"
|
||||
SIZE=$(du -sk --exclude=DEBIAN "$ROOT" | cut -f1)
|
||||
sed -e "s/@VERSION@/$VER/" -e "s/@SIZE@/$SIZE/" "$HERE/files/control" > "$ROOT/DEBIAN/control"
|
||||
fakeroot dpkg-deb -Zxz -z3 --build "$ROOT" "$HERE/${PKG}_${VER}_all.deb"
|
||||
echo ">> Fertig: $HERE/${PKG}_${VER}_all.deb"
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Entpackt Argonaut-.cor-Bilder (Ein Königreich für ein Lama) nach PNG.
|
||||
|
||||
Aufbau: 8 Byte Signatur 17 98 AF 89 FE 42 D1 12, u32 Version (1),
|
||||
u32 entpackte Größe, u32 gepackte Größe, dann LZ-Daten:
|
||||
n < 0x80 -> n Bytes Rohdaten folgen
|
||||
1LLL oooo oooooooo -> kopiere L+3 Bytes ab o Bytes weiter vorne
|
||||
Das Ergebnis sind 640x480 Pixel à 3 Byte (RGB) oder à 1 Byte (Graustufen, z. B. 151.cor).
|
||||
Aufruf: cor2png.py eingabe.cor ausgabe.png (benötigt Pillow)
|
||||
"""
|
||||
import struct
|
||||
import sys
|
||||
|
||||
MAGIC = bytes.fromhex('1798af89fe42d112')
|
||||
|
||||
|
||||
def unpack(data):
|
||||
if data[:8] != MAGIC:
|
||||
raise ValueError('keine COR-Datei')
|
||||
_, size, packed = struct.unpack_from('<III', data, 8)
|
||||
src = data[20:20 + packed]
|
||||
out = bytearray()
|
||||
i = 0
|
||||
while i < len(src) and len(out) < size:
|
||||
b = src[i]
|
||||
if b < 0x80:
|
||||
out += src[i + 1:i + 1 + b]
|
||||
i += 1 + b
|
||||
else:
|
||||
length = ((b >> 4) & 7) + 3
|
||||
off = ((b & 0x0F) << 8) | src[i + 1]
|
||||
i += 2
|
||||
for _ in range(length):
|
||||
out.append(out[-off])
|
||||
return bytes(out), size
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raw, size = unpack(open(sys.argv[1], 'rb').read())
|
||||
print(f'{sys.argv[1]}: {len(raw)} von {size} Bytes')
|
||||
if len(sys.argv) > 2:
|
||||
from PIL import Image
|
||||
mode = {640 * 480 * 3: 'RGB', 640 * 480: 'L'}[size]
|
||||
Image.frombytes(mode, (640, 480), raw).save(sys.argv[2])
|
||||
@@ -0,0 +1,35 @@
|
||||
Ein Königreich für ein Lama unter Wine
|
||||
======================================
|
||||
|
||||
Start: Menüeintrag "Ein Königreich für ein Lama" oder im Terminal `lama`.
|
||||
|
||||
Installierte Dateien
|
||||
/opt/ein-koenigreich-fuer-ein-lama/cd Inhalt der CD (Setup/Eng/Cd), wird zu Laufwerk L:
|
||||
/opt/ein-koenigreich-fuer-ein-lama/hd Programmdateien (groove.exe, Audio-DLLs, Sprache)
|
||||
/usr/share/ein-koenigreich-fuer-ein-lama/soundtrack Soundtrack als MP3
|
||||
|
||||
Pro Benutzer (beim ersten Start angelegt)
|
||||
~/.wine-lama Wine-Prefix (32 Bit)
|
||||
~/.wine-lama/drive_c/Program Files/Disney Interactive/Ein Koenigreich fuer ein Lama
|
||||
Programmordner, enthält die Spielstände (*.ksv)
|
||||
|
||||
Was der Starter bei jedem Start einrichtet
|
||||
- Laufwerk L: als CD-ROM -> /opt/.../cd (das Spiel prüft dort auf 111.cor)
|
||||
- HKLM\Software\Disney Interactive\Emperors New Groove\1.0: CDPath, ScreenW, ScreenH
|
||||
- Wine-virtueller-Desktop "Lama" in Spielauflösung, damit das Spiel die
|
||||
echte Bildschirmauflösung nicht umstellt (es kennt keinen Fenstermodus)
|
||||
- Arbeitsverzeichnis = Programmordner (das Spiel speichert dort; aus einem
|
||||
schreibgeschützten Verzeichnis gestartet stürzt es ab)
|
||||
|
||||
Fenstergröße
|
||||
Standard: Breite des Hauptmonitors, Höhe = Arbeitsbereich minus Titelleiste.
|
||||
Anpassen in ~/.config/ein-koenigreich-fuer-ein-lama.conf, z. B.:
|
||||
WIDTH=1920
|
||||
HEIGHT=1080
|
||||
TITLEBAR=28
|
||||
|
||||
Bekannte Eigenheiten
|
||||
- "ege bitte die CD ..." – das fehlende "L" ist ein Fehler im Originalspiel.
|
||||
- DEFANIM.WAD wird gesucht, fehlt aber auch auf der Original-CD; harmlos.
|
||||
- Zwischensequenzen sind MPEG-1 (.dat); dafür braucht Wine die 32-Bit-
|
||||
GStreamer-Plugins (gstreamer1.0-plugins-ugly:i386, gstreamer1.0-libav:i386).
|
||||
@@ -0,0 +1,19 @@
|
||||
Package: ein-koenigreich-fuer-ein-lama
|
||||
Version: @VERSION@
|
||||
Section: games
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: wine (>= 6.0), wine32:i386, x11-xserver-utils, x11-utils
|
||||
Recommends: gstreamer1.0-plugins-ugly:i386, gstreamer1.0-libav:i386
|
||||
Installed-Size: @SIZE@
|
||||
Maintainer: Elias Müller <elias@elias-mueller.com>
|
||||
Description: Ein Königreich für ein Lama (Disney/Argonaut, PC 2000) für Wine
|
||||
Deutsche PC-Version von Disneys "Ein Königreich für ein Lama"
|
||||
(The Emperor's New Groove), entwickelt von Argonaut Games.
|
||||
.
|
||||
Enthält die vollständigen Spieldaten der CD, einen Starter, der ein
|
||||
eigenes 32-Bit-Wine-Prefix einrichtet (CD als Laufwerk L:, Registry,
|
||||
virtueller Desktop passend zur Bildschirmgröße), einen Menüeintrag
|
||||
sowie den Soundtrack als MP3.
|
||||
.
|
||||
Nur für den privaten Gebrauch mit eigener Original-CD.
|
||||
@@ -0,0 +1,8 @@
|
||||
Ein Königreich für ein Lama / The Emperor's New Groove (PC)
|
||||
Copyright (C) 2000 Disney Interactive; entwickelt von Argonaut Games PLC.
|
||||
|
||||
Proprietäre Software. Dieses Paket enthält die Daten der Original-CD und ist
|
||||
ausschließlich für den privaten Gebrauch durch Besitzer der Original-CD
|
||||
bestimmt. Weitergabe nicht gestattet.
|
||||
|
||||
Startskript und Paketierung: Elias Müller, 2026.
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/bin/sh
|
||||
# Startet "Ein Königreich für ein Lama" (Disney/Argonaut, 2000) unter Wine.
|
||||
#
|
||||
# Beim ersten Start wird ein eigenes 32-Bit-Wine-Prefix angelegt. Bei jedem
|
||||
# Start werden Laufwerk L: (Spiel-CD), Registry und Fenstergröße gesetzt.
|
||||
#
|
||||
# Einstellungen (optional) in ~/.config/ein-koenigreich-fuer-ein-lama.conf:
|
||||
# WIDTH=1920 # Fensterbreite (Standard: Breite des Hauptmonitors)
|
||||
# HEIGHT=1080 # Fensterhöhe (Standard: Arbeitsbereich - Titelleiste)
|
||||
# TITLEBAR=28 # Höhe der Fenster-Titelleiste in Pixeln
|
||||
# WINEPREFIX=... # anderes Prefix (Standard: ~/.wine-lama)
|
||||
set -e
|
||||
|
||||
DATA=/opt/ein-koenigreich-fuer-ein-lama
|
||||
CONF="${XDG_CONFIG_HOME:-$HOME/.config}/ein-koenigreich-fuer-ein-lama.conf"
|
||||
TITLEBAR=28
|
||||
WIDTH=
|
||||
HEIGHT=
|
||||
[ -f "$CONF" ] && . "$CONF"
|
||||
|
||||
export WINEPREFIX="${WINEPREFIX:-$HOME/.wine-lama}"
|
||||
export WINEARCH=win32
|
||||
export WINEDEBUG="${WINEDEBUG:--all}"
|
||||
|
||||
GAMEDIR="$WINEPREFIX/drive_c/Program Files/Disney Interactive/Ein Koenigreich fuer ein Lama"
|
||||
WINGAME='C:\Program Files\Disney Interactive\Ein Koenigreich fuer ein Lama'
|
||||
|
||||
# --- Prefix anlegen --------------------------------------------------------
|
||||
if [ ! -f "$WINEPREFIX/system.reg" ]; then
|
||||
echo "Lege Wine-Prefix in $WINEPREFIX an ..."
|
||||
wineboot -i >/dev/null 2>&1
|
||||
wineserver -w
|
||||
fi
|
||||
|
||||
# --- Programmdateien (Festplatten-Teil der Installation) -------------------
|
||||
# Programmdateien werden verlinkt; Spielstände (*.ksv) werden kopiert, da das
|
||||
# Spiel sie im Programmverzeichnis überschreibt.
|
||||
mkdir -p "$GAMEDIR/music"
|
||||
for f in "$DATA"/hd/* "$DATA"/hd/music/*; do
|
||||
[ -f "$f" ] || continue
|
||||
rel="${f#"$DATA"/hd/}"
|
||||
case "$f" in
|
||||
*.ksv) [ -e "$GAMEDIR/$rel" ] || { cp "$f" "$GAMEDIR/$rel"; chmod u+w "$GAMEDIR/$rel"; } ;;
|
||||
*) ln -sfn "$f" "$GAMEDIR/$rel" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# --- Spiel-CD als Laufwerk L: ----------------------------------------------
|
||||
# Mit aktiven Mods (lama-mod an) zeigt L: auf das Overlay.
|
||||
if [ -d "$WINEPREFIX/cd-overlay" ]; then
|
||||
ln -sfn "$WINEPREFIX/cd-overlay" "$WINEPREFIX/dosdevices/l:"
|
||||
else
|
||||
ln -sfn "$DATA/cd" "$WINEPREFIX/dosdevices/l:"
|
||||
fi
|
||||
|
||||
# --- Fenstergröße bestimmen ------------------------------------------------
|
||||
if [ -z "$WIDTH" ] || [ -z "$HEIGHT" ]; then
|
||||
geo=$(xrandr --current 2>/dev/null | awk '
|
||||
/ connected/ { for (i = 1; i <= NF; i++) if ($i ~ /^[0-9]+x[0-9]+\+/) {
|
||||
if ($0 ~ / primary /) { print $i; found = 1; exit }
|
||||
if (!first) first = $i } }
|
||||
END { if (!found && first) print first }')
|
||||
mw=${geo%%x*}
|
||||
mh=${geo#*x}; mh=${mh%%+*}
|
||||
wa=$(xprop -root _NET_WORKAREA 2>/dev/null | sed -n 's/.*= *//p' | cut -d, -f4 | tr -d ' ')
|
||||
case "$mw$mh" in ''|*[!0-9]*) mw=1024; mh=768 ;; esac
|
||||
h=$mh
|
||||
case "$wa" in ''|*[!0-9]*) ;; *) [ "$wa" -lt "$h" ] && h=$wa ;; esac
|
||||
h=$((h - TITLEBAR))
|
||||
: "${WIDTH:=$mw}"
|
||||
: "${HEIGHT:=$h}"
|
||||
fi
|
||||
|
||||
# --- Registry --------------------------------------------------------------
|
||||
REG=$(mktemp --suffix=.reg)
|
||||
trap 'rm -f "$REG"' EXIT
|
||||
cat > "$REG" <<EOF
|
||||
REGEDIT4
|
||||
|
||||
[HKEY_LOCAL_MACHINE\\Software\\Wine\\Drives]
|
||||
"l:"="cdrom"
|
||||
|
||||
[HKEY_LOCAL_MACHINE\\Software\\Disney Interactive\\Emperors New Groove\\1.0]
|
||||
"CDPath"="L:\\\\"
|
||||
"ScreenW"=dword:$(printf %08x "$WIDTH")
|
||||
"ScreenH"=dword:$(printf %08x "$HEIGHT")
|
||||
|
||||
[HKEY_CURRENT_USER\\Software\\Wine\\Explorer]
|
||||
"Desktop"="Lama"
|
||||
|
||||
[HKEY_CURRENT_USER\\Software\\Wine\\Explorer\\Desktops]
|
||||
"Lama"="${WIDTH}x${HEIGHT}"
|
||||
EOF
|
||||
wine regedit "$REG" >/dev/null 2>&1
|
||||
|
||||
# --- Start -----------------------------------------------------------------
|
||||
# Das Spiel legt Spielstände im aktuellen Verzeichnis an.
|
||||
cd "$GAMEDIR"
|
||||
wine "$WINGAME\\groove.exe" "$@"
|
||||
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Ein Königreich für ein Lama
|
||||
GenericName=Jump'n'Run
|
||||
Comment=Disneys Ein Königreich für ein Lama (2000) unter Wine
|
||||
Exec=/usr/games/ein-koenigreich-fuer-ein-lama
|
||||
Icon=ein-koenigreich-fuer-ein-lama
|
||||
Terminal=false
|
||||
Categories=Game;ActionGame;
|
||||
StartupWMClass=explorer.exe
|
||||
@@ -0,0 +1,97 @@
|
||||
#!/bin/sh
|
||||
# Mods für "Ein Königreich für ein Lama" ein- und ausschalten.
|
||||
#
|
||||
# lama-mod an Mods aus ~/.wine-lama/mods/*/ aktivieren
|
||||
# lama-mod aus Originalzustand (L: = unveränderte CD-Daten)
|
||||
# lama-mod status
|
||||
# lama-mod debug an Debug-Ansicht (Kollision/unsichtbare Objekte) zuschalten
|
||||
# lama-mod debug aus Debug-Ansicht abschalten (andere Mods bleiben, wie sie sind)
|
||||
#
|
||||
# Eine Mod ist ein Ordner, dessen Dateien so liegen wie auf der CD unter
|
||||
# Setup/Eng/Cd (z. B. wads/T1L9M001.wad, T191.COR, movies/191INTRO.DAT).
|
||||
# Aktiviert wird über ein Overlay aus Symlinks: Originaldateien bleiben
|
||||
# unangetastet, Mod-Dateien kommen dazu bzw. ersetzen gleichnamige.
|
||||
# Mods mit einer Datei ".aus" im Ordner werden übersprungen (so schaltet
|
||||
# "lama-mod debug an|aus" die Mod "debug" unabhängig von den anderen).
|
||||
# Reihenfolge: alphabetisch, spätere Mods gewinnen (testlevel > debug).
|
||||
set -e
|
||||
export WINEPREFIX="${WINEPREFIX:-$HOME/.wine-lama}"
|
||||
MODS="$WINEPREFIX/mods"
|
||||
OVL="$WINEPREFIX/cd-overlay"
|
||||
DBG="$MODS/debug"
|
||||
|
||||
if [ -d /opt/ein-koenigreich-fuer-ein-lama/cd ]; then
|
||||
BASE=/opt/ein-koenigreich-fuer-ein-lama/cd
|
||||
else
|
||||
BASE="$WINEPREFIX/iso-dk/Setup/Eng/Cd"
|
||||
fi
|
||||
|
||||
overlay_an() {
|
||||
rm -rf "$OVL"
|
||||
mkdir -p "$OVL"
|
||||
(cd "$BASE" && find . -type d) | while IFS= read -r d; do mkdir -p "$OVL/$d"; done
|
||||
(cd "$BASE" && find . -type f) | while IFS= read -r f; do ln -s "$BASE/$f" "$OVL/$f"; done
|
||||
for m in "$MODS"/*/; do
|
||||
[ -d "$m" ] || continue
|
||||
if [ -e "$m/.aus" ]; then
|
||||
echo "Mod: $(basename "$m") (abgeschaltet)"
|
||||
continue
|
||||
fi
|
||||
echo "Mod: $(basename "$m")"
|
||||
(cd "$m" && find . -path ./src -prune -o -name .aus -prune -o \( -type f -o -type l \) -print) | while IFS= read -r f; do
|
||||
# vorhandene Datei gleichen Namens (Groß-/Kleinschreibung egal) ersetzen
|
||||
dir=$(dirname "$f"); name=$(basename "$f")
|
||||
mkdir -p "$OVL/$dir"
|
||||
find "$OVL/$dir" -maxdepth 1 -iname "$name" -exec rm -f {} +
|
||||
ln -s "$m/$f" "$OVL/$f"
|
||||
[ -n "$LEISE" ] || echo " + $f"
|
||||
done
|
||||
done
|
||||
ln -sfn "$OVL" "$WINEPREFIX/dosdevices/l:"
|
||||
echo "Mods aktiv (L: -> $OVL)"
|
||||
}
|
||||
|
||||
case "${1:-status}" in
|
||||
an|on)
|
||||
overlay_an
|
||||
;;
|
||||
aus|off)
|
||||
ln -sfn "$BASE" "$WINEPREFIX/dosdevices/l:"
|
||||
rm -rf "$OVL"
|
||||
echo "Originalzustand (L: -> $BASE)"
|
||||
;;
|
||||
debug)
|
||||
if [ ! -d "$DBG/wads" ]; then
|
||||
echo "Debug-Mod fehlt ($DBG/wads)." >&2; exit 1
|
||||
fi
|
||||
case "${2:-status}" in
|
||||
an|on)
|
||||
rm -f "$DBG/.aus"
|
||||
LEISE=1 overlay_an
|
||||
echo "Debug-Ansicht AN ($(ls "$DBG/wads" | wc -l) Level). Wirkt beim nächsten Laden eines Levels."
|
||||
;;
|
||||
aus|off)
|
||||
touch "$DBG/.aus"
|
||||
if [ "$(readlink "$WINEPREFIX/dosdevices/l:")" = "$OVL" ]; then
|
||||
LEISE=1 overlay_an
|
||||
fi
|
||||
echo "Debug-Ansicht AUS."
|
||||
;;
|
||||
status)
|
||||
if [ -e "$DBG/.aus" ]; then echo "Debug-Ansicht: aus"; else echo "Debug-Ansicht: an (wenn Mods aktiv)"; fi
|
||||
;;
|
||||
*)
|
||||
sed -n '2,9p' "$0"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
status)
|
||||
echo "L: -> $(readlink "$WINEPREFIX/dosdevices/l:")"
|
||||
for m in "$MODS"/*/; do
|
||||
[ -d "$m" ] || continue
|
||||
if [ -e "$m/.aus" ]; then s=" (abgeschaltet)"; else s=""; fi
|
||||
echo "installierte Mod: $(basename "$m")$s"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
sed -n '2,9p' "$0"; exit 1 ;;
|
||||
esac
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/sh
|
||||
# Mods für "Ein Königreich für ein Lama" ein- und ausschalten.
|
||||
#
|
||||
# lama-mod an Mods aus ~/.wine-lama/mods/*/ aktivieren
|
||||
# lama-mod aus Originalzustand (L: = unveränderte CD-Daten)
|
||||
# lama-mod status
|
||||
#
|
||||
# Eine Mod ist ein Ordner, dessen Dateien so liegen wie auf der CD unter
|
||||
# Setup/Eng/Cd (z. B. wads/T1L9M001.wad, T191.COR, movies/191INTRO.DAT).
|
||||
# Aktiviert wird über ein Overlay aus Symlinks: Originaldateien bleiben
|
||||
# unangetastet, Mod-Dateien kommen dazu bzw. ersetzen gleichnamige.
|
||||
set -e
|
||||
export WINEPREFIX="${WINEPREFIX:-$HOME/.wine-lama}"
|
||||
MODS="$WINEPREFIX/mods"
|
||||
OVL="$WINEPREFIX/cd-overlay"
|
||||
|
||||
if [ -d /opt/ein-koenigreich-fuer-ein-lama/cd ]; then
|
||||
BASE=/opt/ein-koenigreich-fuer-ein-lama/cd
|
||||
else
|
||||
BASE="$WINEPREFIX/iso-dk/Setup/Eng/Cd"
|
||||
fi
|
||||
|
||||
case "${1:-status}" in
|
||||
an|on)
|
||||
rm -rf "$OVL"
|
||||
mkdir -p "$OVL"
|
||||
(cd "$BASE" && find . -type d) | while IFS= read -r d; do mkdir -p "$OVL/$d"; done
|
||||
(cd "$BASE" && find . -type f) | while IFS= read -r f; do ln -s "$BASE/$f" "$OVL/$f"; done
|
||||
for m in "$MODS"/*/; do
|
||||
[ -d "$m" ] || continue
|
||||
echo "Mod: $(basename "$m")"
|
||||
(cd "$m" && find . -path ./src -prune -o \( -type f -o -type l \) -print) | while IFS= read -r f; do
|
||||
# vorhandene Datei gleichen Namens (Groß-/Kleinschreibung egal) ersetzen
|
||||
dir=$(dirname "$f"); name=$(basename "$f")
|
||||
mkdir -p "$OVL/$dir"
|
||||
find "$OVL/$dir" -maxdepth 1 -iname "$name" -exec rm -f {} +
|
||||
ln -s "$m/$f" "$OVL/$f"
|
||||
echo " + $f"
|
||||
done
|
||||
done
|
||||
ln -sfn "$OVL" "$WINEPREFIX/dosdevices/l:"
|
||||
echo "Mods aktiv (L: -> $OVL)"
|
||||
;;
|
||||
aus|off)
|
||||
ln -sfn "$BASE" "$WINEPREFIX/dosdevices/l:"
|
||||
rm -rf "$OVL"
|
||||
echo "Originalzustand (L: -> $BASE)"
|
||||
;;
|
||||
status)
|
||||
echo "L: -> $(readlink "$WINEPREFIX/dosdevices/l:")"
|
||||
ls -1 "$MODS" 2>/dev/null | sed 's/^/installierte Mod: /'
|
||||
;;
|
||||
*)
|
||||
sed -n '2,12p' "$0"; exit 1 ;;
|
||||
esac
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Packt ein Bild als Argonaut-.cor (Gegenstück zu cor2png.py).
|
||||
|
||||
Das Bild wird auf 640x480 RGB gebracht und mit dem LZ-Schema des Spiels
|
||||
komprimiert:
|
||||
n < 0x80 -> n Bytes Rohdaten folgen (n = 1..127)
|
||||
1LLL oooo oooooooo -> kopiere L+3 Bytes (3..10) ab o Bytes (1..4095) zurück
|
||||
Aufruf: png2cor.py eingabe.png ausgabe.cor (benötigt Pillow)
|
||||
"""
|
||||
import struct
|
||||
import sys
|
||||
|
||||
MAGIC = bytes.fromhex('1798af89fe42d112')
|
||||
MAXOFF, MINLEN, MAXLEN = 0x0FFF, 3, 10
|
||||
|
||||
|
||||
def pack(raw):
|
||||
out = bytearray()
|
||||
lit = bytearray()
|
||||
last = {} # 3-Byte-Präfix -> Liste letzter Positionen
|
||||
|
||||
def flush():
|
||||
for k in range(0, len(lit), 127):
|
||||
part = lit[k:k + 127]
|
||||
out.append(len(part))
|
||||
out.extend(part)
|
||||
lit.clear()
|
||||
|
||||
i, n = 0, len(raw)
|
||||
while i < n:
|
||||
best_len, best_off = 0, 0
|
||||
if i + MINLEN <= n:
|
||||
key = raw[i:i + 3]
|
||||
for p in reversed(last.get(key, ())):
|
||||
off = i - p
|
||||
if off > MAXOFF:
|
||||
break
|
||||
ln = 3
|
||||
while ln < MAXLEN and i + ln < n and raw[p + ln] == raw[i + ln]:
|
||||
ln += 1
|
||||
if ln > best_len:
|
||||
best_len, best_off = ln, off
|
||||
if ln == MAXLEN:
|
||||
break
|
||||
step = best_len if best_len >= MINLEN else 1
|
||||
for j in range(i, min(i + step, n - 2)):
|
||||
lst = last.setdefault(raw[j:j + 3], [])
|
||||
lst.append(j)
|
||||
if len(lst) > 16:
|
||||
del lst[0]
|
||||
if best_len >= MINLEN:
|
||||
flush()
|
||||
out.append(0x80 | ((best_len - 3) << 4) | (best_off >> 8))
|
||||
out.append(best_off & 0xFF)
|
||||
i += best_len
|
||||
else:
|
||||
lit.append(raw[i])
|
||||
i += 1
|
||||
flush()
|
||||
return MAGIC + struct.pack('<III', 1, len(raw), len(out)) + bytes(out)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from PIL import Image
|
||||
img = Image.open(sys.argv[1]).convert('RGB').resize((640, 480), Image.LANCZOS)
|
||||
data = pack(img.tobytes())
|
||||
open(sys.argv[2], 'wb').write(data)
|
||||
print(f'{sys.argv[2]}: {len(data)} Bytes')
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Liest und schreibt Level-WADs von "Ein Königreich für ein Lama" (Argonaut).
|
||||
|
||||
Aufbau: u32 Gesamtlänge (ohne dieses Feld), dann Chunks:
|
||||
4 Byte Kennung (rückwärts gespeichert, z. B. 'OFNI' = INFO), u32 Länge, Daten
|
||||
bis zum Chunk 'END '.
|
||||
|
||||
wadtool.py list level.wad
|
||||
wadtool.py name level.wad neu.wad "Neuer Levelname"
|
||||
wadtool.py extract level.wad CHUNK datei.bin
|
||||
wadtool.py replace level.wad neu.wad CHUNK datei.bin
|
||||
"""
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def read(path):
|
||||
d = open(path, 'rb').read()
|
||||
total = struct.unpack_from('<I', d, 0)[0]
|
||||
if total != len(d) - 4:
|
||||
raise ValueError(f'{path}: Längenfeld {total} passt nicht zu {len(d) - 4}')
|
||||
chunks, o = [], 4
|
||||
while o + 8 <= len(d):
|
||||
tag = d[o:o + 4][::-1].decode('latin1')
|
||||
ln = struct.unpack_from('<I', d, o + 4)[0]
|
||||
chunks.append([tag, d[o + 8:o + 8 + ln]])
|
||||
o += 8 + ln
|
||||
if tag == 'END ':
|
||||
break
|
||||
return chunks
|
||||
|
||||
|
||||
def write(path, chunks):
|
||||
body = b''.join(t.encode('latin1')[::-1] + struct.pack('<I', len(c)) + c for t, c in chunks)
|
||||
open(path, 'wb').write(struct.pack('<I', len(body)) + body)
|
||||
|
||||
|
||||
def get(chunks, tag):
|
||||
for c in chunks:
|
||||
if c[0] == tag:
|
||||
return c
|
||||
raise KeyError(tag)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cmd, src = sys.argv[1], sys.argv[2]
|
||||
ch = read(src)
|
||||
if cmd == 'list':
|
||||
for t, c in ch:
|
||||
extra = ''
|
||||
if t == 'NAME':
|
||||
extra = repr(c[4:].split(b'\0')[0].decode('latin1'))
|
||||
print(f'{t!r:8} {len(c):10d} {extra}')
|
||||
elif cmd == 'name':
|
||||
c = get(ch, 'NAME')
|
||||
c[1] = c[1][:4] + sys.argv[4].encode('latin1') + b'\0'
|
||||
write(sys.argv[3], ch)
|
||||
elif cmd == 'extract':
|
||||
open(sys.argv[4], 'wb').write(get(ch, sys.argv[3].ljust(4))[1])
|
||||
elif cmd == 'replace':
|
||||
get(ch, sys.argv[4].ljust(4))[1] = open(sys.argv[5], 'rb').read()
|
||||
write(sys.argv[3], ch)
|
||||
else:
|
||||
sys.exit(__doc__)
|
||||
@@ -0,0 +1,104 @@
|
||||
# Introduction and concepts
|
||||
|
||||
The **LlamaMod level editor** is a 3D editor for the levels of *The Emperor's New Groove* (PC,
|
||||
2000, Argonaut's Croc 2 engine; German: *Ein Königreich für ein Lama*). It belongs to
|
||||
**LlamaMod**, a mod manager for the same game: every level you make is installed and played as a
|
||||
LlamaMod mod, and LlamaMod also brings ready-made mods such as a free camera, a randomizer or a
|
||||
mirror mode (see [LlamaMod mods](18-mods.md)).
|
||||
|
||||
With the editor you can
|
||||
|
||||
* build **new levels** from blocks, ramps, stairs, water, imported 3D models and the game's own
|
||||
tile models, place coins, enemies, checkpoints and the exit, and play them in the game;
|
||||
* **change the original levels** – move, add or remove anything, repaint textures, change fog,
|
||||
music and light;
|
||||
* **share** your work as a small `.llamalevel` file that contains no game data, so anyone with
|
||||
the game can play it.
|
||||
|
||||
> **Note:** The editor never changes your installed game or your CD. LlamaMod works on a private
|
||||
> copy of the game data and builds every level from *your own copy* of the game.
|
||||
|
||||
## What a level is made of
|
||||
|
||||
The game stores each level in one `.wad` file. The editor shows its parts as a tree in the
|
||||
**Outliner** and as properties in the **Inspector**:
|
||||
|
||||
| Part | What it is |
|
||||
|---|---|
|
||||
| **Grid and cells** | A level is a rectangular grid of square **cells**. One cell is one grid square in the viewport (4096 game units); the llama is about 0.6 cells tall. Collision is looked up per cell. |
|
||||
| **Tiles** | The building blocks of the original levels: a *tile model* placed in one cell, turned in steps about the vertical axis. A model can be used by many tiles. |
|
||||
| **Tile models** | The 3D models of the level's tile set with their faces, textures and collision polygons. |
|
||||
| **Brushes** | Editor shapes – floors, blocks, platforms, ramps, stairs, walls, round platforms, fences, trees, water, death planes and imported meshes. They have any size and rotation; when the level is built they are cut into 1×1-cell tiles automatically. See [Building geometry](06-geometry.md). |
|
||||
| **Objects** | Everything with behaviour: the llama (player start), coins, food, checkpoints, the exit door, enemies, villagers, moving platforms, cameras and triggers. The game calls them *strats* (small scripts). See [Objects](09-objects.md). |
|
||||
| **Waypoints** | Chains of points that belong to objects: patrol paths of enemies, camera paths, respawn points, the two corners of trigger boxes. See [Waypoints and paths](10-waypoints.md). |
|
||||
| **Zones** | Environment and teleport entries: fog, sky colour, ambient light and music of an area, and the doors that move the player to another place. See [Environment](12-environment.md). |
|
||||
| **Lights** | Directional and point lights that light the object models. Tiles get their light from baked vertex colours. |
|
||||
| **Visibility regions** | Which parts of the level are drawn from where – the engine's way to stay fast. See [Visibility regions](13-visibility.md). |
|
||||
| **Textures** | 256×256 texture pages and the texture rectangles on them, with optional animations. See [Textures](08-textures.md). |
|
||||
| **Level settings** | Name, author, grid size, death plane height, feature flags and the TestLevel chapter. See [Level settings](14-level-settings.md). |
|
||||
|
||||
## Collision materials
|
||||
|
||||
Every collision polygon has a **material** number that tells the game what happens when the llama
|
||||
touches it. The important ones:
|
||||
|
||||
| Material | Meaning |
|
||||
|---|---|
|
||||
| **0** | normal ground and walls |
|
||||
| **16** | **exit floor** – the level door (LevelDoor object) ends the level when the llama stands on it in the door's cell |
|
||||
| **30** | **no floor / death** – the llama falls, loses a life and respawns at the last checkpoint |
|
||||
| 17, 18 | selective collision (used by a level feature flag) |
|
||||
| others | special surfaces whose meaning is not known yet |
|
||||
|
||||
Press **C** in the editor to see collision coloured by material. The **Collision** tool paints
|
||||
materials (see [Building geometry](06-geometry.md)).
|
||||
|
||||
## Coordinates
|
||||
|
||||
Positions are given in **cells**: **x** grows to the east, **y** is the height, **z** is the grid
|
||||
row (it grows to the south). The status bar shows the position under the mouse pointer and the
|
||||
grid cell. Angles are in degrees; an object with yaw 0° faces +z.
|
||||
|
||||
> **Engine limit:** Tiles and objects can only turn about the vertical axis. Brushes can turn
|
||||
> freely – the build converts them into tiles.
|
||||
|
||||
## Base levels
|
||||
|
||||
Object types, their models and scripts, sounds, the sky and the default textures are not
|
||||
something the editor can create from nothing. Every project therefore has a **base level**: one of
|
||||
the original levels that provides these things. A new level built on *Village chapter 1* can use
|
||||
every object that exists in that chapter – coins, checkpoints, villagers, the exit door and so on.
|
||||
Choose a base whose objects and look you want. The base level is fixed when the project is
|
||||
created. Object types of other levels can be added later with **Assets → All worlds**
|
||||
([Importing objects from other worlds](09-objects.md#importing-objects-from-other-worlds)).
|
||||
|
||||
## Worlds, chapters and the TestLevel
|
||||
|
||||
The game has eight worlds – **Village, Jungle at Night, River, Jungle by Day, Mountain, City,
|
||||
Catacombs, Lab** – each with several chapters. A ninth, hidden world called **TestLevel** has 49
|
||||
empty chapter slots. New levels go into one of these TestLevel chapters, so they never replace an
|
||||
original level: each project gets its own chapter (shown in the New level dialog and in
|
||||
[Level settings](14-level-settings.md)). In the game they appear on the world-9 map as
|
||||
"TestLevel – chapter *n*".
|
||||
|
||||
Edited original levels are different: they replace that original chapter while their mod is
|
||||
switched on in LlamaMod.
|
||||
|
||||
## Projects
|
||||
|
||||
The editor saves **projects** as `.llamalevel` files. A project stores only *your changes* to the
|
||||
base level plus your own imported meshes and textures – never the game's files. That keeps
|
||||
projects small (often a few kilobytes) and shareable. When a level is built, the editor reads the
|
||||
base level from your game copy and applies the changes; building the same project with the same
|
||||
game always gives the same result.
|
||||
|
||||
LlamaMod lists every project in its **levels** folder as a mod in the **Levels** category. Tick it
|
||||
and press **Play** to play the level – or press **F5** in the editor. See
|
||||
[Sharing levels](17-sharing.md).
|
||||
|
||||
## What you need
|
||||
|
||||
* The PC game (CD or ISO image; developed with the German version).
|
||||
* LlamaMod – see [Installing LlamaMod](02-installing.md).
|
||||
* A graphics card with **OpenGL 3.3** for the editor's 3D view.
|
||||
* On Linux, Wine to run the game (LlamaMod sets it up).
|
||||
@@ -0,0 +1,88 @@
|
||||
# Installing LlamaMod and the first start
|
||||
|
||||
LlamaMod runs on **Windows** and **Linux**. It needs your own copy of the game – the CD or an ISO
|
||||
image of it. The game itself does not have to be installed: LlamaMod copies what it needs into
|
||||
its own data folder and never changes the original.
|
||||
|
||||
## Download and start
|
||||
|
||||
| System | Package | Start |
|
||||
|---|---|---|
|
||||
| Windows | `LlamaMod-<version>-full-windows-x64.zip` | Unzip anywhere and start **LlamaMod.exe**. Keep `LlamaMod.exe` and the `runtime` folder together. No installation and no administrator rights are needed. |
|
||||
| Linux | `LlamaMod-<version>-full-linux-x64.tar.gz` | Unpack and start `./LlamaMod`. `./install-desktop-entry.sh` adds a menu entry. Install **Wine** to run the game. |
|
||||
|
||||
Both packages bring their own Java runtime. The editor's 3D view needs a graphics driver with
|
||||
**OpenGL 3.3** (any graphics card from the last ten years).
|
||||
|
||||
## First start: setting up the game
|
||||
|
||||
On the first start a wizard asks where your game is:
|
||||
|
||||

|
||||
|
||||
1. Choose **ISO file…** for a CD image, or **Folder / CD…** for the inserted CD or a copied
|
||||
folder. LlamaMod shows how many files it found and how much disk space it needs – or, in red,
|
||||
what is wrong: the file is not a CD image, the folder does not contain the game, the ISO file
|
||||
is incomplete (an interrupted download), or the disk is too full.
|
||||
2. Check the **Data folder**. Game copy, mods, save games and settings are stored there. The
|
||||
default is `%LOCALAPPDATA%\LlamaMod` on Windows and `~/.local/share/LlamaMod` on Linux;
|
||||
**Change…** picks another place.
|
||||
3. Click **Set up**. LlamaMod copies the game data, checks it for damaged files and reports
|
||||
**All set!** **Cancel** stops the copy; clicking **Set up** again continues where it stopped.
|
||||
|
||||
You can repeat this later with **Settings → Set up again…**.
|
||||
|
||||
## The LlamaMod window
|
||||
|
||||

|
||||
|
||||
* **▶ Play** (top right) starts the game with the selected mods. While the game runs, the button
|
||||
reads **■ Quit game** – handy when the game hangs or its window is hidden. If the game
|
||||
crashes, LlamaMod says so and offers to open the log files.
|
||||
* **Level Editor** (next to Play) opens the level editor in its own window.
|
||||
* The **Mods** tab lists all mods by category (**Levels**, **Gameplay**, **Visual**,
|
||||
**Cheats & debug**). Tick the ones you want, set their options (each one is explained next to
|
||||
it) and click **Apply**. **Restore original** switches all mods off. Mods marked *modifies groove.exe* change the
|
||||
game program in LlamaMod's private copy (see [antivirus warnings](20-troubleshooting.md)).
|
||||
All mods and their options are listed in [LlamaMod mods](18-mods.md).
|
||||
* The **Save games** tab edits the three save slots: unlocked worlds and chapters, coins, gold
|
||||
coins and collectibles per level, lives, where the world map **Opens at**, **Unlock all
|
||||
worlds** and **Unlock TestLevel (world 9)**. **Undo changes** throws away unsaved edits. A
|
||||
backup is made before every change (**Backups** opens the folder); **Import…** reads a `.ksv`
|
||||
file and starts in the backups folder, so restoring a backup is two clicks.
|
||||
* The **Settings** tab sets the game resolution (**Automatic** shows the size it will use),
|
||||
**Run in a window** (Linux: Wine virtual desktop, recommended), the light or dark
|
||||
**Appearance**, the Wine command, the data folder (**Open folder**, **Logs**), **Set up
|
||||
again…** (copies the game once more; mods, settings and save games are kept) and **Clear
|
||||
cache** for the mod cache.
|
||||
|
||||

|
||||
|
||||
> **Tip:** Every level project in the data folder's `levels` folder appears as a mod in the
|
||||
> **Levels** category. That is how you install levels from other people – see
|
||||
> [Sharing levels](17-sharing.md).
|
||||
|
||||
## Starting the editor
|
||||
|
||||
* Click **Level Editor** in LlamaMod's header, or
|
||||
* start LlamaMod with `--editor`, optionally followed by a project file or the name of an
|
||||
original level, for example `LlamaMod --editor t1l1m001` (Village chapter 1).
|
||||
|
||||
The editor opens with a start page: **New level**, **Open original level**, **Open project** and
|
||||
your recent projects. **Help → Getting started** (**Shift+F1**) shows a five-step tour, and this
|
||||
manual is always one **F1** away.
|
||||
|
||||

|
||||
|
||||
## The data folder
|
||||
|
||||
| Folder | Content |
|
||||
|---|---|
|
||||
| `levels/` | your level projects (`.llamalevel`) – each one is a mod |
|
||||
| `editor/` | editor settings, autosaves, prefabs |
|
||||
| `library/` | geometry saved to the editor's library (`.llamamesh`) |
|
||||
| `original/` | the untouched copy of the game from your CD |
|
||||
| `game/`, `cd-active/` | the copy the game runs from, with the active mods applied |
|
||||
| `cache/` | built mod files (cleared with **Settings → Clear cache**) |
|
||||
| `backups/saves/` | save game backups |
|
||||
| `logs/` | log files (game, mod apply) for troubleshooting |
|
||||
@@ -0,0 +1,170 @@
|
||||
# The editor window
|
||||
|
||||

|
||||
|
||||
The window has six areas:
|
||||
|
||||
| Area | Content |
|
||||
|---|---|
|
||||
| **Menu bar** | File, Edit, View, Level, Geometry, Tools, Help – every command of the editor. The [menu reference](19-shortcuts.md) lists them all. |
|
||||
| **Toolbar** | New / open original / open / save, undo / redo, the **tools** in groups – Select, Move, Rotate, Scale · Brush, Tiles, Collision · Paint texture · Place objects, Coins, Waypoints, Zones & triggers · Zones, Lights, Vertex colours, Regions – then duplicate / delete / frame, **Build** and **Play**. The editor always starts with the Select tool. |
|
||||
| **Options bar** | Above the viewport: the active tool with its options, then **Snap**, the move step, the angle step, **World / Local**, the camera view and **Layers**. |
|
||||
| **Viewport** | The level in 3D. See [Navigating the viewport](04-navigation.md). |
|
||||
| **Panels** | Docked around the viewport: Outliner, Objects, Environment, History on the left, Inspector and Visibility on the right, Assets, Textures and Problems at the bottom. |
|
||||
| **Status bar** | Messages, the item under the mouse pointer, the cursor position in cells and the grid cell, counts (tiles · objects · waypoints · selected), the result of the last build (click it to open Problems) and the progress of background work. |
|
||||
|
||||
## The start page
|
||||
|
||||
When no level is open the viewport shows the start page: **New level** (from an empty island, a
|
||||
flat floor or nothing, on a TestLevel chapter), **Open original level** (Village, Jungle, River,
|
||||
City … – move, add and remove anything), **Open project** (a saved `.llamalevel` file) and the
|
||||
list of recent projects.
|
||||
|
||||
## Creating a new level
|
||||
|
||||
**File → New level…** (**Ctrl+N**) opens the **New level** dialog:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Level name** | The name LlamaMod and the loading picture show. |
|
||||
| **Author** | Your name (remembered for the next level). |
|
||||
| **Base level** | The original level that provides object types, textures, sky, fog and music, shown with its loading picture. Default: Village – Chapter 1. See [Base levels](01-introduction.md#base-levels). |
|
||||
| **TestLevel chapter** | The chapter of world 9 (TestLevel) the level replaces when it is enabled. The next free chapter is suggested. |
|
||||
| **Start with** | **Empty** (nothing but the base level's sky, fog and music), **Flat floor** (a 16×14 grass floor, player start and an exit) or **Island** (a grass island with trees in the sea, player start and an exit). |
|
||||
|
||||
Every new level starts clean: of the base level it keeps only the **start zone** (its fog, colours
|
||||
and music), the **directional lights** (the sun that lights the objects), the object types, textures
|
||||
and sounds. The base level's house-door teleports, lamps (point lights), paths and visibility regions
|
||||
are not taken over – everything is visible until you set up regions yourself.
|
||||
|
||||

|
||||
|
||||
**File → Open original level…** (**Ctrl+Shift+O**) opens one of the game's own chapters instead –
|
||||
see [Editing original levels](16-original-levels.md). **File → Open project…** (**Ctrl+O**) opens
|
||||
a saved `.llamalevel` file.
|
||||
|
||||
## Panels
|
||||
|
||||
<!-- generated:panels -->
|
||||
| Panel | Default place | Shown at first |
|
||||
|---|---|---|
|
||||
| **Outliner** | left | yes |
|
||||
| **Inspector** | right | yes |
|
||||
| **Assets** | bottom | yes |
|
||||
| **Objects** | left | yes |
|
||||
| **Textures** | bottom | yes |
|
||||
| **History** | left | yes |
|
||||
| **Problems** | bottom | yes |
|
||||
| **Environment** | left | yes |
|
||||
| **Visibility** | right | yes |
|
||||
<!-- /generated:panels -->
|
||||
|
||||
### Outliner
|
||||
|
||||
The Outliner lists everything in the level as a tree: **Level** (level settings, default zone,
|
||||
visibility regions), **Tiles** (grouped **by model** or **by cell** – choose in the box at the
|
||||
top), **Objects** (by category and type), **Waypoint chains**, **Zones**, **Lights**,
|
||||
**Brushes** and **Assets** (tile models, imported meshes, texture pages). The filter field finds
|
||||
items by name, type or id.
|
||||
|
||||
* Click selects, **Shift+click** and **Ctrl+click** add to the selection, double-click frames
|
||||
the item in the viewport.
|
||||
* The eye button on a row shows or hides the item in the viewport.
|
||||
* The context menu has **Frame in viewport**, **Select similar**, **Hide** / **Show**,
|
||||
**Lock** / **Unlock**, **Duplicate** and **Delete**.
|
||||
|
||||
### Inspector
|
||||
|
||||
The Inspector shows the properties of the selection. Its parts are explained in
|
||||
[Selecting and transforming](05-selection.md#the-inspector); tools and plugins add their own
|
||||
sections (for example **Brush shape**, **Object parameters**, **Environment zone**). Every
|
||||
section header has a **?** button that opens the matching chapter of this manual.
|
||||
|
||||
### Assets
|
||||
|
||||
The Assets panel at the bottom holds what you can drag into the viewport:
|
||||
|
||||
| Tab | Content |
|
||||
|---|---|
|
||||
| **Tile models** | the base level's tile models with thumbnails – drag one into a cell to place a tile ([Building geometry](06-geometry.md)) |
|
||||
| **All worlds** | every object type of every original level, to import into this level ([Importing objects](09-objects.md#importing-objects-from-other-worlds)) |
|
||||
| **Objects** | the placeable object types of the base level and the imported ones ([Objects](09-objects.md)) |
|
||||
| **Textures** | all textures of the level ([Textures](08-textures.md)) |
|
||||
| **Imported** | the meshes imported into this project ([Importing meshes](07-meshes.md)) |
|
||||
| **Library** | geometry you saved for reuse in any level ([The library](07-meshes.md#the-library)) |
|
||||
| **Prefabs** | saved groups of objects ([Prefabs](09-objects.md#prefabs)) |
|
||||
|
||||
### Other panels
|
||||
|
||||
* **Objects** – the object palette with search, categories, favourites and one-click setups
|
||||
([Objects](09-objects.md#the-objects-panel)).
|
||||
* **Environment** – zones and fog, lights and lighting bake ([Environment](12-environment.md)).
|
||||
* **Visibility** – the visibility region matrix ([Visibility regions](13-visibility.md)).
|
||||
* **Textures** – the texture manager ([Textures](08-textures.md#texture-manager)).
|
||||
* **History** – every change of this session; click an entry to go back to that state, click a
|
||||
later one to go forward again.
|
||||
* **Problems** – the results of **Check for problems** and **Build**; double-click a message to
|
||||
select the item it is about ([Building, problems and play-testing](15-build-play.md)).
|
||||
|
||||
## Arranging panels
|
||||
|
||||
* The left and right docks are narrow, so their tabs show only an icon – only the open panel's
|
||||
tab shows its name. Point at an icon to see which panel it is, click it to switch.
|
||||
* Drag the split bars between the docks to resize them.
|
||||
* Right-click a panel's tab and choose **Move to …** to put it into another dock.
|
||||
* The **×** on a tab closes the panel (in the side docks it is on the open tab);
|
||||
**View → Panels** opens it again.
|
||||
* The **?** at the right end of each dock's tab row opens the help for the panel shown there.
|
||||
|
||||
The editor remembers the layout and the split sizes.
|
||||
|
||||
## Layers
|
||||
|
||||
**Layers** in the options bar (and **View → Layers**) switch parts of the viewport display on
|
||||
and off: tiles, object models, markers of logic objects, collision, invisible collision volumes,
|
||||
tile swap alternatives, waypoints and path directions, zones, zone targets, zone areas and
|
||||
trigger radii, camera frusta, lights and light gizmos, visibility regions, brush outlines and the
|
||||
grid. Layers only change the display – hidden layers are still part of the level.
|
||||
|
||||
## Light and dark theme
|
||||
|
||||
**View → Dark theme** switches between the light and the dark look. The setting is shared with
|
||||
LlamaMod and also applies to this manual.
|
||||
|
||||
## Preferences
|
||||
|
||||
**Edit → Preferences…** (**Ctrl+,**):
|
||||
|
||||
| Setting | Meaning |
|
||||
|---|---|
|
||||
| **Autosave every (seconds)** | While there are unsaved changes the editor writes a recovery copy this often (default 90 s). |
|
||||
| **Play-test save slot** | The save slot the game uses for play-tests (default 3). It is unlocked up to your level, with the map cursor on it; a backup is made first. |
|
||||
| **Theme** | Light or Dark (shared with LlamaMod). |
|
||||
|
||||
Mouse scheme, zoom step, orbit speed, the view cube and back faces are set in **View →
|
||||
Navigation → Viewport preferences…** ([Viewport preferences](04-navigation.md#viewport-preferences)).
|
||||
|
||||
## Saving, autosave and recovery
|
||||
|
||||
* **File → Save** (**Ctrl+S**) writes the project; the default folder is LlamaMod's `levels`
|
||||
folder, so the level is a LlamaMod mod right away. **Save as…** (**Ctrl+Shift+S**) picks a
|
||||
new name. A dot "•" in the title bar means unsaved changes.
|
||||
* Every save also stores a **thumbnail** of the current view; it becomes the level's loading
|
||||
picture in the game.
|
||||
* **File → Open recent** lists the last ten projects.
|
||||
* Autosave keeps unsaved changes in the data folder. If the editor or the computer crashes, the
|
||||
next start offers **Recover**, **Discard** or **Later**.
|
||||
* **File → Close level** (**Ctrl+W**) and **Close editor** (**Ctrl+Q**) ask before throwing away
|
||||
changes.
|
||||
|
||||
## Getting help
|
||||
|
||||

|
||||
|
||||
* **Help → Manual** (**F1**) opens this manual. Pressing **F1** while the mouse pointer is over a
|
||||
panel, a tool's options, an Inspector section or a dialog opens the chapter about it.
|
||||
* **Help → Getting started** (**Shift+F1**) is a short illustrated tour.
|
||||
* **Help → Keyboard shortcuts** (**Ctrl+F1**) and **Help → Shortcut sheet (printable)…** list all
|
||||
keys; the complete reference is [Keyboard, mouse and menu reference](19-shortcuts.md).
|
||||
* **Help → Viewport navigation** shows the mouse controls of the active navigation preset.
|
||||
* Most buttons and menu items have tooltips – hover over them for a second.
|
||||
@@ -0,0 +1,129 @@
|
||||
# Navigating the viewport
|
||||
|
||||
The viewport shows the level in 3D with its textures, vertex colours and object models. You move
|
||||
the camera with the mouse, a few keys and the view cube. The right and middle mouse buttons
|
||||
always belong to the camera, whatever tool is active. If you already use another 3D program,
|
||||
pick its mouse scheme under [Navigation presets](#navigation-presets).
|
||||
|
||||

|
||||
|
||||
## Mouse and keys
|
||||
|
||||
These controls are the same in every preset:
|
||||
|
||||
| Input | What it does |
|
||||
|---|---|
|
||||
| **Right mouse button** held, move the mouse | look around (fly mode) |
|
||||
| **Right mouse button** held + **W A S D** | fly forward, left, back, right |
|
||||
| **Right mouse button** held + **Q** / **E** | fly down / up |
|
||||
| **Shift** while flying | fly four times faster |
|
||||
| **Mouse wheel** while flying | change the fly speed |
|
||||
| **Mouse wheel** | zoom smoothly towards the point under the cursor |
|
||||
| **Ctrl+middle** drag or **Alt+right** drag | zoom |
|
||||
| **Alt+left** drag | orbit |
|
||||
| **F** | frame the selection |
|
||||
| **Home** | frame the whole level |
|
||||
| Double-click | select and frame |
|
||||
|
||||
The middle mouse button depends on the preset:
|
||||
|
||||
| Input | Fusion 360 (default) | Blender | Unity / Unreal |
|
||||
|---|---|---|---|
|
||||
| **Middle** drag | pan | orbit | pan |
|
||||
| **Shift+middle** drag | orbit | pan | pan |
|
||||
| Double-click **middle** | frame the whole level | – | – |
|
||||
|
||||
* **Orbit** turns around the surface point under the cursor where you start dragging (if there is
|
||||
none: the selection, then the view centre). A small red-green-blue cross marks that point
|
||||
while you orbit.
|
||||
* **Pan** moves the point you grabbed exactly with the cursor.
|
||||
* **Zoom** changes the distance by a fixed percentage per wheel notch (default 12 %) towards what
|
||||
is under the cursor, so pointing at the sky or a far cliff does not make huge jumps.
|
||||
|
||||
> **Tip:** Fly mode is the quickest way to get around a big level: hold the right mouse button,
|
||||
> steer with the mouse, move with W A S D and adjust the speed with the wheel.
|
||||
|
||||
## The view cube
|
||||
|
||||
The cube in the top right corner of the viewport shows which way you are looking.
|
||||
|
||||
* Click a **face** (Top, Front, Left …), an **edge** or a **corner** to look at the level from
|
||||
there. The camera turns smoothly and keeps its pivot.
|
||||
* **Drag** on the cube to orbit.
|
||||
* The small **house** button goes to the **home view**: a view from the front-right-top that shows
|
||||
the whole level (also **View → Navigation → Home view**).
|
||||
|
||||
**View → Navigation → View cube** hides or shows it.
|
||||
|
||||
## Views
|
||||
|
||||
| Key | View |
|
||||
|---|---|
|
||||
| **Numpad 5** | perspective / orthographic |
|
||||
| **Numpad 7** | top – looking straight down, orthographic |
|
||||
| **Numpad 1** | front, orthographic |
|
||||
| **Numpad 3** | side, orthographic |
|
||||
|
||||
The same views are in **View → Camera** and in the view box of the options bar. Orbiting an
|
||||
orthographic view switches back to perspective. The top view is handy for laying out paths, coin
|
||||
lines and zones; the 3D view for checking heights and jumps.
|
||||
|
||||
## Navigation presets
|
||||
|
||||
**View → Navigation** chooses the mouse scheme: **Fusion 360** (the default), **Blender** or
|
||||
**Unity / Unreal** (see the table above). The status bar shows a one-line summary of the chosen
|
||||
scheme, and **Help → Viewport navigation** shows the complete cheat sheet for it.
|
||||
|
||||
### Viewport preferences
|
||||
|
||||
**View → Navigation → Viewport preferences…** opens the **Viewport & navigation** settings:
|
||||
|
||||

|
||||
|
||||
| Setting | Meaning |
|
||||
|---|---|
|
||||
| **Navigation preset** | Fusion 360, Blender or Unity / Unreal; the table below the settings shows its controls. |
|
||||
| **Zoom step (%)** | Distance change per wheel notch (2–40 %, default 12 %). |
|
||||
| **Invert zoom direction** | Wheel away from you zooms out instead of in. |
|
||||
| **Orbit speed (°/pixel)** | How fast the camera turns while orbiting. |
|
||||
| **Show the view cube** | The cube in the top right corner. |
|
||||
| **Show back sides of one-sided faces** | See [Back faces](#back-faces). |
|
||||
| **Back side opacity** | How strongly back sides are drawn (default 30 %). |
|
||||
|
||||
## Back faces
|
||||
|
||||
Many faces in the game are *one-sided*: the game does not draw them from behind (you can see
|
||||
through a cliff wall from the inside). The editor shows these back sides **darkened and hatched**
|
||||
so you can still see and click them. When the mouse is over one, the status bar adds
|
||||
"(back side)". **View → Show back faces** switches this off; the opacity is a viewport
|
||||
preference.
|
||||
|
||||
> **Note:** The hatched back sides are invisible in the game. If a wall must be visible from
|
||||
> both sides, look at it from behind in the editor before you play-test.
|
||||
|
||||
## Looking through a game camera
|
||||
|
||||
**View → Camera → Look through camera (pilot)** (**Ctrl+Shift+L**) puts the viewport into the
|
||||
selected camera object or camera node; flying then moves that camera. See
|
||||
[Cameras and triggers](11-cameras-triggers.md#look-through-camera).
|
||||
|
||||
## What the viewport shows
|
||||
|
||||
* The **grid** marks the level's cells; geometry outside it has no collision in the game.
|
||||
* **Markers** stand for logic objects without a model (cameras, triggers, the exit, checkpoints'
|
||||
respawn points).
|
||||
* **Collision** (**C**) colours every collision polygon by its material: normal ground, exit floor
|
||||
(16), death floor (30) and others. Invisible walls and blocks are drawn translucent red.
|
||||
* **Waypoints** of the selected objects are drawn as connected points; **View → Show waypoints
|
||||
of all objects** shows every chain.
|
||||
* With **View → Fog preview** the viewport shows the game's fog for the zone the camera is in;
|
||||
everything beyond the fog is drawn as a pale "ghost" so you do not lose track of it.
|
||||
**View → Vertex colours only** (**Shift+V**) hides the textures to judge the lighting
|
||||
([Environment](12-environment.md#view-options)).
|
||||
|
||||
Use **Layers** in the options bar to switch any of these on or off
|
||||
([Layers](03-editor-window.md#layers)).
|
||||
|
||||
> **Note:** The viewport does not animate textures and shows the level with the editor's own
|
||||
> lighting of object models. What you see is very close to the game, but always play-test
|
||||
> ([F5](15-build-play.md)) before you share a level.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Selecting and transforming
|
||||
|
||||
Almost every edit starts with a selection: click something, then move it with the gizmo, change
|
||||
it in the Inspector or use a command from the menus.
|
||||
|
||||
## Selecting
|
||||
|
||||
| Input | Result |
|
||||
|---|---|
|
||||
| Click | select the item under the mouse pointer |
|
||||
| **Shift+click** | add to the selection |
|
||||
| **Ctrl+click** | toggle (add or remove) |
|
||||
| Drag in empty space | box selection (with **Shift** it adds, with **Ctrl** it removes) |
|
||||
| Double-click | select and frame |
|
||||
| Click in empty space | clear the selection |
|
||||
| **Ctrl+A** / **Ctrl+Shift+A** | select all visible items / select none |
|
||||
| **Shift+S** | **Select similar**: all objects of the same type, or all tiles with the same model |
|
||||
|
||||
The **Select** tool (**Q**) only selects. The transform tools below select the same way and
|
||||
additionally show a gizmo. You can also select in the [Outliner](03-editor-window.md#outliner),
|
||||
which reaches items that are hard to click (hidden, locked or far away).
|
||||
|
||||

|
||||
|
||||
## Hiding and locking
|
||||
|
||||
* **H** hides the selection in the viewport, **Alt+H** shows everything again.
|
||||
* **L** locks the selection: locked items are drawn but cannot be clicked in the viewport –
|
||||
useful for a floor you keep hitting by accident. Unlock them from the Outliner's context menu.
|
||||
|
||||
Hiding and locking only affect the editor. Hidden items are still part of the level and the
|
||||
game shows them.
|
||||
|
||||
To leave something out of the built level without deleting it:
|
||||
|
||||
* **Tiles:** tick **Exclude from build** (group *Build*) in the Inspector. The tile stays in the
|
||||
project and in the viewport; the Outliner shows it in italics with *not built*.
|
||||
* **Brushes:** untick **Enabled** in the Inspector.
|
||||
|
||||
## Move, rotate and scale
|
||||
|
||||
| Tool | Key | Use |
|
||||
|---|---|---|
|
||||
| **Move** | **W** | drag the gizmo's arrows (one axis) or squares (a plane); or drag an object straight over the ground |
|
||||
| **Rotate** | **E** | the green ring turns everything about the vertical axis; the red and blue rings turn **brushes** freely in 3D |
|
||||
| **Scale** | **R** | brushes only: drag an axis or the centre; the brush changes its own sizes (width, depth, height, radius …) |
|
||||
|
||||

|
||||
|
||||
* **X** switches the gizmo between **World** axes and the item's own **Local** axes (also the
|
||||
**World / Local** button in the options bar).
|
||||
* Several selected items move and turn together, about the centre of the selection.
|
||||
* While you drag, the status bar shows how far (in cells) or by how many degrees the selection
|
||||
has moved, and the snap step in use.
|
||||
* A drag is one undo step. **Esc** during a drag cancels it.
|
||||
* Waypoints move along when you move their object; a checkpoint's respawn point turns with it.
|
||||
|
||||
> **Engine limit:** Tiles and objects only turn about the vertical axis, and only brushes can be
|
||||
> scaled. The status bar tells you when part of the selection cannot follow.
|
||||
|
||||
Brushes also have handles for resizing, quarter turns and mirroring – see
|
||||
[Building geometry](06-geometry.md#rotating-scaling-and-mirroring). **Geometry → Align** and
|
||||
**Array duplicate…** arrange several items.
|
||||
|
||||
## Snapping
|
||||
|
||||
**Snap** in the options bar (**G**) snaps moves to the **move step** and rotations to the
|
||||
**angle step**:
|
||||
|
||||
| Setting | Values |
|
||||
|---|---|
|
||||
| Move step | 1, 0.5, 0.25, 0.125 or 1/16 cell |
|
||||
| Angle step | 90°, 45°, 15°, 5° or 1° |
|
||||
|
||||
Hold **Ctrl** while dragging to invert snapping for that drag. **Geometry → Grid & snapping…**
|
||||
sets any step you like and switches the grid display ([Grid and snapping](06-geometry.md#grid-and-snapping)).
|
||||
|
||||
## The Inspector
|
||||
|
||||
The Inspector shows what is selected and lets you change it.
|
||||
|
||||

|
||||
|
||||
* The **header** names the selection (kind, name, id) and has a button to frame it. With several
|
||||
items of one kind selected you edit their **common properties**; values that differ show "—".
|
||||
Items of different kinds have no common properties.
|
||||
* **Sections** of tools and plugins come first – for example **Brush shape**, **Object
|
||||
parameters**, **Waypoint chain**, **Environment zone**, **Light**, **Tile**. The section of the
|
||||
active tool (for example **Brush tool**) is at the very top.
|
||||
* Below them are the **property groups** (Transform, Position, …). Click a group header to fold
|
||||
it; the editor remembers which groups you folded. The group **Raw** (data whose meaning is not
|
||||
known) and, for objects, **Type details** (the engine data of the object type, such as its code
|
||||
offset and slots) are folded at first.
|
||||
* The **?** button on every section header opens the matching chapter of this manual.
|
||||
|
||||
### Editing values
|
||||
|
||||
* **Number fields** accept small calculations such as `1.5`, `2+0.25` or `-3*2`. Press **Enter**
|
||||
to apply.
|
||||
* **Drag a number's label** left or right to change the value (**Shift** = fine, **Ctrl** =
|
||||
coarse). The whole drag is one undo step.
|
||||
* Positions are in cells, angles in degrees, colours open a colour picker.
|
||||
* **References** to other items (an object's waypoint chain, a tile's model) have a button to
|
||||
select the referenced item and one to choose another from a list.
|
||||
* For objects, **Object type** changes what the object is – the type fields and parameters of the
|
||||
new type are taken from the base level.
|
||||
|
||||
## Duplicating, copying and deleting
|
||||
|
||||
| Command | Key | Notes |
|
||||
|---|---|---|
|
||||
| **Duplicate** | **Ctrl+D** | a copy one cell east; objects keep their waypoint chains |
|
||||
| **Copy** / **Cut** / **Paste** | **Ctrl+C** / **Ctrl+X** / **Ctrl+V** | within the editor window; each paste is offset a little |
|
||||
| **Copy objects (for other levels)** | **Ctrl+Shift+C** | objects with waypoints and brushes to the system clipboard; **Ctrl+Shift+V** pastes them into any level ([Objects](09-objects.md#copy-objects-between-levels)) |
|
||||
| **Delete** | **Delete** | removes the selection; deleting waypoints relinks the chain |
|
||||
| **Array duplicate…** | **Ctrl+Shift+D** | many copies with an offset and turn each ([Array duplicate](06-geometry.md#array-duplicate)) |
|
||||
|
||||
## Undo and history
|
||||
|
||||
Every change can be undone: **Ctrl+Z** undoes, **Ctrl+Y** (or **Ctrl+Shift+Z**) redoes. The
|
||||
**Edit** menu names the step that will be undone. **Edit → History** opens the **History**
|
||||
panel with all steps of the session – click an entry to jump back to that state.
|
||||
@@ -0,0 +1,408 @@
|
||||
# Building geometry
|
||||
|
||||
Everything the llama walks on, bumps into or falls through is *geometry*. In the editor you build
|
||||
it in two ways:
|
||||
|
||||
* **Brushes** – editor shapes such as blocks, platforms, ramps, stairs, walls, water and death
|
||||
planes. You draw them with the **Brush** tool, resize them with handles and turn them freely.
|
||||
When the level is built, every brush is cut into the engine's tiles automatically.
|
||||
* **Tiles** – the placed models of the base level's tile set, exactly as the original levels are
|
||||
made. The **Tiles** tool paints them onto grid cells.
|
||||
|
||||
Collision is part of both: the **Collision** tool shows and changes what the llama can stand on,
|
||||
where it dies and where the level exit fires.
|
||||
|
||||

|
||||
|
||||
## How the engine stores geometry
|
||||
|
||||
A few engine facts explain most of what follows:
|
||||
|
||||
* The level is a grid of **cells** (1 cell = one grid square, 4096 game units). The llama is
|
||||
about 0.6 cells tall.
|
||||
* Geometry is made of **tiles**: a tile is a model placed in one cell, turned about the vertical
|
||||
axis. A tile cannot be scaled or mirrored and its collision must stay close to its cell.
|
||||
* A tile model may have at most **8000 vertices**.
|
||||
* Every collision polygon carries a **material** number. 0 is normal ground, **16** is the exit
|
||||
floor the level door needs, **30** is "no floor" (the llama falls and loses a life).
|
||||
* Collision is looked up per cell, so geometry outside the level grid has no effect.
|
||||
|
||||
Brushes hide most of this: they can have any size, position and rotation, and the build splits
|
||||
them into 1×1-cell tiles with matching collision for you.
|
||||
|
||||
## Brush tool (B)
|
||||
|
||||
Start it with the toolbar button, the key **B** or **Geometry → Brush tool**. The options bar
|
||||
shows one button per primitive plus **Height**, **Drag height** and **Work plane**; the
|
||||
Inspector shows the same primitives with names (section **Draw**) and the options of the chosen
|
||||
primitive below them.
|
||||
|
||||
### Drawing a brush
|
||||
|
||||
1. Choose a primitive.
|
||||
2. Drag in the viewport. Most primitives start with a **footprint**: press on the ground (or on
|
||||
top of other geometry), drag the rectangle and release.
|
||||
3. For primitives with a height, now move the mouse **up or down** – the preview grows – and
|
||||
**click** to confirm. **Enter** uses the value of the **Height** field instead, **Esc**
|
||||
cancels.
|
||||
|
||||
The new brush is selected and shows its handles. The status bar shows the size while you draw.
|
||||
|
||||
| Option (options bar) | Meaning |
|
||||
|---|---|
|
||||
| **Height** | height used for **Enter** and for a click without dragging |
|
||||
| **Drag height** | after the footprint, the mouse movement sets the height; off = the **Height** field is used directly |
|
||||
| **Work plane** + value | draw on a horizontal plane at this height instead of on the surface under the cursor; the grid moves to that height |
|
||||
|
||||
Footprints snap to the move step of the snapping settings; hold **Ctrl** while dragging to
|
||||
toggle snapping for this drag. **Shift+click** selects an existing brush without drawing.
|
||||
|
||||
> **Tip:** Drawing on the *surface under the cursor* is the fastest way to stack things: start a
|
||||
> drag on top of a block and the new brush stands on it.
|
||||
|
||||
### Primitives
|
||||
|
||||
| Primitive | How to draw | Notes |
|
||||
|---|---|---|
|
||||
| **Block** | footprint, then height | solid box with top, sides and optional bottom |
|
||||
| **Platform** | footprint, then the height of the top | floating slab with an edge row, bottom and **Thickness** |
|
||||
| **Floor** | footprint only | flat floor, top only |
|
||||
| **Ramp** | footprint, then the height of the high end | rises in the main drag direction |
|
||||
| **Stairs** | footprint, then the top height | rises in the drag direction; **Steps**, **Walkable (invisible slope)** |
|
||||
| **Pillar** | click for the default size or drag its size, then height | square column |
|
||||
| **Round** | drag the diameter, then height | cylinder: round platform or column, **Segments** 3–64 |
|
||||
| **Wall** | drag along the wall in any direction, then height | a turned block when diagonal; snapped to the angle step; **Thickness** |
|
||||
| **Fence** | click the corner points, double-click or **Enter** finishes | posts and rails along a polyline |
|
||||
| **Tree** | click | block tree: trunk and two crown cubes |
|
||||
| **Water** | footprint only | water surface without collision, with a death plane just above it |
|
||||
| **Death plane** | footprint only | invisible no-floor plane (material 30) – falling onto it kills |
|
||||
| **Invisible wall** | drag along its length, then height | collision only, nothing is drawn in the game |
|
||||
| **Invisible block** | footprint, then height | invisible collision volume: floor, ceiling or blocker |
|
||||
|
||||
> **Note:** Stairs need **Walkable (invisible slope)**: the engine has no step-up logic, so the
|
||||
> llama walks up an invisible slope that lies over the steps. Stairs start at the floor in front
|
||||
> of the first step (*Start height (floor in front)*).
|
||||
|
||||
### Primitive options
|
||||
|
||||
The options section in the Inspector changes with the primitive. Textures are chosen with a
|
||||
swatch button: click it for a searchable grid of all textures of the level (names are the
|
||||
village texture names; `#n` is texture number *n* of the base level, see
|
||||
[Textures](08-textures.md)). **none** leaves that part out.
|
||||
|
||||
| Option | Primitives | Meaning |
|
||||
|---|---|---|
|
||||
| **Top** / **Texture** | all textured ones | texture of the top (Floor and Water: the only texture) |
|
||||
| **Sides** | Block, Platform, Ramp, Stairs, Pillar, Round, Wall | side texture |
|
||||
| **Top edge** | same | texture of the top row of the sides (e.g. a grass edge), or none |
|
||||
| **Bottom** | same | bottom texture, or none (no bottom faces) |
|
||||
| **Thickness** | Platform, Wall, Invisible wall | slab or wall thickness in cells |
|
||||
| **Steps** | Stairs | number of steps (1–64) |
|
||||
| **Walkable (invisible slope)** | Stairs | adds the invisible slope (see above) |
|
||||
| **Segments** | Round | number of sides of the cylinder |
|
||||
| **Collision** | Block, Round, Wall, Floor, Ramp | off = decoration only, the llama walks through |
|
||||
| **Solid sides** | Block, Round, Wall | off = the sides have no collision, so the llama can walk up onto low plinths |
|
||||
| **Material** | Block, Platform, Round, Wall, Floor, invisible ones | collision material of the brush |
|
||||
|
||||
### Handles: resizing
|
||||
|
||||
A selected brush shows small cubes on its faces – **orange** for the sides, **green** for top and
|
||||
bottom. Drag one to resize: the opposite face stays where it is, also for turned brushes. The
|
||||
status bar shows the new size.
|
||||
|
||||

|
||||
|
||||
### Keys while the Brush tool is active
|
||||
|
||||
| Key | Action |
|
||||
|---|---|
|
||||
| **[** / **]** | turn the selection by 90° left / right |
|
||||
| **Page Up** / **Page Down** | raise / lower the selection by the snap step |
|
||||
| **Enter** | use the **Height** field (height step) or finish a fence |
|
||||
| **Esc** | cancel the current drawing |
|
||||
| **Ctrl** (held) | toggle snapping for this drag |
|
||||
| **Shift+click** | select instead of drawing |
|
||||
|
||||
## Brush properties in the Inspector
|
||||
|
||||
Selecting a single brush shows two Inspector sections: **Brush shape** (below) and the brush's
|
||||
own parameters (all of them, as numbers and texture fields). Every parameter can be typed in;
|
||||
number fields accept arithmetic such as `2+0.5`.
|
||||
|
||||
Common parameters:
|
||||
|
||||
| Parameter | Meaning |
|
||||
|---|---|
|
||||
| **X0 / Z0 / X1 / Z1** | footprint corners in cells (x east, z = grid row, growing south) |
|
||||
| **Bottom / Top**, **Height** | heights in cells |
|
||||
| **Top texture**, **Side texture**, **Top row of the sides**, **Bottom texture** | textures (name, `#n`, a flat colour name or `rgbRRGGBB`) |
|
||||
| **Sides (n, e, s, w)** | which sides of a block exist |
|
||||
| **Collision**, **Side collision**, **Collision material** | collision of the whole brush |
|
||||
| **Casts shadows** | the block shadows other geometry when lighting is baked |
|
||||
| **Texture rotation (0-3, −1 random)** | turns the texture on every face; −1 picks a random turn per tile |
|
||||
| **Tile size** | size of the generated tiles (floors, ramps, water) |
|
||||
| **Tint (r, g, b)** | colour multiplier for the brush's vertex colours |
|
||||
| **Rises towards** | direction of ramps and stairs: `+x`, `-x`, `+z`, `-z` |
|
||||
| **Base height** | ramps and stairs: how far the closed sides reach down (empty = 0.5 below) |
|
||||
| **Post size**, **Post spacing**, **Post texture**, **Rail texture** | fences |
|
||||
| **Trunk height**, **Crown size**, **Trunk size (0 = auto)** | trees |
|
||||
|
||||
### Brush shape section
|
||||
|
||||

|
||||
|
||||
* The first line shows the kind and size, e.g. **Ramp · 6.25 × 2 × 3.5 cells**.
|
||||
* **Rotation°** – three fields for the rotation about x (east), y (up) and z (south) in degrees,
|
||||
applied in the order x·y·z. The bottom centre of the brush stays in place.
|
||||
* **Left 90°** / **Right 90°** – quarter turns about the vertical axis (**[** / **]**).
|
||||
* **Mirror X** / **Mirror Z** – mirror east ↔ west or north ↔ south.
|
||||
* **Visible (off = invisible collision volume)** – hides the brush in the game but keeps its
|
||||
collision. This is how invisible walls and blocks are made.
|
||||
* **Faces (collision and material)** – a table with one row per face: **top**, **bottom**,
|
||||
**north**, **east**, **south**, **west**. **Collision** switches the face's collision on or
|
||||
off, **Material** gives it its own collision material (for example only the top face 16).
|
||||
|
||||
Water and death planes are laid out per grid cell: they can be resized and moved but only turned
|
||||
by 90°. A collider (a free invisible polygon) is edited through its corner list.
|
||||
|
||||
> **Note:** Brushes are baked into tiles when the level is built, so any rotation and scale works.
|
||||
> Tiles placed with the Tiles tool cannot do that – see [Tiles tool](#tiles-tool).
|
||||
|
||||
## Rotating, scaling and mirroring
|
||||
|
||||
The general transform tools are described in [Selection and transforming](05-selection.md).
|
||||
On brushes they can do more than on tiles and objects:
|
||||
|
||||
* **Rotate (E)**: the green ring turns everything about the vertical axis. The **red** and
|
||||
**blue** rings turn **brushes freely in 3D** (imported meshes about their origin). Tiles and
|
||||
objects only turn about the vertical axis in the engine; the status bar says so and leaves
|
||||
them alone.
|
||||
* **Scale (R)** on a brush changes the primitive's own sizes – width, depth, height, thickness,
|
||||
radius, crown … ; meshes stretch per axis. The bottom centre stays.
|
||||
* **Quarter turns and mirrors** of unturned brushes change their parameters instead of adding a
|
||||
rotation, so textures stay aligned to the grid and ramp directions, sides and per-face settings
|
||||
follow.
|
||||
|
||||
**Geometry** menu commands for the selection:
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| **Turn left 90°** / **Turn right 90°** | **Ctrl+[** / **Ctrl+]** | quarter turn about the vertical axis |
|
||||
| **Mirror X (east ↔ west)** / **Mirror Z (north ↔ south)** | | mirror about the centre of the selection; tiles and objects are moved and turned (tile models themselves cannot be mirrored) |
|
||||
| **Array duplicate…** | **Ctrl+Shift+D** | see below |
|
||||
| **Align ▸** | | see below |
|
||||
|
||||
### Array duplicate
|
||||
|
||||
**Geometry → Array duplicate…** (**Ctrl+Shift+D**) makes several copies in one step – a row of
|
||||
platforms, a staircase of blocks, a ring of pillars.
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Copies** | number of new copies |
|
||||
| **Offset X (cells)**, **Offset Y**, **Offset Z** | offset of each copy from the previous one |
|
||||
| **Turn per copy (°)** | each copy is turned once more than the previous one |
|
||||
| **Turn about the selection centre (circular array)** | turn around the centre of the selection instead of each item's own position: arranges copies on a circle |
|
||||
|
||||
Objects in the selection get a copy of their waypoint chain. The whole array is one undo step.
|
||||
|
||||
### Align and distribute
|
||||
|
||||
**Geometry → Align** lines up the selection with the **last selected** item (select two or more):
|
||||
|
||||
* **Align West (min X)**, **Align Centre X**, **Align East (max X)**
|
||||
* **Align Bottom**, **Align Middle Y**, **Align Top**
|
||||
* **Align North (min Z)**, **Align Centre Z**, **Align South (max Z)**
|
||||
* **Distribute along X** / **Distribute along Z** – spaces three or more items evenly between the
|
||||
outermost two.
|
||||
|
||||

|
||||
|
||||
### Grid and snapping
|
||||
|
||||
The options bar holds the quick settings: **Snap** (**G**), the move step (1 … 1/16 cell) and
|
||||
the angle step (90° … 1°). **Geometry → Grid & snapping…** sets any value:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Snapping on** | same as **G**; hold **Ctrl** while dragging to invert |
|
||||
| **Move step (cells)** | any step from 1/64 to 16 cells |
|
||||
| **Angle step (°)** | any angle step |
|
||||
| **Scale step** | step of the Scale tool |
|
||||
| **Show the grid** | grid display on or off |
|
||||
|
||||
The engine places tiles on whole cells; brushes and objects can sit anywhere.
|
||||
|
||||
## Tiles tool
|
||||
|
||||
The **Tiles** tool paints tile models of the base level onto grid cells – the way the original
|
||||
levels are built. Start it with **T**, from the toolbar or **Geometry → Tiles tool**.
|
||||
|
||||

|
||||
|
||||
### Tile palette
|
||||
|
||||
The Inspector shows the **Tile palette**: every tile model of the level with a thumbnail, its
|
||||
vertex count and how many tiles use it. **Filter (model number)** narrows the list, **Only models
|
||||
used in the level** hides unused ones. Click a model to make it the current one, or
|
||||
**Shift+click** a tile in the viewport to pick it.
|
||||
|
||||
### Modes and options
|
||||
|
||||
| Mode | What a click (or drag) does |
|
||||
|---|---|
|
||||
| **Paint** | puts the palette model into the cell under the cursor |
|
||||
| **Pick** | takes the model, height and rotation of the clicked tile (also **Shift+click** in any mode) |
|
||||
| **Erase** | deletes the clicked tiles |
|
||||
| **Raise / lower** | raises a tile by the height step, **Shift+click** lowers |
|
||||
| **Swap model** | replaces the model of the clicked tile with the palette model |
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **On surface** | paint at the height of the tile or ground under the cursor; off = the fixed **Height** |
|
||||
| **Height** | height of painted tiles (**Page Up** / **Page Down**) |
|
||||
| **Rotation** | 0°, 90°, 180° or 270° (**[** / **]**) |
|
||||
| **Step** | height step for raising, lowering and Page Up/Down |
|
||||
|
||||
Painting onto a tile at the same height **swaps its model** instead of stacking a second tile.
|
||||
New tiles copy the vertex colours of an existing tile with the same model.
|
||||
|
||||
> **Tip:** Prefer swapping, moving or hiding original tiles over erasing them. Object scripts can
|
||||
> address tiles by their number, and erasing a tile shifts the numbers of all later tiles. The
|
||||
> status bar warns you when you erase an original tile.
|
||||
|
||||
### Tile section in the Inspector
|
||||
|
||||
Selecting tiles shows the **Tile** section:
|
||||
|
||||
* **Left 90°** / **Right 90°**, **Up** / **Down** (by the snap step).
|
||||
* **Use palette model** – gives the selected tiles the Tiles tool's palette model.
|
||||
* A reminder that tiles only turn about the vertical axis and cannot be scaled or mirrored (the
|
||||
level stores one position and one angle per tile). For free shapes use brushes.
|
||||
|
||||
### Tile swaps (doors and bridges)
|
||||
|
||||
Some levels let object scripts switch a tile to another model – an opening door, a bridge that
|
||||
appears. This is a **tile swap**. The Tile section shows the swap of the selected tile:
|
||||
|
||||
* **Swap entry in cell …** with the current and the alternative model,
|
||||
* **Alternative = palette** – sets the alternative model from the Tiles tool's palette,
|
||||
* **Remove swap** – deletes the swap entry,
|
||||
* **Add swap (door / bridge)** – gives the tile an alternative model.
|
||||
|
||||
The layer **Tile swap alternatives** (View → Layers) draws alternative models in cyan. Tile
|
||||
swaps need a base level with the feature flag WFPC 0x10000; on other bases the section says so.
|
||||
|
||||
## Collision tool
|
||||
|
||||
The **Collision** tool shows and paints collision materials. Start it from the toolbar or
|
||||
**Geometry → Collision tool**. It switches the collision layer on: every collision polygon is
|
||||
drawn in the colour of its material.
|
||||
|
||||

|
||||
|
||||
Hover over geometry: the polygon (on a brush: the whole face) under the cursor is highlighted and
|
||||
the status bar names it and its material. Then:
|
||||
|
||||
| Mode | Action |
|
||||
|---|---|
|
||||
| **Paint material** | click or drag over polygons to give them the current material; **Shift+click** picks the material of a polygon |
|
||||
| **Toggle collision** | click a brush face to switch its collision on or off |
|
||||
|
||||
The Inspector shows the list **Collision materials**; **Material** in the options bar does the
|
||||
same, and **Other…** accepts any number from 0 to 255.
|
||||
|
||||
| Material | Name | Effect |
|
||||
|---|---|---|
|
||||
| **0** | Normal | ordinary ground and walls |
|
||||
| **16** | Exit floor (LevelDoor) | the level door only fires while the llama stands on it in the door's cell |
|
||||
| **30** | No floor / death | the llama falls through and loses a life |
|
||||
| **17** | Selective: only flagged objects | only affects some objects |
|
||||
| **18** | Selective: not flagged objects | only affects the other objects |
|
||||
| 1–15, 20, 26–28, 33, 255 | special, meaning unknown | read by object scripts of the original levels |
|
||||
|
||||
**Shared models**: original tile models are often used by many tiles. Choose **Shared models:
|
||||
change all tiles** (paint the model, every tile using it changes) or **Shared models: copy for
|
||||
this tile** (the painted tile gets its own copy of the model first).
|
||||
|
||||
Brushes have one material per face class (top, sides, bottom); tile models are painted per
|
||||
polygon. Tile collision cannot be switched off – paint it 30 or hide the tile instead.
|
||||
|
||||
The layer **Invisible collision volumes** draws invisible walls, invisible blocks and colliders
|
||||
translucent red so you can see them while editing.
|
||||
|
||||
## Special floors
|
||||
|
||||
### Exit floor
|
||||
|
||||
The level exit is an object, the **LevelDoor**, but it only fires while the llama stands on
|
||||
collision material **16** in the door's own cell. The quick setup **Exit** in the Objects panel
|
||||
places both at once – the door and a 1×1 floor with material 16 (see
|
||||
[Objects](09-objects.md)). To make an existing surface the exit floor, paint its top face 16 with
|
||||
the Collision tool or set the face's **Material** in the Brush shape section.
|
||||
|
||||
### Death floors and the death plane
|
||||
|
||||
Material **30** means "no floor": the llama falls through and loses a life. Use it for pits,
|
||||
lava and the ground under a parkour:
|
||||
|
||||
* the **Death plane** primitive – an invisible plane of material 30 in every cell of its area
|
||||
that is not completely covered by floor,
|
||||
* a **Floor** or **Block** with material 30 (a visible deadly floor),
|
||||
* **Water** – carries its own death plane just above the water surface.
|
||||
|
||||
**Geometry → Death plane height…** moves all death planes at once: death-plane brushes and the
|
||||
original level's material-30 tiles. It shows how many of each exist; **Add a death plane over the
|
||||
whole grid** creates one if there is none. The same height is in
|
||||
[Level settings](14-level-settings.md).
|
||||
|
||||

|
||||
|
||||
### Invisible walls and blocks
|
||||
|
||||
**Invisible wall** and **Invisible block** draw boxes that have collision but are not drawn in the
|
||||
game – to keep the llama on a path or to give a decoration a simple collision. Any brush becomes
|
||||
invisible with **Visible** off in the Brush shape section.
|
||||
|
||||

|
||||
|
||||
### Water
|
||||
|
||||
The **Water** primitive draws a water surface without collision (the llama sinks) and, by
|
||||
default, a death plane just above it. Its parameters: **Water height**, **Texture**, **Death
|
||||
plane** (`none`, `whole` = under the whole water, `area` = only in **Death plane area**) and
|
||||
**Tile size**.
|
||||
|
||||
## Geometry checks
|
||||
|
||||
**Level → Check for problems** and every build run these checks (see
|
||||
[Building and play-testing](15-build-play.md)):
|
||||
|
||||
| Problem | What to do |
|
||||
|---|---|
|
||||
| a tile lies outside the grid | move it in or enlarge the grid in Level settings |
|
||||
| a tile model (also one generated from a brush or mesh) has more than **8000 vertices** | simplify or split the shape |
|
||||
| two identical tiles overlap exactly (same model, cell, height and rotation) | delete one – it causes flickering and double collision |
|
||||
| **no floor collision under the player start** | the llama would fall at once – put floor under it |
|
||||
| the player start is far above the floor | lower it |
|
||||
| **no exit floor (collision material 16) in the LevelDoor's cell** | add or paint the exit floor |
|
||||
| a small **gap** (under 0.2 cells) between neighbouring floors at the same height | close it, the llama can get stuck or fall |
|
||||
| brush warnings | messages of the brush compiler |
|
||||
|
||||
Double-click a problem to select the item.
|
||||
|
||||

|
||||
|
||||
## Engine limits
|
||||
|
||||
> **Engine limit:** at most 8000 vertices per tile model. Brushes are split into 1×1-cell tiles, so
|
||||
> only very dense meshes or many brushes overlapping one cell reach it.
|
||||
|
||||
* Tiles only turn about the vertical axis and cannot be scaled or mirrored; brushes can.
|
||||
* Collision materials of brushes are per face class (top, bottom, each side), of tile models per
|
||||
polygon.
|
||||
* Water and death planes are cell based: they can be moved, resized and turned by 90° only.
|
||||
* The gap check looks only at unturned block, platform and floor tops.
|
||||
* Geometry outside the level grid has no collision.
|
||||
|
||||

|
||||
@@ -0,0 +1,192 @@
|
||||
# Importing meshes and the library
|
||||
|
||||
Brushes cover blocks, ramps and stairs. For everything else – a bridge, a ruin, a statue – you
|
||||
can import a 3D model from Blender or any other modelling program. The editor turns it into a
|
||||
**mesh brush**: when the level is built, the model is cut into the engine's 1×1-cell tiles, gets
|
||||
collision and lit vertex colours, and its textures are packed onto texture pages.
|
||||
|
||||
The **library** works the other way round: it saves geometry from any level (original tiles,
|
||||
brushes and meshes, with their textures) so you can insert it into other levels. And **Export
|
||||
selection as OBJ** takes level geometry to Blender.
|
||||
|
||||
## Supported files
|
||||
|
||||
| Format | What is read |
|
||||
|---|---|
|
||||
| **OBJ** (`.obj` + `.mtl`) | triangles and polygons, UVs, materials with diffuse colour (`Kd`) and texture (`map_Kd`), optional vertex colours (`v x y z r g b`) |
|
||||
| **glTF 2.0** (`.gltf` with external or embedded buffers and images, `.glb`) | node transforms, base colour factor and texture, vertex colours (`COLOR_0`), double-sided materials |
|
||||
|
||||
Textures may be PNG or JPG. The model file and every file it references are **copied into the
|
||||
project**, so the `.llamalevel` file stays complete when you share it (see
|
||||
[Sharing levels](17-sharing.md)).
|
||||
|
||||
## Import mesh dialog
|
||||
|
||||
**File → Import mesh (OBJ, glTF)…** (or **Import mesh…** in the **Imported** tab of the Assets
|
||||
panel) asks for the file and opens the import dialog. The left side is a preview you can orbit by
|
||||
dragging; the grid squares are 1 cell and the small marker shows the llama's size (0.6 cells).
|
||||
|
||||

|
||||
|
||||
**Source** shows the file name, triangle and vertex count, materials and the resulting size in
|
||||
cells.
|
||||
|
||||
### Orientation and size
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Up axis** | **Y up (glTF, most OBJ)** or **Z up (some CAD exports)** |
|
||||
| **Unit scale (file units → cells)** | how many cells one unit of the file is |
|
||||
| **Largest side** … **cells** + **Fit** | sets the unit scale so the largest side becomes this many cells (default 4) |
|
||||
| **Turn** | 0°, 90°, 180° or 270° about the vertical axis |
|
||||
| **Mirror (left ↔ right)** | mirrors the model |
|
||||
| **Stand on the ground (bottom at the click point)** | puts the lowest point of the model on the surface you click |
|
||||
|
||||
### Textures
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Texture size on the page** | 32, 64, **128** or 256 pixels: the size each material texture gets on the level's texture pages |
|
||||
| **UV precision (steps per texture)** | 4, **8**, 16 or 32: how finely each triangle's texture rectangle is rounded |
|
||||
| **Double-sided** | faces are drawn from both sides (thin walls, leaves) |
|
||||
| **Lit (baked vertex colours)** | the model gets lighting like the rest of the level; off = full brightness |
|
||||
|
||||
### Collision
|
||||
|
||||
| Choice | Result |
|
||||
|---|---|
|
||||
| **From the mesh (every triangle)** | every triangle becomes a collision polygon – exact, the llama can walk on all surfaces |
|
||||
| **Simplified: invisible box around it** | an invisible block around the model instead – cheap and smooth, good for statues and props |
|
||||
| **None (decoration only)** | no collision at all |
|
||||
|
||||
**Material** sets the collision material (0 normal, 16 exit floor, 30 death … see
|
||||
[Building geometry](06-geometry.md)).
|
||||
|
||||
### Warnings
|
||||
|
||||
Below the options the dialog estimates how the model will be cut: how many grid cells it covers
|
||||
and how many triangles land in the densest cell. It warns in red when
|
||||
|
||||
* a cell may exceed the engine's **8000 vertices per tile** – simplify the mesh or scale it up,
|
||||
* the model is **larger than the level grid**.
|
||||
|
||||
### Placement
|
||||
|
||||
* **Click in the viewport to place** – after **Import**, a box follows the cursor; click where
|
||||
the model should stand.
|
||||
* **At the view centre** – the model is placed at the point you look at.
|
||||
|
||||
The status bar then says "Placed … – move/turn/scale it with the gizmo tools".
|
||||
|
||||
## The engine's texture rules
|
||||
|
||||
> **Engine limit:** the engine has no free texture coordinates. Every triangle always shows one
|
||||
> half of a rectangular area of a texture page.
|
||||
|
||||
The importer therefore gives each triangle the rectangle around its UVs (rounded to the **UV
|
||||
precision**) on a copy of its material's texture, flipped where that fits better. In practice:
|
||||
|
||||
* **Rectangular quads with UVs that fill the texture map exactly** – the ideal case (walls, planks,
|
||||
floors).
|
||||
* Arbitrary UV layouts (unwrapped characters, atlases) are approximated and can look blurry or
|
||||
shifted.
|
||||
* UVs beyond 0…1 (tiling) are clamped – repeat the geometry instead of the texture.
|
||||
* Untextured materials use their flat colour; vertex colours tint the lighting.
|
||||
|
||||
Imported textures are packed onto new 256×256 texture pages at the chosen size. Several mesh
|
||||
imports add several pages; the engine allows at most 127 pages per level (see
|
||||
[Textures](08-textures.md)).
|
||||
|
||||
## Mesh brushes
|
||||
|
||||
An imported model is listed in the Outliner under **Imported meshes** (the file) and under
|
||||
**Brushes** (each placed copy, a *mesh brush*). The **Imported** tab of the Assets panel shows all
|
||||
meshes of the project: drag one into the viewport to place another copy.
|
||||
|
||||
A mesh brush moves, turns and scales with the gizmo tools like any brush, including free 3D
|
||||
rotation (about its origin) and per-axis stretching with the Scale tool. Its parameters in the
|
||||
Inspector:
|
||||
|
||||
| Parameter | Meaning |
|
||||
|---|---|
|
||||
| **Mesh asset** | the imported file it shows |
|
||||
| **X / Y / Z**, **Rotation (°)**, **Scale** | placement |
|
||||
| **Collision**, **Collision material** | collision from the mesh |
|
||||
| **Double-sided**, **Lit (vertex colours)** | as in the dialog |
|
||||
| **Texture size on the page (16-256)**, **UV rectangle precision (steps per texture)** | as in the dialog |
|
||||
| **Tint (r, g, b)** | colour multiplier |
|
||||
|
||||
The **Brush shape** section (rotation fields, quarter turns, mirror, **Visible**, face table)
|
||||
works as for other brushes.
|
||||
|
||||
### Re-import mesh
|
||||
|
||||
Changed the model in Blender? Select the mesh brush and choose **Geometry → Re-import mesh…**.
|
||||
The editor remembers the source file and asks **Reload <file>?** – **Yes** loads the same file
|
||||
again, **No** lets you choose another file. Up axis, unit scale and the placement of the brush are
|
||||
kept.
|
||||
|
||||
## The library
|
||||
|
||||
The library stores pieces of geometry as reusable assets, available in **every** level and on
|
||||
every base level – a village house in a jungle level, a set of platforms you built once.
|
||||
|
||||

|
||||
|
||||
### Saving to the library
|
||||
|
||||
1. Select tiles, brushes and/or mesh brushes.
|
||||
2. Choose **Geometry → Save selection to library…** or **Save selection…** in the **Library** tab.
|
||||
3. Enter a name (**Save to library**).
|
||||
|
||||
The asset is written to `<data>/library/<name>.llamamesh` (the LlamaMod data folder). It contains
|
||||
the tile models with their collision and vertex colours and every texture used, as pictures.
|
||||
Brushes and meshes are stored in their built form (tiles). Death-plane tiles are left out.
|
||||
|
||||
### Inserting from the library
|
||||
|
||||
* Drag an entry from the **Library** tab into the viewport – it is anchored at the cell under the
|
||||
drop point, or
|
||||
* double-click it or press **Insert** – it is placed at the view centre.
|
||||
|
||||
Textures with identical pixels already in the level are reused; the others are packed onto new
|
||||
texture pages (with their blend mode). Identical tile models are reused too. **Delete** removes
|
||||
the entry from the library (not from levels that already use it).
|
||||
|
||||

|
||||
|
||||
> **Note:** Library pieces stay aligned to whole cells, and objects are not part of them – use
|
||||
> prefabs for objects (see [Objects](09-objects.md)).
|
||||
|
||||
> **Note:** A library file contains pictures of the game's textures. It is meant for your own
|
||||
> projects; when you share a level, the textures it uses are stored in the project anyway.
|
||||
|
||||
## Export selection as OBJ
|
||||
|
||||
**File → Export selection as OBJ…** writes the selected tiles, brushes and meshes as a Wavefront
|
||||
OBJ for Blender:
|
||||
|
||||
* `name.obj` + `name.mtl` + one PNG per texture,
|
||||
* UVs per triangle (the texture-rectangle halves the engine uses),
|
||||
* vertex colours as `v x y z r g b`,
|
||||
* with **Also write the collision polygons (…_collision.obj)** a second OBJ with the collision
|
||||
polygons, grouped by material.
|
||||
|
||||
The coordinates use the importer's convention, so the file can be imported again unchanged: edit
|
||||
it in Blender, then **File → Import mesh** it back (round trip).
|
||||
|
||||
> **Note:** The exported textures are game data – fine for your own editing, please don't share
|
||||
> them.
|
||||
|
||||
## Tips for good meshes
|
||||
|
||||
* Model at the right scale: 1 cell is one grid square, the llama is about 0.6 cells tall. Use
|
||||
**Fit** in the dialog if the file has other units.
|
||||
* Keep the polygon count low – the original levels use simple shapes. Very dense meshes hit the
|
||||
8000-vertex limit per cell.
|
||||
* Use simple, rectangular UV layouts and one texture per material.
|
||||
* Choose **Simplified: invisible box** for decorative props the llama should not climb.
|
||||
* Check the collision with the **Collision** layer (**C**) and play-test from the spot with
|
||||
**Shift+F5**.
|
||||
|
||||
A step-by-step example is the [Blender tutorial](tutorial-blender.md).
|
||||
@@ -0,0 +1,223 @@
|
||||
# Textures
|
||||
|
||||
Every level has its own set of textures, stored on **texture pages** of 256×256 pixels. A
|
||||
*texture* is a rectangle on one of those pages; faces of tiles and brushes refer to a texture by
|
||||
its **number**. The editor lets you see all of them, import your own pictures, animate them and
|
||||
paint them onto faces.
|
||||
|
||||
## Texture basics
|
||||
|
||||
* A level has up to **127 pages**. Each page has one *blend class* (opaque, cut-out,
|
||||
semi-transparent …); every texture on it should have the same class.
|
||||
* Textures are numbered: `#221` is texture 221 of the level. In brush texture fields you can type
|
||||
`#221` or a name. The names (`grass`, `stone`, `bark` …) are those of the village textures;
|
||||
other base levels mostly use numbers.
|
||||
* Brushes can also use flat colours (colour names, or `rgbRRGGBB`).
|
||||
* The game shows textures in **15-bit colour** (5 bits per channel) with 1 bit of transparency,
|
||||
so gradients get coarser and soft edges become hard.
|
||||
* Texture entries are never deleted, because faces and object models refer to them by number.
|
||||
An unused texture can be reused by moving its rectangle.
|
||||
|
||||
## Texture manager
|
||||
|
||||
Open it with the **Textures** tab of the bottom dock, **View → Panels → Texture manager**
|
||||
(**Ctrl+Shift+T**), or the **Window** button for a large separate window.
|
||||
|
||||

|
||||
|
||||
### Pages
|
||||
|
||||
The left list shows every page with a thumbnail, its number and its blend class. Right-click a
|
||||
page for:
|
||||
|
||||
* **Export page as PNG…** – saves the whole page,
|
||||
* **Replace page from PNG…** – loads a picture into the whole page (scaled to 256×256 and reduced
|
||||
to the page's blend class).
|
||||
|
||||
### Atlas
|
||||
|
||||
The middle shows the selected page with every texture rectangle:
|
||||
|
||||
| Colour | Meaning |
|
||||
|---|---|
|
||||
| white | used texture |
|
||||
| red | unused texture |
|
||||
| cyan | animated texture |
|
||||
| orange | the current texture, with 8 handles |
|
||||
|
||||
* Click a rectangle to make it the current texture (the smallest one under the cursor wins).
|
||||
* Drag inside the current rectangle to **move** it, drag a handle to **resize** it. Every face
|
||||
using the texture follows; each drag is one undo step.
|
||||
* The mouse wheel zooms; tooltips show size and usage.
|
||||
* Double-click starts the **Paint texture** tool with that texture.
|
||||
|
||||
### Texture table
|
||||
|
||||
The table lists **#**, a preview, **Name** (editable), **Page**, **Rectangle**, **Blend**,
|
||||
**Faces** (faces of tile models plus brushes using it), **Models** (tile models using it) and
|
||||
**Anim** (its animation, or "frame" if it is a frame of another texture's animation).
|
||||
|
||||
The **Show** box filters the list:
|
||||
|
||||
| Filter | Lists |
|
||||
|---|---|
|
||||
| **All textures** | everything |
|
||||
| **On this page** | textures of the selected page |
|
||||
| **Used** | textures on faces, brushes or in animations |
|
||||
| **Unused** | the others |
|
||||
| **Animated** | textures with an animation |
|
||||
| **Imported** | textures you imported |
|
||||
|
||||
**Name or #** searches by name or number. Double-click a row to paint with that texture.
|
||||
|
||||
> **Note:** Object models (characters, pickups) also use textures from this table, but they are not
|
||||
> counted. "Unused" means *not used by tiles, brushes or animations*.
|
||||
|
||||
### Toolbar
|
||||
|
||||
| Button | Action |
|
||||
|---|---|
|
||||
| **Import…** | import PNG/JPG images as new textures (see below) |
|
||||
| **Replace pixels…** | put a new picture into the selected texture's rectangle |
|
||||
| **Export PNG…** | save the selected texture as a PNG file |
|
||||
| **Paint** | start the Paint texture tool with the selected texture |
|
||||
| **Window** | open the texture manager in its own large window |
|
||||
|
||||
### Texture tab
|
||||
|
||||
Details of the current texture:
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Name** | name shown in the editor, also usable in brush texture fields |
|
||||
| **X / Y** | top-left corner of the rectangle on the page (pixels) |
|
||||
| **W × H** | size in pixels – the engine maps the whole rectangle onto a quad |
|
||||
| **Blend** | blend class (the texture flags); the page's class should match |
|
||||
| flags | the raw flag value |
|
||||
|
||||
Below it a usage line (faces, models, brushes, animations) and two buttons:
|
||||
|
||||
* **Duplicate** – a new texture entry with the same rectangle, e.g. as the starting point for an
|
||||
animation frame,
|
||||
* **Select users** – selects the tiles whose models use the texture.
|
||||
|
||||
## Texture animations
|
||||
|
||||
The **Animation** tab animates the current texture. The game supports two kinds:
|
||||
|
||||
* **Flip-book** – the texture is replaced by a sequence of frame textures in turn (torches,
|
||||
flags, water in the original levels).
|
||||
* **Scroll** – the picture moves vertically inside a band of the page (rivers, lava).
|
||||
|
||||

|
||||
|
||||
**Create animation** starts one (a flip-book begins with the texture itself; add frames with
|
||||
**+**), **Remove animation** removes it.
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Type** | **Flip-book**, **Scroll up** or **Scroll down** |
|
||||
| **Frame delay** | game frames each flip-book frame stays (0 = change every frame; the game runs at about 30 frames per second – the label shows the resulting frames/s) |
|
||||
| **Back and forth** | play forwards then backwards instead of looping |
|
||||
| **Band height** | scroll: height of the page area the picture wraps in (usually the texture height) |
|
||||
| **Speed (px/frame)** | scroll: pixels per game frame |
|
||||
| **Top row (v0)** | scroll: first page row of the band (usually the texture's top edge) |
|
||||
| **Frames** | flip-book frames: **+** adds a texture by number (the current texture is suggested), **−** removes, **◀ ▶** move the selected frame |
|
||||
|
||||
A live preview runs at game speed. The 3D viewport does not animate textures; the preview and the
|
||||
game do.
|
||||
|
||||
> **Tip:** To make a new flip-book: import all frames as textures, select the first one, **Create
|
||||
> animation**, then add the others with **+** by their numbers.
|
||||
|
||||
## Importing textures
|
||||
|
||||
**File → Import texture…** or **Import…** in the texture manager opens the **Import textures**
|
||||
dialog for one or more images (PNG, JPG, BMP, GIF). The two previews show the picture as it is
|
||||
(**Original**) and as the game will show it (**In the game (15-bit)**).
|
||||
|
||||

|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Size (longest side)** | 16, 32, **64**, 128, 256 or **Original** (up to 256); the aspect ratio is kept, rectangles need not be powers of two |
|
||||
| **Blend class** | how the texture is drawn (table below); the description appears below the box |
|
||||
| **Transparent below alpha** | pixels less opaque than this become fully transparent (default 64) |
|
||||
| **Keep half-transparent pixels** | pixels between the cut and 75 % opacity stay half transparent instead of solid |
|
||||
| **Transparent colour** | **None**, **Magenta (FF00FF)** or **Top-left pixel**: a colour that becomes transparent, for images without an alpha channel |
|
||||
| **Dither (smoother gradients in 15-bit colour)** | ordered dithering against colour banding |
|
||||
| **Pack into free space of existing pages** | use unused areas of pages of the same blend class before adding new pages |
|
||||
| **1-pixel border (against seams)** | repeats the edge pixels around the texture, so filtering never shows the neighbour's pixels |
|
||||
|
||||
### Blend classes
|
||||
|
||||
| Class | Use for | What it does |
|
||||
|---|---|---|
|
||||
| **Opaque** | walls, floors, most things | solid; transparent pixels become black |
|
||||
| **Cut-out** | leaves, fences, grids | fully transparent pixels, everything else solid |
|
||||
| **Semi-transparent** | glass, water, smoke | half-transparent pixels blend 50 % |
|
||||
| **Additive glow** | light, fire, sparkles | adds its colour to what is behind it |
|
||||
| **Darken (mode 3)** | shadows | darkens what is behind it |
|
||||
|
||||
The editor guesses the class from the image (alpha channel or not). Imported textures are new
|
||||
texture numbers; the status bar names them. The whole import is one undo step.
|
||||
|
||||
> **Engine limit:** at most 127 texture pages. The **Check** reports more pages as an error.
|
||||
|
||||
### Replacing pixels
|
||||
|
||||
**Edit → Replace texture pixels…** or **Replace pixels…** puts a new picture into the current
|
||||
texture's rectangle – every face using the texture changes at once. The dialog is the same, with
|
||||
the size fixed to the texture's rectangle. Useful to repaint an original texture (a sign, a
|
||||
poster) without touching any faces.
|
||||
|
||||
## Paint texture tool (M)
|
||||
|
||||
The **Paint texture** tool (**M**, toolbar, or double-click a texture in the manager) puts the
|
||||
current texture onto faces.
|
||||
|
||||

|
||||
|
||||
* **Hover**: the face under the cursor gets a white outline; the status bar shows the model, face
|
||||
number, current texture and face flags (and "model shared by n tiles").
|
||||
* **Click**: gives the face the current texture. The clicked face stays selected (orange) for
|
||||
the buttons below.
|
||||
* **Shift+click** picks the texture of a face (eyedropper). **I** or **Edit → Texture
|
||||
eyedropper** does the same for the next click.
|
||||
|
||||
Options bar:
|
||||
|
||||
| Control | Meaning |
|
||||
|---|---|
|
||||
| swatch | the current texture – choose one in the texture manager or pick it from a face |
|
||||
| eyedropper button | the next click picks a texture (**I**) |
|
||||
| scope | **Face** (only the clicked triangle), **Same texture in model** (all faces of the model that had the same texture), **Whole model** |
|
||||
| rotate button | turns the texture on the selected face (cycles its corners; on brushes: the brush's texture rotation) |
|
||||
| mirror button | mirrors the texture on the selected face |
|
||||
| half button | shows the other half of the texture rectangle on the selected triangle |
|
||||
| **Unique** | if the clicked tile shares its model with other tiles, give it its own copy first |
|
||||
|
||||
> **Note:** Original tiles often share one model – a hundred grass tiles may use the same one.
|
||||
> Without **Unique**, painting one of them changes all of them. With **Unique** only the clicked
|
||||
> tile changes (it gets its own copy of the model, which adds data to the level).
|
||||
|
||||
**Brushes**: clicking a brush sets the texture of the side you click – the **top** texture when
|
||||
you click the top, **bottom** for the underside, otherwise the **side** texture (for fences,
|
||||
trees and pillars the first texture parameter, such as the post or trunk). The rotate button
|
||||
then turns the texture of the last painted brush.
|
||||
|
||||
> **Engine limit:** each triangle shows one half of its texture rectangle – that is why "other
|
||||
> half", rotate and mirror exist instead of free UV editing. Object models cannot be painted.
|
||||
|
||||
## Textures in the game
|
||||
|
||||

|
||||
|
||||
## Limits
|
||||
|
||||
* Texture entries are never deleted; reuse unused ones by moving their rectangle.
|
||||
* Object models' textures are not counted as "used" and their faces cannot be painted.
|
||||
* The importer does not change the class of an existing page; it never packs into a page of
|
||||
another class.
|
||||
* Imported meshes create their textures automatically (see
|
||||
[Importing meshes](07-meshes.md)).
|
||||
@@ -0,0 +1,438 @@
|
||||
# Objects
|
||||
|
||||
Objects are everything in a level that *does* something: the llama itself, coins and fruit,
|
||||
checkpoints, exits, enemies, villagers, moving platforms, cameras, cut-scene triggers and many
|
||||
invisible helpers. This chapter shows how to find, place, move, turn and configure them, how to
|
||||
reuse them in other levels and how the editor checks them.
|
||||
|
||||

|
||||
|
||||
## What objects are
|
||||
|
||||
In the game's files an object is called a *strat* (short for strategy). Every object has
|
||||
|
||||
* a **type** (`Coin`, `CheckPointPost`, `LevelDoor`, `CityGuard` …) – the name of its script,
|
||||
* a **position** and a **rotation** (only the turn about the vertical axis is used by most types),
|
||||
* a short list of **parameters** – numbers the script reads when the level starts (for example
|
||||
"snap to floor" for a coin or the target chapter of an exit),
|
||||
* optionally a **waypoint chain** – a list of points the object uses as a path, a camera
|
||||
position, a respawn point or the corners of an area (see [Waypoints and paths](10-waypoints.md)).
|
||||
|
||||
The script code and the 3D model of each type are stored inside the level file. The editor
|
||||
never changes them: it copies them from the base level and only edits position, rotation,
|
||||
parameters and waypoints.
|
||||
|
||||
## Which objects you can place
|
||||
|
||||
Every level is built on a **base level** (see [Introduction](01-introduction.md)). The object
|
||||
types of that base level can be placed right away, because their code and model are copied from
|
||||
it; types of other levels must be imported first (below). The village (Village – Chapter 1, the default base of new levels) has coins,
|
||||
fruit, checkpoints, exits, villagers, cameras and more; other bases offer other enemies and
|
||||
gadgets – the river has river logs, the city has guards, and so on.
|
||||
|
||||
> **Note:** If a type is missing in your base level, the Objects panel simply does not list it. A
|
||||
> setup that needs a missing type (for example an exit on a base without `LevelDoor`) tells you so
|
||||
> in an error message, such as "this base level has no LevelDoor to copy".
|
||||
|
||||
To use object types from other worlds, import them from **Assets → All worlds** – see
|
||||
[Importing objects from other worlds](#importing-objects-from-other-worlds).
|
||||
|
||||
## The Objects panel
|
||||
|
||||
The **Objects** panel sits in the left dock next to the Outliner – the tab with the ⊙ icon (open it with
|
||||
**Tools → Object palette** if you closed it). It has three parts: a search row, the
|
||||
**Quick setups** buttons and the list of all placeable types.
|
||||
|
||||
| Element | What it does |
|
||||
|---|---|
|
||||
| **Search objects…** | Filters the list by type name and by the description of decoded types |
|
||||
| Category box | **All categories**, **Player & start**, **Exits**, **Checkpoints**, **Collectibles**, **Cameras**, **Triggers & dialogue**, **Forces & currents**, **Other objects** |
|
||||
| **★** button | Shows only your favourites |
|
||||
| Quick setups | One-click helpers, see [One-click setups](#one-click-setups) |
|
||||
| Type list | Every placeable type with a rendered thumbnail, its category, the number of variants and the marker **parameters decoded** |
|
||||
|
||||
### Object list
|
||||
|
||||
* **Click** an entry to make it the current type and switch to the **Place objects** tool
|
||||
(**P**). Then click in the viewport to place it.
|
||||
* **Drag** an entry into the viewport to place one object exactly under the mouse pointer.
|
||||
* **Right-click** an entry to add it to or remove it from your **favourites**. Favourites are
|
||||
marked with ★, listed first and remembered between sessions.
|
||||
* Hover an entry for a tooltip with the description of the type.
|
||||
* **parameters decoded** means the editor knows the meaning of the type's parameters and shows
|
||||
named fields in the Inspector (see [Object parameters](#object-parameters)).
|
||||
* **n variants** means the base level contains the type with different settings (different
|
||||
code entry points). The palette places the first variant; to get another one, duplicate an
|
||||
existing object of that variant.
|
||||
|
||||
Thumbnails are rendered in the background the first time the panel is shown; until then a
|
||||
category icon is displayed.
|
||||
|
||||
## Objects in the Assets panel
|
||||
|
||||
The bottom **Assets** panel also has an **Objects** tab with the same types as large tiles,
|
||||
filtered by category. Drag a type from there into the viewport to place it under the mouse
|
||||
pointer. The **Prefabs** tab next to it holds your saved groups of objects
|
||||
(see [Prefabs](#prefabs)).
|
||||
|
||||

|
||||
|
||||
## Place tool (P)
|
||||
|
||||
The **Place objects** tool (key **P**) puts objects onto surfaces and moves them along the
|
||||
ground. It is chosen automatically when you click a type in the Objects panel or a quick setup.
|
||||
|
||||
### Placing an object
|
||||
|
||||
1. Click a type in the Objects panel (the options bar shows *Placing: Coin* or similar).
|
||||
2. Move the mouse over the level. The tool finds the surface under the pointer.
|
||||
3. Click to place. The new object is selected, and the status bar shows its position.
|
||||
|
||||
With **Snap to floor** on, the object is put onto the *collision* floor under the pointer, not
|
||||
just onto the visible surface – so it ends up where the llama can actually reach it. With grid
|
||||
snapping on (**G**), the position snaps to the move step first.
|
||||
|
||||
### Moving and turning objects
|
||||
|
||||
* **Click and drag an object** to move it along the ground. Its height follows the floor when
|
||||
**Snap to floor** is on. Hold **Ctrl** while dragging to invert grid snapping.
|
||||
* With **Move waypoints along** on, the object's waypoint chain moves with it (a guard keeps
|
||||
its patrol path, a camera zone keeps its box).
|
||||
* The selected object shows a **yellow knob** in front of it. Drag the knob to turn the object;
|
||||
the angle snaps to the angle step (Ctrl inverts). A checkpoint's respawn node turns around the
|
||||
post with it.
|
||||
* Each drag is a single undo step.
|
||||
|
||||
You can of course also use the general **Move (W)** and **Rotate (E)** tools and the
|
||||
Inspector – see [Selection and transforming](05-selection.md).
|
||||
|
||||
### Place tool options
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Yaw: Camera direction** | New objects face the way the camera looks (default) |
|
||||
| **Yaw: Facing the camera** | New objects face you – handy for characters and signs |
|
||||
| **Yaw: 0° (+z)** | New objects face the +z direction (south on the grid) |
|
||||
| **Yaw: Keep type default** | New objects get the rotation stored for the type in the base level |
|
||||
| **Snap to floor** | Put new and dragged objects onto the collision floor under the cursor |
|
||||
| **Move waypoints along** | Dragging an object also moves its waypoint chain |
|
||||
| **Exit target** | Only in *Exit* mode: world and chapter the new exit leads to |
|
||||
|
||||
The yaw of new objects also snaps to the angle step while grid snapping is on.
|
||||
|
||||
## One-click setups
|
||||
|
||||
Some objects only work together with other things: a checkpoint needs a respawn point, an exit
|
||||
needs a special floor, a secret needs an area. The **Quick setups** buttons of the Objects panel
|
||||
create the complete set with one click in the viewport.
|
||||
|
||||
| Button | Creates |
|
||||
|---|---|
|
||||
| **Player start** | Moves the player start (or places a Llama with its camera node) |
|
||||
| **Checkpoint** | Checkpoint post with its respawn node in front |
|
||||
| **Exit** | LevelDoor on a 1×1 exit floor (material 16) |
|
||||
| **Secret** | Secret object with a 3×3 box |
|
||||
| **Coin line** | Starts the Coin tool in line mode, see [Coin tool (O)](#coin-tool-o) |
|
||||
| **Coin arc** | Starts the Coin tool in arc mode |
|
||||
|
||||
### Player start
|
||||
|
||||
The player start is the **Llama** object. A level has exactly one, so the setup **moves** the
|
||||
existing Llama to the clicked point (and turns it to the chosen yaw) instead of adding a second
|
||||
one. If the level has no Llama yet, one is placed together with its waypoint chain.
|
||||
|
||||
The first node of the Llama's chain is the **start position of the camera**: the setup puts it
|
||||
8 cells behind the llama, slightly lower; the remaining nodes stay on the llama. See
|
||||
[The start camera](11-cameras-triggers.md#the-start-camera).
|
||||
|
||||
> **Tip:** **Level → Play from camera position** (**Shift+F5**) starts a play-test at another
|
||||
> point without moving the real start – see [Building and play-testing](15-build-play.md).
|
||||
|
||||
### Checkpoint
|
||||
|
||||
Places a **CheckPointPost** (or **CheckPointBox** if the base has no post) and a respawn node
|
||||
0.4 cells in front of it, on the floor. When the llama touches the post, the game stores the
|
||||
node as the respawn point; after losing a life the llama reappears there, facing the node's
|
||||
direction. Turn the post with its knob and the node turns along.
|
||||
|
||||

|
||||
|
||||
### Exit
|
||||
|
||||
Places a **LevelDoor** in the centre of the clicked grid cell and a 1×1 **Floor** brush with
|
||||
collision material **16** (exit floor) under it. The door fires only when the llama stands on
|
||||
material-16 floor *in the door's own grid cell*, which is why both are needed.
|
||||
|
||||
Choose where the exit leads in the options bar (**Exit target**) before you click, or later in
|
||||
the Inspector:
|
||||
|
||||
* a world (**1 · Village** … **8 · Lab**, **9 · TestLevel**) and a chapter of that world,
|
||||
* **World finished → world map (7,7,7)** – the end of a world: the game shows the tally and
|
||||
returns to the world map.
|
||||
|
||||
> **Engine limit:** Do not use *World finished* in a level that runs as a TestLevel chapter
|
||||
> (world 9): it would unlock a world 10 that does not exist and the map crashes. Pick a chapter
|
||||
> instead – the Problems panel warns you.
|
||||
|
||||

|
||||
|
||||
### Secret area
|
||||
|
||||
Places a **Secret** object with a waypoint box of 3×3 cells around the clicked point and
|
||||
switches its *Box area* parameter on. When the llama enters the box, the game shows the secret
|
||||
message and counts the secret. Resize the box with the
|
||||
[Zones and triggers tool (J)](11-cameras-triggers.md#the-zones-and-triggers-tool-j).
|
||||
|
||||
## Coin tool (O)
|
||||
|
||||
The **Coin line / arc** tool (key **O**, or the **Coin line** / **Coin arc** quick setups) places
|
||||
many coins at once. A live preview shows the coins while you move the mouse; **Esc** cancels
|
||||
after the first click.
|
||||
|
||||
* **Line:** click the start point, then the end point. Coins are placed every *Spacing* cells
|
||||
from the start towards the end.
|
||||
* **Arc / circle:** click the centre, then a point on the circle (this sets the radius and the
|
||||
start angle). *Count* coins are spread over *Arc°* degrees; with 360° they form a closed ring.
|
||||
|
||||
| Option | Default | Meaning |
|
||||
|---|---|---|
|
||||
| **Line** / **Arc / circle** | Line | Shape |
|
||||
| **Coin** / **Coin5** | Coin | Coin type (Coin5 is worth five) |
|
||||
| **Spacing** | 0.75 | Distance between coins of a line (0.25–5 cells) |
|
||||
| **Count** | 12 | Number of coins on an arc (1–128) |
|
||||
| **Arc°** | 360 | Angle covered by an arc (10–360°) |
|
||||
| **Height** | 0.3 | Height of the coins above the floor (0–3 cells) |
|
||||
| **Follow floor** | on | Every coin is put onto the floor below it, then raised by *Height* |
|
||||
|
||||
Grid snapping applies to both clicks (Ctrl inverts it). All coins of one line or arc are one
|
||||
undo step.
|
||||
|
||||

|
||||
|
||||
## Object parameters
|
||||
|
||||
Select an object and the Inspector shows the section **Object parameters** above the general
|
||||
properties. It is shown when one object or several objects *of the same type* are selected;
|
||||
changes then apply to all of them.
|
||||
|
||||
### Parameter fields
|
||||
|
||||
At the top a short description explains the type. For decoded types it ends with
|
||||
*(decoded, confidence high/medium/low)*:
|
||||
|
||||
* **high** – the script was read and the behaviour was seen in the game,
|
||||
* **medium** – the script was read,
|
||||
* **low** – only the values of the original levels were compared.
|
||||
|
||||
Each parameter is a row with a name, an editor and the raw value in small grey hexadecimal
|
||||
digits on the right:
|
||||
|
||||
| Parameter kind | Editor |
|
||||
|---|---|
|
||||
| On/off | Check box (stored as 0 or 1.0) |
|
||||
| Number, distance | Number field in cells |
|
||||
| Radius | Number field in cells; the script squares it before comparing. Drag it in the viewport with the [Zones and triggers tool](11-cameras-triggers.md#radius-triggers) |
|
||||
| Seconds | Number field in seconds (the game counts 30 frames per second) |
|
||||
| Count, world, chapter | Whole number |
|
||||
| Choice | Drop-down with the known modes; an unknown value shows as *other: …* |
|
||||
| Event bit | Number 1–32 (0 = none): a progress flag shared with other objects |
|
||||
| Raw | Plain number for values whose meaning is unknown |
|
||||
|
||||
Hover a row for a tooltip with the parameter number (`p0`, `p1` …), its description, the valid
|
||||
range, the values used in the original levels and the raw value. Values outside the known range
|
||||
get an orange warning line below the row.
|
||||
|
||||
Types that are **not decoded** show *Parameters of this type are not decoded yet – raw values*,
|
||||
with one row per parameter (*Parameter 0*, *Parameter 1* …). The tooltips still list the values
|
||||
the original levels use, which is a good hint what makes sense.
|
||||
|
||||
If an object has a different number of parameters than its type reads, a warning line appears
|
||||
with the button **Reset to defaults**. It sets the parameters back to those of the type in the
|
||||
base level.
|
||||
|
||||
### Exit target
|
||||
|
||||
For a **LevelDoor** (and the village's **VillageEndDoor**) the section starts with
|
||||
**Target level**: a world box and a chapter box, and the line *Leads to: …* that names the
|
||||
target in words. The options are the same as for the [Exit setup](#exit).
|
||||
|
||||
### Waypoint row
|
||||
|
||||
At the end of the section a row describes the object's waypoint chain – *No waypoints* or
|
||||
*Waypoints: 4 nodes · patrol path* – with a short explanation of what the nodes mean for this
|
||||
type, or how many original objects of the type have a chain. Buttons:
|
||||
|
||||
| Button | Action |
|
||||
|---|---|
|
||||
| **Create path** / **Edit path** | Switches to the Waypoint tool (**N**) to add and move nodes |
|
||||
| **Unlink** | The object stops using the chain (the nodes stay in the level) |
|
||||
| **Delete path** | Deletes the chain's nodes |
|
||||
| **Link…** | Uses an existing chain: choose its first node from a list |
|
||||
| **Look through** | Only for cameras: [pilot mode](11-cameras-triggers.md#look-through-camera) |
|
||||
|
||||
Details: [Waypoints and paths](10-waypoints.md).
|
||||
|
||||
### General properties
|
||||
|
||||
Below the plugin sections the Inspector lists the raw properties of every object:
|
||||
|
||||
* **Type** – object type, code offset in the level's script block, number of variables and
|
||||
slots, type flags and extra memory (read-only information copied from the base level),
|
||||
* **Transform** – position (x, y, z in cells) and rotation (degrees about x, y and z),
|
||||
* **Behaviour** – the raw parameter list, the waypoint chain reference and the object flags.
|
||||
|
||||
You rarely need these; the named fields above are easier and safer.
|
||||
|
||||
## Decoded object types
|
||||
|
||||
The editor knows the parameters of these types (the rest show raw values):
|
||||
|
||||
| Type | Parameters | Waypoints |
|
||||
|---|---|---|
|
||||
| **Coin** | Snap to floor (drops onto the floor at level start, random spin), Falls (keeps floor collision, rests on moving floors), No shadow | – |
|
||||
| **Coin5** | Snap to floor, Falls | – |
|
||||
| **Health**, **HealthFull**, **HealthGenerator**, **Wompy** | Snap to floor, Falls (Health also No shadow) | – |
|
||||
| **Grapes**, **HealthBanana**, **ChargeBooster** | Snap to floor | – |
|
||||
| **RubyIdol** | Falls, Snap to floor | – |
|
||||
| **CoinLine** / **CoinCircle** | Coins (count), Spacing / Radius – spawners that create coins at run time | – |
|
||||
| **Secret** | Box area | 2 nodes: opposite corners of the secret area |
|
||||
| **Llama** | Helper, Unused, Camera mode | First node = camera start |
|
||||
| **CheckPointPost** | Collision radius (originals 0.2) | 1 node: respawn position and facing |
|
||||
| **LevelDoor** | Tribe, World, Chapter of the next level (7,7,7 = world finished) | – |
|
||||
| **CameraSide**, **CameraLift**, **CameraSetDistance**, **CameraFocusPoint** | see [Cameras and triggers](11-cameras-triggers.md) | box pairs / – |
|
||||
| **CutSceneCameraDirectional**, **CutSceneTrigger** | see [Cut scenes](11-cameras-triggers.md#cut-scenes) | camera path |
|
||||
| **ForcePlayerMovement**, **WaterReboundPoints**, **ObjectDontDropInBox**, **FallOffNoHurt**, **RiverCurrentBox** | see [Force and water objects](11-cameras-triggers.md#force-and-water-objects) | points / box |
|
||||
| **RubyIdolDoor** | Idols needed, Offset (sign distance) | – |
|
||||
| **PressurePadDoor** | Pad flags (bit field), Door z, Camera, Camera hold | – |
|
||||
| **CityGuard** | View range, Chase range, Event bit, Wall collision | Patrol path (wraps to the first node) |
|
||||
| **JumpingBeetleBlue**, **JumpingBeetle** | Jump time, Wait, Jump height, Pause | Jump targets |
|
||||
| **Spider** | Range, Speed, Down time, Up time, Start down | Path |
|
||||
| **Bunny** | Flee range | – |
|
||||
|
||||
> **Tip:** For pickups, leave **Snap to floor** on: the game then drops the coin onto the floor
|
||||
> when the level starts, so a coin placed slightly too high still ends up in the right place.
|
||||
|
||||
## Duplicating, copying and pasting
|
||||
|
||||
* **Edit → Duplicate** (**Ctrl+D**) copies the selection one cell east. Objects keep a copy of
|
||||
their waypoint chain, so a duplicated guard gets its own patrol path.
|
||||
* **Edit → Copy** / **Paste** (**Ctrl+C** / **Ctrl+V**) work inside the open level.
|
||||
* **Delete** removes objects; waypoint chains used only by the deleted objects are removed too.
|
||||
|
||||
### Copy objects between levels
|
||||
|
||||
**Edit → Copy objects (for other levels)** (**Ctrl+Shift+C**) puts the selected objects – with
|
||||
their waypoint chains – and selected brushes on the system clipboard, relative to their common
|
||||
centre. Open another level (or another editor) and choose **Edit → Paste objects at view
|
||||
centre** (**Ctrl+Shift+V**).
|
||||
|
||||
Object types are matched **by name and variant** in the target level's base. Types that the
|
||||
target base does not have are skipped, and a message lists them. Code and models are not
|
||||
copied – for that, see [Importing objects from other worlds](#importing-objects-from-other-worlds).
|
||||
|
||||
## Prefabs
|
||||
|
||||
A prefab is a saved group of objects (with their waypoints) and brushes that you can place again
|
||||
in any level – a checkpoint with coins around it, a guard with its patrol, a small platform with
|
||||
a secret.
|
||||
|
||||
* **Save:** select the objects and brushes, then **Tools → Save selection as prefab…** (or the
|
||||
**Save selection as prefab…** button of the Prefabs tab) and enter a name. The prefab is stored
|
||||
as `<data folder>/editor/prefabs/<name>.json` with a thumbnail.
|
||||
* **Place:** open **Assets → Prefabs**. **Double-click** places the prefab at the view centre,
|
||||
**drag** places it under the mouse pointer.
|
||||
* **Delete** removes the selected prefab file (after a confirmation); **Refresh** rereads the
|
||||
folder.
|
||||
|
||||
The entries show the base level they were made on and how many objects and brushes they hold.
|
||||
As with copy and paste, object types the target base does not know are skipped.
|
||||
|
||||
## Importing objects from other worlds
|
||||
|
||||
A project can only place the object types of its base level – unless you **import** types from
|
||||
other levels. The editor knows every object type of every original level (about 900 types from
|
||||
33 levels) and can copy a type into your level together with everything it needs: its script
|
||||
code, models, animations, textures, sounds and texts. A village level can then have spiders from
|
||||
the jungle, swinging blades from the city or a merry-go-round from the mountain.
|
||||
|
||||

|
||||
|
||||
### The All worlds tab
|
||||
|
||||
**Assets → All worlds** lists the object types of all worlds with thumbnails:
|
||||
|
||||
* **Search all worlds…** finds types by name; the boxes filter by **world** (or *Other levels*)
|
||||
and by **category** (enemies, collectibles & pickups, platforms, doors & mechanisms,
|
||||
characters, animals, effects …).
|
||||
* **Importable only** hides types that cannot be imported (player starts, cameras and cut-scene
|
||||
objects – about 126 of them).
|
||||
* A **✓** marks types already imported into this level. The tooltip shows the source level, how
|
||||
many instances the original has and what the type depends on (sizes, sounds, texts).
|
||||
* The first time, the editor builds this catalogue from your CD (a few seconds, shown in the
|
||||
status bar); it is cached afterwards. **Level → Rebuild object catalogue** scans again.
|
||||
|
||||
### Importing and placing
|
||||
|
||||
* **Drag** a type into the viewport: it is imported (in the background) and placed at the drop
|
||||
point.
|
||||
* **Double-click** imports it and places it at the view centre.
|
||||
* The context menu has **Place at view centre**, **Import into the project** (import only) and
|
||||
**Import all of** *level*….
|
||||
|
||||
Imported types then appear in **Assets → Objects** and the Objects panel like the base level's
|
||||
own types, and you place more of them as usual. Selected instances show an **Imported object**
|
||||
section in the Inspector that names the level they come from.
|
||||
|
||||

|
||||
|
||||
### Import a whole world
|
||||
|
||||
**Level → Import objects of a world…** (**Ctrl+Shift+I**, or **Import world…** in the tab)
|
||||
imports many types at once: choose a world or a single level, tick the types you want (with
|
||||
category, source level, size and notes), keep **Skip types the level already has** on and click
|
||||
**Preview** – the editor merges them in the background and shows exactly what would be added
|
||||
(code, models, textures, sounds, texts) against the engine limits. **Import** then adds them.
|
||||
|
||||

|
||||
|
||||
### Limits and things to know
|
||||
|
||||
| Limit | Value |
|
||||
|---|---|
|
||||
| Level memory (code, textures, models, map, texts) | 16 MB – original levels use up to about 7 MB |
|
||||
| Sound samples | 128 |
|
||||
| Texture pages | 127 |
|
||||
|
||||
The preview and **Check for problems** report these (errors above a limit, warnings near it).
|
||||
|
||||
* **Imports are permanent.** An import changes the level's code layout, so it clears the undo
|
||||
history and appears as a fixed "Import …" step. It cannot be removed from the project later –
|
||||
delete the placed objects instead, or start a new level.
|
||||
* The project only stores *which* types were imported, never game data, so sharing stays legal
|
||||
and small; the receiver's editor and LlamaMod repeat the import from their own CD.
|
||||
* A type whose code already exists in your level (for example the coin) is shared – it keeps
|
||||
your level's model and textures.
|
||||
* New instances get the parameters of the first instance in the source level; change them in
|
||||
**Object parameters**.
|
||||
* Objects that belong to level geometry (doors in walls, tile swaps, river or roller-coaster
|
||||
specials) import fine but only work with matching geometry. Waypoint chains are copied
|
||||
relative to the object.
|
||||
|
||||
## Object checks
|
||||
|
||||
**Level → Check for problems** and every build check the objects. Double-click a message in the
|
||||
**Problems** panel to select the object.
|
||||
|
||||
| Message | What to do |
|
||||
|---|---|
|
||||
| Waypoint chain … is not stored in one piece (error) | Run **Tools → Repair waypoint chains** |
|
||||
| The level has n player start objects | Delete all Llamas but one |
|
||||
| … has n parameters, Type reads m | Press **Reset to defaults** in Object parameters |
|
||||
| Out-of-range value (e.g. a chapter that does not exist) | Correct the field marked orange |
|
||||
| … needs n waypoint(s) / box nodes come in pairs | Add nodes with the Waypoint tool |
|
||||
| … has no waypoints; all original … objects have a chain | The type probably needs a chain – create one |
|
||||
| LevelDoor … without exit floor (collision material 16) | Use the Exit setup or paint material 16 under the door ([Collision](06-geometry.md)) |
|
||||
| … targets (7,7,7) "world finished" in TestLevel | Choose a chapter as target |
|
||||
| Respawn node is n cells away (info) | Move the checkpoint's node next to the post |
|
||||
|
||||

|
||||
@@ -0,0 +1,164 @@
|
||||
# Waypoints and paths
|
||||
|
||||
Many objects need positions besides their own: a guard walks along a patrol path, a camera zone
|
||||
covers a box, a checkpoint stores where the llama respawns, a cut scene flies its camera along a
|
||||
route. The game stores all of these as **waypoints** – points linked into **chains**. This
|
||||
chapter explains how chains work and how to edit them with the **Waypoint paths** tool.
|
||||
|
||||

|
||||
|
||||
## What waypoint chains are
|
||||
|
||||
A waypoint (also called a *node*) has a position, a turn (yaw) and a tilt (pitch), plus a few
|
||||
fields whose meaning is not known yet. Every node can point to a **next** node; following these
|
||||
links from a first node gives a chain. An object refers to the **first node** of its chain.
|
||||
|
||||
* One object uses at most one chain.
|
||||
* Several objects may share one chain (the original levels do this in places).
|
||||
* A chain without an object is allowed but does nothing.
|
||||
|
||||
In the Outliner the chains are listed under **Waypoint chains**. In the viewport nodes are drawn
|
||||
as small markers joined by lines.
|
||||
|
||||
## Chain roles
|
||||
|
||||
What the nodes mean depends on the object type. The Inspector names the role in the
|
||||
[waypoint row](09-objects.md#waypoint-row) and in the Waypoint chain section:
|
||||
|
||||
| Role | Used by | Meaning of the nodes |
|
||||
|---|---|---|
|
||||
| **patrol path** | CityGuard, JumpingBeetleBlue, Spider … | Points the character walks or jumps to; patrols wrap from the last node back to the first |
|
||||
| **camera positions** | Llama (first node), cut-scene cameras, CutSceneTrigger | Camera position; node yaw and pitch give the view direction |
|
||||
| **respawn point** | CheckPointPost | Where the llama reappears, and which way it faces |
|
||||
| **box area (two opposite corners)** | Secret, CameraSide, CameraLift, ObjectDontDropInBox, FallOffNoHurt … | Two nodes span a rectangle on the ground (x and z only); some types use several pairs |
|
||||
| **point list** | ForcePlayerMovement, WaterReboundPoints | Target points |
|
||||
| **waypoint chain** | other types | Meaning unknown – keep the original layout |
|
||||
|
||||
For types that are not decoded, the editor guesses: camera objects get *camera positions*, types
|
||||
whose originals always have exactly two nodes get *box area*.
|
||||
|
||||
## Showing waypoints
|
||||
|
||||
By default the viewport shows only the chains of the **selected** objects and nodes – a big level
|
||||
has hundreds of nodes. To see all of them:
|
||||
|
||||
* **View → Show waypoints of all objects**, or
|
||||
* the **Show all chains** button of the Waypoint tool (it toggles the same setting).
|
||||
|
||||
Two layers (options bar → **Layers**) control the drawing:
|
||||
|
||||
* **Waypoints** – the node markers and connecting lines,
|
||||
* **Path directions** – arrows along the chain, a dashed segment from the last back to the first
|
||||
node for patrol paths (they wrap) and a short tick at each node showing its yaw.
|
||||
|
||||
Click a node marker to select the node. Hidden or locked objects' nodes are not pickable.
|
||||
|
||||
## Waypoint tool (N)
|
||||
|
||||
The **Waypoint paths** button of the toolbar or key **N** starts the tool. It edits the chain of
|
||||
the **selected object**, or the chain the **selected node** belongs to. The options bar reminds
|
||||
you of the mouse actions: *Click: add node · Ctrl+click: insert before · drag: move ·
|
||||
Backspace/Del: remove*.
|
||||
|
||||
### Adding nodes
|
||||
|
||||
1. Select the object (click it while the tool is active – clicking an object selects it).
|
||||
2. **Click** on the ground. The new node is added **after the selected node**, or at the end of
|
||||
the chain if the object itself is selected. If the object has no chain yet, the click creates
|
||||
one with this first node.
|
||||
3. Keep clicking to add more nodes; each new node becomes the selected one, so the chain grows in
|
||||
the order you click.
|
||||
|
||||
**Ctrl+click** inserts the new node **before** the selected node instead (before the first node
|
||||
if the first one is selected).
|
||||
|
||||
The new node copies the pitch and the unknown raw fields of the last node of the chain. With **Follow
|
||||
floor** on it sits on the floor under the pointer; grid snapping applies (Ctrl inverts it – note
|
||||
that Ctrl+click therefore also inverts snapping).
|
||||
|
||||
### Moving and deleting nodes
|
||||
|
||||
* **Drag a node** to move it. With **Follow floor** on it keeps its height above the floor as you
|
||||
drag over hills and steps. Each drag is one undo step.
|
||||
* **Backspace** (while the tool is active) or **Delete** / **Edit → Delete** removes the selected
|
||||
nodes and **relinks** the chain: the previous node now leads to the following one. The next
|
||||
node becomes selected, so you can delete several in a row.
|
||||
* Moving the owner object with the Place tool moves the whole chain along (option
|
||||
*Move waypoints along*).
|
||||
|
||||
### Waypoint tool options
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Follow floor** | New and dragged nodes stay on the collision floor (on by default) |
|
||||
| **Orient new nodes** | A new node faces away from the previous node, i.e. along the path (on by default) |
|
||||
| **Reverse** | Reverses the order of the chain; the object then starts at the former last node |
|
||||
| **Show all chains** | Toggles between the chains of the selection and all chains |
|
||||
|
||||

|
||||
|
||||
## Waypoint chain section
|
||||
|
||||
When a single node is selected, the Inspector shows the section **Waypoint chain**:
|
||||
|
||||
* *Node i of n*, the object(s) using the chain and its role – or *not used by an object*,
|
||||
* **Select object** – selects the owner,
|
||||
* **Edit path** – switches to the Waypoint tool,
|
||||
* **◀** / **▶** – select the previous / next node,
|
||||
* **Delete node** – removes this node and relinks the chain,
|
||||
* **Look through** – shows the view from this node (camera nodes, see
|
||||
[Look through camera](11-cameras-triggers.md#look-through-camera)).
|
||||
|
||||
The node's position, yaw, pitch and raw fields are in the general properties below.
|
||||
|
||||
## Linking chains to objects
|
||||
|
||||
The waypoint row of **Object parameters** (see [Objects](09-objects.md#waypoint-row)) connects
|
||||
chains and objects:
|
||||
|
||||
* **Create path** / **Edit path** – start the Waypoint tool for this object.
|
||||
* **Unlink** – the object no longer uses its chain; the nodes stay in the level (for example to
|
||||
give them to another object).
|
||||
* **Delete path** – removes the chain's nodes.
|
||||
* **Link…** – opens *Link <type> to a waypoint chain* with all chains of the level, nearest first:
|
||||
first node id, number of nodes, distance from the object and which objects use it (or
|
||||
*unused*). Choose one and press OK.
|
||||
|
||||
**Edit → Duplicate** gives the copy its own copy of the chain. Deleting an object also deletes
|
||||
chains that no other object uses.
|
||||
|
||||
## Chains must be stored in one piece
|
||||
|
||||
The game does not really follow the *next* links when it loads a level: it links node number *i*
|
||||
to node *i + 1* in the level's node list whenever *next* is set. A chain therefore has to be
|
||||
stored **contiguously** – all its nodes one after the other.
|
||||
|
||||
The editor keeps chains contiguous when you add, insert or delete nodes. Older projects or unusual
|
||||
edits can break this; then **Level → Check for problems** reports an error *Waypoint chain at … is
|
||||
not stored in one piece*, and building is blocked. Run **Tools → Repair waypoint chains** – it
|
||||
reorders the node list so every chain is in one piece (the status bar says *Waypoint chains repaired*, or *All waypoint chains are stored in one piece*
|
||||
when nothing had to be done).
|
||||
|
||||
## Example: a patrolling enemy
|
||||
|
||||
1. Click **JumpingBeetleBlue** (or another enemy with a patrol path) in the Objects panel and
|
||||
place it with the Place tool.
|
||||
2. Press **N**. The beetle stays selected.
|
||||
3. Click four points around the area the beetle should cover. Watch the arrows: the dashed
|
||||
segment closes the loop back to the first node.
|
||||
4. Press **F5** to try it: the beetle jumps from node to node.
|
||||
|
||||

|
||||
|
||||
## Waypoint checks
|
||||
|
||||
The Problems panel reports:
|
||||
|
||||
| Message | Meaning |
|
||||
|---|---|
|
||||
| Chain not stored in one piece (error) | Run **Tools → Repair waypoint chains** |
|
||||
| … needs n waypoint(s) (…), has m | The type reads more nodes than the chain has |
|
||||
| … uses only n waypoint(s), the chain has m (info) | Extra nodes are ignored by the game |
|
||||
| … box nodes come in pairs | Box zones need an even number of nodes |
|
||||
| … has no waypoints; all original … objects have a chain | Most likely the type needs one |
|
||||
| Respawn node is n cells away (info) | A checkpoint's respawn point far from the post |
|
||||
@@ -0,0 +1,200 @@
|
||||
# Cameras and triggers
|
||||
|
||||
The game has no free camera: it follows the llama on its own, and special objects in the level
|
||||
change how it does that – camera zones, focus points and cut scenes. Other invisible objects react
|
||||
when the llama enters an area or comes close: secrets, cut-scene triggers, force zones. This
|
||||
chapter shows how to see, set up and tune all of them.
|
||||
|
||||

|
||||
|
||||
## How the game camera works
|
||||
|
||||
During play the camera hangs behind the llama at a certain **distance** and **height** and turns
|
||||
with it smoothly. Camera objects change these values while the llama is inside their area:
|
||||
|
||||
* a **camera zone** sets the height, distance and often a fixed view direction (yaw),
|
||||
* a **focus point** turns the camera towards an object when the llama is near,
|
||||
* a **cut scene** takes over the camera completely and flies it along a path.
|
||||
|
||||
All camera objects are invisible in the game. In the editor they are drawn as markers, their
|
||||
areas as boxes and their cameras as frusta (pyramids showing the view).
|
||||
|
||||
## The start camera
|
||||
|
||||
The **Llama** (the player start) owns a waypoint chain. Its **first node is the camera's start
|
||||
position** when the level begins; the game then moves the camera to its normal place behind the
|
||||
llama. Levels made with the editor put this node 8 cells behind the llama (the
|
||||
[Player start](09-objects.md#player-start) setup keeps it there when you move the start).
|
||||
|
||||
The Llama's *Camera mode* parameter switches between the normal and an alternative camera
|
||||
behaviour.
|
||||
|
||||
> **Note:** In the original levels the Llama's chain is often a longer list used by the level's
|
||||
> scripts (for example the village's fly-by at the start). Edit it with care.
|
||||
|
||||
## Camera zones
|
||||
|
||||
A camera zone is an object with a **box**: two waypoints marking opposite corners on the ground.
|
||||
While the llama stands inside the box (the game only tests x and z), the zone controls the camera.
|
||||
Edit the box with the [Zones and triggers tool](#the-zones-and-triggers-tool-j).
|
||||
|
||||
### CameraSide
|
||||
|
||||
The most common camera zone. Its parameters (Inspector → **Object parameters**):
|
||||
|
||||
| Parameter | Meaning |
|
||||
|---|---|
|
||||
| **Height** | Camera height above the llama, 0 = keep the current value |
|
||||
| **Distance** | Horizontal distance behind the llama, 0 = keep |
|
||||
| **Yaw mode** | **free**; **node yaw** – the camera looks in the direction of the zone's first node; **node yaw ±180°** – that direction or the opposite one, whichever is closer to the current view; mode 3, mode 4 (unknown) |
|
||||
| **Height limit** | Only active while the llama is below the first node's height |
|
||||
| **Flag 0x10000** | Sets an object flag (purpose unknown) |
|
||||
| **Several boxes** | The chain holds several boxes (node pairs 1–2, 3–4 …) |
|
||||
| **Height offset** | Added to the camera height |
|
||||
| **Alt. height** / **Alt. distance** | Used instead of Height / Distance in a special game state |
|
||||
| p5 … p9 | Not decoded (originals use small values) |
|
||||
|
||||
With the **Camera frusta** layer on, a selected CameraSide shows where the game camera will be:
|
||||
the editor assumes the llama in the centre of the first box (and distance 2, height 1 when the
|
||||
parameters are 0).
|
||||
|
||||

|
||||
|
||||
> **Tip:** The easiest way to set up a CameraSide is [Look through camera](#look-through-camera):
|
||||
> select the zone, press **Ctrl+Shift+L** and fly the viewport to the view you want. Height,
|
||||
> distance and the node yaw follow.
|
||||
|
||||
### CameraLift
|
||||
|
||||
A camera zone for lifts and object-relative views, with one box.
|
||||
|
||||
| Parameter | Meaning |
|
||||
|---|---|
|
||||
| **Yaw source** | **none**, **object yaw** (the camera turns with the zone object) or **player yaw** |
|
||||
| **Use helper position** | Tests the box against a helper object instead of the llama |
|
||||
| **Smooth** | Softer camera movement |
|
||||
| **Height limit** | Only while the llama is below the node's height |
|
||||
| **Flag 0x10000**, p2 | Not fully understood |
|
||||
|
||||
### CameraSetDistance and CameraFocusPoint
|
||||
|
||||
* **CameraSetDistance** sets several camera values while it is active: *Height* and four raw values
|
||||
(*Value g82*, *g68*, *g83*, *g73*) whose exact effect is not known yet.
|
||||
* **CameraFocusPoint** turns the camera towards the object while the llama is within **Radius**.
|
||||
Further parameters: *Min. height*, *Max. angle* (largest angle between object and view),
|
||||
*Height limit*, three flags and *Blend* (0–1, how fast the camera turns). The radius can be
|
||||
dragged in the viewport (see [Radius triggers](#radius-triggers)).
|
||||
|
||||
## Cut scenes
|
||||
|
||||
Cut scenes are made of two kinds of objects:
|
||||
|
||||
* **CutSceneTrigger** starts a scene when the llama comes within its **Radius**. Its chain is the
|
||||
camera path. Parameters: *Character* (the trigger is a talking character: drops onto the floor),
|
||||
*Radius*, *Event bit* (the scene is skipped once this progress bit is set – so it plays only
|
||||
once), *Height check* (the llama must also be above the trigger), *Flags* (1 = face the
|
||||
llama, 2 = cannot be skipped) and two flags whose purpose is unknown.
|
||||
* **CutSceneCameraDirectional** is the camera of a scene. Every node of its chain is a camera
|
||||
position; the node's **yaw** and **pitch** give the view direction. Parameters: *Event bit*,
|
||||
*Mode*, *Wait*, *Disabled* (removes itself at the start), *End mode*.
|
||||
|
||||
The dialogue, animations and character movements of a scene are part of the object scripts and
|
||||
cannot be edited – but you can move, re-aim and re-time the camera, move the trigger and change
|
||||
its radius.
|
||||
|
||||

|
||||
|
||||
## Camera frusta layer
|
||||
|
||||
The **Camera frusta** layer (options bar → **Layers**, on by default) draws, for the selected
|
||||
objects:
|
||||
|
||||
* **CameraSide** / **CameraLift** – the computed game camera looking at the zone,
|
||||
* **cut-scene cameras** and **camera nodes** – a frustum at every node, pointing along the
|
||||
node's yaw and pitch.
|
||||
|
||||
The game's field of view is approximated with 60°.
|
||||
|
||||
## Look through camera
|
||||
|
||||
**View → Camera → Look through camera (pilot)** (**Ctrl+Shift+L**), or the **Look through**
|
||||
buttons in the Inspector and the options bar of the Zones and triggers tool, turns the viewport
|
||||
into the selected camera:
|
||||
|
||||
| Selection | The viewport shows | Flying changes |
|
||||
|---|---|---|
|
||||
| A camera node (any waypoint) | The view from the node | Node position, yaw and pitch |
|
||||
| A cut-scene camera or other camera object | The view from the first node of its chain | That node's position, yaw and pitch |
|
||||
| A **CameraSide** zone | The game camera of the zone | *Height*, *Distance* and the first node's yaw |
|
||||
| A **CameraLift** zone | The game camera of the zone | The first node's yaw |
|
||||
|
||||
While pilot mode is on, fly as usual (right mouse button + **W A S D**, **Q / E**) – the camera
|
||||
object follows the viewport, and the whole pilot session is **one undo step**. Press
|
||||
**Ctrl+Shift+L** again, or select something else, to end it. The status bar shows *Piloting …*
|
||||
while it is active.
|
||||
|
||||

|
||||
|
||||
> **Note:** The first node of some original cut-scene cameras is a fly-in start point, so looking
|
||||
> through it may show a wall.
|
||||
|
||||
## The Zones and triggers tool (J)
|
||||
|
||||
The **Zones & triggers** tool (toolbar, key **J**) adds handles to the selected object:
|
||||
|
||||
* **pink corner handles** at the four corners of each box of a box zone – drag a corner to resize
|
||||
the box; the opposite corner stays,
|
||||
* a **yellow radius knob** for every radius parameter (CutSceneTrigger, CameraFocusPoint, guards'
|
||||
view and chase ranges, ForcePlayerMovement, Bunny) – drag it to change the radius; the status
|
||||
bar shows the value.
|
||||
|
||||
Grid snapping applies (Ctrl inverts it). Clicks elsewhere select as usual. The options bar has a
|
||||
**Look through camera** button for camera zones. Each drag is one undo step.
|
||||
|
||||

|
||||
|
||||
### Box zones
|
||||
|
||||
These types use one box (two nodes) – or, for CameraSide with *Several boxes*, several pairs:
|
||||
|
||||
| Type | Effect while the llama is inside |
|
||||
|---|---|
|
||||
| **Secret** | Shows the secret message and counts the secret (needs *Box area* on) |
|
||||
| **CameraSide**, **CameraLift** | Camera control, see [Camera zones](#camera-zones) |
|
||||
| **ObjectDontDropInBox** | Objects (for example fruit from smashed pots) are not dropped here |
|
||||
| **FallOffNoHurt** | Falling off costs no energy (optional *Game state* condition) |
|
||||
| **RiverCurrentBox** | River current (not decoded in detail) |
|
||||
|
||||
The box is a rectangle on the ground; the game ignores the height. The editor draws it with an
|
||||
estimated height of about 1.2 cells above the lower node.
|
||||
|
||||
### Radius triggers
|
||||
|
||||
Radius parameters are distances in cells. The scripts compare the *squared* distance, which the
|
||||
editor handles for you – just enter or drag the radius. The **Zone areas & trigger radii** layer
|
||||
draws the circles of the selected objects.
|
||||
|
||||

|
||||
|
||||
## Force and water objects
|
||||
|
||||
* **ForcePlayerMovement** pushes or steers the llama towards the points of its chain while it is
|
||||
within *Radius*: *Active*, *Radius*, *Game state* (only in that state), *Lock controls*,
|
||||
*Align yaw* (the llama turns to the node's yaw).
|
||||
* **WaterReboundPoints** (and **WaterReboundPointsTurnsOff**): the points of its chain are where
|
||||
the llama is thrown back to after falling into water. Parameter *Active*.
|
||||
|
||||
## Zone areas layer
|
||||
|
||||
The **Zone areas & trigger radii** layer draws the boxes of **all** zone objects as outlines and
|
||||
fills the boxes and radius circles of the **selected** ones. Switch it off in a busy original
|
||||
level if the outlines get in the way.
|
||||
|
||||
## Known limits
|
||||
|
||||
* The camera preview of CameraSide assumes the llama in the box centre and the default distance
|
||||
and height when the parameters are 0; the real camera also depends on where the llama enters.
|
||||
* Zone heights in the viewport are estimates; the game tests x and z only.
|
||||
* Many camera parameters are only partly understood (*p5 … p9*, *Value g…*). Copying values
|
||||
from similar zones in the original levels works best.
|
||||
* Cut-scene content (dialogue, animation) cannot be edited.
|
||||
@@ -0,0 +1,251 @@
|
||||
# Environment: zones, fog, music and light
|
||||
|
||||
This chapter covers everything that sets the *mood* of a level: fog and draw distance, sky and
|
||||
backdrop colours, music, teleports between areas, the lights that colour object models and the
|
||||
baked vertex colours that light the level geometry itself.
|
||||
|
||||
Most of it lives in the **Environment** panel (left dock, next to the Outliner) with its three
|
||||
tabs **Zones**, **Lights** and **Lighting**, plus four tools: **Zones**, **Lights**, **Paint vertex
|
||||
colours** and the region painter of the next chapter ([Visibility regions](13-visibility.md)).
|
||||
|
||||

|
||||
|
||||
## How the game uses zones
|
||||
|
||||
The game stores a small list of *environment zones* in every level. Each zone holds a complete
|
||||
environment: fog mode and distances, fog/sky colour, the ambient colour for object models, a
|
||||
music track and a sky model. There are two kinds:
|
||||
|
||||
* **The start zone** (exactly one per level). The level begins with its fog, colours and music.
|
||||
Its trigger cell is not used – the original levels park it outside the playfield at cell
|
||||
(3, y, 0).
|
||||
* **Teleport / environment zones.** Each one belongs to a *trigger cell* of the grid. When the
|
||||
player walks onto an **exit floor** (collision material **16**) or into a door object
|
||||
(RubyIdolDoor, PressurePadDoor) in that cell, the game looks up the zone of the player's cell,
|
||||
moves the player to the zone's **target** facing the zone's direction, and switches to the
|
||||
zone's fog, colours and music. The house doors in the Village work this way: you enter a door
|
||||
and arrive inside the house, with the indoor fog and music.
|
||||
|
||||
A zone can also *only* switch the environment without moving the player: untick **Move the
|
||||
player here** in its Inspector section. That is how you make, for example, a cave entrance that
|
||||
turns the fog dark while the llama keeps walking.
|
||||
|
||||
> **Engine limit:** the game switches zones only through these triggers. There is no "area" in
|
||||
> which a zone is active – after a teleport the new environment stays until the next trigger.
|
||||
|
||||
## The Zones tab
|
||||
|
||||
**Level → Environment zones** opens the Environment panel on this tab.
|
||||
|
||||
### Fog preview
|
||||
|
||||
| Option | What it does |
|
||||
|---|---|
|
||||
| **Live fog in the viewport** | Draws the game's fog in the 3D view: geometry fades to the fog colour and everything beyond the fog end disappears, just like in the game. Also **View → Fog preview**. |
|
||||
| **Zone** | Whose fog is shown: **Camera (nearest zone area)** guesses the zone from where the camera looks (nearest teleport target or the player start), **Start zone**, or **Selected zone only**. A selected zone is always previewed. |
|
||||
| **Detail** | The game's detail setting **Minimum**, **Medium** or **Maximum**: the fog distances are interpolated between the Min and Max pairs of the zone. |
|
||||
|
||||
The line below shows which zone is previewed and its fog distances in cells. The distances are
|
||||
measured from the point the camera orbits around (the game camera follows the llama a few cells
|
||||
behind), so orbiting shows the "visible bubble" around that point. When you zoom far out for an
|
||||
overview, the preview pauses and says *Zoom in to see the fog of …*.
|
||||
|
||||

|
||||
|
||||
### Zone list
|
||||
|
||||
The list shows the start zone first (*Start zone (level default)*), then every other zone with a
|
||||
swatch of its fog colour, its trigger → target, the fog end distance and the music track.
|
||||
Clicking selects the zone (also in the viewport and the Inspector), double-clicking frames it.
|
||||
|
||||
| Button | What it does |
|
||||
|---|---|
|
||||
| **+ Teleport** | Starts the **Zones** tool: click the trigger cell, then the arrival point. |
|
||||
| **+ Environment** | Adds a zone that only switches fog, colours and music, at the cell the camera looks at. |
|
||||
| delete | Deletes the selected zones. |
|
||||
| frame | Frames the selection in the viewport. |
|
||||
|
||||
New zones copy the environment of the start zone, so they look the same until you change them.
|
||||
|
||||
## Environment zone section
|
||||
|
||||
Selecting a zone shows the **Environment zone** section in the Inspector. Its header has
|
||||
**Frame**, **Make start zone** and **Duplicate** (a copy one cell east). Raw fields whose meaning
|
||||
is unknown stay in the generic properties below the section.
|
||||
|
||||
### Trigger
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Cell X**, **Cell Z (row)** | The trigger cell. It needs an exit floor (material 16) or a door object, otherwise the teleport never fires. |
|
||||
| **Cell Y (height)** | The height of the trigger, for stacked zones in one cell. |
|
||||
| **Height test** | When the zone matches: *player y ≤ cell Y*, *player y ≤ cell Y − 1* or *player y ≤ cell Y + 1 (no step)*. The lowest matching zone of the cell wins. |
|
||||
|
||||
For the start zone this part only explains that the trigger cell is not used.
|
||||
|
||||
### Teleport target
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Move the player here** | On: the player is moved to the target. Off: only fog, colours and music change. |
|
||||
| **Target X / Y / Z** | Arrival point in cells. |
|
||||
| **Facing (°)** | Direction the player looks after arriving: 0 = +z (down the grid), 90 = +x (east). |
|
||||
| **Step forward** | Cells the player is pushed along the facing after the teleport, so they do not stand on the exit floor again. Not used with the height test *Y + 1*. |
|
||||
|
||||
### Fog and draw distance
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Mode** | *0 – no fog*, *1 – darkness, light around the player (radius = fog start…end)*, *2 – fog (table)*, *3 – fog (vertex, most levels)*. No original level uses mode 1. |
|
||||
| fog ramp bar | Shows the fog band from start to end in the zone colour. |
|
||||
| **Draw distance** | Draw distance in cells at detail Min, Medium and **Max**. Beyond it nothing is drawn. |
|
||||
| **Start (Min)**, **End (Min)** | Fog start and end at detail Minimum. |
|
||||
| **Start (Max)**, **End (Max)** | Fog start and end at detail Maximum. If the Max start is not above the Min start, the game uses 1.5 × the Min pair. |
|
||||
| **Fog / sky colour** | The colour everything fades to; also the backdrop colour behind the sky. |
|
||||
| **Ambient (objects)** | Added to the light of all object models in this zone. Tiles are not affected – they use their vertex colours. |
|
||||
|
||||
Colour pickers update the viewport live while you pick; the whole pick is one undo step.
|
||||
|
||||
> **Tip:** the original levels end their fog between 7 and 23 cells. Much shorter fog makes a wall
|
||||
> right in front of the player, much longer fog is slow on old PCs and wakes enemies from far away.
|
||||
|
||||
### Music and sky
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Music** | Track started when the zone becomes active (`music/<name>.ASF`): VILLAGE, JUNGLE1, RIVER, CITY, CATACOMB, LAB, BALLOON, KRONK, VICTORY … *0 – (none)* stops the music. |
|
||||
| **Sky model** | The object model drawn as the sky dome (one of the sky models used in this level), or none. |
|
||||
| **Sky yaw** | Turns the sky dome. |
|
||||
|
||||
## Zones tool
|
||||
|
||||
The **Zones** tool (toolbar group *env*, or **+ Teleport**) edits triggers and targets directly in
|
||||
the viewport. The options bar has two modes:
|
||||
|
||||
| Mode | Click / drag |
|
||||
|---|---|
|
||||
| **Target** | Nothing selected: a click on a cell creates a new zone there (its trigger) – then click where the player should arrive. With a zone selected: click or drag places its arrival point; **Shift+drag** turns the facing (22.5° steps). |
|
||||
| **Trigger cell** | Clicks move the selected zone's trigger cell. |
|
||||
|
||||
**[** and **]** turn the facing of the selected zone by 22.5°.
|
||||
|
||||
The viewport shows a ring and a facing arrow at every zone target (layer *Zone targets &
|
||||
facing*). The selected zone additionally gets a filled trigger cell, a box and an arc to its
|
||||
target. The target ring is pickable: clicking it selects the zone.
|
||||
|
||||
## Lights
|
||||
|
||||
The **Lights** tab lists all lights of the level (colour swatch, type, position and radius).
|
||||
|
||||
| Control | What it does |
|
||||
|---|---|
|
||||
| **Preview lights on objects** | Lights every object model in the viewport with the engine's formula (also **View → Light objects (LGHT preview)**). |
|
||||
| **+ Point** | Starts the **Lights** tool. |
|
||||
| **+ Directional** | Adds a directional light (a sun). |
|
||||
| delete | Deletes the selected lights. |
|
||||
|
||||
> **Engine limit:** lights only light **object models** (characters, pickups, props), per vertex:
|
||||
> the zone's ambient colour + all directional lights + the nearest point lights (6 at most). The
|
||||
> level geometry (tiles) is never lit at run time – it keeps its baked vertex colours. To light
|
||||
> tiles, [bake the lighting](#baking-the-lighting) or [paint vertex colours](#painting-vertex-colours).
|
||||
|
||||
Directional lights have no position; the viewport draws them as diamonds with a direction line
|
||||
above the player start. A new level keeps the base level's directional lights (Village: three) and
|
||||
none of its point lights.
|
||||
|
||||

|
||||
|
||||
### Light section
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Light type** | **Directional (sun)**, **Point light** or **Negative point light (darkens)**. Other type numbers are ignored by the engine. |
|
||||
| **Colour** | Light colour (red / green / blue). |
|
||||
| **Intensity** | 1.0 = colour value 128 (the engine doubles it), 2.0 = maximum. |
|
||||
| **Azimuth (°)**, **Elevation (°)** | Directional lights: where the light comes from (0 = from +z, 90 = from +x / east). |
|
||||
| **X**, **Y (height)**, **Z (row)** | Point lights: position in cells. |
|
||||
| **Full radius** | Full strength up to this distance (cells). |
|
||||
| **Falloff radius** | Linear falloff to zero at this distance; nothing beyond. |
|
||||
| **Flicker** | The engine randomly scales the light ×1.5 / ×0.5 every frame (torches, fires). |
|
||||
|
||||
**Frame** and **Duplicate** are in the section header.
|
||||
|
||||
### Lights tool
|
||||
|
||||
Click on the level to place a point light one cell above the surface; drag to set its radius. The
|
||||
options bar chooses a colour preset – **Torch (orange)**, **Fire (red)**, **Lamp (warm white)**,
|
||||
**Magic (cyan)**, **Moon (blue)**, **Glow (green)** – the **Height** above the surface and the
|
||||
**Radius**.
|
||||
|
||||
In the viewport, directional lights are shown as arrows above the level centre and point lights
|
||||
as radius rings (layer *Light gizmos*); a selected point light shows spheres for both radii.
|
||||
|
||||
## Baking the lighting
|
||||
|
||||
The **Lighting** tab (also **Level → Bake lighting…**) computes new vertex colours for the tiles:
|
||||
sun light with real shadows, a sky/ground hemisphere and ambient occlusion in corners. A bake of
|
||||
the whole Village takes under a second and is one undo step.
|
||||
|
||||

|
||||
|
||||
| Group | Options |
|
||||
|---|---|
|
||||
| **Preset** | **Day**, **Dusk**, **Night**, **Cave**, **Flat (no lighting)** fill in the values below (nothing changes until you bake). **Level's current** loads the level's own lighting settings. |
|
||||
| **Sun** | **Azimuth (°)** (0 = from south, 90 = from east), **Elevation (°)**, **Strength**, **Sun colour**. |
|
||||
| **Sky** | **Sky colour** (light from above), **Ground colour** (light from below), **Ambient occlusion** (darkening of corners and crevices), **AO radius** (cells), **Shadow light** (0 = black shadows, 1 = no shadows). |
|
||||
| **Bake** | **All tiles** or **Selected tiles**; **Add point lights (LGHT) to tiles** (the level's point lights also brighten the tiles, with shadows); **Also light brushes (level setting)** – brushes are lit when they are built, from the level's lighting settings, so the bake can store its values there; **Set start zone fog & ambient colour** – takes the preset's fog and ambient colour into the start zone. |
|
||||
| **Display** | **Textured** or **Vertex colours only**; **Paint vertex colours** switches to the brush. |
|
||||
|
||||
Press **Bake lighting**. The status line says how many tiles were baked.
|
||||
|
||||

|
||||
|
||||
> **Note:** the bake reproduces the look of LlamaMod's level builder, not the hand-tuned original
|
||||
> lighting of Argonaut. Bake **Selected tiles** if you only want to relight a part of an original
|
||||
> level.
|
||||
|
||||
## Painting vertex colours
|
||||
|
||||
The **Paint vertex colours** tool (**V**) is a brush for the vertex colours of tiles – darken a
|
||||
corner, warm up a fireplace, add a glow under a lamp. Every stroke is one undo step.
|
||||
|
||||

|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| Mode | **Paint** (blend towards the colour), **Lighten**, **Darken**, **Smooth** (evens out neighbouring vertices). |
|
||||
| colour | The paint colour. **Ctrl+click** on the level picks a colour. |
|
||||
| **Bright** | Brightness: 1.0 = the texture's own colour, 2.0 = maximum (the engine doubles vertex colours). |
|
||||
| **Radius** | Brush radius in cells (0.1–16, default 1.5). |
|
||||
| **Str.** | Strength per dab (0.01–1, default 0.5). |
|
||||
| Falloff | **Smooth**, **Linear** or **Constant** towards the brush edge. |
|
||||
| **Selection only** | Only paint the selected tiles. |
|
||||
|
||||
> **Tip:** tiles that share a model still have their own vertex colours, so painting never
|
||||
> changes other tiles.
|
||||
|
||||
## View options
|
||||
|
||||
| Menu item | Effect |
|
||||
|---|---|
|
||||
| **View → Fog preview** | Live fog of the zone (see [Fog preview](#fog-preview)). |
|
||||
| **View → Light objects (LGHT preview)** | Engine lighting on object models. |
|
||||
| **View → Vertex colours only** (**Shift+V**) | Shows only the baked/painted vertex colours, without textures – useful to judge the lighting. |
|
||||
|
||||
## Environment checks
|
||||
|
||||
**Level → Check for problems** and every build also check the environment:
|
||||
|
||||
| Severity | Problem |
|
||||
|---|---|
|
||||
| warning | No start zone (the level starts without its fog, colours and music), or several start zones (the last one wins). |
|
||||
| warning | Fog ends after less than 3 cells even at detail Maximum, or the draw distance is above 30 cells. |
|
||||
| warning | Fog start is not before fog end. |
|
||||
| warning | A trigger cell is outside the grid (never entered). |
|
||||
| error | A teleport target is outside the grid. |
|
||||
| info | No exit floor (material 16) or door object in a trigger cell – the teleport only fires on an exit floor. |
|
||||
| warning | Tiles with flat grey (unlit) or completely black vertex colours – bake the lighting. |
|
||||
| warning / info | Point lights with falloff radius 0 or smaller than the full radius, black lights, light types the engine ignores. |
|
||||
|
||||
Double-click a problem to select the zone or light. The visibility checks are described in
|
||||
[Visibility regions](13-visibility.md).
|
||||
@@ -0,0 +1,114 @@
|
||||
# Visibility regions
|
||||
|
||||
The game was written for PCs of the year 2000. To keep the frame rate up it does not draw the
|
||||
whole level all the time: the level grid is divided into up to **32 visibility regions**, and for
|
||||
each region a *mask* says which regions can be seen from there. In the Village, for example, the
|
||||
inside of a house is not drawn while you stand outside.
|
||||
|
||||
New levels start with one region where everything is visible – fine for small levels. For big
|
||||
levels, or when you change an original level so that new parts become visible, you edit the
|
||||
regions here.
|
||||
|
||||
## How the engine decides what to draw
|
||||
|
||||
1. The game takes the grid cell the **camera** is in and looks up that cell's region.
|
||||
2. The region's **mask** has one bit per region. Tiles and objects in cells whose region bit is
|
||||
set are drawn; all others are skipped.
|
||||
3. A mask of **0** means "draw everything". When the camera is **outside the grid**, everything
|
||||
is drawn as well.
|
||||
|
||||
So a row in the mask table answers "standing here, what do I see?". A region must always see
|
||||
itself – otherwise the ground under the llama and the llama itself would vanish.
|
||||
|
||||
> **Note:** it is the camera's cell that counts, not the llama's. The camera hangs a few cells
|
||||
> behind the player, so give neighbouring regions some overlap.
|
||||
|
||||
## Visibility panel
|
||||
|
||||
**Level → Visibility regions** opens the **Visibility** panel (right dock).
|
||||
|
||||

|
||||
|
||||
### Mask matrix
|
||||
|
||||
A 32 × 32 grid of check cells: the **row** is the region the camera is in, the **column** is the
|
||||
region that is drawn (header *cam↓ draw→*). Click a cell to toggle it, drag to paint several.
|
||||
Regions that no cell uses are dimmed. Clicking a row label picks that region (for the preview and
|
||||
the region brush). A row without any bit means "everything" – the engine rule above.
|
||||
|
||||
Hovering a row shows how many cells the region has, its own triangles and how many triangles the
|
||||
game draws with the camera there.
|
||||
|
||||
### Masks
|
||||
|
||||
| Control | What it does |
|
||||
|---|---|
|
||||
| **Symmetric** | While on, toggling *A sees B* also sets *B sees A*. |
|
||||
| **All visible** | Every region sees every region. |
|
||||
| **Self only** | Every region sees only itself (a starting point for hand-made masks). |
|
||||
| **Make symmetric** | If A sees B, B now also sees A. |
|
||||
| **Auto-generate…** | Computes regions and masks from the level layout (see below). |
|
||||
| **Paint regions** | Starts the region brush in the viewport. |
|
||||
|
||||
### Preview
|
||||
|
||||
**Show** hides in the viewport what the game would not draw:
|
||||
|
||||
| Setting | Shows |
|
||||
|---|---|
|
||||
| **Off (draw everything)** | The normal editor view. |
|
||||
| **Follow the camera** | What the game draws for the region the editor camera is in – fly around and watch parts appear and disappear. |
|
||||
| **From region n** | What the game draws for a camera in region *n*. |
|
||||
|
||||
The preview hides tiles and objects through the editor's hidden flags and restores exactly the
|
||||
items it hid; things you hid yourself stay hidden. While it is active they show as hidden in the
|
||||
Outliner.
|
||||
|
||||

|
||||
|
||||
### Statistics
|
||||
|
||||
The bottom of the panel shows how many regions are in use and the triangles drawn per camera
|
||||
region (maximum and mean). A warning appears when one region draws a lot – the original levels
|
||||
stay well below 30 000 triangles.
|
||||
|
||||
## Auto-generate
|
||||
|
||||
**Auto-generate…** opens *Auto-generate visibility regions*:
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Layout** | **One region, everything visible**; **Rectangular blocks, visible within a distance**; **Connected areas (islands / rooms), visible within a distance** (default – flood-fills connected floors, at most 32 areas). |
|
||||
| **Visible within (cells)** | Regions closer than this see each other. The fog end distance of the level is a good value (default 12). |
|
||||
|
||||
It replaces the region of every cell and all masks in one undo step. The result line names the
|
||||
highest number of triangles drawn from one region; if it is heavy for the original engine it
|
||||
suggests a smaller distance or more, smaller areas.
|
||||
|
||||
> **Tip:** more regions means less to draw, but areas can pop in when the camera crosses a
|
||||
> border. Always check the result with **Follow the camera** and in a play-test.
|
||||
|
||||
## Paint regions tool
|
||||
|
||||
The **Paint regions** tool sets the region of grid cells with a square brush. It switches the
|
||||
*Visibility regions* layer on, which colours every cell by its region.
|
||||
|
||||
| Option | Meaning |
|
||||
|---|---|
|
||||
| **Region** | The region to paint (colour swatches, Region 0–31). |
|
||||
| **Brush** | 1 × 1, 3 × 3, 5 × 5, 9 × 9 or 17 × 17 cells. |
|
||||
| **Ctrl+click** | Picks the region of a cell. |
|
||||
|
||||
The masks are edited in the Visibility panel. Cells added by growing the grid get region 0.
|
||||
|
||||
## Visibility checks
|
||||
|
||||
Building and **Level → Check for problems** report:
|
||||
|
||||
* **error** – the player start is in a region whose mask does not include the region itself (the
|
||||
ground and the llama would be invisible);
|
||||
* **warning** – a region whose geometry is never visible from any region;
|
||||
* **info** – a region that draws more than 30 000 triangles (heavy for the original engine; the
|
||||
fog distance limits it further).
|
||||
|
||||
The Village (96 × 96 cells) uses 22 of the 32 regions.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Level settings
|
||||
|
||||
Every level has one set of global settings: its name, the TestLevel chapter it goes into, the
|
||||
size of the grid, the death plane and a few engine flags. You edit them in the **Level settings**
|
||||
dialog; all values are also visible in the Inspector.
|
||||
|
||||
## Opening the settings
|
||||
|
||||
* **Level → Level settings…** opens the dialog.
|
||||
* The **Level settings** node at the top of the Outliner selects the settings, so the Inspector
|
||||
shows them as normal properties (including the lighting values used for brushes, see
|
||||
[below](#settings-in-the-inspector)).
|
||||
|
||||
Clicking **OK** applies all changes as one undo step called *Level settings*; **Cancel** changes
|
||||
nothing.
|
||||
|
||||

|
||||
|
||||
## Level
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Name** | Shown in LlamaMod's mod list and on the loading screen. |
|
||||
| **Author** | Your name, shown in LlamaMod. |
|
||||
| **Description** | A few sentences for the mod list. |
|
||||
| **Project** | *new level* or *changes to an original level* (read only). |
|
||||
| **Base level** | The original level the project is built on – it provides the object code, textures, sounds, sky and music (read only). |
|
||||
| **TestLevel chapter** | New levels only: the chapter of world 9 (TestLevel, 1–49) the level replaces when its mod is on. |
|
||||
|
||||
Below the chapter field the dialog lists which chapters other level projects in your `levels`
|
||||
folder already use, so you can pick a free one. Each level needs its own chapter; chapter 1 is
|
||||
also used by LlamaMod's Test World mod. Players can change the chapter later in the level mod's
|
||||
options in LlamaMod (see [Sharing levels](17-sharing.md)).
|
||||
|
||||
## Base level
|
||||
|
||||
The base level is chosen when you create a level (**File → New level…**) and cannot be changed
|
||||
afterwards, because the project stores only the differences to it. It decides:
|
||||
|
||||
* which **object types** you can place – only types whose code is in the base level exist
|
||||
(a Llama, coins, the enemies of that world …);
|
||||
* the **textures** you start with, the **sky** models, sounds, the default fog and music (its start
|
||||
zone) and the sun (its directional lights);
|
||||
* the engine data layout (the read-only feature flags below).
|
||||
|
||||
For new levels the default base is Village chapter 1, which has the widest choice of objects.
|
||||
|
||||
## Grid
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Width (cells, x)** | Columns. Growing adds cells in the east. |
|
||||
| **Height (cells, z)** | Rows. Growing adds cells at the far end (higher z). |
|
||||
|
||||
The note shows the current size and the minimum the content needs – you cannot shrink the grid
|
||||
below what the level uses. New cells get visibility region 0 (see
|
||||
[Visibility regions](13-visibility.md)).
|
||||
|
||||
> **Engine limit:** tiles, objects and teleport targets must stay inside the grid. Collision is
|
||||
> looked up per grid cell, so geometry outside it has no collision.
|
||||
|
||||
## Death plane
|
||||
|
||||
The death plane is an invisible floor with collision material **30**: touching it, or falling
|
||||
below it, costs the llama a life (it respawns at the last checkpoint).
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Height** | Height of all death planes of the level. Changing it moves the death-plane and sea brushes and, in original levels, the "no floor" tiles (material 30) together. |
|
||||
| **Add a death plane over the whole grid** | Only shown when the level has none: adds one death-plane brush covering the grid. |
|
||||
|
||||
The note lists the death planes found (brushes and no-floor tiles). **Geometry → Death plane
|
||||
height…** does the same from the Geometry menu.
|
||||
|
||||
## Feature flags
|
||||
|
||||
The *WFPC* value of the level is a set of engine flags, shown as check boxes with their hex
|
||||
value:
|
||||
|
||||
| Flag | Meaning | Editable |
|
||||
|---|---|---|
|
||||
| `0x00000010` | MAP has a path buffer size (block 14) | no (layout) |
|
||||
| `0x00000100` | STPC has an extra model block | no (layout) |
|
||||
| `0x00000800` | Fog flag of the renderer | yes |
|
||||
| `0x00010000` | Tile swaps (doors / bridges) | no (layout) |
|
||||
| `0x00080000` | Script flag (read by object scripts) | yes |
|
||||
| `0x00100000` | TRPS chunk has extra entries | no (layout) |
|
||||
| `0x00200000` | MAP has a path block | no (layout) |
|
||||
| `0x04000000` | Path entries with an extra word | no (layout) |
|
||||
| `0x08000000` | Collision materials 17/18 are ignored | yes |
|
||||
| `0x10000000` | Two vertex colour pointer tables (light states) | no (layout) |
|
||||
|
||||
Layout flags change how the level data is stored and are fixed by the base level, so they are
|
||||
greyed out. Set bits whose meaning is unknown are listed as *(unknown)* – keep them unless you
|
||||
know better.
|
||||
|
||||
## Objects
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| **Strat pool extra** | Slots for objects = this value + 30. The pool also has to hold objects that are spawned during play (projectiles, effects). Raise it if you place many more objects than the base level had. |
|
||||
|
||||
## Settings in the Inspector
|
||||
|
||||
With the **Level settings** node selected, the Inspector shows the same values as properties,
|
||||
grouped into *Level*, *Grid*, *Objects*, *Lighting* and *Raw*. The **Lighting** group holds the
|
||||
lighting that brushes and meshes get when they are built: texture rotation, sun azimuth,
|
||||
elevation, strength and colour, sky and ground light, ambient occlusion, AO radius and shadow.
|
||||
The **Lighting** tab of the Environment panel can fill these in for you (option *Also light
|
||||
brushes* when baking, see [Baking the lighting](12-environment.md#baking-the-lighting)).
|
||||
|
||||

|
||||
@@ -0,0 +1,100 @@
|
||||
# Building, problems and play-testing
|
||||
|
||||
Before the game can load your level, the editor **builds** it: brushes and meshes become tiles,
|
||||
textures are packed, objects and waypoints are written, and everything is checked. Building is
|
||||
fast (a few seconds) and happens in the background, so you can keep working.
|
||||
|
||||
## Check for problems
|
||||
|
||||
**Level → Check for problems** runs all checks without building. The results appear in the
|
||||
**Problems** panel:
|
||||
|
||||

|
||||
|
||||
* **Errors** (red) would break the level. They block **Build** and **Play** until you fix them.
|
||||
* **Warnings** (yellow) are things that probably do not work as you expect.
|
||||
* **Info** (blue) are hints.
|
||||
|
||||
Double-click a message to select the item it is about (and frame it with **F**). The button in
|
||||
the panel's toolbar validates again without building.
|
||||
|
||||
### What is checked
|
||||
|
||||
| Area | Examples | Details |
|
||||
|---|---|---|
|
||||
| Level | no player start (error), several player starts, no exit in a new level, no geometry | [Objects](09-objects.md#object-checks) |
|
||||
| Geometry | tiles outside the grid, tile models over 8000 vertices, overlapping identical tiles, no floor under the player start, no exit floor (16) in the door's cell, small gaps between floors | [Building geometry](06-geometry.md#geometry-checks) |
|
||||
| Objects | wrong parameter counts, values out of range, missing waypoints, impossible exit targets | [Objects](09-objects.md#object-checks) |
|
||||
| Waypoints | chains not stored in one piece (with an automatic repair) | [Waypoints](10-waypoints.md#waypoint-checks) |
|
||||
| Environment | fog too short or too long, missing start zone, teleport targets outside the grid, black or ignored lights | [Environment](12-environment.md#environment-checks) |
|
||||
| Visibility | the player start in a region that does not draw itself, regions that are never drawn | [Visibility regions](13-visibility.md#visibility-checks) |
|
||||
| Textures | more than 127 texture pages, textures on missing pages | [Textures](08-textures.md#limits) |
|
||||
|
||||
## Build
|
||||
|
||||
**Level → Build** (**Ctrl+B**, toolbar **Build**) checks and builds the level. When it is done the
|
||||
Problems panel shows **Build OK** with the numbers of tiles (and how many came from brushes),
|
||||
objects and waypoints, the size of the level file and the time it took – plus any warnings. The
|
||||
status bar keeps the result of the last build; click it to open the Problems panel.
|
||||
|
||||

|
||||
|
||||
**File → Export level WAD…** builds the level and saves the game file (`.wad`) wherever you like
|
||||
– for your own experiments; to play or share a level you do not need it.
|
||||
|
||||
## Play-testing
|
||||
|
||||
**Level → Play** (**F5**, toolbar **Play**) does everything in one go:
|
||||
|
||||
1. builds the level,
|
||||
2. installs it in LlamaMod's `levels` folder as a level mod (next to the mods you have switched
|
||||
on),
|
||||
3. prepares the play-test save slot (unlocked up to your level),
|
||||
4. starts the game **directly in the level** – no logos, no menus, no map.
|
||||
|
||||

|
||||
|
||||
In the game, press **Escape** to quit straight back to the editor. When the game has ended,
|
||||
LlamaMod switches your normal mod selection back on; the level itself stays installed.
|
||||
|
||||
### Play from the camera position
|
||||
|
||||
**Level → Play from camera position** (**Shift+F5**) starts the llama on the ground in the middle
|
||||
of the view, facing the way the camera looks. Point the view at the spot you want to test – a
|
||||
difficult jump, the end of a parkour – and press **Shift+F5**.
|
||||
|
||||

|
||||
|
||||
The editor checks that there is walkable **collision** at that point: many things that look solid
|
||||
(tree crowns, roofs, decoration) have none. If there is no floor nearby, it tells you instead of
|
||||
dropping the llama into the void. The original level's opening fly-by is skipped in this mode.
|
||||
|
||||
### Play-test options
|
||||
|
||||
| Option (Level menu) | Default | Meaning |
|
||||
|---|---|---|
|
||||
| **Play boots straight into the level** | on | Off: the game starts at the main menu with the map cursor on your level (choose *Spiel starten* → slot → Enter on the map); groove.exe is not changed. |
|
||||
| **Escape quits the play-test** | on | In a play-test the pause key ends the game at once. Off: Escape opens the normal pause menu. |
|
||||
| Play-test save slot (**Edit → Preferences**) | 3 | The slot the game plays with; it is backed up before it is changed. |
|
||||
|
||||
> **Note:** Booting into the level uses the **Boot to level** mod, which adds code to LlamaMod's
|
||||
> private copy of groove.exe. Some antivirus programs warn about such files – see
|
||||
> [Troubleshooting](20-troubleshooting.md).
|
||||
|
||||
### When something goes wrong
|
||||
|
||||
| Message or symptom | What to do |
|
||||
|---|---|
|
||||
| "The game is still running" | The level files cannot be replaced while the game runs. Click **Quit game and play** to close it and start the play-test, or quit it yourself. |
|
||||
| The llama falls through the floor | Look at the collision (**C**); give the floor collision (the brush's collision faces, or a collision material other than 30). |
|
||||
| The level door does nothing | The door needs **exit floor (16)** in its own cell – use the **Exit** setup of the Objects panel. |
|
||||
| The game crashes while loading | Run **Check for problems** and fix all errors; keep everything inside the grid; only one player start. |
|
||||
| Objects are missing in the game | Some objects only appear after an event or a cut-scene; also check the visibility regions. |
|
||||
|
||||
More in [Troubleshooting and FAQ](20-troubleshooting.md).
|
||||
|
||||
## Playing without the editor
|
||||
|
||||
The level is now a mod in LlamaMod's **Levels** category. To play it the normal way, tick it in
|
||||
LlamaMod, click **Apply** and **Play**. New levels are on the world-9 (TestLevel) map – unlock
|
||||
it in **Save games → Unlock TestLevel (world 9)**; edited original levels replace their chapter.
|
||||
@@ -0,0 +1,106 @@
|
||||
# Editing original levels
|
||||
|
||||
Besides building new levels you can change the game's own 31 levels: add coins and checkpoints,
|
||||
move platforms, change the fog and music, open up new paths. Your project stores only the
|
||||
changes; the original files on the CD and in LlamaMod's game copy are never modified.
|
||||
|
||||
## Opening an original level
|
||||
|
||||
**File → Open original level…** (**Ctrl+Shift+O**, or **Open original level** on the start page)
|
||||
shows every level of the CD by name, with its loading picture as a preview:
|
||||
|
||||
* *Village – Chapter 1* … *Lab – Chapter 5*, sorted by world and chapter. The worlds are Village,
|
||||
Jungle at Night, River, Jungle by Day, Mountain, City, Catacombs and Lab.
|
||||
* Chapters marked *(unused)* exist on the CD but are not reachable from the world map.
|
||||
* *Other – …* entries are the front-end and demo files (menus, attract demo); they are listed for
|
||||
completeness.
|
||||
|
||||
Pick a level and click **Open**. Loading takes a moment; the level appears exactly as on the CD.
|
||||
|
||||

|
||||
|
||||
> **Tip:** you can also start the editor straight into a level from the command line:
|
||||
> `LlamaMod --editor t1l1m001` (the file name of the level: t1 l*world* m*chapter*).
|
||||
|
||||
## What you can change
|
||||
|
||||
Everything the editor shows can be edited in an original level, with the same tools as in a new
|
||||
level:
|
||||
|
||||
* **objects** – move, turn, delete, add any type of this level, change parameters
|
||||
([Objects](09-objects.md));
|
||||
* **waypoint chains** of enemies, cameras and respawn points ([Waypoints and paths](10-waypoints.md));
|
||||
* **tiles** – move, turn, paint with other tile models, repaint textures, paint collision
|
||||
([Building geometry](06-geometry.md));
|
||||
* new **brushes** and imported **meshes** on top of the original geometry;
|
||||
* **zones**, fog, music, **lights**, vertex colours and **visibility regions**
|
||||
([Environment](12-environment.md), [Visibility regions](13-visibility.md));
|
||||
* **textures** – import new ones or replace pixels ([Textures](08-textures.md)).
|
||||
|
||||
The base level of an edited original is the level itself, so all object types of that level are
|
||||
available.
|
||||
|
||||
## The project stores only differences
|
||||
|
||||
When you save, the `.llamalevel` file contains only what you changed compared to the original
|
||||
level, plus imported meshes and textures and a thumbnail. Projects are usually a few kilobytes
|
||||
and contain no game data, so you may share them freely.
|
||||
|
||||
Building is reproducible: the same project and the same CD always give the same level file, and
|
||||
an unchanged project builds a file that is byte-for-byte identical to the original.
|
||||
|
||||
## Keep tile numbers stable
|
||||
|
||||
Some object scripts address tiles **by their number** in the level, for example doors or
|
||||
bridges that swap their model. Deleting an original tile shifts the numbers of all tiles after
|
||||
it, and such a script may then move the wrong tile.
|
||||
|
||||
* Prefer **moving** an unwanted tile out of the way (for example below the ground) or
|
||||
**painting another model** onto it with the Tiles tool – painting onto a tile at the same
|
||||
height replaces its model instead of adding a tile, so the numbering stays.
|
||||
* New tiles are added at the end and never shift existing numbers.
|
||||
|
||||
> **Note:** **Edit → Hide selection** (**H**) only hides things in the editor's viewport. Hidden
|
||||
> tiles and objects are still built into the level and appear in the game.
|
||||
|
||||
## Playing your changes
|
||||
|
||||
**Play** (**F5**) builds the level, installs it as a LlamaMod mod and starts the game directly in
|
||||
the changed chapter. **Play from camera position** (**Shift+F5**) puts the llama on the ground in
|
||||
the middle of your view. See [Building and play-testing](15-build-play.md).
|
||||
|
||||
While the level mod is enabled in LlamaMod, your version **replaces that chapter** of the game:
|
||||
you reach it on the world map as usual, and it uses your save game's progress.
|
||||
|
||||
> **Note:** with **Play from camera position** the level's intro fly-by is skipped – the original
|
||||
> cut-scene camera is tied to the original start position.
|
||||
|
||||
## Conflicts with other mods
|
||||
|
||||
Only one mod can provide a level file. If two enabled mods change the same original level – for
|
||||
example two edited versions of Village chapter 1 – LlamaMod stops applying with a message that
|
||||
names the file. Switch one of them off.
|
||||
|
||||
Mods that work on *all* levels are applied after level projects and include your changes:
|
||||
**Mirror mode**, the **Randomizer**, **Draw distance** and the **Debug wireframe** (see
|
||||
[LlamaMod mods](18-mods.md)).
|
||||
|
||||
## Known oddities
|
||||
|
||||
* **Exit floor check:** in 8 original levels **Level → Check for problems** reports that the
|
||||
LevelDoor has no exit floor (material 16) in its cell. The original exit floors decode one cell
|
||||
off the door (for example, door cell 42,49 and floor at 43,48 in the Village). The exits work
|
||||
in the game – ignore this message for original doors. Exits you build yourself are checked
|
||||
correctly.
|
||||
* **Snap to floor** on original levels uses the same collision data, so objects may occasionally
|
||||
land a little off near those exit floors.
|
||||
* **Environment zones** of original levels are mostly house doors: their trigger cells hold exit
|
||||
floors. Moving a door without moving its zone breaks the teleport (see
|
||||
[How the game uses zones](12-environment.md#how-the-game-uses-zones)).
|
||||
* **Coins near the start** of Village chapter 1 are not drawn at the very beginning, also in the
|
||||
unmodified game, so changes there are hard to see right after loading.
|
||||
|
||||
## Tutorial
|
||||
|
||||
[Tutorial: Edit an original level](tutorial-original-level.md) walks through a complete example:
|
||||
moving coins, adding a checkpoint and changing the music of Village chapter 1.
|
||||
@@ -0,0 +1,69 @@
|
||||
# Sharing levels
|
||||
|
||||
A level project is a single `.llamalevel` file. It contains your changes, the meshes and textures
|
||||
you imported and a thumbnail – **no game data** – and is usually only a few kilobytes (more if
|
||||
you imported large textures or models). Everyone who has the game can play it: LlamaMod builds
|
||||
the level from *their* copy of the CD.
|
||||
|
||||
## Sending a level
|
||||
|
||||
1. **File → Save** (**Ctrl+S**). By default projects are saved in LlamaMod's `levels` folder
|
||||
(inside the data folder, see [Installing LlamaMod](02-installing.md#the-data-folder)).
|
||||
2. Give the level a good name, author and description in
|
||||
[Level settings](14-level-settings.md) – LlamaMod shows them on the mod card.
|
||||
3. Send the `.llamalevel` file: forum post, Discord, e-mail, a download link.
|
||||
|
||||
> **Tip:** Save once more just before you share: the thumbnail is taken from the current view
|
||||
> and becomes the loading picture in the game. Frame something nice first.
|
||||
|
||||
## Installing a level you received
|
||||
|
||||
Any of these works:
|
||||
|
||||
* **Copy the file into the `levels` folder** of LlamaMod's data folder (**Settings → Data folder
|
||||
→ Open folder**, then `levels`) and restart LlamaMod. The level appears in the **Levels**
|
||||
category of the **Mods** tab.
|
||||
* **Open it in the editor** (**File → Open project**) and press **F5**: the play-test installs it
|
||||
in the `levels` folder and starts it.
|
||||
* From the command line: `LlamaMod --import-level <file.llamalevel>`.
|
||||
|
||||
Then tick the level in LlamaMod, click **Apply** and **▶ Play**.
|
||||
|
||||
## Where the level appears in the game
|
||||
|
||||
| Project | In the game |
|
||||
|---|---|
|
||||
| **New level** | on the world-9 map as **TestLevel – chapter *n*** (its own loading picture with the level name). Unlock world 9 in **Save games → Unlock TestLevel (world 9)**, or play it with the editor's **F5**. |
|
||||
| **Edited original level** | replaces that chapter (for example Village chapter 3) while the mod is on. Switch the mod off to get the original back. |
|
||||
|
||||
## Chapters and conflicts
|
||||
|
||||
Each new level occupies one of the 49 TestLevel chapters. The editor picks a free chapter for
|
||||
new projects, but levels from different people may use the same one. If two active level mods
|
||||
use the same chapter – or two mods change the same original level – LlamaMod stops applying and
|
||||
names the files involved. Fix it in the mod's options: every new-level mod has a
|
||||
**TestLevel chapter** option (1–49).
|
||||
|
||||
> **Note:** Chapter 1 of the TestLevel is also used by the built-in **Test World** mod. Prefer
|
||||
> chapters 2 and above for your own levels.
|
||||
|
||||
## Updating a shared level
|
||||
|
||||
Change the project and save it under the **same file name**; the receiver replaces the old file.
|
||||
LlamaMod notices the change (it keys every level by the file's contents) and rebuilds it on the
|
||||
next **Apply**.
|
||||
|
||||
## Sharing parts of a level
|
||||
|
||||
* **Prefabs** – groups of objects you saved (**Tools → Save selection as prefab…**) live in the
|
||||
data folder's `editor/prefabs` folder and can be copied to another computer.
|
||||
* **Library assets** – geometry saved with **Geometry → Save selection to library…** is a
|
||||
`.llamamesh` file in the `library` folder. Note that library files *do* contain textures from
|
||||
the game, so share them only with people who own it.
|
||||
* **Copy objects (for other levels)** (**Ctrl+Shift+C**) puts objects as text on the clipboard –
|
||||
you can even paste that into a forum post for others to paste into their level.
|
||||
|
||||
## Sharing this manual
|
||||
|
||||
The manual window's **Export** button saves the whole manual as HTML pages or as one HTML file
|
||||
with all pictures, ready to upload or attach to a forum post.
|
||||
@@ -0,0 +1,194 @@
|
||||
# LlamaMod mods
|
||||
|
||||
Besides your own levels, LlamaMod comes with mods that change the game: skip the intro, see
|
||||
further, play mirrored, shuffle the coins, fly a free camera and more. This chapter explains how
|
||||
mods work and lists every built-in mod with its options.
|
||||
|
||||
## Using mods
|
||||
|
||||
1. Open the **Mods** tab in LlamaMod.
|
||||
2. Tick the mods you want. A ticked mod shows its options, each with a short explanation;
|
||||
changed options take effect on the next **Apply**.
|
||||
3. Click **Apply**. LlamaMod builds the changed game files into its private copy – your
|
||||
original files stay untouched. The status bar shows the progress and the time it takes.
|
||||
4. Click **▶ Play**.
|
||||
|
||||
**Restore original** switches all mods off. Applying is refused while the game runs – quit it
|
||||
first.
|
||||
|
||||
* Mods are applied in a fixed order, so they combine: the **Mirror mode** also mirrors the Test
|
||||
World and your levels; the **Debug wireframe** is built on top of everything else.
|
||||
* Built mod files are cached, so switching mods on and off again is quick. **Settings → Clear
|
||||
cache** throws the cache away (it is rebuilt when needed).
|
||||
* Mods marked **modifies groove.exe** add code to the game program of LlamaMod's copy. This is
|
||||
safe, but on Windows some antivirus programs flag the changed file – see
|
||||
[Troubleshooting](20-troubleshooting.md).
|
||||
|
||||

|
||||
|
||||
## Level mods
|
||||
|
||||
Every `.llamalevel` project in the data folder's `levels` folder is a mod in the **Levels**
|
||||
category, named after the level, with its author and description. Mods of new levels have one
|
||||
option:
|
||||
|
||||
| Option | Values | Meaning |
|
||||
|---|---|---|
|
||||
| TestLevel chapter | 1 – 49 | the chapter of world 9 the level occupies; each level needs its own (chapter 1 is also used by the Test World mod) |
|
||||
|
||||
Edited original levels have no options – they replace their chapter. See
|
||||
[Sharing levels](17-sharing.md).
|
||||
|
||||
## Command line
|
||||
|
||||
LlamaMod can be scripted:
|
||||
|
||||
```
|
||||
LlamaMod --mods list all mods with their options
|
||||
LlamaMod --apply fog,mirror --opt fog.distance=400 apply mods with options
|
||||
LlamaMod --apply restore the original game
|
||||
LlamaMod --launch start the game
|
||||
```
|
||||
|
||||
Option values are checked and saved like in the window.
|
||||
|
||||
## Built-in mods
|
||||
|
||||
The following list is generated from the program, so it always matches your LlamaMod version.
|
||||
|
||||
<!-- generated:mods -->
|
||||
### Levels mods
|
||||
|
||||
#### Test World
|
||||
|
||||
Turns the hidden TestLevel (world 9, chapter 1) into a playground island: a gallery of every object in the game, an animal enclosure and a parkour course with checkpoints. To reach it, click "Unlock TestLevel" on the Save games tab.
|
||||
|
||||
*Id* `testworld`
|
||||
|
||||
### Gameplay mods
|
||||
|
||||
#### Boot to level
|
||||
|
||||
Play starts the game straight in the chosen level – no logos, no menus, no world map. The game plays with the chosen save slot (a new game if it is empty). Handy for practising one level.
|
||||
|
||||
*Id* `boot-to-level` · **modifies groove.exe** (see [antivirus warnings](20-troubleshooting.md))
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| World | 1 – 9 | 1 | 1 = Village … 8 = Lab, 9 = TestLevel |
|
||||
| Chapter | 1 – 49 | 1 | Chapter of that world (TestLevel: 1–49). |
|
||||
| Save slot | 1 – 3 | 3 | The save game used for lives and progress. The game also saves into it. |
|
||||
| Skip startup logos | on / off | on | Also skips the logo movies and the title screen. |
|
||||
| Escape quits the game | on / off | off | Escape ends the game at once instead of opening the pause menu. |
|
||||
| Player start | text | (empty) | Leave empty for the level's own start. Advanced: "x, y, z[, angle]" in cells moves the start. |
|
||||
|
||||
#### Intro skip
|
||||
|
||||
Gets you to the main menu faster: skips the logo movies at the start and stops the demo that plays when you wait in the main menu. Can also skip the story movies between chapters.
|
||||
|
||||
*Id* `intro-skip` · **modifies groove.exe** (see [antivirus warnings](20-troubleshooting.md))
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Skip startup logos | on / off | on | The Disney and Argonaut logo movies and the publisher screen. |
|
||||
| Disable attract demo | on / off | on | The game no longer plays a demo after a minute in the main menu. |
|
||||
| Skip story movies | on / off | off | The movies before and after chapters. The credits still play. |
|
||||
|
||||
#### Mirror mode
|
||||
|
||||
Plays every level mirrored left to right, like the mirror mode of racing games. The controls stay the same.
|
||||
|
||||
*Id* `mirror`
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Worlds | text | all | "all", or the numbers of the worlds to mirror, e.g. "1,3" (1 = Village, 9 = TestLevel). |
|
||||
| Readable textures | on / off | off | Flips writing and pictures back so they read normally. Some textures (water edges, paths) then show seams. Off: a true mirror image. |
|
||||
| Mirror object models | on / off | off | Also mirrors the shape of objects such as huts and crates (characters stay as they are). Off: objects are only placed mirrored. |
|
||||
|
||||
#### Practice tools
|
||||
|
||||
Practise hard jumps: press F5 to remember where the llama stands and F8 to jump back there (in the same level; the keys can be changed below). Also adds extra checkpoints along the coin trail of levels that have checkpoints.
|
||||
|
||||
*Id* `practice` · **modifies groove.exe** (see [antivirus warnings](20-troubleshooting.md))
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Save position key | F1, F2, F3, F4, F5, F7, F8, F9, F11, F12, Insert, Delete, Home, End | F5 | Remembers where the llama stands. |
|
||||
| Restore position key | F1, F2, F3, F4, F5, F7, F8, F9, F11, F12, Insert, Delete, Home, End | F8 | Puts the llama back to the remembered place. |
|
||||
| Extra checkpoints | on / off | on | More checkpoints along the coin trail, in levels that already have checkpoints. |
|
||||
| Checkpoint spacing | 4 – 40 | 10 | Distance between two checkpoints in tiles. Smaller = more checkpoints. |
|
||||
|
||||
#### Randomizer
|
||||
|
||||
Moves coins and food (and, if you like, pots and enemies) to other places in each level. Every coin stays reachable, and the way through the level does not change. The same seed always gives the same layout, so friends can play the same one.
|
||||
|
||||
*Id* `randomizer`
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Seed | any text | random | Any word or number. The same seed gives the same layout. |
|
||||
| Coins | on / off | on | Shuffle the coins. |
|
||||
| Health and food | on / off | on | Shuffle food and health pickups. |
|
||||
| Mix coins and food | on / off | on | Coins and food may swap places. Off: coins only trade places with coins, food with food. |
|
||||
| Pots and jars | on / off | off | Shuffle the pots and jars you can smash. |
|
||||
| Enemies | on / off | off | Enemies that stand still swap places with others of the same kind. |
|
||||
|
||||
### Visual mods
|
||||
|
||||
#### Draw distance
|
||||
|
||||
See further in every level: the fog moves back and distant parts of the level stay visible. Objects and enemies also come to life from further away.
|
||||
|
||||
*Id* `fog`
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Draw distance (%) | 50 – 600 | 250 | 100 = like the original, 250 = two and a half times as far. Below 100 the fog gets thicker. |
|
||||
| Fog | Scaled, Off | Scaled | Scaled: the fog fades in further away. Off: no fog – the world ends abruptly at the draw distance. |
|
||||
|
||||
### Cheats & debug mods
|
||||
|
||||
#### Built-in cheats
|
||||
|
||||
Switches on the game's secret cheat codes for you, so you don't have to type the arrow-key sequences in the main menu. Tick the cheats you want.
|
||||
|
||||
*Id* `cheats` · **modifies groove.exe** (see [antivirus warnings](20-troubleshooting.md))
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Infinite health | on / off | on | Hits and falls into water cost no energy, so you never lose a life (code ← → → → ↑ → → ↑). |
|
||||
| Start with 50 collectibles | on / off | off | The pink idol counter starts at 50 in every chapter (code ↓ ← → ↓ ↓ ← → ↓). |
|
||||
| Complete chapter rewards | on / off | off | Finishing a chapter also gives you its collectible and gold coin (code → → ↓ ↓ ↓ ↑ ↓ ↓). |
|
||||
| Start with 500 fruit | on / off | off | The purple fruit counter starts at 500 in every chapter (code ↑ ↓ → ← ← ← ← ↓). |
|
||||
| Full charge meter | on / off | off | The charge bar starts full in every chapter (code ↑ ← ↓ → ↓ ↓ ↑ ↑). |
|
||||
| Write display diagnostics | on / off | off | For graphics problems: the game writes a report of your graphics devices (<computer name>.dispdiag) into the game folder. Same as its hidden -display_diagnostics switch. |
|
||||
|
||||
#### Debug wireframe
|
||||
|
||||
Shows what is normally invisible: the walls and floors the llama collides with (also invisible ones) as coloured lines, and markers for cameras, triggers, exits and checkpoints.
|
||||
|
||||
*Id* `debug-wireframe`
|
||||
|
||||
#### Free camera & noclip
|
||||
|
||||
Press F7 to fly the camera freely around the level: arrow keys move, A/S turn, PgUp/PgDn look up and down, X/Z rise and sink, Shift or Space go faster. Press F9 for noclip: the llama flies through walls (arrow keys, X/Z up and down). Press the key again to switch off (the keys can be changed below).
|
||||
|
||||
*Id* `freecam` · **modifies groove.exe** (see [antivirus warnings](20-troubleshooting.md))
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Free camera key | F1, F2, F3, F4, F5, F7, F8, F9, F11, F12, Insert, Delete, Home, End | F7 | Switches the free camera on and off. |
|
||||
| Noclip key | F1, F2, F3, F4, F5, F7, F8, F9, F11, F12, Insert, Delete, Home, End | F9 | Switches noclip (fly through walls) on and off. |
|
||||
| Pause game during free camera | on / off | on | Enemies and objects freeze while the free camera is on. |
|
||||
| Camera speed | 1 – 32 | 3 | How fast the free camera flies (1 = slow, 32 = very fast). |
|
||||
| Noclip speed | 1 – 32 | 2 | How fast the llama flies in noclip (1 = slow, 32 = very fast). |
|
||||
<!-- /generated:mods -->
|
||||
|
||||
## Pictures
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
@@ -0,0 +1,277 @@
|
||||
# Keyboard, mouse and menu reference
|
||||
|
||||
The tables in this chapter (except the mouse table) are generated from the editor's own list of
|
||||
tools and commands, so they always match your version – including plugins. **Help → Shortcut
|
||||
sheet (printable)…** prints the keys on one page.
|
||||
|
||||
Single keys without **Ctrl** or **Alt** (tool keys, **F**, **H**, **Delete** …) work while the
|
||||
mouse is over the viewport or nothing is being typed; they never fire while a text field has the
|
||||
focus.
|
||||
|
||||
## Mouse
|
||||
|
||||
| Input | Action |
|
||||
|---|---|
|
||||
| Click / **Shift+click** / **Ctrl+click** | select / add / toggle |
|
||||
| Drag in empty space | box selection (**Shift** adds, **Ctrl** removes) |
|
||||
| Double-click | select and frame |
|
||||
| **Right mouse** held + mouse | look around; **W A S D** fly, **Q** / **E** down / up, **Shift** faster, wheel = fly speed |
|
||||
| Mouse wheel | zoom towards the cursor |
|
||||
| **Ctrl+middle** / **Alt+right** drag | zoom |
|
||||
| **Alt+left** drag | orbit |
|
||||
| **Middle** drag | pan (Fusion 360, Unity / Unreal) or orbit (Blender) |
|
||||
| **Shift+middle** drag | orbit (Fusion 360), pan (Blender, Unity / Unreal) |
|
||||
| Double-click **middle** | frame the whole level (Fusion 360) |
|
||||
| View cube: click / drag / house | look from that side / orbit / home view |
|
||||
| **Ctrl** while dragging | invert snapping |
|
||||
| **Esc** while dragging | cancel the drag |
|
||||
|
||||
The middle-button bindings follow the navigation preset (**View → Navigation**, see
|
||||
[Navigation presets](04-navigation.md#navigation-presets)); **Help → Viewport navigation** shows
|
||||
the cheat sheet of the active preset.
|
||||
|
||||
## Keys
|
||||
|
||||
Every tool has its own single key, and no key is used twice (a unit test checks this for the
|
||||
built-in tools and every plugin):
|
||||
|
||||
* **Q W E R** – select, move, rotate, scale (as in most 3D programs)
|
||||
* Geometry: **B** brush, **T** tiles, **K** collision, **M** paint texture (material), **V** paint
|
||||
vertex colours
|
||||
* Objects: **P** place, **O** coin line / arc, **N** waypoint paths (nodes), **J** zones &
|
||||
triggers
|
||||
* Environment: **Z** teleport / environment zones, **U** lights (bulb), **Y** visibility regions
|
||||
* Commands use the other letters (**F** frame, **G** snap, **H** hide, **L** lock, **I**
|
||||
eyedropper, **C** collision view, **X** local space) or **Ctrl** / **Shift** combinations.
|
||||
|
||||
<!-- generated:shortcuts -->
|
||||
### Tools
|
||||
|
||||
| Key | Tool | What it does |
|
||||
|---|---|---|
|
||||
| **B** | Brush | Brush: draw blocks, platforms, ramps, stairs, walls, water … on the ground or on surfaces; drag the handles of a selected brush to resize it |
|
||||
| **E** | Rotate | Rotate: green ring = turn about the vertical axis (everything); red/blue rings turn brushes freely (tiles and objects only turn about the vertical axis) |
|
||||
| **J** | Zones & triggers | Zones & triggers (J): drag the corner handles of box zones and the radius knob of triggers |
|
||||
| **K** | Collision | Collision: paint collision materials (exit floor 16, death 30, …) per polygon or brush face, switch brush faces' collision on/off |
|
||||
| **M** | Paint texture | Click faces to give them the current texture; Shift+click picks a face's texture (eyedropper) |
|
||||
| **N** | Waypoint paths | Waypoint paths (N): select an object, click to add nodes, drag nodes, Del removes |
|
||||
| **O** | Coin line / arc | Coin line / arc (O): two clicks place a line or a circle of coins |
|
||||
| **P** | Place objects | Place objects (P): click to place the palette type on the ground, drag objects to move, drag the knob to rotate |
|
||||
| **Q** | Select | Select: click, Shift+click adds, Ctrl+click toggles, drag for a box |
|
||||
| **R** | Scale | Scale: brushes (floors, boxes, meshes) – drag a gizmo axis or the centre |
|
||||
| **T** | Tiles | Tiles: paint tile models onto grid cells, pick, erase, raise/lower and swap tiles |
|
||||
| **U** | Lights | Place point lights: click to place, drag to set the radius |
|
||||
| **V** | Paint vertex colours | Vertex colour brush for tiles (Ctrl+click picks a colour) |
|
||||
| **W** | Move | Move: drag the gizmo arrows/planes, or drag an object over the ground |
|
||||
| **Y** | Paint regions | Paint visibility regions on grid cells (Ctrl+click picks a region) |
|
||||
| **Z** | Zones | Teleport / environment zones: click a cell to add a zone, click again for its target |
|
||||
|
||||
### Commands with a shortcut
|
||||
|
||||
| Key | Command | Menu |
|
||||
|---|---|---|
|
||||
| **Ctrl+N** | New level | File |
|
||||
| **Ctrl+Shift+O** | Open original level | File |
|
||||
| **Ctrl+O** | Open project | File |
|
||||
| **Ctrl+S** | Save | File |
|
||||
| **Ctrl+Shift+S** | Save as | File |
|
||||
| **Ctrl+W** | Close level | File |
|
||||
| **Ctrl+Q** | Close editor | File |
|
||||
| **Ctrl+Z** | Undo | Edit |
|
||||
| **Ctrl+Y** | Redo | Edit |
|
||||
| **Ctrl+X** | Cut | Edit |
|
||||
| **Ctrl+C** | Copy | Edit |
|
||||
| **Ctrl+V** | Paste | Edit |
|
||||
| **Ctrl+D** | Duplicate | Edit |
|
||||
| **Delete** | Delete | Edit |
|
||||
| **Ctrl+Shift+C** | Copy objects (for other levels) | Edit |
|
||||
| **Ctrl+Shift+V** | Paste objects at view centre | Edit |
|
||||
| **Ctrl+A** | Select all | Edit |
|
||||
| **Ctrl+Shift+A** | Select none | Edit |
|
||||
| **Shift+S** | Select similar | Edit |
|
||||
| **H** | Hide selection | Edit |
|
||||
| **Alt+H** | Show all hidden | Edit |
|
||||
| **L** | Lock selection | Edit |
|
||||
| **I** | Texture eyedropper | Edit |
|
||||
| **Ctrl+,** | Preferences | Edit |
|
||||
| **F** | Frame selection | View |
|
||||
| **Home** | Frame level | View |
|
||||
| **Numpad 5** | Perspective | View → Camera |
|
||||
| **Numpad 7** | Top | View → Camera |
|
||||
| **Numpad 1** | Front | View → Camera |
|
||||
| **Numpad 3** | Side | View → Camera |
|
||||
| **Ctrl+Shift+L** | Look through camera (pilot) | View → Camera |
|
||||
| **X** | Gizmo in local space | View |
|
||||
| **G** | Snap to grid | View |
|
||||
| **C** | Show collision | View |
|
||||
| **Ctrl+Shift+T** | Texture manager | View → Panels |
|
||||
| **Shift+V** | Vertex colours only | View |
|
||||
| **Ctrl+B** | Build | Level |
|
||||
| **F5** | Play | Level |
|
||||
| **Shift+F5** | Play from camera position | Level |
|
||||
| **Ctrl+Shift+I** | Import objects of a world | Level |
|
||||
| **Ctrl+[** | Turn left 90° | Geometry |
|
||||
| **Ctrl+]** | Turn right 90° | Geometry |
|
||||
| **Ctrl+Shift+D** | Array duplicate | Geometry |
|
||||
| **F1** | Manual | Help |
|
||||
| **Shift+F1** | Getting started | Help |
|
||||
| **Ctrl+F1** | Keyboard shortcuts | Help |
|
||||
| **Ctrl+Shift+Z** | Redo | (keyboard only) |
|
||||
<!-- /generated:shortcuts -->
|
||||
|
||||
## Keys inside tools
|
||||
|
||||
| Tool | Keys |
|
||||
|---|---|
|
||||
| Brush | **Enter** type the height, **Esc** cancel, **[** / **]** turn 90°, **Page Up** / **Page Down** raise / lower |
|
||||
| Tiles | **[** / **]** rotation, **Page Up** / **Page Down** height, **Shift+click** pick |
|
||||
| Paint texture | **Shift+click** pick a face's texture |
|
||||
| Collision | **Shift+click** pick a material |
|
||||
| Waypoint paths | **Ctrl+click** insert before, **Backspace** / **Delete** remove a node |
|
||||
| Zones | **Shift+drag** set the facing, **[** / **]** turn |
|
||||
| Paint vertex colours, Paint regions | **Ctrl+click** pick |
|
||||
|
||||
## In the game during a play-test
|
||||
|
||||
| Key | Action |
|
||||
|---|---|
|
||||
| **Escape** | quit straight back to the editor (Level → Escape quits the play-test) |
|
||||
|
||||
## Menu reference
|
||||
|
||||
Every menu command with its shortcut and a short description.
|
||||
|
||||
<!-- generated:menus -->
|
||||
### File menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| New level… | **Ctrl+N** | Create a new level from a template |
|
||||
| Open original level… | **Ctrl+Shift+O** | Edit one of the game's levels |
|
||||
| Open project… | **Ctrl+O** | Open a .llamalevel project |
|
||||
| Save | **Ctrl+S** | Save the project |
|
||||
| Save as… | **Ctrl+Shift+S** | Save the project under a new name |
|
||||
| Close level | **Ctrl+W** | Close the project |
|
||||
| Import mesh (OBJ, glTF)… | | Import an OBJ or glTF model as level geometry (preview, size, textures, collision) |
|
||||
| Import texture… | | Import PNG/JPG images as textures (colour reduction, blend class, packing) |
|
||||
| Export level WAD… | | Build the level and save the game file (.wad) somewhere |
|
||||
| Export selection as OBJ… | | Mesh, UVs, vertex colours, textures (PNG) and collision for Blender |
|
||||
| Close editor | **Ctrl+Q** | Close the editor |
|
||||
|
||||
### Edit menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Undo | **Ctrl+Z** | Undo the last change |
|
||||
| Redo | **Ctrl+Y** | Redo what was undone |
|
||||
| History | | Show all changes; click one to go back to it |
|
||||
| Cut | **Ctrl+X** | Cut the selection |
|
||||
| Copy | **Ctrl+C** | Copy the selection |
|
||||
| Paste | **Ctrl+V** | Paste next to the original |
|
||||
| Duplicate | **Ctrl+D** | Duplicate the selection (one cell east) |
|
||||
| Delete | **Delete** | Delete the selection (waypoints: the chain is relinked) |
|
||||
| Copy objects (for other levels) | **Ctrl+Shift+C** | Copies objects with their waypoints and brushes to the system clipboard (paste into any level) |
|
||||
| Paste objects at view centre | **Ctrl+Shift+V** | |
|
||||
| Select all | **Ctrl+A** | Select everything that is visible |
|
||||
| Select none | **Ctrl+Shift+A** | Clear the selection |
|
||||
| Select similar | **Shift+S** | Objects of the same type / tiles of the same model |
|
||||
| Hide selection | **H** | Hide the selection in the viewport (editor only: it is still built – tiles have Exclude from build in the inspector) |
|
||||
| Show all hidden | **Alt+H** | Show everything that was hidden |
|
||||
| Lock selection | **L** | Locked items stay visible but cannot be clicked in the viewport |
|
||||
| Replace texture pixels… | | Replace the current texture's pixels with an image |
|
||||
| Texture eyedropper | **I** | Pick the texture of a face in the viewport |
|
||||
| Preferences… | **Ctrl+,** | Autosave, play-test save slot, theme |
|
||||
|
||||
### View menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Frame selection | **F** | Frame the selection (F) |
|
||||
| Frame level | **Home** | Show the whole level (Home) |
|
||||
| Navigation → Fusion 360 (on/off) | | Mouse bindings like Fusion 360 |
|
||||
| Navigation → Blender (on/off) | | Mouse bindings like Blender |
|
||||
| Navigation → Unity / Unreal (on/off) | | Mouse bindings like Unity / Unreal |
|
||||
| Camera → Perspective | **Numpad 5** | Back to the perspective view |
|
||||
| Camera → Top | **Numpad 7** | Look straight down (orthographic) |
|
||||
| Camera → Front | **Numpad 1** | Front view (orthographic) |
|
||||
| Camera → Side | **Numpad 3** | Side view (orthographic) |
|
||||
| Navigation → View cube (on/off) | | |
|
||||
| Navigation → Home view | | |
|
||||
| Gizmo in local space (on/off) | **X** | Gizmo axes in world or local space (X) |
|
||||
| Snap to grid (on/off) | **G** | Snap moves and rotations to the grid (G; Ctrl while dragging inverts it) |
|
||||
| Show collision (on/off) | **C** | Show collision polygons coloured by material (C) |
|
||||
| Camera → Look through camera (pilot) (on/off) | **Ctrl+Shift+L** | |
|
||||
| Navigation → Viewport preferences… | | |
|
||||
| Show waypoints of all objects (on/off) | | |
|
||||
| Dark theme (on/off) | | Switch between the light and dark theme |
|
||||
| Show back faces (on/off) | | Draw the back sides of one-sided faces (invisible in the game) hatched instead of hiding them |
|
||||
| Fog preview (on/off) | | Game fog of the zone the camera is in |
|
||||
| Light objects (LGHT preview) (on/off) | | |
|
||||
| Vertex colours only (on/off) | **Shift+V** | Show the baked/painted vertex colours without textures |
|
||||
| Panels → Texture manager | **Ctrl+Shift+T** | Pages, textures, usage and animations |
|
||||
|
||||
### Level menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Level settings… | | Name, chapter, grid size, death plane, feature flags |
|
||||
| Check for problems | | List problems that would break the level (missing start, exits …) |
|
||||
| Build | **Ctrl+B** | Validate the level and build its WAD (in the background) |
|
||||
| Play | **F5** | Build the level, install it as a mod and start the game directly in it (no menus; your mod selection is restored when the game exits) |
|
||||
| Play from camera position | **Shift+F5** | Play-test with the llama standing on the ground point in the middle of the view, facing the camera direction |
|
||||
| Play boots straight into the level (on/off) | | Off: Play starts at the main menu with the map cursor on the level (no change to groove.exe) |
|
||||
| Escape quits the play-test (on/off) | | In a play-test the pause key (Escape) ends the game at once, back to the editor |
|
||||
| Bake lighting… | | |
|
||||
| Environment zones | | |
|
||||
| Visibility regions | | |
|
||||
| Import objects of a world… | **Ctrl+Shift+I** | Copy object types (enemies, pickups, platforms …) of another world into this level |
|
||||
| Rebuild object catalogue | | Scan all levels of the CD again (thumbnails, sizes) |
|
||||
|
||||
### Geometry menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Brush tool | | Draw blocks, platforms, ramps, stairs, walls, water … (B) |
|
||||
| Tiles tool | | Paint, pick, erase, raise and swap tiles (T) |
|
||||
| Collision tool | | Paint collision materials, switch brush faces' collision (K) |
|
||||
| Align → Align West (min X) | | Line the selection up with the last selected item |
|
||||
| Align → Align Centre X | | Line the selection up with the last selected item |
|
||||
| Align → Align East (max X) | | Line the selection up with the last selected item |
|
||||
| Turn left 90° | **Ctrl+[** | |
|
||||
| Turn right 90° | **Ctrl+]** | |
|
||||
| Mirror X (east ↔ west) | | |
|
||||
| Mirror Z (north ↔ south) | | |
|
||||
| Array duplicate… | **Ctrl+Shift+D** | n copies with an offset (and turn) each |
|
||||
| Align → Align Bottom | | Line the selection up with the last selected item |
|
||||
| Align → Align Middle Y | | Line the selection up with the last selected item |
|
||||
| Align → Align Top | | Line the selection up with the last selected item |
|
||||
| Align → Align North (min Z) | | Line the selection up with the last selected item |
|
||||
| Align → Align Centre Z | | Line the selection up with the last selected item |
|
||||
| Align → Align South (max Z) | | Line the selection up with the last selected item |
|
||||
| Grid & snapping… | | Move/angle/scale steps (any value), grid display |
|
||||
| Death plane height… | | |
|
||||
| Re-import mesh… | | Load the selected mesh brush's file again (or another file) and keep its placement |
|
||||
| Save selection to library… | | Tiles, brushes and meshes as a reusable asset (with textures) for any level |
|
||||
| Align → Distribute along X | | |
|
||||
| Align → Distribute along Z | | |
|
||||
|
||||
### Tools menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Object palette | | |
|
||||
| Save selection as prefab… | | |
|
||||
| Repair waypoint chains | | Stores every waypoint chain in one piece (needed by the game) |
|
||||
|
||||
### Help menu
|
||||
|
||||
| Command | Key | What it does |
|
||||
|---|---|---|
|
||||
| Manual | **F1** | The complete user manual: contents, search, tutorials. F1 over a panel, tool or dialog opens the matching chapter |
|
||||
| Export manual as HTML… | | Save the manual as HTML pages (one per chapter) to share it or read it in a browser |
|
||||
| Getting started | **Shift+F1** | A short illustrated guide: from a new level to play-testing and sharing it |
|
||||
| Keyboard shortcuts | **Ctrl+F1** | All keyboard and mouse shortcuts (the complete list is in the manual) |
|
||||
| Viewport navigation | | |
|
||||
| Shortcut sheet (printable)… | | All shortcuts on one page – print it or save it as HTML |
|
||||
| About the level editor | | Version, OpenGL and plugin information |
|
||||
<!-- /generated:menus -->
|
||||
@@ -0,0 +1,118 @@
|
||||
# Troubleshooting and FAQ
|
||||
|
||||
## Setting up and playing
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| "This file is not a CD image (ISO)" | You picked another kind of file. Choose the game's `.iso` file, or use **Folder / CD…** for the CD or a copied folder. |
|
||||
| "The game was not found here" | The folder is not the game CD. Choose the CD drive itself or a folder you copied the whole CD into – it contains a folder named `Setup`. |
|
||||
| "The ISO file is incomplete" | The download or copy of the ISO was interrupted. Copy or download it again. |
|
||||
| "Some game files are damaged" | The CD or ISO copy is faulty. Try another copy, or clean the CD. |
|
||||
| "Not enough free disk space" | The game copy needs about 900 MB. Free up space or choose another **Data folder**. |
|
||||
| The game hangs or its window is gone | Click **■ Quit game** in LlamaMod (the Play button while the game runs). |
|
||||
| "The game crashed" | Switch off the mods you turned on last, or click **Restore original**, and play again. If the original game crashes too, report it with `game.log` (**Settings → Logs**). |
|
||||
| "groove.exe was removed or changed" | Click **Rebuild**; LlamaMod writes it again and then starts the game. On Windows, see [Antivirus warnings](#antivirus-warnings). |
|
||||
|
||||
## The editor
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| "OpenGL 3.3 is not available" or a black viewport | Update the graphics driver. In a virtual machine, switch on 3D acceleration. Without a usable driver the editor can still run with software OpenGL, but slowly. |
|
||||
| The editor is slow in a big level | Hide what you do not need (**H**, or switch layers off), close the Textures window, use the top view for large moves. |
|
||||
| A key does nothing | Single-letter keys do not work while a text field has the focus – click into the viewport first. Some keys are shared by two tools (see [Keys](19-shortcuts.md#keys)); use the toolbar button. |
|
||||
| I lost my changes after a crash | Start the editor again and choose **Recover** – autosave keeps unsaved changes (Edit → Preferences sets how often). |
|
||||
| A panel is gone | **View → Panels** opens it again. |
|
||||
| An object type I want is not in the list | The Objects list shows the base level's types and the ones you imported. Import the type from **Assets → All worlds** ([Importing objects from other worlds](09-objects.md#importing-objects-from-other-worlds)). |
|
||||
|
||||
## Building and play-testing
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| Build or Play is refused | The Problems panel lists errors; fix them first (double-click a message to find the item). |
|
||||
| "The game is still running" | Level files cannot be replaced while the game runs – click **Quit game and play** in the message, or quit the game yourself. |
|
||||
| The llama falls through the floor | Show collision (**C**). The floor needs collision: check the brush's collision faces in **Brush shape**, or paint the floor with the **Collision** tool. |
|
||||
| **Play from camera position** says there is no floor | Point the middle of the view at walkable ground. Tree crowns, roofs and decoration often have no collision. |
|
||||
| The exit does not work | The LevelDoor needs **exit floor (16)** in its cell. The **Exit** setup in the Objects panel places both together. |
|
||||
| The level does not load / the game crashes | **Level → Check for problems**; keep tiles inside the grid; exactly one player start; no tile model over 8000 vertices. |
|
||||
| My level is missing on the world map | New levels are in world 9 (TestLevel). Unlock it in LlamaMod's **Save games** tab, or play with **F5**. |
|
||||
| Two levels show the same content | They use the same TestLevel chapter – change the **TestLevel chapter** option of one of them. |
|
||||
| Objects near the start are invisible at first | Also true in the original levels: objects within a few cells of the start appear after a moment. |
|
||||
|
||||
## Windows
|
||||
|
||||
### Antivirus warnings
|
||||
|
||||
Some mods (and every play-test with **Play boots straight into the level**) add code to
|
||||
**groove.exe** in LlamaMod's private game copy. Antivirus programs such as Windows Defender may
|
||||
report this changed file as a threat – a false positive: your original files are untouched and
|
||||
nothing is downloaded.
|
||||
|
||||

|
||||
|
||||
* On Windows, LlamaMod shows a notice before it applies such mods for the first time (Linux
|
||||
has no such problem and shows none).
|
||||
* If groove.exe was removed or blocked, LlamaMod says so and offers **Rebuild**.
|
||||
* To stop it from happening again, add the LlamaMod data folder as an exclusion: Windows
|
||||
Security → Virus & threat protection → Manage settings → Exclusions → Add or remove exclusions
|
||||
→ Add an exclusion → Folder.
|
||||
* Or switch off **Level → Play boots straight into the level**: play-tests then start at the
|
||||
main menu and do not change groove.exe.
|
||||
|
||||
### Windows in a virtual machine
|
||||
|
||||
LlamaMod and the editor work in a virtual machine with 3D acceleration, but the game's old
|
||||
DirectX 6/7 graphics often do not: "Direct Draw kann nicht gestartet werden" or an upside-down
|
||||
picture are typical. Use a real Windows PC, or play under Wine on Linux. On real hardware no
|
||||
extra wrapper should be needed.
|
||||
|
||||
## Linux
|
||||
|
||||
* The game runs through **Wine**; install it from your distribution. **Settings → Wine command**
|
||||
points LlamaMod at a specific Wine (leave it empty for the installed one); the line below it
|
||||
says whether that Wine was found.
|
||||
* The first **Play** prepares Wine for the game, which can take a minute.
|
||||
* **Settings → Run in a window** (Wine virtual desktop) is recommended – otherwise the game
|
||||
switches the whole screen to its resolution.
|
||||
* LlamaMod uses its own Wine prefix in the data folder, so your other Wine programs are not
|
||||
affected.
|
||||
|
||||
## The mod cache
|
||||
|
||||
LlamaMod keeps built mod files in the data folder's `cache` folder. If something looks wrong
|
||||
after an update, **Settings → Clear cache** throws it away; active mods are rebuilt on the next
|
||||
**Apply**.
|
||||
|
||||
## Known limits
|
||||
|
||||
* Object types from other levels can be imported, but imports are permanent and limited by the
|
||||
engine's 16 MB level memory, 128 sounds and 127 texture pages
|
||||
([Importing objects](09-objects.md#importing-objects-from-other-worlds)).
|
||||
* Tiles and objects only turn about the vertical axis; only brushes scale and turn freely.
|
||||
* The engine has no free texture coordinates: every triangle shows one half of a texture
|
||||
rectangle ([Textures](08-textures.md)).
|
||||
* At most 8000 vertices per tile model and 127 texture pages per level.
|
||||
* Lights only light object models; tiles use baked vertex colours.
|
||||
* Texture animations are not animated in the viewport (the texture manager previews them).
|
||||
* Many object parameters and some data fields are not understood yet – they are shown raw.
|
||||
* The editor was tested mainly on Linux; Windows works, but real Windows hardware has seen less
|
||||
testing.
|
||||
|
||||
## FAQ
|
||||
|
||||
**Do I need the German version of the game?**
|
||||
The tools were developed with the German CD. Other language versions use the same engine and
|
||||
should work; if one does not, please report it.
|
||||
|
||||
**Can I share levels with people who do not have the game?**
|
||||
No – levels are built from the receiver's own game copy. That is also what makes sharing legal:
|
||||
a project contains no game data.
|
||||
|
||||
**Does the editor change my installed game or my saves?**
|
||||
No. LlamaMod works on its own copy in the data folder. Play-tests use one save slot of that copy
|
||||
(slot 3 by default) and back it up first.
|
||||
|
||||
**Can I edit a level I downloaded?**
|
||||
Yes – open the `.llamalevel` file with **File → Open project**.
|
||||
|
||||
**Where are my levels?**
|
||||
In the `levels` folder of the data folder (**Settings → Data folder → Open folder** in LlamaMod).
|
||||
@@ -0,0 +1,54 @@
|
||||
# Glossary
|
||||
|
||||
| Term | Meaning |
|
||||
|---|---|
|
||||
| **Ambient colour** | The base light of object models in a zone, set in the zone's environment. |
|
||||
| **Base level** | The original level a project is built on. It provides the object types, sounds, sky and default textures. Fixed when the project is created. |
|
||||
| **Blend class** | How a texture is drawn: opaque, cut-out, semi-transparent, additive glow or darken. |
|
||||
| **Brush** | An editor shape (block, platform, ramp, stairs, wall, cylinder, floor, fence, tree, water, death plane, mesh). Converted into tiles when the level is built. |
|
||||
| **Build** | Turning the project into the game's level file (`.wad`): brushes become tiles, textures are packed, everything is checked. |
|
||||
| **Cell** | One grid square of the level, the unit of all positions (4096 game units). |
|
||||
| **Chain** | See *waypoint chain*. |
|
||||
| **Chapter** | One level of a world, for example Village chapter 2. The TestLevel world has 49 chapter slots for new levels. |
|
||||
| **Checkpoint** | A *CheckPointPost* object; the llama respawns at its respawn waypoint after losing a life. |
|
||||
| **Collision material** | A number on every collision polygon: 0 normal, 16 exit floor, 30 no floor (death), others special. |
|
||||
| **Collision polygon** | The invisible surfaces the llama walks on and bumps into. They are separate from what you see. |
|
||||
| **Cut-out** | A texture with fully transparent pixels (leaves, fences). |
|
||||
| **Death plane** | An invisible material-30 floor below the level: falling onto it costs a life. |
|
||||
| **Exit floor** | Collision with material 16. The LevelDoor object ends the level when the llama stands on exit floor in the door's cell. |
|
||||
| **Face** | A triangle of a tile model with one texture. |
|
||||
| **Fog** | The distance fade of a zone; its end distance is also how far the game draws. |
|
||||
| **Gizmo** | The arrows and rings in the viewport for moving and rotating the selection. |
|
||||
| **Grid** | The rectangle of cells that makes up the level. Collision outside it does not work. |
|
||||
| **groove.exe** | The game program. Some mods change LlamaMod's copy of it. |
|
||||
| **Inspector** | The panel with the properties of the selection. |
|
||||
| **Layer** | A part of the viewport display that can be switched on and off (tiles, collision, waypoints …). |
|
||||
| **`.llamalevel`** | A level project file: your changes, imported meshes and textures, a thumbnail. No game data. |
|
||||
| **`.llamamesh`** | A library asset: reusable geometry with its textures. |
|
||||
| **LevelDoor** | The exit object; its parameters choose the next level. |
|
||||
| **Library** | The editor's store of reusable geometry, shared by all levels. |
|
||||
| **Llama** | The player object; its position is the player start. |
|
||||
| **Marker** | A symbol in the viewport for an object without a model (camera, trigger, exit …). |
|
||||
| **Mesh brush** | An imported OBJ or glTF model placed in the level. |
|
||||
| **Mod** | A change to the game that LlamaMod applies to its private game copy. Every level project is a mod. |
|
||||
| **Object** | Anything with behaviour: player, coins, enemies, doors, cameras, triggers. The game calls them *strats*. |
|
||||
| **Outliner** | The panel with the tree of everything in the level. |
|
||||
| **Page** | A 256×256 texture image; textures are rectangles on pages. |
|
||||
| **Play-test** | Building the level and starting the game directly in it (**F5**). |
|
||||
| **Prefab** | A saved group of objects (with waypoints and brushes) for reuse. |
|
||||
| **Region** | A visibility region: cells grouped so the game can skip drawing parts of the level that cannot be seen. |
|
||||
| **Respawn node** | The waypoint where the llama reappears after losing a life at a checkpoint. |
|
||||
| **Snapping** | Moves and rotations in fixed steps (**G**). |
|
||||
| **Start zone** | The zone whose fog, colours and music apply when the level starts. |
|
||||
| **Strat** | The game's name for an object and its script. |
|
||||
| **TestLevel** | The hidden world 9 with 49 empty chapters; new levels go there. |
|
||||
| **Teleport** | A zone that moves the player to a target point when an object (usually a door) in its trigger cell fires. |
|
||||
| **Tile** | A tile model placed in a cell, turned in steps about the vertical axis. |
|
||||
| **Tile model** | A 3D model of the level's tile set, with faces, textures and collision. |
|
||||
| **Tile swap** | An alternative model of a tile that the game switches to (opening doors, broken bridges). |
|
||||
| **Vertex colours** | Colours stored per corner of a tile; they carry the lighting of the level. |
|
||||
| **WAD** | The game's level file (`t1l1m001.wad` = Village chapter 1). |
|
||||
| **Waypoint chain** | A list of points belonging to an object: a patrol path, a camera path, a respawn point or the corners of a box. |
|
||||
| **Work plane** | A fixed height the Brush tool draws on instead of the surface under the cursor. |
|
||||
| **World** | A group of chapters on the game's map: Village, Jungle at Night, River, Jungle by Day, Mountain, City, Catacombs, Lab (and the hidden TestLevel). |
|
||||
| **Zone** | An environment entry: fog, colours, music, sky – and for teleports a trigger cell and a target. |
|
||||
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 44 KiB |