llama coaster: ride the catacombs coaster cart on a new track (loop or grand circuit with drops, climbs, boosts, spin pads and jumps), 1-3 laps, three speeds, coins; offline cart simulation checks every jump and climb; roller coaster chapter in the strats docs
This commit is contained in:
1 parent
6d449257a7
commit
f5fd411592
21 files changed
+1818
-17
No files matched your search
+1
-1
@@ -51,7 +51,7 @@ tutorials (first level, parkour, editing an original level, Blender import)
|
||||
* [The script language](strats/script-language.md): writing new behaviour
|
||||
* [Customising strats](strats/custom-types.md): constants, imports, clones, custom types, mods
|
||||
* [Example: the Alligator Arena](strats/arena.md): a complete minigame explained step by step
|
||||
* [Example: the roller coaster](strats/roller-coaster.md): coming soon
|
||||
* [Example: the roller coaster](strats/roller-coaster.md): a new ride for the game's own coaster cart – track data and waypoints, no new strat code
|
||||
|
||||
**[Tools](tools.md)** – LlamaMod's launcher, editor and command line, the Python kit, the in-game
|
||||
test harnesses
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
@@ -74,6 +74,21 @@ another mod on the same chapter stops the apply with a message – pick another
|
||||
|
||||

|
||||
|
||||
## The Llama Coaster ride
|
||||
|
||||
The **Llama Coaster** mod (Levels) puts a roller-coaster ride on a TestLevel chapter (32–49,
|
||||
default 48). You ride the cart from the Catacombs coaster levels: it leaves the station by itself,
|
||||
races down drops and up climbs, speeds up on the boost arrows, jumps over a gap and turns round on
|
||||
the spin pad. Press **Left** and **Right** to move the cart across the track and collect the
|
||||
coins. After the last lap the cart stops at the station, fireworks go off and the tally appears;
|
||||
**Enter** rides again, and *Beenden und zur Auswahlkarte wechseln* in the Esc menu goes back to the
|
||||
map. The options pick the track (*Loop* or the longer *Grand circuit*), the laps (1–3), the speed
|
||||
and whether there are coins. Unlock TestLevel on the **Save games** tab and pick the chapter on the
|
||||
world-9 map. A level project or another mod on the same chapter stops the apply with a message –
|
||||
pick another chapter then.
|
||||
|
||||

|
||||
|
||||
## Command line
|
||||
|
||||
LlamaMod can be scripted:
|
||||
@@ -109,6 +124,20 @@ A minigame on a TestLevel chapter: alligators come in waves into a walled pit. E
|
||||
| Coins per hit | 0 – 5 | 1 | Coins that pop out per hit (5 more at the end). |
|
||||
| TestLevel chapter | 32 – 49 | 49 | Chapter of world 9 the arena replaces (32–49; chapter 1 is the Test World's). |
|
||||
|
||||
#### Llama Coaster
|
||||
|
||||
A roller coaster ride on a TestLevel chapter, with the cart from the Catacombs coaster levels: drops, climbs, boost arrows, a spin pad that turns the cart backwards and a jump over a gap. Steer left and right to stay on the track and collect coins; the ride ends at the station. Unlock TestLevel on the Save games tab.
|
||||
|
||||
*Id* `coaster`
|
||||
|
||||
| Option | Values | Default | Description |
|
||||
|---|---|---|---|
|
||||
| Track | Loop, Grand circuit | Loop | Short loop (about 100 units) or the grand circuit (about 150 units, two jumps, two spins). |
|
||||
| Laps | 1 – 3 | 2 | Laps before the ride stops at the station. |
|
||||
| Speed | Slow, Normal (as in the game), Fast | Normal (as in the game) | Cruise speed and boost strength of the cart. |
|
||||
| Coins | on / off | on | Coins along the track. |
|
||||
| TestLevel chapter | 32 – 49 | 48 | Chapter of world 9 the coaster replaces (32–49; chapter 1 is the Test World's, 49 the arena's). |
|
||||
|
||||
#### Test World
|
||||
|
||||
Turns the hidden TestLevel (world 9, chapter 1) into a playground island: a gallery of every character and object model of all worlds (standing still, grouped by world) and a parkour course with checkpoints. To reach it, click "Unlock TestLevel" on the Save games tab.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
@@ -12,7 +12,7 @@ can read every one of them, change their numbers, write new ones and move them b
|
||||
| [The script language](script-language.md) | writing new behaviour in LlamaMod's structured language |
|
||||
| [Customising strats](custom-types.md) | changing constants, cloning types, custom types in the editor and in mods |
|
||||
| [Example: the Alligator Arena](arena.md) | a complete minigame written in the script language, explained step by step |
|
||||
| [Example: the roller coaster](roller-coaster.md) | coming soon |
|
||||
| [Example: the roller coaster](roller-coaster.md) | a new ride for the original coaster cart: how the ride works, track and waypoint data, speed patch |
|
||||
|
||||
Lab notes and tables: [notes/strat-opcodes.md](../../notes/strat-opcodes.md) (all 434 opcodes with
|
||||
semantics, confidence and Argonaut names), [notes/strat-language.md](../../notes/strat-language.md)
|
||||
|
||||
+187
-15
@@ -1,20 +1,192 @@
|
||||
# Example: the roller coaster
|
||||
|
||||
> **Coming soon.** A roller-coaster mod is in development. This page will walk through it the way
|
||||
> [the arena page](arena.md) does, once it is finished. Until then, its lab notes will appear as
|
||||
> `notes/mod-coaster.md` and its code under `src/main/java/com/eliasmueller/llamamod/mods/coaster/`.
|
||||
The *Llama Coaster* mod builds a new roller-coaster ride: a circuit with drops, climbs, boost
|
||||
arrows, a spin pad, a jump over a gap, a station where the ride starts and ends, and fireworks at
|
||||
the finish. Unlike the [arena](arena.md) it writes no new strat code: it **reuses the game's own
|
||||
coaster cart** (`RollerCoaster`) and only gives it new track data – new geometry and a new
|
||||
waypoint chain. This page explains how the original ride works and how the mod feeds it.
|
||||
|
||||
<!-- TODO (docs): fill in when mods/coaster is merged: overview + screenshots (docs/img/strats/),
|
||||
files table, the track geometry, the cart/player strat scripts step by step, options, tests,
|
||||
lessons learned. Link notes/mod-coaster.md and the 18-mods.md section. -->
|
||||

|
||||
|
||||
## What is already known about the original rides
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| [`CoasterMod.java`](../../src/main/java/com/eliasmueller/llamamod/mods/coaster/CoasterMod.java) | the mod: options, chapter check, writes the WAD and the loading picture |
|
||||
| [`CoasterTrack.java`](../../src/main/java/com/eliasmueller/llamamod/mods/coaster/CoasterTrack.java) | the two layouts; turns legs and pieces into segments, corners and the waypoint chain |
|
||||
| [`CoasterLevel.java`](../../src/main/java/com/eliasmueller/llamamod/mods/coaster/CoasterLevel.java) | the level script: track bed, rails, pillars, station, ground, objects |
|
||||
| [`CoasterSpeed.java`](../../src/main/java/com/eliasmueller/llamamod/mods/coaster/CoasterSpeed.java) | patches the cart's speed constants for the Speed option |
|
||||
| [`CoasterSim.java`](../../src/main/java/com/eliasmueller/llamamod/mods/coaster/CoasterSim.java) | frame-by-frame model of the cart, to check a layout without the game |
|
||||
| [`CoasterTest.java`](../../src/test/java/com/eliasmueller/llamamod/mods/coaster/CoasterTest.java) | unit tests |
|
||||
| [notes/mod-coaster.md](../../notes/mod-coaster.md) | lab notes: engine facts, what was verified in the game |
|
||||
|
||||
* Catacombs chapters 1, 3 and 5 (`t1l7m001`, `t1l7m003`, `t1l7m005`) are roller-coaster rides. In
|
||||
these levels the player is not the `Llama` strat but a **`RollerCoaster`** strat
|
||||
([Objects](../reference/objects.md#special-objects)).
|
||||
* The rides have the longest views of the game: fog end up to 23 cells
|
||||
([Engine facts](../reference/engine-limits.md#drawing)).
|
||||
* The ride music is track 25, `ROLLER` ([Music](../reference/audio.md#music)).
|
||||
* Objects of these levels can be imported into other levels, but they only work with matching
|
||||
geometry ([manual chapter 9](../manual/09-objects.md#limits-and-things-to-know)).
|
||||
Options: **track** (Loop ~100 units, Grand circuit ~150 units), **laps** (1–3, default 2),
|
||||
**speed** (slow / normal / fast), **coins** (on/off), TestLevel **chapter** (32–49, default 48).
|
||||
See [manual chapter 18](../manual/18-mods.md#the-llama-coaster-ride) for players.
|
||||
|
||||
## 1. How the original ride works
|
||||
|
||||
Catacombs chapters 1, 3 and 5 (`t1l7m001`, `t1l7m003`, `t1l7m005`) are roller-coaster rides. The
|
||||
ride music is track 25, `ROLLER` ([Music](../reference/audio.md#music)); the levels have the
|
||||
longest views of the game (fog end up to 23 cells, [Engine facts](../reference/engine-limits.md#drawing)).
|
||||
|
||||
* **The cart is the player.** These levels have no `Llama` strat. The `RollerCoaster` strat calls
|
||||
`isPlayer()` and draws `model:0` – the cart *with* Kuzco the llama and Pacha in it – so the llama
|
||||
is not attached at run time, it is part of the cart model and its animations (lean, cheer, look
|
||||
back). See [Objects](../reference/objects.md#special-objects).
|
||||
* **The camera** is the ordinary `Camera` strat, spawned by the cart like the Llama spawns it. It
|
||||
follows the global `g29`; in a corner the cart sets `g29` to the heading *after* the turn, so the
|
||||
camera swings round first.
|
||||
* **Track following**: the cart drives straight along its heading and turns by exactly 90° at a
|
||||
waypoint. Its height comes from the floor under it. So a ride is a chain of straight legs on the
|
||||
grid with 90° corners; slopes, jumps and gaps are pure geometry.
|
||||
* **Floor materials** of the track bed trigger the effects: 5 boost arrows, 11 jump, 13 spin pad
|
||||
(the cart hops and turns round, riding backwards to the next corner), 16 the end, 30 the
|
||||
invisible death plane below (fall = restart).
|
||||
* **Start and end**: the first waypoints are *station* nodes – the cart crawls out with letterbox
|
||||
borders. On material 16, when the current waypoint is the last one, the strat waits 30 frames and
|
||||
calls `endLevel` with its own parameters 1–3 (tribe, world, chapter) → the tally screen.
|
||||
* Helpers: `RollerDoor` (gates), `FireworksTrigger` (rockets at its waypoint spots when the cart
|
||||
passes), `CoinRollerCoaster` (coins hovering over the track), `WompyRollerCoaster`.
|
||||
|
||||
The river levels (`t1l3m001…4`) look similar but are not rail rides: their player
|
||||
`KuscoAndPachaTogetherOnATree` floats on water, is pushed by current zones, steers freely between
|
||||
the banks and leaves through a normal `LevelDoor`. That is why the mod uses the coaster.
|
||||
|
||||
### The cart script step by step
|
||||
|
||||
Excerpts of `RollerCoaster` as the editor's script view shows it (`v19` = speed, `v22` = boost
|
||||
excess, `v18` = sideways offset, `v21` = 0 or 2048 when riding backwards):
|
||||
|
||||
```
|
||||
call L_0200() // prepare the waypoints:
|
||||
// self.wpX = int(self.wpX * 2 + 0.5) / 2 x/z rounded to halves
|
||||
// setWaypointParam2((self.wpRotY + 512) & 3072) heading rounded to a quarter turn
|
||||
spawn<4, 41, 2, 0x248000, 0>(0.9, 1.0, 0, 0, unit:Camera)
|
||||
isPlayer()
|
||||
self.y = self.floorHeight
|
||||
showLevelStartInfo<1>()
|
||||
loop {
|
||||
call L_0074() // the end check (below)
|
||||
call L_012c() // left/right input → v18 (at most half the speed)
|
||||
moveRightQ(v18)
|
||||
moveForwardQ(v19)
|
||||
if (v22 > 2r) { v19 -= 2r; v22 -= 2r } // a boost wears off …
|
||||
else if (v19 > 0.15) { v19 = max(v19 - 2r, 0.15) } // … down to cruise 0.15 (614 raw)
|
||||
if (self.floorMaterial == 11) { … g22 = 163r } // jump: vertical speed
|
||||
else if (self.floorMaterial == 5) { v19 += 20r; v22 += 20r } // boost arrows
|
||||
else if (self.floorMaterial == 13) { … g22 = 61r; v20 = 128 } // spin: hop + half turn
|
||||
if (self.y - 204r - v19 * 1228r < self.floorHeight && self.floorMaterial != -1) {
|
||||
self.y = self.floorHeight // stay on the floor (a climb > ~0.1 per frame is lost)
|
||||
} else { … fall … }
|
||||
// corner: within 0.75 of the waypoint, steer round it and take the next one
|
||||
v15 = (self.x - self.wpX) * v4 + (self.z - self.wpZ) * v5
|
||||
if (v15 < 0.75 | (self.wpParam && v15 < 2.0)) { … g29 = self.wpRotY … }
|
||||
…
|
||||
}
|
||||
|
||||
L_0074: // the end
|
||||
if (v13 > 1) { v13 -= 1; if (v13 <= 1) { endLevel(v1, v2, v3) } }
|
||||
else if (self.floorMaterial == 16 && (self.wpEndFlags & 3r)) { v13 = 30 }
|
||||
```
|
||||
|
||||
## 2. The plan
|
||||
|
||||
* **Base level = Catacombs 1 (`t1l7m001`)**, not the village: it already contains the cart, its
|
||||
camera, coins, gates, fireworks, textures, sounds and the ride music. Importing them into the
|
||||
village ([like the arena](arena.md#3-compiling-and-importing-arenaimport)) would only copy the
|
||||
same things over. The mod keeps the base level's code and replaces geometry and objects.
|
||||
* The **track** follows the cart's rules: straight legs along the axes, 90° corners, heights
|
||||
changing only on straights.
|
||||
* The **cart's waypoint chain** is generated from the same layout, so geometry and path cannot
|
||||
disagree.
|
||||
* The level goes into a TestLevel chapter ([why 32–49](../reference/testlevel.md)).
|
||||
|
||||
## 3. The track (`CoasterTrack`)
|
||||
|
||||
A layout is a start corner and a list of legs; each leg is a heading and a list of pieces
|
||||
(kind, length in units, height change):
|
||||
|
||||
```java
|
||||
new CoasterTrack("loop", new double[] {10, 10, 24}, List.of(
|
||||
stationLeg(90, 4, 8, 4, 2), // run-in, END, brake, STATION, first drop
|
||||
leg(0, p(TRACK, 2), p(TRACK, 8, 2), p(TRACK, 2)), // climb 2
|
||||
leg(270, p(TRACK, 2), p(SPIN, 1), p(TRACK, 1), p(TRACK, 4, -2)),
|
||||
leg(0, p(BOOST, 2), p(JUMP, 1), p(GAP, 2, -1), p(TRACK, 9)), // jump over a gap
|
||||
leg(270, p(TRACK, 3), p(TRACK, 5, -2), p(TRACK, 2)),
|
||||
leg(180, p(BOOST, 1), p(TRACK, 2), p(TRACK, 25, 7)))); // lift hill back up
|
||||
```
|
||||
|
||||
The constructor lays the pieces out and refuses a layout that does not close, turns by anything
|
||||
but 90° or lacks exactly one STATION and one END on leg 0. Each kind maps to a floor material
|
||||
(TRACK 0, BOOST 5, JUMP 11, SPIN 13, END 16).
|
||||
|
||||

|
||||
|
||||
**Waypoints** (`nodes(laps)`): node 0 one unit behind the cart and node 1 at the end of the
|
||||
station, both with parameter 1.0 (the crawl); then one node per corner, 0.5 before its centre with
|
||||
the heading after the turn, repeated for every lap; and a last node 9 units past the END pad. So
|
||||
the END pad only ends the ride in the last lap – in earlier laps the cart rolls over it.
|
||||
|
||||
## 4. The level (`CoasterLevel.build`)
|
||||
|
||||
The level is a [`LevelScript`](../../src/main/java/com/eliasmueller/llamamod/levelbuild/LevelScript.java)
|
||||
for the [`LevelBuilder`](../../src/main/java/com/eliasmueller/llamamod/levelbuild/LevelBuilder.java):
|
||||
|
||||
* **Track bed**: per unit two 1 × 1 quads with the piece's texture and material (boost arrows,
|
||||
jump stripes, spin target), an underside, and **rails** 0.35 high on both sides – their inner
|
||||
faces are collision walls, so steering cannot leave the track. Gaps get end faces.
|
||||
* **Corners**: flat 2 × 2 squares with rails on the two outer sides.
|
||||
* **Pillars** every 5 units and under each corner, a **boarding platform** with posts left of the
|
||||
station, a **ground plane** at height 0 with material 30 (the death plane).
|
||||
* **Objects**:
|
||||
|
||||
```java
|
||||
l.strat("RollerCoaster", st[0], st[1], st[2], st[3],
|
||||
new int[] {0, tribe * FX, world * FX, chapter * FX}, // endLevel target = this chapter
|
||||
LevelBuilder.Waypoints.of(wps), 0, false);
|
||||
l.strat("RollerDoor", …); // gate at the station exit
|
||||
l.strat("FireworksTrigger", …, Waypoints.of(fw), …); // six rocket spots around the END pad
|
||||
l.strat("CoinRollerCoaster", …); // every 1.5 units on long straights
|
||||
```
|
||||
|
||||
## 5. Speed and checking a layout (`CoasterSpeed`, `CoasterSim`)
|
||||
|
||||
The **Speed** option scales two constants of the cart: the cruise speed `pushShort 614` (six
|
||||
places: the floor after a boost and the cap in corners) and the boost `pushShort 20` (two places).
|
||||
`CoasterSpeed.find` locates them in the unit's listing (the instruction before and after must
|
||||
match) and rewrites only those 16-bit operands.
|
||||
|
||||
A faster cart flies farther, and a jump that lands in a corner's turn zone misses the turn.
|
||||
`CoasterSim` replays the cart's speed and jump rules frame by frame on a layout and reports jumps
|
||||
that do not clear their gap or land too late, and climbs steeper than the floor probe allows.
|
||||
The tests run it for every track × speed × laps.
|
||||
|
||||
## 6. The mod (`CoasterMod`)
|
||||
|
||||
`apply` refuses a chapter whose WAD another mod (or a level project) already changed, builds the
|
||||
level on `t1l7m001`, sets the tally total to the number of coins (`LevelTally.counted`) and draws
|
||||
a loading picture in Java (the title sits in the band the tally text leaves free).
|
||||
|
||||

|
||||
|
||||
## 7. How it was tested
|
||||
|
||||
* **Unit tests** (`CoasterTest`): both layouts close, contain every feature and do not overlap;
|
||||
bad layouts are refused; the waypoint chain follows the cart's rounding rules; every jump lands
|
||||
for all speeds and laps; the speed patch changes exactly the 8 operands; the built level has one
|
||||
RollerCoaster (and no Llama), the gate, the fireworks, the coins, the right exit target, the
|
||||
floor materials 0/5/11/13/16/30 and the tally total; a chapter another mod wrote is refused.
|
||||
* **In the game** (`tools/apptest.py`): Loop and Grand circuit at all three speeds, 1 and 2 laps –
|
||||
full rides from the station to the tally with a screenshot every 1.5 s, no crash. After the tally
|
||||
Enter restarts the ride; in the ride Esc → *Beenden und zur Auswahlkarte wechseln* goes back to
|
||||
the world map.
|
||||
|
||||
## What to take from it
|
||||
|
||||
1. **Reuse a ride type with new data** when its rules fit: a new geometry plus a new waypoint chain
|
||||
is a new ride, without writing strat code.
|
||||
2. **Read the original strat first** – the 90° corners, the half-unit rounding and the 0.1 climb
|
||||
limit all come from its script, and the layout code enforces them.
|
||||
3. **Generate path and geometry from one description**, so they always match.
|
||||
4. **Model the physics offline** (`CoasterSim`) to catch bad jumps before starting the game.
|
||||
5. **Constants can be tuned in place**: find them in the listing by their neighbours and patch the
|
||||
operand, instead of recompiling the strat.
|
||||
Reference in new issue
Block a user