Procedural generation in Theralite

Thomas
June 22, 2025

Where do we use procedural generation?

Being a classic roguelike game, Theralite contains a lot of procedural content generation. In this short devlog I’ll highlight some of themost interesting areas.

Zones and Biomes

The world of Theralite is assembled by zones. A zone is an area consisting of a given number of levels. To guarantee a visual representation each zone uses the same biome tileset for the generated levels. We add some variety by allowing multiple tilesets per zone. For each generated level a different tileset could be chosen.
And of course each tileset contains a set of different wall tiles and a set of different ground tiles to allow more visual randomness.
Each zone has it’s own assigned LevelGenerator that is responsible for generating random levels matching the “zone style”.
Currently Theralite uses three different level generation algorithms which we will describe in a moment. But first let’s finish the zones.
Zones have a number of configuration parameters which can be set randomly or “hard coded”. Currently they are hard coded to ease testing of game mechanics. The most important parameter is “is this zone unlocked/opened for the player or not”. The player has to kill boss monsters to require keys which unlock other zones.
Zones are also connected with other zones via exit areas. We can specify on which level of which zone should be an exit to the first level of another zone. This way we can connect our zones and define the game world.
At the moment our game world and the zone connections are hard coded but the implementation allows for a total randomization of this world generation. We could place the player in any zone and let him progress through the world by unlocking another (reachable) zone after killing a boss monster for example.

Level Generators

Now let’s look a bit into our level generators that are responsible for the look of the levels.
Although I said we have three different level generators we do have actually four.
The simplest one generates our current HUB (= starting) level. This one level zone only contains exit areas to reach the zones we have already implemented (remember, testing game mechanics…).
This level generator just creates a simple rectangle with indestructible walls and tries to place the required exit areas randomly inside this level without overlapping.
The other generators are more sophsticated ;-)

The Mines level generator

This “walker” level generator is a modern algorithm, used for example by the indie classic “Nuclear Throne” from former dutch studio Vlambeer.
So how does our own implementation work?

  1. Choose the size of the level
  2. Mark each tile in the level as VOID/unspecified.
  3. Start at the center of the level and choose a random direction (up, down, left, right)
  4. Mark the current tile as FLOOR which means it’s an empty space where the player and monsters can walk around.
  5. Take a fifty percent chance if you keep the direction or choose a new random direction (up, down, left, right)
  6. Walk one tile in that direction.
  7. Go back to 4 unless you have walked around the level for a certain number of times (number of tiles in the level * 0.75)
  8. Add some (1 to 5) clusters of INDESTRUCTIBLE WALLS in the remaining VOID areas
  9. Find all VOID tiles that have no neighbor and make them ROCKS
  10. Make the border VOID tiles INDESTRUCTIBLE WALLS so the player can’t exit the level
  11. All remaining VOID tiles become normal WALLS or JEWELWALLS or INDESTRUCTIBLE WALLS, based on some random value
  12. Place a shop room inside the level
  13. Add an exit to the levels above and below
  14. Add an exit area if this level in this zone should have one.

The way the walker generator works assures that each FLOOR or empty tile can be reached by the player – there will be no free areas that you can’t walk to.
Our walker generator is also able to deal with an arbitrary tunnel width (we use a width of 3). So instead of just marking 1 tile as FLOOR we mark 3 tiles as FLOOR, so the current one and then the tiles left and right of it, based on the current direction.
This is the most complex level generator we have in our game, the remaining ones are easier!

The Settlements level generator

This one is the classic Rogue level generator. Yes, I mean the original Rogue game from 1980 – the ancestor of all roguelike games!
So how does this algorithm work?

  1. Choose the size of the level
  2. Divide the level into a grid (we use “cell” or room sizes of 16 by 16) so the level is divided into grid cells of 16 by 16 tiles
  3. Each grid cell gets a flag indicating if it is connected and an array of grid cells it is connected to (the cells are numbered from 1 to n, starting top left going down to bottom right, row by row)
  4. Pick a random grid cell and mark it connected.
  5. While there are unconnected neighbor cells, connect to one of them, make that the current cell, mark it connected and repeat (this will create a path of connected cells with a random length)
  6. Now there are still unconnected cells left. While there are unconnected cells, try to connect them to a random connected neighbor. You might have to iterate over those unconnected cells several times before all cells are connected to at least one other cell
  7. Add some additional random connections between neighbor cells
  8. Now generate the rooms and corridors. The first cell from the path (see 5.) will become a room and get the exit upwards, the last cell from the path will become a room get the exit downwards. Every other cell has a 25% chance of becoming just a hallway instead of a room
  9. Each room must be smaller than a cell (so up to 16 by 16 tiles). Corridors must be carved so that they connect the rooms. Hallways are just “connection points where two or more corridors meet
  10. The rest of the level is filled with walls, jewel walls, indestructible walls and an indestructible wall around the whole level
  11. One of the rooms will be used as a shop without using a predefined room template (explained a bit later)

The Barracks level generator

This is another pretty simple level generator.

  1. Again, choose the size of the level
  2. Create an empty level, just surrounded by the indestructible wall around the level
  3. Place a shop room anywhere in that level
  4. Choose a random number between 5 and 10 and repeat 5. to 7. for this amount
  5. Choose a random barrack room template
  6. Choose a random position in the level and try to place the room template without overlapping with other rooms already placed (20 tries allowed)
  7. If a matching position is found, create the room at this place.
  8. Now a few rooms are placed but that would look just boring. So we randomly place 10 to 15 “rock areas” between the rooms. Those rock areas start on a free tile and are made up of 20 to 30 walls, placed by a simple walker algorithm, similar to the mines level generator, assuring that the rock areas are not placed inside rooms.

That’s pretty much it. The only thing left worth mentioning is the rooms.

Rooms

Rooms are predesigned elements of Theralite. There are exit areas, shop rooms, barrack rooms, (yet unused) storage rooms and (yet unused) temple rooms and we could add even more room types if needed.
The game contains a room editor that allows to design any room up to a maximum size of 25 by 25 tiles although I doubt we would ever need a room that big. But who knows ;-)
There is a standard building tileset but you can use any other tileset too when designing a room.
Also decoration elements can be placed or the position of the shop keeper in a shop room for example.
For exit areas there is a way to specify the name of the zone this exit area should lead to.
When the level generators request a room template to be placed they will get a random one of the available ones and the code also returns a randomly rotated version of that room template to offer more variety again.
Below is a screenshot of the builtin room editor.

That's all?

For now, that’s it about procedural level generation.
But another blog entry explaining generation of enemies (based on zone, difficulty and so on), items, quests and more could follow ;-)