Exemple #1
0
        public IEnumerable <Tuple <LinkedNode, Requirement> > SuccessorsRequires(Capabilities capsForward, bool onlyInternal = false)
        {
            foreach (var iedge in this.Static.Edges)
            {
                if (iedge.NodeTarget == null)
                {
                    continue;
                }
                var reqs = iedge.ReqOut.Conflicts(capsForward);
                if (reqs is Impossible)
                {
                    continue;
                }

                if (iedge.NodeTarget.ParentRoom == this.Room.Static)
                {
                    yield return(Tuple.Create(this.Room.Nodes[iedge.NodeTarget.Name], reqs));
                }
                else
                {
                    yield return(Tuple.Create(this.Room.WarpMap[iedge.NodeTarget.ParentRoom.Level.Name].Nodes[iedge.NodeTarget.Name], reqs));
                }
            }

            if (!onlyInternal)
            {
                foreach (var edge in this.Edges)
                {
                    var check1 = edge.CorrespondingEdge(this);
                    var check2 = edge.OtherEdge(this);

                    var reqs = Requirement.And(new List <Requirement> {
                        check1.ReqOut.Conflicts(capsForward), check2.ReqIn.Conflicts(capsForward)
                    });
                    if (reqs is Impossible)
                    {
                        continue;
                    }
                    yield return(Tuple.Create(edge.OtherNode(this), reqs));
                }
            }
        }
        public override bool Equals(Requirement other)
        {
            // TODO: this assumes that hashes are unique...

            if (!(other is Disjunction i))
            {
                return(false);
            }
            if (this.Children.Count != i.Children.Count)
            {
                return(false);
            }
            for (int j = 0; j < this.Children.Count; j++)
            {
                if (!this.Children[j].Equals(i.Children[j]))
                {
                    return(false);
                }
            }
            return(true);
        }
        public override bool StrictlyBetterThan(Requirement other)
        {
            if (other is Possible)
            {
                return(false);
            }
            if (other is Impossible)
            {
                return(true);
            }
            if (other is Conjunction c)
            {
                // in order for this to be strictly better than other, all of this' elements must be present in other
                // and other must have extra elements
                if (this.Children.Count >= c.Children.Count)
                {
                    return(false);
                }
                foreach (var thisChild in this.Children)
                {
                    var found = false;
                    foreach (var cChild in c.Children)
                    {
                        if (cChild.Equals(thisChild))
                        {
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                    {
                        return(false);
                    }
                }
                return(true);
            }

            // a conjunction cannot possibly be a strict improvement over something which is not a conjunction
            return(false);
        }
        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);
                }
            }
        }
 public Disjunction(List <Requirement> Children)
 {
     Requirement.Normalize(Children);
     this.Children = Children;
 }
 public override bool StrictlyBetterThan(Requirement other)
 {
     return(true);
 }