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); }