Exemple #1
0
        public static void ResetEverythingNewGame()
        {
            hashUseOnceID                          = new HashSet <int>();
            dictUseOnceID                          = new Dictionary <int, int>();
            iMaxDeathsAllowed                      = 0;
            iDeathsThisRun                         = 0;
            _hashsetItemStatsLookedAt              = new HashSet <string>();
            _hashsetItemPicksLookedAt              = new HashSet <string>();
            _hashsetItemFollowersIgnored           = new HashSet <string>();
            TownRun._dictItemStashAttempted        = new Dictionary <int, int>();
            hashRGUIDBlacklist60                   = new HashSet <int>();
            hashRGUIDBlacklist90                   = new HashSet <int>();
            hashRGUIDBlacklist15                   = new HashSet <int>();
            vBacktrackList                         = new SortedList <int, Vector3>();
            iTotalBacktracks                       = 0;
            HasMappedPlayerAbilities               = false;
            PlayerMover.iTotalAntiStuckAttempts    = 1;
            PlayerMover.vSafeMovementLocation      = Vector3.Zero;
            PlayerMover.vOldPosition               = Vector3.Zero;
            PlayerMover.iTimesReachedStuckPoint    = 0;
            PlayerMover.TimeLastRecordedPosition   = DateTime.Today;
            PlayerMover.LastGeneratedStuckPosition = DateTime.Today;
            PlayerMover.iTimesReachedMaxUnstucks   = 0;
            PlayerMover.iCancelUnstuckerForSeconds = 0;
            PlayerMover._lastCancelledUnstucker    = DateTime.Today;
            NavHelper.UsedStuckSpots               = new List <GridPoint>();

            // Reset all the caches
            dictGilesObjectTypeCache     = new Dictionary <int, GObjectType>();
            dictGilesMonsterAffixCache   = new Dictionary <int, MonsterAffixes>();
            dictGilesMaxHealthCache      = new Dictionary <int, double>();
            dictGilesLastHealthCache     = new Dictionary <int, double>();
            dictGilesLastHealthChecked   = new Dictionary <int, int>();
            dictGilesBurrowedCache       = new Dictionary <int, bool>();
            dictGilesActorSNOCache       = new Dictionary <int, int>();
            dictGilesACDGUIDCache        = new Dictionary <int, int>();
            dictGilesInternalNameCache   = new Dictionary <int, string>();
            dictGilesGameBalanceIDCache  = new Dictionary <int, int>();
            dictGilesDynamicIDCache      = new Dictionary <int, int>();
            dictGilesVectorCache         = new Dictionary <int, Vector3>();
            dictGilesGoldAmountCache     = new Dictionary <int, int>();
            dictGilesQualityCache        = new Dictionary <int, ItemQuality>();
            dictGilesPickupItem          = new Dictionary <int, bool>();
            dictSummonedByID             = new Dictionary <int, int>();
            dictTotalInteractionAttempts = new Dictionary <int, int>();
            listProfilesLoaded           = new List <string>();
            CurrentProfile = "";
            FirstProfile   = "";


            NavHelper.UpdateSearchGridProvider();
            GoldInactivity.ResetCheckGold();

            global::GilesTrinity.XmlTags.TrinityLoadOnce.UsedProfiles = new List <string>();

            GenericCache.ClearCache();
            GenericBlacklist.ClearBlacklist();
        }
Exemple #2
0
        /// <summary>
        /// Finds an optimal position for using Monk Tempest Rush out of combat
        /// </summary>
        /// <returns></returns>
        internal static Vector3 FindTempestRushTarget()
        {
            Vector3 target = PlayerMover.LastMoveToTarget;
            Vector3 myPos  = ZetaDia.Me.Position;

            if (GilesTrinity.CurrentTarget != null && NavHelper.CanRayCast(myPos, target))
            {
                target = GilesTrinity.CurrentTarget.Position;
            }

            float distance = target.Distance2D(myPos);

            if (distance < 30f)
            {
                double direction = MathUtil.FindDirectionRadian(myPos, target);
                target = MathEx.GetPointAt(myPos, 40f, (float)direction);
            }

            return(target);
        }
Exemple #3
0
        /// <summary>
        /// Called when user Enable the plugin.
        /// </summary>
        public void OnEnabled()
        {
            BotMain.OnStart += TrinityBotStart;
            BotMain.OnStop  += TrinityBotStop;

            // Set up the pause button

            // rrrix: removing for next DB beta...
            //Application.Current.Dispatcher.Invoke(PaintMainWindowButtons());

            SetWindowTitle();

            if (!Directory.Exists(FileManager.PluginPath))
            {
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Fatal Error - cannot enable plugin. Invalid path: {0}", FileManager.PluginPath);
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Please check you have installed the plugin to the correct location, and then restart DemonBuddy and re-enable the plugin.");
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, @"Plugin should be installed to \<DemonBuddyFolder>\Plugins\Trinity\");
            }
            else
            {
                HasMappedPlayerAbilities = false;
                IsPluginEnabled          = true;

                // Settings are available after this...
                LoadConfiguration();

                Navigator.PlayerMover = new PlayerMover();
                SetUnstuckProvider();
                GameEvents.OnPlayerDied += TrinityOnDeath;
                GameEvents.OnGameJoined += TrinityOnJoinGame;
                GameEvents.OnGameLeft   += TrinityOnLeaveGame;

                GameEvents.OnItemSold     += TrinityOnItemSold;
                GameEvents.OnItemSalvaged += TrinityOnItemSalvaged;
                GameEvents.OnItemStashed  += TrinityOnItemStashed;

                GameEvents.OnGameChanged += GameEvents_OnGameChanged;

                if (NavProvider == null)
                {
                    NavProvider = new DefaultNavigationProvider();
                }

                // enable or disable process exit events
                //ZetaDia.Memory.Process.EnableRaisingEvents = false;



                CombatTargeting.Instance.Provider   = new BlankCombatProvider();
                LootTargeting.Instance.Provider     = new BlankLootProvider();
                ObstacleTargeting.Instance.Provider = new BlankObstacleProvider();

                if (Settings.Loot.ItemFilterMode != global::GilesTrinity.Settings.Loot.ItemFilterMode.DemonBuddy)
                {
                    ItemManager.Current = new TrinityItemManager();
                }
                NavHelper.UpdateSearchGridProvider();

                // Safety check incase DB "OnStart" event didn't fire properly
                if (BotMain.IsRunning)
                {
                    TrinityBotStart(null);
                    if (ZetaDia.IsInGame)
                    {
                        TrinityOnJoinGame(null, null);
                    }
                }

                SetBotTPS();

                TrinityPowerManager.LoadLegacyDelays();

                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "*******************TRINITY*****************", Description);;
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "ATIVADO: {0} carregado - mod by WAR!", Description);;
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "*******************TRINITY*****************", Description);;
            }

            if (StashRule != null)
            {
                // reseting stash rules
                StashRule.reset();
            }
        }
Exemple #4
0
        private static void RefreshSetKiting(ref Vector3 vKitePointAvoid, bool NeedToKite, ref bool TryToKite)
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.Kiting"))
            {
                TryToKite = false;

                var monsterList = from m in GilesObjectCache
                                  where m.Type == GObjectType.Unit &&
                                  m.Weight > 0 &&
                                  m.RadiusDistance <= PlayerKiteDistance &&
                                  (m.IsBossOrEliteRareUnique ||
                                   ((m.HitPointsPct >= .15 || m.MonsterStyle != MonsterSize.Swarm) && !m.IsBossOrEliteRareUnique)
                                  )
                                  select m;

                if (CurrentTarget != null && CurrentTarget.Type == GObjectType.Unit && PlayerKiteDistance > 0 && CurrentTarget.RadiusDistance <= PlayerKiteDistance)
                {
                    TryToKite       = true;
                    vKitePointAvoid = PlayerStatus.CurrentPosition;
                }

                if (monsterList.Count() > 0 && (PlayerStatus.ActorClass != ActorClass.Wizard || IsWizardShouldKite()))
                {
                    TryToKite       = true;
                    vKitePointAvoid = PlayerStatus.CurrentPosition;
                }

                // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                bool shouldKamikazeTreasureGoblins = (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize);

                double msCancelledEmergency = DateTime.Now.Subtract(timeCancelledEmergencyMove).TotalMilliseconds;
                bool   shouldEmergencyMove  = msCancelledEmergency >= cancelledEmergencyMoveForMilliseconds && NeedToKite;

                double msCancelledKite = DateTime.Now.Subtract(timeCancelledKiteMove).TotalMilliseconds;
                bool   shouldKite      = msCancelledKite >= cancelledKiteMoveForMilliseconds && TryToKite;

                if (shouldKamikazeTreasureGoblins && (shouldEmergencyMove || shouldKite))
                {
                    Vector3 vAnySafePoint = NavHelper.FindSafeZone(false, 1, vKitePointAvoid, true, monsterList);

                    if (LastKitePosition == null)
                    {
                        LastKitePosition = new KitePosition()
                        {
                            PositionFoundTime = DateTime.Now,
                            Position          = vAnySafePoint,
                            Distance          = vAnySafePoint.Distance(PlayerStatus.CurrentPosition)
                        };
                    }

                    if (vAnySafePoint != Vector3.Zero && vAnySafePoint.Distance(PlayerStatus.CurrentPosition) >= 1)
                    {
                        if ((DateTime.Now.Subtract(LastKitePosition.PositionFoundTime).TotalMilliseconds > 3000 && LastKitePosition.Position == vAnySafePoint) ||
                            (CurrentTarget != null && DateTime.Now.Subtract(lastGlobalCooldownUse).TotalMilliseconds > 1500 && TryToKite))
                        {
                            timeCancelledKiteMove            = DateTime.Now;
                            cancelledKiteMoveForMilliseconds = 1500;
                            DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kite movement failed, cancelling for {0:0}ms", cancelledKiteMoveForMilliseconds);
                            return;
                        }
                        else
                        {
                            LastKitePosition = new KitePosition()
                            {
                                PositionFoundTime = DateTime.Now,
                                Position          = vAnySafePoint,
                                Distance          = vAnySafePoint.Distance(PlayerStatus.CurrentPosition)
                            };
                        }

                        if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                        {
                            DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting to: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}, Nearby Monsters: {5:0} NeedToKite: {6} TryToKite: {7}",
                                         vAnySafePoint, vAnySafePoint.Distance(PlayerStatus.CurrentPosition), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, vAnySafePoint)),
                                         PlayerStatus.CurrentHealthPct, PlayerKiteDistance, monsterList.Count(),
                                         NeedToKite, TryToKite);
                        }
                        CurrentTarget = new GilesObject()
                        {
                            Position       = vAnySafePoint,
                            Type           = GObjectType.Avoidance,
                            Weight         = 90000,
                            CentreDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vAnySafePoint),
                            RadiusDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vAnySafePoint),
                            InternalName   = "KitePoint"
                        };

                        //timeCancelledKiteMove = DateTime.Now;
                        //cancelledKiteMoveForMilliseconds = 100;

                        // Try forcing a target update with each kiting
                        //bForceTargetUpdate = true;
                    }
                    //else
                    //{
                    //    // Didn't find any kiting we could reach, so don't look for any more kite spots for at least 1.5 seconds
                    //    timeCancelledKiteMove = DateTime.Now;
                    //    cancelledKiteMoveForMilliseconds = 500;
                    //}
                }
                else if (!shouldEmergencyMove && NeedToKite)
                {
                    DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Emergency movement cancelled for {0:0}ms", DateTime.Now.Subtract(timeCancelledEmergencyMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
                else if (!shouldKite && TryToKite)
                {
                    DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kite movement cancelled for {0:0}ms", DateTime.Now.Subtract(timeCancelledKiteMove).TotalMilliseconds - cancelledKiteMoveForMilliseconds);
                }
            }
        }
Exemple #5
0
 private static void RefreshDoBackTrack()
 {
     // See if we should wait for [playersetting] milliseconds for possible loot drops before continuing run
     if (DateTime.Now.Subtract(lastHadUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill || DateTime.Now.Subtract(lastHadEliteUnitInSights).TotalMilliseconds <= Settings.Combat.Misc.DelayAfterKill)
     {
         CurrentTarget = new GilesObject()
         {
             Position       = PlayerStatus.CurrentPosition,
             Type           = GObjectType.Avoidance,
             Weight         = 20000,
             CentreDistance = 2f,
             RadiusDistance = 2f,
             InternalName   = "GilesWaitForLootDrops"
         };
         DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Behavior, "Waiting for loot to drop, delay: {0}ms", Settings.Combat.Misc.DelayAfterKill);
     }
     // Now see if we need to do any backtracking
     if (CurrentTarget == null && iTotalBacktracks >= 2 && Settings.Combat.Misc.AllowBacktracking && !PlayerStatus.IsInTown)
     // Never bother with the 1st backtrack position nor if we are in town
     {
         // See if we're already within 18 feet of our start position first
         if (Vector3.Distance(PlayerStatus.CurrentPosition, vBacktrackList[1]) <= 18f)
         {
             vBacktrackList   = new SortedList <int, Vector3>();
             iTotalBacktracks = 0;
         }
         // See if we can raytrace to the final location and it's within 25 feet
         if (iTotalBacktracks >= 2 && Vector3.Distance(PlayerStatus.CurrentPosition, vBacktrackList[1]) <= 25f &&
             NavHelper.CanRayCast(PlayerStatus.CurrentPosition, vBacktrackList[1]))
         {
             vBacktrackList   = new SortedList <int, Vector3>();
             iTotalBacktracks = 0;
         }
         if (iTotalBacktracks >= 2)
         {
             // See if we can skip to the next backtracker location first
             if (iTotalBacktracks >= 3)
             {
                 if (Vector3.Distance(PlayerStatus.CurrentPosition, vBacktrackList[iTotalBacktracks - 1]) <= 10f)
                 {
                     vBacktrackList.Remove(iTotalBacktracks);
                     iTotalBacktracks--;
                 }
             }
             CurrentTarget = new GilesObject()
             {
                 Position       = vBacktrackList[iTotalBacktracks],
                 Type           = GObjectType.Backtrack,
                 Weight         = 20000,
                 CentreDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vBacktrackList[iTotalBacktracks]),
                 RadiusDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vBacktrackList[iTotalBacktracks]),
                 InternalName   = "GilesBacktrack"
             };
         }
     }
     else
     {
         vBacktrackList   = new SortedList <int, Vector3>();
         iTotalBacktracks = 0;
     }
     // End of backtracking check
     //TODO : If this code is obselete remove it (Check that)
     // Finally, a special check for waiting for wrath of the berserker cooldown before engaging Azmodan
     if (CurrentTarget == null && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && Settings.Combat.Barbarian.WaitWOTB && !GilesUseTimer(SNOPower.Barbarian_WrathOfTheBerserker) &&
         ZetaDia.CurrentWorldId == 121214 &&
         (Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
     {
         bDontSpamOutofCombat = true;
         Logging.Write("[Trinity] Waiting for Wrath Of The Berserker cooldown before continuing to Azmodan.");
         CurrentTarget = new GilesObject()
         {
             Position       = PlayerStatus.CurrentPosition,
             Type           = GObjectType.Avoidance,
             Weight         = 20000,
             CentreDistance = 2f,
             RadiusDistance = 2f,
             InternalName   = "GilesWaitForWrath"
         };
     }
     // And a special check for wizard archon
     if (CurrentTarget == null && Hotbar.Contains(SNOPower.Wizard_Archon) && !GilesUseTimer(SNOPower.Wizard_Archon) && Settings.Combat.Wizard.WaitArchon && ZetaDia.CurrentWorldId == 121214 &&
         (Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
     {
         DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Waiting for Wizard Archon cooldown before continuing to Azmodan.");
         CurrentTarget = new GilesObject()
         {
             Position       = PlayerStatus.CurrentPosition,
             Type           = GObjectType.Avoidance,
             Weight         = 20000,
             CentreDistance = 2f,
             RadiusDistance = 2f,
             InternalName   = "GilesWaitForArchon"
         };
     }
     // And a very sexy special check for WD BigBadVoodoo
     if (CurrentTarget == null && Hotbar.Contains(SNOPower.Witchdoctor_BigBadVoodoo) && !PowerManager.CanCast(SNOPower.Witchdoctor_BigBadVoodoo) && ZetaDia.CurrentWorldId == 121214 &&
         (Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(711.25f, 716.25f, 80.13903f)) <= 40f || Vector3.Distance(PlayerStatus.CurrentPosition, new Vector3(546.8467f, 551.7733f, 1.576313f)) <= 40f))
     {
         DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Waiting for WD BigBadVoodoo cooldown before continuing to Azmodan.");
         CurrentTarget = new GilesObject()
         {
             Position       = PlayerStatus.CurrentPosition,
             Type           = GObjectType.Avoidance,
             Weight         = 20000,
             CentreDistance = 2f,
             RadiusDistance = 2f,
             InternalName   = "GilesWaitForVoodooo"
         };
     }
 }
Exemple #6
0
        /// <summary>
        /// This method will add and update necessary information about all available actors. Determines GilesObjectType, sets ranges, updates blacklists, determines avoidance, kiting, target weighting
        /// and the result is we will have a new target for the Target Handler. Returns true if the cache was refreshed.
        /// </summary>
        /// <returns>True if the cache was updated</returns>
        public static bool RefreshDiaObjectCache(bool forceUpdate = false)
        {
            using (new PerformanceLogger("RefreshDiaObjectCache"))
            {
                if (DateTime.Now.Subtract(LastRefreshedCache).TotalMilliseconds < Settings.Advanced.CacheRefreshRate && !forceUpdate)
                {
                    if (!UpdateCurrentTarget())
                    {
                        return(false);
                    }
                }
                LastRefreshedCache = DateTime.Now;

                using (new PerformanceLogger("RefreshDiaObjectCache.UpdateBlock"))
                {
                    GenericCache.MaintainCache();
                    GenericBlacklist.MaintainBlacklist();

                    using (ZetaDia.Memory.AcquireFrame())
                    {
                        // Update player-data cache, including buffs
                        GilesPlayerCache.UpdateCachedPlayerData();

                        if (PlayerStatus.CurrentHealthPct <= 0)
                        {
                            return(false);
                        }

                        if (Settings.Combat.Misc.UseNavMeshTargeting && !gp.CanStandAt(gp.WorldToGrid(PlayerStatus.CurrentPosition.ToVector2())))
                        {
                            NavHelper.UpdateSearchGridProvider();
                        }


                        RefreshCacheInit();

                        // Now pull up all the data and store anything we want to handle in the super special cache list
                        // Also use many cache dictionaries to minimize DB<->D3 memory hits, and speed everything up a lot
                        RefreshCacheMainLoop();
                    }
                }

                // Reduce ignore-for-loops counter
                if (IgnoreTargetForLoops > 0)
                {
                    IgnoreTargetForLoops--;
                }
                // If we have an avoidance under our feet, then create a new object which contains a safety point to move to
                // But only if we aren't force-cancelling avoidance for XX time
                bool bFoundSafeSpot = false;

                using (new PerformanceLogger("RefreshDiaObjectCache.AvoidanceCheck"))
                {
                    // Note that if treasure goblin level is set to kamikaze, even avoidance moves are disabled to reach the goblin!
                    if (StandingInAvoidance && (!AnyTreasureGoblinsPresent || Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize) &&
                        DateTime.Now.Subtract(timeCancelledEmergencyMove).TotalMilliseconds >= cancelledEmergencyMoveForMilliseconds)
                    {
                        Vector3 vAnySafePoint = NavHelper.FindSafeZone(false, 1, PlayerStatus.CurrentPosition, true);
                        // Ignore avoidance stuff if we're incapacitated or didn't find a safe spot we could reach
                        if (vAnySafePoint != vNullLocation)
                        {
                            if (Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement))
                            {
                                DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting Avoidance: {0} Distance: {1:0} Direction: {2:0}, Health%={3:0.00}, KiteDistance: {4:0}",
                                             vAnySafePoint, vAnySafePoint.Distance(Me.Position), MathUtil.GetHeading(MathUtil.FindDirectionDegree(Me.Position, vAnySafePoint)),
                                             PlayerStatus.CurrentHealthPct, PlayerKiteDistance);
                            }

                            bFoundSafeSpot = true;
                            CurrentTarget  = new GilesObject()
                            {
                                Position       = vAnySafePoint,
                                Type           = GObjectType.Avoidance,
                                Weight         = 20000,
                                CentreDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vAnySafePoint),
                                RadiusDistance = Vector3.Distance(PlayerStatus.CurrentPosition, vAnySafePoint),
                                InternalName   = "GilesSafePoint"
                            };;
                        }
                        //else
                        //{
                        //    // Didn't find any safe spot we could reach, so don't look for any more safe spots for at least 2.8 seconds
                        //    cancelledEmergencyMoveForMilliseconds = 2800;
                        //    timeCancelledEmergencyMove = DateTime.Now;
                        //    DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Unable to find kite location, canceling emergency movement for {0}ms", cancelledEmergencyMoveForMilliseconds);
                        //}
                    }
                }

                /*
                 * Give weights to objects
                 */
                // Special flag for special whirlwind circumstances
                bAnyNonWWIgnoreMobsInRange = false;
                // Now give each object a weight *IF* we aren't skipping direcly to a safe-spot
                if (!bFoundSafeSpot)
                {
                    RefreshDiaGetWeights();
                    RefreshSetKiting(ref vKitePointAvoid, NeedToKite, ref TryToKite);
                }
                // Not heading straight for a safe-spot?
                // No valid targets but we were told to stay put?
                if (CurrentTarget == null && ShouldStayPutDuringAvoidance && !StandingInAvoidance)
                {
                    CurrentTarget = new GilesObject()
                    {
                        Position       = PlayerStatus.CurrentPosition,
                        Type           = GObjectType.Avoidance,
                        Weight         = 20000,
                        CentreDistance = 2f,
                        RadiusDistance = 2f,
                        InternalName   = "GilesStayPutPoint"
                    };
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Staying Put During Avoidance");
                }
                using (new PerformanceLogger("RefreshDiaObjectCache.FinalChecks"))
                {
                    // force to stay put if we want to town run and there's no target
                    if (CurrentTarget == null && ForceVendorRunASAP)
                    {
                        bDontMoveMeIAmDoingShit = true;
                    }

                    // Still no target, let's see if we should backtrack or wait for wrath to come off cooldown...
                    if (CurrentTarget == null)
                    {
                        RefreshDoBackTrack();
                    }
                    // Still no target, let's end it all!
                    if (CurrentTarget == null)
                    {
                        return(true);
                    }
                    // Ok record the time we last saw any unit at all
                    if (CurrentTarget.Type == GObjectType.Unit)
                    {
                        lastHadUnitInSights = DateTime.Now;
                        // And record when we last saw any form of elite
                        if (CurrentTarget.IsBoss || CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin)
                        {
                            lastHadEliteUnitInSights = DateTime.Now;
                        }
                    }
                    // Record the last time our target changed
                    if (CurrentTargetRactorGUID != CurrentTarget.RActorGuid)
                    {
                        RecordTargetHistory();
                        DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Weight, "Found New Target - {0} CurrentTargetRactorGUID: {1} CurrentTarget.RActorGuid: {2}",
                                     DateTime.Now, CurrentTargetRactorGUID, CurrentTarget.RActorGuid);
                        dateSincePickedTarget = DateTime.Now;
                        iTargetLastHealth     = 0f;
                    }
                    else
                    {
                        // We're sticking to the same target, so update the target's health cache to check for stucks
                        if (CurrentTarget.Type == GObjectType.Unit)
                        {
                            // Check if the health has changed, if so update the target-pick time before we blacklist them again
                            if (CurrentTarget.HitPointsPct != iTargetLastHealth)
                            {
                                DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Weight, "Keeping Target {0} - CurrentTarget.iHitPoints: {1:0.00}  iTargetLastHealth: {2:0.00} ",
                                             CurrentTarget.RActorGuid, CurrentTarget.HitPointsPct, iTargetLastHealth);
                                dateSincePickedTarget = DateTime.Now;
                            }
                            // Now store the target's last-known health
                            iTargetLastHealth = CurrentTarget.HitPointsPct;
                        }
                    }
                }
                // We have a target and the cached was refreshed
                return(true);
            }
        }
Exemple #7
0
        // Special Zig-Zag movement for whirlwind/tempest
        /// <summary>
        /// Finds an optimal position for Barbarian Whirlwind, Monk Tempest Rush, or Demon Hunter Strafe
        /// </summary>
        /// <param name="origin"></param>
        /// <param name="ringDistance"></param>
        /// <param name="randomizeDistance"></param>
        /// <returns></returns>
        internal static Vector3 GetZigZagTarget(Vector3 origin, float ringDistance, bool randomizeDistance = false)
        {
            var     minDistance      = 9f;
            Vector3 myPos            = PlayerStatus.CurrentPosition;
            float   distanceToTarget = origin.Distance2D(myPos);

            Vector3 zigZagPoint = origin;

            using (new PerformanceLogger("FindZigZagTargetLocation"))
            {
                using (new PerformanceLogger("FindZigZagTargetLocation.CheckObjectCache"))
                {
                    bool  useTargetBasedZigZag = false;
                    float maxDistance          = 25f;
                    int   minTargets           = 2;

                    if (GilesTrinity.PlayerStatus.ActorClass == ActorClass.Monk)
                    {
                        maxDistance          = 20f;
                        minTargets           = 3;
                        useTargetBasedZigZag = (GilesTrinity.Settings.Combat.Monk.TargetBasedZigZag);
                    }
                    if (GilesTrinity.PlayerStatus.ActorClass == ActorClass.Barbarian)
                    {
                        useTargetBasedZigZag = (GilesTrinity.Settings.Combat.Barbarian.TargetBasedZigZag);
                    }

                    int  eliteCount         = ObjectCache.Count(u => u.Type == GObjectType.Unit && u.IsBossOrEliteRareUnique);
                    bool shouldZigZagElites = ((GilesTrinity.CurrentTarget.IsBossOrEliteRareUnique && eliteCount > 1) || eliteCount == 0);

                    if (useTargetBasedZigZag && shouldZigZagElites && !AnyTreasureGoblinsPresent && ObjectCache.Where(o => o.Type == GObjectType.Unit).Count() >= minTargets)
                    {
                        var clusterPoint = TargetUtil.GetBestClusterPoint(ringDistance, ringDistance, false);
                        if (clusterPoint.Distance2D(PlayerStatus.CurrentPosition) >= minDistance)
                        {
                            DbHelper.Log(LogCategory.Movement, "Returning ZigZag: BestClusterPoint {0} r-dist={1} t-dist={2}", clusterPoint, ringDistance, clusterPoint.Distance2D(PlayerStatus.CurrentPosition));
                            return(clusterPoint);
                        }
                        IEnumerable <GilesObject> zigZagTargets =
                            from u in ObjectCache
                            where u.Type == GObjectType.Unit && u.RadiusDistance < maxDistance &&
                            !GilesTrinity.hashAvoidanceObstacleCache.Any(a => Vector3.Distance(u.Position, a.Location) < AvoidanceManager.GetAvoidanceRadiusBySNO(a.ActorSNO, a.Radius) && PlayerStatus.CurrentHealthPct <= AvoidanceManager.GetAvoidanceHealthBySNO(a.ActorSNO, 1))
                            select u;
                        if (zigZagTargets.Count() >= minTargets)
                        {
                            zigZagPoint = zigZagTargets.OrderByDescending(u => u.CentreDistance).FirstOrDefault().Position;
                            if (NavHelper.CanRayCast(zigZagPoint) && zigZagPoint.Distance2D(PlayerStatus.CurrentPosition) >= minDistance)
                            {
                                DbHelper.Log(LogCategory.Movement, "Returning ZigZag: TargetBased {0} r-dist={1} t-dist={2}", zigZagPoint, ringDistance, zigZagPoint.Distance2D(PlayerStatus.CurrentPosition));
                                return(zigZagPoint);
                            }
                        }
                    }
                }

                Random rndNum = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), NumberStyles.HexNumber));

                using (new PerformanceLogger("FindZigZagTargetLocation.RandomZigZagPoint"))
                {
                    float   highestWeightFound = float.NegativeInfinity;
                    Vector3 bestLocation       = Vector3.Zero;

                    // the unit circle always starts at 0 :)
                    double min = 0;
                    // the maximum size of a unit circle
                    double max = 2 * Math.PI;
                    // the number of times we will iterate around the circle to find points
                    double piSlices = 16;

                    // We will do several "passes" to make sure we can get a point that we can least zig-zag to
                    // The total number of points tested will be piSlices * distancePasses.Count
                    List <float> distancePasses = new List <float>();
                    distancePasses.Add(ringDistance * 1 / 2); // Do one loop at 1/2 distance
                    distancePasses.Add(ringDistance * 3 / 4); // Do one loop at 3/4 distance
                    distancePasses.Add(ringDistance);         // Do one loop at exact distance

                    foreach (float distance in distancePasses)
                    {
                        for (double direction = min; direction < max; direction += (Math.PI / piSlices))
                        {
                            // Starting weight is 1
                            float pointWeight = 1f;

                            // Find a new XY
                            zigZagPoint = MathEx.GetPointAt(origin, distance, (float)direction);
                            // Get the Z
                            zigZagPoint.Z = GilesTrinity.gp.GetHeight(zigZagPoint.ToVector2());

                            // Make sure we're actually zig-zagging our target, except if we're kiting
                            bool intersectsPath = MathUtil.IntersectsPath(CurrentTarget.Position, CurrentTarget.Radius, myPos, zigZagPoint);
                            if (GilesTrinity.PlayerKiteDistance <= 0 && !intersectsPath)
                            {
                                continue;
                            }

                            // if we're kiting, lets not actualy run through monsters
                            if (GilesTrinity.PlayerKiteDistance > 0 && GilesTrinity.hashMonsterObstacleCache.Any(m => m.Location.Distance(zigZagPoint) <= GilesTrinity.PlayerKiteDistance))
                            {
                                continue;
                            }

                            // Ignore point if any AoE in this point position
                            if (GilesTrinity.hashAvoidanceObstacleCache.Any(m => m.Location.Distance(zigZagPoint) <= m.Radius && PlayerStatus.CurrentHealthPct <= AvoidanceManager.GetAvoidanceHealthBySNO(m.ActorSNO, 1)))
                            {
                                continue;
                            }

                            // Make sure this point is in LoS/walkable (not around corners or into a wall)
                            bool canRayCast = !Navigator.Raycast(PlayerStatus.CurrentPosition, zigZagPoint);
                            if (!canRayCast)
                            {
                                continue;
                            }

                            float distanceToPoint           = zigZagPoint.Distance2D(myPos);
                            float distanceFromTargetToPoint = zigZagPoint.Distance2D(origin);

                            // Lots of weight for points further away from us (e.g. behind our CurrentTarget)
                            pointWeight *= distanceToPoint;

                            // Add weight for any units in this point
                            int monsterCount = ObjectCache.Count(u => u.Type == GObjectType.Unit && u.Position.Distance2D(zigZagPoint) <= Math.Max(u.Radius, 10f));
                            if (monsterCount > 0)
                            {
                                pointWeight *= monsterCount;
                            }

                            DbHelper.Log(LogCategory.Movement, "ZigZag Point: {0} distance={1:0} distaceFromTarget={2:0} intersectsPath={3} weight={4:0} monsterCount={5}",
                                         zigZagPoint, distanceToPoint, distanceFromTargetToPoint, intersectsPath, pointWeight, monsterCount);

                            // Use this one if it's more weight, or we haven't even found one yet, or if same weight as another with a random chance
                            if (pointWeight > highestWeightFound)
                            {
                                highestWeightFound = pointWeight;

                                if (GilesTrinity.Settings.Combat.Misc.UseNavMeshTargeting)
                                {
                                    bestLocation = new Vector3(zigZagPoint.X, zigZagPoint.Y, GilesTrinity.gp.GetHeight(zigZagPoint.ToVector2()));
                                }
                                else
                                {
                                    bestLocation = new Vector3(zigZagPoint.X, zigZagPoint.Y, zigZagPoint.Z + 4);
                                }
                            }
                        }
                    }
                    DbHelper.Log(LogCategory.Movement, "Returning ZigZag: RandomXY {0} r-dist={1} t-dist={2}", bestLocation, ringDistance, bestLocation.Distance2D(PlayerStatus.CurrentPosition));
                    return(bestLocation);
                }
            }
        }
Exemple #8
0
        internal static Vector3 newFindSafeZone(Vector3 origin, bool shouldKite = false, bool isStuck = false, IEnumerable <GilesObject> monsterList = null)
        {
            /*
             * generate 50x50 grid of 5x5 squares within max 100 distance from origin to edge of grid
             *
             * all squares start with 0 weight
             *
             * check if Center IsNavigable
             * check Z
             * check if avoidance is present
             * check if monsters are present
             *
             * final distance tile weight = (Max Dist - Dist)/Max Dist*Max Weight
             *
             * end result should be that only navigable squares where no avoidance, monsters, or obstacles are present
             */

            float gridSquareSize = 5f;
            int   maxDistance    = 200;
            int   maxWeight      = 100;
            int   maxZDiff       = 14;

            int gridTotalSize = (int)(maxDistance / gridSquareSize) * 2;

            /* If maxDistance is the radius of a circle from the origin, then we want to get the hypotenuse of the radius (x) and tangent (y) as our search grid corner
             * anything outside of the circle will not be considered
             */
            Vector2 topleft = new Vector2(origin.X - maxDistance, origin.Y - maxDistance);


            //Make a circle on the corners of the square
            double gridSquareRadius = Math.Sqrt((Math.Pow(gridSquareSize / 2, 2) + Math.Pow(gridSquareSize / 2, 2)));

            GridPoint bestPoint = new GridPoint(Vector3.Zero, 0, 0);

            int nodesNotNavigable = 0;
            int nodesZDiff        = 0;
            int nodesGT45Raycast  = 0;
            int nodesAvoidance    = 0;
            int nodesMonsters     = 0;
            int pathFailures      = 0;

            for (int x = 0; x < gridTotalSize; x++)
            {
                for (int y = 0; y < gridTotalSize; y++)
                {
                    Vector2 xy   = new Vector2(topleft.X + (x * gridSquareSize), topleft.Y + (y * gridSquareSize));
                    Vector3 xyz  = Vector3.Zero;
                    Point   p_xy = Point.Empty;

                    if (GilesTrinity.Settings.Combat.Misc.UseNavMeshTargeting)
                    {
                        xyz = new Vector3(xy.X, xy.Y, gp.GetHeight(xy));
                    }
                    else
                    {
                        xyz = new Vector3(xy.X, xy.Y, origin.Z + 4);
                    }

                    GridPoint gridPoint = new GridPoint(xyz, 0, origin.Distance(xyz));

                    //if (gridPoint.Distance > maxDistance + gridSquareRadius)
                    //    continue;
                    if (GilesTrinity.Settings.Combat.Misc.UseNavMeshTargeting)
                    {
                        p_xy = gp.WorldToGrid(xy);
                        if (!gp.CanStandAt(p_xy))
                        {
                            nodesNotNavigable++;
                            continue;
                        }
                    }
                    else
                    {
                        // If ZDiff is way too different (up a cliff or wall)
                        if (Math.Abs(gridPoint.Position.Z - origin.Z) > maxZDiff)
                        {
                            nodesZDiff++;
                            continue;
                        }
                    }
                    if (gridPoint.Distance > 45 && Navigator.Raycast(origin, xyz))
                    {
                        nodesGT45Raycast++;
                        continue;
                    }

                    if (isStuck && gridPoint.Distance > (PlayerMover.iTotalAntiStuckAttempts + 2) * 5)
                    {
                        continue;
                    }

                    /*
                     * Check if a square is occupied already
                     */
                    // Avoidance
                    if (GilesTrinity.hashAvoidanceObstacleCache.Any(a => Vector3.Distance(xyz, a.Location) - a.Radius <= gridSquareRadius))
                    {
                        nodesAvoidance++;
                        continue;
                    }
                    // Obstacles
                    if (GilesTrinity.hashNavigationObstacleCache.Any(a => Vector3.Distance(xyz, a.Location) - a.Radius <= gridSquareRadius))
                    {
                        nodesMonsters++;
                        continue;
                    }

                    // Monsters
                    if (shouldKite)
                    {
                        // Any monster standing in this GridPoint
                        if (GilesTrinity.hashMonsterObstacleCache.Any(a => Vector3.Distance(xyz, a.Location) - a.Radius <= (shouldKite ? gridSquareRadius : gridSquareSize + GilesTrinity.PlayerKiteDistance)))
                        {
                            nodesMonsters++;
                            continue;
                        }

                        if (!hasEmergencyTeleportUp)
                        {
                            // Any monsters blocking in a straight line between origin and this GridPoint
                            foreach (GilesObstacle monster in GilesTrinity.hashMonsterObstacleCache.Where(m =>
                                                                                                          MathEx.IntersectsPath(new Vector3(m.Location.X, m.Location.Y, 0), m.Radius, new Vector3(origin.X, origin.Y, 0), new Vector3(gridPoint.Position.X, gridPoint.Position.Y, 0))
                                                                                                          ))
                            {
                                nodesMonsters++;
                                continue;
                            }
                        }

                        int nearbyMonsters = (monsterList != null ? monsterList.Count() : 0);
                    }

                    if (isStuck && UsedStuckSpots.Any(p => Vector3.Distance(p.Position, gridPoint.Position) <= gridSquareRadius))
                    {
                        continue;
                    }

                    if (!isStuck)
                    {
                        gridPoint.Weight = ((maxDistance - gridPoint.Distance) / maxDistance) * maxWeight;

                        // Low weight for close range grid points
                        if (shouldKite && gridPoint.Distance < GilesTrinity.PlayerKiteDistance)
                        {
                            gridPoint.Weight = (int)gridPoint.Distance;
                        }
                    }
                    else
                    {
                        gridPoint.Weight = gridPoint.Distance;
                    }

                    // Boss Areas
                    if (UnSafeZone.UnsafeKiteAreas.Any(a => a.WorldId == ZetaDia.CurrentWorldId && Vector3.Distance(a.Position, gridPoint.Position) <= a.Radius))
                    {
                        continue;
                    }

                    if (shouldKite)
                    {
                        // make sure we can raycast to our target
                        if (!NavHelper.CanRayCast(gridPoint.Position, GilesTrinity.LastPrimaryTargetPosition))
                        {
                            continue;
                        }

                        /*
                         * We want to down-weight any grid points where monsters are closer to it than we are
                         */
                        foreach (GilesObstacle monster in GilesTrinity.hashMonsterObstacleCache)
                        {
                            float distFromMonster           = gridPoint.Position.Distance2D(monster.Location);
                            float distFromOrigin            = gridPoint.Position.Distance2D(origin);
                            float distFromOriginToAvoidance = origin.Distance2D(monster.Location);
                            if (distFromOriginToAvoidance < distFromOrigin)
                            {
                                continue;
                            }

                            if (distFromMonster < distFromOrigin)
                            {
                                gridPoint.Weight -= distFromOrigin;
                            }
                            else if (distFromMonster > distFromOrigin)
                            {
                                gridPoint.Weight += distFromMonster;
                            }
                        }
                        foreach (GilesObstacle avoidance in GilesTrinity.hashAvoidanceObstacleCache)
                        {
                            float distFromAvoidance         = gridPoint.Position.Distance2D(avoidance.Location);
                            float distFromOrigin            = gridPoint.Position.Distance2D(origin);
                            float distFromOriginToAvoidance = origin.Distance2D(avoidance.Location);

                            float health = AvoidanceManager.GetAvoidanceHealthBySNO(avoidance.ActorSNO, 1f);
                            float radius = AvoidanceManager.GetAvoidanceRadiusBySNO(avoidance.ActorSNO, 1f);

                            // position is inside avoidance
                            if (PlayerStatus.CurrentHealthPct < health && distFromAvoidance < radius)
                            {
                                continue;
                            }

                            // closer to avoidance than it is to player
                            if (distFromOriginToAvoidance < distFromOrigin)
                            {
                                continue;
                            }

                            if (distFromAvoidance < distFromOrigin)
                            {
                                gridPoint.Weight -= distFromOrigin;
                            }
                            else if (distFromAvoidance > distFromOrigin)
                            {
                                gridPoint.Weight += distFromAvoidance;
                            }
                        }
                    }
                    else if (isStuck)
                    {
                        // give weight to points nearer to our destination
                        gridPoint.Weight *= (maxDistance - PlayerMover.LastMoveToTarget.Distance2D(gridPoint.Position)) / maxDistance * maxWeight;
                    }
                    else if (!shouldKite && !isStuck) // melee avoidance use only
                    {
                        var monsterCount = GilesTrinity.GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.Position.Distance2D(gridPoint.Position) <= gridSquareRadius);
                        if (monsterCount > 0)
                        {
                            gridPoint.Weight *= monsterCount;
                        }
                    }

                    if (gridPoint.Weight > bestPoint.Weight && gridPoint.Distance > 1)
                    {
                        bestPoint = gridPoint;
                    }

                    //if (gridPoint.Weight > 0)
                    //    DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Moving, "Kiting grid point {0}, distance: {1:0}, weight: {2:0}", gridPoint.Position, gridPoint.Distance, gridPoint.Weight);
                }
            }

            if (isStuck)
            {
                UsedStuckSpots.Add(bestPoint);
            }

            DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting grid found {0}, distance: {1:0}, weight: {2:0}", bestPoint.Position, bestPoint.Distance, bestPoint.Weight);
            DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "Kiting grid stats NotNavigable {0} ZDiff {1} GT45Raycast {2} Avoidance {3} Monsters {4} pathFailures {5}",
                         nodesNotNavigable,
                         nodesZDiff,
                         nodesGT45Raycast,
                         nodesAvoidance,
                         nodesMonsters,
                         pathFailures);
            return(bestPoint.Position);
        }
Exemple #9
0
        /// <summary>
        /// This is wired up by Plugin.OnEnabled, and called when the bot is started
        /// </summary>
        /// <param name="bot"></param>
        private static void TrinityBotStart(IBot bot)
        {
            // Recording of all the XML's in use this run
            try
            {
                string sThisProfile = Zeta.CommonBot.Settings.GlobalSettings.Instance.LastProfile;
                if (sThisProfile != CurrentProfile)
                {
                    listProfilesLoaded.Add(sThisProfile);
                    CurrentProfile = sThisProfile;
                    if (FirstProfile == "")
                    {
                        FirstProfile = sThisProfile;
                    }
                }
            }
            catch { }
            // Update actors if possible (if already in-game)
            if (ZetaDia.IsInGame && !ZetaDia.IsLoadingWorld && ZetaDia.Actors != null)
            {
                ZetaDia.Actors.Update();
                NavHelper.UpdateSearchGridProvider(true);
            }
            HasMappedPlayerAbilities = false;
            if (!bMaintainStatTracking)
            {
                ItemStatsWhenStartedBot   = DateTime.Now;
                ItemStatsLastPostedReport = DateTime.Now;
                bMaintainStatTracking     = true;
            }
            else
            {
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Note: Maintaining item stats from previous run. To reset stats fully, please restart DB.");
            }

            UsedProfileManager.RefreshProfileBlacklists();

            ReplaceTreeHooks();

            PlayerMover.TimeLastRecordedPosition = DateTime.Now;
            PlayerMover.timeLastRestartedGame    = DateTime.Now;
            GoldInactivity.ResetCheckGold();

            if (Zeta.CommonBot.Settings.CharacterSettings.Instance.KillRadius < 20)
            {
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "WARNING: Low Kill Radius detected, currently set to: {0} (you can change this through Demonbuddy bot settings)",
                             Zeta.CommonBot.Settings.CharacterSettings.Instance.KillRadius);
            }

            if (Zeta.CommonBot.Settings.CharacterSettings.Instance.LootRadius < 50)
            {
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "WARNING: Low Gold Loot Radius detected, currently set to: {0} (you can change this through Demonbuddy bot settings)",
                             Zeta.CommonBot.Settings.CharacterSettings.Instance.LootRadius);
            }

            if (StashRule == null)
            {
                StashRule = new ItemRules.Interpreter();
            }

            StashRule.readConfiguration();
        }
Exemple #10
0
        private static void Monk_MaintainTempestRush()
        {
            if (!Monk_TempestRushReady())
            {
                return;
            }

            if (PlayerStatus.IsInTown || Zeta.CommonBot.Logic.BrainBehavior.IsVendoring)
            {
                return;
            }

            if (TownRun.IsTryingToTownPortal())
            {
                return;
            }

            if (TimeSinceUse(SNOPower.Monk_TempestRush) > 150)
            {
                return;
            }

            bool shouldMaintain = false;
            bool nullTarget     = CurrentTarget == null;

            if (!nullTarget)
            {
                // maintain for everything except items, doors, interactables... stuff we have to "click" on
                switch (CurrentTarget.Type)
                {
                case GObjectType.Unit:
                case GObjectType.Gold:
                case GObjectType.Avoidance:
                case GObjectType.Barricade:
                case GObjectType.Destructible:
                case GObjectType.Globe:
                {
                    if (Settings.Combat.Monk.TROption == TempestRushOption.TrashOnly &&
                        (TargetUtil.AnyElitesInRange(40f) || CurrentTarget.IsBossOrEliteRareUnique))
                    {
                        shouldMaintain = false;
                    }
                    else
                    {
                        shouldMaintain = true;
                    }
                }
                break;
                }
            }
            else
            {
                shouldMaintain = true;
            }

            if (Settings.Combat.Monk.TROption != TempestRushOption.MovementOnly && GilesUseTimer(SNOPower.Monk_TempestRush) && shouldMaintain)
            {
                Vector3 target = LastTempestRushLocation;

                string locationSource = "LastLocation";

                //if (CurrentTarget != null && GilesNavHelper.CanRayCast(PlayerStatus.CurrentPosition, CurrentTarget.Position))
                //{
                //    locationSource = "Current Target Position";
                //    target = CurrentTarget.Position;
                //}

                if (target.Distance2D(ZetaDia.Me.Position) <= 1f)
                {
                    // rrrix edit: we can't maintain here
                    return;

                    //locationSource = "ZigZag";
                    //target = FindZigZagTargetLocation(target, 23f);
                }

                if (target == Vector3.Zero)
                {
                    return;
                }

                float DestinationDistance = target.Distance2D(ZetaDia.Me.Position);

                //target = MathEx.CalculatePointFrom(target, PlayerStatus.CurrentPosition, aimPointDistance);
                target = TargetUtil.FindTempestRushTarget();

                if (DestinationDistance > 10f && NavHelper.CanRayCast(ZetaDia.Me.Position, target))
                {
                    Monk_TempestRushStatus(String.Format("Using Tempest Rush to maintain channeling, source={0}, V3={1} dist={2:0}", locationSource, target, DestinationDistance));

                    var usePowerResult = ZetaDia.Me.UsePower(SNOPower.Monk_TempestRush, target, CurrentWorldDynamicId, -1);
                    if (usePowerResult)
                    {
                        dictAbilityLastUse[SNOPower.Monk_TempestRush] = DateTime.Now;
                    }
                }
            }
        }
Exemple #11
0
        /// <summary>
        /// Update the cached data on the player information, including buffs if needed
        /// </summary>
        internal static void UpdateCachedPlayerData()
        {
            using (new PerformanceLogger("UpdateCachedPlayerData"))
            {
                if (DateTime.Now.Subtract(PlayerStatus.LastUpdated).TotalMilliseconds <= 100)
                {
                    return;
                }
                // If we aren't in the game of a world is loading, don't do anything yet
                if (!ZetaDia.IsInGame || ZetaDia.IsLoadingWorld)
                {
                    return;
                }
                var me = ZetaDia.Me;
                if (me == null)
                {
                    return;
                }

                try
                {
                    PlayerStatus.LastUpdated    = DateTime.Now;
                    PlayerStatus.IsInTown       = me.IsInTown;
                    PlayerStatus.IsDead         = me.IsDead;
                    PlayerStatus.IsInGame       = ZetaDia.IsInGame;
                    PlayerStatus.IsLoadingWorld = ZetaDia.IsLoadingWorld;

                    PlayerStatus.IsIncapacitated = (me.IsFeared || me.IsStunned || me.IsFrozen || me.IsBlind);
                    PlayerStatus.IsRooted        = me.IsRooted;

                    PlayerStatus.CurrentHealthPct     = me.HitpointsCurrentPct;
                    PlayerStatus.PrimaryResource      = me.CurrentPrimaryResource;
                    PlayerStatus.PrimaryResourcePct   = PlayerStatus.PrimaryResource / me.MaxPrimaryResource;
                    PlayerStatus.SecondaryResource    = me.CurrentSecondaryResource;
                    PlayerStatus.SecondaryResourcePct = PlayerStatus.SecondaryResource / me.MaxSecondaryResource;
                    PlayerStatus.CurrentPosition      = me.Position;

                    PlayerStatus.GoldPickupRadius = me.GoldPickupRadius;
                    PlayerStatus.Coinage          = me.Inventory.Coinage;

                    if (PlayerStatus.PrimaryResource >= GilesTrinity.MinEnergyReserve)
                    {
                        PlayerStatus.WaitingForReserveEnergy = false;
                    }
                    if (PlayerStatus.PrimaryResource < 20)
                    {
                        PlayerStatus.WaitingForReserveEnergy = true;
                    }


                    PlayerStatus.MyDynamicID = me.CommonData.DynamicId;
                    PlayerStatus.Level       = me.Level;
                    PlayerStatus.ActorClass  = me.ActorClass;
                    PlayerStatus.BattleTag   = ZetaDia.Service.CurrentHero.BattleTagName;
                    PlayerStatus.LevelAreaId = ZetaDia.CurrentLevelAreaId;

                    if (PlayerStatus.ActorClass == ActorClass.WitchDoctor && HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Witchdoctor_Hex && s.RuneIndex == 1))
                    {
                        PlayerStatus.IsHidden = me.IsHidden;
                    }
                    else
                    {
                        PlayerStatus.IsHidden = false;
                    }

                    if (DateTime.Now.Subtract(PlayerStatus.Scene.LastUpdate).TotalMilliseconds > 1000 && GilesTrinity.Settings.Combat.Misc.UseNavMeshTargeting)
                    {
                        int CurrentSceneSNO = -1;
                        CurrentSceneSNO = (int)ZetaDia.Me.SceneId;
                        if (PlayerStatus.SceneId != CurrentSceneSNO)
                        {
                            PlayerStatus.SceneId = CurrentSceneSNO;
                            DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Updating Grid Provider", true);
                            NavHelper.UpdateSearchGridProvider();
                        }
                    }

                    // World ID safety caching incase it's ever unavailable
                    GilesTrinity.CurrentWorldDynamicId = ZetaDia.CurrentWorldDynamicId;
                    PlayerStatus.WorldDynamicID        = ZetaDia.CurrentWorldDynamicId;
                    PlayerStatus.WorldID             = ZetaDia.CurrentWorldId;
                    GilesTrinity.cachedStaticWorldId = ZetaDia.CurrentWorldId;
                    // Game difficulty, used really for vault on DH's
                    GilesTrinity.iCurrentGameDifficulty = ZetaDia.Service.CurrentHero.CurrentDifficulty;

                    // Refresh player buffs (to check for archon)
                    RefreshBuffs();
                }
                catch (Exception ex)
                {
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception for grabbing player data.{0}{1}", Environment.NewLine, ex);
                }
            }
        }
Exemple #12
0
        private static TrinityPower GetDemonHunterPower(bool IsCurrentlyAvoiding, bool UseOOCBuff, bool UseDestructiblePower)
        {
            // Pick the best destructible power available
            if (UseDestructiblePower)
            {
                return(GetDemonHunterDestroyPower());
            }
            MinEnergyReserve = 25;
            // Shadow Power
            if (!UseOOCBuff && Hotbar.Contains(SNOPower.DemonHunter_ShadowPower) && !PlayerStatus.IsIncapacitated &&
                PlayerStatus.SecondaryResource >= 14 &&
                (PlayerStatus.CurrentHealthPct <= 0.99 || PlayerStatus.IsRooted || ElitesWithinRange[RANGE_25] >= 1 || AnythingWithinRange[RANGE_15] >= 3) &&
                GilesUseTimer(SNOPower.DemonHunter_ShadowPower))
            {
                return(new TrinityPower(SNOPower.DemonHunter_ShadowPower, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Smoke Screen
            if ((!UseOOCBuff || Settings.Combat.DemonHunter.SpamSmokeScreen) && Hotbar.Contains(SNOPower.DemonHunter_SmokeScreen) &&
                !GetHasBuff(SNOPower.DemonHunter_ShadowPower) && PlayerStatus.SecondaryResource >= 14 &&
                (
                    (PlayerStatus.CurrentHealthPct <= 0.90 || PlayerStatus.IsRooted || ElitesWithinRange[RANGE_20] >= 1 || AnythingWithinRange[RANGE_15] >= 3 || PlayerStatus.IsIncapacitated) ||
                    Settings.Combat.DemonHunter.SpamSmokeScreen
                ) &&
                GilesUseTimer(SNOPower.DemonHunter_SmokeScreen))
            {
                return(new TrinityPower(SNOPower.DemonHunter_SmokeScreen, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Preparation

            if (
                (
                    ((!UseOOCBuff && !PlayerStatus.IsIncapacitated && AnythingWithinRange[RANGE_40] >= 1) ||
                     Settings.Combat.DemonHunter.SpamPreparation)
                ) &&
                Hotbar.Contains(SNOPower.DemonHunter_Preparation) &&
                PlayerStatus.SecondaryResource <= 10 &&
                //GilesUseTimer(SNOPower.DemonHunter_Preparation) &&
                //PowerManager.CanCast(SNOPower.DemonHunter_Preparation)
                TrinityPowerManager.CanUse(SNOPower.DemonHunter_Preparation)
                )
            {
                return(new TrinityPower(SNOPower.DemonHunter_Preparation, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Evasive Fire
            if (!UseOOCBuff && Hotbar.Contains(SNOPower.DemonHunter_EvasiveFire) && !PlayerStatus.IsIncapacitated &&
                (((AnythingWithinRange[RANGE_20] >= 1 || CurrentTarget.RadiusDistance <= 20f) && GilesUseTimer(SNOPower.DemonHunter_EvasiveFire)) ||
                 DHHasNoPrimary()))
            {
                float range = DHHasNoPrimary() ? 70f : 0f;

                return(new TrinityPower(SNOPower.DemonHunter_EvasiveFire, range, vNullLocation, -1, CurrentTarget.ACDGuid, 1, 1, WAIT_FOR_ANIM));
            }
            // Companion
            if (!PlayerStatus.IsIncapacitated && Hotbar.Contains(SNOPower.DemonHunter_Companion) && iPlayerOwnedDHPets == 0 &&
                PlayerStatus.SecondaryResource >= 10 && GilesUseTimer(SNOPower.DemonHunter_Companion))
            {
                return(new TrinityPower(SNOPower.DemonHunter_Companion, 0f, vNullLocation, CurrentWorldDynamicId, -1, 2, 1, WAIT_FOR_ANIM));
            }
            // Sentry Turret
            if (!UseOOCBuff && !PlayerStatus.IsIncapacitated && Hotbar.Contains(SNOPower.DemonHunter_Sentry) &&
                (TargetUtil.AnyElitesInRange(50) || TargetUtil.AnyMobsInRange(50, 2) || TargetUtil.IsEliteTargetInRange(50)) &&
                PlayerStatus.PrimaryResource >= 30 && PowerManager.CanCast(SNOPower.DemonHunter_Sentry))
            {
                return(new TrinityPower(SNOPower.DemonHunter_Sentry, 0f, PlayerStatus.CurrentPosition, CurrentWorldDynamicId, -1, 0, 0, NO_WAIT_ANIM));
            }
            // Marked for Death
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_MarkedForDeath) &&
                PlayerStatus.SecondaryResource >= 3 &&
                (ElitesWithinRange[RANGE_40] >= 1 || AnythingWithinRange[RANGE_40] >= 3 ||

                 ((CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin || CurrentTarget.IsBoss) &&
                  CurrentTarget.Radius <= 40 && CurrentTarget.RadiusDistance <= 40f)) &&
                GilesUseTimer(SNOPower.DemonHunter_MarkedForDeath))
            {
                return(new TrinityPower(SNOPower.DemonHunter_MarkedForDeath, 40f, vNullLocation, CurrentWorldDynamicId, CurrentTarget.ACDGuid, 1, 1, WAIT_FOR_ANIM));
            }
            // Vault
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Vault) && !PlayerStatus.IsRooted && !PlayerStatus.IsIncapacitated &&
                // Only use vault to retreat if < level 60, or if in inferno difficulty for level 60's
                (PlayerStatus.Level < 60 || iCurrentGameDifficulty == GameDifficulty.Inferno) &&
                (CurrentTarget.RadiusDistance <= 10f || AnythingWithinRange[RANGE_6] >= 1) &&
                ((!Hotbar.Contains(SNOPower.DemonHunter_ShadowPower) && PlayerStatus.SecondaryResource >= 16) ||
                 (Hotbar.Contains(SNOPower.DemonHunter_ShadowPower) && PlayerStatus.SecondaryResource >= 22)) &&
                //GilesUseTimer(SNOPower.DemonHunter_Vault) &&
                DateTime.Now.Subtract(GilesTrinity.dictAbilityLastUse[SNOPower.DemonHunter_Vault]).TotalMilliseconds >= GilesTrinity.Settings.Combat.DemonHunter.VaultMovementDelay &&
                PowerManager.CanCast(SNOPower.DemonHunter_Vault))
            {
                Vector3 vNewTarget = MathEx.CalculatePointFrom(CurrentTarget.Position, PlayerStatus.CurrentPosition, -15f);
                return(new TrinityPower(SNOPower.DemonHunter_Vault, 20f, vNewTarget, CurrentWorldDynamicId, -1, 1, 2, WAIT_FOR_ANIM));
            }
            // Rain of Vengeance
            if (!UseOOCBuff && Hotbar.Contains(SNOPower.DemonHunter_RainOfVengeance) && !PlayerStatus.IsIncapacitated &&
                (AnythingWithinRange[RANGE_25] >= 3 || ElitesWithinRange[RANGE_25] >= 1) &&
                GilesUseTimer(SNOPower.DemonHunter_RainOfVengeance) && PowerManager.CanCast(SNOPower.DemonHunter_RainOfVengeance))
            {
                return(new TrinityPower(SNOPower.DemonHunter_RainOfVengeance, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Cluster Arrow
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_ClusterArrow) && !PlayerStatus.IsIncapacitated &&
                PlayerStatus.PrimaryResource >= 50 &&
                (ElitesWithinRange[RANGE_50] >= 1 || AnythingWithinRange[RANGE_50] >= 5 || ((CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin || CurrentTarget.IsBoss) && CurrentTarget.RadiusDistance <= 69f)) &&
                GilesUseTimer(SNOPower.DemonHunter_ClusterArrow))
            {
                return(new TrinityPower(SNOPower.DemonHunter_ClusterArrow, 69f, vNullLocation, CurrentWorldDynamicId, CurrentTarget.ACDGuid, 1, 1, WAIT_FOR_ANIM));
            }
            // Multi Shot
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Multishot) && !PlayerStatus.IsIncapacitated &&
                PlayerStatus.PrimaryResource >= 30 &&
                (ElitesWithinRange[RANGE_40] >= 1 || AnythingWithinRange[RANGE_40] >= 2 || ((CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin || CurrentTarget.IsBoss) &&
                                                                                            CurrentTarget.RadiusDistance <= 30f)))
            {
                return(new TrinityPower(SNOPower.DemonHunter_Multishot, 40f, CurrentTarget.Position, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Fan of Knives
            if (!UseOOCBuff && Hotbar.Contains(SNOPower.DemonHunter_FanOfKnives) && !PlayerStatus.IsIncapacitated &&
                PlayerStatus.PrimaryResource >= 20 &&
                (AnythingWithinRange[RANGE_15] >= 4 || ElitesWithinRange[RANGE_15] >= 1) &&
                PowerManager.CanCast(SNOPower.DemonHunter_FanOfKnives))
            {
                return(new TrinityPower(SNOPower.DemonHunter_FanOfKnives, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Strafe spam - similar to barbarian whirlwind routine
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Strafe) && !PlayerStatus.IsIncapacitated && !PlayerStatus.IsRooted &&
                // Only if there's 3 guys in 25 yds
                AnythingWithinRange[RANGE_25] >= 3 &&
                // Check for energy reservation amounts
                ((PlayerStatus.PrimaryResource >= 15 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= MinEnergyReserve))
            {
                bool bGenerateNewZigZag = (DateTime.Now.Subtract(lastChangedZigZag).TotalMilliseconds >= 1500 ||
                                           (vPositionLastZigZagCheck != vNullLocation && PlayerStatus.CurrentPosition == vPositionLastZigZagCheck && DateTime.Now.Subtract(lastChangedZigZag).TotalMilliseconds >= 200) ||
                                           Vector3.Distance(PlayerStatus.CurrentPosition, vSideToSideTarget) <= 4f ||
                                           CurrentTarget.ACDGuid != iACDGUIDLastWhirlwind);
                vPositionLastZigZagCheck = PlayerStatus.CurrentPosition;
                if (bGenerateNewZigZag)
                {
                    float fExtraDistance = CurrentTarget.CentreDistance <= 10f ? 10f : 5f;
                    //vSideToSideTarget = FindZigZagTargetLocation(CurrentTarget.vPosition, CurrentTarget.fCentreDist + fExtraDistance);
                    vSideToSideTarget = NavHelper.FindSafeZone(false, 1, CurrentTarget.Position, false);
                    // Resetting this to ensure the "no-spam" is reset since we changed our target location
                    LastPowerUsed         = SNOPower.None;
                    iACDGUIDLastWhirlwind = CurrentTarget.ACDGuid;
                    lastChangedZigZag     = DateTime.Now;
                }
                return(new TrinityPower(SNOPower.DemonHunter_Strafe, 25f, vSideToSideTarget, CurrentWorldDynamicId, -1, 0, 0, WAIT_FOR_ANIM));
            }
            // Spike Trap
            if (!UseOOCBuff && !PlayerStatus.IsIncapacitated && Hotbar.Contains(SNOPower.DemonHunter_SpikeTrap) &&
                LastPowerUsed != SNOPower.DemonHunter_SpikeTrap &&
                (ElitesWithinRange[RANGE_30] >= 1 || AnythingWithinRange[RANGE_25] > 4 || ((CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin || CurrentTarget.IsBoss) && CurrentTarget.RadiusDistance <= 35f)) &&
                PlayerStatus.PrimaryResource >= 30 && GilesUseTimer(SNOPower.DemonHunter_SpikeTrap))
            {
                // For distant monsters, try to target a little bit in-front of them (as they run towards us), if it's not a treasure goblin
                float fExtraDistance = 0f;
                if (CurrentTarget.CentreDistance > 17f && !CurrentTarget.IsTreasureGoblin)
                {
                    fExtraDistance = CurrentTarget.CentreDistance - 17f;
                    if (fExtraDistance > 5f)
                    {
                        fExtraDistance = 5f;
                    }
                    if (CurrentTarget.CentreDistance - fExtraDistance < 15f)
                    {
                        fExtraDistance -= 2;
                    }
                }
                Vector3 vNewTarget = MathEx.CalculatePointFrom(CurrentTarget.Position, PlayerStatus.CurrentPosition, CurrentTarget.CentreDistance - fExtraDistance);
                return(new TrinityPower(SNOPower.DemonHunter_SpikeTrap, 40f, vNewTarget, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }
            // Caltrops
            if (!UseOOCBuff && Hotbar.Contains(SNOPower.DemonHunter_Caltrops) && !PlayerStatus.IsIncapacitated &&
                PlayerStatus.SecondaryResource >= 6 && (AnythingWithinRange[RANGE_30] >= 2 || ElitesWithinRange[RANGE_40] >= 1) &&
                GilesUseTimer(SNOPower.DemonHunter_Caltrops))
            {
                return(new TrinityPower(SNOPower.DemonHunter_Caltrops, 0f, vNullLocation, CurrentWorldDynamicId, -1, 1, 1, WAIT_FOR_ANIM));
            }

            //skillDict.Add("ElementalArrow", SNOPower.DemonHunter_ElementalArrow);
            //runeDict.Add("BallLightning", 1);
            //runeDict.Add("FrostArrow", 0);
            //runeDict.Add("ScreamingSkull", 2);
            //runeDict.Add("LightningBolts", 4);
            //runeDict.Add("NetherTentacles", 3);

            var hasBallLightning   = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 1);
            var hasFrostArrow      = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 0);
            var hasScreamingSkull  = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 2);
            var hasLightningBolts  = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 4);
            var hasNetherTentacles = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 3);

            // Elemental Arrow
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_ElementalArrow) &&
                GilesUseTimer(SNOPower.DemonHunter_ElementalArrow) && !PlayerStatus.IsIncapacitated &&
                ((PlayerStatus.PrimaryResource >= 10 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= MinEnergyReserve))
            {
                // Players with grenades *AND* elemental arrow should spam grenades at close-range instead
                if (Hotbar.Contains(SNOPower.DemonHunter_Grenades) && CurrentTarget.RadiusDistance <= 18f)
                {
                    return(new TrinityPower(SNOPower.DemonHunter_Grenades, 18f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
                }
                // Now return elemental arrow, if not sending grenades instead
                return(new TrinityPower(SNOPower.DemonHunter_ElementalArrow, 65f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
            }
            // Chakram
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Chakram) && !PlayerStatus.IsIncapacitated &&
                // If we have elemental arrow or rapid fire, then use chakram as a 110 second buff, instead
                ((!Hotbar.Contains(SNOPower.DemonHunter_ClusterArrow)) ||
                 DateTime.Now.Subtract(dictAbilityLastUse[SNOPower.DemonHunter_Chakram]).TotalMilliseconds >= 110000) &&
                ((PlayerStatus.PrimaryResource >= 10 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= MinEnergyReserve))
            {
                return(new TrinityPower(SNOPower.DemonHunter_Chakram, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
            }
            // Rapid Fire
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_RapidFire) && !PlayerStatus.IsIncapacitated &&
                ((PlayerStatus.PrimaryResource >= 20 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= MinEnergyReserve))
            {
                // Players with grenades *AND* rapid fire should spam grenades at close-range instead
                if (Hotbar.Contains(SNOPower.DemonHunter_Grenades) && CurrentTarget.RadiusDistance <= 18f)
                {
                    return(new TrinityPower(SNOPower.DemonHunter_Grenades, 18f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 0, WAIT_FOR_ANIM));
                }
                // Now return rapid fire, if not sending grenades instead
                return(new TrinityPower(SNOPower.DemonHunter_RapidFire, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 0, NO_WAIT_ANIM));
            }
            // Impale
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Impale) && !PlayerStatus.IsIncapacitated &&
                (AnythingWithinRange[RANGE_12] <= 3) &&
                ((PlayerStatus.PrimaryResource >= 25 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= MinEnergyReserve) &&
                CurrentTarget.RadiusDistance <= 50f)
            {
                return(new TrinityPower(SNOPower.DemonHunter_Impale, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
            }
            // Hungering Arrow
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_HungeringArrow) && !PlayerStatus.IsIncapacitated)
            {
                return(new TrinityPower(SNOPower.DemonHunter_HungeringArrow, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 0, WAIT_FOR_ANIM));
            }
            // Entangling shot
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_EntanglingShot) && !PlayerStatus.IsIncapacitated)
            {
                return(new TrinityPower(SNOPower.DemonHunter_EntanglingShot, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 0, WAIT_FOR_ANIM));
            }
            // Bola Shot
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_BolaShot) && !PlayerStatus.IsIncapacitated)
            {
                return(new TrinityPower(SNOPower.DemonHunter_BolaShot, 50f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
            }
            // Grenades
            if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Grenades) && !PlayerStatus.IsIncapacitated)
            {
                return(new TrinityPower(SNOPower.DemonHunter_Grenades, 40f, vNullLocation, -1, CurrentTarget.ACDGuid, 0, 1, WAIT_FOR_ANIM));
            }
            // Default attacks
            if (!UseOOCBuff && !IsCurrentlyAvoiding)
            {
                return(new TrinityPower(GetDefaultWeaponPower(), GetDefaultWeaponDistance(), vNullLocation, CurrentWorldDynamicId, CurrentTarget.ACDGuid, 0, 0, WAIT_FOR_ANIM));
            }
            return(new TrinityPower(SNOPower.None, -1, vNullLocation, -1, -1, 0, 0, WAIT_FOR_ANIM));
        }