Ejemplo n.º 1
0
        /// <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, Space.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, Space.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, Space.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);
            }
        }
Ejemplo n.º 2
0
        /// <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.Space == Space.Wall || head.Space == Space.Granite || head.Space == Space.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, Space.Door, head.From.Tile) &&
                    DoorLeadsToOtherRoom(Dungeon.GetAdjacentTilesOfType(head.Tile, Space.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, Space.Path, head.From.Tile))
                {
                    if (allowConnectionToConnectedArea || RoomUnconnectedToAdjacentArea(door.Area,
                                                                                        Dungeon.GetAdjacentTilesOfType(head.Tile, Space.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);
        }
Ejemplo n.º 3
0
        /// <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, Space.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.Space = Space.Path;
                head.Tile.Area  = area;
            }

            // Connect the *start* of the path to the room it came from

            ConnectAreas(head.Tile);
        }