Esempio n. 1
0
        public static async Task <bool> Interact(NetworkObject obj, int attempts)
        {
            if (obj == null)
            {
                GlobalLog.Error("[Interact] Object for interaction is null.");
                return(false);
            }

            var name = obj.Name;

            GlobalLog.Debug($"[Interact] Now going to interact with \"{name}\".");

            for (int i = 1; i <= attempts; i++)
            {
                if (!LokiPoe.IsInGame || LokiPoe.Me.IsDead)
                {
                    break;
                }

                await Coroutines.CloseBlockingWindows();

                await Coroutines.FinishCurrentAction();

                await Wait.LatencySleep();

                if (await Coroutines.InteractWith(obj))
                {
                    GlobalLog.Debug($"[Interact] \"{name}\" has been successfully interacted.");
                    return(true);
                }
                GlobalLog.Error($"[Interact] Fail to interact with \"{name}\". Attempt: {i}/{attempts}.");
                await Wait.SleepSafe(100, 200);
            }
            return(false);
        }
Esempio n. 2
0
        public static async Task <bool> Interact(NetworkObject obj, Func <bool> success, string desc, int timeout = 3000)
        {
            if (obj == null)
            {
                GlobalLog.Error("[Interact] Object for interaction is null.");
                return(false);
            }

            var name = obj.Name;

            GlobalLog.Debug($"[Interact] Now going to interact with \"{name}\".");

            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            await Wait.LatencySleep();

            if (await Coroutines.InteractWith(obj))
            {
                if (!await Wait.For(success, desc, 100, timeout))
                {
                    return(false);
                }

                GlobalLog.Debug($"[Interact] \"{name}\" has been successfully interacted.");
                return(true);
            }
            GlobalLog.Error($"[Interact] Fail to interact with \"{name}\".");
            await Wait.SleepSafe(300, 500);

            return(false);
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        public static async Task AtOnce(Vector2i pos, string destination, int minDistance = 20)
        {
            if (LokiPoe.MyPosition.Distance(pos) <= minDistance)
            {
                return;
            }

            while (LokiPoe.MyPosition.Distance(pos) > minDistance)
            {
                if (LogInterval.Elapsed)
                {
                    await Coroutines.CloseBlockingWindows();

                    GlobalLog.Debug($"[MoveAtOnce] Moving to {destination} at {pos} (distance: {LokiPoe.MyPosition.Distance(pos)})");
                }

                if (!LokiPoe.IsInGame || LokiPoe.Me.IsDead || BotManager.IsStopping)
                {
                    return;
                }

                TowardsWalkable(pos, destination);
                await Wait.Sleep(50);
            }
            await Coroutines.FinishCurrentAction();
        }
Esempio n. 5
0
 public static async Task TalkTo(NetworkObject npc)
 {
     if (await npc.AsTownNpc().Talk())
     {
         await Coroutines.CloseBlockingWindows();
     }
     else
     {
         ErrorManager.ReportError();
     }
 }
Esempio n. 6
0
        public async Task <bool> Run()
        {
            if (!Enabled || !World.CurrentArea.IsCombatArea)
            {
                return(false);
            }

            var chests = LokiPoe.ObjectManager.Objects
                         .Where <Chest>(c => c.Distance <= 10 && !c.IsOpened && c.IsStompable && !Processed.Contains(c.Id))
                         .OrderBy(c => c.DistanceSqr)
                         .ToList();

            if (chests.Count == 0)
            {
                //run this task only once, by StuckDetection demand
                Enabled = false;
                return(false);
            }

            LokiPoe.ProcessHookManager.Reset();
            await Coroutines.CloseBlockingWindows();

            var positions1 = new List <Vector2i> {
                LokiPoe.MyPosition
            };
            var positions2 = new List <Vector2> {
                LokiPoe.MyWorldPosition
            };

            foreach (var chest in chests)
            {
                Processed.Add(chest.Id);
                positions1.Add(chest.Position);
                positions2.Add(chest.WorldPosition);
            }

            foreach (var position in positions1)
            {
                MouseManager.SetMousePos("EXtensions.CommonTasks.HandleBlockingChestsTask", position);
                await Click();
            }

            foreach (var position in positions2)
            {
                MouseManager.SetMousePos("EXtensions.CommonTasks.HandleBlockingChestsTask", position);
                await Click();
            }
            return(true);
        }
        public static async Task <bool> TalkToSin()
        {
            if (World.Act9.Highgate.IsCurrentArea)
            {
                if (!await Helpers.Sin_A9.Talk())
                {
                    ErrorManager.ReportError();
                    return(true);
                }
                await Coroutines.CloseBlockingWindows();

                return(false);
            }
            await Travel.To(World.Act9.Highgate);

            return(true);
        }
Esempio n. 8
0
        public static async Task <bool> UseQuestItem(string metadata)
        {
            var item = Inventories.InventoryItems.Find(i => i.Class == ItemClasses.QuestItem && i.Metadata.ContainsIgnorecase(metadata));

            if (item == null)
            {
                GlobalLog.Error($"[UseQuestItem] Fail to find item with metadata \"{metadata}\" in inventory.");
                return(false);
            }

            var pos  = item.LocationTopLeft;
            var id   = item.LocalId;
            var name = item.Name;

            GlobalLog.Debug($"[UseQuestItem] Now going to use \"{name}\".");

            if (!await Inventories.OpenInventory())
            {
                ErrorManager.ReportError();
                return(false);
            }

            var err = InventoryUi.InventoryControl_Main.UseItem(id);

            if (err != UseItemResult.None)
            {
                GlobalLog.Error($"[UseQuestItem] Fail to use \"{name}\". Error: \"{err}\".");
                return(false);
            }

            if (!await Wait.For(() => InventoryUi.InventoryControl_Main.Inventory.FindItemByPos(pos) == null, "quest item despawn", 100, 2000))
            {
                return(false);
            }

            if (LokiPoe.InGameState.CursorItemOverlay.Item != null)
            {
                GlobalLog.Error($"[UseQuestItem] Error. \"{name}\" has been picked to cursor.");
                return(false);
            }
            await Wait.SleepSafe(500); //give a quest state time to update

            await Coroutines.CloseBlockingWindows();

            return(true);
        }
Esempio n. 9
0
        private static async Task <bool> OpenChallenges()
        {
            await Coroutines.CloseBlockingWindows();

            LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.open_challenges_panel, true, false, false);

            if (!await Wait.For(() => LokiPoe.InGameState.ChallengesUi.IsOpened, "challenges panel opening"))
            {
                return(false);
            }

            if (Settings.Instance.ArtificialDelays)
            {
                await Wait.ArtificialDelay();
            }

            return(true);
        }
Esempio n. 10
0
        public static async Task <bool> TurnInStaff()
        {
            if (!Helpers.PlayerHasQuestItem(QuestItemMetadata.StaffOfPurity))
            {
                return(false);
            }

            if (World.Act10.OriathDocks.IsCurrentArea)
            {
                if (await TownBannon.Talk())
                {
                    await Coroutines.CloseBlockingWindows();
                }
                else
                {
                    ErrorManager.ReportError();
                }
                return(true);
            }
            await Travel.To(World.Act10.OriathDocks);

            return(true);
        }
Esempio n. 11
0
        public static async Task <bool> OpenInventory()
        {
            if (InventoryUi.IsOpened && !LokiPoe.InGameState.PurchaseUi.IsOpened && !LokiPoe.InGameState.SellUi.IsOpened)
            {
                return(true);
            }

            await Coroutines.CloseBlockingWindows();

            LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.open_inventory_panel, true, false, false);

            if (!await Wait.For(() => InventoryUi.IsOpened, "inventory panel opening"))
            {
                return(false);
            }

            if (Settings.Instance.ArtificialDelays)
            {
                await Wait.ArtificialDelay();
            }

            return(true);
        }
Esempio n. 12
0
        /// <summary>
        /// Opens the inventory panel.
        /// </summary>
        /// <returns></returns>
        public static async Task <bool> OpenInventoryPanel(int timeout = 10000)
        {
            CommunityLib.Log.DebugFormat("[OpenInventoryPanel]");

            var sw = Stopwatch.StartNew();

            // Make sure we close all blocking windows so we can actually open the inventory.
            if (!LokiPoe.InGameState.InventoryUi.IsOpened)
            {
                await Coroutines.CloseBlockingWindows();
            }

            // Open the inventory panel like a player would.
            while (!LokiPoe.InGameState.InventoryUi.IsOpened)
            {
                CommunityLib.Log.DebugFormat("[OpenInventoryPanel] The InventoryUi is not opened. Now opening it.");

                if (sw.ElapsedMilliseconds > timeout)
                {
                    CommunityLib.Log.ErrorFormat("[OpenInventoryPanel] Timeout.");
                    return(false);
                }

                if (LokiPoe.Me.IsDead)
                {
                    CommunityLib.Log.ErrorFormat("[OpenInventoryPanel] We are now dead.");
                    return(false);
                }

                LokiPoe.Input.SimulateKeyEvent(LokiPoe.Input.Binding.open_inventory_panel, true, false, false);
                await Coroutines.LatencyWait(2);

                await Coroutines.ReactionWait();
            }

            return(true);
        }
Esempio n. 13
0
        public async Task <bool> Run()
        {
            var area = World.CurrentArea;

            if (!area.IsHideoutArea && !area.IsMapRoom)
            {
                return(false);
            }

            await Coroutines.CloseBlockingWindows();

            var golemSkill = SkillBar.Skills.FirstOrDefault(s => s.IsOnSkillBar && s.SkillTags.Contains("golem"));

            if (golemSkill != null)
            {
                var golemObj = golemSkill.DeployedObjects.FirstOrDefault() as Monster;
                if (golemObj == null || golemObj.HealthPercent < MinGolemHpPercent)
                {
                    GlobalLog.Debug($"[CastAuraTask] Now summoning \"{golemSkill.Name}\".");
                    SkillBar.Use(golemSkill.Slot, false);
                    await Wait.SleepSafe(100);

                    await Coroutines.FinishCurrentAction();

                    await Wait.SleepSafe(100);
                }
            }
            var auras = GetAurasForCast();

            if (auras.Count > 0 && AllAuras.Any(a => a.IsOnSkillBar))
            {
                GlobalLog.Info($"[CastAuraTask] Found {auras.Count} aura(s) for casting.");
                await CastAuras(auras);
            }
            return(false);
        }
        public async Task <bool> Run()
        {
            if (!settings.Instance.ExaltRecipeEnabled)
            {
                return(false);
            }

            if (_shaperStashTabIsFull || ErrorLimitReached)
            {
                return(false);
            }

            var area = World.CurrentArea;

            if (!area.IsTown && !area.IsHideoutArea)
            {
                return(false);
            }

            if (_shouldUpdateStashData)
            {
                GlobalLog.Debug("[StashRecipeTask] Updating shaper exalt recipe stash data (every Start)");

                if (settings.Instance.ExaltRecipeEnabled)
                {
                    if (!await OpenShaperRecipeTab())
                    {
                        return(true);
                    }
                    else
                    {
                        Class1.ShaperStashData.SyncWithStashTab(RecipeData.ExaltRecipeItemType.Shaper);
                    }
                }

                _shouldUpdateStashData = false;
            }
            else
            {
                if (AnyItemToStash)
                {
                    GlobalLog.Debug("[StashRecipeTask] Updating shaper exalt recipe stash data before actually stashing the items.");

                    if (settings.Instance.ExaltRecipeEnabled)
                    {
                        if (!await OpenShaperRecipeTab())
                        {
                            return(true);
                        }
                        else
                        {
                            Class1.ShaperStashData.SyncWithStashTab(RecipeData.ExaltRecipeItemType.Shaper);
                        }
                    }
                }
                else
                {
                    GlobalLog.Info("[StashRecipeTask] AnyItemsToStash empty, No items to stash for shaper exalt recipe.");
                    await Coroutines.CloseBlockingWindows();

                    return(false);
                }
            }

            var itemsToStash = ItemsToStash;

            if (itemsToStash.Count == 0)
            {
                GlobalLog.Info("[StashRecipeTask] No items to stash for shaper exalt recipe.");
                await Coroutines.CloseBlockingWindows();

                return(false);
            }

            GlobalLog.Info($"[StashRecipeTask] {itemsToStash.Count} items to stash for shaper exalt recipe.");

            await OpenShaperRecipeTab();

            // Shaper Loop
            foreach (var item in itemsToStash.OrderBy(i => i.Position, Position.Comparer.Instance))
            {
                if (item.RecipeType != RecipeData.ExaltRecipeItemType.Shaper)
                {
                    continue;
                }

                GlobalLog.Debug($"[StashRecipeTask] Now stashing \"{item.Name}\" for shaper exalt recipe.");
                var itemPos = item.Position;
                if (!Inventories.StashTabCanFitItem(itemPos))
                {
                    GlobalLog.Error("[StashRecipeTask] Stash tab for shaper exalt recipe is full and must be cleaned.");
                    _shaperStashTabIsFull = true;
                    return(true);
                }
                if (!await Inventories.FastMoveFromInventory(itemPos))
                {
                    ReportError();
                    return(true);
                }
                Class1.ShaperStashData.IncreaseItemCount(item.ItemType);
                GlobalLog.Info($"[Events] Item stashed ({item.FullName})");
                Utility.BroadcastMessage(this, Events.Messages.ItemStashedEvent, item);
            }
            await Wait.SleepSafe(300);

            Class1.ShaperStashData.SyncWithStashTab(RecipeData.ExaltRecipeItemType.Shaper);
            Class1.ShaperStashData.Log();
            return(true);
        }
Esempio n. 15
0
        public async Task <bool> Run()
        {
            var area = World.CurrentArea;

            if (!area.IsMap && !area.IsOverworldArea)
            {
                return(false);
            }

            if (LokiPoe.InstanceInfo.Incursion.IncursionsRemaining != 0)
            {
                return(false);
            }

            var cache = CombatAreaCache.Current;

            if (cache.Storage["IsTempleCompleted"] != null)
            {
                return(false);
            }

            var alva = Incursion.CachedAlva;

            if (alva == null || alva.Unwalkable || alva.Ignored)
            {
                return(false);
            }

            var pos = alva.Position;

            if (pos.Distance > 20 || pos.PathDistance > 20)
            {
                if (!pos.TryCome())
                {
                    GlobalLog.Error($"[EnterTempleTask] Fail to move to {pos}. Alva is unwalkable.");
                    alva.Unwalkable = true;
                }
                return(true);
            }

            var alvaObj = alva.Object;

            if (alvaObj == null)
            {
                GlobalLog.Error("[EnterTempleTask] Unexpected error. We are near cached Alva, but actual object is null.");
                alva.Ignored = true;
                return(true);
            }

            var portal = ActiveTemplePortal;

            if (portal == null)
            {
                var attempts = ++alva.InteractionAttempts;
                if (attempts > 7)
                {
                    GlobalLog.Error("[EnterTempleTask] All attempts to interact with Alva have been spent.");
                    alva.Ignored = true;
                    return(true);
                }
                if (alvaObj.HasNpcFloatingIcon)
                {
                    if (await PlayerAction.Interact(alvaObj))
                    {
                        await Wait.Sleep(200);

                        await Coroutines.CloseBlockingWindows();
                    }
                    return(true);
                }
                if (await alvaObj.AsTownNpc().Converse("Enter Temple"))
                {
                    await Coroutines.CloseBlockingWindows();

                    await Wait.For(() => ActiveTemplePortal != null, "Temple portals activation", 500, 10000);
                }
                return(true);
            }

            if (Settings.Instance.SkipTemple)
            {
                cache.Storage["IsTempleCompleted"] = true;
                return(true);
            }

            if (ErrorManager.GetErrorCount("EnterTemple") >= 5)
            {
                GlobalLog.Error("[EnterTempleTask] Failed to enter Temple portal 5 times.");
                alva.Ignored = true;
                return(true);
            }
            if (!await PlayerAction.TakePortal(portal))
            {
                ErrorManager.ReportError("EnterTemple");
                await Wait.SleepSafe(500);
            }
            return(true);
        }
Esempio n. 16
0
        /// <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);
        }
Esempio n. 17
0
        /// <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);
        }
Esempio n. 18
0
        public static async Task <bool> SellItems(List <Vector2i> itemPositions)
        {
            if (itemPositions == null)
            {
                GlobalLog.Error("[SellItems] Item list for sell is null.");
                return(false);
            }
            if (itemPositions.Count == 0)
            {
                GlobalLog.Error("[SellItems] Item list for sell is empty.");
                return(false);
            }

            var vendor = GetSellVendor();

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

            if (!await vendor.OpenSellPanel())
            {
                return(false);
            }

            itemPositions.Sort(Position.Comparer.Instance);

            var soldItems = new List <CachedItem>(itemPositions.Count);

            foreach (var itemPos in itemPositions)
            {
                var item = InventoryUi.InventoryControl_Main.Inventory.FindItemByPos(itemPos);
                if (item == null)
                {
                    GlobalLog.Error($"[SellItems] Fail to find item at {itemPos}. Skipping it.");
                    continue;
                }

                soldItems.Add(new CachedItem(item));

                if (!SellUi.TradeControl.InventoryControl_YourOffer.Inventory.CanFitItem(item.Size))
                {
                    break;
                }

                if (!await Inventories.FastMoveToVendor(itemPos))
                {
                    return(false);
                }
            }

            var gainedItems = new List <CachedItem>();

            foreach (var item in SellUi.TradeControl.InventoryControl_OtherOffer.Inventory.Items)
            {
                gainedItems.Add(new CachedItem(item));
            }

            var accepted = SellUi.TradeControl.Accept();

            if (accepted != TradeResult.None)
            {
                GlobalLog.Error($"[SellItems] Fail to accept sell. Error: \"{accepted}\".");
                return(false);
            }
            if (!await Wait.For(() => !SellUi.IsOpened, "sell panel closing"))
            {
                await Coroutines.CloseBlockingWindows();

                return(false);
            }

            // game needs some time do despawn sold items from inventory
            await Wait.SleepSafe(200);

            GlobalLog.Info($"[Events] Items sold ({soldItems.Count})");
            Utility.BroadcastMessage(null, Events.Messages.ItemsSoldEvent, soldItems, gainedItems);
            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);
        }
Esempio n. 20
0
        public async Task <bool> Run()
        {
            if (ErrorLimitReached)
            {
                return(false);
            }

            var area = World.CurrentArea;

            if (!area.IsTown && !area.IsHideoutArea)
            {
                return(false);
            }

            if (!ChaosRecipe.StashData.HasCompleteSet())
            {
                GlobalLog.Info("[SellRecipeTask] No chaos recipe set to sell.");
                return(false);
            }

            GlobalLog.Debug("[SellRecipeTask] Now going to take and sell a set of rare items for chaos recipe.");

            if (!await Inventories.OpenStashTab(Settings.Instance.StashTab))
            {
                ReportError();
                return(true);
            }

            ChaosRecipe.StashData.SyncWithStashTab();

            if (!ChaosRecipe.StashData.HasCompleteSet())
            {
                GlobalLog.Error("[SellRecipeTask] Saved stash data does not match actual stash data.");
                await Coroutines.CloseBlockingWindows();

                return(false);
            }

            var takenItemData = new RecipeData();

            int lowestItemType = RecipeItemType.None;
            var lowestItem     = Inventories.StashTabItems
                                 .OrderBy(i => i.ItemLevel)
                                 .FirstOrDefault(i => RecipeData.IsItemForChaosRecipe(i, out lowestItemType));

            if (lowestItem == null)
            {
                GlobalLog.Error("[SellRecipeTask] Unknown error. Fail to find actual item for chaos recipe.");
                ReportError();
                return(true);
            }

            GlobalLog.Debug($"[SellRecipeTask] Now taking \"{lowestItem.Name}\" (iLvl: {lowestItem.ItemLevel})");

            if (!await Inventories.FastMoveFromStashTab(lowestItem.LocationTopLeft))
            {
                ReportError();
                return(true);
            }

            takenItemData.IncreaseItemCount(lowestItemType);

            while (true)
            {
                int type = RecipeItemType.None;

                for (int i = 0; i < RecipeItemType.TotalTypeCount; i++)
                {
                    var count = takenItemData.GetItemCount(i);
                    if (count == 0 || (count == 1 && i == RecipeItemType.Ring))
                    {
                        type = i;
                        break;
                    }
                }

                if (type == RecipeItemType.None)
                {
                    break;
                }

                var item = Inventories.StashTabItems
                           .Where(i => RecipeData.IsItemForChaosRecipe(i, out var t) && t == type)
                           .OrderByDescending(i => i.ItemLevel)
                           .FirstOrDefault();

                if (item == null)
                {
                    GlobalLog.Error("[SellRecipeTask] Unknown error. Fail to find actual item for chaos recipe.");
                    ReportError();
                    return(true);
                }

                GlobalLog.Debug($"[SellRecipeTask] Now taking \"{item.Name}\" (iLvl: {item.ItemLevel})");

                if (!await Inventories.FastMoveFromStashTab(item.LocationTopLeft))
                {
                    ReportError();
                    return(true);
                }

                takenItemData.IncreaseItemCount(type);
            }

            await Wait.SleepSafe(300);

            ChaosRecipe.StashData.SyncWithStashTab();

            var recipeItems = Inventories.InventoryItems
                              .Where(i => RecipeData.IsItemForChaosRecipe(i, out var t))
                              .Select(i => i.LocationTopLeft)
                              .ToList();

            if (recipeItems.Count == 0)
            {
                GlobalLog.Error("[SellRecipeTask] Unknown error. There are no items in player's inventory after taking them from stash.");
                ReportError();
                return(true);
            }

            if (!await TownNpcs.SellItems(recipeItems))
            {
                ReportError();
            }

            return(true);
        }
Esempio n. 21
0
        public async Task <bool> Run()
        {
            var area = World.CurrentArea;

            if (!area.IsMap && !area.IsOverworldArea)
            {
                return(false);
            }

            if (CombatAreaCache.IsInIncursion)
            {
                return(false);
            }

            if (LokiPoe.InstanceInfo.Incursion.IncursionsRemaining == 0)
            {
                return(false);
            }

            var cache = CombatAreaCache.Current;

            if (cache.Storage["IsIncursionCompleted"] != null)
            {
                return(false);
            }

            var alva = cache.Storage["AlvaValai"] as CachedObject;

            if (alva == null || alva.Unwalkable || alva.Ignored)
            {
                return(false);
            }

            var pos = alva.Position;

            if (pos.IsFar || pos.IsFarByPath)
            {
                if (!pos.TryCome())
                {
                    GlobalLog.Error($"[EnterIncursionTask] Fail to move to {pos}. Alva is unwalkable.");
                    alva.Unwalkable = true;
                }
                return(true);
            }

            var alvaObj = alva.Object;

            if (alvaObj == null)
            {
                GlobalLog.Error("[EnterIncursionTask] Unexpected error. We are near cached Alva, but actual object is null.");
                alva.Ignored = true;
                return(true);
            }

            var timePortal = TimePortal;

            if (timePortal == null)
            {
                GlobalLog.Error("[EnterIncursionTask] Unexpected error. There is no Time Portal near Alva.");
                cache.Storage["IsIncursionCompleted"] = true;
                return(true);
            }

            if (timePortal.Components.TransitionableComponent.Flag2 == 3)
            {
                GlobalLog.Warn("[EnterIncursionTask] Incursion in this area has been completed.");
                cache.Storage["IsIncursionCompleted"] = true;

                if (Settings.Instance.LeaveAfterIncursion)
                {
                    FinishGridning();
                }

                return(true);
            }

            if (!timePortal.IsTargetable)
            {
                var attempts = ++alva.InteractionAttempts;
                if (attempts > 5)
                {
                    GlobalLog.Error("[EnterIncursionTask] All attempts to interact with Alva have been spent.");
                    alva.Ignored = true;
                    return(true);
                }
                if (alvaObj.HasNpcFloatingIcon)
                {
                    if (await PlayerAction.Interact(alvaObj))
                    {
                        await Wait.Sleep(200);

                        await Coroutines.CloseBlockingWindows();
                    }
                    return(true);
                }
                if (await alvaObj.AsTownNpc().Converse("Enter Incursion"))
                {
                    await Coroutines.CloseBlockingWindows();

                    await Wait.For(() => timePortal.Fresh().IsTargetable, "Time Portal activation", 200, 5000);
                }
                return(true);
            }

            if (Settings.Instance.PortalBeforeIncursion && area.IsMap && !AnyPortalsNearby)
            {
                // Have to do this because portal spawned right near Time Portal has a high chance to overlap labels
                var distantPos = WorldPosition.FindPathablePositionAtDistance(30, 35, 5);
                if (distantPos != null)
                {
                    await Move.AtOnce(distantPos, "away from Time Portal", 10);

                    await PlayerAction.CreateTownPortal();
                }
                else
                {
                    await PlayerAction.CreateTownPortal();
                }
            }

            if (ErrorManager.GetErrorCount("EnterIncursion") >= 5)
            {
                GlobalLog.Error("[EnterIncursionTask] Failed to enter Time Portal 5 times.");
                cache.Storage["IsIncursionCompleted"] = true;
                return(true);
            }
            if (await PlayerAction.TakeTransition(timePortal))
            {
                GlobalLog.Warn("[EnterIncursionTask] IsInIncursion: true");
                CombatAreaCache.IsInIncursion = true;
                SetRoomSettings();
            }
            else
            {
                ErrorManager.ReportError("EnterIncursion");
                await Wait.SleepSafe(500);
            }
            return(true);
        }
Esempio n. 22
0
        /// <summary>
        /// Implements the ability to handle a logic passed through the system.
        /// </summary>
        /// <param name="logic">The logic to be processed.</param>
        /// <returns>A LogicResult that describes the result..</returns>
        public async Task <LogicResult> Logic(Logic logic)
        {
            if (logic.Id == "hook_post_combat")
            {
                // Don't update while we are not in the game.
                if (!LokiPoe.IsInGame)
                {
                    return(LogicResult.Unprovided);
                }

                // When the game is paused, don't try to run.
                if (LokiPoe.InstanceInfo.IsGamePaused)
                {
                    return(LogicResult.Unprovided);
                }

                // Don't try to do anything when the escape state is active.
                if (LokiPoe.StateManager.IsEscapeStateActive)
                {
                    return(LogicResult.Unprovided);
                }

                // Don't level skill gems if we're dead.
                if (LokiPoe.Me.IsDead)
                {
                    return(LogicResult.Unprovided);
                }

                // Can't level skill gems under this scenario either.
                if (LokiPoe.InGameState.IsTopMostOverlayActive)
                {
                    return(LogicResult.Unprovided);
                }

                // Can't level skill gems under this scenario either.
                if (LokiPoe.InGameState.SkillsUi.IsOpened)
                {
                    return(LogicResult.Unprovided);
                }

                // Only check for skillgem leveling at a fixed interval.
                if (!_needsToUpdate && !_levelWait.IsFinished)
                {
                    return(LogicResult.Unprovided);
                }

                Func <Inventory, Item, Item, bool> eval = (inv, holder, gem) =>
                {
                    // Ignore any "globally ignored" gems. This just lets the user move gems around
                    // equipment, without having to worry about where or what it is.
                    if (ContainsHelper(gem.Name))
                    {
                        if (GemLevelerSettings.Instance.DebugStatements)
                        {
                            Log.DebugFormat("[LevelSkillGemTask] {0} => {1}.", gem.Name, "GlobalNameIgnoreList");
                        }
                        return(false);
                    }

                    // Now look though the list of skillgem strings to level, and see if the current gem matches any of them.
                    var ss = string.Format("{0} [{1}: {2}]", gem.Name, inv.PageSlot, holder.GetSocketIndexOfGem(gem));
                    foreach (var str in GemLevelerSettings.Instance.SkillGemsToLevelList)
                    {
                        if (str.Equals(ss, StringComparison.OrdinalIgnoreCase))
                        {
                            if (GemLevelerSettings.Instance.DebugStatements)
                            {
                                Log.DebugFormat("[LevelSkillGemTask] {0} => {1}.", gem.Name, str);
                            }
                            return(true);
                        }
                    }

                    // No match, we shouldn't level this gem.
                    return(false);
                };

                // If we have icons on the hud to process.
                if (LokiPoe.InGameState.SkillGemHud.AreIconsDisplayed)
                {
                    // If the InventoryUi is already opened, skip this logic and let the next set run.
                    if (!LokiPoe.InGameState.InventoryUi.IsOpened)
                    {
                        // We need to close blocking windows.
                        await Coroutines.CloseBlockingWindows();

                        // We need to let skills finish casting, because of 2.6 changes.
                        await Coroutines.FinishCurrentAction();

                        await Coroutines.LatencyWait();

                        await Coroutines.ReactionWait();

                        var res = LokiPoe.InGameState.SkillGemHud.HandlePendingLevelUps(eval);

                        Log.InfoFormat("[LevelSkillGemTask] SkillGemHud.HandlePendingLevelUps returned {0}.", res);

                        if (res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemDismissed ||
                            res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemLeveled)
                        {
                            await Coroutines.LatencyWait();

                            await Coroutines.ReactionWait();

                            return(LogicResult.Provided);
                        }
                    }
                }

                if (_needsToUpdate || LokiPoe.InGameState.InventoryUi.IsOpened)
                {
                    if (LokiPoe.InGameState.InventoryUi.IsOpened)
                    {
                        _needsToCloseInventory = false;
                    }
                    else
                    {
                        _needsToCloseInventory = true;
                    }

                    // We need the inventory panel open.
                    if (!await OpenInventoryPanel())
                    {
                        Log.ErrorFormat("[LevelSkillGemTask] OpenInventoryPanel failed.");
                        return(LogicResult.Provided);
                    }

                    // If we have icons on the inventory ui to process.
                    // This is only valid when the inventory panel is opened.
                    if (LokiPoe.InGameState.InventoryUi.AreIconsDisplayed)
                    {
                        var res = LokiPoe.InGameState.InventoryUi.HandlePendingLevelUps(eval);

                        Log.InfoFormat("[LevelSkillGemTask] InventoryUi.HandlePendingLevelUps returned {0}.", res);

                        if (res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemDismissed ||
                            res == LokiPoe.InGameState.HandlePendingLevelUpResult.GemLeveled)
                        {
                            await Coroutines.LatencyWait();

                            await Coroutines.ReactionWait();

                            return(LogicResult.Provided);
                        }
                    }
                }

                // Just wait 5-10s between checks.
                _levelWait.Reset(TimeSpan.FromMilliseconds(LokiPoe.Random.Next(5000, 10000)));

                //if (_needsToCloseInventory)
                {
                    await Coroutines.CloseBlockingWindows();

                    _needsToCloseInventory = false;
                }

                _needsToUpdate = false;
            }

            return(LogicResult.Unprovided);
        }
Esempio n. 23
0
        /// <summary>
        /// This coroutine interacts with an area transition in order to change areas. It assumes
        /// you are in interaction range with the area transition itself. It can be used both in town,
        /// and out of town, given the previous conditions are met.
        /// </summary>
        /// <param name="obj">The area transition object to take.</param>
        /// <param name="newInstance">Should a new instance be created.</param>
        /// <param name="isLocal">Is the area transition local? In other words, should the couroutine not wait for an area change.</param>
        /// <param name="maxInstances">The max number of instance entries allowed to Join a new instance or -1 to not check.</param>
        /// <returns>A TakeAreaTransitionError that describes the result.</returns>
        public static async Task <Results.TakeAreaTransitionError> TakeAreaTransition(NetworkObject obj, bool newInstance,
                                                                                      int maxInstances,
                                                                                      bool isLocal = false)
        {
            CommunityLib.Log.InfoFormat("[TakeAreaTransition] {0} {1} {2}", obj.Name, newInstance ? "(new instance)" : "",
                                        isLocal ? "(local)" : "");

            await Coroutines.CloseBlockingWindows();

            await Coroutines.FinishCurrentAction();

            var hash = LokiPoe.LocalData.AreaHash;
            var pos  = LokiPoe.MyPosition;

            if (!await InteractWith(obj, newInstance))
            {
                return(Results.TakeAreaTransitionError.InteractFailed);
            }

            if (newInstance)
            {
                if (!await WaitForInstanceManager(5000))
                {
                    LokiPoe.ProcessHookManager.ClearAllKeyStates();

                    return(Results.TakeAreaTransitionError.InstanceManagerDidNotOpen);
                }

                LokiPoe.ProcessHookManager.ClearAllKeyStates();

                await Coroutines.LatencyWait();

                await Coroutine.Sleep(1000); // Let the gui stay open a bit before clicking too fast.

                if (LokiPoe.InGameState.InstanceManagerUi.InstanceCount >= maxInstances)
                {
                    return(Results.TakeAreaTransitionError.TooManyInstances);
                }

                var nierr = LokiPoe.InGameState.InstanceManagerUi.JoinNewInstance();
                if (nierr != LokiPoe.InGameState.JoinInstanceResult.None)
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] InstanceManagerUi.JoinNew returned {0}.", nierr);
                    return(Results.TakeAreaTransitionError.JoinNewFailed);
                }

                // Wait for the action to take place first.
                await Coroutines.LatencyWait();

                await Coroutines.ReactionWait();
            }

            if (isLocal)
            {
                if (!await WaitForPositionChange(pos))
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] WaitForPositionChange failed.");
                    return(Results.TakeAreaTransitionError.WaitForAreaChangeFailed);
                }
            }
            else
            {
                if (!await Areas.WaitForAreaChange(hash))
                {
                    CommunityLib.Log.ErrorFormat("[TakeAreaTransition] WaitForAreaChange failed.");
                    return(Results.TakeAreaTransitionError.WaitForAreaChangeFailed);
                }
            }

            return(Results.TakeAreaTransitionError.None);
        }
Esempio n. 24
0
        public async Task <bool> Run()
        {
            var area = World.CurrentArea;

            if (!area.IsTown && !area.IsHideoutArea)
            {
                return(false);
            }

            var itemsToId  = new List <Vector2i>();
            var itemFilter = ItemEvaluator.Instance;

            foreach (var item in Inventories.InventoryItems)
            {
                if (item.IsIdentified || item.IsCorrupted || item.IsMirrored)
                {
                    continue;
                }

                if (!itemFilter.Match(item, EvaluationType.Id))
                {
                    continue;
                }

                itemsToId.Add(item.LocationTopLeft);
            }

            if (itemsToId.Count == 0)
            {
                GlobalLog.Info("[IdTask] No items to identify.");
                return(false);
            }

            GlobalLog.Info($"[IdTask] {itemsToId.Count} items to id.");

            int scrollsAmount = LokiPoe.InstanceInfo.GetPlayerInventoryBySlot(InventorySlot.Main).ItemAmount(CurrencyNames.Wisdom);

            if (scrollsAmount == 0 && Inventories.AvailableInventorySquares == 0)
            {
                GlobalLog.Error("[IdTask] No id scrolls and no free space in inventory. Now stopping the bot because it cannot continue.");
                BotManager.Stop();
                return(true);
            }

            GlobalLog.Info($"[IdTask] {scrollsAmount} id scrolls.");

            if (scrollsAmount < itemsToId.Count)
            {
                GlobalLog.Warn("[IdTask] Not enough id scrolls to identify all items. Now going to take them from stash.");

                var result = await Inventories.WithdrawCurrency(CurrencyNames.Wisdom);

                if (result == WithdrawResult.Error)
                {
                    ErrorManager.ReportError();
                    return(true);
                }
                if (result == WithdrawResult.Unavailable)
                {
                    GlobalLog.Error("[IdTask] There are no id scrolls in all tabs assigned to them. Now stopping the bot because it cannot continue.");
                    BotManager.Stop();
                    return(true);
                }
            }

            if (!await Inventories.OpenInventory())
            {
                ErrorManager.ReportError();
                return(true);
            }

            itemsToId.Sort(Position.Comparer.Instance);

            foreach (var pos in itemsToId)
            {
                if (!await Identify(pos))
                {
                    ErrorManager.ReportError();
                    return(true);
                }
            }
            await Coroutines.CloseBlockingWindows();

            return(true);
        }
        public async Task <bool> Run()
        {
            if (ErrorLimitReached)
            {
                return(false);
            }

            var area = World.CurrentArea;

            if (!area.IsTown && !area.IsHideoutArea)
            {
                return(false);
            }

            var errors = GetUserErrors();

            if (errors.Count > 0)
            {
                foreach (var error in errors)
                {
                    GlobalLog.Error(error);
                }
                BotManager.Stop();
                return(true);
            }

            var currencyToRestock = new List <string>();

            foreach (var currency in Settings.Instance.InventoryCurrencies)
            {
                var name    = currency.Name;
                var restock = currency.Restock;

                if (restock < 0)
                {
                    continue;
                }

                GetCurrentAndMaxStackCount(name, out var count, out var maxStackCount);

                if (restock >= maxStackCount)
                {
                    GlobalLog.Error($"[InventoryCurrency] Invalid restock value for \"{name}\". Restock: {restock}. Max stack count: {maxStackCount}.");
                    GlobalLog.Error("[InventoryCurrency] Restock value must be less than item's max stack count. Please correct your settings.");
                    BotManager.Stop();
                    return(true);
                }

                if (count > restock)
                {
                    continue;
                }

                if (Unavailable.Contains(name))
                {
                    GlobalLog.Debug($"[CurrencyRestockTask] Skipping \"{name}\" restock because it is marked as unavailable.");
                    continue;
                }

                GlobalLog.Debug($"[CurrencyRestockTask] Restock is needed for \"{name}\". Current count: {count}. Count to restock: {restock}.");
                currencyToRestock.Add(name);
            }

            if (currencyToRestock.Count == 0)
            {
                GlobalLog.Info("[CurrencyRestockTask] No currency to restock.");
                return(false);
            }

            foreach (var currency in currencyToRestock)
            {
                GlobalLog.Debug($"[CurrencyRestockTask] Now going to restock \"{currency}\".");

                var result = await Inventories.WithdrawCurrency(currency);

                if (result == WithdrawResult.Error)
                {
                    ReportError();
                    return(true);
                }
                if (result == WithdrawResult.Unavailable)
                {
                    GlobalLog.Warn($"[CurrencyRestockTask] There are no \"{currency}\" in all tabs assigned to them. Now marking this currency as unavailable.");
                    Unavailable.Add(currency);
                }
            }
            await Coroutines.CloseBlockingWindows();

            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 (_skip)
            {
                return(false);
            }

            // Don't level passives if we're dead.
            if (LokiPoe.Me.IsDead)
            {
                return(false);
            }

            // Don't try to level passives if we only want to allocate in town, and are not currently in town.
            if (AutoPassivesSettings.Instance.OnlyAllocateInTown && !(LokiPoe.Me.IsInTown || LokiPoe.Me.IsInHideout))
            {
                return(false);
            }

            // Try to not allocate if there's a monster somewhat close, will avoid lots of issues.
            // More lightweight check to just get an idea of what is around us, rather than the heavy IsActive.
            if (
                LokiPoe.ObjectManager.GetObjectsByType <Monster>()
                .Any(m => m.IsAliveHostile && m.Distance < 100))
            {
                return(false);
            }

            // Only check for passive leveling at a fixed interval.
            if (!_levelWait.IsFinished)
            {
                return(false);
            }

            if (LokiPoe.InstanceInfo.PassiveSkillPointsAvailable == 0)
            {
                _levelWait.Reset(TimeSpan.FromMilliseconds(LokiPoe.Random.Next(5000, 10000)));

                // Close the window to prevent other issues.
                if (LokiPoe.InGameState.SkillsUi.IsOpened)
                {
                    Log.DebugFormat("[AssignPassivesTask] The SkillsPanel is open. Now closing it to avoid issues.");
                    await Coroutines.CloseBlockingWindows();

                    return(true);
                }

                return(false);
            }

            var pendingPassives =
                AutoPassivesSettings.Instance.Passives.Where(p => !LokiPoe.InstanceInfo.PassiveSkillIds.Contains(p.Id)).ToList();

            if (!pendingPassives.Any())
            {
                _levelWait.Reset(TimeSpan.FromMilliseconds(LokiPoe.Random.Next(5000, 10000)));

                // Close the window to prevent other issues.
                if (LokiPoe.InGameState.SkillsUi.IsOpened)
                {
                    Log.DebugFormat("[AssignPassivesTask] The SkillsPanel is open. Now closing it to avoid issues.");
                    await Coroutines.CloseBlockingWindows();

                    return(true);
                }

                return(false);
            }

            if (!await OpenSkillsUi())
            {
                Log.ErrorFormat("[AssignPassivesTask] OpenSkillsUi failed.");
                await Coroutines.CloseBlockingWindows();

                return(true);
            }

            // Handle the passive tree reset by closing the dialog.
            if (LokiPoe.InGameState.GlobalWarningDialog.IsPassiveTreeWarningOverlayOpen)
            {
                Log.DebugFormat("[AssignPassivesTask] IsPassiveTreeWarningOverlayOpen. Now attempting to close it.");
                LokiPoe.Input.SimulateKeyEvent(Keys.Escape, true, false, false);
                await Coroutine.Sleep(250);

                return(true);
            }

            // Make sure we don't screw up the user's character ;)
            if (LokiPoe.InGameState.SkillsUi.IsResetAllPassivesEnabled && LokiPoe.InGameState.SkillsUi.IsResetAllPassivesVisible)
            {
                Log.ErrorFormat(
                    "[AssignPassivesTask] The \"Reset All Passives\" button is available. Please reset your passive tree, or manually allocate a point first.");
                _skip = true;
                LokiPoe.Input.SimulateKeyEvent(Keys.Escape, true, false, false);
                await Coroutine.Sleep(250);

                return(true);
            }

            var passive = pendingPassives.First();

            var error = true;

            var ret = LokiPoe.InGameState.SkillsUi.ChoosePassive(passive.Id);

            if (ret == LokiPoe.InGameState.ChoosePassiveError.None)
            {
                var ret2 = LokiPoe.InGameState.SkillsUi.ConfirmOperation();
                if (ret2 == LokiPoe.InGameState.PassiveAllocationActionError.None)
                {
                    Log.InfoFormat("[AssignPassivesTask] The passive {0} was assigned.", passive.Id);
                    error = false;
                }
                else
                {
                    Log.ErrorFormat("[AssignPassivesTask] ConfirmOperation returned {0} for {1}.", ret2, passive.Id);
                }
            }
            else
            {
                Log.ErrorFormat("[AssignPassivesTask] ChoosePassive returned {0} for {1}.", ret, passive.Id);
            }

            // If there was an error, stop trying to allocate passives until user intervention.
            if (error)
            {
                _skip = true;
                return(true);
            }

            // If we have no more points, then reset the delay, otherwise, try to keep allocating the next time it executes.
            if (LokiPoe.InstanceInfo.PassiveSkillPointsAvailable == 0)
            {
                _levelWait.Reset(TimeSpan.FromMilliseconds(LokiPoe.Random.Next(5000, 10000)));
                await Coroutines.CloseBlockingWindows();
            }

            await Coroutine.Sleep(LokiPoe.Random.Next(750, 1250));

            return(true);
        }
Esempio n. 27
0
        /// <summary>
        /// Goes to the specified area using waypoint.
        /// </summary>
        /// <param name="name">Name of the area eg "Highgate"</param>
        /// <param name="difficulty"></param>
        /// <param name="newInstance">Do you want to open new instance?</param>
        /// <returns></returns>
        public static async Task <LokiPoe.InGameState.TakeWaypointResult> TakeWaypoint(string name, Difficulty difficulty = Difficulty.Unknown, bool newInstance = false)
        {
            //We are already there
            if (LokiPoe.LocalData.WorldArea.Name == name && LokiPoe.LocalData.WorldArea.Difficulty == difficulty && !newInstance)
            {
                return(LokiPoe.InGameState.TakeWaypointResult.None);
            }

            //await Coroutines.CloseBlockingWindows();

            // First try of fastgotohideout instead of LokiPoe.InGameState.WorldUi.GoToHideout()
            if (name.Equals("Hideout", StringComparison.OrdinalIgnoreCase) && (LokiPoe.Me.IsInHideout || LokiPoe.Me.IsInTown))
            {
                await Coroutines.CloseBlockingWindows();

                var res = await FastGoToHideout();

                switch (res)
                {
                case Results.FastGoToHideoutResult.None:
                    return(LokiPoe.InGameState.TakeWaypointResult.None);

                case Results.FastGoToHideoutResult.NoHideout:
                    return(LokiPoe.InGameState.TakeWaypointResult.AreaNotFound);

                case Results.FastGoToHideoutResult.NotInGame:
                    return(LokiPoe.InGameState.TakeWaypointResult.UiNotOpen);
                    //if we timed out then try to use default method like below
                }
            }

            if (!LokiPoe.InGameState.WorldUi.IsOpened)
            {
                var opened = await LibCoroutines.OpenWaypoint();

                if (opened != Results.OpenWaypointError.None)
                {
                    CommunityLib.Log.ErrorFormat("[TakeWaypoint] Fail to open waypoint. Error: \"{0}\".", opened);
                    return(LokiPoe.InGameState.TakeWaypointResult.WaypointControlNotVisible);
                }
            }
            if (difficulty == Difficulty.Unknown)
            {
                difficulty = LokiPoe.CurrentWorldArea.Difficulty;
            }

            //var areaId = name == "Hideout" ? "" : GetZoneId(difficulty.ToString(), name);
            CommunityLib.Log.InfoFormat($"[TakeWaypoint] Going to {name} at {difficulty}.");

            var areaHash = LokiPoe.LocalData.AreaHash;
            var taken    = name.Equals("Hideout", StringComparison.OrdinalIgnoreCase)
                ? LokiPoe.InGameState.WorldUi.GoToHideout()
                : LokiPoe.InGameState.WorldUi.TakeWaypoint(LokiPoe.GetZoneId(difficulty.ToString(), name), newInstance, Int32.MaxValue);

            if (taken != LokiPoe.InGameState.TakeWaypointResult.None)
            {
                CommunityLib.Log.ErrorFormat("[TakeWaypoint] Failed to take waypoint to \"{0}\". Error: \"{1}\".", name, taken);
                return(taken);
            }

            var awaited = await Areas.WaitForAreaChange(areaHash);

            return(awaited ? LokiPoe.InGameState.TakeWaypointResult.None : LokiPoe.InGameState.TakeWaypointResult.CouldNotJoinNewInstance);
        }
Esempio n. 28
0
        public static async Task <Portal> CreateTownPortal()
        {
            var portalSkill = LokiPoe.InGameState.SkillBarHud.Skills.FirstOrDefault(s => s.Name == "Portal" && s.IsOnSkillBar);

            if (portalSkill != null)
            {
                await Coroutines.FinishCurrentAction();

                await Wait.SleepSafe(100);

                var err = LokiPoe.InGameState.SkillBarHud.Use(portalSkill.Slot, false);
                if (err != LokiPoe.InGameState.UseResult.None)
                {
                    GlobalLog.Error($"[CreateTownPortal] Fail to cast portal skill. Error: \"{err}\".");
                    return(null);
                }
                await Coroutines.FinishCurrentAction();

                await Wait.SleepSafe(100);
            }
            else
            {
                var portalScroll = Inventories.InventoryItems
                                   .Where(i => i.Name == CurrencyNames.Portal)
                                   .OrderBy(i => i.StackCount)
                                   .FirstOrDefault();

                if (portalScroll == null)
                {
                    GlobalLog.Error("[CreateTownPortal] Out of portal scrolls.");
                    return(null);
                }

                int itemId = portalScroll.LocalId;

                if (!await Inventories.OpenInventory())
                {
                    return(null);
                }

                await Coroutines.FinishCurrentAction();

                await Wait.SleepSafe(100);

                var err = LokiPoe.InGameState.InventoryUi.InventoryControl_Main.UseItem(itemId);
                if (err != UseItemResult.None)
                {
                    GlobalLog.Error($"[CreateTownPortal] Fail to use a Portal Scroll. Error: \"{err}\".");
                    return(null);
                }

                if (Settings.Instance.ArtificialDelays)
                {
                    await Wait.ArtificialDelay();
                }

                await Coroutines.CloseBlockingWindows();
            }
            Portal portal = null;
            await Wait.For(() => (portal = PortalInRangeOf(40)) != null, "portal spawning");

            return(portal);
        }
Esempio n. 29
0
        public async Task <bool> Run()
        {
            var area = World.CurrentArea;

            if (!area.IsTown && !area.IsHideoutArea)
            {
                return(false);
            }

            var itemsToStash      = new List <StashItem>();
            var inventoryCurrency = Settings.Instance.InventoryCurrencies;

            foreach (var item in Inventories.InventoryItems)
            {
                var c = item.Class;

                if (c == ItemClasses.QuestItem || c == ItemClasses.PantheonSoul)
                {
                    continue;
                }

                if (c == ItemClasses.StackableCurrency && inventoryCurrency.Any(i => i.Name == item.Name))
                {
                    continue;
                }

                itemsToStash.Add(new StashItem(item));
            }

            foreach (var currency in inventoryCurrency)
            {
                foreach (var excess in Inventories.GetExcessCurrency(currency.Name))
                {
                    itemsToStash.Add(new StashItem(excess));
                }
            }

            if (itemsToStash.Count == 0)
            {
                GlobalLog.Info("[StashTask] No items to stash.");
                return(false);
            }

            if (_checkInvalidTabs)
            {
                if (!await Inventories.OpenStash())
                {
                    ErrorManager.ReportError();
                    return(true);
                }
                var wrongTabs = GetNonexistentTabs();
                if (wrongTabs.Count > 0)
                {
                    GlobalLog.Error("[StashTask] The following tabs are specified in stashing rules but do not exist in stash:");
                    GlobalLog.Error($"{string.Join(", ", wrongTabs)}");
                    GlobalLog.Error("[StashTask] Please provide correct tab names.");
                    BotManager.Stop();
                    return(true);
                }
                GlobalLog.Debug("[StashTask] All tabs specified in stashing rules exist in stash.");
                _checkInvalidTabs = false;
            }

            if (_checkFullTabs)
            {
                if (Settings.Instance.FullTabs.Count > 0)
                {
                    if (!await FullTabCheck())
                    {
                        ErrorManager.ReportError();
                        return(true);
                    }
                }
                _checkFullTabs = false;
            }

            GlobalLog.Info($"[StashTask] {itemsToStash.Count} items to stash.");

            AssignStashTabs(itemsToStash);

            foreach (var item in itemsToStash.OrderBy(i => i.StashTab).ThenBy(i => i.Position, Position.Comparer.Instance))
            {
                var itemName = item.Name;
                var itemPos  = item.Position;
                var tabName  = item.StashTab;

                GlobalLog.Debug($"[StashTask] Now going to stash \"{itemName}\" to \"{tabName}\" tab.");

                if (!await Inventories.OpenStashTab(tabName))
                {
                    ErrorManager.ReportError();
                    return(true);
                }
                if (StashUi.StashTabInfo.IsPremiumMap)
                {
                    GlobalLog.Error("Map stash tab is unsupported and there are no plans to support it in the future. Please remove it from stashing settings.");
                    BotManager.Stop();
                    return(true);
                }
                if (!Inventories.StashTabCanFitItem(itemPos))
                {
                    if (StashUi.StashTabInfo.IsPremiumSpecial)
                    {
                        var metadata = item.Metadata;
                        GlobalLog.Warn($"[StashTask] Cannot fit \"{itemName}\" to \"{tabName}\" tab.");
                        GlobalLog.Warn($"[StashTask] Now marking inventory control for \"{metadata}\" as full.");
                        Settings.Instance.MarkTabAsFull(tabName, metadata);
                    }
                    else
                    {
                        GlobalLog.Warn($"[StashTask] Cannot fit \"{itemName}\" to \"{tabName}\" tab. Now marking this tab as full.");
                        Settings.Instance.MarkTabAsFull(tabName, null);
                    }
                    return(true);
                }
                if (!await Inventories.FastMoveFromInventory(itemPos))
                {
                    ErrorManager.ReportError();
                    return(true);
                }
                GlobalLog.Info($"[Events] Item stashed ({item.FullName})");
                Utility.BroadcastMessage(this, Events.Messages.ItemStashedEvent, item);
            }
            await Coroutines.CloseBlockingWindows();

            return(true);
        }
Esempio n. 30
0
        /// <summary>
        /// This coroutine creates a portal to town from a Portal Scroll in the inventory.
        /// </summary>
        /// <returns>true if the Portal Scroll was used and false otherwise.</returns>
        public static async Task <bool> CreatePortalToTown()
        {
            if (LokiPoe.Me.IsInTown)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town portals are not allowed in town.");
                return(false);
            }

            if (LokiPoe.Me.IsInHideout)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town portals are not allowed in hideouts.");
                return(false);
            }

            if (LokiPoe.CurrentWorldArea.IsMissionArea || LokiPoe.CurrentWorldArea.IsDenArea ||
                LokiPoe.CurrentWorldArea.IsRelicArea || LokiPoe.CurrentWorldArea.IsDailyArea)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] Town Portals are not allowed in mission areas.");
                return(false);
            }

            await Coroutines.FinishCurrentAction();

            await Coroutines.CloseBlockingWindows();

            var portalSkill = LokiPoe.InGameState.SkillBarHud.Skills.FirstOrDefault(s => s.Name == "Portal");

            if (portalSkill != null && portalSkill.CanUse(true))
            {
                CommunityLib.Log.DebugFormat("[CreatePortalToTown] We have a Portal skill on the skill bar. Now using it.");

                var err = LokiPoe.InGameState.SkillBarHud.Use(portalSkill.Slot, false);
                CommunityLib.Log.InfoFormat($"[CreatePortalToTown] SkillBarHud.Use returned {err}.");

                await Coroutines.LatencyWait();

                await Coroutines.FinishCurrentAction();

                if (err == LokiPoe.InGameState.UseResult.None)
                {
                    var sw = Stopwatch.StartNew();
                    while (sw.ElapsedMilliseconds < 3000)
                    {
                        var portal = LokiPoe.ObjectManager.Objects.OfType <Portal>().FirstOrDefault(p => p.Distance < 50);
                        if (portal != null)
                        {
                            return(true);
                        }

                        CommunityLib.Log.DebugFormat("[CreatePortalToTown] No portal was detected yet, waiting...");
                        await Coroutines.LatencyWait();
                    }
                }
            }

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now opening the inventory panel.");

            // We need the inventory panel open.
            if (!await OpenInventoryPanel())
            {
                return(false);
            }

            await Coroutines.ReactionWait();

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now searching the main inventory for a Portal Scroll.");

            var item = LokiPoe.InstanceInfo.GetPlayerInventoryItemsBySlot(InventorySlot.Main).FirstOrDefault(i => i.Name == "Portal Scroll");

            if (item == null)
            {
                CommunityLib.Log.ErrorFormat("[CreatePortalToTown] There are no Portal Scrolls in the inventory.");
                return(false);
            }

            CommunityLib.Log.DebugFormat("[CreatePortalToTown] Now using the Portal Scroll.");

            var err2 = LokiPoe.InGameState.InventoryUi.InventoryControl_Main.UseItem(item.LocalId);

            if (err2 != UseItemResult.None)
            {
                CommunityLib.Log.ErrorFormat($"[CreatePortalToTown] UseItem returned {err2}.");
                return(false);
            }

            await Coroutines.LatencyWait();

            await Coroutines.ReactionWait();

            await Coroutines.CloseBlockingWindows();

            return(true);
        }