Beispiel #1
0
        public CorridorTile ChooseNextTile(Dungeon dungeon, double chanceToTurn)
        {
            Direction nextDirection = ChooseNextDirection(chanceToTurn);
            Tile      nextTile      = dungeon.GetTileByDirection(Tile, nextDirection);

            return(new CorridorTile(nextTile, this, nextDirection));
        }
        /// <summary>
        /// Account for all the cases a door may open into.
        ///   - Another room. Carve no corridor, just link areas
        ///   - A wall of another room. Carve a corridor straight ahead until a walkable space is found
        ///   - Solid rock. Call the flood-fill search to find a door or path for a corridor to connect to
        /// </summary>
        /// <param name="door"></param>
        /// <param name="chanceToTurn"></param>
        /// <param name="allowConnectionToConnectedArea"></param>
        public void GenerateCorridor(Tile door, double chanceToTurn, bool allowConnectionToConnectedArea)
        {
            Tile startOfPath = Dungeon.GetTileByDirection(door, door.Direction);

            // If door is already connected to a path or another door, there is nothing to do
            // (The initial set of doors touch no other doors, so if a door is adjacent,
            // it was spawned while carving a path straight ahead.)

            if (Dungeon.IsTileAdjacentTo(door, Space.WALKABLE, Dungeon.GetTileByDirection(door, Tile.Invert(door.Direction))))
            {
                if (allowConnectionToConnectedArea || !door.Area.To.Contains(startOfPath.Area))
                {
                    ConnectAreas(door);
                }
                else
                {
                    EraseDoor(door);
                }
                return;
            }

            // If the door has opened into a wall, carve straight ahead until the other room can be entered
            // Then exit this method call

            if (startOfPath.Space == Space.Wall)
            {
                CorridorThroughRoomWall(door, startOfPath, allowConnectionToConnectedArea);
                return;
            }

            // If there is solid stone ahead, start a path

            CorridorWalk(door, chanceToTurn, allowConnectionToConnectedArea);
        }
Beispiel #3
0
        /// <summary>
        /// Randomly chooses a wall tile as a door.
        /// Does not choose tiles touching an existing door, not even by a corner.
        /// </summary>
        /// <returns></returns>
        public Tile GenerateDoor()
        {
            int tries = 0;

            while (tries < 100)
            {
                // Because rooms can share walls, some wall tiles may already be doors from another room
                // So check the actual tile as well as this room's list of doors

                Tile tile = walls[DungeonGenerator.Rng.Next(0, walls.Count)];
                if (!Doors.Contains(tile) && tile.Space != Space.Door &&
                    !Dungeon.IsTileSurroundedBy(tile, Space.Door) &&
                    Dungeon.GetTileByDirection(tile).Space != Space.Granite)
                {
                    SetTileAsDoor(tile);
                    return(tile);
                }
                ++tries;
            }
            foreach (Tile tile in walls)
            {
                tile.Debug = true;
            }
            return(null);
            //throw new InvalidOperationException("Room for another door could not be found");
        }
        /// <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);
            }
        }
        /// <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);
        }