/// <summary> /// Actually performs room placement in the scratchpad. /// </summary> /// <param name="roomData"></param> /// <param name="mapExit"></param> /// <param name="roomExit"></param> /// <param name="scope"></param> /// <param name="primaryPath"></param> private void PlaceRoom(RoomData roomData, Vector2Int mapExit, Vector2Int roomExit, int scope, bool primaryPath) { int maxDistance = 0; roomData.placeCount++; for (int x = 0; x < roomData.width; ++x) { for (int y = 0; y < roomData.height; ++y) { int mapX = mapExit.x - roomExit.x + x; int mapY = mapExit.y - roomExit.y + y; Vector2Int mapPos = new Vector2Int(mapX, mapY); char roomTile = roomData.Tile(x, y); // Empty tiles shouldn't be represented in the dictionary if (roomTile == RandomDungeonTileData.EMPTY_TILE) { continue; } // Create a new tile or edit a tile that already exists. // This ensures we don't generate unnecessary garbage. RandomDungeonTileData td = null; if (!mRoomScratch.ContainsKey(mapPos)) { td = new RandomDungeonTileData(); mRoomScratch.Add(mapPos, td); float distance = Vector2Int.Distance(roomExit, new Vector2Int(x, y)); int distanceInt = Mathf.CeilToInt(distance); maxDistance = Mathf.Max(maxDistance, distanceInt); td.tileId = mCurrentTileId + distanceInt; td.position = mapPos; } else { td = mRoomScratch[mapPos]; td.Clear(); } td.tileType = roomTile; td.scope = scope; td.room = mCurrentRoomId; if (primaryPath) { td.distanceFromPrimaryPath = 0; } else { // todo bdsowers - this is not perfect // maybe it doesn't need to be perfect, we'll see int mapExitDistance = mRoomScratch[mapExit].distanceFromPrimaryPath; td.distanceFromPrimaryPath = mapExitDistance + 1; maxDistanceFromPrimaryPath = Mathf.Max(maxDistanceFromPrimaryPath, td.distanceFromPrimaryPath); } // Trap // Register it in the map proper as a walkable tile // give a block of trap tiles the same identifier - they form one large trap if (roomTile == RandomDungeonTileData.TRAP_TILE) { int neighborTrap = NeighborTrap(mapX, mapY); int trapId = neighborTrap; if (trapId == -1) { trapId = mCurrentTrapId; mCurrentTrapId++; } td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.trap = trapId; } else if (roomTile == RandomDungeonTileData.POSSIBLE_CHEST_TILE) { td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.chest = 1; } else if (roomTile == RandomDungeonTileData.GUARANTEED_CHEST_TILE) { td.tileType = RandomDungeonTileData.WALKABLE_TILE; td.chest = 2; } // Add the new exit to the list of available exits if (roomTile == RandomDungeonTileData.EXIT_TILE) { mAvailableExits.Add(mapPos); } } } ++mCurrentRoomId; mCurrentTileId += maxDistance + 1; }
/// <summary> /// Repeatedly tries to place a room, choosing a random room from the room set and a random exit to place it off of. /// This will retry some maximum number of times and quit if it never finds a valid choice. /// </summary> /// <param name="roomCategory"></param> /// <param name="primaryPath"></param> /// <param name="scope"></param> /// <param name="roomPlacementOptions"></param> /// <param name="roomDataOverride"></param> /// <returns>The room data for the room that was placed, or null if no room could be placed.</returns> private RoomData TryPlaceRoom(string roomCategory, bool primaryPath, int scope, RoomPlacementOptions roomPlacementOptions = RoomPlacementOptions.None, RoomData roomDataOverride = null) { int maxAttempts = 200; while (maxAttempts > 0) { Vector2Int mapExit = ChooseMapExitForNextRoom(); RoomData randomRoom = roomDataOverride != null ? roomDataOverride : mRoomSet.RandomRoomOfCategory(roomCategory, mPreviousRoomPlaced, mRNG); if (randomRoom == null) { --maxAttempts; continue; } Vector2Int roomExit = randomRoom.RandomExit(mRNG); if (scope == -1) { scope = mRoomScratch[mapExit].scope; } if (!RoomHasInvalidCollision(randomRoom, mapExit, roomExit, scope, roomPlacementOptions)) { // If we're constructing a primary path, clear out any exits currently // in our list. Placing a room will add new available exits to build off of. // This also guards against the primary path looping in on itself. if (primaryPath) { mAvailableExits.Clear(); mPrimaryPathPositions.Add(new Vector2Int(mapExit.x, mapExit.y)); } mAvailableExits.Remove(mapExit); PlaceRoom(randomRoom, mapExit, roomExit, scope, primaryPath); // The probability of picking a room lowers each time it's picked randomRoom.probability /= 2; mPreviousRoomPlaced = randomRoom; mPreviousMapExitUsed = mapExit; return(randomRoom); } --maxAttempts; } return(null); }