Пример #1
0
        internal static void TrinityOnItemSold(object sender, ItemEventArgs e)
        {
            ResetTownRun();

            try
            {
                ACDItem i = e.Item;

                if (i == null || !i.IsValid || i.IsDisposed)
                {
                    return;
                }

                var cachedItem = CachedACDItem.GetCachedItem(i);
                switch (i.ItemBaseType)
                {
                case ItemBaseType.Gem:
                case ItemBaseType.Misc:
                    break;

                default:
                    TownRun.LogJunkItems(cachedItem, cachedItem.TrinityItemBaseType, cachedItem.TrinityItemType, ItemValuation.ValueThisItem(cachedItem, cachedItem.TrinityItemType));
                    break;
                }
            }
            catch (Exception ex)
            {
                if (ex is CoroutineStoppedException)
                {
                    throw;
                }
            }
        }
Пример #2
0
        /// <summary>
        /// This will replace the main BehaviorTree hooks for Combat, Vendoring, and Looting.
        /// </summary>
        private static void ReplaceTreeHooks()
        {
            // This is the do-all-be-all god-head all encompasing piece of trinity
            TreeHooks.Instance.ReplaceHook("Combat", new Decorator(ctx => CheckHasTarget(ctx), HandleTargetAction()));

            // We still want the main VendorRun logic, we're just going to take control of *when* this logic kicks in
            PrioritySelector VendorRunPrioritySelector = (TreeHooks.Instance.Hooks["VendorRun"][0] as Decorator).Children[0] as PrioritySelector;

            TreeHooks.Instance.ReplaceHook("VendorRun", new Decorator(ret => TownRun.TownRunCanRun(ret), VendorRunPrioritySelector));

            // Loot tree is now empty and never runs (Loot is handled through combat)
            TreeHooks.Instance.ReplaceHook("Loot", new Decorator(ret => false, new Action()));
        }
Пример #3
0
        public static void CheckShouldTownRunForGambling()
        {
            if (!ZetaDia.IsInTown)
            {
                IsDumpingShards = false;
            }

            if (Trinity.Trinity.Settings.Gambling.ShouldTownRun && ZetaDia.CPlayer.BloodshardCount >= Math.Min(Trinity.Trinity.Settings.Gambling.SaveShardsThreshold, Trinity.Trinity.Player.MaxBloodShards))
            {
                if (CanRun() && !ShouldSaveShards && !TownRun.IsTryingToTownPortal() && !BrainBehavior.IsVendoring)
                {
                    BrainBehavior.ForceTownrun("Bloodshard Spending Threshold");
                }
            }
        }
Пример #4
0
        private void TrinityOnItemSalvaged(object sender, ItemEventArgs e)
        {
            ACDItem i = e.Item;

            var cachedItem = GilesCachedACDItem.GetCachedItem(i);

            ResetTownRun();
            switch (i.ItemBaseType)
            {
            case ItemBaseType.Gem:
            case ItemBaseType.Misc:
                break;

            default:
                TownRun.LogJunkItems(cachedItem, cachedItem.TrinityItemBaseType, cachedItem.TrinityItemType, ItemValuation.ValueThisItem(cachedItem, cachedItem.TrinityItemType));
                break;
            }
        }
Пример #5
0
        public static bool ShouldIgnore(TrinityCacheObject cacheObject)
        {
            if (TownRun.IsTryingToTownPortal())
            {
                return(false);
            }

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

            if (!cacheObject.IsFullyValid())
            {
                return(true);
            }

            var isRare     = cacheObject.CommonData.MonsterQualityLevel == Zeta.Game.Internals.Actors.MonsterQuality.Rare;
            var isMinion   = cacheObject.CommonData.MonsterQualityLevel == Zeta.Game.Internals.Actors.MonsterQuality.Minion;
            var isChampion = cacheObject.CommonData.MonsterQualityLevel == Zeta.Game.Internals.Actors.MonsterQuality.Champion;

            if ((cacheObject.IsEliteRareUnique || cacheObject.IsBoss || isMinion) && cacheObject.HitPointsPct <= Settings.Combat.Misc.ForceKillElitesHealth)
            {
                return(false);
            }

            if (Trinity.Settings.Combat.Misc.IgnoreHighHitePointTrash && cacheObject.IsTrashMob)
            {
                var unitName = cacheObject.InternalName.ToLower();
                if (HighHitPointTrashMobNames.Any(name => unitName.Contains(name)))
                {
                    return(true);
                }
            }

            if ((Trinity.Settings.Combat.Misc.IgnoreRares && (isRare | isMinion) || Trinity.Settings.Combat.Misc.IgnoreChampions && isChampion) && !cacheObject.IsBoss)
            {
                return(true);
            }

            return(false);
        }
Пример #6
0
        /// <summary>
        /// Receive Pulse event from DemonBuddy.
        /// </summary>
        public void OnPulse()
        {
            try
            {
                if (ZetaDia.Me == null)
                {
                    return;
                }

                if (!ZetaDia.IsInGame || !ZetaDia.Me.IsValid || ZetaDia.IsLoadingWorld)
                {
                    return;
                }

                // hax for sending notifications after a town run
                if (!Zeta.CommonBot.Logic.BrainBehavior.IsVendoring && !PlayerStatus.IsInTown)
                {
                    TownRun.SendEmailNotification();
                    TownRun.SendMobileNotifications();
                }

                // See if we should update the stats file
                if (DateTime.Now.Subtract(ItemStatsLastPostedReport).TotalSeconds > 10)
                {
                    ItemStatsLastPostedReport = DateTime.Now;
                    OutputReport();
                }

                // Recording of all the XML's in use this run
                UsedProfileManager.RecordProfile();

                Monk_MaintainTempestRush();
            }
            catch (Exception ex)
            {
                DbHelper.Log(LogCategory.UserInformation, "Exception in Pulse: {0}", ex.ToString());
            }
        }
Пример #7
0
        private static void ReplaceVendorRunHook()
        {
            if (!TreeHooks.Instance.Hooks.ContainsKey("VendorRun"))
            {
                return;
            }
            // We still want the main VendorRun logic, we're just going to take control of *when* this logic kicks in
            var vendorDecorator = TreeHooks.Instance.Hooks["VendorRun"][0] as Decorator;

            if (vendorDecorator != null)
            {
                StoreAndReplaceHook("VendorRun", new Decorator(TownRun.TownRunCanRun, new ActionRunCoroutine(ret => TownRun.TownRunCoroutineWrapper(vendorDecorator))));
            }
        }
Пример #8
0
        private static double RefreshKillRadius()
        {
            // Cancel altogether if it's not even in range, unless it's a boss or an injured treasure goblin
            double killRange = CurrentBotKillRange;

            // Bosses get extra radius
            if (c_unit_IsBoss)
            {
                if (c_ActorSNO != 80509)
                {
                    // Kulle Exception
                    killRange *= 1.5;
                }
                // And even more if they're already injured
                if (c_HitPointsPct <= 0.98)
                {
                    killRange *= 4;
                }
                // And make sure we have a MINIMUM range for bosses - incase they are at screen edge etc + Kulle exception
                if (killRange <= 200 && c_ActorSNO != 80509)
                {
                    killRange = 200;
                }
            }
            // Special short-range list to ignore weakling mobs
            if (PlayerKiteDistance <= 0 && !GetHasBuff(SNOPower.Wizard_Archon) && hashActorSNOShortRangeOnly.Contains(c_ActorSNO))
            {
                killRange = 12;
            }
            // Prevent long-range mobs beign ignored while they may be pounding on us
            if (killRange <= 30 && hashActorSNORanged.Contains(c_ActorSNO))
            {
                killRange = 120f;
            }

            // Injured treasure goblins get a huge extra radius - since they don't stay on the map long if injured, anyway!
            if (c_unit_IsTreasureGoblin && (c_CentreDistance <= 60 || c_HitPointsPct <= 0.99))
            {
                c_ForceLeapAgainst = true;
                if (Settings.Combat.Misc.GoblinPriority <= GoblinPriority.Prioritize)
                {
                    killRange *= 2.5;
                }
                else
                {
                    killRange *= 4;
                }
                // Minimum distance of 60
                if (killRange <= 60)
                {
                    killRange = 60;
                }
            }
            // Elitey type mobs and things
            else if ((c_unit_IsElite || c_unit_IsRare || c_unit_IsUnique || c_unit_IsMinion))
            {
                c_ForceLeapAgainst = true;

                // using new GUI slider for elite kill range
                killRange = Settings.Combat.Misc.EliteRange;

                // if we've damaged an elite and its still on screen, keep it
                if (c_HitPointsPct < 1 && killRange < 60)
                {
                    killRange = 60;
                }
            }
            // Safety for TownRun and UseTownPortalTag
            if (TownRun.IsTryingToTownPortal())
            {
                if (killRange <= 90)
                {
                    killRange = 90;
                }
            }
            return(killRange);
        }
Пример #9
0
        private static bool RefreshGilesUnit(bool AddToCache)
        {
            AddToCache = true;

            // See if this is a boss
            c_unit_IsBoss = hashBossSNO.Contains(c_ActorSNO);

            // hax for Diablo_shadowClone
            c_unit_IsAttackable = c_InternalName.StartsWith("Diablo_shadowClone");

            // Prepare the fake object for target handler
            if (FakeObject == null)
            {
                FakeObject = c_diaUnit;
            }

            if (c_CommonData.ACDGuid == -1)
            {
                AddToCache = false;
                return(AddToCache);
            }

            // Dictionary based caching of monster types based on the SNO codes
            MonsterType monsterType;
            // See if we need to refresh the monster type or not
            bool bAddToDictionary    = !dictionaryStoredMonsterTypes.TryGetValue(c_ActorSNO, out monsterType);
            bool bRefreshMonsterType = bAddToDictionary;

            using (new PerformanceLogger("RefreshUnit.5"))
            {
                // If it's a boss and it was an ally, keep refreshing until it's not an ally
                // Because some bosses START as allied for cutscenes etc. until they become hostile
                if (c_unit_IsBoss && !bRefreshMonsterType)
                {
                    switch (monsterType)
                    {
                    case MonsterType.Ally:
                    case MonsterType.Scenery:
                    case MonsterType.Helper:
                    case MonsterType.Team:
                        bRefreshMonsterType = true;
                        break;
                    }
                }
            }
            using (new PerformanceLogger("RefreshUnit.6"))
            {
                // Now see if we do need to get new data for this boss or not
                if (bRefreshMonsterType)
                {
                    try
                    {
                        monsterType = RefreshMonsterType(c_CommonData, monsterType, bAddToDictionary);
                    }
                    catch (Exception ex)
                    {
                        DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting monsterinfo and monstertype for unit {0} [{1}]", c_InternalName, c_ActorSNO);
                        DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "{0}", ex);
                        DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.CacheManagement, "ActorTypeAttempt={0}", c_diaUnit.ActorType);
                        AddToCache = false;
                    }
                }

                // Make sure it's a valid monster type
                switch (monsterType)
                {
                case MonsterType.Ally:
                case MonsterType.Scenery:
                case MonsterType.Helper:
                case MonsterType.Team:
                {
                    AddToCache      = false;
                    c_IgnoreSubStep = "AllySceneryHelperTeam";
                    return(AddToCache);
                }
                    //break;
                }
            }
            // Force return here for un-attackable allies
            if (!AddToCache)
            {
                return(AddToCache);
            }

            MonsterAffixes monsterAffixes;

            using (new PerformanceLogger("RefreshUnit.8"))
            {
                // Only set treasure goblins to true *IF* they haven't disabled goblins! Then check the SNO in the goblin hash list!
                c_unit_IsTreasureGoblin = false;
                // Flag this as a treasure goblin *OR* ignore this object altogether if treasure goblins are set to ignore
                if (hashActorSNOGoblins.Contains(c_ActorSNO))
                {
                    if (Settings.Combat.Misc.GoblinPriority != 0)
                    {
                        c_unit_IsTreasureGoblin = true;
                    }
                    else
                    {
                        AddToCache      = false;
                        c_IgnoreSubStep = "IgnoreTreasureGoblins";
                        return(AddToCache);
                    }
                }
                // Pull up the Monster Affix cached data
                monsterAffixes = RefreshAffixes(c_CommonData);

                /*
                 *
                 * This should be moved to HandleTarget
                 *
                 */
                if (PlayerStatus.ActorClass == ActorClass.Barbarian && Hotbar.Contains(SNOPower.Barbarian_WrathOfTheBerserker) && GilesUseTimer(SNOPower.Barbarian_WrathOfTheBerserker, true))
                {
                    //WotB only used on Arcane, Frozen, Jailer, Molten and Electrified+Reflect Damage elites
                    if (monsterAffixes.HasFlag(MonsterAffixes.ArcaneEnchanted) || monsterAffixes.HasFlag(MonsterAffixes.Frozen) ||
                        monsterAffixes.HasFlag(MonsterAffixes.Jailer) || monsterAffixes.HasFlag(MonsterAffixes.Molten) ||
                        (monsterAffixes.HasFlag(MonsterAffixes.Electrified) && monsterAffixes.HasFlag(MonsterAffixes.ReflectsDamage)) ||
                        //Bosses and uber elites
                        c_unit_IsBoss || c_ActorSNO == 256015 || c_ActorSNO == 256000 || c_ActorSNO == 255996 ||
                        //...or more than 4 elite mobs in range (only elites/rares/uniques, not minions!)
                        ElitesWithinRange[RANGE_50] > 4)
                    {
                        shouldUseBerserkerPower = true;
                    }
                }
                else
                {
                    shouldUseBerserkerPower = false;
                }

                // Is this something we should try to force leap/other movement abilities against?
                c_ForceLeapAgainst = false;
            }
            double killRange;

            killRange = RefreshKillRadius();

            c_KillRange = killRange;

            if (monsterAffixes.HasFlag(MonsterAffixes.Shielding))
            {
                c_unit_IsShielded = true;
            }

            // Only if at full health, else don't bother checking each loop
            // See if we already have this monster's size stored, if not get it and cache it
            if (!dictionaryStoredMonsterSizes.TryGetValue(c_ActorSNO, out c_unit_MonsterSize))
            {
                try
                {
                    RefreshMonsterSize();
                }
                catch (Exception ex)
                {
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting monstersize info for unit {0} [{1}]", c_InternalName, c_ActorSNO);
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "{0}", ex);
                    AddToCache = false;
                    return(AddToCache);
                }
            }
            // Retrieve collision sphere radius, cached if possible
            if (!dictGilesCollisionSphereCache.TryGetValue(c_ActorSNO, out c_Radius))
            {
                try
                {
                    RefreshMonsterRadius();
                }
                catch (Exception ex)
                {
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "Safely handled exception getting collisionsphere radius for unit {0} [{1}]", c_InternalName, c_ActorSNO);
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.CacheManagement, "{0}", ex);
                    AddToCache = false;
                    return(AddToCache);
                }
                dictGilesCollisionSphereCache.Add(c_ActorSNO, c_Radius);
            }

            double dThisMaxHealth = RefreshMonsterHealth();

            // And finally put the two together for a current health percentage
            c_HitPointsPct = c_HitPoints / dThisMaxHealth;

            // Unit is already dead
            if (c_HitPoints <= 0d && !c_unit_IsBoss)
            {
                AddToCache      = false;
                c_IgnoreSubStep = "0HitPoints";

                // return here immediately
                return(AddToCache);
            }

            AddToCache = RefreshUnitAttributes(AddToCache, c_diaUnit);

            if (!AddToCache)
            {
                return(AddToCache);
            }

            c_CurrentAnimation = c_diaUnit.CommonData.CurrentAnimation;


            // A "fake distance" to account for the large-object size of monsters
            c_RadiusDistance -= (float)c_Radius;
            if (c_RadiusDistance <= 1f)
            {
                c_RadiusDistance = 1f;
            }

            // Special flags to decide whether to target anything at all
            if (c_IsEliteRareUnique || c_unit_IsBoss)
            {
                AnyElitesPresent = true;
            }

            // Extended kill radius after last fighting, or when we want to force a town run
            if ((Settings.Combat.Misc.ExtendedTrashKill && iKeepKillRadiusExtendedFor > 0) || ForceVendorRunASAP || TownRun.IsTryingToTownPortal())
            {
                if (c_RadiusDistance <= killRange && AddToCache)
                {
                    AnyMobsInRange = true;
                }
            }
            else
            {
                if (c_RadiusDistance <= Settings.Combat.Misc.NonEliteRange && AddToCache)
                {
                    AnyMobsInRange = true;
                }
            }
            if (c_unit_IsTreasureGoblin)
            {
                AnyTreasureGoblinsPresent = true;
            }

            // Units with very high priority (1900+) allow an extra 50% on the non-elite kill slider range
            if (!AnyMobsInRange && !AnyElitesPresent && !AnyTreasureGoblinsPresent && c_RadiusDistance <= (Settings.Combat.Misc.NonEliteRange * 1.5))
            {
                int iExtraPriority;
                // Enable extended kill radius for specific unit-types
                if (hashActorSNORanged.Contains(c_ActorSNO))
                {
                    AnyMobsInRange = true;
                }
                if (!AnyMobsInRange && dictActorSNOPriority.TryGetValue(c_ActorSNO, out iExtraPriority))
                {
                    if (iExtraPriority >= 1900)
                    {
                        AnyMobsInRange = true;
                    }
                }
            }
            return(AddToCache);
        }
Пример #10
0
        /// <summary>
        /// Find fresh targets, start main BehaviorTree if needed, cast any buffs needed etc.
        /// </summary>
        /// <param name="ret"></param>
        /// <returns></returns>
        internal static bool CheckHasTarget(object ret)
        {
            using (new PerformanceLogger("Trinity.CheckHasTarget"))
            {
                // If we aren't in the game or a world is loading, don't do anything yet
                if (!ZetaDia.IsInGame || !ZetaDia.Me.IsValid || ZetaDia.IsLoadingWorld)
                {
                    return(false);
                }

                if (ZetaDia.Me.IsDead)
                {
                    GoldInactivity.ResetCheckGold();
                }
                else if (GoldInactivity.GoldInactive())
                {
                    BotMain.PauseWhile(GoldInactivity.GoldInactiveLeaveGame);
                    return(false);
                }

                if (lastWorldId != PlayerStatus.WorldID)
                {
                    ISearchAreaProvider mgp = Navigator.SearchGridProvider;
                }

                if (!HotbarRefreshTimer.IsRunning)
                {
                    HotbarRefreshTimer.Start();
                }

                if (!HasMappedPlayerAbilities || HotbarRefreshTimer.ElapsedMilliseconds > 10000 || ShouldRefreshHotbarAbilities)
                {
                    // Update the cached player's cache
                    ActorClass tempClass = ActorClass.Invalid;
                    try
                    {
                        tempClass = PlayerStatus.ActorClass;
                    }
                    catch
                    {
                        DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.GlobalHandler, "Safely handled exception trying to get character class.");
                    }

                    GilesPlayerCache.RefreshHotbar();

                    dictAbilityRepeatDelay = new Dictionary <SNOPower, int>(dictAbilityRepeatDefaults);
                    if (ZetaDia.CPlayer.PassiveSkills.Contains(SNOPower.Wizard_Passive_CriticalMass) && PlayerStatus.ActorClass == ActorClass.Wizard)
                    {
                        dictAbilityRepeatDelay[SNOPower.Wizard_FrostNova]          = 25;
                        dictAbilityRepeatDelay[SNOPower.Wizard_ExplosiveBlast]     = 25;
                        dictAbilityRepeatDelay[SNOPower.Wizard_DiamondSkin]        = 100;
                        dictAbilityRepeatDelay[SNOPower.Wizard_SlowTime]           = 6000;
                        dictAbilityRepeatDelay[SNOPower.Wizard_WaveOfForce]        = 1500;
                        dictAbilityRepeatDelay[SNOPower.Wizard_MirrorImage]        = 1500;
                        dictAbilityRepeatDelay[SNOPower.Wizard_Archon_ArcaneBlast] = 1500;
                        dictAbilityRepeatDelay[SNOPower.Wizard_Teleport]           = 2700;
                        dictAbilityRepeatDelay[SNOPower.Wizard_Archon_SlowTime]    = 1500;
                        dictAbilityRepeatDelay[SNOPower.Wizard_Archon_Teleport]    = 2700;
                    }
                    if (PlayerStatus.ActorClass == ActorClass.WitchDoctor && ZetaDia.CPlayer.PassiveSkills.Contains(SNOPower.Witchdoctor_Passive_GraveInjustice))
                    {
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_SoulHarvest]     = 1000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_SpiritWalk]      = 1000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_Horrify]         = 1000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_Gargantuan]      = 20000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_SummonZombieDog] = 20000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_GraspOfTheDead]  = 500;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_SpiritBarrage]   = 2000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_Locust_Swarm]    = 2000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_Haunt]           = 2000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_Hex]             = 3000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_MassConfusion]   = 15000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_FetishArmy]      = 20000;
                        dictAbilityRepeatDelay[SNOPower.Witchdoctor_BigBadVoodoo]    = 20000;
                    }
                    if (PlayerStatus.ActorClass == ActorClass.Barbarian && ZetaDia.CPlayer.PassiveSkills.Contains(SNOPower.Barbarian_Passive_BoonOfBulKathos))
                    {
                        dictAbilityRepeatDelay[SNOPower.Barbarian_Earthquake]          = 90500;
                        dictAbilityRepeatDelay[SNOPower.Barbarian_CallOfTheAncients]   = 90500;
                        dictAbilityRepeatDelay[SNOPower.Barbarian_WrathOfTheBerserker] = 90500;
                    }
                    // Pick an appropriate health set etc. based on class
                    switch (PlayerStatus.ActorClass)
                    {
                    case ActorClass.Barbarian:
                        // What health % should we use a potion, or look for a globe
                        PlayerEmergencyHealthPotionLimit = Settings.Combat.Barbarian.PotionLevel;
                        PlayerEmergencyHealthGlobeLimit  = Settings.Combat.Barbarian.HealthGlobeLevel;
                        PlayerKiteDistance = Settings.Combat.Barbarian.KiteLimit;
                        break;

                    case ActorClass.Monk:
                        // What health % should we use a potion, or look for a globe
                        PlayerEmergencyHealthPotionLimit = Settings.Combat.Monk.PotionLevel;
                        PlayerEmergencyHealthGlobeLimit  = Settings.Combat.Monk.HealthGlobeLevel;
                        // Monks never kite :)
                        PlayerKiteDistance = 0;
                        break;

                    case ActorClass.Wizard:
                        // What health % should we use a potion, or look for a globe
                        PlayerEmergencyHealthPotionLimit = Settings.Combat.Wizard.PotionLevel;
                        PlayerEmergencyHealthGlobeLimit  = Settings.Combat.Wizard.HealthGlobeLevel;
                        PlayerKiteDistance = Settings.Combat.Wizard.KiteLimit;
                        break;

                    case ActorClass.WitchDoctor:
                        // What health % should we use a potion, or look for a globe
                        PlayerEmergencyHealthPotionLimit = Settings.Combat.WitchDoctor.PotionLevel;
                        PlayerEmergencyHealthGlobeLimit  = Settings.Combat.WitchDoctor.HealthGlobeLevel;
                        PlayerKiteDistance = Settings.Combat.WitchDoctor.KiteLimit;
                        break;

                    case ActorClass.DemonHunter:
                        // What health % should we use a potion, or look for a globe
                        PlayerEmergencyHealthPotionLimit = Settings.Combat.DemonHunter.PotionLevel;
                        PlayerEmergencyHealthGlobeLimit  = Settings.Combat.DemonHunter.HealthGlobeLevel;
                        PlayerKiteDistance = Settings.Combat.DemonHunter.KiteLimit;
                        break;
                    }
                }
                // Clear target current and reset key variables used during the target-handling function

                //CurrentTarget = null;
                bDontMoveMeIAmDoingShit = false;
                TimesBlockedMoving      = 0;
                IsAlreadyMoving         = false;
                lastMovementCommand     = DateTime.Today;
                IsWaitingForPower       = false;
                IsWaitingAfterPower     = false;
                IsWaitingForPotion      = false;
                wasRootedLastTick       = false;

                ClearBlacklists();
                using (new PerformanceLogger("CheckHasTarget.RefreshCache"))
                {
                    // Refresh Cache if needed
                    bool CacheWasRefreshed = RefreshDiaObjectCache();
                }

                // We have a target, start the target handler!
                if (CurrentTarget != null)
                {
                    IsWholeNewTarget        = true;
                    bDontMoveMeIAmDoingShit = true;
                    ShouldPickNewAbilities  = true;
                    return(true);
                }

                //Monk_MaintainTempestRush();


                // Pop a potion when necessary
                if (PlayerStatus.CurrentHealthPct <= PlayerEmergencyHealthPotionLimit)
                {
                    if (!PlayerStatus.IsIncapacitated && GilesUseTimer(SNOPower.DrinkHealthPotion))
                    {
                        ACDItem thisBestPotion = ZetaDia.Me.Inventory.Backpack.Where(i => i.IsPotion).OrderByDescending(p => p.HitpointsGranted).ThenBy(p => p.ItemStackQuantity).FirstOrDefault();
                        if (thisBestPotion != null)
                        {
                            WaitWhileAnimating(4, true);
                            ZetaDia.Me.Inventory.UseItem((thisBestPotion.DynamicId));
                        }
                        dictAbilityLastUse[SNOPower.DrinkHealthPotion] = DateTime.Now;
                        WaitWhileAnimating(3, true);
                    }
                }
                sStatusText = "[Trinity] No more targets - DemonBuddy/profile management is now in control";

                if (Settings.Advanced.DebugInStatusBar && bResetStatusText)
                {
                    bResetStatusText   = false;
                    BotMain.StatusText = sStatusText;
                }

                // Nothing to do... do we have some maintenance we can do instead, like out of combat buffing?

                if (DateTime.Now.Subtract(lastMaintenanceCheck).TotalMilliseconds > 150)
                {
                    lastMaintenanceCheck = DateTime.Now;

                    // Out of combat buffing etc. but only if we don't want to return to town etc.
                    ACDAnimationInfo myAnimationState = ZetaDia.Me.CommonData.AnimationInfo;

                    if (!PlayerStatus.IsInTown && !IsReadyToTownRun && !ForceVendorRunASAP && myAnimationState != null &&
                        myAnimationState.State != AnimationState.Attacking &&
                        myAnimationState.State != AnimationState.Casting &&
                        myAnimationState.State != AnimationState.Channeling)
                    {
                        bDontSpamOutofCombat = false;

                        powerBuff = AbilitySelector(false, true, false);

                        if (powerBuff.SNOPower != SNOPower.None)
                        {
                            WaitWhileAnimating(4, true);
                            DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.Behavior, "Using OOC Buff: {0}", powerBuff.SNOPower.ToString());
                            if (powerBuff.WaitTicksBeforeUse > 0)
                            {
                                BotMain.PauseFor(new TimeSpan(0, 0, 0, 0, (int)powerBuff.WaitBeforeUseDelay));
                            }
                            ZetaDia.Me.UsePower(powerBuff.SNOPower, powerBuff.TargetPosition, powerBuff.TargetDynamicWorldId, powerBuff.TargetRActorGUID);
                            LastPowerUsed = powerBuff.SNOPower;
                            dictAbilityLastUse[powerBuff.SNOPower] = DateTime.Now;
                            if (powerBuff.WaitTicksAfterUse > 0)
                            {
                                BotMain.PauseFor(new TimeSpan(0, 0, 0, 0, (int)powerBuff.WaitAfterUseDelay));
                            }
                            WaitWhileAnimating(3, true);
                        }
                    }
                    else if (myAnimationState != null)
                    {
                        // Check if we are portalling to town, if so increase our kill radius temporarily
                        switch (myAnimationState.Current)
                        {
                        case SNOAnim.barbarian_male_HTH_Recall_Channel_01:
                        case SNOAnim.Barbarian_Female_HTH_Recall_Channel_01:
                        case SNOAnim.Monk_Male_recall_channel:
                        case SNOAnim.Monk_Female_recall_channel:
                        case SNOAnim.WitchDoctor_Male_recall_channel:
                        case SNOAnim.WitchDoctor_Female_recall_channel:
                        case SNOAnim.Wizard_Male_HTH_recall_channel:
                        case SNOAnim.Wizard_Female_HTH_recall_channel:
                        case SNOAnim.Demonhunter_Male_HTH_recall_channel:
                        case SNOAnim.Demonhunter_Female_HTH_recall_channel:
                            iKeepKillRadiusExtendedFor      = 20;
                            timeKeepKillRadiusExtendedUntil = DateTime.Now.AddSeconds(iKeepKillRadiusExtendedFor);
                            break;
                        }
                    }
                }
                CurrentTarget = null;

                if ((GilesTrinity.ForceVendorRunASAP || GilesTrinity.IsReadyToTownRun) && TownRun.TownRunTimerRunning())
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Waiting for town run timer", true);
                    return(true);
                }

                // Ok let DemonBuddy do stuff this loop, since we're done for the moment
                //DbHelper.Log(TrinityLogLevel.Verbose, LogCategory.GlobalHandler, sStatusText);

                return(false);
            }
        }
Пример #11
0
 public static Composite CreateUseHoradricCache()
 {
     return
         (new Decorator(ret => Trinity.Settings.Loot.TownRun.OpenHoradricCaches && !BrainBehavior.IsVendoring && !Trinity.ForceVendorRunASAP && !TownRun.IsTryingToTownPortal() &&
                        DateTime.UtcNow.Subtract(LastCheckedForHoradricCache).TotalSeconds > 1,
                        new Sequence(
                            new Action(ret => LastCheckedForHoradricCache = DateTime.UtcNow),
                            new Decorator(ret => HasHoradricCaches(),
                                          new Action(ret => OpenHoradricCache())
                                          )
                            )
                        ));
 }
Пример #12
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;
                    }
                }
            }
        }
Пример #13
0
        /// <summary>
        /// Determines whether or not to leave the game based on the gold inactivity timer
        /// </summary>
        /// <returns></returns>
        internal static bool GoldInactive()
        {
            if (!GilesTrinity.Settings.Advanced.GoldInactivityEnabled)
            {
                // timer isn't enabled so move along!
                ResetCheckGold();
                return(false);
            }
            try
            {
                if (!ZetaDia.IsInGame)
                {
                    ResetCheckGold(); //If not in game, reset the timer
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Not in game, gold inactivity reset", 0);
                    return(false);
                }
                if (ZetaDia.IsLoadingWorld)
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Loading world, gold inactivity reset", 0);
                    return(false);
                }
                if ((DateTime.Now.Subtract(lastCheckBag).TotalSeconds < 5))
                {
                    return(false);
                }

                // sometimes bosses take a LONG time
                if (GilesTrinity.CurrentTarget != null && GilesTrinity.CurrentTarget.IsBoss)
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Current target is boss, gold inactivity reset", 0);
                    ResetCheckGold();
                    return(false);
                }

                if (TownRun.IsTryingToTownPortal())
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Trying to town portal, gold inactivity reset", 0);
                    ResetCheckGold();
                    return(false);
                }
                // Don't go inactive on WaitTimer tags
                ProfileBehavior c = null;
                try
                {
                    if (ProfileManager.CurrentProfileBehavior != null)
                    {
                        c = ProfileManager.CurrentProfileBehavior;
                    }
                }
                catch { }
                if (c != null && c.GetType() == typeof(WaitTimerTag))
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Wait timer tag, gold inactivity reset", 0);
                    ResetCheckGold();
                    return(false);
                }



                lastCheckBag = DateTime.Now;
                int currentcoin = GilesTrinity.PlayerStatus.Coinage;

                if (currentcoin != lastKnowCoin && currentcoin != 0)
                {
                    lastRefreshCoin = DateTime.Now;
                    lastKnowCoin    = currentcoin;
                }
                int notpickupgoldsec = Convert.ToInt32(DateTime.Now.Subtract(lastRefreshCoin).TotalSeconds);
                if (notpickupgoldsec >= GilesTrinity.Settings.Advanced.GoldInactivityTimer)
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Gold inactivity after {0}s. Sending abort.", notpickupgoldsec);
                    lastRefreshCoin  = DateTime.Now;
                    lastKnowCoin     = currentcoin;
                    notpickupgoldsec = 0;
                    return(true);
                }
                else if (notpickupgoldsec > 0)
                {
                    DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Gold unchanged for {0}s", notpickupgoldsec);
                }
            }
            catch (Exception e)
            {
                DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, e.Message);
            }
            DbHelper.Log(TrinityLogLevel.Normal, LogCategory.GlobalHandler, "Gold inactivity error - no result", 0);
            return(false);
        }
Пример #14
0
        /// <summary>
        /// This will replace the main BehaviorTree hooks for Combat, Vendoring, and Looting.
        /// </summary>
        internal static void ReplaceTreeHooks()
        {
            if (Trinity.IsPluginEnabled)
            {
                // This is the do-all-be-all god-head all encompasing piece of trinity
                StoreAndReplaceHook("Combat", new Decorator(Trinity.TargetCheck, Trinity.HandleTargetAction()));

                // We still want the main VendorRun logic, we're just going to take control of *when* this logic kicks in
                var vendorDecorator = TreeHooks.Instance.Hooks["VendorRun"][0] as Decorator;
                if (vendorDecorator != null)
                {
                    StoreAndReplaceHook("VendorRun", new Decorator(TownRun.TownRunCanRun, TownRun.TownRunWrapper(vendorDecorator.Children[0])));
                }

                // Loot tree is now empty and never runs (Loot is handled through combat)
                // This is for special out of combat handling like Horadric Cache
                Composite lootComposite = TreeHooks.Instance.Hooks["Loot"][0];
                StoreAndReplaceHook("Loot", Composites.CreateLootBehavior(lootComposite));

                if (_goldInactiveComposite == null)
                {
                    _goldInactiveComposite = GoldInactivity.CreateGoldInactiveLeaveGame();
                }

                Logger.Log("Inserting GoldInactivity into BotBehavior");
                TreeHooks.Instance.InsertHook("BotBehavior", 0, _goldInactiveComposite);
            }
            else
            {
                ReplaceHookWithOriginal("Combat");
                ReplaceHookWithOriginal("VendorRun");
                ReplaceHookWithOriginal("Loot");

                Logger.Log("Removing GoldInactivity from BotBehavior");
                TreeHooks.Instance.RemoveHook("BotBehavior", _goldInactiveComposite);
            }
        }
Пример #15
0
        private static void RefreshDiaGetWeights()
        {
            using (new PerformanceLogger("RefreshDiaObjectCache.Weighting"))
            {
                double MovementSpeed = PlayerMover.GetMovementSpeed();

                // Store if we are ignoring all units this cycle or not
                bool bIgnoreAllUnits = !AnyElitesPresent &&
                                       !AnyMobsInRange &&
                                       (
                    (
                        !AnyTreasureGoblinsPresent &&
                        Settings.Combat.Misc.GoblinPriority >= GoblinPriority.Prioritize
                    ) ||
                    Settings.Combat.Misc.GoblinPriority < GoblinPriority.Prioritize
                                       ) &&
                                       PlayerStatus.CurrentHealthPct >= 0.85d;

                bool PrioritizeCloseRangeUnits = (ForceCloseRangeTarget || PlayerStatus.IsRooted || MovementSpeed < 1 || GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.RadiusDistance < 5f) >= 3);

                bool hasWrathOfTheBerserker = PlayerStatus.ActorClass == ActorClass.Barbarian && GetHasBuff(SNOPower.Barbarian_WrathOfTheBerserker);

                int TrashMobCount  = GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.IsTrashMob);
                int EliteCount     = Settings.Combat.Misc.IgnoreElites ? 0 : GilesObjectCache.Count(u => u.Type == GObjectType.Unit && u.IsBossOrEliteRareUnique);
                int AvoidanceCount = Settings.Combat.Misc.AvoidAOE ? 0 : GilesObjectCache.Count(o => o.Type == GObjectType.Avoidance && o.CentreDistance <= 50f);

                bool profileTagCheck = false;
                if (ProfileManager.CurrentProfileBehavior != null)
                {
                    Type behaviorType = ProfileManager.CurrentProfileBehavior.GetType();
                    if (behaviorType == typeof(WaitTimerTag) || behaviorType == typeof(UseTownPortalTag) || behaviorType == typeof(XmlTags.TrinityTownRun))
                    {
                        profileTagCheck = true;
                    }
                }

                bool ShouldIgnoreTrashMobs =
                    (!TownRun.IsTryingToTownPortal() &&
                     !profileTagCheck &&
                     !PrioritizeCloseRangeUnits &&
                     Settings.Combat.Misc.TrashPackSize > 1 &&
                     EliteCount == 0 &&
                     AvoidanceCount == 0 &&
                     PlayerStatus.Level >= 15 &&
                     MovementSpeed >= 1
                    );

                string unitWeightInfo = "";

                foreach (GilesObject cacheObject in GilesObjectCache.OrderBy(c => c.CentreDistance))
                {
                    unitWeightInfo = "";

                    // Just to make sure each one starts at 0 weight...
                    cacheObject.Weight = 0d;

                    // Now do different calculations based on the object type
                    switch (cacheObject.Type)
                    {
                    // Weight Units
                    case GObjectType.Unit:
                    {
                        int nearbyMonsterCount = GilesObjectCache.Count(u => u.IsTrashMob && cacheObject.Position.Distance2D(u.Position) <= Settings.Combat.Misc.TrashPackClusterRadius);

                        // Ignore Solitary Trash mobs (no elites present)
                        // Except if has been primary target or if already low on health (<= 20%)
                        if (ShouldIgnoreTrashMobs && cacheObject.IsTrashMob && !cacheObject.HasBeenPrimaryTarget && cacheObject.RadiusDistance >= 2f &&
                            !(nearbyMonsterCount >= Settings.Combat.Misc.TrashPackSize))
                        {
                            unitWeightInfo = String.Format("Ignoring trash mob {0} {1} nearbyCount={2} packSize={3} packRadius={4:0} radiusDistance={5:0} ShouldIgnore={6} ms={7:0.00} Elites={8} Avoid={9} profileTagCheck={10} level={11} prioritize={12}",
                                                           cacheObject.InternalName, cacheObject.RActorGuid, nearbyMonsterCount, Settings.Combat.Misc.TrashPackSize, Settings.Combat.Misc.TrashPackClusterRadius,
                                                           cacheObject.RadiusDistance, ShouldIgnoreTrashMobs, MovementSpeed, EliteCount, AvoidanceCount, profileTagCheck, PlayerStatus.Level, PrioritizeCloseRangeUnits);
                            break;
                        }
                        else
                        {
                            unitWeightInfo = String.Format("Adding trash mob {0} {1} nearbyCount={2} packSize={3} packRadius={4:0} radiusDistance={5:0} ShouldIgnore={6} ms={7:0.00} Elites={8} Avoid={9} profileTagCheck={10} level={11} prioritize={12}",
                                                           cacheObject.InternalName, cacheObject.RActorGuid, nearbyMonsterCount, Settings.Combat.Misc.TrashPackSize, Settings.Combat.Misc.TrashPackClusterRadius,
                                                           cacheObject.RadiusDistance, ShouldIgnoreTrashMobs, MovementSpeed, EliteCount, AvoidanceCount, profileTagCheck, PlayerStatus.Level, PrioritizeCloseRangeUnits);
                        }

                        // Ignore elite option, except if trying to town portal
                        if (Settings.Combat.Misc.IgnoreElites && (cacheObject.IsEliteRareUnique) && !TownRun.IsTryingToTownPortal())
                        {
                            break;
                        }


                        // No champions, no mobs nearby, no treasure goblins to prioritize, and not injured, so skip mobs
                        if (bIgnoreAllUnits)
                        {
                            break;
                        }

                        // Monster is in cache but not within kill range
                        if (cacheObject.RadiusDistance > cacheObject.KillRange)
                        {
                            break;
                        }

                        if (cacheObject.HitPoints <= 0)
                        {
                            break;
                        }

                        // Total up monsters at various ranges
                        if (cacheObject.RadiusDistance <= 50f)
                        {
                            bool isElite = (cacheObject.IsEliteRareUnique || cacheObject.IsBoss);

                            bool isRended = cacheObject.HasDotDPS;

                            // Flag up any bosses in range
                            if (cacheObject.IsBoss)
                            {
                                anyBossesInRange = true;
                            }
                            if (cacheObject.RadiusDistance <= 6f)
                            {
                                AnythingWithinRange[RANGE_6]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_6]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 9f && !isRended)
                            {
                                NonRendedTargets_9++;
                            }
                            if (cacheObject.RadiusDistance <= 12f)
                            {
                                AnythingWithinRange[RANGE_12]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_12]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 15f)
                            {
                                AnythingWithinRange[RANGE_15]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_15]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 20f)
                            {
                                AnythingWithinRange[RANGE_20]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_20]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 25f)
                            {
                                if (!bAnyNonWWIgnoreMobsInRange && !hashActorSNOWhirlwindIgnore.Contains(cacheObject.ActorSNO))
                                {
                                    bAnyNonWWIgnoreMobsInRange = true;
                                }
                                AnythingWithinRange[RANGE_25]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_25]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 30f)
                            {
                                AnythingWithinRange[RANGE_30]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_30]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 40f)
                            {
                                AnythingWithinRange[RANGE_40]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_40]++;
                                }
                            }
                            if (cacheObject.RadiusDistance <= 50f)
                            {
                                AnythingWithinRange[RANGE_50]++;
                                if (isElite)
                                {
                                    ElitesWithinRange[RANGE_50]++;
                                }
                            }
                        }

                        // Force a close range target because we seem to be stuck *OR* if not ranged and currently rooted
                        if (PrioritizeCloseRangeUnits)
                        {
                            cacheObject.Weight = (50 - cacheObject.RadiusDistance) / 50 * 20000d;

                            // Goblin priority KAMIKAZEEEEEEEE
                            if (cacheObject.IsTreasureGoblin && Settings.Combat.Misc.GoblinPriority == GoblinPriority.Kamikaze)
                            {
                                cacheObject.Weight += 25000;
                            }
                        }
                        else
                        {
                            // Not attackable, could be shielded, make super low priority
                            if (cacheObject.IsShielded)
                            {
                                // Only 500 weight helps prevent it being prioritized over an unshielded
                                cacheObject.Weight = 500;
                            }
                            // Not forcing close-ranged targets from being stuck, so let's calculate a weight!
                            else
                            {
                                // Elites/Bosses that are killed should have weight erased so we don't keep attacking
                                if ((cacheObject.IsEliteRareUnique || cacheObject.IsBoss) && cacheObject.HitPointsPct <= 0)
                                {
                                    cacheObject.Weight = 0;
                                    break;
                                }


                                // Starting weight of 5000
                                if (cacheObject.IsTrashMob)
                                {
                                    cacheObject.Weight = (CurrentBotKillRange - cacheObject.RadiusDistance) / CurrentBotKillRange * 5000;
                                }

                                // Starting weight of 8000 for elites
                                if (cacheObject.IsBossOrEliteRareUnique)
                                {
                                    cacheObject.Weight = (90f - cacheObject.RadiusDistance) / 90f * 8000;
                                }

                                // Give extra weight to ranged enemies
                                if ((PlayerStatus.ActorClass == ActorClass.Barbarian || PlayerStatus.ActorClass == ActorClass.Monk) &&
                                    (cacheObject.MonsterStyle == MonsterSize.Ranged || hashActorSNORanged.Contains(c_ActorSNO)))
                                {
                                    cacheObject.Weight          += 1100;
                                    cacheObject.ForceLeapAgainst = true;
                                }

                                // Lower health gives higher weight - health is worth up to 1000ish extra weight
                                if (cacheObject.IsTrashMob && cacheObject.HitPointsPct < 0.20)
                                {
                                    cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 1000;
                                }

                                // Elites on low health get extra priority - up to 2500ish
                                if (cacheObject.IsBossOrEliteRareUnique && cacheObject.HitPointsPct < 0.20)
                                {
                                    cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 2500;
                                }

                                // Goblins on low health get extra priority - up to 4000ish
                                if (Settings.Combat.Misc.GoblinPriority >= GoblinPriority.Prioritize && cacheObject.IsTreasureGoblin && cacheObject.HitPointsPct <= 0.98)
                                {
                                    cacheObject.Weight += (100 - cacheObject.HitPointsPct) / 100 * 4000;
                                }

                                // Bonuses to priority type monsters from the dictionary/hashlist set at the top of the code
                                int iExtraPriority;
                                if (dictActorSNOPriority.TryGetValue(cacheObject.ActorSNO, out iExtraPriority))
                                {
                                    cacheObject.Weight += iExtraPriority;
                                }

                                // Close range get higher weights the more of them there are, to prevent body-blocking
                                if (cacheObject.RadiusDistance <= 5f)
                                {
                                    cacheObject.Weight += (2000 * cacheObject.Radius);
                                }

                                // Special additional weight for corrupt growths in act 4 ONLY if they are at close range (not a standard priority thing)
                                if ((cacheObject.ActorSNO == 210120 || cacheObject.ActorSNO == 210268) && cacheObject.CentreDistance <= 25f)
                                {
                                    cacheObject.Weight += 2000;
                                }

                                // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                                if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                                {
                                    cacheObject.Weight += 1000;
                                }

                                // Prevent going less than 300 yet to prevent annoyances (should only lose this much weight from priority reductions in priority list?)
                                if (cacheObject.Weight < 300)
                                {
                                    cacheObject.Weight = 300;
                                }

                                // If any AoE between us and target, do not attack, for non-ranged attacks only
                                if (!Settings.Combat.Misc.KillMonstersInAoE && PlayerKiteDistance <= 0 && hashAvoidanceObstacleCache.Any(o => MathUtil.IntersectsPath(o.Location, o.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                                {
                                    cacheObject.Weight = 1;
                                }

                                // See if there's any AOE avoidance in that spot, if so reduce the weight to 1, for non-ranged attacks only
                                if (!Settings.Combat.Misc.KillMonstersInAoE && PlayerKiteDistance <= 0 && hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius))
                                {
                                    cacheObject.Weight = 1;
                                }

                                if (PlayerKiteDistance > 0)
                                {
                                    if (GilesObjectCache.Any(m => m.Type == GObjectType.Unit &&
                                                             MathUtil.IntersectsPath(cacheObject.Position, cacheObject.Radius, PlayerStatus.CurrentPosition, m.Position) &&
                                                             m.RActorGuid != cacheObject.RActorGuid))
                                    {
                                        cacheObject.Weight = 0;
                                    }
                                }

                                // Deal with treasure goblins - note, of priority is set to "0", then the is-a-goblin flag isn't even set for use here - the monster is ignored
                                if (cacheObject.IsTreasureGoblin && !GilesObjectCache.Any(u => (u.Type == GObjectType.Door || u.Type == GObjectType.Barricade) && u.RadiusDistance <= 40f))
                                {
                                    // Logging goblin sightings
                                    if (lastGoblinTime == DateTime.Today)
                                    {
                                        iTotalNumberGoblins++;
                                        lastGoblinTime = DateTime.Now;
                                        DbHelper.Log(TrinityLogLevel.Normal, LogCategory.UserInformation, "Goblin #{0} in sight. Distance={1:0}", iTotalNumberGoblins, cacheObject.CentreDistance);
                                    }
                                    else
                                    {
                                        if (DateTime.Now.Subtract(lastGoblinTime).TotalMilliseconds > 30000)
                                        {
                                            lastGoblinTime = DateTime.Today;
                                        }
                                    }

                                    if (hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius) && Settings.Combat.Misc.GoblinPriority != GoblinPriority.Kamikaze)
                                    {
                                        cacheObject.Weight = 1;
                                        break;
                                    }

                                    // Original Trinity stuff for priority handling now
                                    switch (Settings.Combat.Misc.GoblinPriority)
                                    {
                                    case GoblinPriority.Normal:
                                        // Treating goblins as "normal monsters". Ok so I lied a little in the config, they get a little extra weight really! ;)
                                        cacheObject.Weight += 751;
                                        break;

                                    case GoblinPriority.Prioritize:
                                        // Super-high priority option below...
                                        cacheObject.Weight += 20000;
                                        break;

                                    case GoblinPriority.Kamikaze:
                                        // KAMIKAZE SUICIDAL TREASURE GOBLIN RAPE AHOY!
                                        cacheObject.Weight += 40000;
                                        break;
                                    }
                                }
                            }

                            // Forcing close range target or not?
                        }

                        // This is an attackable unit
                        break;
                    }

                    case GObjectType.Item:
                    case GObjectType.Gold:
                    {
                        // Weight Items

                        // We'll weight them based on distance, giving gold less weight and close objects more
                        //if (cacheObject.GoldAmount > 0)
                        //    cacheObject.Weight = 5000d - (Math.Floor(cacheObject.CentreDistance) * 2000d);
                        //else
                        //    cacheObject.Weight = 8000d - (Math.Floor(cacheObject.CentreDistance) * 1900d);

                        if (cacheObject.GoldAmount > 0)
                        {
                            cacheObject.Weight = (300 - cacheObject.CentreDistance) / 300 * 9000d;
                        }
                        else
                        {
                            cacheObject.Weight = (300 - cacheObject.CentreDistance) / 300 * 9000d;
                        }


                        // Point-blank items get a weight increase
                        if (cacheObject.GoldAmount <= 0 && cacheObject.CentreDistance <= 12f)
                        {
                            cacheObject.Weight += 1000d;
                        }

                        // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                        if (cacheObject.RActorGuid == CurrentTargetRactorGUID)
                        {
                            cacheObject.Weight += 800;
                        }

                        // Give yellows more weight
                        if (cacheObject.GoldAmount <= 0 && cacheObject.ItemQuality >= ItemQuality.Rare4)
                        {
                            cacheObject.Weight += 4000d;
                        }

                        // Give legendaries more weight
                        if (cacheObject.GoldAmount <= 0 && cacheObject.ItemQuality >= ItemQuality.Legendary)
                        {
                            cacheObject.Weight += 15000d;
                        }

                        // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority
                        //if (PrioritizeCloseRangeUnits)
                        //    cacheObject.Weight = (200f - cacheObject.CentreDistance) / 200f * 18000d;

                        if (PlayerStatus.ActorClass == ActorClass.Monk && TimeSinceUse(SNOPower.Monk_TempestRush) < 1000 && cacheObject.ItemQuality < ItemQuality.Legendary)
                        {
                            cacheObject.Weight = 500;
                        }

                        // If there's a monster in the path-line to the item, reduce the weight to 1, except legendaries
                        if (cacheObject.ItemQuality < ItemQuality.Legendary && hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius * 1.2f, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight = 1;
                        }

                        // ignore any items/gold if there is mobs in kill radius and we aren't combat looting
                        if (CurrentTarget != null && AnyMobsInRange && !Zeta.CommonBot.Settings.CharacterSettings.Instance.CombatLooting && cacheObject.ItemQuality < ItemQuality.Legendary)
                        {
                            cacheObject.Weight = 1;
                        }

                        // See if there's any AOE avoidance in that spot or inbetween us, if so reduce the weight to 1
                        if (hashAvoidanceObstacleCache.Any(aoe => cacheObject.Position.Distance2D(aoe.Location) <= aoe.Radius))
                        {
                            cacheObject.Weight = 1;
                        }

                        // ignore non-legendaries and gold near elites if we're ignoring elites
                        // not sure how we should safely determine this distance
                        if (Settings.Combat.Misc.IgnoreElites && cacheObject.ItemQuality < ItemQuality.Legendary &&
                            GilesObjectCache.Any(u => u.Type == GObjectType.Unit && u.IsEliteRareUnique && u.Position.Distance2D(cacheObject.Position) <= 40f))
                        {
                            cacheObject.Weight = 0;
                        }

                        break;
                    }

                    case GObjectType.Globe:
                    {
                        // Weight Health Globes

                        // Give all globes 0 weight (so never gone-to), unless we have low health, then go for them
                        if (PlayerStatus.CurrentHealthPct > PlayerEmergencyHealthGlobeLimit || !Settings.Combat.Misc.CollectHealthGlobe)
                        {
                            cacheObject.Weight = 0;
                        }
                        else
                        {
                            // Ok we have globes enabled, and our health is low...!
                            cacheObject.Weight = (300f - cacheObject.RadiusDistance) / 300f * 17000d;

                            // Point-blank items get a weight increase
                            if (cacheObject.CentreDistance <= 15f)
                            {
                                cacheObject.Weight += 3000d;
                            }

                            // Close items get a weight increase
                            if (cacheObject.CentreDistance <= 60f)
                            {
                                cacheObject.Weight += 1500d;
                            }

                            // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                            if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                            {
                                cacheObject.Weight += 800;
                            }

                            // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority
                            //if (bPrioritizeCloseRange)

                            //    thisgilesobject.dThisWeight = 22000 - (Math.Floor(thisgilesobject.fCentreDistance) * 200);

                            // If there's a monster in the path-line to the item, reduce the weight by 15% for each
                            Vector3 point = cacheObject.Position;
                            foreach (GilesObstacle tempobstacle in hashMonsterObstacleCache.Where(cp =>
                                                                                                  MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, point)))
                            {
                                cacheObject.Weight *= 0.85;
                            }

                            // See if there's any AOE avoidance in that spot, if so reduce the weight by 10%
                            if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                            {
                                cacheObject.Weight *= 0.9;
                            }

                            // Calculate a spot reaching a little bit further out from the globe, to help globe-movements
                            if (cacheObject.Weight > 0)
                            {
                                cacheObject.Position = MathEx.CalculatePointFrom(cacheObject.Position, PlayerStatus.CurrentPosition, cacheObject.CentreDistance + 3f);
                            }

                            // do not collect health globes if we are kiting and health globe is too close to monster or avoidance
                            if (PlayerKiteDistance > 0)
                            {
                                if (hashMonsterObstacleCache.Any(m => m.Location.Distance(cacheObject.Position) < PlayerKiteDistance))
                                {
                                    cacheObject.Weight = 0;
                                }
                                if (hashAvoidanceObstacleCache.Any(m => m.Location.Distance(cacheObject.Position) < PlayerKiteDistance))
                                {
                                    cacheObject.Weight = 0;
                                }
                            }
                        }
                        break;
                    }

                    case GObjectType.HealthWell:
                    {
                        // Healths Wells get handled correctly ...
                        if (cacheObject.Type == GObjectType.HealthWell && PlayerStatus.CurrentHealthPct <= .75)
                        {
                            cacheObject.Weight += 7500;
                        }
                        if (cacheObject.Type == GObjectType.HealthWell && PlayerStatus.CurrentHealthPct <= .25)
                        {
                            cacheObject.Weight += 20000d;
                        }
                        break;
                    }

                    case GObjectType.Shrine:
                    {
                        // Weight Shrines
                        cacheObject.Weight = (75f - cacheObject.RadiusDistance) / 75f * 14500f;

                        // Very close shrines get a weight increase
                        if (cacheObject.CentreDistance <= 30f)
                        {
                            cacheObject.Weight += 10000d;
                        }

                        if (cacheObject.Weight > 0)
                        {
                            // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                            if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                            {
                                cacheObject.Weight += 400;
                            }

                            // If there's a monster in the path-line to the item
                            if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                            {
                                cacheObject.Weight = 1;
                            }

                            // See if there's any AOE avoidance in that spot, if so reduce the weight to 1
                            if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                            {
                                cacheObject.Weight = 1;
                            }

                            // if there's any monsters nearby
                            if (TargetUtil.AnyMobsInRange(15f))
                            {
                                cacheObject.Weight = 1;
                            }

                            if (PrioritizeCloseRangeUnits)
                            {
                                cacheObject.Weight = 1;
                            }
                        }
                        break;
                    }

                    case GObjectType.Door:
                    {
                        if (!GilesObjectCache.Any(u => u.Type == GObjectType.Unit && u.HitPointsPct > 0 &&
                                                  MathUtil.IntersectsPath(u.Position, u.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            if (cacheObject.RadiusDistance <= 20f)
                            {
                                cacheObject.Weight += 15000d;
                            }

                            // We're standing on the damn thing... open it!!
                            if (cacheObject.RadiusDistance <= 12f)
                            {
                                cacheObject.Weight += 30000d;
                            }
                        }
                        break;
                    }

                    case GObjectType.Destructible:
                    case GObjectType.Barricade:
                    {
                        // rrrix added this as a single "weight" source based on the DestructableRange.
                        // Calculate the weight based on distance, where a distance = 1 is 5000, 90 = 0
                        cacheObject.Weight = (90f - cacheObject.RadiusDistance) / 90f * 5000f;

                        // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                        if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                        {
                            cacheObject.Weight += 400;
                        }

                        //// Close destructibles get a weight increase
                        //if (cacheObject.CentreDistance <= 16f)
                        //    cacheObject.Weight += 1500d;

                        // If there's a monster in the path-line to the item, reduce the weight by 50%
                        if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight *= 0.5;
                        }

                        // See if there's any AOE avoidance in that spot, if so reduce the weight to 1
                        if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight = 1;
                        }

                        // Are we prioritizing close-range stuff atm? If so limit it at a value 3k lower than monster close-range priority
                        if (PrioritizeCloseRangeUnits)
                        {
                            cacheObject.Weight = (200d - cacheObject.CentreDistance) / 200d * 19200d;
                        }

                        //// We're standing on the damn thing... break it
                        if (cacheObject.RadiusDistance <= 5f)
                        {
                            cacheObject.Weight += 40000d;
                        }

                        //// Fix for WhimsyShire Pinata
                        if (hashSNOContainerResplendant.Contains(cacheObject.ActorSNO))
                        {
                            cacheObject.Weight = 100 + cacheObject.RadiusDistance;
                        }
                        break;
                    }

                    case GObjectType.Interactable:
                    {
                        // Weight Interactable Specials

                        // Very close interactables get a weight increase
                        cacheObject.Weight = (90d - cacheObject.CentreDistance) / 90d * 15000d;
                        if (cacheObject.CentreDistance <= 12f)
                        {
                            cacheObject.Weight += 1000d;
                        }

                        // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                        if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                        {
                            cacheObject.Weight += 400;
                        }

                        // If there's a monster in the path-line to the item, reduce the weight by 50%
                        if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight *= 0.5;
                        }

                        // See if there's any AOE avoidance in that spot, if so reduce the weight to 1
                        if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight = 1;
                        }

                        //if (bAnyMobsInCloseRange || (CurrentTarget != null && CurrentTarget.IsBossOrEliteRareUnique))
                        //    cacheObject.Weight = 1;

                        break;
                    }

                    case GObjectType.Container:
                    {
                        // Weight Containers

                        // Very close containers get a weight increase
                        cacheObject.Weight = (190d - cacheObject.CentreDistance) / 190d * 11000d;
                        if (cacheObject.CentreDistance <= 12f)
                        {
                            cacheObject.Weight += 600d;
                        }

                        // Was already a target and is still viable, give it some free extra weight, to help stop flip-flopping between two targets
                        if (cacheObject.RActorGuid == CurrentTargetRactorGUID && cacheObject.CentreDistance <= 25f)
                        {
                            cacheObject.Weight += 400;
                        }

                        // If there's a monster in the path-line to the item, reduce the weight by 50%
                        if (hashMonsterObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight *= 0.5;
                        }

                        // See if there's any AOE avoidance in that spot, if so reduce the weight to 1
                        if (hashAvoidanceObstacleCache.Any(cp => MathUtil.IntersectsPath(cp.Location, cp.Radius, PlayerStatus.CurrentPosition, cacheObject.Position)))
                        {
                            cacheObject.Weight = 1;
                        }
                        break;
                    }
                    }

                    // Switch on object type

                    // Force the character to stay where it is if there is nothing available that is out of avoidance stuff and we aren't already in avoidance stuff
                    if (cacheObject.Weight == 1 && !StandingInAvoidance && GilesObjectCache.Any(o => o.Type == GObjectType.Avoidance))
                    {
                        cacheObject.Weight           = 0;
                        ShouldStayPutDuringAvoidance = true;
                    }
                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.Weight,
                                 "Weight={2:0} target= {0} ({1}) type={3} R-Dist={4:0} IsElite={5} RAGuid={6} {7}",
                                 cacheObject.InternalName, cacheObject.ActorSNO, cacheObject.Weight, cacheObject.Type, cacheObject.RadiusDistance, cacheObject.IsElite, cacheObject.RActorGuid, unitWeightInfo);

                    // Prevent current target dynamic ranged weighting flip-flop
                    if (CurrentTargetRactorGUID == cacheObject.RActorGuid && cacheObject.Weight <= 1)
                    {
                        cacheObject.Weight = 100;
                    }

                    // Is the weight of this one higher than the current-highest weight? Then make this the new primary target!
                    if (cacheObject.Weight > w_HighestWeightFound && cacheObject.Weight > 0)
                    {
                        // Clone the current Giles-cache object
                        CurrentTarget        = cacheObject.Clone();
                        w_HighestWeightFound = cacheObject.Weight;

                        // See if we can try attempting kiting later
                        NeedToKite      = false;
                        vKitePointAvoid = vNullLocation;

                        // Kiting and Avoidance
                        if (CurrentTarget.Type == GObjectType.Unit)
                        {
                            var AvoidanceList = hashAvoidanceObstacleCache.Where(o =>
                                                                                 // Distance from avoidance to target is less than avoidance radius
                                                                                 o.Location.Distance(CurrentTarget.Position) <= (GetAvoidanceRadius(o.ActorSNO) * 1.2) &&
                                                                                 // Distance from obstacle to me is <= cacheObject.RadiusDistance
                                                                                 o.Location.Distance(PlayerStatus.CurrentPosition) <= (cacheObject.RadiusDistance - 4f)
                                                                                 );

                            // if there's any obstacle within a specified distance of the avoidance radius *1.2
                            if (AvoidanceList.Any())
                            {
                                foreach (GilesObstacle o in AvoidanceList)
                                {
                                    DbHelper.Log(TrinityLogLevel.Debug, LogCategory.Targetting, "Avoidance: Id={0} Weight={1} Loc={2} Radius={3} Name={4}", o.ActorSNO, o.Weight, o.Location, o.Radius, o.Name);
                                }

                                vKitePointAvoid = CurrentTarget.Position;
                                NeedToKite      = true;
                            }
                        }
                    }
                }

                // Loop through all the objects and give them a weight
                if (CurrentTarget != null && CurrentTarget.InternalName != null && CurrentTarget.ActorSNO > 0 && CurrentTarget.RActorGuid != CurrentTargetRactorGUID)
                {
                    RecordTargetHistory();

                    DbHelper.Log(TrinityLogLevel.Verbose,
                                 LogCategory.Targetting,
                                 "Target changed to name={2} sno={0} type={1} raGuid={3}",
                                 CurrentTarget.InternalName,
                                 CurrentTarget.ActorSNO,
                                 CurrentTarget.Type,
                                 CurrentTarget.RActorGuid);
                }
            }
        }