public static async Task <bool> KillRalakesh()
        {
            if (_ralakeshKilled)
            {
                return(false);
            }

            if (World.Act7.AshenFields.IsCurrentArea)
            {
                var roomObj = RalakeshRoomObj;
                if (roomObj != null)
                {
                    if (await Helpers.StopBeforeBoss(Settings.BossNames.Ralakesh))
                    {
                        return(true);
                    }

                    if (roomObj.PathExists())
                    {
                        var mob = Helpers.ClosestActiveMob;
                        if (mob != null && mob.PathExists())
                        {
                            PlayerMoverManager.MoveTowards(mob.Position);
                            return(true);
                        }
                        await Helpers.MoveAndWait(roomObj, "Waiting for any Ralakesh fight object");

                        return(true);
                    }
                }
            }
            await Travel.To(World.Act7.NorthernForest);

            return(true);
        }
예제 #2
0
        public static bool Towards(Vector2i pos, string destination)
        {
            if (LogInterval.Elapsed)
            {
                GlobalLog.Debug($"[MoveTowards] Moving towards {destination} at {pos} (distance: {LokiPoe.MyPosition.Distance(pos)})");
            }

            if (!PlayerMoverManager.MoveTowards(pos))
            {
                GlobalLog.Error($"[MoveTowards] Fail to move towards {destination} at {pos}");
                return(false);
            }
            return(true);
        }
예제 #3
0
        public static async Task MoveAndWait(NetworkObject obj, string log = null, int distance = 20)
        {
            var pos = obj.Position;

            if (LokiPoe.MyPosition.Distance(pos) > distance)
            {
                PlayerMoverManager.MoveTowards(pos);
            }
            else
            {
                GlobalLog.Debug(log ?? $"Waiting for {obj.Name}");
                await Wait.StuckDetectionSleep(200);
            }
        }
예제 #4
0
        public void Stop()
        {
            _taskManager.Stop();
            PluginManager.Stop();
            RoutineManager.Stop();
            PlayerMoverManager.Stop();

            // When the bot is stopped, we want to remove the process hook manager.
            LokiPoe.ProcessHookManager.Disable();

            // Cleanup the coroutine.
            if (_coroutine != null)
            {
                _coroutine.Dispose();
                _coroutine = null;
            }
        }
예제 #5
0
        public void Start()
        {
            ItemEvaluator.Instance   = DefaultItemEvaluator.Instance;
            Explorer.CurrentDelegate = user => CombatAreaCache.Current.Explorer.BasicExplorer;

            ComplexExplorer.ResetSettingsProviders();
            ComplexExplorer.AddSettingsProvider("MapBot", MapBotExploration, ProviderPriority.Low);

            // Cache all bound keys.
            LokiPoe.Input.Binding.Update();

            // Reset the default MsBetweenTicks on start.
            Log.Debug($"[Start] MsBetweenTicks: {BotManager.MsBetweenTicks}.");
            Log.Debug($"[Start] NetworkingMode: {LokiPoe.ConfigManager.NetworkingMode}.");
            Log.Debug($"[Start] KeyPickup: {LokiPoe.ConfigManager.KeyPickup}.");
            Log.Debug($"[Start] IsAutoEquipEnabled: {LokiPoe.ConfigManager.IsAutoEquipEnabled}.");

            // Since this bot will be performing client actions, we need to enable the process hook manager.
            LokiPoe.ProcessHookManager.Enable();

            _coroutine = null;

            ExilePather.Reload();

            _taskManager.Reset();

            AddTasks();

            Events.Start();
            PluginManager.Start();
            RoutineManager.Start();
            PlayerMoverManager.Start();
            _taskManager.Start();

            foreach (var plugin in PluginManager.EnabledPlugins)
            {
                Log.Debug($"[Start] The plugin {plugin.Name} is enabled.");
            }

            if (ExilePather.BlockTrialOfAscendancy == FeatureEnum.Unset)
            {
                //no need for this, map trials are in separate areas
                ExilePather.BlockTrialOfAscendancy = FeatureEnum.Disabled;
            }
        }
예제 #6
0
 public static async Task MoveToBossOrAnyMob(Monster boss)
 {
     if (!boss.IsActive)
     {
         var mob = LokiPoe.ObjectManager.Objects.Closest <Monster>(m => m.IsActive && !Blacklist.Contains(m.Id));
         if (mob != null)
         {
             GlobalLog.Debug($"\"{boss.Name}\" is not targetable. Now going to the closest active monster.");
             if (!PlayerMoverManager.MoveTowards(mob.Position))
             {
                 GlobalLog.Error($"Fail to move towards \"{mob.Name}\" at {mob.Position}. Now blacklisting it.");
                 Blacklist.Add(mob.Id, TimeSpan.FromSeconds(10), "fail to move to");
             }
             return;
         }
     }
     await MoveAndWait(boss.WalkablePosition());
 }
예제 #7
0
        public void Tick()
        {
            if (_coroutine == null)
            {
                _coroutine = new Coroutine(() => MainCoroutine());
            }

            ExilePather.Reload();

            Events.Tick();
            CombatAreaCache.Tick();
            _taskManager.Tick();
            PluginManager.Tick();
            RoutineManager.Tick();
            PlayerMoverManager.Tick();
            StuckDetection.Tick();

            Statistics.Instance.Tick();

            // Check to see if the coroutine is finished. If it is, stop the bot.
            if (_coroutine.IsFinished)
            {
                Log.Debug($"The bot coroutine has finished in a state of {_coroutine.Status}");
                BotManager.Stop();
                return;
            }

            try
            {
                _coroutine.Resume();
            }
            catch
            {
                var c = _coroutine;
                _coroutine = null;
                c.Dispose();
                throw;
            }
        }
예제 #8
0
        public static async Task <bool> KillGarukhan()
        {
            if (Helpers.PlayerHasQuestItem(QuestItemMetadata.SekhemaFeather))
            {
                return(false);
            }

            if (World.Act9.Quarry.IsCurrentArea)
            {
                var garukhan = Garukhan;
                if (garukhan != null)
                {
                    if (await Helpers.StopBeforeBoss(Settings.BossNames.Garukhan))
                    {
                        return(true);
                    }

                    if (!garukhan.IsActive)
                    {
                        var mob = Helpers.ClosestActiveMob;
                        if (mob != null && mob.PathExists())
                        {
                            PlayerMoverManager.MoveTowards(mob.Position);
                            return(true);
                        }
                    }
                    await Helpers.MoveAndWait(garukhan.WalkablePosition());

                    return(true);
                }
                await Helpers.MoveAndTakeLocalTransition(GarukhanRoomTgt);

                return(true);
            }
            await Travel.To(World.Act9.Quarry);

            return(true);
        }
예제 #9
0
        private bool BasicExploration()
        {
            var explorer = BasicExplorer;

            if (!explorer.HasLocation)
            {
                return(false);
            }

            var location = explorer.Location;

            if (LogInterval.Elapsed)
            {
                var distance = LokiPoe.MyPosition.Distance(location);
                var percent  = Math.Round(explorer.PercentComplete, 1);
                GlobalLog.Debug($"[ComplexExplorer] Exploring to the location {location} ({distance}) [{percent} %].");
            }
            if (!PlayerMoverManager.MoveTowards(location))
            {
                GlobalLog.Error($"[ComplexExplorer] MoveTowards failed for {location}. Adding this location to ignore list.");
                explorer.Ignore(location);
            }
            return(true);
        }
예제 #10
0
        public static async Task <bool> Execute(int range = -1)
        {
            var cachedMonsters = CombatAreaCache.Current.Monsters;

            if (CurrentTarget == null)
            {
                CurrentTarget = range == -1
                    ? cachedMonsters.ClosestValid()
                    : cachedMonsters.ClosestValid(m => m.Position.Distance <= range);

                if (CurrentTarget == null)
                {
                    return(false);
                }
            }

            if (Blacklist.Contains(CurrentTarget.Id))
            {
                GlobalLog.Debug("[TrackMobLogic] Current target is in global blacklist. Now abandoning it.");
                CurrentTarget.Ignored = true;
                CurrentTarget         = null;
                return(true);
            }

            var pos = CurrentTarget.Position;

            if (pos.IsFar || pos.IsFarByPath)
            {
                if (LogInterval.Elapsed)
                {
                    GlobalLog.Debug($"[TrackMobTask] Cached monster locations: {cachedMonsters.Valid().Count()}");
                    GlobalLog.Debug($"[TrackMobTask] Moving to {pos}");
                }
                if (!PlayerMoverManager.MoveTowards(pos))
                {
                    GlobalLog.Error($"[TrackMobTask] Fail to move to {pos}. Marking this monster as unwalkable.");
                    CurrentTarget.Unwalkable = true;
                    CurrentTarget            = null;
                }
                return(true);
            }

            var monsterObj = CurrentTarget.Object as Monster;

            // Untested fix to not wait on a captured beast. Will be changed once confirmed issue is solved.
            //if (monsterObj == null || monsterObj.IsDead || (Loki.Game.LokiPoe.InstanceInfo.Bestiary.IsActive && (monsterObj.HasBestiaryCapturedAura || monsterObj.HasBestiaryDisappearingAura)))

            if (monsterObj == null || monsterObj.IsDead)
            {
                cachedMonsters.Remove(CurrentTarget);
                CurrentTarget = null;
            }
            else
            {
                var attempts = ++CurrentTarget.InteractionAttempts;
                if (attempts > MaxKillAttempts)
                {
                    GlobalLog.Error("[TrackMobTask] All attempts to kill current monster have been spent. Now ignoring it.");
                    CurrentTarget.Ignored = true;
                    CurrentTarget         = null;
                    return(true);
                }
                GlobalLog.Debug($"[TrackMobTask] Alive monster is nearby, this is our {attempts}/{MaxKillAttempts} attempt to kill it.");
                await Coroutine.Sleep(200);
            }
            return(true);
        }
예제 #11
0
        /// <summary>
        /// Coroutine logic to execute.
        /// </summary>
        /// <returns>true if logic was executed to handle this type and false otherwise.</returns>
        public async Task <bool> Run()
        {
            // NOTE: This task's Run function is triggered from "hook_post_combat" Logic, as it's added via a secondary TaskManager!

            // If this task needs to be disabled due to errors, support doing so.
            if (_skip)
            {
                return(false);
            }

            // Don't do anything in these cases.
            if (LokiPoe.Me.IsDead || LokiPoe.Me.IsInHideout || LokiPoe.Me.IsInTown || LokiPoe.Me.IsInMapRoom)
            {
                return(false);
            }

            // If we're currently disabled, skip logic.
            if (!BreachesSettings.Instance.Enabled)
            {
                return(false);
            }

            var myPos = LokiPoe.MyPosition;

            var active = BreachDataManager.Active;

            if (active == null)
            {
                return(false);
            }

            // Make sure the breach is still valid and not blacklisted if it's set.
            // We don't re-eval current against settings, because of the performance overhead.
            if (_current != null)
            {
                if (!_current.IsValid || Blacklist.Contains(_current.Id))
                {
                    _current = null;
                }
            }

            // Find the next best breach.
            if (_current == null)
            {
                _current =
                    active.Breaches.Where(m => m.IsValid && !Blacklist.Contains(m.Id) && ShouldActivate(m))
                    .OrderBy(m => m.Position.Distance(myPos))
                    .FirstOrDefault();
                _moveErrors = 0;
            }

            // Nothing to do if there's no breach.
            if (_current == null)
            {
                return(false);
            }

            // If we can't move to the breach, blacklist it.
            if (_moveErrors > 5)
            {
                Blacklist.Add(_current.Id, TimeSpan.FromHours(1),
                              string.Format("[HandleBreachesTask::Logic] Unable to move to the Breach."));
                _current = null;
                return(true);
            }

            // If we are too far away to interact, move towards the object.
            if (myPos.Distance(_current.WalkablePosition) > 50)
            {
                // Make sure nothing is in the way.
                await Coroutines.CloseBlockingWindows();

                // Try to move towards the location.
                if (!PlayerMoverManager.MoveTowards(_current.WalkablePosition))
                {
                    Log.ErrorFormat("[HandleBreachesTask::Logic] PlayerMoverManager.MoveTowards({0}) failed for Breach [{1}].",
                                    _current.WalkablePosition, _current.Id);
                    _moveErrors++;
                    return(true);
                }

                _moveErrors = 0;

                return(true);
            }

            // Make sure we're not doing anything before we interact.
            await Coroutines.FinishCurrentAction();

            // If the user wants to manually open, or just find them without opening, this task just blocks everything else after it,
            // rather than stopping the bot, to avoid deaths.
            if (!BreachesSettings.Instance.Open)
            {
                return(true);
            }

            // Now process the object, but make sure it exists.
            var breach = _current.NetworkObject;

            if (breach == null)
            {
                _current.Activate = false;
                Log.ErrorFormat("[HandleBreachesTask::Logic] The NetworkObject does not exist for the Breach [{0}] yet.", _current.Id);
                _current = null;
                return(true);
            }

            // Try to move towards the location.
            if (!PlayerMoverManager.MoveTowards(_current.WalkablePosition))
            {
                Log.ErrorFormat("[HandleBreachesTask::Logic] PlayerMoverManager.MoveTowards({0}) failed for Breach [{1}].",
                                _current.WalkablePosition, _current.Id);
                _moveErrors++;
                return(true);
            }

            return(true);
        }
예제 #12
0
        /// <summary>
        /// Runs a task.
        /// </summary>
        /// <returns>true if the task ran and false otherwise.</returns>
        public async Task <bool> Run()
        {
            StuckDetection.Reset();             // We don't want StuckDetection logic running really.

            var leader = Leader;
            var me     = LokiPoe.Me;

            // If we don't have the leader in view, let's try to guess what they did.
            if (leader == null)
            {
                // If we've at least seen the leader once, first try moving to where they were last seen.
                if (_leaderData.LastKnownPosition != Vector2i.Zero)
                {
                    // Move closer to their last known position if we're out of range.
                    if (me.Position.Distance(_leaderData.LastKnownPosition) > 20)
                    {
                        // First, make sure we can actually get to the player's last known position before trying to move there.
                        if (ExilePather.PathExistsBetween(me.Position, _leaderData.LastKnownPosition, true))
                        {
                            // Just move to the location.
                            if (!PlayerMoverManager.MoveTowards(_leaderData.LastKnownPosition))
                            {
                                Log.Error($"[FollowerTask] PlayerMoverManager.MoveTowards failed for {_leaderData.LastKnownPosition}.");
                            }
                        }
                    }

                    // Clear the data so we don't run again.
                    _leaderData.LastKnownPosition = Vector2i.Zero;
                }

                // We have to decide which we want to use based on distance.
                if (_leaderData.LabyrinthReturnPortal != null && _leaderData.LastAreaTransition != null)
                {
                    if (_leaderData.LabyrinthReturnPortal.Distance < _leaderData.LastAreaTransition.Distance)
                    {
                        // Check to see if we saw the player near an area transition or the exit portal
                        if (await HandleLabyrinthReturnPortal())
                        {
                            return(true);
                        }
                    }
                    else
                    {
                        // Check to see if we saw the player near an area transition or the exit portal
                        if (await HandleLastAreaTransition())
                        {
                            return(true);
                        }
                    }
                }
                else                 // Order doesn't matter
                {
                    // Check to see if we saw the player near an area transition or the exit portal
                    if (await HandleLastAreaTransition())
                    {
                        return(true);
                    }

                    // Check to see if we saw the player near an area transition or the exit portal
                    if (await HandleLabyrinthReturnPortal())
                    {
                        return(true);
                    }
                }

                Log.Warn("[TODO 1]");

                return(true);
            }

            // Check to see if were within range. If so, return, as we have nothing else to do here.
            if (leader.Distance <= FollowerSettings.Instance.FollowDistance)
            {
                return(true);
            }

            // Otherwise, first check to see if a path exists between us and the leader, this is mostly to handle transitions
            if (ExilePather.PathExistsBetween(me.Position, leader.Position, true))
            {
                var leaderDistance = leader.Distance;

                // If there's an area transition closer to us than the leader, it's a special boss one,
                // but we don't need to stop the bot really, we can just sit and wait until it opens. Unless
                // we want the character to take it, in which case we can add that logic s well.
                if (LokiPoe.ObjectManager.Objects.OfType <AreaTransition>().Any(at => StringHelper.IsArenaTransition(at) && at.Distance < leaderDistance && at.IsTargetable))
                {
                    return(true);
                }

                // Just move to towards the player.
                if (!PlayerMoverManager.MoveTowards(leader.Position))
                {
                    // We can't do much other than log the error and let the user fix the issue.
                    Log.Error($"[FollowerTask] PlayerMoverManager.MoveTowards failed for {leader.Position}.");
                }

                // Nothing else to do.
                return(true);
            }

            // Check to see if we saw the player near an area transition.
            if (await HandleLastAreaTransition())
            {
                return(true);
            }

            Log.Warn("[TODO 2]");

            // This task takes control over QB/MB, so it should always return true;
            return(true);
        }
예제 #13
0
        public async Task <bool> Run()
        {
            if (!World.CurrentArea.IsCombatArea)
            {
                return(false);
            }

            var items      = CombatAreaCache.Current.Items;
            var validItems = items.FindAll(i => !i.Ignored && !i.Unwalkable);

            if (validItems.Count == 0)
            {
                return(false);
            }

            if (_item == null)
            {
                if (_isInPreTownrunMode)
                {
                    var squares = Inventories.AvailableInventorySquares;

                    _item = validItems
                            .Where(i => i.Position.Distance <= 40 && CanFit(i.Size, squares))
                            .OrderBy(i => i.Rarity != Rarity.Unique)
                            .ThenByDescending(i => i.Size.X * i.Size.Y)
                            .ThenBy(i => i.Position.DistanceSqr)
                            .FirstOrDefault();

                    if (_item == null)
                    {
                        if (!await PlayerAction.TpToTown())
                        {
                            ErrorManager.ReportError();
                            return(true);
                        }
                        ReturnAfterTownrunTask.Enabled = true;
                        return(true);
                    }
                }
                else
                {
                    _item = validItems.OrderBy(i => i.Rarity != Rarity.Unique).ThenBy(i => i.Position.DistanceSqr).First();
                }
            }

            var pos = _item.Position;

            if (pos.IsFar || pos.IsFarByPath)
            {
                if (LogInterval.Elapsed)
                {
                    GlobalLog.Debug($"[LootItemTask] Items to pick up: {validItems.Count}");
                    GlobalLog.Debug($"[LootItemTask] Moving to {pos}");
                }
                if (!PlayerMoverManager.MoveTowards(pos))
                {
                    GlobalLog.Error($"[LootItemTask] Fail to move to {pos}. Marking this item as unwalkable.");
                    _item.Unwalkable = true;
                    _item            = null;
                }
                return(true);
            }
            var itemObj = _item.Object;

            if (itemObj == null)
            {
                items.Remove(_item);
                _item = null;
                return(true);
            }
            if (!CanFit(_item.Size, Inventories.AvailableInventorySquares))
            {
                _isInPreTownrunMode = true;
                _item = null;
                return(true);
            }
            var attempts = ++_item.InteractionAttempts;

            if (attempts > MaxItemPickupAttempts)
            {
                if (_item.Position.Name == CurrencyNames.Mirror)
                {
                    GlobalLog.Error("[LootItemTask] Fail to pick up the Mirror of Kalandra. Now stopping the bot.");
                    BotManager.Stop();
                }
                else
                {
                    GlobalLog.Error("[LootItemTask] All attempts to pick up an item have been spent. Now ignoring it.");
                    _item.Ignored = true;
                    _item         = null;
                }
                return(true);
            }

            if (attempts % 3 == 0)
            {
                await PlayerAction.DisableAlwaysHighlight();
            }

            if (attempts == MaxItemPickupAttempts / 2)
            {
                if (PortalNearby)
                {
                    GlobalLog.Debug("[LootItemTask] There is a portal nearby, which probably blocks current item label.");
                    GlobalLog.Debug("[LootItemTask] Now going to create a new portal at some distance.");

                    if (await MoveAway(40, 70))
                    {
                        await PlayerAction.CreateTownPortal();
                    }
                }
                else
                {
                    GlobalLog.Debug("[LootItemTask] Now trying to move away from item, sometimes it helps.");
                    await MoveAway(30, 50);
                }
                return(true);
            }

            await PlayerAction.EnableAlwaysHighlight();

            GlobalLog.Debug($"[LootItemTask] Now picking up {pos}");

            var cached = new CachedItem(itemObj.Item);

            if (await PlayerAction.Interact(itemObj))
            {
                await Wait.LatencySleep();

                if (await Wait.For(() => _item.Object == null, "item pick up", 100, 400))
                {
                    items.Remove(_item);
                    _item = null;
                    GlobalLog.Info($"[Events] Item looted ({cached.Name})");
                    Utility.BroadcastMessage(this, Events.Messages.ItemLootedEvent, cached);
                }
                return(true);
            }
            await Wait.StuckDetectionSleep(300);

            return(true);
        }