Example #1
0
        public override void Load(FileReader stream)
        {
            base.Load(stream);

            MapX = stream.ReadInt16();
            MapY = stream.ReadInt16();
            MapW = stream.ReadInt16();
            MapH = stream.ReadInt16();

            Type = RoomRegistry.FromIndex(stream.ReadByte());

            var count = stream.ReadByte();

            for (var i = 0; i < count; i++)
            {
                var c = RoomControllerRegistery.Get(stream.ReadString());

                if (c != null)
                {
                    Controllers.Add(c);
                    c.Room = this;
                    c.Load(stream);
                }
            }

            Id = stream.ReadString();
        }
Example #2
0
 public override void Initialize(ICoreAPI api)
 {
     // Registers the updater
     base.Initialize(api);
     RegisterGameTickListener(UpdateStep, 1200);
     rmaker = api.ModLoader.GetModSystem <RoomRegistry>();
 }
Example #3
0
        private Task <IChatServer> CreateServer(ICollection <ChatRoom> initialRooms)
        {
            var trackingFactory = InMemoryMessageTracker.Factory;
            var roomsSource     =
                new InMemoryRoomSourceFactory(trackingFactory, new InMemoryRoomBackplaneFactory(), initialRooms);
            var roomRegistry = new RoomRegistry(roomsSource);
            var chatServer   = new ChatServer(TestingLogger.CreateFactory(), roomRegistry);

            pendingTasks.Add(chatServer.RunAsync(testsLifetime.Token));
            pendingTasks.Add(roomRegistry.RunAsync(testsLifetime.Token));
            return(Task.FromResult <IChatServer>(chatServer));
        }
Example #4
0
        public async Task <bool> UpdateRoomRegisteryAsync(UserRegistery user, RoomRegistry roomData)
        {
            if (!Users.Any(r => r.Username.Equals(user.Username, StringComparison.Ordinal) &&
                           r.UserToken == user.UserToken))
            {
                return(false);
            }

            if (!roomData.CreatedBy.Equals(user.Username))
            {
                return(false);
            }

            await GrainFactory.GetGrain <IRoomGrain>(roomData.RoomName).SetupRoomAsync(roomData);

            return(true);
        }
Example #5
0
        public override void Save(FileWriter stream)
        {
            base.Save(stream);

            stream.WriteInt16((short)MapX);
            stream.WriteInt16((short)MapY);
            stream.WriteInt16((short)MapW);
            stream.WriteInt16((short)MapH);

            stream.WriteByte((byte)RoomRegistry.FromType(Type));
            stream.WriteByte((byte)Controllers.Count);

            foreach (var c in Controllers)
            {
                stream.WriteString(c.Id);
                c.Save(stream);
            }

            stream.WriteString(Id);
        }
Example #6
0
        public async Task <RoomRegistry> CreateRoomAsync(string username, string roomName, string password, bool isPubliclyVisible, params string[] modorators)
        {
            if (Rooms.Any(room => room.RoomName.Equals(roomName, StringComparison.Ordinal)))
            {
                return(null);
            }

            var createdRoom = new RoomRegistry
            {
                RoomName          = roomName,
                RoomKey           = Guid.NewGuid(),
                RoomPassword      = password,
                IsPubliclyVisible = isPubliclyVisible,
                Modorators        = new [] { username }.ToList(),
                CreatedAt = DateTime.UtcNow,
                CreatedBy = username
            };

            Rooms.Add(createdRoom);
            await GrainFactory.GetGrain <IRoomGrain>(roomName).SetupRoomAsync(createdRoom);

            return(createdRoom);
        }
Example #7
0
 public override void Initialize(ICoreAPI api)
 {
     base.Initialize(api);
     rmaker     = api.ModLoader.GetModSystem <RoomRegistry>();
     growthTick = RegisterGameTickListener(growthMonitior, 3000);
 }
        public override List <RoomDef> Build(List <RoomDef> rooms)
        {
            SetupRooms(rooms);

            if (landmarkRoom == null)
            {
                landmarkRoom = MultiConnection[Rnd.Int(MultiConnection.Count)];
            }

            if (MultiConnection.Contains(landmarkRoom))
            {
                MultiConnection.Remove(landmarkRoom);
            }

            var startAngle = Rnd.Float(0, 180);

            var roomsOnLoop = (int)(MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);

            roomsOnLoop = Math.Min(roomsOnLoop, MultiConnection.Count);

            var roomsOnFirstLoop = roomsOnLoop / 2;

            if (roomsOnLoop % 2 == 1)
            {
                roomsOnFirstLoop += Rnd.Int(2);
            }

            firstLoop = new List <RoomDef>();
            var pathTunnels = ArrayUtils.Clone(PathTunnelChances);

            for (var i = 0; i <= roomsOnFirstLoop; i++)
            {
                if (i == 0)
                {
                    firstLoop.Add(landmarkRoom);
                }
                else
                {
                    firstLoop.Add(MultiConnection[0]);
                    MultiConnection.RemoveAt(0);
                }

                var tunnels = Rnd.Chances(pathTunnels);

                if (tunnels == -1)
                {
                    pathTunnels = ArrayUtils.Clone(PathTunnelChances);
                    tunnels     = Rnd.Chances(pathTunnels);
                }

                pathTunnels[tunnels]--;

                for (var j = 0; j < tunnels; j++)
                {
                    firstLoop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));
                }
            }

            if (Entrance != null)
            {
                firstLoop.Insert((firstLoop.Count + 1) / 2, Entrance);
            }

            var roomsOnSecondLoop = roomsOnLoop - roomsOnFirstLoop;

            secondLoop = new List <RoomDef>();

            for (var i = 0; i <= roomsOnSecondLoop; i++)
            {
                if (i == 0)
                {
                    secondLoop.Add(landmarkRoom);
                }
                else
                {
                    secondLoop.Add(MultiConnection[0]);
                    MultiConnection.RemoveAt(0);
                }

                var tunnels = Rnd.Chances(pathTunnels);

                if (tunnels == -1)
                {
                    pathTunnels = ArrayUtils.Clone(PathTunnelChances);
                    tunnels     = Rnd.Chances(pathTunnels);
                }

                pathTunnels[tunnels]--;

                for (var j = 0; j < tunnels; j++)
                {
                    secondLoop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));
                }
            }

            if (Exit != null)
            {
                secondLoop.Insert((secondLoop.Count + 1) / 2, Exit);
            }

            landmarkRoom.SetSize();
            landmarkRoom.SetPos(0, 0);

            var   prev = landmarkRoom;
            float targetAngle;

            for (var i = 1; i < firstLoop.Count; i++)
            {
                var r = firstLoop[i];
                targetAngle = startAngle + getTargetAngle(i / (float)firstLoop.Count);

                if ((int)PlaceRoom(rooms, prev, r, targetAngle) != -1)
                {
                    prev = r;

                    if (!rooms.Contains(prev))
                    {
                        rooms.Add(prev);
                    }
                }
                else
                {
                    return(null);
                }
            }

            while (!prev.ConnectWithRoom(landmarkRoom))
            {
                var c = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);

                if ((int)PlaceRoom(rooms, prev, c, AngleBetweenRooms(prev, landmarkRoom)) == -1)
                {
                    return(null);
                }

                firstLoop.Add(c);
                rooms.Add(c);
                prev = c;
            }

            prev        = landmarkRoom;
            startAngle += 180f;

            /*for (var i = 1; i < secondLoop.Count; i++){
             *      var r = secondLoop[i];
             *      targetAngle = startAngle + getTargetAngle(i / (float)secondLoop.Count);
             *
             *      if ((int) PlaceRoom(rooms, prev, r, targetAngle) != -1) {
             *              prev = r;
             *
             *              if (!rooms.Contains(prev)) {
             *                      rooms.Add(prev);
             *              }
             *      } else {
             *              return null;
             *      }
             * }
             *
             * while (!prev.ConnectWithRoom(landmarkRoom)) {
             *      var c = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);
             *
             *      if ((int) PlaceRoom(rooms, prev, c, AngleBetweenRooms(prev, landmarkRoom)) == -1){
             *              return null;
             *      }
             *
             *      secondLoop.Add(c);
             *      rooms.Add(c);
             *      prev = c;
             * }*/

            firstLoopCenter = new Vector2();

            foreach (var r in firstLoop)
            {
                firstLoopCenter.X += (r.Left + r.Right) / 2f;
                firstLoopCenter.Y += (r.Top + r.Bottom) / 2f;
            }

            firstLoopCenter.X /= firstLoop.Count;
            firstLoopCenter.Y /= firstLoop.Count;

            secondLoopCenter = new Vector2();

            foreach (var r in secondLoop)
            {
                secondLoopCenter.X += (r.Left + r.Right) / 2f;
                secondLoopCenter.Y += (r.Top + r.Bottom) / 2f;
            }

            secondLoopCenter.X /= secondLoop.Count;
            secondLoopCenter.Y /= secondLoop.Count;

            var branchable = new List <RoomDef>(firstLoop);

            branchable.AddRange(secondLoop);
            branchable.Remove(landmarkRoom);

            var roomsToBranch = new List <RoomDef>();

            roomsToBranch.AddRange(MultiConnection);
            roomsToBranch.AddRange(SingleConnection);
            WeightRooms(branchable);
            CreateBranches(rooms, branchable, roomsToBranch, BranchTunnelChances);

            FindNeighbours(rooms);

            foreach (var r in rooms)
            {
                foreach (var n in r.Neighbours)
                {
                    if (!n.Connected.ContainsKey(r) && Rnd.Float() < ExtraConnectionChance)
                    {
                        r.ConnectWithRoom(n);
                    }
                }
            }

            return(rooms);
        }
Example #9
0
        protected virtual List <RoomDef> CreateRooms()
        {
            var rooms = new List <RoomDef>();
            var biome = LevelSave.BiomeGenerated;
            var final = IsFinal();
            var rush  = Run.Type == RunType.BossRush;
            var first = Run.Depth % 2 == 1;
            var loop  = Run.Loop > 0;
            var cave  = biome is CaveBiome;

            if (!rush && biome is DesertBiome)
            {
                rooms.Add(new DesertWellRoom());
            }

            if (final)
            {
                Log.Info("Prepare for the final!");
            }

            Log.Info($"Generating a level for {biome.Id} biome");

            rooms.Add(new EntranceRoom());

            if (Run.Depth == 5 && LevelSave.GenerateMarket && Run.Loop == 0)
            {
                rooms.Add(new ShopRoom());
                rooms.Add(new ExitRoom());

                if (GlobalSave.IsTrue(ShopNpc.Gobetta) && Rnd.Chance(10))
                {
                    rooms.Add(new GobettaShopRoom());
                }

                if (Rnd.Chance(2))
                {
                    rooms.Add(new TrashGoblinRoom());
                }

                if (Rnd.Chance(3))
                {
                    rooms.Add(new ChestMinigameRoom());
                }

                if (Rnd.Chance(4))
                {
                    rooms.Add(new VendingRoom());
                }

                if (GlobalSave.IsTrue(ShopNpc.Roger) && Rnd.Chance(10))
                {
                    rooms.Add(new RogerShopRoom());
                }

                if (Rnd.Chance(30))
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Secret, biome));
                }

                rooms.Add(new EmptyRoom());
                return(rooms);
            }

            if (!rush && !loop)
            {
                if (Run.Depth == 2)
                {
                    rooms.Add(new SecretKeyRoom());
                }
                else if (Run.Depth == 4)
                {
                    rooms.Add(new ClawMinigameRoom());
                }
            }

            if (!final)
            {
                var cn = LevelSave.XL ? 2 : 1;

                var regular    = rush || final ? 0 : biome.GetNumRegularRooms() * cn;
                var special    = rush || final ? 0 : biome.GetNumSpecialRooms() * cn;
                var trap       = rush || final ? 0 : biome.GetNumTrapRooms();
                var connection = rush || final ? 1 : GetNumConnectionRooms();
                var secret     = rush || final ? 0 : biome.GetNumSecretRooms() * cn;

                Log.Info($"Creating r{regular} sp{special} c{connection} sc{secret} t{trap} rooms");

                for (var I = 0; I < regular; I++)
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Regular, biome));
                }

                for (var i = 0; i < trap; i++)
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Trap, biome));
                }

                for (var I = 0; I < special; I++)
                {
                    var room = RoomRegistry.Generate(RoomType.Special, biome);
                    if (room != null)
                    {
                        rooms.Add(room);
                    }
                }

                for (var I = 0; I < connection; I++)
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Connection, biome));
                }

                if (!cave && !rush && !final && Run.Type != RunType.Challenge)
                {
                    if (!loop && !LevelSave.GenerateShops && first)
                    {
                        if (LevelSave.XL)
                        {
                            rooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));
                        }

                        rooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));
                    }

                    if (!LevelSave.GenerateTreasure && (!first || LevelSave.GenerateShops))
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Shop, biome));
                    }
                }

                if (!cave)
                {
                    if (!LevelSave.GenerateShops && LevelSave.GenerateTreasure && !first)
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));
                    }

                    if (!LevelSave.GenerateShops && loop && Run.Depth == 1 && Run.Type != RunType.Challenge)
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Treasure, biome));
                    }
                }

                if (rush)
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));
                    rooms.Add(new PrebossRoom());

                    if (Run.Depth < 11)
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Connection, biome));
                        rooms.Add(RoomRegistry.Generate(RoomType.Shop, biome));
                    }
                }
                else if (first)
                {
                    rooms.Add(new ExitRoom());
                }
                else
                {
                    rooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));
                    rooms.Add(new PrebossRoom());

                    if (Run.Depth < 10)
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Granny, biome));
                        rooms.Add(RoomRegistry.Generate(RoomType.OldMan, biome));
                    }
                }

                if (biome is CaveBiome && Rnd.Chance(5))
                {
                    rooms.Add(new SecretEmeraldGolemRoom());
                }

                if (!cave && !rush)
                {
                    if (Rnd.Chance(95))
                    {
                        if (Rnd.Chance(2 + Run.Scourge * 5))
                        {
                            rooms.Add(new ScourgedRoom());
                        }
                        else
                        {
                            if (Rnd.Chance())
                            {
                                rooms.Add(new ChallengeRoom());
                            }
                            else
                            {
                                rooms.Add(new SpikedRoom());
                            }
                        }
                    }

                    var addDarkMarket = (Run.Depth > 2 && Rnd.Chance(10) && GameSave.IsFalse("saw_blackmarket"));

                    if (addDarkMarket)
                    {
                        rooms.Add(new DarkMarketEntranceRoom());
                        rooms.Add(new DarkMarketRoom());
                    }

                    if (!addDarkMarket && Rnd.Chance(1))
                    {
                        secret--;
                        rooms.Add(new SecretDarkMarketEntranceRoom());
                        rooms.Add(new DarkMarketRoom());
                    }

                    for (var I = 0; I < secret; I++)
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.Secret, biome));
                    }

                    if (Rnd.Chance(30))
                    {
                        rooms.Add(RoomRegistry.Generate(RoomType.SubShop, biome));
                    }

                    if (NpcSaveRoom.ShouldBeAdded())
                    {
                        rooms.Add(new NpcSaveRoom());
                        rooms.Add(new NpcKeyRoom());
                    }

                    TombRoom.Insert(rooms);
                    biome.ModifyRooms(rooms);
                }
            }
            else
            {
                rooms.Add(RoomRegistry.Generate(RoomType.Boss, biome));
                rooms.Add(new PrebossRoom());
            }

            return(rooms);
        }
Example #10
0
 public Task SetupRoomAsync(RoomRegistry createdRoom)
 {
     throw new NotImplementedException();
 }
Example #11
0
        protected bool CreateBranches(List <RoomDef> Rooms, List <RoomDef> Branchable, List <RoomDef> RoomsToBranch, float[] ConnChances)
        {
            var     I = 0;
            var     N = 0;
            float   Angle;
            int     Tries;
            RoomDef Curr;

            var ConnectingRoomsThisBranch = new List <RoomDef>();
            var ConnectionChances         = ArrayUtils.Clone(ConnChances);

            while (I < RoomsToBranch.Count)
            {
                var R = RoomsToBranch[I];
                N++;
                ConnectingRoomsThisBranch.Clear();

                do
                {
                    Curr = Branchable[Rnd.Int(Branchable.Count)];
                } while (Curr is ConnectionRoom);

                var ConnectingRooms = Rnd.Chances(ConnectionChances);

                if (ConnectingRooms == -1)
                {
                    ConnectionChances = ArrayUtils.Clone(ConnChances);
                    ConnectingRooms   = Rnd.Chances(ConnectionChances);
                }

                ConnectionChances[ConnectingRooms]--;

                for (var J = 0; J < ConnectingRooms; J++)
                {
                    var T = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);
                    Tries = 3;

                    do
                    {
                        Angle = PlaceRoom(Rooms, Curr, T, RandomBranchAngle(Curr));
                        Tries--;
                    } while (Math.Abs(Angle - (-1)) < 0.01f && Tries > 0);

                    if (Math.Abs(Angle - (-1)) < 0.01f)
                    {
                        foreach (var C in ConnectingRoomsThisBranch)
                        {
                            C.ClearConnections();
                            Rooms.Remove(C);
                        }

                        ConnectingRoomsThisBranch.Clear();

                        break;
                    }

                    ConnectingRoomsThisBranch.Add(T);
                    Rooms.Add(T);


                    Curr = T;
                }

                if (ConnectingRoomsThisBranch.Count != ConnectingRooms)
                {
                    if (N > 30)
                    {
                        return(false);
                    }

                    continue;
                }

                Tries = 10;

                do
                {
                    Angle = PlaceRoom(Rooms, Curr, R, RandomBranchAngle(Curr));
                    Tries--;
                } while (Math.Abs(Angle - (-1)) < 0.01f && Tries > 0);

                if (Math.Abs(Angle - (-1)) < 0.01f)
                {
                    foreach (var T in ConnectingRoomsThisBranch)
                    {
                        T.ClearConnections();
                        Rooms.Remove(T);
                    }

                    ConnectingRoomsThisBranch.Clear();

                    if (N > 30)
                    {
                        return(false);
                    }

                    continue;
                }

                foreach (var AConnectingRoomsThisBranch in ConnectingRoomsThisBranch)
                {
                    if (Rnd.Int(3) <= 1)
                    {
                        Branchable.Add(AConnectingRoomsThisBranch);
                    }
                }

                if (R.GetMaxConnections(RoomDef.Connection.All) > 1 && Rnd.Int(3) == 0)
                {
                    if (R is RegularRoom room)
                    {
                        /*for (var J = 0; J < room.GetSize().GetConnectionWeight(); J++) {
                         *      Branchable.Add(room);
                         * }*/

                        Branchable.Add(room);
                    }
                    else
                    {
                        Branchable.Add(R);
                    }
                }

                I++;
            }

            return(true);
        }
Example #12
0
        public override List <RoomDef> Build(List <RoomDef> Init)
        {
            SetupRooms(Init);

            if (Entrance == null)
            {
                Log.Error("No entrance!");
                return(null);
            }

            var Branchable = new List <RoomDef>();

            Entrance.SetSize();
            Entrance.SetPos(0, 0);
            Branchable.Add(Entrance);

            if (MultiConnection.Count == 0)
            {
                PlaceRoom(Init, Entrance, Exit, Rnd.Angle());

                if (Boss != null && !PlaceBoss(Init, Exit))
                {
                    return(null);
                }

                return(Init);
            }

            var RoomsOnPath = (int)(MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);

            RoomsOnPath = Math.Min(RoomsOnPath, MultiConnection.Count);
            RoomDef Curr        = Entrance;
            var     PathTunnels = ArrayUtils.Clone(PathTunnelChances);

            for (var I = 0; I <= RoomsOnPath; I++)
            {
                if (I == RoomsOnPath && Exit == null)
                {
                    continue;
                }

                var Tunnels = Rnd.Chances(PathTunnels);

                if (Tunnels == -1)
                {
                    PathTunnels = ArrayUtils.Clone(PathTunnelChances);
                    Tunnels     = Rnd.Chances(PathTunnels);
                }

                PathTunnels[Tunnels]--;

                if (I != 0 && Run.Depth != 0)
                {
                    for (var J = 0; J < Tunnels; J++)
                    {
                        var T = RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated);

                        if (Math.Abs(PlaceRoom(Init, Curr, T, Direction + Rnd.Float(-PathVariance, PathVariance)) - (-1)) < 0.01f)
                        {
                            return(null);
                        }

                        Branchable.Add(T);
                        Init.Add(T);
                        Curr = T;
                    }
                }

                var R = I == RoomsOnPath ? Exit : MultiConnection[I];


                if (Math.Abs(PlaceRoom(Init, Curr, R, Direction + Rnd.Float(-PathVariance, PathVariance)) - (-1)) < 0.01f)
                {
                    return(null);
                }

                if (R == Exit && Boss != null && !PlaceBoss(Init, R))
                {
                    return(null);
                }

                Branchable.Add(R);
                Curr = R;
            }

            var RoomsToBranch = new List <RoomDef>();

            for (var I = RoomsOnPath; I < MultiConnection.Count; I++)
            {
                RoomsToBranch.Add(MultiConnection[I]);
            }

            RoomsToBranch.AddRange(SingleConnection);

            WeightRooms(Branchable);

            if (!CreateBranches(Init, Branchable, RoomsToBranch, BranchTunnelChances))
            {
                return(null);
            }

            FindNeighbours(Init);

            foreach (var R in Init)
            {
                foreach (var N in R.Neighbours)
                {
                    if (!N.Connected.ContainsKey(R) && Rnd.Float() < ExtraConnectionChance)
                    {
                        R.ConnectWithRoom(N);
                    }
                }
            }

            return(Init);
        }
Example #13
0
        public override List <RoomDef> Build(List <RoomDef> Init)
        {
            SetupRooms(Init);

            if (Entrance == null)
            {
                return(null);
            }

            Entrance.SetPos(0, 0);
            Entrance.SetSize();
            var StartAngle = Rnd.Angle();
            var Loop       = new List <RoomDef>();

            var RoomsOnLoop = (int)(MultiConnection.Count * PathLength) + Rnd.Chances(PathLenJitterChances);

            RoomsOnLoop = Math.Min(RoomsOnLoop, MultiConnection.Count);
            RoomsOnLoop++;
            var PathTunnels = ArrayUtils.Clone(PathTunnelChances);

            for (var i = MultiConnection.Count - 1; i >= 0; i--)
            {
                var r = MultiConnection[i];

                if (r is ConnectionRoom)
                {
                    Loop.Add(r);
                    MultiConnection.RemoveAt(i);
                }
            }

            for (var I = 0; I < RoomsOnLoop; I++)
            {
                if (I == 0)
                {
                    Loop.Add(Entrance);
                }
                else
                {
                    Loop.Add(MultiConnection[0]);
                    MultiConnection.RemoveAt(0);
                }

                var Tunnels = Rnd.Chances(PathTunnels);

                if (Tunnels == -1)
                {
                    PathTunnels = ArrayUtils.Clone(PathTunnelChances);
                    Tunnels     = Rnd.Chances(PathTunnels);
                }

                PathTunnels[Tunnels]--;

                for (var J = 0; J < Tunnels; J++)
                {
                    Loop.Add(RoomRegistry.Generate(RoomType.Connection, LevelSave.BiomeGenerated));
                }
            }

            if (Exit != null)
            {
                Loop.Insert((Loop.Count + 1) / 2, Exit);
            }

            if (LevelSave.BiomeGenerated is LibraryBiome)
            {
                var c = (Loop.Count + 1);

                Loop.Insert(c / 4, new LibraryConnectionRoom());
                Loop.Insert(c / 4 * 3, new LibraryConnectionRoom {
                    BottomHalf = true
                });
            }

            RoomDef Prev = Entrance;
            float   TargetAngle;

            for (var I = 1; I < Loop.Count; I++)
            {
                var R = Loop[I];
                TargetAngle = StartAngle + this.TargetAngle(I / (float)Loop.Count);

                if ((int)PlaceRoom(Init, Prev, R, TargetAngle) != -1)
                {
                    Prev = R;

                    if (!Init.Contains(Prev))
                    {
                        Init.Add(Prev);
                    }

                    if (R == Exit && Boss != null)
                    {
                        var a = TargetAngle - 90;
                        var i = 0;

                        while (true)
                        {
                            var an = PlaceRoom(Init, R, Boss, a);

                            if ((int)an != -1)
                            {
                                break;
                            }

                            i++;

                            if (i > 36)
                            {
                                return(null);
                            }

                            a += 10;
                        }

                        a = Rnd.Angle();
                        i = 0;

                        if (Granny != null)
                        {
                            while (true)
                            {
                                var an = PlaceRoom(Init, Boss, Granny, a);

                                if ((int)an != -1)
                                {
                                    break;
                                }

                                i++;

                                if (i > 72)
                                {
                                    return(null);
                                }

                                a += 5;
                            }
                        }

                        a = Rnd.Angle();
                        i = 0;

                        if (OldMan != null)
                        {
                            while (true)
                            {
                                var an = PlaceRoom(Init, Boss, OldMan, a);

                                if ((int)an != -1)
                                {
                                    break;
                                }

                                i++;

                                if (i > 72)
                                {
                                    return(null);
                                }

                                a += 5;
                            }
                        }
                    }
                }
                else
                {
                    return(null);
                }
            }

            while (!Prev.ConnectTo(Entrance))
            {
                var C = RoomRegistry.Generate(RoomType.Regular, LevelSave.BiomeGenerated);

                if ((int)PlaceRoom(Loop, Prev, C, AngleBetweenRooms(Prev, Entrance)) == -1)
                {
                    return(null);
                }

                Loop.Add(C);
                Init.Add(C);
                Prev = C;
            }

            LoopCenter = new Vector2();

            foreach (var R in Loop)
            {
                LoopCenter.X += (R.Left + R.Right) / 2f;
                LoopCenter.Y += (R.Top + R.Bottom) / 2f;
            }

            LoopCenter.X /= Loop.Count;
            LoopCenter.Y /= Loop.Count;
            var Branchable    = new List <RoomDef>(Loop);
            var RoomsToBranch = new List <RoomDef>();

            RoomsToBranch.AddRange(MultiConnection);
            RoomsToBranch.AddRange(SingleConnection);
            WeightRooms(Branchable);

            if (!CreateBranches(Init, Branchable, RoomsToBranch, BranchTunnelChances))
            {
                return(null);
            }

            FindNeighbours(Init);

            foreach (var R in Init)
            {
                foreach (var N in R.Neighbours)
                {
                    if (!N.Connected.ContainsKey(R) && Rnd.Float() < ExtraConnectionChance)
                    {
                        R.ConnectWithRoom(N);
                    }
                }
            }

            if (!Prev.Connected.ContainsKey(Entrance))
            {
                Prev.Neighbours.Add(Entrance);
                Entrance.Neighbours.Add(Prev);
                Prev.Connected[Entrance] = null;
                Entrance.Connected[Prev] = null;
            }

            return(Init);
        }