Files
llamamod/notes/mod-coaster.md

8.2 KiB
Raw Permalink Blame History

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 Llama strat: RollerCoaster calls isPlayer() and lookAtMe(), uses model: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 Camera strat (spawn<4,41,2,0x248000,0>(0.9, 1.0, …, unit:Camera)), the same chase camera as the Llama's; it follows g29 = 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 speed v19 (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. RollerDoor are gates the cart passes, FireworksTrigger fires rockets at its waypoint spots when the cart passes, WompyRollerCoaster is 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 + Camera into the village would only duplicate them. The original geometry and objects are replaced by LevelBuilder output (LevelScript.buildWad), so format.stpcmerge is only used read-only (StpcImage/StratCode) by CoasterSpeed.
  • 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 six pushShort 614 (cruise floor/cap) and two pushShort 20 (boost, after pushVar v19/v22) in the RollerCoaster unit with StratListing and rewrites the 16-bit operands; nothing else changes.
  • Checking a layout offline (CoasterSim, test everyJumpLandsAndNoClimbLosesTheFloor): 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: RollerCoaster at the station start, a RollerDoor at the station exit, a FireworksTrigger before 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.

ride tracks (editor top view: loop, grand) tally

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).