8.2 KiB
Llama Coaster (coaster, LEVELS)
Package mods/coaster: CoasterMod (options, chapter check, writes wads/T1L9M0nn.wad +
loading picture T19nn.COR), CoasterLevel (level script: track geometry + objects),
CoasterTrack (layouts → segments, corners, waypoint chain), CoasterSpeed (patches the
RollerCoaster strat's speed constants), CoasterSim (frame model of the strat's speed/jump logic,
used by the tests to check a layout). Tests: CoasterTest. Registered in ModRegistry (one line).
Docs: docs/strats/roller-coaster.md, manual chapter 18.
| Option | Default | Meaning |
|---|---|---|
track |
loop |
loop (~103 units/lap) or grand (~150 units, two jumps, two spin pads) |
laps |
2 (1–3) | laps before the ride ends at the station |
speed |
normal |
slow ×0.8, normal ×1, fast ×1.25 (cruise 614 raw and boost 20 raw/frame) |
coins |
on | CoinRollerCoaster along the straights (loop 27, grand 44; placed once, not per lap) |
chapter |
48 (32–49) | TestLevel chapter; a chapter another mod already wrote → apply error |
How the original rides work
Roller coaster = Catacombs 1, 3, 5 (t1l7m001/3/5, world 7 – not world 8; Yzma's lab is
world 8 and has no ride). Strat units of t1l7m001: RollerCoaster (unit 0, 1775 words),
CameraFixedPointBox, RollerDoor, CoinRollerCoaster, WompyRollerCoaster,
FireworksTrigger, Camera, SpawnableRing, Sparkles, SpawnableNeedleBall.
- The cart is the player. There is no
Llamastrat:RollerCoastercallsisPlayer()andlookAtMe(), usesmodel:0(cart with Kuzco-llama and Pacha, scale 2) and its animations (lean, cheer, look back, fall). The llama is part of the cart model, not attached at runtime. - Camera: the strat spawns the shared
Camerastrat (spawn<4,41,2,0x248000,0>(0.9, 1.0, …, unit:Camera)), the same chase camera as the Llama's; it followsg29= the cart's heading, which the strat sets to the next waypoint's heading in corners (so the camera swings round before the cart).CameraFixedPointBox(one per level) is a fixed-point camera zone. - Track following = waypoint chain + floor. At start (
L_0200) every waypoint x/z is rounded to halves and its heading to a quarter turn (param2). The cart drives straight along its heading at speedv19(min 0.15 = 614 raw), the floor height comes from the collision floor below it (noFloorPhysics,self.y = floorHeight; a climb steeper than ~0.1 per frame loses the floor). Within 0.75 in front of the current waypoint it turns by 90° on a small arc round the waypoint (funnel: lateral offset clamped to 1.2·distance) and switches to the next one – so the tracks are straight legs on the grid with 90° corners; only the geometry makes slopes. Left/right input shifts the cart sideways (v18, ±half the speed); the rails are collision walls. - Floor materials (collision material of the track bed): 5 boost (+20 raw speed and "excess" per frame, decays back to cruise), 11 jump (vertical speed 163 raw, gravity 14 raw per frame), 13 spin (small hop + half turn: the cart rides backwards until the next corner), 15 an animation/sound pad, 16 the end (only when the current waypoint is the last one), 30 the invisible death plane far below (fall → restart).
- Start: the first two waypoints have param 1.0 (station): the cart crawls (0.025 + nudges) out of the station with letterbox borders and the start line, then picks up cruise speed.
- End: on material 16 with the last waypoint active the strat plays a sound and after 30
frames calls
endLevel(param1..3)– the cart's own params 1–3 are the target (tribe, world, chapter) → tally screen.RollerDoorare gates the cart passes,FireworksTriggerfires rockets at its waypoint spots when the cart passes,WompyRollerCoasteris a spinning Wompy pick-up.
River = Jungle river 1–4 (t1l3m001…4, world 3; world 2 is the jungle at night). The player
strat is KuscoAndPachaTogetherOnATree (both on a log, also isPlayer() + the shared Camera).
It also rounds its waypoints to halves/quarter turns and turns at waypoints whose param is 1 or 2
(left/right), but it floats on water (floorMaterial 5 = water there: rumble, splash particles)
and is pushed by current/force zones (RiverCurrentBox, many "kraft" zones); the player steers
freely between the banks, CameraLift/RiverWaterfallCamera give the scripted shots, and the
level ends at a normal LevelDoor. It is a steerable boat, not a rail ride, so the coaster mod
uses the RollerCoaster strat.
Design
- Base level = t1l7m001 (not the village + import): its STPC already has every unit the ride
needs and their textures, sounds and the ride music; importing
RollerCoaster+Camerainto the village would only duplicate them. The original geometry and objects are replaced byLevelBuilderoutput (LevelScript.buildWad), soformat.stpcmergeis only used read-only (StpcImage/StratCode) byCoasterSpeed. - Track: straight legs along the axes, 2 wide (two 1-wide lanes, centre line on integers), joined by flat 2 × 2 corner squares; heights change only on straights. Pieces: TRACK, BOOST (mat 5), JUMP (11), SPIN (13), END (16), STATION, GAP (no floor). Rails 0.35 high (inner face = collision), underside, pillars every 5 units and under corners, a boarding platform with posts left of the station, ground plane at y = 0 with material 30. Textures are t1l7m001 TEXT indices.
- Leg 0 of every layout: run-in, END pad, brake run, STATION (5), first drop with a boost at its top. The circuit must close (checked) and END must come before STATION on leg 0.
- Waypoint chain (
CoasterTrack.nodes): node 0 one unit behind the cart and node 1 at the station's end, both param 1.0 (crawl); then one node per corner, 0.5 before its centre, heading after the turn, repeated per lap; last node 9 units past the END pad on leg 0, so the END pad is live only in the last lap. RollerCoaster params = (0, 1, 9, chapter) ×4096 → the tally restarts the ride, like the arena. - Speed (
CoasterSpeed): finds the sixpushShort 614(cruise floor/cap) and twopushShort 20(boost, afterpushVar v19/v22) in the RollerCoaster unit withStratListingand rewrites the 16-bit operands; nothing else changes. - Checking a layout offline (
CoasterSim, testeveryJumpLandsAndNoClimbLosesTheFloor): for every track × speed × laps every jump must clear its gap and land before the commit zone of the next corner, no climb > 0.1 per frame, speed stays 0.02–0.45. - Objects:
RollerCoasterat the station start, aRollerDoorat the station exit, aFireworksTriggerbefore the END pad with six rocket spots, CoinRollerCoaster every 1.5 units on straights ≥ 4 long outside leg 0 (on a slight zig-zag). The tally total (LNFO) is the coin count. - Loading/tally picture: drawn in Java (dark purple, a rail curve, title "Llama Coaster" in the band y 265–335 that the game's tally text leaves free).
Verified in game (apptest, :26, 2026-11-07)
- loop/normal 1 lap and 2 laps, loop/fast 1 lap, grand/fast 1 lap (chapter 40), grand/slow: station crawl with letterbox and start line, drops, climbs, boost arrows, start hint "Kusco, bleib in der Mitte der Kurve und wir werden uns automatisch umdrehen!", spin pad (cart turns backwards), jump over the gap and landing, corners, coins counted (e.g. 14/27, 19/44), END pad → fireworks → tally with the loading picture. No crash in any run.
- After the tally: Enter restarts the ride (same chapter); Esc asks "Möchtest du das Spiel beenden?" (No → back to the tally). In the ride, Esc → Beenden und zur Auswahlkarte wechseln → Yes → world-9 map on "TestLevel Kapitel 48". Same behaviour as the arena.
Limits
- Only 90° corners on the grid and straight slopes (the strat cannot follow curves or banking); no loops/inversions (the cart has no roll).
- The tally coin count is not kept on the world map (it showed 0 after the ride) – same as the other TestLevel mods; not investigated.
- The original levels' sky/fog/lighting of t1l7m001 stays (dark catacombs, fog end 23 cells).


