using System; using System.Collections.Generic; using System.Linq; using System.Text; using Unity.VisualScripting; using UnityEngine; using Random = System.Random; namespace DungeonGenerator { public class DungeonGenerator { private const int SIDE_LENGTH_OF_MONSTER = 4; private const int SIDE_LENGTH_OF_NORMAL = 2; private const int WIDTH_OF_BOSS = 10; private const int HEIGHT_OF_BOSS = 6; private int _xLength = 40; private int _yLength = 28; public DungeonMap GenerateDungeon(int length, float monsterRoomRatio) { _xLength = 40; _yLength = 28; Random random = new Random(); DungeonMap dungeonMap = new DungeonMap(_xLength, _yLength); dungeonMap.AddRooms(GenerateEntranceRooms(_xLength, _yLength, random.Next(1,4))); dungeonMap.AddRoom(GenerateOnlyBossRoom(_xLength, _yLength, WIDTH_OF_BOSS, HEIGHT_OF_BOSS)); EvenDisperser disperser = new EvenDisperser(_xLength, _yLength, dungeonMap.GetUnoccupiedPoints()); //TODO calculate L and W from length int numberOfMonsterRooms = 7; // TODO: Calculate from ratio for (var i = 0; i < numberOfMonsterRooms; i ++) { dungeonMap.AddRoom(disperser.GenerateAndPlaceRoom( SIDE_LENGTH_OF_MONSTER, SIDE_LENGTH_OF_MONSTER, RoomType.Monster)); } return dungeonMap; } private Room GenerateOnlyBossRoom(int xLengthOfDungeon, int yLengthOfDungeon, int width, int heigth) { // Place monster room in the middle third int middleAreaX = xLengthOfDungeon / 3; int middleAreaY = yLengthOfDungeon / 3; Random random = new Random(); int bossX = middleAreaX + random.Next(0, middleAreaX - width); int bossY = middleAreaY + random.Next(0, middleAreaY - heigth); return new Room(RoomType.Boss, width, heigth, new Point(bossX, bossY)); } private enum Side { Top, Right, Bottom, Left } private List GenerateEntranceRooms(int xLengthOfDungeon, int yLengthOfDungeon, int numberOfEntranceLines) { if (numberOfEntranceLines > 4) { throw new Exception("Number of entrance lines cannot be greater than 4"); } const int numEntranceRooms = 12; List entranceRooms = new List(); Random random = new Random(); Dictionary sidesToEnterOn = new() { { Side.Top, 0}, { Side.Right, 0}, { Side.Bottom, 0}, { Side.Left, 0} }; // Randomly assign starting lines to sides of dungeon for (var i = 0; i < numberOfEntranceLines; i++) { while (true) { Side side = (Side)random.Next(0, 4); if (sidesToEnterOn[side] < 2) { sidesToEnterOn[side] += 1; break; } } } int roomsPerLine = numEntranceRooms / numberOfEntranceLines; int bottom = yLengthOfDungeon - SIDE_LENGTH_OF_NORMAL; int oneRoomFromBottom = bottom - SIDE_LENGTH_OF_NORMAL; int right = xLengthOfDungeon - SIDE_LENGTH_OF_NORMAL; // Generate entrance lines on each side switch (sidesToEnterOn[Side.Top]) { case 2: // Add half of points for this entrance line to the top left side for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i,0))); } // Add the rest of the points for this entrance line to the top right side. for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right - i,0))); } break; case 1: int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL); for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL,new Point(startOfLine + i, 0))); } break; } switch (sidesToEnterOn[Side.Right]) { case 2: // Add points for this entrance line to the top right side for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, i + SIDE_LENGTH_OF_NORMAL))); } // Add the rest of the points for this entrance line to the bottom right side. for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, oneRoomFromBottom - i))); } break; case 1: int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL); for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(right, startOfLine + i))); } break; } switch (sidesToEnterOn[Side.Bottom]) { case 2: // Add half of points for this entrance line to the bottom left side for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(i, bottom))); } // Add the rest of the points for this entrance line to the bottom right side. for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point((xLengthOfDungeon - 1) - i, bottom))); } break; case 1: int startOfLine = GetStartOfCenteredLine(xLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL); for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(startOfLine + i, bottom))); } break; } switch (sidesToEnterOn[Side.Left]) { case 2: // Add half of points for this entrance line to the top left side for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, i + SIDE_LENGTH_OF_NORMAL))); } // Add the rest of the points for this entrance line to the bottom left side. for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, oneRoomFromBottom - i))); } break; case 1: int startOfLine = GetStartOfCenteredLine(yLengthOfDungeon, roomsPerLine, SIDE_LENGTH_OF_NORMAL); for (var i = 0; i < roomsPerLine * SIDE_LENGTH_OF_NORMAL; i += SIDE_LENGTH_OF_NORMAL) { entranceRooms.Add(new Room(RoomType.Entrance, SIDE_LENGTH_OF_NORMAL, SIDE_LENGTH_OF_NORMAL, new Point(0, startOfLine + i))); } break; } return entranceRooms; } private int GetStartOfCenteredLine(int length, int numberOfRooms, int sizeOfRoom) { int midpoint = length / 2; return midpoint - (numberOfRooms * sizeOfRoom / 2); } } }