# Objects, waypoints, zones and lights Everything that is not static geometry lives in the second half of the MAP chunk: object instances ("strats"), their parameters, waypoint chains and environment zones. Lights are in their own chunk, LGHT. Full byte layouts: [notes/objects.md](../../notes/objects.md). ## Strats: objects are programs An object – coin, enemy, door, camera, the player – is an instance of a **strat**: a script in the level's STPC code. A MAP record says *where* and *which code*; the code does the rest. There is no type id: **the type is the code's byte offset in STPC**. Type names come from the code itself (a `debugName "Coin"` instruction at the entry point). How the code works: [Strats](../strats/README.md). About 300 types are placed in the original levels, about 200 more are only spawned by other strats (splinters, effects, heads). The full list of which type appears in which level, with instance counts, is [notes/strat_types_table.md](../../notes/strat_types_table.md) (`tools/strat_table.py`). ## The MAP object blocks After the geometry blocks ([Geometry](geometry.md#map-the-tile-grid-certain)): | Block | Format | |---|---| | parameter pool | `u32 n, n × u32` – all object parameters of the level, referenced by index | | environment zones | `u32 n, n × 90 bytes` (below) | | waypoints | `u32 n, n × 34 bytes {u32 next, u32, u16 rx, ry, rz, s32 x, y, z, u32, u32}`; `next ≠ 0` = the following entry belongs to the same chain | | strats | `u32 nStrats, u32 poolExtra`, nStrats × 58-byte records | | optional tail | paths (WFPC 0x200000, unused by the CD levels), a buffer size (WFPC 0x10), a u16 | ### Strat record (58 bytes, *certain* unless noted) | Offset | Field | |---|---| | 0 | rotation x, y, z (u16 each, 4096 = 360°; x/z almost always 0) | | 6 | position x, y, z (s32, 20.12 fixed point, game space) | | 18 | **code offset in STPC = the type** | | 22 / 26 | parameter count / index into the parameter pool (−1 if none) | | 30 | number of strat variables (fixed per type) | | 34 | 16-byte slots for event handlers (fixed per type, *likely*) | | 38 | type flags: collision and physics setup (fixed per type) | | 42 | extra memory words (collision bones; fixed per type) | | 46 | first waypoint index or −1 | | 54 | flags; bit 1 = not created at level start | `poolExtra` is the number of strat slots beyond 30: the engine allocates `poolExtra + 30` slots, which must cover all placed objects **plus everything spawned at run time**. The type fields (variables, slots, flags, extra) come from the compiler and must be copied from an original instance of the same type; a type that uses collision but has type flags 0 crashes the game. Builders and the editor do this automatically. ### Parameters The *n* parameters of an instance are pushed onto the new strat's stack and become its **variables v0 … v(n−1)**. Values are 20.12 fixed point by convention (0x1000 = 1.0), booleans 0 / 0x1000, counts and world/chapter numbers `n << 12`. The editor knows the meaning of the parameters of many types (schemas in [`editor/tools/objects/Schemas.java`](../../src/main/java/com/eliasmueller/llamamod/editor/tools/objects/Schemas.java), findings in [notes/editor-object-schemas.md](../../notes/editor-object-schemas.md)); the others are shown raw with the values used in the original levels. ### Waypoints A waypoint chain is a list of positions used for patrol paths, moving platforms, camera paths – and for some types (guards, box walkers) as a **pair of boxes** the object must stand in, or the game removes it ("removing strat"). Guards also wait for an **event bit** (global variable 95) that another object sets ([notes/editor-object-schemas.md](../../notes/editor-object-schemas.md#event-bits-global-95)). The **player's waypoint chain is the start camera**: the camera takes the first node within 2.5 cells of the llama. A good start has one node about 2 cells behind the llama and 0.5 above it, and nothing solid right behind the llama (the camera moves aside). ## Special objects | Role | Type | Notes | |---|---|---| | player start | `Llama` | exactly one per level (`RollerCoaster`, `KuscoAndPachaTogetherOnATree`, `LlamaChase` in special levels) | | checkpoint | `CheckPointPost` (spawns `CheckPointHead`), `CheckPointBox` | the respawn point after a fall | | exit | `LevelDoor` | invisible trigger, see below; variants `VillageEndDoor`, `EndGameDoor` | | cameras | `CameraSide`, `CutSceneCameraDirectional`, `CutSceneTrigger` | camera zones and cut scenes | | always present | `CheatTeleport`, `Wompy`, `CutSceneTrigger` | | ### The exit (LevelDoor) An exit is **two parts working together** (decompiled strat code; the details below were checked in game in Jungle Day 2 with a debugger, the basic rule also in Village 1): * The **LevelDoor** object (no model) writes its three parameters – the next level (tribe, world, chapter) – to globals g101–g103 and its grid cell to g104/g105. It does **not** end the level itself in the cases we tested (see the details below). * **Kuzco's own script** ends the level when **all** of these hold: ``` floor material under Kuzco == 16 ; the remembered floor (see "floor test" below) and floor(x), floor(z) == the cell in g104/g105 ; the exit's grid cell, any height and Kuzco is at most ~0.6 above that floor's height -> level change to g101..g103 (tally screen) ``` On a material-16 floor **outside** the exit cell the same check is a house door: fade-out and the teleport of the environment zone of that cell. So a normal exit needs **a floor with collision material 16 in the exit's grid cell**. In several original levels that floor only exists after a tile swap opens the door (Village 1 and Jungle Day 2: the RubyIdolDoor swaps the tile to a model that has the material-16 pad; checked in game in Village 1). The parameters of the originals are (1, world, chapter + 1); **(7, 7, 7)** in the last chapter of a world means "world finished" – in TestLevel that crashes, so custom levels use (1, 9, chapter). The tally shows coins x / LNFO total and secrets and unlocks the next chapter. The arena sets g101–g105 itself to make its own exit ([Arena](../strats/arena.md)). **Details checked in game (Jungle Day 2, t1l4m002, 2026-11-07):** * The LevelDoor stores its parameters and cell in g101–g105, then checks global 0x21 **once** (after 5 ticks); if it is not 3 the door removes itself. In Jungle Day 2 it was gone after the start, so the Llama's check is what ends the level. That check needs floor material 16, the door's cell, and the llama no more than 0.6 above the recorded floor height. Off the exit cell the same material-16 check is the house door (fade-out and zone teleport). * The floor test only looks at tiles in the player's cell and takes the **nearest upward floor below the player, at any distance**. Material 17 is ignored for the llama. A llama hovering 3.7 units above a house-door pad records material 16. * Each tick runs all strat scripts first and then the floor tests. A position change made after the floor tests is seen by the next tick's scripts with the **old** floor record. So hovering above any house-door pad and then moving the llama straight to floor height in the exit cell ends the level, even though the exit cell has no material 16 yet (it appears only in the swap model when the RubyIdolDoor opens). Moving there from normal ground does nothing. ## Environment zones (90 bytes, *certain* for the fields below) A zone sets fog, colours, music and sky, and optionally teleports the player. | Field | Meaning | |---|---| | cell x, y, z | the trigger cell | | target x, y, z, angle | teleport target and facing | | flags (+0x20) | flag 8 = **start zone** (exactly one per level: the level begins with its settings); flag 4 = do not move the player | | sky model | STPC offset of a sky model (0 = none) | | fog mode | 0 none, 1 darkness with a light around the player, 2 table fog, 3 vertex fog | | fog start / end | two pairs (detail Minimum and Maximum); **fog end = far clip = draw distance** | | colours | ambient colour for object lighting, fog/backdrop colour | | music id | 1–39 (see [Music](audio.md#music)), 0 stops the music | Teleports are triggered from strat code (opcode 0x100 looks up the zone of the calling object's cell). In the original levels the trigger cells hold exit floors (material 16) or door objects – this is how the village house doors work. The editor edits zones in the *Environment* panel ([manual chapter 12](../manual/12-environment.md)). ## Lights LGHT: `u32 n`, then per light a type, a colour (×2/255) and direction or position (game space). Lights only light **object models** (ambient + all directional lights + the nearest point lights, at most 6). Tiles use baked vertex colours, so changing a light does not change the ground – bake the vertex colours again. Point lights are full up to radius *a* and fade to 0 at *b*; one byte makes them flicker. ## Tools | Task | Tool | |---|---| | list types, instances, parameters of a level | [`tools/strats.py`](../../tools/strats.py) `level.wad [--all]`, [`tools/map_dump.py`](../../tools/map_dump.py) `--strats --tiles --lights` | | type × level table | [`tools/strat_table.py`](../../tools/strat_table.py) | | place objects from a script | [`tools/levelbuild.py`](../../tools/levelbuild.py) `L.strat(...)`, Java [`LevelBuilder`](../../src/main/java/com/eliasmueller/llamamod/levelbuild/LevelBuilder.java) | | place, edit, check objects visually | the level editor ([manual chapter 9](../manual/09-objects.md), [10](../manual/10-waypoints.md), [11](../manual/11-cameras-triggers.md)) |