public override bool Equals(object obj) { if ((obj == null) || !this.GetType().Equals(obj.GetType())) { return(false); } else { CorridorTile other = (CorridorTile)obj; return(Tile == other.Tile); } }
public CorridorTile(Tile tile, CorridorTile from, Direction dir) { Tile = tile; From = from; PreviousDirection = dir; DirectionsToTry = new List <Direction>(); DirectionsToTry.Add(Direction.Up); DirectionsToTry.Add(Direction.Down); DirectionsToTry.Add(Direction.Left); DirectionsToTry.Add(Direction.Right); DirectionsToTry.Remove(Tile.Invert(dir)); }
/// <summary> /// If a door opens into the wall of another room, carving straight ahead is guaranteed /// to open into that room. Make a door at the other end. /// It's possible that if the door opens into the corner of another room, our corridor /// opens into another corridor first. This is fine, just don't make the last tile a door. /// </summary> /// <param name="door"></param> /// <param name="startOfPath"></param> public void CorridorThroughRoomWall(Tile door, Tile startOfPath, bool allowConnectionToConnectedArea) { // Prepare a stack of path tiles so we can call our general method to carve the corridor Stack <CorridorTile> path = new Stack <CorridorTile>(); CorridorTile wrappedDoor = new CorridorTile(door, null, door.Direction); CorridorTile head = new CorridorTile(startOfPath, wrappedDoor, door.Direction); path.Push(head); while (!Dungeon.IsTileAdjacentTo(head.Tile, Block.WALKABLE, head.From.Tile)) { Tile nextTile = Dungeon.GetTileByDirection(head.Tile, door.Direction); head = new CorridorTile(nextTile, head, door.Direction); path.Push(head); } if (!allowConnectionToConnectedArea && !RoomUnconnectedToAdjacentArea(door.Area, Dungeon.GetAdjacentTilesOfType(head.Tile, Block.WALKABLE, head.From.Tile))) { EraseDoor(door); return; } // If the last tile is directly touching another room's interior, make this tile a door // As a wall tile originally, the door tile is already facing out from its room Tile otherDoor = path.Peek().Tile; if (Dungeon.IsTileAdjacentTo(otherDoor, Block.Room)) { path.Pop(); Room otherRoom = (Room)otherDoor.Area; otherRoom.SetTileAsDoor(otherDoor); } // If we didn't pop our only path tile off of the stack, carve the remaining corridor if (path.Count > 0) { CarveCorridor(path); } else { ConnectAreas(door); } }
/// <summary> /// Perform a flood-fill search from a door to another room's door or a path. /// </summary> /// <param name="door"></param> /// <param name="chanceToTurn"></param> public void CorridorWalk(Tile door, double chanceToTurn, bool allowConnectionToConnectedArea) { bool DoorLeadsToOtherRoom(List <Tile> doors) { foreach (Tile d in doors) { if (door.Area != d.Area) { return(true); } } return(false); } HashSet <CorridorTile> visited = new HashSet <CorridorTile>(); Stack <CorridorTile> path = new Stack <CorridorTile>(); Tile firstTile = Dungeon.GetTileByDirection(door); CorridorTile start = new CorridorTile(door, null, door.Direction); CorridorTile head = new CorridorTile(firstTile, start, door.Direction); path.Push(head); visited.Add(head); while (path.Count > 0) { head = path.Peek(); // Can we carve this tile? // If a door is on the head of the stack, it belongs to the room we came from. // (If we had found a door to another room, we would already have exited the while loop) // Treat these doors as walls. if (head.Block == Block.Wall || head.Block == Block.Granite || head.Block == Block.Door) { path.Pop(); continue; } // Have we found any doors? // If all adjacent doors lead to the room we came from, carry on if (Dungeon.IsTileAdjacentTo(head.Tile, Block.Door, head.From.Tile) && DoorLeadsToOtherRoom(Dungeon.GetAdjacentTilesOfType(head.Tile, Block.Door, head.From.Tile))) { CarveCorridor(path); return; } // Have we found an existing path? Connect to it and end // If we are not allowed to connect to it, then we must skirt around it if (Dungeon.IsTileAdjacentTo(head.Tile, Block.Path, head.From.Tile)) { if (allowConnectionToConnectedArea || RoomUnconnectedToAdjacentArea(door.Area, Dungeon.GetAdjacentTilesOfType(head.Tile, Block.Path, head.From.Tile))) { CarveCorridor(path); return; } else { // Do not allow our path to touch existing paths. Treat this tile as non-carvable path.Pop(); continue; } } // Decide where to go next, or step back one tile if all paths have been explored if (head.DirectionsToTry.Count > 0) { CorridorTile next; do { next = head.ChooseNextTile(Dungeon, chanceToTurn); } while (visited.Contains(next) && head.DirectionsToTry.Count > 0); if (visited.Contains(next)) { path.Pop(); } else { path.Push(next); visited.Add(next); } } else { path.Pop(); } } // There are no doors or paths to connect to, so erase this door EraseDoor(door); }
/// <summary> /// Commits a stack of wrapped corridor tiles to the dungeon. /// </summary> /// <param name="path"></param> public void CarveCorridor(Stack <CorridorTile> path) { // Unwrap the tiles in the stack to populate a set HashSet <Tile> tiles = new HashSet <Tile>(); foreach (CorridorTile wrappedTile in path) { tiles.Add(wrappedTile.Tile); } // Get an existing Path object if there is one; otherwise make a new object Area area; List <Tile> adjacentPaths = Dungeon.GetAdjacentTilesOfType(path.Peek().Tile, Block.Path); if (adjacentPaths.Count > 0) { area = adjacentPaths[0].Area; } else { area = new Path(); area.InitializeArea(); } // Connect the *end* of the path to any adjacent Area objects Tile end = path.Peek().Tile; end.Area = area; ConnectAreas(end); // Finally begin carving the corridor CorridorTile head = null; while (path.Count > 0) { head = path.Pop(); tiles.Remove(head.Tile); List <Tile> adjacents = Dungeon.GetAdjacentTiles(head.Tile, head.From.Tile); foreach (Tile adjacent in adjacents) { if (tiles.Contains(adjacent)) { // Loops exists, trim it while (path.Peek().Tile != adjacent) { Tile remove = path.Pop().Tile; tiles.Remove(remove); } } } head.Tile.Block = Block.Path; head.Tile.Area = area; } // Connect the *start* of the path to the room it came from ConnectAreas(head.Tile); }