Entry 30
The dungeon generator ported to Rust, with its tables as generated data
Documented in Dungeon generation.
Filestools/dungeon_tables.pytools/test_dungeon_rs.pycrates/piney-data/src/dungeoncrates/piney-data/tests/dungeon.rscrates/piney-data/examples/dungeon_snapshot.rsdocs/engine/dungeon.md
19 reproduced DUNGEON::Generate in tools/dungeon.py and checked it
against the game in eemu. This entry carries it into the port as
piney_data::dungeon, following the pattern of 27: the engine's tables
are extracted once into generated Rust, and asset data is read from the disc
at run time. A helper agent did the port; I re-ran its checks.
The tables
tools/dungeon_tables.py reads through dungeon.py's Data, which finds
each table through the code that uses it. It writes
crates/piney-data/src/dungeon/inf.rs (425 KB, exempt from rustfmt, with a
--check mode). It holds:
- the 31
ROOM_INFOtables (713 rows), reached throughMakeFloor's four jump tables. Each row has a model name, an exit mask (Exits(NORTH | UP)) and aRotation. symroom,DungeonName/DungeonName2anddungeonData.- the eight dummy-name patterns
SetAllGimsearches, read from its code and asserted equal todungeon.py's. - the dungeon-type rule as tables, and a
SaveFlagenum: Infection'ssaveData+0x6772test, and Mutation's bit 62 of+0x5ec8(25). - the 88 hand-made story dungeons (
EditDungeon), with 2,794ROOMDATAand 657GIMMICKDATArows.
The story layouts are level data rather than engine rules, and make up 264 KB of the file. The user was asked and chose to commit them as port data, like the placement tables.
The file holds no player-facing text.
The Rust
generate(&Tables, &Params, &DummySource). Takes the seed, dungeon type,levelMax/roomMax, server, volume, first keyword, field type and area code. It returns every floor:- the 80 x 80 realmap;
- the rooms, with position, size, exits and the chosen model, rotation, minimap code and dummy rolls;
- the stairs, restarts and start positions;
- the Gott statue room, the kept gimmicks and the final RNG.
GenerateError::NoDownStairs. Covers the case where the game would loop forever.- Dummy counts. Each room model's item-box and
psdummies are counted from the dungeon's CCS file (Dummies::load), following ExtObj asccMatchIndexdoes. The counts are not a table, because they are asset data. story(&Tables, event, index)andreal_map. These areMakeRealMap, for the story dungeons.
Checked
tools/test_dungeon_rs.py builds an example binary
(examples/dungeon_snapshot) and compares it with dungeon.py field by
field:
- 360 random dungeons: all 10 types, servers 0-4, volumes 1-4, word 131,
lake starts, and the five cases
test_dungeon.pyruns in the game; 1,293 floors, 12,351 rooms, 742 restarts, 339 statue rooms and 15,829 kept gimmicks, with 0 mismatches; - all 88 story layouts;
- the type rule on 624 inputs per rule;
- the dummy counts of all 18 dungeon CCS files;
- that the generated file is current.
A deliberately changed stair threshold broke 83 of the 360 cases, so the comparison bites. On integration I re-ran it: 5 tests, OK. The six Rust unit tests (fixed seeds, zero dummy counts, numbers only) pass.
the story dungeons' room models (MakeRoom(ROOMDATA*)); the item boxes, circles and idols WORLD_MAN::EntryGimmick places later; the start positions of rooms without a lake entry (OBJ_0ppp); the other volumes' tables (the tool already runs on Mutation, and each volume would be one more generated file).