/// <summary> /// Verifies whether room placement is possible. /// We go through every tile in the room and ensure that it's not overlapping something invalid /// (ie: if we try to place a wall that would overlap a floor tile, that's invalid). /// </summary> /// <param name="roomData"></param> /// <param name="mapExit"></param> /// <param name="roomExit"></param> /// <param name="scope"></param> /// <param name="roomPlacementOptions"></param> /// <returns></returns> private bool RoomHasInvalidCollision(RoomData roomData, Vector2Int mapExit, Vector2Int roomExit, int scope, RoomPlacementOptions roomPlacementOptions = RoomPlacementOptions.None) { bool fullOverlap = true; for (int roomX = 0; roomX < roomData.width; ++roomX) { for (int roomY = 0; roomY < roomData.height; ++roomY) { int mapX = mapExit.x - roomExit.x + roomX; int mapY = mapExit.y - roomExit.y + roomY; Vector2Int mapPos = new Vector2Int(mapX, mapY); int roomTile = roomData.Tile(roomX, roomY); if (!mRoomScratch.ContainsKey(mapPos) || roomTile == RandomDungeonTileData.EMPTY_TILE) { // Any kind of tile can be placed over an empty location // However, at this point we do know that the rooms are not 100% overlapping fullOverlap = false; continue; } else { int mapTile = mRoomScratch[mapPos].tileType; int mapTileScope = mRoomScratch[mapPos].scope; if (scope != mapTileScope && !RoomPlacementOptionSet(roomPlacementOptions, RoomPlacementOptions.AllowMismatchScopes)) { // We're trying to connect with a room in a different scope, which we can never do to ensure // that a scope only has a single point of entry. return(true); } else if (RoomPlacementOptionSet(roomPlacementOptions, RoomPlacementOptions.AllowWallsToBecomeExits) && mapTile == RandomDungeonTileData.WALL_TILE && roomTile == RandomDungeonTileData.EXIT_TILE) { // If the options indicate that walls can become exits, support that. continue; } else if (mapTile != roomTile) { // Only identical tiles can be placed over one another. return(true); } } } } // There's still the chance that this room is being placed completely over a previous room, which // we don't want to allow because it throws off our room counts. // We should be trying to place against at least one empty square return(fullOverlap); }
/// <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; }