/// <summary>
        /// <para>Calculates and returns which resources can meet meet the logical criteria
        /// for refilling by farming this farm cycle.</para>
        /// <para>This includes resources that only meet those criteria after redistributing
        /// the drop rate from other resources that were farmed to full.</para>
        /// </summary>
        /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
        /// <param name="costingResources">A dictionary of resources that have a cost associated with executing a cycle.
        /// The resource is the key and the cost per cycle is the value.</param>
        /// <returns></returns>
        private IEnumerable <ConsumableResourceEnum> ComputeFarmableResources(SuperMetroidModel model,
                                                                              IDictionary <ConsumableResourceEnum, int> costingResources)
        {
            ISet <ConsumableResourceEnum>        farmableResources = new HashSet <ConsumableResourceEnum>();
            IEnumerable <ConsumableResourceEnum> newFarmableResources;

            // Figure out which resources meet the threshold for farmability
            // We'll keep looping as long as we find farmable resources,
            // to discover resources that go above the threshold when redistributing drop rates
            do
            {
                // Determine effective drop rates for this iteration
                EnemyDrops effectiveDropRates = FarmCycle.RoomEnemy.Enemy.GetEffectiveDropRates(model, farmableResources);

                // Look for resources that meet the logical farming threshold, but didn't in the previous loops
                newFarmableResources = Enum.GetValues(typeof(ConsumableResourceEnum))
                                       .Cast <ConsumableResourceEnum>()
                                       .Except(farmableResources)
                                       .Where(resource =>
                {
                    return(CalculateResourceVariationPerSecond(model, resource, effectiveDropRates, costingResources)
                           >= model.LogicalOptions.SpawnerFarmingOptions.MinimumRatesPerSecond[resource]);
                })
                                       // Actualize this to calculate it only once
                                       .ToArray();

                farmableResources.UnionWith(newFarmableResources);
            } // Stop iterating if the last loop revealed no new farmable resource
            while (newFarmableResources.Any());

            return(farmableResources);
        }
        public bool IsResourceAvailable(SuperMetroidModel model, ConsumableResourceEnum resource, int quantity)
        {
            if (quantity == 0)
            {
                return(true);
            }

            // If resource tracking is enabled, look at current resource amounts
            if (model.LogicalOptions.ResourceTrackingEnabled)
            {
                // The other resources can be fully spent, but for energy we don't want to go below 1
                if (resource == ConsumableResourceEnum.ENERGY)
                {
                    return(GetCurrentAmount(resource) > quantity);
                }
                else
                {
                    return(GetCurrentAmount(resource) >= quantity);
                }
            }
            // If resource tracking is not enabled, use max resource amounts instead of current amounts
            else
            {
                // The other resources can be fully spent, but for energy we don't want to go below 1
                if (resource == ConsumableResourceEnum.ENERGY)
                {
                    return(GetMaxAmount(resource) > quantity);
                }
                else
                {
                    return(GetMaxAmount(resource) >= quantity);
                }
            }
        }
示例#3
0
        public override ExecutionResult Execute(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
        {
            IEnumerable <int> visitedNodeIds = inGameState.GetVisitedNodeIds(usePreviousRoom);

            // If the node at which we entered is not allowed, this is not fulfilled.
            if (!NodeIds.Contains(visitedNodeIds.First()))
            {
                return(null);
            }

            // If we have visited a node to avoid, this is not fulfilled.
            if (NodeIdsToAvoid.Intersect(visitedNodeIds).Any())
            {
                return(null);
            }

            // If we were supposed to stay put but have visited more than the starting node, this is not fulfilled
            if (MustStayPut && visitedNodeIds.Count() > 1)
            {
                return(null);
            }

            // If we have destroyed an obstacle that needed to be preserved, this is not fulfilled
            if (ObstaclesIdsToAvoid.Intersect(inGameState.GetDestroyedObstacleIds(usePreviousRoom)).Any())
            {
                return(null);
            }

            // We've avoided all pitfalls. This ResetRoom is fulfilled. Clone the InGameState to fulfill method contract
            return(new ExecutionResult(inGameState.Clone()));
        }
        /// <summary>
        /// <para>Calculates how much of the provided resource is gained or lost (on average) by executing this farm cycle once,
        /// given the provided effective drop rates and resource costs per cycle</para>
        /// <para>If the resource is also spent while executing a cycle, the calculation includes
        /// reducing the drop rate by the safety margin in the logical options.</para>
        /// </summary>
        /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
        /// <param name="resource">The resource to check</param>
        /// <param name="effectiveDropRates">The effective drop rates, after accounting for unneeded drops.</param>
        /// <param name="costingResources">A dictionary  of resources to their cost per cycle.</param>
        /// <returns></returns>
        private decimal CalculateResourceVariationPerCycle(SuperMetroidModel model, ConsumableResourceEnum resource,
                                                           EnemyDrops effectiveDropRates, IDictionary <ConsumableResourceEnum, int> costingResources)
        {
            // If this farm cycle has to spend some of this resource, do some adaptations:
            // - Reduce the expected drop rate by the logical safety margin
            // - Include the cost when looking at the amount obtained from drops
            decimal dropRateMultiplier;
            int     costPerCycle;

            if (costingResources.TryGetValue(resource, out costPerCycle))
            {
                dropRateMultiplier = (100 - model.LogicalOptions.SpawnerFarmingOptions.SafetyMarginPercent) / 100;
            }
            else
            {
                costPerCycle       = 0;
                dropRateMultiplier = 1M;
            }

            decimal netGainPerCycle = resource.GetRelatedDrops()
                                      .Select(drop => dropRateMultiplier * model.Rules.ConvertDropRateToPercent(effectiveDropRates.GetDropRate(drop))
                                              * FarmCycle.RoomEnemy.Quantity * model.Rules.GetDropResourceCount(drop))
                                      .Sum() - costPerCycle;

            return(netGainPerCycle);
        }
示例#5
0
        public void Initialize(SuperMetroidModel model)
        {
            SuperMetroidModel = model;

            List <Action> postInitializationCallbacks = new List <Action>();

            foreach (RoomNode node in Nodes.Values)
            {
                postInitializationCallbacks.AddRange(node.Initialize(model, this));
            }

            foreach (RoomObstacle obstacle in Obstacles.Values)
            {
                postInitializationCallbacks.AddRange(obstacle.Initialize(model, this));
            }

            foreach (Link link in Links)
            {
                postInitializationCallbacks.AddRange(link.Initialize(model, this));
            }

            foreach (RoomEnemy enemy in EnemiesSequence)
            {
                postInitializationCallbacks.AddRange(enemy.Initialize(model, this));
            }

            // If we received any callbacks to execute after the room is done, execute them now
            postInitializationCallbacks.ForEach(action => action.Invoke());
        }
示例#6
0
        public IEnumerable <string> InitializeReferencedLogicalElementProperties(SuperMetroidModel model)
        {
            List <string> unhandled = new List <string>();

            foreach (RoomNode node in Nodes.Values)
            {
                unhandled.AddRange(node.InitializeReferencedLogicalElementProperties(model, this));
            }

            foreach (Link link in Links)
            {
                unhandled.AddRange(link.InitializeReferencedLogicalElementProperties(model, this));
            }

            foreach (RoomEnemy enemy in EnemiesSequence)
            {
                unhandled.AddRange(enemy.InitializeReferencedLogicalElementProperties(model, this));
            }

            foreach (RoomObstacle obstacle in Obstacles.Values)
            {
                unhandled.AddRange(obstacle.InitializeReferencedLogicalElementProperties(model, this));
            }

            return(unhandled.Distinct());
        }
示例#7
0
        public override int CalculateDamage(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
        {
            int currentRegularEnergy = inGameState.GetCurrentAmount(Items.RechargeableResourceEnum.RegularEnergy);

            // Don't take damage if we've already reached the threshold
            return(Math.Max(0, currentRegularEnergy - Value));
        }
示例#8
0
        public ExecutionResult Execute(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
        {
            bool enemyInitiallyFull = EnemyWithHealth.Health == EnemyWithHealth.Enemy.Hp;

            EnemyWithHealth.Enemy.WeaponSusceptibilities.TryGetValue(Weapon.Name, out WeaponSusceptibility susceptibility);
            if (susceptibility == null)
            {
                return(null);
            }
            int numberOfShots = susceptibility.NumberOfHits(EnemyWithHealth.Health);

            ExecutionResult result = Weapon.ShotRequires.Execute(model, inGameState, times: times * numberOfShots, usePreviousRoom: usePreviousRoom);

            if (result != null)
            {
                // Record the kill

                // If the enemy was full, then the prior splash attack (if any) didn't affect it. Ignore it.
                if (enemyInitiallyFull)
                {
                    result.AddKilledEnemy(EnemyWithHealth.Enemy, Weapon, numberOfShots);
                }
                // If the enemy was not full, the splash attack contributed to its death
                else
                {
                    result.AddKilledEnemy(EnemyWithHealth.Enemy, new [] { (PriorSplashWeapon, PriorSplashShots), (Weapon, numberOfShots) });
        /// <summary>
        /// <para>Calculates how much of the provided resource is gained or lost (on average) over 60 frames of farming,
        /// given the provided effective drop rates and resource costs per cycle</para>
        /// <para>If the resource is also spent while executing a cycle, the calculation includes
        /// reducing the drop rate by the safety margin in the logical options.</para>
        /// </summary>
        /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
        /// <param name="resource">The resource to check</param>
        /// <param name="effectiveDropRates">The effective drop rates, after accounting for unneeded drops.</param>
        /// <param name="costingResources">A dictionary  of resources to their cost per cycle.</param>
        /// <returns></returns>
        private decimal CalculateResourceVariationPerSecond(SuperMetroidModel model, ConsumableResourceEnum resource,
                                                            EnemyDrops effectiveDropRates, IDictionary <ConsumableResourceEnum, int> costingResources)
        {
            decimal variationPerCycle = CalculateResourceVariationPerCycle(model, resource, effectiveDropRates, costingResources);

            return(variationPerCycle / FarmCycle.CycleFrames * 60);
        }
        // STITCHME It might be valuable to eventually have InGameState be able to say which nodes are reachable?

        // STITCHME It could be nice to keep track of all canResets in the room and evaluate them as you move around?
        // Another option would be to have something in an initialization phase that converts canResets into just names,
        // and adds information on nodes and strats that they invalidate the canReset.
        // We'll see when we get to the step of reducing logical elements *shrug*

        /// <summary>
        /// Creates a new InGameState
        /// </summary>
        /// <param name="model">A SuperMetroidModel. Its rooms must have both been set and initialized.
        /// Its items and game flags must also have been set.</param>
        /// <param name="itemContainer">The result of reading the items.json file.</param>
        public InGameState(SuperMetroidModel model, ItemContainer itemContainer)
        {
            IEnumerable <ResourceCapacity> startingResources = itemContainer.StartingResources;

            Inventory = new ItemInventory(startingResources);

            Resources = new ResourceCount();

            // Start the player at full
            foreach (ResourceCapacity capacity in startingResources)
            {
                Resources.ApplyAmountIncrease(capacity.Resource, capacity.MaxAmount);
            }

            // Initialize starting game flags
            foreach (string gameFlagName in itemContainer.StartingGameFlagNames)
            {
                ApplyAddGameFlag(model.GameFlags[gameFlagName]);
            }

            // Initialize starting items
            foreach (string itemName in itemContainer.StartingItemNames)
            {
                ApplyAddItem(model.Items[itemName]);
            }

            RoomNode startingNode = model.Rooms[itemContainer.StartingRoomName].Nodes[itemContainer.StartingNodeId];

            InRoomState = new InRoomState(startingNode);
        }
        public ExecutionResult Execute(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
        {
            // There may be up to 2 requirements. This StratObstacle may have some, and the RoomObstacle may also have some general requirements that apply to any strat.

            // Start with the RoomObstacle's requirements
            ExecutionResult result = StratObstacle.Obstacle.Requires.Execute(model, inGameState, times: times, usePreviousRoom: usePreviousRoom);

            // If we couldn't execute the RoomObstacle's requirements, give up
            if (result == null)
            {
                return(null);
            }

            // Add this specific StratObstacle's requirements
            result = result.AndThen(StratObstacle.Requires, model, times: times, usePreviousRoom: usePreviousRoom);
            // If that failed, give up
            if (result == null)
            {
                return(null);
            }

            // We have succeeded, but we must update the ExecutionResult and its InGameState to reflect any destroyed obstacles
            result.ApplyDestroyedObstacles(new[] { StratObstacle.Obstacle }.Concat(StratObstacle.AdditionalObstacles), usePreviousRoom);

            return(result);
        }
 /// <summary>
 /// Consumes the provided quantity of the provided consumable resource. When consuming energy, regular energy is used up first (down to 1)
 /// then reserves are used.
 /// </summary>
 /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
 /// <param name="resource">The resource to consume</param>
 /// <param name="quantity">The amount to consume</param>
 public void ApplyConsumeResource(SuperMetroidModel model, ConsumableResourceEnum resource, int quantity)
 {
     // Don't bother with current resource count if resource tracking is disabled
     if (model.LogicalOptions.ResourceTrackingEnabled)
     {
         Resources.ApplyAmountReduction(resource, quantity);
     }
 }
示例#13
0
        public IEnumerable <string> InitializeReferencedLogicalElementProperties(SuperMetroidModel model, Room room)
        {
            List <string> unhandled = new List <string>();

            unhandled.AddRange(Requires.InitializeReferencedLogicalElementProperties(model, room));

            return(unhandled.Distinct());
        }
示例#14
0
        public override AbstractNavigationAction Reverse(SuperMetroidModel model)
        {
            InteractWithNodeAction reverseAction = new InteractWithNodeAction($"Undo action '{this.IntentDescription}'");

            TransferDataToReverseAbstractAction(reverseAction);

            return(reverseAction);
        }
 /// <summary>
 /// Sets current value for the provided resource to the current maximum
 /// </summary>
 /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
 /// <param name="resource">The resource to refill</param>
 public void ApplyRefillResource(SuperMetroidModel model, RechargeableResourceEnum resource)
 {
     // Don't bother with current resource count if resource tracking is disabled
     if (model.LogicalOptions.ResourceTrackingEnabled)
     {
         Resources.ApplyAmount(resource, Inventory.GetMaxAmount(resource));
     }
 }
        public override AbstractNavigationAction Reverse(SuperMetroidModel model)
        {
            MoveToNodeAction reverseAction = new MoveToNodeAction($"Undo action '{this.IntentDescription}'");

            TransferDataToReverseAbstractAction(reverseAction);
            reverseAction.StratUsed = StratUsed;

            return(reverseAction);
        }
        public IEnumerable <Action> Initialize(SuperMetroidModel model, Room room)
        {
            // Initialize LeadsToNode
            if (LeadsToNodeId != null)
            {
                LeadsToNode = room.Nodes[(int)LeadsToNodeId];
            }

            return(Enumerable.Empty <Action>());
        }
        public IEnumerable <Action> Initialize(SuperMetroidModel model, Room room)
        {
            // Initialize Obstacle
            Obstacle = room.Obstacles[ObstacleId];

            // Initialize AdditionalObstacles
            AdditionalObstacles = AdditionalObstacleIds.Select(id => room.Obstacles[id]);

            return(Enumerable.Empty <Action>());
        }
        /// <summary>
        /// Creates and returns an ExecutionResult based on the provided in-game state, with the provided resources refilled.
        /// </summary>
        /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
        /// <param name="inGameState">The in-game state to use for execution. This will NOT be altered by this method.</param>
        /// <param name="resourcesToRefill">The resources that should be refilled.</param>
        /// <returns></returns>
        private ExecutionResult ExecuteRefill(SuperMetroidModel model, InGameState inGameState, IEnumerable <ConsumableResourceEnum> resourcesToRefill)
        {
            InGameState resultingState = inGameState.Clone();

            foreach (ConsumableResourceEnum resource in resourcesToRefill)
            {
                resultingState.ApplyRefillResource(model, resource);
            }
            return(new ExecutionResult(resultingState));
        }
        public AbstractNavigationAction(string intent, SuperMetroidModel model, InGameState initialInGameState, ExecutionResult executionResult) : this(intent)
        {
            Succeeded = true;

            // Initialize position change
            if (initialInGameState.GetCurrentNode() != executionResult.ResultingState.GetCurrentNode())
            {
                PositionChange = (initialInGameState.GetCurrentNode(), executionResult.ResultingState.GetCurrentNode());
            }

            // Initialize gained and lost items
            ItemInventory gainedInventory = executionResult.ResultingState.GetInventoryExceptWith(initialInGameState);
            ItemsGained = gainedInventory;
            // Cannot lose items, just create an empty inventory
            ItemsLost = new ItemInventory(model.StartConditions.BaseResourceMaximums);

            // Initialize enabled and disabled items
            ItemsDisabledNames = executionResult.ResultingState.GetDisabledItemNames().Except(initialInGameState.GetDisabledItemNames());
            ItemsEnabledNames  = initialInGameState.GetDisabledItemNames().Except(executionResult.ResultingState.GetDisabledItemNames());

            // Initialize flags gained
            GameFlagsGained = GameFlagsGained.Concat(executionResult.ResultingState.GetActiveGameFlagsExceptWith(initialInGameState).Values);

            // Initialize locks opened
            LocksOpened = LocksOpened.Concat(executionResult.ResultingState.GetOpenedNodeLocksExceptWith(initialInGameState).Values);

            // Initialize item locations taken
            ItemLocationsTaken = ItemLocationsTaken.Concat(executionResult.ResultingState.GetTakenItemLocationsExceptWith(initialInGameState).Values);

            // Initialize resources before and after
            ResourcesBefore = initialInGameState.GetCurrentResources();
            ResourcesAfter  = executionResult.ResultingState.GetCurrentResources();

            // Initialize destroyed obstacles, but that's only relevant if we didn't change rooms
            if (executionResult.ResultingState.GetCurrentRoom() == initialInGameState.GetCurrentRoom())
            {
                ObstaclesDestroyed = ObstaclesDestroyed.Concat(
                    executionResult.ResultingState.GetDestroyedObstacleIds()
                    .Except(initialInGameState.GetDestroyedObstacleIds())
                    .Select(obstacleId => executionResult.ResultingState.GetCurrentRoom().Obstacles[obstacleId])
                    );
            }

            // Transfer information data from the ExecutionResult.
            // No need to copy since they are IEnumerable and not supposed to be mutated.
            RunwaysUsed             = executionResult.RunwaysUsed;
            CanLeaveChargedExecuted = executionResult.CanLeaveChargedExecuted;
            OpenedLocks             = executionResult.OpenedLocks;
            BypassedLocks           = executionResult.BypassedLocks;
            KilledEnemies           = executionResult.KilledEnemies;

            // Since the set of items is mutable, do not transfer the instance
            ItemsInvolved.UnionWith(executionResult.ItemsInvolved);
            DamageReducingItemsInvolved.UnionWith(executionResult.DamageReducingItemsInvolved);
        }
 /// <summary>
 /// Sets current value for the provided consumable resource to the current maximum.
 /// This is almost the same as refilling a rechargeable resource,
 /// except both types of energy are grouped together.
 /// </summary>
 /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
 /// <param name="resource">The resource to refill</param>
 public void ApplyRefillResource(SuperMetroidModel model, ConsumableResourceEnum resource)
 {
     // Don't bother with current resource count if resource tracking is disabled
     if (model.LogicalOptions.ResourceTrackingEnabled)
     {
         foreach (RechargeableResourceEnum rechargeableResource in resource.ToRechargeableResources())
         {
             ApplyRefillResource(model, rechargeableResource);
         }
     }
 }
        /// <summary>
        /// Goes through all logical elements within this LogicalRequirements (and all LogicalRequirements within any of them),
        /// attempting to initialize any property that is an object referenced by another property(which is its identifier).
        /// </summary>
        /// <param name="model">A SuperMetroidModel that contains global data</param>
        /// <param name="room">The room in which this LogicalRequirements is, or null if it's not in a room</param>
        /// <returns>A sequence of strings describing references that could not be initialized properly.</returns>
        public IEnumerable <string> InitializeReferencedLogicalElementProperties(SuperMetroidModel model, Room room)
        {
            List <string> unhandled = new List <string>();

            foreach (AbstractLogicalElement logicalElement in LogicalElements)
            {
                unhandled.AddRange(logicalElement.InitializeReferencedLogicalElementProperties(model, room));
            }

            return(unhandled);
        }
示例#23
0
        public IEnumerable <string> InitializeReferencedLogicalElementProperties(SuperMetroidModel model, Room room, RoomNode node)
        {
            List <string> unhandled = new List <string>();

            foreach (Strat strat in Strats)
            {
                unhandled.AddRange(strat.InitializeReferencedLogicalElementProperties(model, room));
            }

            return(unhandled.Distinct());
        }
示例#24
0
        // Ok so how do I want this to work? We'll have operations that will have results.
        // What are things you can do:
        // - Follow a link
        // - Interact with current node
        //   - Remember that interacting with a door means you change rooms
        // - Needs some kind of support for a remote exit.
        // - In the case of door locks, you could absolutely attempt to open the lock without interacting with it
        // - Farm enemies
        //   - Optionally you could provide a door to use to reset the room and keep farming (mandatory if the enemies don't respawn)
        //   - Optionally you could indicate specific enemies you want to farm
        //   - Optionally you could indicate a weapon to use (only worth doing if no effective free weapon available)
        // Anything else?
        // - There could be some more complex operations like "go to THIS node", but then that can lead to evaluating a lot of things to find the cheapest option.
        //   Still, I'm sure it could be worth.
        //
        // Failure to do an action would leave the state unchanged and return something to indicate failure.
        //
        // Some kind of system to customize/override the items at in-game locations could be good, to navigate an actual randomized seed and grab items.
        // Though this one might be out of scope for GameNavigator. It should probably happen upstream.



        /// <summary>
        /// Constructor that initializes a GameNavigator with the provided initial state.
        /// </summary>
        /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
        /// <param name="initialState">The starting inGameState for this navigator.</param>
        /// <param name="maxPreviousStatesSize">The maximum number of previous states that this navigator should keep in memory.</param>
        /// <param name="options">Optional game navigation options. If left null, default options will be used.</param>
        public GameNavigator(SuperMetroidModel model, InGameState initialState, int maxPreviousStatesSize, GameNavigatorOptions options = null)
        {
            GameModel             = model;
            CurrentInGameState    = initialState;
            MaxPreviousStatesSize = maxPreviousStatesSize;
            if (options == null)
            {
                options = new GameNavigatorOptions();
            }
            Options = options;
        }
示例#25
0
        public IEnumerable <Action> Initialize(SuperMetroidModel model, Room room)
        {
            List <Action> postRoomInitializeCallbacks = new List <Action>();

            foreach (LinkTo linkTo in To)
            {
                postRoomInitializeCallbacks.AddRange(linkTo.Initialize(model, room));
            }

            return(postRoomInitializeCallbacks);
        }
示例#26
0
 /// <summary>
 /// Creates and returns an instance of EnemyDrops reprenting this enemy's effective drop rates,
 /// given that the provided resources are full.
 /// </summary>
 /// <param name="model">A model that can be used to obtain data about the current game configuration.</param>
 /// <param name="fullResources">An enumeration of consumable resources that are considered full
 /// (and hence no longer cause their corresponding enemy drop to happen).</param>
 /// <returns></returns>
 public EnemyDrops GetEffectiveDropRates(SuperMetroidModel model, IEnumerable <ConsumableResourceEnum> fullResources)
 {
     if (fullResources.Any())
     {
         return(model.Rules.CalculateEffectiveDropRates(Drops, model.Rules.GetUnneededDrops(fullResources)));
     }
     else
     {
         return(Drops.Clone());
     }
 }
示例#27
0
        public IEnumerable <string> InitializeReferencedLogicalElementProperties(SuperMetroidModel model, Room room)
        {
            List <string> unhandled = new List <string>();

            foreach (LinkTo linkTo in To)
            {
                unhandled.AddRange(linkTo.InitializeReferencedLogicalElementProperties(model, room));
            }

            return(unhandled.Distinct());
        }
 public ExecutionResult Execute(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
 {
     // The bypass attempt fails if there's no way to bypass
     if (StratObstacle.Bypass == null)
     {
         return(null);
     }
     else
     {
         return(StratObstacle.Bypass.Execute(model, inGameState, times: times, usePreviousRoom: usePreviousRoom));
     }
 }
示例#29
0
        public void Initialize(SuperMetroidModel model, Room room, RoomNode node)
        {
            // Eliminate disabled strats
            Strats = Strats.WhereEnabled(model);

            foreach (Strat strat in Strats)
            {
                strat.Initialize(model, room);
            }

            Node = node;
        }
 public override ExecutionResult Execute(SuperMetroidModel model, InGameState inGameState, int times = 1, bool usePreviousRoom = false)
 {
     if (inGameState.HasGameFlag(GameFlag))
     {
         // Clone the In-game state to fulfill method contract
         return(new ExecutionResult(inGameState.Clone()));
     }
     else
     {
         return(null);
     }
 }