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