Ejemplo n.º 1
0
        private void OnLoadLevelHook(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool fromLoader)
        {
            var settings = this.InRandomizerSettings;

            if (fromLoader && settings != null)
            {
                // Don't restart the timer on retry
                self.Session.FirstLevel = false;
            }
            orig(self, playerIntro, fromLoader);
            // also, set the core mode right
            if (fromLoader && this.InRandomizer)
            {
                var leveldata             = self.Session.LevelData;
                var dyn                   = new DynData <LevelData>(leveldata);
                RandoConfigCoreMode modes = dyn.Get <RandoConfigCoreMode>("coreModes");
                self.CoreMode         = modes?.All ?? Session.CoreModes.None;
                self.Session.CoreMode = self.CoreMode;
            }

            if (settings != null && settings.Algorithm == LogicType.Labyrinth && Everest.Loader.DependencyLoaded(new EverestModuleMetadata()
            {
                Name = "BingoUI"
            }))
            {
                var ui = LoadGemUI(fromLoader); // must be a separate method or the jit will be very sad :(
                self.Add(ui);                   // lord f*****g help us
            }
        }
Ejemplo n.º 2
0
        private void OnLoadLevelHook(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool fromLoader)
        {
            // HACK: reset endingSettings in case VersionNumberAndVariants is called from something other than AreaComplete
            this.endingSettings = null;

            var settings = this.InRandomizerSettings;

            if (fromLoader && settings != null)
            {
                // Don't restart the timer on retry
                self.Session.FirstLevel = false;
            }
            orig(self, playerIntro, fromLoader);
            // also, set the core mode right
            // if we're transitioning, we already set it correctly via the direction
            if (settings != null && !self.Transitioning && playerIntro != Player.IntroTypes.Respawn)
            {
                var leveldata             = self.Session.LevelData;
                var dyn                   = new DynData <LevelData>(leveldata);
                RandoConfigCoreMode modes = dyn.Get <RandoConfigCoreMode>("coreModes");
                self.CoreMode         = modes?.All ?? Session.CoreModes.None;
                self.Session.CoreMode = self.CoreMode;
            }

            if (settings != null && settings.IsLabyrinth && Everest.Loader.DependencyLoaded(new EverestModuleMetadata()
            {
                Name = "BingoUI"
            }))
            {
                var ui = LoadGemUI(fromLoader); // must be a separate method or the jit will be very sad :(
                self.Add(ui);                   // lord f*****g help us
            }

            if (settings != null && playerIntro == Player.IntroTypes.Transition)
            {
                // reset color grading
                self.NextColorGrade("", 2f);
            }
        }
Ejemplo n.º 3
0
        public StaticRoom(AreaKey Area, RandoConfigRoom config, LevelData Level, List <Hole> Holes)
        {
            this.Area  = Area;
            this.Level = Level;
            this.Holes = Holes;

            this.Name       = AreaData.Get(Area).GetSID() + "/" + (Area.Mode == AreaMode.Normal ? "A" : Area.Mode == AreaMode.BSide ? "B" : "C") + "/" + Level.Name;
            this.End        = config.End;
            this.Hub        = config.Hub;
            this.Tweaks     = config.Tweaks ?? new List <RandoConfigEdit>();
            this.CoreModes  = config.Core;
            this.ExtraSpace = config.ExtraSpace ?? new List <RandoConfigRectangle>();

            this.Collectables = new List <StaticCollectable>();
            foreach (var entity in Level.Entities)
            {
                switch (entity.Name.ToLower())
                {
                case "strawberry":
                case "key":
                    this.Collectables.Add(new StaticCollectable {
                        Position = entity.Position,
                        MustFly  = false,
                    });
                    break;
                }
            }
            this.Collectables.Sort((StaticCollectable a, StaticCollectable b) => {
                if (a.Position.Y > b.Position.Y)
                {
                    return(1);
                }
                else if (a.Position.Y < b.Position.Y)
                {
                    return(-1);
                }
                else if (a.Position.X > b.Position.X)
                {
                    return(1);
                }
                else if (a.Position.X < b.Position.X)
                {
                    return(-1);
                }
                else
                {
                    return(0);
                }
            });

            this.Nodes = new Dictionary <string, StaticNode>()
            {
                { "main", new StaticNode()
                  {
                      Name       = "main",
                      ParentRoom = this
                  } }
            };
            foreach (var subroom in config.Subrooms ?? new List <RandoConfigRoom>())
            {
                if (subroom.Room == null || this.Nodes.ContainsKey(subroom.Room))
                {
                    throw new Exception($"Invalid subroom name in {this.Area} {this.Name}");
                }
                this.Nodes.Add(subroom.Room, new StaticNode()
                {
                    Name = subroom.Room, ParentRoom = this
                });
            }

            this.ProcessSubroom(this.Nodes["main"], config);
            foreach (var subroom in config.Subrooms ?? new List <RandoConfigRoom>())
            {
                this.ProcessSubroom(this.Nodes[subroom.Room], subroom);
            }

            // assign unmarked holes
            foreach (var uhole in this.Holes)
            {
                if (uhole.Kind != HoleKind.Unknown)
                {
                    continue;
                }

                var        bestDist = 10000f;
                StaticNode bestNode = null;
                var        lowPos   = uhole.LowCoord(this.Level.Bounds);
                var        highPos  = uhole.HighCoord(this.Level.Bounds);
                foreach (var node in this.Nodes.Values)
                {
                    foreach (var edge in node.Edges)
                    {
                        if (edge.HoleTarget == null)
                        {
                            continue;
                        }
                        if (edge.HoleTarget == uhole)
                        {
                            bestNode = null;
                            goto doublebreak;
                        }

                        var pos  = edge.HoleTarget.LowCoord(this.Level.Bounds);
                        var dist = (pos - lowPos).Length();
                        if (!uhole.LowOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        dist = (pos - highPos).Length();
                        if (!uhole.HighOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        pos  = edge.HoleTarget.HighCoord(this.Level.Bounds);
                        dist = (pos - lowPos).Length();
                        if (!uhole.LowOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        dist = (pos - highPos).Length();
                        if (!uhole.HighOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }
                    }
                }

doublebreak:
                if (bestNode != null)
                {
                    bestNode.Edges.Add(new StaticEdge {
                        FromNode   = bestNode,
                        HoleTarget = uhole,
                        ReqIn      = this.ProcessReqs(null, uhole, false),
                        ReqOut     = this.ProcessReqs(null, uhole, true),
                    });
                }
            }

            // assign unmarked collectables
            foreach (var c in this.Collectables)
            {
                if (c.ParentNode != null)
                {
                    continue;
                }

                var        bestDist = 1000f;
                StaticNode bestNode = null;
                foreach (var node in this.Nodes.Values)
                {
                    foreach (var edge in node.Edges)
                    {
                        if (edge.HoleTarget == null)
                        {
                            continue;
                        }

                        var pos  = edge.HoleTarget.LowCoord(new Rectangle(0, 0, this.Level.Bounds.Width, this.Level.Bounds.Height));
                        var dist = (pos - c.Position).Length();
                        if (dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        pos  = edge.HoleTarget.HighCoord(new Rectangle(0, 0, this.Level.Bounds.Width, this.Level.Bounds.Height));
                        dist = (pos - c.Position).Length();
                        if (dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }
                    }
                }

                if (bestNode != null)
                {
                    c.ParentNode = bestNode;
                    bestNode.Collectables.Add(c);
                }
            }
        }
Ejemplo n.º 4
0
        public StaticRoom(AreaKey Area, RandoConfigRoom config, LevelData Level, List <Hole> Holes)
        {
            // hack: force credits screens into the epilogue roomset
            if (Area.ID == 7 && Level.Name.StartsWith("credits-"))
            {
                Area = new AreaKey(8);
            }
            this.Area  = Area;
            this.Level = Level;
            this.Holes = Holes;

            this.Name            = AreaData.Get(Area).GetSID() + "/" + (Area.Mode == AreaMode.Normal ? "A" : Area.Mode == AreaMode.BSide ? "B" : "C") + "/" + Level.Name;
            this.ReqEnd          = this.ProcessReqs(config.ReqEnd);
            this.Hub             = config.Hub;
            this.Tweaks          = config.Tweaks ?? new List <RandoConfigEdit>();
            this.CoreModes       = config.Core;
            this.ExtraSpace      = config.ExtraSpace ?? new List <RandoConfigRectangle>();
            this.Worth           = config.Worth ?? (float)Math.Sqrt(Level.Bounds.Width * Level.Bounds.Width + Level.Bounds.Height * Level.Bounds.Height) / 369.12870384189847f + 1;
            this.SpinnersShatter = config.SpinnersShatter;

            this.Collectables = new List <StaticCollectable>();
            foreach (var entity in Level.Entities)
            {
                if (RandoModule.Instance.MetaConfig.CollectableNames.Contains(entity.Name))
                {
                    this.Collectables.Add(new StaticCollectable {
                        Position = entity.Position,
                        MustFly  = false,
                    });
                }
            }
            this.Collectables.Sort((a, b) => {
                if (a.Position.Y > b.Position.Y)
                {
                    return(1);
                }
                else if (a.Position.Y < b.Position.Y)
                {
                    return(-1);
                }
                else if (a.Position.X > b.Position.X)
                {
                    return(1);
                }
                else if (a.Position.X < b.Position.X)
                {
                    return(-1);
                }
                else
                {
                    return(0);
                }
            });

            this.Nodes = new Dictionary <string, StaticNode>()
            {
                { "main", new StaticNode()
                  {
                      Name       = "main",
                      ParentRoom = this
                  } }
            };
            foreach (var subroom in config.Subrooms ?? new List <RandoConfigRoom>())
            {
                if (subroom.Room == null || this.Nodes.ContainsKey(subroom.Room))
                {
                    throw new Exception($"Invalid subroom name in {this.Area} {this.Name}");
                }
                this.Nodes.Add(subroom.Room, new StaticNode()
                {
                    Name = subroom.Room, ParentRoom = this
                });
            }

            this.ProcessSubroom(this.Nodes["main"], config);
            foreach (var subroom in config.Subrooms ?? new List <RandoConfigRoom>())
            {
                this.ProcessSubroom(this.Nodes[subroom.Room], subroom);
            }

            // assign unmarked holes
            foreach (var uhole in this.Holes)
            {
                if (uhole.Kind != HoleKind.Unknown)
                {
                    continue;
                }

                var        bestDist = 10000f;
                StaticNode bestNode = null;
                var        lowPos   = uhole.LowCoord(this.Level.Bounds);
                var        highPos  = uhole.HighCoord(this.Level.Bounds);
                foreach (var node in this.Nodes.Values)
                {
                    foreach (var edge in node.Edges.Where(edge => edge.HoleTarget != null))
                    {
                        if (edge.HoleTarget == uhole)
                        {
                            bestNode = null;
                            goto doublebreak;
                        }

                        var pos  = edge.HoleTarget.LowCoord(this.Level.Bounds);
                        var dist = (pos - lowPos).Length();
                        if (!uhole.LowOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        dist = (pos - highPos).Length();
                        if (!uhole.HighOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        pos  = edge.HoleTarget.HighCoord(this.Level.Bounds);
                        dist = (pos - lowPos).Length();
                        if (!uhole.LowOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        dist = (pos - highPos).Length();
                        if (!uhole.HighOpen && dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }
                    }
                }

doublebreak:
                bestNode?.Edges?.Add(new StaticEdge {
                    FromNode   = bestNode,
                    HoleTarget = uhole,
                    ReqIn      = this.ProcessReqs(null, uhole, false),
                    ReqOut     = this.ProcessReqs(null, uhole, true),
                });
            }

            // assign unmarked collectables
            foreach (var c in this.Collectables)
            {
                if (c.ParentNode != null)
                {
                    continue;
                }

                var        bestDist = 1000f;
                StaticNode bestNode = null;
                foreach (var node in this.Nodes.Values)
                {
                    foreach (var edge in node.Edges)
                    {
                        if (edge.HoleTarget == null)
                        {
                            continue;
                        }

                        var pos  = edge.HoleTarget.LowCoord(new Rectangle(0, 0, this.Level.Bounds.Width, this.Level.Bounds.Height));
                        var dist = (pos - c.Position).Length();
                        if (dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }

                        pos  = edge.HoleTarget.HighCoord(new Rectangle(0, 0, this.Level.Bounds.Width, this.Level.Bounds.Height));
                        dist = (pos - c.Position).Length();
                        if (dist < bestDist)
                        {
                            bestDist = dist;
                            bestNode = node;
                        }
                    }
                }

                if (bestNode != null)
                {
                    c.ParentNode = bestNode;
                    bestNode.Collectables.Add(c);
                }
            }

            // perform fg tweaks
            var regex     = new Regex("\\r\\n|\\n\\r|\\n|\\r");
            var tweakable = new List <List <char> >();

            foreach (var line in regex.Split(Level.Solids))
            {
                var lst = new List <char>();
                tweakable.Add(lst);
                foreach (var ch in line)
                {
                    lst.Add(ch);
                }
            }

            void setTile(int x, int y, char tile)
            {
                while (y >= tweakable.Count)
                {
                    tweakable.Add(new List <char>());
                }

                while (x >= tweakable[y].Count)
                {
                    tweakable[y].Add('0');
                }

                tweakable[y][x] = tile;
            }

            foreach (var tweak in config.Tweaks ?? new List <RandoConfigEdit>())
            {
                if (tweak.Name == "fgTiles")
                {
                    setTile((int)tweak.X, (int)tweak.Y, tweak.Update.Tile);
                }
            }

            Level.Solids = string.Join("\n", tweakable.Select(line => string.Join("", line)));

            // peform decal tweaks
            foreach (var decalList in new[] { Level.FgDecals, Level.BgDecals })
            {
                var removals = new List <DecalData>();
                foreach (var decal in decalList)
                {
                    var fg = object.ReferenceEquals(decalList, Level.FgDecals);
                    foreach (var tweak in config.Tweaks ?? new List <RandoConfigEdit>())
                    {
                        if (tweak.Decal == (fg ? RandoConfigDecalType.FG : RandoConfigDecalType.BG) &&
                            (tweak.Name == null || tweak.Name == decal.Texture) &&
                            (tweak.X == null || (int)tweak.X.Value == (int)decal.Position.X) &&
                            (tweak.Y == null || (int)tweak.Y.Value == (int)decal.Position.Y))
                        {
                            if (tweak.Update?.Remove ?? false)
                            {
                                removals.Add(decal);
                            }
                            else
                            {
                                if (tweak.Update?.X != null)
                                {
                                    decal.Position.X = tweak.Update.X.Value;
                                }
                                if (tweak.Update?.Y != null)
                                {
                                    decal.Position.Y = tweak.Update.Y.Value;
                                }
                                if (tweak.Update?.ScaleX != null)
                                {
                                    decal.Position.X = tweak.Update.ScaleX.Value;
                                }
                                if (tweak.Update?.ScaleY != null)
                                {
                                    decal.Position.Y = tweak.Update.ScaleY.Value;
                                }
                            }

                            break;
                        }
                    }
                }

                foreach (var decal in removals)
                {
                    decalList.Remove(decal);
                }
            }

            foreach (var tweak in config.Tweaks ?? new List <RandoConfigEdit>())
            {
                if ((tweak.Update?.Add ?? false) && tweak.Decal != RandoConfigDecalType.None)
                {
                    var newDecal = new DecalData {
                        Texture  = tweak.Name,
                        Position = new Vector2(tweak.Update.X.Value, tweak.Update.Y.Value),
                        Scale    = new Vector2(tweak.Update.ScaleX.Value, tweak.Update.ScaleY.Value),
                    };
                    (tweak.Decal == RandoConfigDecalType.BG ? Level.BgDecals : Level.FgDecals).Add(newDecal);
                }
            }
        }