Exemplo n.º 1
0
        public static async Task <CoroutineResult> EnsureInRift()
        {
            if (!ZetaDia.IsInTown)
            {
                return(CoroutineResult.NoAction);
            }

            if (!IsRiftPortalOpen)
            {
                return(CoroutineResult.NoAction);
            }

            var rp = RiftPortal;

            if (rp != null)
            {
                return(await CommonCoroutines.MoveAndInteract(
                           rp,
                           () => ZetaDia.IsInGame &&
                           !ZetaDia.Globals.IsLoadingWorld &&
                           !ZetaDia.Globals.IsPlayingCutscene &&
                           !ZetaDia.IsInTown));
            }

            // TODO: Make sure we move somewhere we expect the portal to show up.
            await CommonCoroutines.MoveTo(ZetaDia.Actors.GetActorsOfType <DiaGizmo>()
                                          .Where(g => g.Distance > 10f)
                                          .OrderBy(g => g.Distance)
                                          .FirstOrDefault());

            return(CoroutineResult.Running);
        }
Exemplo n.º 2
0
 public static async Task <bool> EnsureKadalaWindow()
 {
     if (await CommonCoroutines.MoveAndInteract(
             TownInfo.Kadala.GetActor(),
             () => UIElements.VendorWindow.IsVisible) == CoroutineResult.Running)
     {
         return(false);
     }
     return(UIElements.VendorWindow.IsVisible);
 }
Exemplo n.º 3
0
        public static async Task <bool> ClearRift()
        {
            if (AdvDia.RiftQuest.Step >= RiftStep.UrshiSpawned)
            {
                return(true);
            }

            if (await EnsureInRift() == CoroutineResult.Running)
            {
                return(false);
            }

            // TODO: Handle Cow level
            if (ExitPortal == null)
            {
                await ExplorationCoroutine.Explore(new HashSet <SNOLevelArea> {
                    AdvDia.CurrentLevelAreaId
                });

                return(false);
            }

            var tmpWorld     = ZetaDia.Globals.WorldSnoId;
            var tmpLevelArea = ZetaDia.CurrentLevelAreaSnoId;


            // There is a rare but possible condition when the character enters the ExitPortal
            // but IsLoadingWorld and IsPlayingCutscene does not return 'true'.
            //
            // In this case the bot runs in an infinite loop of cycling between two portals.
            // The reason is because it was checked for CoroutineResult.Done before and since the implementation
            // of CommonCoroutines.MoveAndInteract only returns Done when the condition is met it was always 'Running' returned.
            //
            // Changing the MoveAndInteract breaks navigation due to the wait timout. Adding the change of the
            // level and world area ids in the condition leads to returning NoAction in second iteration.
            //
            // Due to these reasons we simply ignore the Coroutine.Result in that specific case and everything
            // is fixed and working.
            //
            // Don't change that. You have been warned. It works like it is now.
            await CommonCoroutines.MoveAndInteract(
                ExitPortal,
                () => ZetaDia.Globals.IsLoadingWorld ||
                ZetaDia.Globals.IsPlayingCutscene);

            if (tmpLevelArea != ZetaDia.CurrentLevelAreaSnoId ||
                tmpWorld != ZetaDia.Globals.WorldSnoId)
            {
                PreviousWorld = tmpWorld;
                PreviousLevel = tmpLevelArea;
            }

            return(false);
        }
Exemplo n.º 4
0
        public static async Task <CoroutineResult> RepairItems()
        {
            if (!ZetaDia.IsInTown)
            {
                return(CoroutineResult.NoAction);
            }

            if (!EquipmentNeedsRepair())
            {
                return(CoroutineResult.NoAction);
            }

            var coinage         = ZetaDia.Storage.PlayerDataManager.ActivePlayerData.Coinage;
            var shouldRepairAll = coinage > InventoryManager.GetRepairCost(true);

            if (!shouldRepairAll)
            {
                if (coinage < InventoryManager.GetRepairCost(false))
                {
                    s_logger.Error($"[{nameof(RepairItems)}] Can't afford to repair");
                    return(CoroutineResult.Failed);
                }
            }

            if (!(GameUI.IsBlackSmithWindowOpen || UIElements.VendorWindow.IsVisible))
            {
                var smith       = TownInfo.Blacksmith;
                var merchant    = TownInfo.NearestMerchant;
                var repairActor = (Randomizer.Boolean ? merchant : smith) ?? (smith ?? merchant);

                if (repairActor == null)
                {
                    s_logger.Error($"[{nameof(RepairItems)}] Failed to find somewhere to repair :(");
                    return(CoroutineResult.Failed);
                }
                ;

                if (await CommonCoroutines.MoveAndInteract(
                        repairActor.GetActor(),
                        () => GameUI.IsBlackSmithWindowOpen ||
                        UIElements.VendorWindow.IsVisible) == CoroutineResult.Running)
                {
                    return(CoroutineResult.Running);
                }
            }

            await Coroutine.Yield();

            s_logger.Information($"[{nameof(RepairItems)}] Repairing equipment while at this vendor");
            Repair(shouldRepairAll);
            return(CoroutineResult.Done);
        }
Exemplo n.º 5
0
        public async Task <bool> HandleTarget(TrinityActor target)
        {
            if (await TrinityCombat.Routines.Current.HandleAvoiding())
            {
                return(true);
            }

            if (await TrinityCombat.Routines.Current.HandleKiting())
            {
                return(true);
            }

            if (target == null ||
                !target.IsValid)
            {
                Clear();
                return(false);
            }

            if (TryBlacklist(target))
            {
                Clear();
                return(false);
            }

            // Gizmos should always use the MoveAndInteract coroutine.
            // Don't try to outsmart the game with custom shit down the line.
            if (target.IsGizmo &&
                target.ToDiaObject() is DiaGizmo obj &&
                !obj.IsDestructibleObject)
            {
                // TODO: Fix the interaction condition here.
                if (await CommonCoroutines.MoveAndInteract(
                        obj,
                        () => obj is GizmoLootContainer lc ? lc.IsOpen : obj.HasBeenOperated) == CoroutineResult.Running)
                {
                    return(true);
                }

                Clear();
                return(false);
            }

            SetCurrentTarget(target);

            var power = TrinityCombat.Routines.Current.GetPowerForTarget(target);

            SetCurrentPower(power);

            return(await TrinityCombat.Routines.Current.HandleTarget(target));
        }
Exemplo n.º 6
0
        public static async Task <CoroutineResult> SellItems()
        {
            if (!ZetaDia.IsInTown)
            {
                return(CoroutineResult.NoAction);
            }

            var sellItem = InventoryManager.Backpack
                           .FirstOrDefault(i => ShouldSell(i) &&
                                           InventoryManager.CanSellItem(i));

            if (sellItem == null)
            {
                if (await RepairItems() == CoroutineResult.Running)
                {
                    return(CoroutineResult.Running);
                }

                GameUI.CloseVendorWindow();
                return(CoroutineResult.Done);
            }

            if (!UIElements.VendorWindow.IsVisible)
            {
                var merchant = TownInfo.NearestMerchant;
                if (merchant == null)
                {
                    s_logger.Error($"[{nameof(SellItems)}] Unable to find merchant info for this area :(");
                    return(CoroutineResult.Failed);
                }

                if (await CommonCoroutines.MoveAndInteract(
                        merchant.GetActor(),
                        () => UIElements.VendorWindow.IsVisible) == CoroutineResult.Running)
                {
                    return(CoroutineResult.Running);
                }
            }

            if (!sellItem.IsValid || sellItem.IsUnidentified)
            {
                s_logger.Debug($"[{nameof(SellItems)}] Invalid Items Detected: IsValid={sellItem.IsValid} IsUnidentified={sellItem.IsUnidentified}");
                return(CoroutineResult.Failed);
            }

            s_logger.Debug($"[{nameof(SellItems)}] Selling: {sellItem.Name} ({sellItem.ActorSnoId}) Quality={sellItem.ItemQualityLevel} IsAncient={sellItem.Stats.IsAncient} Name={sellItem.InternalName}");
            ItemEvents.FireItemSold(sellItem);
            InventoryManager.SellItem(sellItem);
            Core.Inventory.InvalidAnnIds.Add(sellItem.AnnId);
            return(CoroutineResult.Running);
        }
        public static async Task <bool> PutExtractionCandidatesBackToStash()
        {
            if (!ZetaDia.IsInGame ||
                !ZetaDia.IsInTown)
            {
                return(true);
            }

            if (!s_extractionCandidatesTakenFromStash.Any())
            {
                return(true);
            }

            if (await CommonCoroutines.MoveAndInteract(
                    TownInfo.Stash?.GetActor(),
                    () => UIElements.StashWindow.IsVisible) == CoroutineResult.Running)
            {
                return(false);
            }

            // Find the first item from the list.
            var item = InventoryManager.Backpack.FirstOrDefault(i => s_extractionCandidatesTakenFromStash.Contains(i.AnnId));

            // When the backpack does no longer contain a item from the list we are done...
            if (item == null)
            {
                s_extractionCandidatesTakenFromStash.Clear();
                return(true);
            }

            // Make sure the item is valid.
            if (!item.IsValid || item.IsDisposed)
            {
                return(false);
            }

            // TODO: Is that try/catch really required?
            try
            {
                s_logger.Debug($"[{nameof(PutExtractionCandidatesBackToStash)}] Adding {item.Name} ({item.ActorSnoId}) to stash. StackSize={item.ItemStackQuantity} AnnId={item.AnnId} InternalName={item.InternalName} Id={item.ActorSnoId} Quality={item.ItemQualityLevel} AncientRank={item.AncientRank}");
                InventoryManager.QuickStash(item);
            }
            catch (Exception ex)
            {
                s_logger.Error($"[{nameof(PutExtractionCandidatesBackToStash)}] Failed to handle one item. See Exception.", ex);
            }

            // When we reach that point we have to run again...
            return(false);
        }
Exemplo n.º 8
0
        /* Should be able to wait for finishing this task While doing something.
         * Otherwise we see the bot locks in dilemma between going to Quest/Rift
         * or Vacuuming nearby items -Seq */
        public static async Task <bool> Execute()
        {
            if (!ZetaDia.IsInGame ||
                ZetaDia.Globals.IsLoadingWorld ||
                ZetaDia.Globals.IsPlayingCutscene ||
                ZetaDia.IsInTown)
            {
                return(true);
            }

            // A check for is casting.
            if (ZetaDia.Me.LoopingAnimationEndTime > 0)
            {
                return(true);
            }

            // Items that shouldn't be picked up are currently excluded from cache.
            // a pickup evaluation should be added here if that changes.
            var currentPickup = Core.Targets.OfType <TrinityItem>().FirstOrDefault(i => i.Distance < 8f && i.ActorSnoId != 0);

            // When no item is inside the vacuum range of 8 just continue.
            if (currentPickup == null)
            {
                return(true);
            }

            // Collect information about the item to pickup.
            var logLine =
                $"[{nameof(VacuumItems)}] {currentPickup.Name} ({currentPickup.ActorSnoId}) InternalName: {currentPickup.InternalName} GbId: {currentPickup.GameBalanceId}";

            var tmp = currentPickup.ToAcdItem().AsRActor;

            // Use the coroutine to pick up the item.
            if (await CommonCoroutines.MoveAndInteract(
                    tmp,
                    () => currentPickup.ActorSnoId == 0) == CoroutineResult.Running)
            {
                return(false);
            }

            // The item was picked up trigger RecordSpell and log the info collected above.
            SpellHistory.RecordSpell(SNOPower.Axe_Operate_Gizmo);
            s_logger.Information(logLine);

            // We are not done yet so return false.
            return(false);
        }
Exemplo n.º 9
0
        // TODO: Add a way to open the cow portal.
        public static async Task <bool> ClearCowLevel()
        {
            if (ZetaDia.IsInTown)
            {
                return(true);
            }

            if (!RiftData.PossibleHolyCowLevelID.Contains(AdvDia.CurrentLevelAreaId))
            {
                return(true);
            }

            if (HolyCow != null)
            {
                Debugger.Break();
            }

            return(await CommonCoroutines.MoveAndInteract(
                       HolyCow,
                       () => false) == CoroutineResult.Running);
        }
Exemplo n.º 10
0
        public static async Task <CoroutineResult> TurnInQuest()
        {
            if (AdvDia.RiftQuest.Step != RiftStep.Cleared)
            {
                return(CoroutineResult.NoAction);
            }

            if (await EnsureIsInTown() == CoroutineResult.Running)
            {
                return(CoroutineResult.Running);
            }

            if (Orek == null)
            {
                await CommonCoroutines.MoveTo(ZetaDia.Actors.GetActorsOfType <DiaGizmo>()
                                              .Where(g => g.Distance > 10f)
                                              .OrderByDescending(g => g.Distance)
                                              .FirstOrDefault());

                return(CoroutineResult.Running);
            }

            if (!(Orek.IsValid &&
                  await CommonCoroutines.MoveAndInteract(
                      Orek,
                      () => !Orek.IsQuestGiver) != CoroutineResult.Running))
            {
                return(CoroutineResult.Running);
            }

            if (s_experienceTracker.IsStarted)
            {
                s_experienceTracker.StopAndReport(nameof(RiftCoroutine));
            }

            return(CoroutineResult.Done);
        }
Exemplo n.º 11
0
        public static async Task <bool> ClearRift()
        {
            if (AdvDia.RiftQuest.Step >= RiftStep.UrshiSpawned)
            {
                return(true);
            }

            if (await EnsureInRift() == CoroutineResult.Running)
            {
                return(false);
            }

            // TODO: Handle Cow level
            if (ExitPortal == null)
            {
                await ExplorationCoroutine.Explore(new HashSet <SNOLevelArea> {
                    AdvDia.CurrentLevelAreaId
                });

                return(false);
            }

            var tmpWorld     = ZetaDia.Globals.WorldSnoId;
            var tmpLevelArea = ZetaDia.CurrentLevelAreaSnoId;

            if (await CommonCoroutines.MoveAndInteract(
                    ExitPortal,
                    () => ZetaDia.Globals.IsLoadingWorld ||
                    ZetaDia.Globals.IsPlayingCutscene) ==
                CoroutineResult.Done)
            {
                PreviousWorld = tmpWorld;
                PreviousLevel = tmpLevelArea;
            }

            return(false);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Moves to something and interacts with it
        /// </summary>
        /// <param name="obj">object to interact with</param>
        /// <param name="interactLimit">maximum number of times to interact</param>
        public static async Task <bool> Execute(DiaObject obj, int interactLimit = 5)
        {
            if (obj == null)
            {
                return(false);
            }

            if (!obj.IsFullyValid())
            {
                return(false);
            }

            if (interactLimit < 1)
            {
                interactLimit = 5;
            }

            if (Core.Player.IsInTown)
            {
                GameUI.CloseVendorWindow();
            }

            return(await CommonCoroutines.MoveAndInteract(obj, () => IsInteracting || interactLimit-- < 0) == CoroutineResult.Running);
        }
Exemplo n.º 13
0
        public static async Task <CoroutineResult> StashItems()
        {
            if (!ZetaDia.IsInTown)
            {
                return(CoroutineResult.NoAction);
            }

            var item = InventoryManager.Backpack.FirstOrDefault(ShouldStash);

            if (item == null)
            {
                return(CoroutineResult.Done);
            }

            if (!UIElements.StashWindow.IsVisible)
            {
                var stash = ZetaDia.Actors.GetActorsOfType <GizmoPlayerSharedStash>().FirstOrDefault();
                if (stash == null)
                {
                    return(CoroutineResult.Failed);
                }

                if (await CommonCoroutines.MoveAndInteract(
                        stash,
                        () => UIElements.StashWindow.IsVisible) == CoroutineResult.Running)
                {
                    return(CoroutineResult.Running);
                }
            }

            if (Core.Settings.Items.BuyStashTabs &&
                StashPagesAvailableToPurchase)
            {
                s_logger.Error($"[{nameof(StashItems)}] Attempting to buy stash pages");
                InventoryManager.BuySharedStashSlots();
            }

            // TODO: Figure out if those 2 calls are still relevant.
            await StackRamaladnisGift();
            await StackCraftingMaterials();

            try
            {
                var page = GetBestStashLocation(item, out var col, out var row);
                if (page == -1)
                {
                    s_logger.Error($"[{nameof(StashItems)}] No place to put item, stash is probably full ({item.Name} [{col},{row}] Page={page})");
                    HandleFullStash();
                    return(CoroutineResult.Failed);
                }

                if (page != InventoryManager.CurrentStashPage)
                {
                    s_logger.Debug($"[{nameof(StashItems)}] Changing to stash page: {page}");
                    InventoryManager.SwitchStashPage(page);
                    Core.StuckHandler.Reset("Still stashing...");
                    return(CoroutineResult.Running);
                }

                s_logger.Information($"[{nameof(StashItems)}] Stashing: {item.Name} ({item.ActorSnoId}) [{item.InventoryColumn},{item.InventoryRow} {item.InventorySlot}] Quality={item.ItemQualityLevel} IsAncient={item.Stats.IsAncient} InternalName={item.InternalName} StashPage={page}");

                ItemEvents.FireItemStashed(item);
                InventoryManager.MoveItem(
                    item.AnnId,
                    Core.Player.MyDynamicID,
                    InventorySlot.SharedStash,
                    col,
                    row);
            }
            catch (Exception ex)
            {
                s_logger.Error($"[{nameof(StashItems)}] Exception Stashing Item", ex);
            }

            Core.StuckHandler.Reset("Still stashing...");
            return(CoroutineResult.Running);
        }
Exemplo n.º 14
0
        public static async Task <bool> OpenRift(RiftType riftType,
                                                 int maxLevel,
                                                 int maxEmpowerLevel,
                                                 bool shouldEmpower,
                                                 bool runNormalUntilXP)
        {
            if (IsRiftPortalOpen)
            {
                return(IsRiftPortalOpen);
            }

            var riftKeys = CurrentRiftKeyCount;

            if (riftType == RiftType.Greater &&
                riftKeys <= PluginSettings.Current.MinimumKeys &&
                !PluginSettings.Current.GreaterRiftRunNephalem)
            {
                s_logger.Error($"[{nameof(OpenRift)}] You have no Greater Rift Keys. Stopping the bot.");
                BotMain.Stop();
                return(false);
            }

            s_logger.Debug($"[{nameof(OpenRift)}] I have {riftKeys} rift keys.");

            if (await EnsureIsInTown() == CoroutineResult.Running)
            {
                return(false);
            }

            if (riftKeys <= PluginSettings.Current.MinimumKeys)
            {
                riftType = RiftType.Nephalem;
            }

            // TODO: Figure out why there is that check against that magic.
            var maximizeXp = runNormalUntilXP &&
                             riftType == RiftType.Greater &&
                             ZetaDia.Me.RestExperience <5000000000 &&
                                                        ZetaDia.Me.RestExperience> -1;

            if (maximizeXp)
            {
                riftType = RiftType.Nephalem;
            }

            var level       = Math.Min(riftType == RiftType.Greater ? RiftData.GetGreaterRiftLevel() : -1, maxLevel);
            var isEmpowered = riftType == RiftType.Greater &&
                              shouldEmpower &&
                              level <= maxEmpowerLevel &&
                              RiftData.EmpoweredRiftCost.TryGetValue(level, out var empoweredCost) &&
                              ZetaDia.Storage.PlayerDataManager.ActivePlayerData.Coinage >=
                              (empoweredCost + PluginSettings.Current.MinimumGold);

            DiaGizmo lrs = LootRunSwitch;

            if (lrs == null)
            {
                await CommonCoroutines.MoveTo(ZetaDia.Actors.GetActorsOfType <DiaGizmo>()
                                              .Where(g => g.Distance > 10f)
                                              .OrderByDescending(g => g.Distance)
                                              .FirstOrDefault());

                return(false);
            }

            if (!s_experienceTracker.IsStarted)
            {
                s_experienceTracker.Start();
            }

            if (await CommonCoroutines.MoveAndInteract(
                    lrs,
                    () => UIElements.RiftDialog.IsVisible) == CoroutineResult.Running)
            {
                return(false);
            }

            ZetaDia.Me.OpenRift(level, isEmpowered);
            return(await Coroutine.Wait(TimeSpan.FromSeconds(2), () => IsRiftPortalOpen));
        }