6.9 KiB
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: 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):
- model = the first
address model; setModelof 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. - 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.
- "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 …).
- A display strat is compiled with
StratCompilerand appended as its own unit to the source level's STPC: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).strat GxTipoVillage { setModel(model:17) animPlay(anim:60) // skinned models only loop { if (!self.animPlaying) { animPlay(anim:60) } yield } } mergeInto(base)imports all display entries withStpcMerge.mergeexactly 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 soLevelBuilderknows 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_0041ae20allocates 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.
Tests
GalleryTest: every entry is placed once, has a non-empty model (skinned = figure, posed with an animation), its unit only usesdebugName 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=noneimports nothing,gallery=a,b,xplaces a and b and reports x.TestWorldGoldenTest: SHA-256 of the test world (default andstart=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.llamalevelkeep 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.



