Пример #1
0
        /// <summary>
        /// Calculates and returns the expected real world seconds until the node despawns
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static NodeLifespan GetNodeLifespan(GatheringPointObject node)
        {
            var eorzeaMinutesTillDespawn = (int)byte.MaxValue;

            if (node.IsUnspoiled())
            {
                if (WorldManager.ZoneId > 350)
                {
                    eorzeaMinutesTillDespawn = 55 - WorldManager.EorzaTime.Minute;
                }
                else
                {
                    // We really don't know how much time is left on the node, but it does have at least the 5 more EM.
                    eorzeaMinutesTillDespawn = 60 - WorldManager.EorzaTime.Minute;
                }
            }

            if (node.IsEphemeral())
            {
                var hoursFromNow = WorldManager.EorzaTime.AddHours(4);
                var rounded      = new DateTime(
                    hoursFromNow.Year,
                    hoursFromNow.Month,
                    hoursFromNow.Day,
                    hoursFromNow.Hour - hoursFromNow.Hour % 4,
                    0,
                    0);

                eorzeaMinutesTillDespawn = (int)(rounded - WorldManager.EorzaTime).TotalMinutes;
            }

            return(new NodeLifespan(eorzeaMinutesTillDespawn * 35 / 12));
        }
Пример #2
0
 internal void ResetInternal()
 {
     interactedWithNode = false;
     GatherSpot         = null;
     Node            = null;
     GatherItem      = null;
     CollectableItem = null;
 }
        /// <summary>
        /// Executes the strategy logic in charge of regenerating GP after the gather.
        /// </summary>
        /// <returns></returns>
        public async Task <GpRegenStrategyResult> RegenerateGp(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType)
        {
            var rtn = new GpRegenStrategyResult()
            {
                StrategyState        = GpRegenStrategyResult.GpRegenStrategyResultState.OK,
                EffectiveCordialType = cordialType,
                OriginalCordialType  = cordialType,
            };

            var useCordial = cordialTime.HasFlag(CordialTime.AfterGather) &&
                             this.cordialStock.HasStock() &&
                             this.cordialStock.GetCordialCooldown() == TimeSpan.Zero;

            var currentGp = ExProfileBehavior.Me.CurrentGP;
            var maxGp     = ExProfileBehavior.Me.MaxGP;
            var missingGp = maxGp - currentGp;
            var cordial   = this.cordialStock.GetBestCordial(missingGp, cordialType);

            // Return OK if there is no cordial to use
            if (cordial == null)
            {
                rtn.UseState = InventoryItem.UseResult.OK;
                return(rtn);
            }

            // Use the cordial
            rtn.UseState = await cordial.Use(
                ExProfileBehavior.Me
                );

            // Log the result
            this.LogCordialResult(
                rtn.UseState ?? InventoryItem.UseResult.CantUse,
                cordial,
                currentGp
                );

            return(rtn);
        }
Пример #4
0
 /// <summary>
 /// Returns true if the node is unspoiled or legendary
 /// </summary>
 public static bool IsUnspoiled(this GatheringPointObject node)
 {
     // Temporary until we decide if legendary have any diff properties or if we should treat them the same.
     return(node.EnglishName.IndexOf("unspoiled", StringComparison.InvariantCultureIgnoreCase) >= 0 ||
            node.EnglishName.IndexOf("legendary", StringComparison.InvariantCultureIgnoreCase) >= 0);
 }
Пример #5
0
 /// <summary>
 /// Returns true if the node is concealed
 /// </summary>
 public static bool IsConcealed(this GatheringPointObject node)
 {
     return(node.EnglishName.IndexOf("concealed", StringComparison.InvariantCultureIgnoreCase) >= 0);
 }
Пример #6
0
 /// <summary>
 /// Returns true if the node is an ephemeral node
 /// </summary>
 public static bool IsEphemeral(this GatheringPointObject node)
 {
     return(node.EnglishName.IndexOf("ephemeral", StringComparison.InvariantCultureIgnoreCase) >= 0);
 }
Пример #7
0
 public override bool ShouldForceGather(GatheringPointObject node)
 {
     return(!node.IsEphemeral() && !node.IsUnspoiled());
 }
Пример #8
0
        /// <summary>
        /// Executes the strategy logic in charge of regenerating GP before the gather.
        /// </summary>
        /// <returns></returns>
        public async Task <GpRegenStrategyResult> RegenerateGp(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType)
        {
            var rtn = new GpRegenStrategyResult()
            {
                EffectiveCordialType = this.effectiveCordialType,
                OriginalCordialType  = this.requestedCordialType,
            };

            // Return OK immediately if there is no node
            if (node == null)
            {
                this.logger.GatheringNodeIsGone();

                rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NodeGone;
                return(rtn);
            }

            // Configure the strategy and report to the log
            this.Configure(node, gatherRotation, gatherStrategy, cordialTime, cordialType);
            this.logger.LogReport(this);

            // Return not enough time if player has less than 3 seconds to gather
            if (this.EffectiveTimeTillGather.TotalSeconds < 3)
            {
                this.logger.GatheringNotEnoughTime();

                rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughTime;
                return(rtn);
            }

            if (this.gatherStrategy == GatherStrategy.GatherOrCollect)
            {
                // Return not enough GP if we cannot meet the target breakpoint for the rotation
                if (this.BreakpointGp > this.TargetGp)
                {
                    this.logger.RegeneratingNotEnoughGp();

                    rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughGp;
                    return(rtn);
                }
            }

            // Use the cordial if one was selected
            if (this.Cordial != null)
            {
                rtn.UseState = await this.Cordial.Use(
                    ExProfileBehavior.Me,
                    maxTimeout : this.EffectiveTimeTillGather,
                    dismount : true
                    );

                this.LogCordialResult(rtn.UseState.Value);

                // Recalculate player's ability to gather after cordial use failure
                if (rtn.UseState != InventoryItem.UseResult.OK)
                {
                    this.effectiveCordialType = CordialType.None;
                    this.CalculateTargetAndCordialSelection();

                    this.logger.LogReport(this);

                    // Return not enough GP if we cannot meet the target breakpoint for the rotation
                    if (this.BreakpointGp > this.TargetGp)
                    {
                        this.logger.RegeneratingNotEnoughGp();

                        rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.NotEnoughGp;
                        return(rtn);
                    }
                }
            }

            // Handle TouchAndGo overrides
            if (this.gatherStrategy == GatherStrategy.TouchAndGo)
            {
                // Do nothing if this is not ephemeral
                if (!node.IsEphemeral())
                {
                    this.logger.GatheringNodeSkippedNotEphemeral();

                    rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK;
                    return(rtn);
                }

                if (this.EffectiveTimeToRegenerate.TotalSeconds > MAX_TOUCHANDGO_WAIT)
                {
                    this.logger.RegeneratingSkippedExceedsEphemeralMaxWait(
                        this.EffectiveTimeToRegenerate.TotalSeconds,
                        MAX_TOUCHANDGO_WAIT
                        );

                    rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK;
                    return(rtn);
                }
            }

            // Return OK immediately if the rotation forcefully gathers the item
            if (gatherRotation.ShouldForceGather(node))
            {
                rtn.StrategyState = GpRegenStrategyResult.GpRegenStrategyResultState.OK;
                return(rtn);
            }

            // Execute wait logic
            rtn.StrategyState = await this.WaitForGpRegeneration();

            return(rtn);
        }
Пример #9
0
        /// <summary>
        /// Configures the strategy for use
        /// </summary>
        protected void Configure(GatheringPointObject node, IGatheringRotation gatherRotation, GatherStrategy gatherStrategy, CordialTime cordialTime, CordialType cordialType)
        {
            if (gatherRotation == null)
            {
                throw new ArgumentNullException("gatherRotation");
            }

            // Set gathering parameters
            this.gatherRotation = gatherRotation;
            this.gatherStrategy = gatherStrategy;

            // Set cordial parameters
            this.cordialTime          = cordialTime;
            this.requestedCordialType = this.effectiveCordialType = cordialType;

            // Override cordial type
            if (this.requestedCordialType > CordialType.None)
            {
                // Turn off cordial when there is no stock
                if (!this.cordialStockManager.HasStock())
                {
                    this.effectiveCordialType = CordialType.None;

                    this.logger.RegeneratingCordialUseDisabledNoStock();
                }

                // Turn off cordial when node is not ephemeral in TnG strategies
                if (this.gatherStrategy == GatherStrategy.TouchAndGo && !node.IsEphemeral())
                {
                    this.effectiveCordialType = CordialType.None;
                }
            }
            else
            {
                this.effectiveCordialType = this.requestedCordialType;
            }

            // Set node lifespan parameters
            this.NodeLifespan = new EffectiveNodeLifespan(NodeHelper.GetNodeLifespan(node), this.gatherRotation.Attributes.RequiredTimeInSeconds);
            if (this.gatherStrategy == GatherStrategy.TouchAndGo)
            {
                this.NodeLifespan.Clamp(TimeSpan.Zero, TimeSpan.FromSeconds(MAX_TOUCHANDGO_WAIT));
            }
            this.EffectiveTimeTillGather = this.NodeLifespan.DeSpawn;

            // Set GP parameters
            this.StartingGp  = this.CurrentGp;
            this.MaxGp       = ExProfileBehavior.Me.MaxGP;
            this.EffectiveGp = CharacterResource.GetEffectiveGp(this.NodeLifespan.DeSpawnTicks);

            // Set breakpoint and cordial parameters
            this.CalculateTargetAndCordialSelection();

            // Calculate regeneration parameters
            this.RegeneratedGp = (ushort)(this.TargetGp - this.CordialGp - this.StartingGp);
            if (this.RegeneratedGp < 0)
            {
                this.RegeneratedGp = 0;
            }
            this.EffectiveTimeToRegenerate = CharacterResource.EstimateExpectedRegenerationTime(this.RegeneratedGp);
        }
Пример #10
0
        private async Task <bool> FindNode(bool retryCenterHotspot = true)
        {
            if (Node != null)
            {
                return(false);
            }

            StatusText = Localization.Localization.ExGather_SearchForNodes;

            while (Behaviors.ShouldContinue)
            {
                IEnumerable <GatheringPointObject> nodes =
                    GameObjectManager.GetObjectsOfType <GatheringPointObject>().Where(gpo => gpo.CanGather).ToArray();

                if (GatherStrategy == GatherStrategy.TouchAndGo && HotSpots != null)
                {
                    if (GatherObjects != null)
                    {
                        nodes = nodes.Where(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
                    }

                    foreach (var node in
                             nodes.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location))
                             .OrderBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location))
                             .Skip(1))
                    {
                        if (!Blacklist.Contains(node.ObjectId, BlacklistFlags.Interact))
                        {
                            Blacklist.Add(
                                node,
                                BlacklistFlags.Interact,
                                TimeSpan.FromSeconds(18),
                                Localization.Localization.ExGather_SkipFurthestNodes);
                        }
                    }
                }

                nodes = nodes.Where(gpo => !Blacklist.Contains(gpo.ObjectId, BlacklistFlags.Interact));

                if (FreeRange)
                {
                    nodes = nodes.Where(gpo => gpo.Distance2D(ExProfileBehavior.Me.Location) < Radius);
                }
                else
                {
                    if (HotSpots != null)
                    {
                        nodes = nodes.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location));
                    }
                }

                // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                if (GatherObjects != null)
                {
                    Node =
                        nodes.OrderBy(
                            gpo =>
                            GatherObjects.FindIndex(i => string.Equals(gpo.EnglishName, i, StringComparison.InvariantCultureIgnoreCase)))
                        .ThenBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location))
                        .FirstOrDefault(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
                }
                else
                {
                    Node = nodes.OrderBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location)).FirstOrDefault();
                }

                if (Node == null)
                {
                    if (HotSpots != null)
                    {
                        var myLocation = ExProfileBehavior.Me.Location;

                        var distanceToFurthestVisibleGameObject =
                            GameObjectManager.GameObjects.Select(o => o.Location.Distance2D(myLocation))
                            .OrderByDescending(o => o)
                            .FirstOrDefault();

                        var distanceToFurthestVectorInHotspot = myLocation.Distance2D(HotSpots.CurrentOrDefault)
                                                                + HotSpots.CurrentOrDefault.Radius;

                        if (myLocation.Distance2D(HotSpots.CurrentOrDefault) > Radius && GatherStrategy == GatherStrategy.GatherOrCollect &&
                            retryCenterHotspot && distanceToFurthestVisibleGameObject <= distanceToFurthestVectorInHotspot)
                        {
                            Logger.Verbose(Localization.Localization.ExGather_DistanceObject + distanceToFurthestVisibleGameObject);
                            Logger.Verbose(Localization.Localization.ExGather_DistanceHotSpot + distanceToFurthestVectorInHotspot);

                            Logger.Warn(
                                Localization.Localization.ExGather_NoAvailableNode);
                            await HotSpots.CurrentOrDefault.XYZ.MoveTo(radius : Radius, name : HotSpots.CurrentOrDefault.Name);

                            retryCenterHotspot = false;
                            await Coroutine.Yield();

                            continue;
                        }

                        if (!await ChangeHotSpot())
                        {
                            retryCenterHotspot = false;
                            await Coroutine.Yield();

                            continue;
                        }
                    }

                    if (FreeRange && !FreeRangeConditional())
                    {
                        await Coroutine.Yield();

                        isDone = true;
                        return(true);
                    }

                    return(true);
                }

                var entry = Blacklist.GetEntry(Node.ObjectId);
                if (entry != null && entry.Flags.HasFlag(BlacklistFlags.Interact))
                {
                    Logger.Warn(Localization.Localization.ExGather_NodeBlacklist);

                    if (await
                        Coroutine.Wait(entry.Length,
                                       () => entry.IsFinished || Node.Location.Distance2D(ExProfileBehavior.Me.Location) > Radius) ||
                        Core.Player.IsDead)
                    {
                        if (!entry.IsFinished)
                        {
                            Node = null;
                            Logger.Info(Localization.Localization.ExGather_NodeReset);
                            return(false);
                        }
                    }

                    Logger.Info(Localization.Localization.ExGather_NodeBlacklistRemoved);
                }

                Logger.Info(Localization.Localization.ExGather_NodeSet + Node);

                if (HotSpots == null)
                {
                    MovementManager.SetFacing2D(Node.Location);
                }

                if (Poi.Current.Unit != Node)
                {
                    Poi.Current = new Poi(Node, PoiType.Gather);
                }

                return(true);
            }

            return(true);
        }
Пример #11
0
 public virtual bool ShouldForceGather(GatheringPointObject node)
 {
     return(false);
 }
Пример #12
0
		private async Task<bool> FindNode(bool retryCenterHotspot = true)
		{
			if (Node != null)
			{
				return false;
			}

			StatusText = "Searching for nodes";

			while (Behaviors.ShouldContinue)
			{
				IEnumerable<GatheringPointObject> nodes =
					GameObjectManager.GetObjectsOfType<GatheringPointObject>().Where(gpo => gpo.CanGather).ToArray();

				if (GatherStrategy == GatherStrategy.TouchAndGo && HotSpots != null)
				{
					if (GatherObjects != null)
					{
						nodes = nodes.Where(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
					}

					foreach (
						var node in
							nodes.OrderBy(gpo => gpo.Location.Distance2D(Me.Location))
								.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location))
								.Skip(1))
					{
						if (!Blacklist.Contains(node.ObjectId, BlacklistFlags.Interact))
						{
							Blacklist.Add(
								node,
								BlacklistFlags.Interact,
								TimeSpan.FromSeconds(18),
								"Skip furthest nodes in hotspot. We only want 1.");
						}
					}
				}

				nodes = nodes.Where(gpo => !Blacklist.Contains(gpo.ObjectId, BlacklistFlags.Interact));

				if (FreeRange)
				{
					nodes = nodes.Where(gpo => gpo.Distance2D(Me.Location) < Radius);
				}
				else
				{
					if (HotSpots != null)
					{
						nodes =
							nodes.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location));
					}
				}

				// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
				if (GatherObjects != null)
				{
					Node =
						nodes.OrderBy(
							gpo =>
							GatherObjects.FindIndex(i => string.Equals(gpo.EnglishName, i, StringComparison.InvariantCultureIgnoreCase)))
							.ThenBy(gpo => gpo.Location.Distance2D(Me.Location))
							.FirstOrDefault(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
				}
				else
				{
					Node = nodes.OrderBy(gpo => gpo.Location.Distance2D(Me.Location)).FirstOrDefault();
				}

				if (Node == null)
				{
					if (HotSpots != null)
					{
						var myLocation = Me.Location;

						var distanceToFurthestVisibleGameObject =
							GameObjectManager.GameObjects.Select(o => o.Location.Distance2D(myLocation))
								.OrderByDescending(o => o)
								.FirstOrDefault();

						var distanceToFurthestVectorInHotspot = myLocation.Distance2D(HotSpots.CurrentOrDefault)
																+ HotSpots.CurrentOrDefault.Radius;

						if (GatherStrategy == GatherStrategy.GatherOrCollect && retryCenterHotspot
							&& distanceToFurthestVisibleGameObject <= distanceToFurthestVectorInHotspot)
						{
							Logger.Verbose("Distance to furthest visible game object -> " + distanceToFurthestVisibleGameObject);
							Logger.Verbose("Distance to furthest vector in hotspot -> " + distanceToFurthestVectorInHotspot);

							Logger.Warn(
								"Could not find any nodes and can not confirm hotspot is empty via object detection, trying again from center of hotspot.");
							await Behaviors.MoveTo(HotSpots.CurrentOrDefault, radius: Radius, name: HotSpots.CurrentOrDefault.Name);

							retryCenterHotspot = false;
							await Coroutine.Yield();
							continue;
						}

						if (!ChangeHotSpot())
						{
							retryCenterHotspot = false;
							await Coroutine.Yield();
							continue;
						}
					}

					if (FreeRange && !FreeRangeConditional())
					{
						await Coroutine.Yield();
						isDone = true;
						return true;
					}

					return true;
				}

				var entry = Blacklist.GetEntry(Node.ObjectId);
				if (entry != null && entry.Flags.HasFlag(BlacklistFlags.Interact))
				{
					Logger.Warn("Node on blacklist, waiting until we move out of range or it clears.");

					if (await Coroutine.Wait(entry.Length, () => entry.IsFinished || Node.Location.Distance2D(Me.Location) > Radius))
					{
						if (!entry.IsFinished)
						{
							Node = null;
							Logger.Info("Node Reset, Reason: Ran out of range");
							return false;
						}
					}

					Logger.Info("Node removed from blacklist.");
				}

				Logger.Info("Node set -> " + Node);

				if (HotSpots == null)
				{
					MovementManager.SetFacing2D(Node.Location);
				}

				if (Poi.Current.Unit != Node)
				{
					Poi.Current = new Poi(Node, PoiType.Gather);
				}

				return true;
			}

			return true;
		}
Пример #13
0
		internal void ResetInternal()
		{
			interactedWithNode = false;
			GatherSpot = null;
			Node = null;
			GatherItem = null;
			CollectableItem = null;
		}
Пример #14
0
		private async Task<bool> FindNode(bool retryCenterHotspot = true)
		{
			if (Node != null)
			{
				return false;
			}

			StatusText = Localization.Localization.ExGather_SearchForNodes;

			while (Behaviors.ShouldContinue)
			{
				IEnumerable<GatheringPointObject> nodes =
					GameObjectManager.GetObjectsOfType<GatheringPointObject>().Where(gpo => gpo.CanGather).ToArray();

				if (GatherStrategy == GatherStrategy.TouchAndGo && HotSpots != null)
				{
					if (GatherObjects != null)
					{
						nodes = nodes.Where(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
					}

					foreach (var node in
						nodes.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location))
							.OrderBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location))
							.Skip(1))
					{
						if (!Blacklist.Contains(node.ObjectId, BlacklistFlags.Interact))
						{
							Blacklist.Add(
								node,
								BlacklistFlags.Interact,
								TimeSpan.FromSeconds(18),
								Localization.Localization.ExGather_SkipFurthestNodes);
						}
					}
				}

				nodes = nodes.Where(gpo => !Blacklist.Contains(gpo.ObjectId, BlacklistFlags.Interact));

				if (FreeRange)
				{
					nodes = nodes.Where(gpo => gpo.Distance2D(ExProfileBehavior.Me.Location) < Radius);
				}
				else
				{
					if (HotSpots != null)
					{
						nodes = nodes.Where(gpo => HotSpots.CurrentOrDefault.WithinHotSpot2D(gpo.Location));
					}
				}

				// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
				if (GatherObjects != null)
				{
					Node =
						nodes.OrderBy(
							gpo =>
								GatherObjects.FindIndex(i => string.Equals(gpo.EnglishName, i, StringComparison.InvariantCultureIgnoreCase)))
							.ThenBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location))
							.FirstOrDefault(gpo => GatherObjects.Contains(gpo.EnglishName, StringComparer.InvariantCultureIgnoreCase));
				}
				else
				{
					Node = nodes.OrderBy(gpo => gpo.Location.Distance2D(ExProfileBehavior.Me.Location)).FirstOrDefault();
				}

				if (Node == null)
				{
					if (HotSpots != null)
					{
						var myLocation = ExProfileBehavior.Me.Location;

						var distanceToFurthestVisibleGameObject =
							GameObjectManager.GameObjects.Select(o => o.Location.Distance2D(myLocation))
								.OrderByDescending(o => o)
								.FirstOrDefault();

						var distanceToFurthestVectorInHotspot = myLocation.Distance2D(HotSpots.CurrentOrDefault)
						                                        + HotSpots.CurrentOrDefault.Radius;

						if (myLocation.Distance2D(HotSpots.CurrentOrDefault) > Radius && GatherStrategy == GatherStrategy.GatherOrCollect
						    && retryCenterHotspot && distanceToFurthestVisibleGameObject <= distanceToFurthestVectorInHotspot)
						{
							Logger.Verbose(Localization.Localization.ExGather_DistanceObject + distanceToFurthestVisibleGameObject);
							Logger.Verbose(Localization.Localization.ExGather_DistanceHotSpot + distanceToFurthestVectorInHotspot);

							Logger.Warn(
                                Localization.Localization.ExGather_NoAvailableNode);
							await HotSpots.CurrentOrDefault.XYZ.MoveTo(radius: Radius, name: HotSpots.CurrentOrDefault.Name);

							retryCenterHotspot = false;
							await Coroutine.Yield();
							continue;
						}

						if (!await ChangeHotSpot())
						{
							retryCenterHotspot = false;
							await Coroutine.Yield();
							continue;
						}
					}

					if (FreeRange && !FreeRangeConditional())
					{
						await Coroutine.Yield();
						isDone = true;
						return true;
					}

					return true;
				}

				var entry = Blacklist.GetEntry(Node.ObjectId);
				if (entry != null && entry.Flags.HasFlag(BlacklistFlags.Interact))
				{
					Logger.Warn(Localization.Localization.ExGather_NodeBlacklist);

					if (await
						Coroutine.Wait(entry.Length,
							() => entry.IsFinished || Node.Location.Distance2D(ExProfileBehavior.Me.Location) > Radius)
					    || Core.Player.IsDead)
					{
						if (!entry.IsFinished)
						{
							Node = null;
							Logger.Info(Localization.Localization.ExGather_NodeReset);
							return false;
						}
					}

					Logger.Info(Localization.Localization.ExGather_NodeBlacklistRemoved);
				}

				Logger.Info(Localization.Localization.ExGather_NodeSet + Node);

				if (HotSpots == null)
				{
					MovementManager.SetFacing2D(Node.Location);
				}

				if (Poi.Current.Unit != Node)
				{
					Poi.Current = new Poi(Node, PoiType.Gather);
				}

				return true;
			}

			return true;
		}
 internal static int Base(this GatheringPointObject node)
 {
     return((int)Core.Memory.Read <uint>(node.Pointer + 0x80));
 }