7.8 KiB
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.
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.
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
(tools/strat_table.py).
The MAP object blocks
After the geometry blocks (Geometry):
| 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,
findings in 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).
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) – certain
The LevelDoor has no model. Every frame it checks:
game state is "running"
and the floor polygon under the llama has collision material 16
and floor(llama.x) == floor(door.x) and floor(llama.z) == floor(door.z) ; same grid cell
-> endLevel(tribe, world, chapter) ; its three parameters
So an exit needs a floor with collision material 16 in the door's grid cell – height does not
matter. In several original levels the pad only appears when a tile swap opens the door (Village 1:
the RubyIdolDoor swaps the tile to a model that has the material-16 pad). The parameters are the
next level; the originals use (1, world, chapter + 1), and (7, 7, 7) in the last chapter of a
world means "world finished" – in TestLevel that crashes, so custom levels use (1, 9, chapter).
endLevel shows the tally (coins x / LNFO total, secrets) and unlocks the next chapter.
A second path in the Llama's own code ends the level when it stands on material 16 in the cell stored in globals g104/g105 with the target in g101–g103 – the arena uses this (Arena).
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), 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).
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 level.wad [--all], tools/map_dump.py --strats --tiles --lights |
| type × level table | tools/strat_table.py |
| place objects from a script | tools/levelbuild.py L.strat(...), Java LevelBuilder |
| place, edit, check objects visually | the level editor (manual chapter 9, 10, 11) |