Exemplo n.º 1
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);
            }
        }
Exemplo n.º 2
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);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Returns an appropriately selected GilesPower and related information
        /// </summary>
        /// <param name="IsCurrentlyAvoiding">Are we currently avoiding?</param>
        /// <param name="UseOOCBuff">Buff Out Of Combat</param>
        /// <param name="UseDestructiblePower">Is this for breaking destructables?</param>
        /// <returns></returns>
        internal static TrinityPower AbilitySelector(bool IsCurrentlyAvoiding = false, bool UseOOCBuff = false, bool UseDestructiblePower = false)
        {
            using (new PerformanceLogger("GilesAbilitySelector"))
            {
                // See if archon just appeared/disappeared, so update the hotbar
                if (ShouldRefreshHotbarAbilities)
                {
                    GilesPlayerCache.RefreshHotbar();
                }

                // Switch based on the cached character class

                TrinityPower power = CurrentPower;

                using (new PerformanceLogger("AbilitySelector.ClassAbility"))
                {
                    switch (PlayerStatus.ActorClass)
                    {
                    // Barbs
                    case ActorClass.Barbarian:
                        power = GetBarbarianPower(IsCurrentlyAvoiding, UseOOCBuff, UseDestructiblePower);
                        break;

                    // Monks
                    case ActorClass.Monk:
                        power = GetMonkPower(IsCurrentlyAvoiding, UseOOCBuff, UseDestructiblePower);
                        break;

                    // Wizards
                    case ActorClass.Wizard:
                        power = GetWizardPower(IsCurrentlyAvoiding, UseOOCBuff, UseDestructiblePower);
                        break;

                    // Witch Doctors
                    case ActorClass.WitchDoctor:
                        power = GetWitchDoctorPower(IsCurrentlyAvoiding, UseOOCBuff, UseDestructiblePower);
                        break;

                    // Demon Hunters
                    case ActorClass.DemonHunter:
                        power = GetDemonHunterPower(IsCurrentlyAvoiding, UseOOCBuff, UseDestructiblePower);
                        break;
                    }
                }
                // use IEquatable to check if they're equal
                if (CurrentPower == power)
                {
                    DbHelper.Log(LogCategory.Behavior, "Keeping {0}", CurrentPower.ToString());
                    return(CurrentPower);
                }
                else if (power != null)
                {
                    DbHelper.Log(LogCategory.Behavior, "Selected new {0}", power.ToString());
                    return(power);
                }
                else
                {
                    return(defaultPower);
                }
            }
        }