Dungeon Generator for Dungeons and Dragons

Room content

Figure 11. Some tables and beer barrels in the kitchen.

It would also be nice if the rooms has something else than just terrain. Many actions in Dungeons and Dragons are possible, like grabbing a glass and smashing it in someone’s  head. You don’t need complex things to get this done, having a bookshelf to throw down can be enough satisfaction. Almost any furniture really works.

Every room in the dungeon gets a function assigned to it. These functions aren’t gameplay functions, they are what buildings would realistically have like a place to make food or a common room where the inhabitants can relax. I’ve used the following list from the Dungeon Master Guide on page 293 of the lair (Wizards of the Coast, 2014) where I’ve also sorted the rooms if the generation should always contain it.

public string[] requiredFunctions = new string[] {
    "Kitchen",
    "BedRoom",
    "ThroneRoom",
    "Storage",
    "Guardroom" };

public string[] optionalFunctions = new string[] {
    "Armory",
    "AudienceChamber",
    "Banquet",
    // And more
};
Figure 12. How it looks in the editor

To determine the room functions, every required function is assigned to a random room. If the room already has a function, the code tries again. Then for the other rooms, it assigns a random function to it.

// Required functions
for (int i = 0; i < requiredFunctions.Length; i++)
{
    // Get random room
    Room randomRoom = GetRandomRoom();

    // If it doesn't have a function yet-
    if (randomRoom.function == "")
    {
        // Create content and text
        randomRoom.CreateFunction(requiredFunctions[i]);
    }
    else
    {
        // Try again
        i--;
    }
}

// Optional rooms
for (int i = 0; i < rooms.Count; i++)
{
    // For each room without a function, create a random function and give it content and text
    if (rooms[i].function == "")
    {
        rooms[i].CreateFunction(requiredFunctions[GetRandomFunction()]);
    }
}

For each room, it needs to generate from a list of objects depended on its function. It choses a random amount to generate and then either generates this object in the middle or the side of the room. It keeps track of where it can place objects with a two dimensional Boolean array. If it can’t place the object, it tries again.

// Function for when to generate following content
public string function;

public GameObject[] objectsToGenerate;
public int minAmount;
public int maxAmount;
public int bigestSize; // The largest object

public float generateFromWallX; // Used for when generating away from the middle
public float generateFromWallY; // Used for when generating away from the middle
public GeneratePositionType positionPlacement; // Generation type

public void Generate(Room room, Tile[,] grid)
{
    int randomAmount = RandomAmount(); // Amount to generate
    
    // Positions that can/can't be placed at
    bool[,] occupationGrid = new bool[room.xSize, room.ySize]; 
    bool recursion;
    Vector2 position;

    OccupyWalls(occupationGrid);

    if (positionPlacement == GeneratePositionType.Middle)
    {
        for (int i = 0; i < randomAmount; i++)
        {
            // Random position
            Position = RandomPosition(room);

            // Check if generation is possible
            if (ValidPosition(occupationGrid, position)
            {
                ControlRecursion()
                recursion = true;
            }

            // Instantiate
            if (!dontGenerate)
            {
                GameObject.Instantiate(RandomObject(objectsToGenerate))], 
                    position, 
                    Quaternion.identity);

                OccupyPosition(position);
            }
        }
    }
}


if (positionPlacement == GeneratePositionType.Side)
{
    for (int i = 0; i < randomAmount; i++)
    {        
        // Choose a random side (Horizontal, vertical)
        if (RandomSide())
        {
            int xRandom = RandomSizePosition(room.xSize);

            // Choose a random side (Left, right)
            if (RandomSide())
            {
                position = SidePosition(left, xRandom)  

                // Check if generation is possible
                if (ValidPosition(occupationGrid, position))
                {
                    ControlRecursion()
                    recursion = true;
                }
                
                // Instantiate
                if (!recursion)
                {
                    GameObject.Instantiate(RandomObject(objectsToGenerate))], 
                        position, 
                        Quaternion.identity);

                    OccupyPosition(position);
                }
            }
            // Other side generation possibilities continues on
        }
    }
}

From here it is just quantity rather than quality and just brain storming ideas.

Related Posts