Birdoggydog's Builds

Making one dungeon generator mix every way up and down

Lifts, ladders, spirals and turning stairs now come from one table of rates, with corridors that bend and floors that stack by the real ground.

The dungeon generator now lays every way up and down by default, from one table of rates: ladders, lifts, spirals between floors, spirals within a floor, stairs and ramps that turn a corner, and sunk, raised and graded rooms. After I watched the turning stairs and spirals, I said I wanted rising to be a rule, with all of it coming from one random generator in one dungeon. Asking for --rising off still gives the old output, byte for byte.

56 seconds in one generated three-floor dungeon: a lift down, a stair turning a curved corner at about 0:14, a spiral up at about 0:28, a ladder up at about 0:35, and a graded way into a sunk room at about 0:49.

How does one table decide everything?

RATES in tools/dungeon_rising.py holds a chance for each kind, per floor. A floor gets 1 to 3 corridor bends, and each bend corner has a 0.5 chance of a curve mark. A sunk room is 0.7, a raised room 0.35, a graded room 0.3, a spiral within a floor 0.6, and a spiral between a pair of floors 0.6. Each way into a sunk or raised room is a ramp 0.35 of the time and a stair otherwise. A dungeon of several floors always gets a lift and a ladder between each two floors.

What a floor wants is drawn from its own seed and level, not from the try. The generator makes several tries of a floor and keeps the best. If each try rolled its own wants, keeping the fullest one would quietly raise every rate.

Why did the corridors need bends?

The generator’s corridors ran mostly straight from room to room, so there was almost never a corner to turn a stair round. A bend takes a straight run of plain corridor, fills its middle with rock, and steps the way one square aside, which makes four right-angled corners where there were none. It only happens where the squares the jog takes are rock and touch no other open square, so no two ways can meet. Three times in four the bend goes near a room’s way in, within 3 squares, so a stair coming out of the room turns on it.

A sunk room is then a room with no entrance, exit, lift or ladder in it that isn’t by the goal, dropped 1 m. Each way into it becomes plain corridor squares out to the first right-angled corner within 6 squares, and at least one way has to turn. Everything laid is taken off again if the ground refuses it or a hard check fails. The squares I draw myself are never sunk, raised or cut.

Why did the floors need to read the ground?

Floors were stacked with 2 m of rock between them. A part sunk 2.5 to 4.5 m would cut through the floor under it, which is why spirals were only laid on a dungeon of one floor. Now a floor stands under the one above by the real top of its ceiling, and deeper under any part of the upper floor that is sunk. The rule takes the lower floor’s tallest roof within reach of what the upper floor digs and, under a sunk part, adds how deep it is sunk.

The rule exists twice, in the game’s floor stacking and in the Python the generator and checks use. A test makes sure the two agree on a generated three-floor fixture. A new check wants a spiral between floors to have a winding that fits the rise the stacking gives it.

Eight frames from the film: a lift doorway, a stair turning a curved orange-striped corridor, a lift shaft, a spiral stair, a ladder and a room sunk below the floor.

The film’s contact sheet, with its captions.

What did the first pass get wrong?

Two things. The chooser ranked “laid more rising” above “has its secrets” and above how many of my stored rooms were used. A draft on the designer page lost its secrets, and “use my rooms” kept a try with a single stored room. The order is now secrets first, then stored rooms laid, then rising laid, then whether the goal is seen early, then the score. Rising never beats a try with its secrets.

The second was worse. Rising could sink a room I had drawn myself, which showed up in a fixture with two drawn rooms. Now the drawn squares are kept out of everything rising touches, and the check that my pins are kept also holds their floor level.

Did it hold up?

Over 40 one-floor seeds nothing failed. They laid 87 bends, 70 turning stair squares, 87 ramps, 33 sunk rooms, 14 raised rooms, 11 graded rooms and 26 spirals within a floor. Over 20 three-floor seeds nothing failed either: 40 lifts, 60 ladders, a spiral between floors in 26 of 40 pairs, 43 sunk rooms and 109 bends. With rising off, 6 one-floor and 2 three-floor seeds came out byte-identical to before. A walking test goes from the entrance down two lifts to floor 3, up the spiral and the ladder back to floor 1, 268 squares in all.

The designer page doesn’t draw the sunk and raised parts of a generated floor yet, though it now carries them in the sheet. I also haven’t laid a raised gallery, a ledge around a room, or chosen heights by the kind of room.