Floor Generation Overview
Floor generation is performed as a list of steps, which allows a developer to customize their floor layout at every part of the pipeline. This page covers the basics in what each step is responsible for, and why it is needed.
Overview
A dungeon map can generate without items, enemies, or traps. But at a bare minimum, a dungeon map must generate terrain (plus entrance/exit) in order to complete without errors. There are 4 main options on how to do this:
- Generate a Grid of Rooms, which is them converted into a connected List of Rooms, which are then used to generate tiles.
- Generate a connected List of Rooms, and then use those rooms to generate tiles.
- Generate Tiles directly.
- Load a Pre-made Map.
The type of floor gen you choose in the editor will dictate which options you have:
Generating Tiles Directly
Direct tile generation will randomly generate wall and floor tiles, and then add a start and end point somewhere in the result. To use this approach, make the floor a StairsFloorGen
.
- The first step needed is
InitTilesStep
, which specifies the dimensions of the floor in tiles and initializes a grid of wall tiles.
- Then an algorithm is used to carve out floor tiles out of the dungeon, such as
SpecificTilesStep
orPerlinWaterStep
.
- Finally,
StairsStep
is used to choose a start and end tile on a walkable tile(purple).
While this approach theoretically works has been used in some debug room tests, it has never shown up in practice due to its inflexibility compared to the Grid or List of Rooms methods that follow.
List of Rooms
List of Rooms is an approach that splits generation into rooms and hallways, planning out their dimensions before filling in the tile details. To use this approach, make the floor a RoomFloorGen
.
- The first step needed is
InitFloorPlanStep
, which initializes a space for which to plan out rooms and halls:
- Then, a path generator such as
FloorPathBranch
is run to place the rooms with connecting halls between them (yellow):
- Then, the list of room and halls are then translated into tiles, using
DrawFloorToTileStep
.
It accomplishes this by first asking each room to generate its tiles:
Then, the hall algorithms are asked to generate:
This leaves us with all floor tiles:
- Lastly, the start and end tile are marked, by first selecting 2 separate rooms (pink) and then choosing a tile (purple) in each room to put the marker. The step responsible for this is
FloorStairsStep
Room Floors are somewhat uncommon and has few templates to choose from for floor shape. However it's possible to vary the floor shape a lot simply by choosing different room types to generate with.
Grid of Rooms
Grid of Rooms is an approach that starts generation off with a grid of rooms, before planning out their dimensions and then filling in the tile details. It is basically the List of Rooms approach with extra steps. To use this approach, make the floor a GridFloorGen
.
- The first step needed is
InitGridPlanStep
, which initializes a grid of cells:
- Then, a path generator such as
GridPathBranch
is run to place rooms in the grid (blue) with connecting halls between them (yellow):
Each room and hall filled in here are also assigned an algorithm at this step.
- The grid rooms and grid connectors are then translated into a list of rooms and halls, using
DrawGridToFloorStep
.
It accomplishes this by first having each room algorithm then choose its size and location:
The rooms then signal their connection requirements to the halls, which then have their sizes chosen:
Then finally by writing it out to an actual list of rooms and halls:
- Then, the list of room and halls are then translated into tiles, using
DrawFloorToTileStep
.
It accomplishes this by first asking each room to generate its tiles:
Then, the hall algorithms are asked to generate:
This leaves us with all floor tiles:
- Lastly, the start and end tile are marked, by first selecting 2 separate rooms (pink) and then choosing a tile (purple) in each room to put the marker. The step responsible for this is
FloorStairsStep
Grid Floors are the most common approach to dungeon generation, with a large number of unique templates for floor shape.
Pre-Made Map
Pre-made maps directly load a file from the Data/Maps/ directory to be used as a dungeon map. To use this approach, make the floor a LoadGen
.
Only one step is needed, which is the file-loading step: MappedRoomStep
Pre-made maps are often used for fixed dungeon floors such as the reward rooms at the end of a dungeon, or secret rooms.
Priority System
Floor generation is broken down into an ordered list of steps, each assigned a priority. The priority determines at what point in the generation process the step should be performed, with a lower number means a step will execute earlier. While these priority numbers do not need to be obeyed for modding, they are the numbers that base PMDO uses. Priority becomes especially handy when using Zone Steps to plan out dungeon features across multiple floors instead of a single one.
Steps Summary
While the Overview section covers the bare minimum steps to generate without error, you may notice that generating a map only with those steps will have no name, no music, no time limit, and even no textures, forcing you to rely on the minimap to understand the terrain. Below is a table of commonly used steps, what priorities PMDO places them in, and what they are used for.
Priority | Step | Description |
---|---|---|
-7 | MappedRoomStep | Loads a dungeon map to use as this floor's layout, including its entities and properties. |
-6 | MapDataStep | Sets the music, time limit, and darkness of the floor. |
-6 | MapNameIDStep | Gives the map a name. |
-6 | MapTitleDropStep | Makes the map name show up before fading in. |
-6 | MapEffectStep | Sets event data for the floor. |
-5 | InitGridPlanStep | Initializes a grid for GridFloorGen. |
-4 | GridPathBranch, GridPathCircle, GridPathTwoSides, etc. | Generates a path of rooms and halls for GridFloorGen. |
-4 | SetGridDefaultsStep | Turns some rooms into halls (1 tile size), for GridFloorGen. |
-4 | ConnectGridBranchStep | Connects some adjacent rooms, for GridFloorGen. |
-4 | CombineGridRoomStep | Combines some rooms into larger rooms, for GridFloorGen. |
-3 | InitFloorPlanStep | Initializes a list of rooms and halls for RoomFloorGen. |
-3 | DrawGridToFloorStep | Initializes a list of rooms and halls and populates it with the grid from GridFloorGen. |
-2 | FloorPathBranch | Generates a path of rooms and halls for RoomFloorGen. |
-1 | InitTilesStep | Sets the floor dimensions and initializes a grid of tiles, for StairsFloorGen. |
-1 | DrawFloorToTileStep | Creates a grid of tiles and draws onto it based on the list of rooms and halls from a RoomFloorGen or GridFloorGen. |
0 | SpecificTilesStep | Sets the floor to specific tiles. Only used for debug. |
0.1 | UnbreakableBorderStep | Adds a border of unbreakable tiles at the edge of the map. |
0.3 | AddTunnelStep | Digs tunnels into the walls starting from a room. |
1 | MoneySpawnStep | Sets the spawn table for money on this floor. |
1.1 | ItemSpawnStep | Sets the spawn table for items on this floor. |
1.2 | MobSpawnStep | Sets the spawn table for mobs on this floor. |
1.2 | MobSpawnSettingsStep | Sets the rules for enemies respawning on the floor. |
1.3 | TileSpawnStep | Sets the spawn table for traps on this floor. |
2 | FloorStairsStep | Places the start point and the end stairs on different rooms of the floor, for RoomFloorGen or GridFloorGen. |
2 | StairsStep | Places the start point and the end stairs on different tiles of the floor, for StairsFloorGen. |
3 | PerlinWaterStep | Adds water/lava/etc. using Perlin Noise. |
3 | BlobWaterStep | Adds water/lava/etc. by placing several blobs made from cellular automata. |
4 | MapTextureStep | Defines the textures for floors, walls, and water. |
4 | MapDictTextureStep | Defines the textures in a more advanced way, needed if the layout uses grass. |
5 | RandomRoomSpawnStep<?, EffectTile> | Spawns traps in random rooms. |
5 | SpacedRoomSpawnStep<?, EffectTile> | Spawns traps in random rooms, taking care not to place in the same room or adjacent rooms. |
6 | TerminalSpawnStep<?, MoneySpawn> | Spawns money in dead-end rooms. |
6.1 | DueSpawnStep<?, InvItem, MapEntrance> | Spawns items based on how far they are from the starting room. |
6.2 | PlaceRandomMobsStep | Randomly places enemies on the map. |
7 | DetectIsolatedStairsStep | Testing step: Looks for a path from start to end and throws an error if none can be found. |
7 | DetectTileStep | Testing step: Checks to see if a certain tile can be found on the map and throws an error if none can be found. |
The sections below go into more detail of what each priority is typically used for, as well as less commonly used steps used in those priority brackets.
Floor Data
Priority -6
Examples:
- MapDataStep
- MapEffectStep
- MapNameIDStep
- DefaultMapStatusStep
- MapTimeLimitStep
Grid Creation
Priority -5
Examples:
- InitGridPlanStep
Grid Path Generation
Priority -4
Examples:
- GridPathBranch
- GridPathCircle
- GridPathTwoSides
- GridPathGrid
- GridPathBeetle
- GridPathTiered
- SetGridDefaultsStep
- ConnectGridBranchStep
- CombineGridRoomStep
Room List Creation
Priority -3
Examples:
- InitFloorPlanStep
- DrawGridToFloorStep
Room List Generation
Priority -2
Examples:
- FloorPathBranch
Tiles Creation
Priority -1
Examples:
- InitTilesStep
- DrawFloorToTileStep
Tiles Generation
Priority 0
Examples:
- SpecificTilesStep
Spawn Tables
Priority 1
Examples:
- MoneySpawnStep
- ItemSpawnStep (Priority 1.1)
- MobSpawnStep (Priority 1.2)
- TileSpawnStep (Priority 1.3)
Exits
Priority 2
Examples:
- FloorStairsStep
- StairsStep
Water
Priority 3
Examples:
- PerlinWaterStep
- BlobWaterStep
Textures
Priority 4
Used to be here because textures were actually placed here, but now only assigns textures to the map itself and lets the map compute them after ALL steps are done. Thus, this step is the least dependent on its current position in the steps.
Examples:
- MapTextureStep
- MapDictTextureStep
Tile Spawns
Priority 5
Examples:
- RandomSpawnStep
- DueSpawnStep
- TerminalSpawnStep
Spawns
Priority 6
Examples:
- All steps in Tile Spawns
- PlaceRandomMobsStep
- PlaceDisconnectedMobsStep
- PlaceNoLocMobsStep
Debug Checks
Priority 7
These gen steps are used to check the dungeon for issues, and throw an error if they're found. Useful for stress testing.
Examples:
- DetectIsolatedStairsStep
- DetectTileStep