164 lines
9.5 KiB
Markdown
164 lines
9.5 KiB
Markdown
# 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)) |
|