Esempio n. 1
0
        public static LinkedNodeSet Closure(LinkedNode start, Capabilities capsForward, Capabilities capsReverse, bool internalOnly, int maxDistance = 9999)
        {
            var result = new LinkedNodeSet(new List <LinkedNode> {
                start
            });

            result.Extend(capsForward, capsReverse, internalOnly, maxDistance);
            return(result);
        }
Esempio n. 2
0
            public override bool Next()
            {
                if (this.Tries >= 5)
                {
                    Logger.Log("randomizer", $"Failure: took too many tries to satisfy {this.Req} from {Node.Room.Static.Name}:{Node.Static.Name}");
                    return(false);
                }

                // each attempt we should back further away from the idea that we might add a new room
                int  roll         = this.Logic.Random.Next(5);
                bool extendingMap = roll > this.Tries;

                this.Tries++;

                var caps     = this.Logic.Caps.WithoutKey().WithFlags(this.State);
                int maxSteps = 99999;

                if (!InternalOnly)
                {
                    maxSteps = this.Logic.Random.Next(1, 20);
                }
                var closure = LinkedNodeSet.Closure(this.Node, caps, caps, this.InternalOnly, maxSteps);

                closure.Shuffle(this.Logic.Random);

                if (this.Req is FlagRequirement fr)
                {
                    var curval = this.State.TryGetValue(fr.Flag, out var x) ? x : FlagState.Unset;
                    if (fr.Set && (curval == FlagState.Both || curval == FlagState.Set || curval == FlagState.UnsetToSet))
                    {
                        return(true);
                    }
                    if (!fr.Set && (curval == FlagState.Both || curval == FlagState.Unset || curval == FlagState.SetToUnset))
                    {
                        return(true);
                    }
                }

                if (!extendingMap)
                {
                    switch (this.Req)
                    {
                    case KeyRequirement keyReq: {
                        // just try to place a key
                        foreach (var spot in closure.UnlinkedCollectables())
                        {
                            if (spot.Static.MustFly)
                            {
                                continue;
                            }
                            if (spot.Node.Room == this.OriginalNode.Room)
                            {
                                // don't be boring!
                                continue;
                            }
                            this.AddReceipt(PlaceCollectableReceipt.Do(spot.Node, spot.Static, LinkedCollectable.Key, false, keyReq.KeyholeID, this.OriginalNode.Room));
                            return(true);
                        }

                        // try again for things that we need to bubble back from
                        var newClosure = new LinkedNodeSet(closure);
                        newClosure.Extend(caps, null, true);
                        foreach (var spot in newClosure.UnlinkedCollectables())
                        {
                            if (spot.Static.MustFly)
                            {
                                continue;
                            }
                            if (spot.Node.Room == this.OriginalNode.Room)
                            {
                                // don't be boring!
                                continue;
                            }
                            this.AddReceipt(PlaceCollectableReceipt.Do(spot.Node, spot.Static, LinkedCollectable.Key, true, keyReq.KeyholeID, this.OriginalNode.Room));
                            return(true);
                        }

                        // third try: place a room which has a reachable spot
                        var appropriateNodes = this.Logic.RemainingRooms
                                               .Where(x => x.ReqEnd is Impossible)
                                               .SelectMany(r => r.Nodes.Values)
                                               .Where(n => n.Collectables.Count(c => !c.MustFly) != 0)
                                               .ToList();
                        appropriateNodes.Shuffle(this.Logic.Random);
                        foreach (var n in appropriateNodes)
                        {
                            // hack: make a linkednode for each staticnode so that the closure methods can work on it...
                            var edges = LinkedNodeSet
                                        .Closure(new LinkedRoom(n.ParentRoom, Vector2.Zero).Nodes[n.Name], caps, caps, true)
                                        .Shuffle(this.Logic.Random)
                                        .UnlinkedEdges()
                                        .Select(e => e.Static);
                            foreach (var edge in edges)
                            {
                                foreach (var startEdge in closure.UnlinkedEdges())
                                {
                                    var receipt = ConnectAndMapReceipt.Do(this.Logic, startEdge, edge, true);
                                    if (receipt != null)
                                    {
                                        this.AddReceipt(receipt);
                                        var cols = n.Collectables.Where(c => !c.MustFly).ToList();
                                        cols.Shuffle(this.Logic.Random);
                                        this.AddReceipt(PlaceCollectableReceipt.Do(receipt.NewRoom.Nodes[n.Name], cols[this.Logic.Random.Next(cols.Count)], LinkedCollectable.Key, false, keyReq.KeyholeID, this.OriginalNode.Room));
                                        return(true);
                                    }
                                }
                            }
                        }

                        break;
                    }

                    case FlagRequirement flagReq: {
                        var appropriateNodes = this.Logic.RemainingRooms
                                               .SelectMany(r => r.Nodes.Values)
                                               .Where(n => n.FlagSetters.Any(s => s.Item1 == flagReq.Flag && s.Item2 == flagReq.Set))
                                               .ToList();
                        appropriateNodes.Shuffle(this.Logic.Random);
                        foreach (var n in appropriateNodes)
                        {
                            // hack: make a linkednode for each staticnode so that the closure methods can work on it...
                            var edges = LinkedNodeSet
                                        .Closure(new LinkedRoom(n.ParentRoom, Vector2.Zero).Nodes[n.Name], caps, caps, true)
                                        .Shuffle(this.Logic.Random)
                                        .UnlinkedEdges()
                                        .Select(e => e.Static);
                            foreach (var edge in edges)
                            {
                                foreach (var startEdge in closure.UnlinkedEdges())
                                {
                                    var receipt = ConnectAndMapReceipt.Do(this.Logic, startEdge, edge, true);
                                    if (receipt != null)
                                    {
                                        this.AddReceipt(receipt);
                                        // TODO: check for reverse traversability back to orig node
                                        return(true);
                                    }
                                }
                            }
                        }
                        break;
                    }

                    default: {
                        throw new Exception($"Don't know how to satisfy {this.Req}. What?");
                    }
                    }
                }

                // see if we can find somewhere to extend the map
                foreach (var outEdge in closure.UnlinkedEdges())
                {
                    if (!this.Logic.Map.HoleFree(outEdge.Node.Room, outEdge.Static.HoleTarget))
                    {
                        continue;
                    }
                    foreach (var toEdge in this.Logic.AvailableNewEdges(caps, caps, e => e.FromNode.ParentRoom.ReqEnd is Impossible))
                    {
                        var mapped = ConnectAndMapReceipt.Do(this.Logic, outEdge, toEdge, isBacktrack: true);
                        if (mapped == null)
                        {
                            continue;
                        }

                        this.AddReceipt(mapped);
                        this.AddNextTask(new TaskPathwaySatisfyRequirement(this.Logic, mapped.EntryNode, this.Req, this.State, this.OriginalNode, true, this.Tries));
                        return(true);
                    }
                }

                // if we failed to both extend the map or place the capability at the same time, we're f****d!
                if (!extendingMap)
                {
                    return(false);
                }

                // try again
                return(this.Next());
            }
            public override bool Next()
            {
                if (this.Tries >= 5)
                {
                    Logger.Log("randomizer", $"Failure: took too many tries to place key from {Node.Room.Static.Name}:{Node.Static.Name}");
                    return(false);
                }

                // each attempt we should back further away from the idea that we might add a new room
                int  roll         = this.Logic.Random.Next(5);
                bool extendingMap = roll > this.Tries;

                this.Tries++;

                var caps     = this.Logic.Caps.WithoutKey();
                int maxSteps = 99999;

                if (!InternalOnly)
                {
                    maxSteps = this.Logic.Random.Next(6, 20);
                }
                var closure = LinkedNodeSet.Closure(this.Node, caps, caps, this.InternalOnly, maxSteps);

                closure.Shuffle(this.Logic.Random);

                if (!extendingMap)
                {
                    // just try to place a key
                    foreach (var spot in closure.UnlinkedCollectables())
                    {
                        if (spot.Static.MustFly)
                        {
                            continue;
                        }
                        if (spot.Node.Room == this.OriginalNode.Room)
                        {
                            // don't be boring!
                            continue;
                        }
                        this.AddReceipt(PlaceCollectableReceipt.Do(spot.Node, spot.Static, LinkedNode.LinkedCollectable.Key, false));
                        this.OriginalNode.Room.UsedKeyholes.Add(this.KeyholeID);
                        return(true);
                    }

                    // try again for things that we need to bubble back from
                    var newClosure = new LinkedNodeSet(closure);
                    newClosure.Extend(caps, null, true);
                    foreach (var spot in newClosure.UnlinkedCollectables())
                    {
                        if (spot.Static.MustFly)
                        {
                            continue;
                        }
                        if (spot.Node.Room == this.OriginalNode.Room)
                        {
                            // don't be boring!
                            continue;
                        }
                        this.AddReceipt(PlaceCollectableReceipt.Do(spot.Node, spot.Static, LinkedNode.LinkedCollectable.Key, true));
                        this.OriginalNode.Room.UsedKeyholes.Add(this.KeyholeID);
                        return(true);
                    }
                }

                // see if we can find somewhere to extend the map
                foreach (var outEdge in closure.UnlinkedEdges())
                {
                    if (!this.Logic.Map.HoleFree(outEdge.Node.Room, outEdge.Static.HoleTarget))
                    {
                        continue;
                    }
                    foreach (var toEdge in this.Logic.AvailableNewEdges(caps, caps, e => e.FromNode.ParentRoom.ReqEnd is Impossible))
                    {
                        var mapped = ConnectAndMapReceipt.Do(this.Logic, outEdge, toEdge, isBacktrack: true);
                        if (mapped == null)
                        {
                            continue;
                        }
                        this.AddReceipt(mapped);
                        this.AddNextTask(new TaskPathwayPlaceKey(this.Logic, mapped.EntryNode, this.KeyholeID, this.OriginalNode, true, this.Tries));
                        return(true);
                    }
                }

                // try again
                return(this.Next());
            }