test world: gallery of all 253 figures and objects of every world as static display strats (cross-world import, idle animation, no ai), packed rows per world with coloured posts, animal pen removed

This commit is contained in:
MineTec committed 2026-11-07 13:59:54 +01:00
1 parent 6a76cac69f
commit d030c9c6c7
15 files changed
+1053 -175

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

+116
View File
@@ -0,0 +1,116 @@
# Test World (`testworld`, LEVELS)
Package `mods/testworld`: `TestWorldMod` (writes `wads/T1L9M001.wad` + loading picture `T191.COR`),
`TestWorld` (the level script), `Gallery` (all-worlds model gallery), `Layout` (row packing),
`JumpLab` (separate jump-measuring level, not used by the mod). No options in the launcher; the
script options below are for tests and tools (`ViewerDemo testworld`, `TestWorld.buildWad(…, opts)`).
| Script option | Default | Meaning |
|---|---|---|
| `gallery` | `all` | `none`, or comma-separated original type names (`TipoVillage,Spider`) |
| `start` | `plaza` | `plaza`, `rowN` (middle of the aisle in front of gallery row N), `pathN` (its west end), `parkour`, `pk1`..`pk5`, `goal`, `goal2` |
| `door` | `1,9,1` | exit parameters (tribe, world, chapter of the next level) |
## Layout (2026-11-07 rework)
Island (x 11..43.5, z 9.5..≈34) + strip under the parkour end. Start plaza x 15..21, z 12..19; the
parkour along z = 15.5 to the goal platform with the exit is unchanged. The animal enclosure and
viewing podium are gone. South of the plaza the **gallery**: rows along +x (x 16.6..43), one block of
rows per world (1..8, then the front end), figures before objects, ordered by catalogue category
(characters, player models, enemies, animals, other figures; collectibles, checkpoints, exits,
mechanisms …). Every item stands on a 0.08 high stone pedestal sized to its model (min 0.3 × 0.35,
gap 0.15); in front of every row a 0.75 wide sand aisle. Row posts at x 15.05 in the world colour;
the first row of a world carries one small block per world number (front end: white, none).
The island grows southwards with the gallery (12 rows, z 20.5..≈33).
![gallery from the editor viewer](img/mods/testworld_top.jpg)
## Gallery: every model of the game, without AI
`Gallery.build(wads)` scans the level WADs (t1l1m001…t1l8m006, t6l6m001/2) in order. For each strat
type of a level's MAP (first level that places it wins, names deduplicated):
1. model = the first `address model; setModel` of the type's code (`StratModels.modelOf`, follows
spawn stubs); otherwise the first one in any unit of its import closure (types that show their
model through sub-strats: RisingColumns, FlockOfBirds, spawners …) – not for cameras, triggers
and cut scenes. Types with their own model are handled first, so they win step 3.
2. skinned models also get an animation set: the first one the type's code addresses that has the
model's bone count (bone matrices, no vertex deltas), else any such set of the level.
3. "look" = SHA-256 of the model bytes with every face texture replaced by its pixels, plus the
animation bytes; a type that looks exactly like an earlier one is dropped (TipoLab = TipoCatacombs …).
4. A **display strat** is compiled with `StratCompiler` and appended as its own unit to the
*source* level's STPC:
```
strat GxTipoVillage {
setModel(model:17)
animPlay(anim:60) // skinned models only
loop {
if (!self.animPlaying) { animPlay(anim:60) }
yield
}
}
```
No collision, physics, waypoints, events, texts or sounds – it cannot move, attack, talk,
trigger anything or delete itself. Type fields in MAP: 1 variable, 0 slots, type flags 0, no
parameters, no waypoints (nothing for the engine's "no waypoints → remove" checks to find).
5. `mergeInto(base)` imports all display entries with `StpcMerge.merge` exactly like the editor's
cross-world import: models, animation sets and textures come along (identical ones shared), the
tiny units are appended, the base's own code is relocated (MAP strat codes remapped), TEXT gets
the new pages/entries. One unplaced prototype record per display type is added to the base MAP so
`LevelBuilder` knows the types (`l.strat("GxTipoVillage", …)`); the builder replaces all records.
Result (German CD): **253 entries**, merge +5.95 MB (227 models, 96 animation sets, 93 texture
pages → 111 of 127, 3126 texture entries, 0 sounds/texts); STPC 10.1 MB, WAD 14.6 MB. Scan + merge
≈ 10 s (mod apply).
| World | figures | objects | total |
|---|---|---|---|
| 1 Village | 23 | 27 | 50 |
| 2 Jungle | 11 | 7 | 18 |
| 3 River | 30 | 6 | 36 |
| 4 Jungle day | 13 | 9 | 22 |
| 5 Mountain | 7 | 11 | 18 |
| 6 City | 13 | 17 | 30 |
| 7 Catacombs | 7 | 19 | 26 |
| 8 Lab / end | 30 | 20 | 50 |
| front end | 3 | 0 | 3 |
Not shown (81 of 334 type names): 52 without a model of their own (cameras, cut-scene/dialogue triggers,
force/current boxes, sound/particle effects, LevelDoor (its door is level geometry), Secret,
CheatTeleport, AppearingPlatforms*, MouthPlatform …), 28 that look exactly like an earlier entry,
1 skinned model without a usable animation (EndGameGuardsBottle). `TestWorld.notShown()` lists them
with the reason.
## Engine facts found on the way
* **Strats are only drawn near the player.** Objects farther than ≈12.5 units from the llama are
not rendered (they still exist) – walking along the gallery reveals the rows; a free camera (mod
`freecam`) far away from the llama shows empty pedestals.
* Strat heap: `FUN_0041ae20` allocates in u16-sized word blocks from a heap initialised with
`(short)0x800000 − 3` = 65533 words (≈256 KB) for the strat pool (0x154 bytes × (poolExtra+30)),
collision blocks and per-strat variables – plenty for the gallery (≈280 strats).
## Verified in game (apptest :26, 2026-11-07, host load ≈30)
Mods `testworld` (+ `freecam` with `freeze=false`, noclip F9 for the walk): level loads (no crash),
all rows walked twice (254- and final 253-entry build), figures stand still and play their idle animation in place (screenshot
diff: only limbs change), no dialogue, cut scene or attack, the llama walks through them. The
game stayed responsive (no freeze); frame rate not measurable at that host load. Over the
south edge the llama falls into the sea and respawns at the plaza checkpoint as before.
![village and jungle figures](img/mods/testworld_village.jpg)
![Condor, guards and townsfolk](img/mods/testworld_condor.jpg)
![lab and end-game figures](img/mods/testworld_river.jpg)
## Tests
* `GalleryTest`: every entry is placed once, has a non-empty model (skinned = figure, posed with an
animation), its unit only uses `debugName address setModel animPlay pushProp not jz jmpYield end`,
type flags 0 / no parameters / no waypoints, merged code decodes without errors; rows do not
overlap; `gallery=none` imports nothing, `gallery=a,b,x` places a and b and reports x.
* `TestWorldGoldenTest`: SHA-256 of the test world (default and `start=parkour`) pins the current
output (no Python counterpart any more), 253 gallery objects; jump lab and loading picture still
compared with the Python tools.
* `TestWorldExampleTest` / `examples/testwelt.llamalevel` keep the **original** test world (enclosure,
base-level gallery, `TestWorldBrushes` = port of levels/testwelt.py): the brush project's build is
compared with the level builder's WAD of the same script instead of the mod's output.