/// <summary> /// This coroutine interacts with the waypoint and waits for the world panel to open. When called from a hideout, /// the waypoint must be in spawn range, otherwise the coroutine will fail. The movement is done without returning, /// so this should be carefully used when not in town. /// </summary> /// <returns>An OpenStashError that describes the result.</returns> public static async Task <Results.OpenWaypointError> OpenWaypoint() { await Coroutines.CloseBlockingWindows(); await Coroutines.FinishCurrentAction(); var waypoint = LokiPoe.ObjectManager.Waypoint; if (waypoint == null) { if (!LokiPoe.Me.IsInTown) { return(Results.OpenWaypointError.NoWaypoint); } if ( !await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(Actor.GuessWaypointLocation()), 25, 60000, () => LokiPoe.ObjectManager.Waypoint != null)) { return(Results.OpenWaypointError.CouldNotMoveToWaypoint); } waypoint = LokiPoe.ObjectManager.Waypoint; if (waypoint == null) { return(Results.OpenWaypointError.NoWaypoint); } } if (ExilePather.PathDistance(LokiPoe.MyPosition, waypoint.Position) > 30) { if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(waypoint.Position), 25, 15000, () => false)) { return(Results.OpenWaypointError.CouldNotMoveToWaypoint); } } await Coroutines.FinishCurrentAction(); waypoint = LokiPoe.ObjectManager.Waypoint; if (waypoint == null) { return(Results.OpenWaypointError.NoWaypoint); } if (!await InteractWith(waypoint)) { return(Results.OpenWaypointError.InteractFailed); } if (!await WaitForWorldPanel()) { return(Results.OpenWaypointError.WorldPanelDidNotOpen); } await Coroutine.Sleep(1000); // Adding this in to let the gui load more return(Results.OpenWaypointError.None); }
public static Vector2i CalcSafePosition(double escapeAngle, float safeDistance) { Vector2i result = new Vector2i(); for (int angleModificator = 0; angleModificator < 36; angleModificator++) { //We prioritize a route as close to our escape angle as possible double angle = escapeAngle + (Math.Ceiling((double)angleModificator / 2) * 0.174533 * (angleModificator % 2 == 0 ? 1 : -1)); Vector2i pos = GeometryHelper.GetPointOnCircle(LokiPoe.Me.Position, angle, safeDistance); bool skipPos = false; try { skipPos = !ExilePather.NavigationGrid.IsWalkable(pos) || !ExilePather.CanObjectSee(LokiPoe.Me, pos, true) || Utility.ClosedDoorBetween(LokiPoe.Me, pos, 10, 10, true); } catch { skipPos = true; } if (skipPos) { continue; } result = pos; break; } return(result); }
/// <summary> /// Checks for a closed door between start and end. /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="distanceFromPoint">How far to check around each point for a door object.</param> /// <param name="stride">The distance between points to check in the path.</param> /// <param name="dontLeaveFrame">Should the current frame not be left?</param> /// <returns>true if there's a closed door and false otherwise.</returns> public static bool ClosedDoorBetween( Vector2i start, Vector2i end, int distanceFromPoint = 10, int stride = 10, bool dontLeaveFrame = false) { var doors = LokiPoe.ObjectManager.Doors.Where(d => !d.IsOpened).ToList(); if (!doors.Any()) { return(false); } var path = ExilePather.GetPointsOnSegment(start, end, dontLeaveFrame); for (var i = 0; i < path.Count; i += stride) { if (doors.Any(door => door.Position.Distance(path[i]) <= distanceFromPoint)) { return(true); } } return(false); }
public static WorldPosition FindPathablePosition(Vector2i pos, int step = 10, int radius = 30) { var myPos = LokiPoe.MyPosition; int x = pos.X; int y = pos.Y; for (int r = step; r <= radius; r += step) { int minX = x - r; int minY = y - r; int maxX = x + r; int maxY = y + r; for (int i = minX; i <= maxX; i += step) { for (int j = minY; j <= maxY; j += step) { if (i != minX && i != maxX && j != minY && j != maxY) { continue; } var p = new Vector2i(i, j); if (ExilePather.PathExistsBetween(myPos, p)) { return(new WorldPosition(p)); } } } } return(null); }
/// <summary> /// Used to reset the starting area transition. This is for handling local area transitions. /// </summary> public void ResetStartingAreaTransition() { var at = LokiPoe.ObjectManager.GetObjectsByType <AreaTransition>().OrderBy(a => a.Distance).FirstOrDefault(); StartingAreaTransitionName = at != null ? at.Name : ""; StartingAreaTransitionLocation = at != null ? ExilePather.FastWalkablePositionFor(at) : Vector2i.Zero; }
public BreachCache(Breach breach) { Id = breach.Id; Position = breach.Position; WalkablePosition = ExilePather.FastWalkablePositionFor(breach); IsValid = true; Log.InfoFormat("[BreachCache] {0} {1}", Id, WalkablePosition); }
private void ReloadExilePatherButton_OnClick(object sender, RoutedEventArgs e) { Dispatcher.BeginInvoke(new Action(() => { using (LokiPoe.AcquireFrame()) { ExilePather.Reload(true); } GetDataFunc().ForceReload = true; Log.InfoFormat("[ReloadExilePatherButton_OnClick] Done!"); })); }
public MonolithCache(Monolith monolith) { Id = monolith.Id; Position = monolith.Position; WalkablePosition = ExilePather.FastWalkablePositionFor(monolith); MonsterName = monolith.Name; MonsterMetadata = monolith.MonsterTypeMetadata; Essences = monolith.EssenceBaseItemTypes; IsValid = true; Log.InfoFormat("[MonolithCache] {0} {1} {2} {3} {4}", Id, WalkablePosition, MonsterName, MonsterMetadata, string.Join(", ", Essences.Select(e => e.Metadata))); }
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; } }
/// <summary> /// Returns the number of mobs between 2 points /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="distanceFromPoint"></param> /// <param name="dontLeaveFrame">Should the current frame not be left?</param> /// <returns></returns> public static int NumberOfMobsBetween(Vector2i start, Vector2i end, int distanceFromPoint = 5, bool dontLeaveFrame = false) { var mobs = LokiPoe.ObjectManager.GetObjectsByType <Monster>().Where(d => d.IsActive).ToList(); if (!mobs.Any()) { return(0); } var path = ExilePather.GetPointsOnSegment(start, end, dontLeaveFrame); var count = 0; for (var i = 0; i < path.Count; i += 10) { count += mobs.Count(mob => mob.Position.Distance(path[i]) <= distanceFromPoint); } return(count); }
private void ShowAreaInformation(DatWorldAreaWrapper area) { TextBoxInfoRaw.AppendText(area.ToString()); var sb = new StringBuilder(); // Handle updates when the bot isn't running. if (!BotManager.IsRunning) { ExilePather.Reload(); //StaticLocationManager.Tick(); } /*sb.AppendLine(string.Format("[Static Locations]")); * foreach (var kvp in StaticLocationManager.StaticLocations) * { * sb.AppendLine(string.Format("\t{0}", kvp.Key)); * foreach (var pos in kvp.Value) * { * sb.AppendLine(string.Format("\t\t{0}", pos)); * } * }*/ /*sb.AppendLine(string.Format("[Static Waypoints]")); * foreach (var pos in StaticLocationManager.StaticWaypointLocations) * { * sb.AppendLine(string.Format("\t{0}", pos)); * }*/ sb.AppendLine(string.Format("[Mods]")); foreach (var mod in LokiPoe.LocalData.MapMods) { sb.AppendLine(string.Format("\t{0}: {1}", mod.Key, mod.Value)); } sb.AppendLine(string.Format("[Terrain]")); sb.AppendLine(string.Format("\tCols: {0}", LokiPoe.TerrainData.Cols)); sb.AppendLine(string.Format("\tRows: {0}", LokiPoe.TerrainData.Rows)); TextBoxInfoRaw.AppendText(sb.ToString()); }
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; } }
private AreaStateCache(uint hash) { Hash = hash; WorldArea = LokiPoe.CurrentWorldArea; ShouldCheckForWaypoint = LokiPoe.CurrentWorldArea.HasWaypoint; ShouldCheckForStash = LokiPoe.CurrentWorldArea.IsTown; HasStashLocation = false; HasWaypointLocation = false; var areaId = WorldArea.Id; HasWaypointEntry = LokiPoe.InstanceInfo.AvailableWaypoints.ContainsKey(areaId); SeenAreaTransitions = new List <string>(); //GenerateStaticLocations(); ResetStartingAreaTransition(); var portal = LokiPoe.ObjectManager.GetObjectsByType <Portal>().OrderBy(a => a.Distance).FirstOrDefault(); StartingPortalLocation = portal != null ? ExilePather.FastWalkablePositionFor(portal) : Vector2i.Zero; //if (!DisableDefaultExplorer) //{ // var ge = new GridExplorer // { // AutoResetOnAreaChange = false // }; // Explorer = ge; //} }
/// <summary> /// This coroutine will attempt to take a portal /// </summary> /// <returns>true if the portal was taken, and an area change occurred, and false otherwise.</returns> public static async Task <bool> TakeClosestPortal() { var sw = Stopwatch.StartNew(); if (LokiPoe.ConfigManager.IsAlwaysHighlightEnabled) { CommunityLib.Log.InfoFormat("[TakeClosestPortal] Now disabling Always Highlight to avoid label issues."); LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.highlight_toggle, true, false, false); await Coroutine.Sleep(16); } NetworkObject portal = null; while (portal == null || !portal.IsTargetable) { CommunityLib.Log.DebugFormat($"[TakeClosestPortal] Now waiting for the portal to spawn. {sw.Elapsed} elapsed."); await Coroutines.LatencyWait(); portal = LokiPoe.ObjectManager.GetObjectsByType <Portal>() .Where(p => p.Distance < 50) .OrderBy(p => p.Distance) .FirstOrDefault(); if (sw.ElapsedMilliseconds > 10000) { break; } } if (portal == null) { CommunityLib.Log.ErrorFormat("[TakeClosestPortal] A portal was not found."); return(false); } var pos = ExilePather.FastWalkablePositionFor(portal); CommunityLib.Log.Debug($"[TakeClosestPortal] The portal was found at {pos}."); if (!await Navigation.MoveToLocation(pos, 5, 10000, () => false)) { return(false); } var hash = LokiPoe.LocalData.AreaHash; // Try to interact 3 times. for (var i = 0; i < 3; i++) { if (LokiPoe.Me.IsDead) { break; } await Coroutines.FinishCurrentAction(); CommunityLib.Log.Debug($"[TakeClosestPortal] The portal to interact with is {portal.Id} at {pos}."); if (await InteractWith(portal)) { if (await Areas.WaitForAreaChange(hash)) { CommunityLib.Log.Debug("[TakeClosestPortal] The portal has been taken."); return(true); } } await Coroutine.Sleep(1000); } CommunityLib.Log.ErrorFormat("[TakeClosestPortal] We have failed to take the portal 3 times."); return(false); }
public static float PathDistance(this NetworkObject obj) { return(ExilePather.PathDistance(LokiPoe.MyPosition, obj.Position)); }
/// <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); }
/// <summary> /// This coroutine interacts with stash and waits for the stash panel to open. When called from a hideout, /// the stash must be in spawn range, otherwise the coroutine will fail. /// </summary> ///<param name="guild">Should the guild stash be opened?</param> /// <returns>An OpenStashError that describes the result.</returns> public static async Task <Results.OpenStashError> OpenStash(bool guild = false) { await Coroutines.CloseBlockingWindows(); await Coroutines.FinishCurrentAction(); var stash = Stash.DetermineStash(guild); if (stash == null) { if (LokiPoe.Me.IsInHideout) { return(Results.OpenStashError.NoStash); } var mtl = await Navigation.MoveToLocation( ExilePather.FastWalkablePositionFor(Actor.GuessStashLocation()), 25, 60000, () => Stash.DetermineStash(guild) != null && Stash.DetermineStash(guild).Distance < 75); if (!mtl) { return(Results.OpenStashError.CouldNotMoveToStash); } stash = Stash.DetermineStash(guild); if (stash == null) { return(Results.OpenStashError.NoStash); } } if (stash.Distance > 30) { var p = stash.Position; if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(p), 25, 15000, () => false)) { return(Results.OpenStashError.CouldNotMoveToStash); } } await Coroutines.FinishCurrentAction(); stash = Stash.DetermineStash(guild); if (stash == null) { return(Results.OpenStashError.NoStash); } if (!await InteractWith(stash)) { return(Results.OpenStashError.InteractFailed); } if (guild) { if (!await Dialog.WaitForPanel(Dialog.PanelType.GuildStash)) { return(Results.OpenStashError.StashPanelDidNotOpen); } await Stash.WaitForStashTabChange(guild : true); } else { if (!await Dialog.WaitForPanel(Dialog.PanelType.Stash)) { return(Results.OpenStashError.StashPanelDidNotOpen); } await Stash.WaitForStashTabChange(); } return(Results.OpenStashError.None); }
private void OnTick() { //if (Explorer != null) //{ // Explorer.Tick(); //} var update = false; if (!_itemThrottle.IsRunning) { _itemThrottle.Start(); update = true; } else { if (_itemThrottle.ElapsedMilliseconds >= ItemThrottleMs) { update = true; } } //using (new PerformanceTimer("Tick::WorldItem", 1)) { if (update) { var myPos = LokiPoe.MyPosition; var added = 0; foreach (var worldItem in LokiPoe.ObjectManager.GetObjectsByType <WorldItem>()) { var doAdd = false; Vector2i pos; if (!_ignoreItems.TryGetValue(worldItem.Id, out pos)) { doAdd = true; } else { if (pos != worldItem.Position) { Log.InfoFormat("[AreaStateCache] An item collision has been detected! Item id {0}.", worldItem.Id); _ignoreItems.Remove(worldItem.Id); doAdd = true; } } if (doAdd) { if (added > 10) { break; } ++added; var item = worldItem.Item; if (worldItem.IsAllocatedToOther) { if (DateTime.Now < worldItem.PublicTime) { //Log.InfoFormat("[AreaStateCache] The item {0} is not being marked for pickup because it is allocated to another player.", item.FullName); //_ignoreItems.Add(worldItem.Id, worldItem.Position); continue; } } var visibleOverride = false; if (LootVisibleItemsOverride) { // We can only consider items when they are visible, otherwise we ignore stuff we might want. if (!LokiPoe.ConfigManager.IsAlwaysHighlightEnabled) { continue; } if (LokiPoe.Input.GetClickableHighlightLabelPosition(worldItem) != Vector2.Zero) { visibleOverride = true; } } IItemFilter filter = null; if (visibleOverride || ItemEvaluator.Match(item, EvaluationType.PickUp, out filter)) { var location = new ItemLocation { Id = worldItem.Id, Name = worldItem.Name, Position = worldItem.Position, Rarity = worldItem.Item.Rarity, Metadata = worldItem.Item.Metadata }; if (_itemLocations.ContainsKey(location.Id)) { _itemLocations[location.Id] = location; } else { _itemLocations.Add(location.Id, location); } Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being added from filter [{3}].{2}", location.Id, location.Name, worldItem.HasAllocation ? " [Allocation " + worldItem.PublicTime + "]" : "", filter != null ? filter.Name : "(null)"); } _ignoreItems.Add(worldItem.Id, worldItem.Position); } } var toRemove = new List <int>(); foreach (var kvp in _itemLocations) { if (Blacklist.Contains(kvp.Key)) { Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being removed because the id has been Blacklisted.", kvp.Value.Id, kvp.Value.Name); toRemove.Add(kvp.Value.Id); } else if (myPos.Distance(kvp.Value.Position) < 30) { if (LokiPoe.ObjectManager.GetObjectById <WorldItem>(kvp.Value.Id) == null) { Log.InfoFormat("[AreaStateCache] The location {0} [{1}] is being removed because the WorldItem does not exist.", kvp.Value.Id, kvp.Value.Name); toRemove.Add(kvp.Value.Id); } } } foreach (var id in toRemove) { _itemLocations.Remove(id); } _itemThrottle.Restart(); } } if (!_chestThrottle.IsRunning) { _chestThrottle.Start(); } else { if (_chestThrottle.ElapsedMilliseconds >= ChestThrottleMs) { //using (new PerformanceTimer("Tick::Chest", 1)) { var addedChests = new List <ChestLocation>(); foreach (var chest in LokiPoe.ObjectManager.GetObjectsByType <Chest>().ToList()) { ChestLocation location; if (!_chestLocations.TryGetValue(chest.Id, out location)) { location = new ChestLocation { Id = chest.Id, Name = chest.Name, IsTargetable = chest.IsTargetable, IsOpened = chest.IsOpened, IsStrongBox = chest.IsStrongBox, IsVaalVessel = chest.IsVaalVessel, OpensOnDamage = chest.OpensOnDamage, Position = chest.Position, Stats = chest.Stats.ToList(), IsIdentified = chest.IsIdentified, IsBreakable = chest.OpensOnDamage, Rarity = chest.Rarity, Metadata = chest.Type }; _chestLocations.Add(location.Id, location); addedChests.Add(location); } if (!location.IsOpened) { location.IsOpened = chest.IsOpened; location.IsLocked = chest.IsLocked; location.IsTargetable = chest.IsTargetable; // Support for chests that change locked state, without the lock state updating. var tc = chest.Components.TransitionableComponent; if (tc != null) { if ((tc.Flag1 & 2) != 0) { location.IsLocked = false; } } if (chest.IsVaalVessel) { location.IsLocked = false; } if (!location.IsCorrupted && chest.IsCorrupted) { location.IsCorrupted = chest.IsCorrupted; location.Stats = chest.Stats.ToList(); } if (!location.IsIdentified && chest.IsIdentified) { location.IsIdentified = chest.IsIdentified; location.Stats = chest.Stats.ToList(); } } if (addedChests.Count > 10) { break; } } foreach (var location in addedChests) { if (!location.IsBreakable) { location.Position = ExilePather.FastWalkablePositionFor(location.Position); } LokiPoe.InvokeEvent(OnChestLocationAdded, null, new OnChestLocationAddedEventArgs(location)); } addedChests.Clear(); _chestThrottle.Restart(); } } } if (!_questThrottle.IsRunning) { _questThrottle.Start(); } else { if (_questThrottle.ElapsedMilliseconds >= QuestThrottleMs) { if (LokiPoe.CurrentWorldArea.IsMissionArea) { if (!HasKaruiSpiritLocation) { var obj = LokiPoe.ObjectManager.GetObjectByName("Karui Spirit"); if (obj != null) { AddLocation(ExilePather.FastWalkablePositionFor(obj), obj.Id, obj.Name); HasKaruiSpiritLocation = true; } } } _questThrottle.Restart(); } } if (!_throttle.IsRunning) { _throttle.Start(); } else { if (_throttle.ElapsedMilliseconds >= ThrottleMs) { if (!_timeInInstance.IsRunning) { _timeInInstance.Start(); } if (!_timeInArea.IsRunning) { _timeInArea.Start(); } // Do we need to update wp state flags. if (_updateCheckForWaypoint) { // If the current area doesn't have a wp, we do not want to do any more logic processing. if (!LokiPoe.CurrentWorldArea.HasWaypoint) { _updateCheckForWaypoint = false; ShouldCheckForWaypoint = false; HasWaypointLocation = false; HasWaypointEntry = false; } else { ShouldCheckForWaypoint = true; } } // Do we need to update at state flags. if (_updateAreaTransition) { ShouldCheckForAreaTransition = true; } if (ShouldCheckForStash) { //using (new PerformanceTimer("ShouldCheckForStash", 1)) { if (!HasStashLocation) { var stash = LokiPoe.ObjectManager.Stash; if (stash != null) { // Save the location so we know where it is when the entity isn't in view. AddLocation(ExilePather.FastWalkablePositionFor(stash), stash.Id, "Stash"); // We now have the waypoint location. HasStashLocation = true; } } else { ShouldCheckForStash = false; } } } // If we need to handle wps. if (ShouldCheckForWaypoint) { //using (new PerformanceTimer("ShouldCheckForWaypoint", 1)) { // If we don't have the wp location yet, check to see if we see one. if (!HasWaypointLocation) { var wp = LokiPoe.ObjectManager.Waypoint; if (wp != null) { // Save the location so we know where it is when the entity isn't in view. AddLocation(ExilePather.FastWalkablePositionFor(wp), wp.Id, "Waypoint"); // We now have the waypoint location. HasWaypointLocation = true; } } // If we don't have the wp entry yet, poll for us having it now. // But only if we've seen the waypoint, since otherwise there's no way we have it. if (HasWaypointLocation && !HasWaypointEntry) { var areaId = WorldArea.Id; HasWaypointEntry = LokiPoe.InstanceInfo.AvailableWaypoints.ContainsKey(areaId); } // Once we have both the location and the entry, we do not need to execute wp logic anymore. if (HasWaypointLocation && HasWaypointEntry) { _updateCheckForWaypoint = false; ShouldCheckForWaypoint = false; } } } // If we need to handle ats. if (ShouldCheckForAreaTransition) { //using (new PerformanceTimer("ShouldCheckForAreaTransition", 1)) { // If there are any area transitions on screen, add them if we don't already know of them. foreach (var transition in LokiPoe.ObjectManager.Objects.OfType <AreaTransition>().ToList()) { var name = transition.Name; // We have to check all this in order to handle the areas that have transitions with the same name, but different // entity ids. if (HasLocation(name, transition.Id)) { continue; } AddLocation(ExilePather.FastWalkablePositionFor(transition), transition.Id, name); if (!SeenAreaTransitions.Contains(name)) { SeenAreaTransitions.Add(name); } } } } // Check to see if we need a new anchor point to kite back towards. if (!_hasAnchorPoint || LokiPoe.LocalData.AreaHash != _anchorPointSeed) { ResetAnchorPoint(); ResetCurrentAnchorPoint(); } _throttle.Restart(); } } }
public static bool PathExists(this NetworkObject obj) { return(ExilePather.PathExistsBetween(LokiPoe.MyPosition, obj.Position)); }
public static WorldPosition FindWalkablePosition(Vector2i pos, int radius = 15) { var walkable = ExilePather.FastWalkablePositionFor(pos, radius); return(ExilePather.PathExistsBetween(LokiPoe.MyPosition, walkable) ? new WorldPosition(walkable) : null); }
/// <summary> /// Attempts to move towards a position. This function will perform pathfinding logic and take into consideration move distance /// to try and smoothly move towards a point. /// </summary> /// <param name="position">The position to move towards.</param> /// <param name="user">A user object passed.</param> /// <returns>true if the position was moved towards, and false if there was a pathfinding error.</returns> public bool MoveTowards(Vector2i position, params dynamic[] user) { var myPosition = LokiPoe.MyPosition; if ( _cmd == null || // No command yet _cmd.Path == null || _cmd.EndPoint != position || // Moving to a new position LokiPoe.CurrentWorldArea.IsTown || // In town, always generate new paths (_sw.IsRunning && _sw.ElapsedMilliseconds > OldPlayerMoverSettings.Instance.PathRefreshRateMs) || // New paths on interval _cmd.Path.Count <= 2 || // Not enough points _cmd.Path.All(p => myPosition.Distance(p) > 7)) // Try and find a better path to follow since we're off course { _cmd = new PathfindingCommand(myPosition, position, 3, OldPlayerMoverSettings.Instance.AvoidWallHugging); if (!ExilePather.FindPath(ref _cmd)) { _sw.Restart(); Log.ErrorFormat("[OldPlayerMover.MoveTowards] ExilePather.FindPath failed from {0} to {1}.", myPosition, position); return(false); } //Log.InfoFormat("[OldPlayerMover.MoveTowards] Finding new path."); _sw.Restart(); //_originalPath = new IndexedList<Vector2i>(_cmd.Path); } // Eliminate points until we find one within a good moving range. while (_cmd.Path.Count > 1) { if (_cmd.Path[0].Distance(myPosition) < OldPlayerMoverSettings.Instance.MoveRange) { _cmd.Path.RemoveAt(0); } else { break; } } var point = _cmd.Path[0]; point += new Vector2i(LokiPoe.Random.Next(-2, 3), LokiPoe.Random.Next(-2, 3)); if (_useForceAdjustments) { var negX = 0; var posX = 0; var tmp1 = point; var tmp2 = point; for (var i = 0; i < 10; i++) { tmp1.X--; if (!ExilePather.IsWalkable(tmp1)) { negX++; } tmp2.X++; if (!ExilePather.IsWalkable(tmp2)) { posX++; } } if (negX > 5 && posX == 0) { point.X += 10; if (OldPlayerMoverSettings.Instance.DebugAdjustments) { Log.WarnFormat("[OldPlayerMover.MoveTowards] X-Adjustments being made!"); } _cmd.Path[0] = point; } else if (posX > 5 && negX == 0) { point.X -= 10; if (OldPlayerMoverSettings.Instance.DebugAdjustments) { Log.WarnFormat("[OldPlayerMover.MoveTowards] X-Adjustments being made!"); } _cmd.Path[0] = point; } var negY = 0; var posY = 0; tmp1 = point; tmp2 = point; for (var i = 0; i < 10; i++) { tmp1.Y--; if (!ExilePather.IsWalkable(tmp1)) { negY++; } tmp2.Y++; if (!ExilePather.IsWalkable(tmp2)) { posY++; } } if (negY > 5 && posY == 0) { point.Y += 10; if (OldPlayerMoverSettings.Instance.DebugAdjustments) { Log.WarnFormat("[OldPlayerMover.MoveTowards] Y-Adjustments being made!"); } _cmd.Path[0] = point; } else if (posY > 5 && negY == 0) { point.Y -= 10; if (OldPlayerMoverSettings.Instance.DebugAdjustments) { Log.WarnFormat("[OldPlayerMover.MoveTowards] Y-Adjustments being made!"); } _cmd.Path[0] = point; } } // Le sigh... if (_useAct3TownAdjustments) { var seed = LokiPoe.LocalData.AreaHash; if (_tgtSeed != seed || _tgts == null) { Log.InfoFormat("[OldPlayerMover.MoveTowards] Now building TGT info."); _tgts = LokiPoe.TerrainData.TgtEntries; _tgtSeed = seed; } if (TgtUnderPlayer.TgtName.Equals("Art/Models/Terrain/Act3Town/Act3_town_01_01_c16r7.tgt")) { Log.InfoFormat("[OldPlayerMover.MoveTowards] Act 3 Town force adjustment being made!"); point.Y += 5; } } var move = LokiPoe.InGameState.SkillBarHud.LastBoundMoveSkill; if (move == null) { Log.ErrorFormat("[OldPlayerMover.MoveTowards] Please assign the \"Move\" skill to your skillbar!"); return(false); } if ((LokiPoe.ProcessHookManager.GetKeyState(move.BoundKeys.Last()) & 0x8000) != 0 && LokiPoe.Me.HasCurrentAction) { if (myPosition.Distance(position) < OldPlayerMoverSettings.Instance.SingleUseDistance) { LokiPoe.ProcessHookManager.ClearAllKeyStates(); LokiPoe.InGameState.SkillBarHud.UseAt(move.Slots.Last(), false, point); if (OldPlayerMoverSettings.Instance.DebugInputApi) { Log.WarnFormat("[SkillBarHud.UseAt] {0}", point); } _lastPoint = point; } else { if (OldPlayerMoverSettings.Instance.UseMouseSmoothing) { var d = _lastPoint.Distance(point); if (d >= OldPlayerMoverSettings.Instance.MouseSmoothDistance) { MouseManager.SetMousePos("OldPlayerMover.MoveTowards", point, false); if (OldPlayerMoverSettings.Instance.DebugInputApi) { Log.WarnFormat("[MouseManager.SetMousePos] {0} [{1}]", point, d); } _lastPoint = point; } else { if (OldPlayerMoverSettings.Instance.DebugInputApi) { Log.WarnFormat("[MouseManager.SetMousePos] Skipping moving mouse to {0} because [{1}] < [{2}]", point, d, OldPlayerMoverSettings.Instance.MouseSmoothDistance); } } } else { MouseManager.SetMousePos("OldPlayerMover.MoveTowards", point, false); } } } else { LokiPoe.ProcessHookManager.ClearAllKeyStates(); if (myPosition.Distance(position) < OldPlayerMoverSettings.Instance.SingleUseDistance) { LokiPoe.InGameState.SkillBarHud.UseAt(move.Slots.Last(), false, point); if (OldPlayerMoverSettings.Instance.DebugInputApi) { Log.WarnFormat("[SkillBarHud.UseAt] {0}", point); } } else { LokiPoe.InGameState.SkillBarHud.BeginUseAt(move.Slots.Last(), false, point); if (OldPlayerMoverSettings.Instance.DebugInputApi) { Log.WarnFormat("[BeginUseAt] {0}", point); } } } return(true); }
/// <summary> /// This coroutine interacts with a npc and waits for the npc dialog panel to open. When called for a non-main town npc /// the npc must be in spawn range, otherwise the coroutine will fail. The movement is done without returning, /// so this should be carefully used when not in town. /// </summary> /// <param name="name">Name of the NPC to interact with</param> /// <param name="skipTalk">Should the bot skip all the dialog NPC's have before the dialog panel appears"</param> /// <returns>An OpenStashError that describes the result.</returns> public static async Task <Results.TalkToNpcError> TalkToNpc(string name, bool skipTalk = true) { await Coroutines.CloseBlockingWindows(); await Coroutines.FinishCurrentAction(); var npc = LokiPoe.ObjectManager.GetObjectByName(name); if (npc == null) { var pos = Actor.GuessNpcLocation(name); if (pos == Vector2i.Zero) { return(Results.TalkToNpcError.NoNpc); } if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(pos), 25, 60000, () => LokiPoe.ObjectManager.GetObjectByName(name) != null)) { return(Results.TalkToNpcError.CouldNotMoveToNpc); } npc = LokiPoe.ObjectManager.GetObjectByName(name); if (npc == null) { return(Results.TalkToNpcError.NoNpc); } } if (ExilePather.PathDistance(LokiPoe.MyPosition, npc.Position) > 30) { if (!await Navigation.MoveToLocation(ExilePather.FastWalkablePositionFor(npc.Position), 25, 15000, () => false)) { return(Results.TalkToNpcError.CouldNotMoveToNpc); } npc = LokiPoe.ObjectManager.GetObjectByName(name); if (npc == null) { return(Results.TalkToNpcError.NoNpc); } } await Coroutines.FinishCurrentAction(); if (!await InteractWith(npc)) { return(Results.TalkToNpcError.InteractFailed); } // Clicking continue if NPC is blablaing (xD) while (skipTalk && LokiPoe.InGameState.NpcDialogUi.DialogDepth != 1) { if (LokiPoe.InGameState.NpcDialogUi.DialogDepth == 2) { CommunityLib.Log.DebugFormat("[CommunityLib][TalkToNpc] Now closing a dialog/reward window."); LokiPoe.Input.SimulateKeyEvent(Keys.Escape, true, false, false); // Give the client enough time to close the gui itself. It waits for the server to show the new one. await Coroutine.Sleep(LokiPoe.Random.Next(800, 1000)); await Coroutines.ReactionWait(); } else { CommunityLib.Log.InfoFormat("[CommunityLib][TalkToNpc] Waiting for the Npc window to open."); await Coroutines.ReactionWait(); } } if (!await Dialog.WaitForPanel(Dialog.PanelType.NpcDialog)) { return(Results.TalkToNpcError.NpcDialogPanelDidNotOpen); } return(Results.TalkToNpcError.None); }