Dungeon Generator for Dungeons and Dragons

Monster and terrain generation

Monsters

For the rooms themselves, I wanted to add a little bit more than just emptiness. I’ve copied the method of the book Dungeon Master Guide on page 82, which contains an encounter generation method for dungeon masters. It is the most well know and common method. For each room with combat assigned to it, it will generate a random terrain and add random monsters to it. To explain it simply for monsters, for each monster you add to an encounter, the difficulty increases by their experience points. For each of the four difficulties (easy, medium, hard and deadly,) a party has a threshold for when an encounter is classified as that difficulty. For example, 5 level 1 adventurers have a medium threshold of 250, so when you add 300 experience worth of monsters to the combat, it is considered medium. This experience of the monsters is also multiplied by the number of monsters, but that is the only additional calculation other than adding the sum of experience (Wizards of the Coast, 2014). Two different monsters (three with boss) is fine, one is boring and four or more gets complicated.

public void PopulateRoom(int experienceBudget)
{
    // Initialize and declare values
    int experienceSpend = 0;
    float modifier = 1;

    // Randomly select two monsters from the selection
    Monster monsterOne = GetMonster()
    Monster monsterTwo = GetDifferentMonster(monsterOne)

    // Add the boss in the final room
    if (IsFinalBossRoom())
    {
        AddMonster(GetBoss());
        experienceSpend = GetExperienceSpend(monsters); 
        // Modifier stays at 1
    }

    // While we can experienceSpend experience-
    while (experienceSpend * modifier < experienceBudget)
    {
        // Add random monster
        if (UnityEngine.Random.Range(0, 2) < 1)
        {
            AddMonster(monsterOne);
        }
        else
        {
            AddMonster(monsterTwo);
        }

        // Change modifier correctly to the monster count
        modifier = GetModifier(monsters.Count);
        experienceSpend = GetExperienceSpend(monsters);
    }
}

Terrain

For the terrain generation I’ve created an inheritance class and an array containing the classes that inherit from it. These classes contain a function to generate terrain in the room with. I could create a function that fills the entire room with a tile or just creates a large hole in it. When a room contains combat, I randomly choose a type of generation and a random tile to use (for example, I can randomly get a generation that generated a few circles of terrain that damages a character). The chances for the generation are ratio based, if I have a value of 1 for no terrain and 2 for hole like generation, I have a 1:2 chance respectively (in the code for example, I roll a number from 1 to 3, the total of the ratios combined. If I roll 2, it checks the first index ratio and is higher than 1. It then is reduced by 1 and checks if the new number 1 is lower than 2. Since it is, it chooses the hole like generation).

To prevent weird generations like walls that can likely block a path or movement reduction terrain that will have little impact with the type of generation, I also disable tiles generations can use with terrainViability.

The shapes of the rooms have been done exactly the same as the terrain generation, except it doesn’t use the code where it randomly selects a tile. Figure 10 for example has a cross shape.

private RoomTerrain[] terrains; // Following classes inherit from this
[SerializeField] private NoTerrain noTerrain;
[SerializeField] private HoleTerrain holeTerrain;
[SerializeField] private CellularAutomataTerrain cellularAutomataTerrain;

// Terrain tiles: Damaging, solid wall, movement reduction and cover
[SerializeField] private bool[,] terrainViability = new bool[,]
{
    { true, true, true, true },
    { true, true, true, true },
    { true, false, true, true } // Cellular automata and walls can generate impossible rooms.
};

public void CreateTerrains()
{
    terrains = new RoomTerrain[] { noTerrain, holeTerrain, CellularAutomataTerrain };
    
    int random;
    for (int i = 0; i < rooms.Count; i++)
    {
        // Check if this is a combat room
        if (IsCombat(rooms[i])
        {
            for (int j = 0; j < terrains.Length; j++)
            {
                // Generate terrain
                rooms[i].CreateTerrain(RandomTerrain(terrains), RandomTile(terrainViability));
                break;
            }
        }
    }
}

Public class RoomTerrain ()
{
    public virtual void CreateTerrain(Tile tile)
    {
        // Inheritance code
    }
}
Figure 9. Generation that randomly creates squares of terrain and used one type of monster (which can still happen).
Figure 10. Cellular Automata generation that has spread damaging terrain across the room. Also the boss fight.

Related Posts