initial commit: llamamod 0.2.0 – reverse-engineered level formats (wad, map, trak, text, stpc), python tools and notes, java mod manager (iso install, mod pipeline with exe patching, save editor, wine/windows launcher) with mods (test world, debug wireframe, mirror, randomizer, fog, cheats, intro skip, practice, free camera, boot to level, level projects) and the 3d level editor (geometry, objects, cross-world import, environment, textures, play-test, manual)

This commit is contained in:
MineTec committed 2026-11-07 08:15:40 +01:00
commit b36a366240
826 files changed
+105304

No files matched your search

+408
View File
@@ -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.
![Drawing a ramp with the Brush tool](img/geo_draw.jpg)
## 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.
![A selected brush with its resize handles](img/geo_handles.jpg)
### 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 Brush shape section after turning a ramp with the blue ring](img/geo_rotate3d.jpg)
* 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.
![The Geometry menu with the Align submenu](img/geo_menu.jpg)
### 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**.
![The Tiles tool with its palette in the village](img/geo_tiles.jpg)
### 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.
![Painting collision materials](img/geo_collision.jpg)
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).
![In the game: stepping onto a death floor](img/geo_game_death.jpg)
### 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.
![In the game: an invisible wall stops the llama at the edge](img/geo_game_invisible_wall.jpg)
### 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.
![A clean build of a brush level](img/geo_build_ok.jpg)
## 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.
![In the game: a course built from brushes](img/geo_game_course.jpg)