void ConnectIslandRecursive(int IslandId, Dictionary <int, List <FloorIslandAdjacency> > AdjacencyByIslands,
                                    HashSet <int> IslandVisited, System.Random random, FloorDoorManager DoorManager, Dictionary <int, FloorChunk> IslandToChunkMap)
        {
            if (IslandVisited.Contains(IslandId))
            {
                return;
            }
            IslandVisited.Add(IslandId);

            if (!AdjacencyByIslands.ContainsKey(IslandId))
            {
                // No adjacent islands
                return;
            }

            List <FloorIslandAdjacency> AdjacentNodes = AdjacencyByIslands[IslandId];
            HashSet <int> AdjacentIslands             = new HashSet <int>();

            foreach (FloorIslandAdjacency AdjacentNode in AdjacentNodes)
            {
                AdjacentIslands.Add(AdjacentNode.A.IslandId);
                AdjacentIslands.Add(AdjacentNode.B.IslandId);
            }
            AdjacentIslands.Remove(IslandId);
            IslandNodePriorityPredicate SortPredicate = new IslandNodePriorityPredicate(IslandToChunkMap);

            int[] AdjacentIslandArray = new List <int>(AdjacentIslands).ToArray();
            System.Array.Sort(AdjacentIslandArray, SortPredicate);

            foreach (int AdjacentIsland in AdjacentIslandArray)
            {
                if (IslandVisited.Contains(AdjacentIsland))
                {
                    continue;
                }

                // Find all the adjacent cells between these two islands
                List <FloorIslandAdjacency> EdgeNodes = new List <FloorIslandAdjacency>();
                foreach (FloorIslandAdjacency AdjacentNode in AdjacentNodes)
                {
                    if (AdjacentNode.A.IslandId == AdjacentIsland || AdjacentNode.B.IslandId == AdjacentIsland)
                    {
                        EdgeNodes.Add(AdjacentNode);
                    }
                }

                // Connect a door in any one of the edge nodes
                if (EdgeNodes.Count > 0)
                {
                    int Index = random.Next(0, EdgeNodes.Count);
                    FloorIslandAdjacency DoorEdge = EdgeNodes[Index];
                    // Create a door here
                    DoorManager.RegisterDoor(DoorEdge.A.Location, DoorEdge.B.Location);

                    // Move into this room now
                    ConnectIslandRecursive(AdjacentIsland, AdjacencyByIslands, IslandVisited, random, DoorManager, IslandToChunkMap);
                }
            }
        }
        void BuildLayout()
        {
            ChunkDB     = new FloorChunkDB();
            DoorManager = new FloorDoorManager();
            Visited.Clear();
            random = new System.Random((int)floorPlanConfig.Seed);

            int NumFloors = Mathf.RoundToInt(floorPlanConfig.BuildingSize.y);

            for (int y = 0; y < NumFloors; y++)
            {
                // Build the hallways and the intermediate floor chunks (which will hold the rooms)
                List <FloorChunk> FloorChunks = new List <FloorChunk>();
                {
                    FloorChunk InitialFloor = ChunkDB.Create();
                    InitialFloor.Bounds.Location = new IntVector(0, y, 0);
                    InitialFloor.Bounds.Size     = MathUtils.ToIntVector(floorPlanConfig.BuildingSize);

                    Stack <FloorChunk> Stack = new Stack <FloorChunk>();
                    Stack.Push(InitialFloor);
                    while (Stack.Count > 0)
                    {
                        FloorChunk Top  = Stack.Pop();
                        float      Area = Top.Area();
                        if (Area <= 0)
                        {
                            continue;
                        }
                        if (Top.Area() <= floorPlanConfig.MinRoomChunkArea)
                        {
                            FloorChunks.Add(Top);
                        }
                        else
                        {
                            // Needs to be split further
                            FloorChunk Left    = ChunkDB.Create();
                            FloorChunk Right   = ChunkDB.Create();
                            FloorChunk Hallway = ChunkDB.Create();

                            SplitChunk(Top, Left, Right, Hallway);
                            ChunkDB.Register(Hallway);

                            Stack.Push(Left);
                            Stack.Push(Right);
                        }
                    }
                }

                // Split the floor chunks (space between the hallways) to create rooms
                foreach (FloorChunk Chunk in FloorChunks)
                {
                    Stack <FloorChunk> Stack = new Stack <FloorChunk>();
                    Stack.Push(Chunk);
                    int MinArea = floorPlanConfig.MinRoomSize * floorPlanConfig.MinRoomSize;
                    int MaxArea = floorPlanConfig.MaxRoomSize * floorPlanConfig.MaxRoomSize;

                    while (Stack.Count > 0)
                    {
                        FloorChunk Top            = Stack.Pop();
                        bool       bRequiresSplit = true;
                        int        Area           = Top.Area();
                        int        Length         = Top.GetLength();
                        if (Length > floorPlanConfig.MaxRoomSize)
                        {
                            // Length is too big. force a split
                            bRequiresSplit = true;
                        }
                        else if (Area <= MinArea)
                        {
                            // This room is too small and should not be split
                            bRequiresSplit = false;
                        }
                        else if (Area <= MaxArea)
                        {
                            float SplitProbability = (Area - MinArea) / (MaxArea - MinArea);
                            SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset;
                            if (Chunk.GetLength() >= Chunk.GetWidth() * 2)
                            {
                                SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset;
                            }
                            bRequiresSplit = (random.Next() < SplitProbability);
                        }

                        if (bRequiresSplit)
                        {
                            FloorChunk Left  = ChunkDB.Create();
                            FloorChunk Right = ChunkDB.Create();
                            SplitChunk(Top, Left, Right);
                            Stack.Push(Left);
                            Stack.Push(Right);
                        }
                        else
                        {
                            ChunkDB.Register(Top);
                        }
                    }
                }

                /*
                 *      // Get the chunks defined by the room volumes
                 *      List<FloorChunk> RoomVolumeChunks = new List<FloorChunk>();
                 *      if (World) {
                 *              FRectangle BuildingBounds;
                 *              BuildingBounds.Location = FIntVector::ZeroValue;
                 *              BuildingBounds.Size = FMathUtils::ToIntVector(floorPlanConfig.BuildingSize);
                 *              for (TActorIterator<AFloorPlanRoomVolume> It(World); It; ++It) {
                 *                      AFloorPlanRoomVolume* Volume = *It;
                 *                      if (Volume.Dungeon != Dungeon) {
                 *                              // This volume is not supposed to affect this dungeon
                 *                              continue;
                 *                      }
                 *                      FVector GridSize = floorPlanConfig.GridSize;
                 *                      FRectangle VolumeBounds;
                 *                      Volume.GetDungeonVolumeBounds(GridSize, VolumeBounds);
                 *                      int VolumeStartZ = VolumeBounds.Location.Z;
                 *                      int VolumeEndZ = VolumeStartZ + VolumeBounds.Size.Z;
                 *
                 *                      if (z < VolumeStartZ || z >= VolumeEndZ) {
                 *                              // Out of the volume bounds
                 *                              continue;
                 *                      }
                 *
                 *                      FRectangle ChunkBounds = VolumeBounds;
                 *                      ChunkBounds.Location.Z = z;
                 *                      ChunkBounds.Size.Z = 1;
                 *                      ChunkBounds.Clip(BuildingBounds);
                 *                      if (ChunkBounds.Size.Z == 0) continue;
                 *                      int ChunkZ = ChunkBounds.Location.Z;
                 *
                 *                      FloorChunk RoomVolumeChunk = ChunkDB.Create();
                 *                      RoomVolumeChunk.Bounds = ChunkBounds;
                 *                      RoomVolumeChunk.ChunkType = FloorChunkType.Room;
                 *                      RoomVolumeChunk.bEmitGroundMarker = (ChunkZ == VolumeStartZ);
                 *                      RoomVolumeChunk.bEmitCeilingMarker = (ChunkZ == VolumeEndZ - 1);
                 *                      RoomVolumeChunk.bConnectDoors = Volume.bConnectDoors;
                 *                      RoomVolumeChunk.WallMarker = Volume.WallMarker;
                 *                      RoomVolumeChunk.GroundMarker = Volume.GroundMarker;
                 *                      RoomVolumeChunk.CeilingMarker = Volume.CeilingMarker;
                 *                      RoomVolumeChunk.DoorMarker = Volume.DoorMarker;
                 *                      RoomVolumeChunk.CenterMarker = Volume.CenterMarker;
                 *                      RoomVolumeChunk.bCreateWalls = Volume.bCreateWalls;
                 *
                 *                      // Since this chunk is defined by a volume, we can have a more detailed rasterised cell shape
                 *                      GetVolumeCells(Volume, z, RoomVolumeChunk.BoundCells);
                 *
                 *                      // Give a higher priority to the volume chunk so it overrides everything in its path
                 *                      RoomVolumeChunk.Priority = Volume.Priority;
                 *
                 *                      RoomVolumeChunks.Add(RoomVolumeChunk);
                 *                      ChunkDB.Register(RoomVolumeChunk);
                 *              }
                 *      }
                 */
            }

            ChunkDB.CacheChunkPositions();

            for (int y = 0; y < floorPlanConfig.BuildingSize.y; y++)
            {
                CreateDoors(y);
            }
        }
Esempio n. 3
0
        void BuildLayout()
        {
            ChunkDB     = new FloorChunkDB();
            DoorManager = new FloorDoorManager();
            Visited.Clear();
            random = new System.Random((int)floorPlanConfig.Seed);

            int NumFloors = Mathf.RoundToInt(floorPlanConfig.BuildingSize.y);

            for (int y = 0; y < NumFloors; y++)
            {
                // Build the hallways and the intermediate floor chunks (which will hold the rooms)
                List <FloorChunk> FloorChunks = new List <FloorChunk>();
                {
                    FloorChunk InitialFloor = ChunkDB.Create();
                    InitialFloor.Bounds.Location = new IntVector(0, y, 0);
                    InitialFloor.Bounds.Size     = MathUtils.ToIntVector(floorPlanConfig.BuildingSize);

                    Stack <FloorChunk> Stack = new Stack <FloorChunk>();
                    Stack.Push(InitialFloor);
                    while (Stack.Count > 0)
                    {
                        FloorChunk Top  = Stack.Pop();
                        float      Area = Top.Area();
                        if (Area <= 0)
                        {
                            continue;
                        }
                        if (Top.Area() <= floorPlanConfig.MinRoomChunkArea)
                        {
                            FloorChunks.Add(Top);
                        }
                        else
                        {
                            // Needs to be split further
                            FloorChunk Left    = ChunkDB.Create();
                            FloorChunk Right   = ChunkDB.Create();
                            FloorChunk Hallway = ChunkDB.Create();

                            SplitChunk(Top, Left, Right, Hallway);
                            ChunkDB.Register(Hallway);

                            Stack.Push(Left);
                            Stack.Push(Right);
                        }
                    }
                }

                // Split the floor chunks (space between the hallways) to create rooms
                foreach (FloorChunk Chunk in FloorChunks)
                {
                    Stack <FloorChunk> Stack = new Stack <FloorChunk>();
                    Stack.Push(Chunk);
                    int MinRoomSize = floorPlanConfig.MinRoomSize;
                    int MaxRoomSize = floorPlanConfig.MaxRoomSize;
                    MaxRoomSize = Mathf.Max(MinRoomSize, MaxRoomSize);

                    int MinArea = MinRoomSize * MinRoomSize;
                    int MaxArea = MaxRoomSize * MaxRoomSize;

                    while (Stack.Count > 0)
                    {
                        FloorChunk Top            = Stack.Pop();
                        bool       bRequiresSplit = true;
                        int        Area           = Top.Area();
                        int        Length         = Top.GetLength();
                        if (Length > MaxRoomSize)
                        {
                            // Length is too big. force a split
                            bRequiresSplit = true;
                        }
                        else if (Area <= MinArea)
                        {
                            // This room is too small and should not be split
                            bRequiresSplit = false;
                        }
                        else if (Area <= MaxArea)
                        {
                            float SplitProbability = (Area - MinArea) / (MaxArea - MinArea);
                            SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset;
                            if (Chunk.GetLength() >= Chunk.GetWidth() * 2)
                            {
                                SplitProbability += floorPlanConfig.RoomSplitProbabilityOffset;
                            }
                            bRequiresSplit = (random.Next() < SplitProbability);
                        }

                        if (bRequiresSplit)
                        {
                            FloorChunk Left  = ChunkDB.Create();
                            FloorChunk Right = ChunkDB.Create();
                            SplitChunk(Top, Left, Right);
                            Stack.Push(Left);
                            Stack.Push(Right);
                        }
                        else
                        {
                            ChunkDB.Register(Top);
                        }
                    }
                }

                // TODO: Add support for floor plan specific volumes
                // ...
            }

            ChunkDB.CacheChunkPositions();

            for (int y = 0; y < floorPlanConfig.BuildingSize.y; y++)
            {
                CreateDoors(y);
            }
        }