Files
llamamod/notes/mod-randomizer.md

63 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Randomizer mod (`randomizer`, GAMEPLAY)
Code: `src/main/java/com/eliasmueller/llamamod/mods/randomizer/` (`RandomizerMod`, `Shuffler`),
test `src/test/.../mods/randomizer/RandomizerModTest` (needs `-Dllamamod.cd=<cd dir>`).
## Options
| Key | Type | Default | Effect |
|---|---|---|---|
| `seed` | SEED | random on first use | same seed = same layout |
| `coins` | BOOL | on | `Coin`, `Coin5` |
| `food` | BOOL | on | `Health`, `HealthFull`, `Grapes`, `HealthBanana` |
| `mix` | BOOL | on | coins and food share one pool (otherwise each kind only among its own places) |
| `pots` | BOOL | off | `SmashPot(spawn)`, `Jar` among their own places |
| `enemies` | BOOL | off | enemies without patrol path, only among places of the same type |
## How it works
Per level WAD `t1l[1-8]mNNN.wad`: parse MAP (`MapChunk`, TRAK vertex counts), name every strat from
STPC (`Strats.nameOr`), sort eligible strats into pools, and permute the *places* inside each pool:
only fields 0–5 of the 58-byte strat record (rotation x/y/z, position x/y/z) are exchanged. Type
code, parameters, nVars/slots/flags/extra and the waypoint index stay with the strat, so the
multiset of objects in a level and the set of occupied places are unchanged – every pickup ends
on a spot where the original game had a pickup (reachable by construction). MAP is rebuilt with
`MapChunk.build()`; all other chunks are untouched.
PRNG: `java.util.Random(seed * 0x9E3779B97F4A7C15 + levelFileName.hashCode())`, pools in MAP order,
`Collections.shuffle` – both are specified by the JDK, so a seed gives the same result everywhere.
Never moved:
* every type not in the lists above (Llama/start, LevelDoor, CheckPoint*, Camera*, CutScene*,
triggers, Force*, switches/doors, RubyIdol (doors depend on it), ChargeBooster, CoinLine/Circle/
RollerCoaster, Secret, platforms …),
* strats with a waypoint (index ≠ −1: patrol paths, secret areas – their coordinates are absolute)
and strats with flag bit 1 (spawned later by an event),
* pots within 3 tiles of a `Secret` (the village secret is "smash the pot cluster").
Pool sizes (all options on, seed 1): 10–65 pickups per level, up to 14 pots; enemies only in
t1l4m002/3 (`VenusFlyTrap`, `AxeGuard`) because almost all enemies have patrol waypoints. Roller
coaster levels (t1l7m001/3/5) and t1l8m006 are unchanged.
Save game: coins per chapter are counted at pickup; the number of coins in a level is unchanged,
so the per-chapter totals and the "all coins" flag behave as in the original.
## Verified in game (apptest, 2026-11-06)
* Village t1l1m001, seed 1: level loads and plays, no crash (most swaps there are coin↔coin, so the
start view looks the same).
* Jungle t1l2m001, seed 2 (chosen because 3 food items land near the start): three of the four coins on
the path ahead of the start are replaced by Health/HealthFull pickups, the coins moved elsewhere
(`img/mods/randomizer-jungle-seed2.jpg`); level runs normally.
* Unit test (`RandomizerModTest`, all 33 WADs): deterministic per seed, different seeds differ,
pickup places are an exact permutation, type/params/waypoint fields unchanged, every other strat
(Llama, LevelDoor, CheckPoint*, cameras, triggers …) byte-identical, strats with waypoints never
move.
## Known limits
* Not played to the level exit in game; correctness of the exit/checkpoints rests on them being
untouched (unit test).
* A coin that sat in the air in an arc may now be a food item there (still reachable, it was a
pickup spot before); first coin parameter (0x1000 vs 0) stays with the strat.
* Enemy shuffle has little effect: almost all enemies have patrol waypoints and are excluded.