package dev.llan.model.board.generation; import dev.llan.model.Game; import dev.llan.model.board.*; import dev.llan.model.board.Tile.TileType; import dev.llan.model.board.generation.Room.RoomType; import dev.llan.model.board.generation.hallways.Hallway; import dev.llan.model.pieces.GamePieces; import dev.llan.model.pieces.enemies.EnemyFactory; import dev.llan.model.pieces.inanimates.Door; import dev.llan.model.pieces.inanimates.Inanimate; import dev.llan.model.pieces.inanimates.TreasureChest; import dev.llan.model.pieces.player.MainCharacter; import dev.llan.model.pieces.enemies.Enemy; import dev.llan.model.pieces.player.Player; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.Random; import static dev.llan.model.board.generation.Constants.*; public class MapInitialization { private Player player; private List enemies; private List inanimates; private final Grid grid; private final Game game; private Room start; public MapInitialization(Game game, GameMap map) { this.game = game; this.grid = map.getGrid(); enemies = new ArrayList<>(); inanimates = new ArrayList<>(); } private void reset() { enemies = new ArrayList<>(); inanimates = new ArrayList<>(); player = null; } public GamePieces generateMap(Optional player) { System.out.println("[INIT] Generating new map"); reset(); int rowSize = grid.getRowSize(); int colSize = grid.getColSize(); Tile[][] newMap = new Tile[rowSize][colSize]; List viablePoints = getAllViablePoints(rowSize, colSize); int numRooms = generateNumberOfRooms(); List rooms = new ArrayList<>(); for (int i = 0; i < numRooms; i++) { Room room = generateRandomRoom(viablePoints); rooms.add(room); if(viablePoints.isEmpty()) { break; } } placeRooms(newMap, rooms); selectStartRoom(rooms, grid.getRowSize(), grid.getColSize()); List hallways = generateHallways(rooms); placeHallways(hallways, newMap); grid.setGrid(newMap); setDisplays(newMap); generateObjectClusters(rooms, player); fillRemainingTiles(newMap); return new GamePieces(this.player, enemies, inanimates); } private int generateNumberOfRooms() { return new Random().nextInt(MAX_ROOMS - MIN_ROOMS + 1) + MIN_ROOMS; } private List getAllViablePoints(int rowSize, int colSize) { List points = new ArrayList<>(); for (int row = MIN_SIDE_PADDING; row < rowSize - MIN_SIDE_PADDING; row++) { for (int col = MIN_SIDE_PADDING; col < colSize - MIN_SIDE_PADDING; col++) { points.add(new Point(row, col)); } } return points; } private Point selectRandomPoint(List viablePoints) { Random random = new Random(); int idx = random.nextInt(viablePoints.size()); return viablePoints.remove(idx); } private Room generateRandomRoom(List viablePoints) { Random random = new Random(); int rowRadius = random.nextInt(MIN_ROOM_RADIUS, MAX_ROOM_RADIUS + 1); int colRadius = random.nextInt(MIN_ROOM_RADIUS, MAX_ROOM_RADIUS + 1); Point point = selectRandomPoint(viablePoints); Room room = new Room(rowRadius, colRadius, point); room.removePointsWithinRadius(viablePoints); return room; } private void placeRooms(Tile[][] map, List rooms) { for (Room room : rooms) { room.placeTiles(map); } } private void selectStartRoom(List rooms, int rowSize, int colSize) { Point corner = getRandomCorner(rowSize, colSize); double minDistance = Double.POSITIVE_INFINITY; Room min = rooms.getFirst(); for(Room room : rooms) { double distance = Point.getDistance(corner, room.getCenter()); if(distance < minDistance) { minDistance = distance; min = room; } } start = min; start.setType(RoomType.START); rooms.sort((o1, o2) -> { double dist1 = Point.getDistance(start.getCenter(), o1.getCenter()); double dist2 = Point.getDistance(start.getCenter(), o2.getCenter()); return Double.compare(dist1, dist2); }); } private Point getRandomCorner(int rowSize, int colSize) { List corners = new ArrayList<>(); corners.add(new Point(0, 0)); corners.add(new Point(0, colSize)); corners.add(new Point(rowSize, 0)); corners.add(new Point(rowSize, colSize)); int index = new Random().nextInt(4); return corners.get(index); } private List generateHallways(List rooms) { List toAdd = new ArrayList<>(rooms); List added = new ArrayList<>(); added.add(toAdd.removeFirst()); List hallways = new ArrayList<>(); while(!toAdd.isEmpty()) { if(toAdd.size() == 1) { toAdd.getFirst().setType(RoomType.END); } RoomConnection connection = RoomConnection.getMinimalDistance(added, toAdd); hallways.add(new Hallway(connection.from(), connection.to())); toAdd.remove(connection.to()); added.add(connection.to()); } return hallways; } private void placeHallways(List hallways, Tile[][] map) { for(Hallway hallway : hallways) { hallway.placeTiles(map); } } private void setDisplays(Tile[][] map) { for(int row = 0; row < grid.getRowSize(); row++) { for(int col = 0; col < grid.getColSize(); col++) { if(map[row][col] == null) { continue; } DisplayType type = DisplayHelper.getDisplayType(row, col, map); map[row][col].setDisplayType(type); } } } private void generateObjectClusters(List rooms, Optional character) { if(character.isPresent()) { player = character.get(); player.setPosition(start.getCenter()); } else { player = new MainCharacter(start.getCenter(), grid); } grid.tileAt(start.getCenter()).addEntity(player); for(Room room : rooms) { if (room.getType() == RoomType.ENEMY) { TreasureChest chest = new TreasureChest(game, room.getCenter(), player, grid); grid.tileAt(room.getCenter()).addInanimate(chest); inanimates.add(chest); List enemies = EnemyFactory.generateCluster(room.getCenter(), game.getFloor(), grid); this.enemies.addAll(enemies); } else if (room.getType() == RoomType.END){ Door door = new Door(room.getCenter(), game); grid.tileAt(room.getCenter()).addInanimate(door); inanimates.add(door); } } } private void fillRemainingTiles(Tile[][] newMap) { for(int row = 0; row < grid.getRowSize(); row++) { for(int col = 0; col < grid.getColSize(); col++) { if(newMap[row][col] == null) { newMap[row][col] = new Tile(new Point(row, col), TileType.UNMOVABLE); newMap[row][col].setDisplayType(DisplayType.VOID); } } } } }