Ejemplo n.º 1
0
        /// <summary>
        /// Re-reads the active assigned skills and runes from thoe hotbar
        /// </summary>
        internal static void RefreshHotbar()
        {
            using (new PerformanceLogger("RefreshHotbar"))
            {
                // Update Hotbar Skills first
                HotbarSkills.Update();

                SpellTracker.RefreshCachedSpells();

                if (!Trinity.GetHasBuff(SNOPower.Wizard_Archon) && !Player.IsHidden)
                {
                    Trinity.hashCachedPowerHotbarAbilities = new List <SNOPower>(Trinity.Hotbar);
                }
            }

            // Monk Seven Sided Strike: Sustained Attack
            if (Player.ActorClass == ActorClass.Monk && HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_SevenSidedStrike && s.RuneIndex == 3))
            {
                CombatBase.SetSNOPowerUseDelay(SNOPower.Monk_SevenSidedStrike, 17000);
            }

            if (Player.ActorClass == ActorClass.Witchdoctor && HotbarSkills.PassiveSkills.Contains(SNOPower.Witchdoctor_Passive_GraveInjustice))
            {
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_SoulHarvest, 1000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_SpiritWalk, 1000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_Horrify, 1000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_Gargantuan, 20000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_SummonZombieDog, 20000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_GraspOfTheDead, 500);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_SpiritBarrage, 2000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_Locust_Swarm, 2000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_Haunt, 2000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_Hex, 3000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_MassConfusion, 15000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_FetishArmy, 20000);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Witchdoctor_BigBadVoodoo, 20000);
            }
            if (Player.ActorClass == ActorClass.Barbarian && HotbarSkills.PassiveSkills.Contains(SNOPower.Barbarian_Passive_BoonOfBulKathos))
            {
                CombatBase.SetSNOPowerUseDelay(SNOPower.Barbarian_Earthquake, 90500);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Barbarian_CallOfTheAncients, 90500);
                CombatBase.SetSNOPowerUseDelay(SNOPower.Barbarian_WrathOfTheBerserker, 90500);
            }
        }
Ejemplo n.º 2
0
        private static TrinityPower GetMonkPower(bool IsCurrentlyAvoiding, bool UseOOCBuff, bool UseDestructiblePower)
        {
            if (UseDestructiblePower)
            {
                return(GetMonkDestroyPower());
            }

            // Monks need 80 for special spam like tempest rushing
            MinEnergyReserve = 80;


            // Epiphany
            // Desert shroud: reduce incoming damage by 50%
            bool hasDesertShroud = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_Monk_Epiphany && s.RuneIndex == 0);
            // Soothing Mist: heal self and allies for 4129+(0.25*HealthGlobeBonus) life
            bool hasSoothingMist = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_Monk_Epiphany && s.RuneIndex == 1);

            //Inner Fire X1_Monk_Epiphany/3/HotbarSlot3
            //Windwalker  X1_Monk_Epiphany/2/HotbarSlot3
            //Soothing Mist X1_Monk_Epiphany/1/HotbarSlot3
            //Ascendance X1_Monk_Epiphany/4/HotbarSlot3
            //Desert Shroud  X1_Monk_Epiphany/0/HotbarSlot3
            //None   X1_Monk_Epiphany/0/HotbarSlot3

            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.X1_Monk_Epiphany, CombatBase.CanCastFlags.NoTimer) &&
                (TargetUtil.EliteOrTrashInRange(15f) || TargetUtil.AnyMobsInRange(15f, 5)) &&
                (Player.PrimaryResourcePct < 0.50 || ((hasDesertShroud || hasSoothingMist) && Player.CurrentHealthPct < 0.50))
                )
            {
                return(new TrinityPower(SNOPower.X1_Monk_Epiphany));
            }

            //// Monk - Primary

            bool hasThunderClap = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_FistsofThunder && s.RuneIndex == 0);
            //bool hasLightningFlash = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_FistsofThunder && s.RuneIndex == 4);
            //bool hasStaticCharge = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_FistsofThunder && s.RuneIndex == 3);
            //bool hasQuickening = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_FistsofThunder && s.RuneIndex == 3);
            //bool hasBoundingLight = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_FistsofThunder && s.RuneIndex == 1);

            //bool hasPiercingTrident = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_DeadlyReach && s.RuneIndex == 1);
            //bool hasKeenEye = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_DeadlyReach && s.RuneIndex == 4);
            //bool hasScatteredBlows = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_DeadlyReach && s.RuneIndex == 2);
            //bool hasStrikeFromBeyond = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_DeadlyReach && s.RuneIndex == 3);
            bool hasForesight = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_DeadlyReach && s.RuneIndex == 0);

            //bool hasMangle = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CripplingWave && s.RuneIndex == 0);
            //bool hasConcussion = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CripplingWave && s.RuneIndex == 2);
            //bool hasRisingTide = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CripplingWave && s.RuneIndex == 3);
            //bool hasTsunami = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CripplingWave && s.RuneIndex == 1);
            //bool hasBreakingWave = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CripplingWave && s.RuneIndex == 4);

            //bool hasHandsOfLightning = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WayOfTheHundredFists && s.RuneIndex == 1);
            bool hasBlazingFists = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WayOfTheHundredFists && s.RuneIndex == 2);
            bool hasFistsOfFury  = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WayOfTheHundredFists && s.RuneIndex == 0);
            //bool hasSpiritedSalvo = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WayOfTheHundredFists && s.RuneIndex == 3);
            //bool hasWindforceFlurry = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WayOfTheHundredFists && s.RuneIndex == 4);

            // Breath of Heaven Rune
            bool hasInfusedWithLight = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_BreathOfHeaven && s.RuneIndex == 3);

            // Serenity if health is low
            if ((Player.CurrentHealthPct <= 0.50 || (Player.IsIncapacitated && Player.CurrentHealthPct <= 0.90)) && CombatBase.CanCast(SNOPower.Monk_Serenity))
            {
                return(new TrinityPower(SNOPower.Monk_Serenity, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1));
            }

            // Mystic ally
            if (CombatBase.CanCast(SNOPower.X1_Monk_MysticAlly_v2) && TargetUtil.EliteOrTrashInRange(30f))
            {
                return(new TrinityPower(SNOPower.X1_Monk_MysticAlly_v2, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 2, 2));
            }

            // InnerSanctuary
            if (!UseOOCBuff && TargetUtil.EliteOrTrashInRange(16f) && CombatBase.CanCast(SNOPower.X1_Monk_InnerSanctuary))
            {
                return(new TrinityPower(SNOPower.X1_Monk_InnerSanctuary, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1));
            }

            // Blinding Flash
            if (!UseOOCBuff && Player.PrimaryResource >= 20 && CombatBase.CanCast(SNOPower.Monk_BlindingFlash) &&
                (
                    TargetUtil.AnyElitesInRange(15, 1) ||
                    Player.CurrentHealthPct <= 0.4 ||
                    (TargetUtil.AnyMobsInRange(15, 3)) ||
                    (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance <= 15f) ||
                    // as pre-sweeping wind buff
                    (TargetUtil.AnyMobsInRange(15, 1) && CombatBase.CanCast(SNOPower.Monk_SweepingWind) && !GetHasBuff(SNOPower.Monk_SweepingWind) && Settings.Combat.Monk.HasInnaSet)
                ) &&
                // Check if either we don't have sweeping winds, or we do and it's ready to cast in a moment
                (CheckAbilityAndBuff(SNOPower.Monk_SweepingWind) ||
                 (!GetHasBuff(SNOPower.Monk_SweepingWind) &&
                  (CombatBase.CanCast(SNOPower.Monk_SweepingWind, CombatBase.CanCastFlags.NoTimer))) ||
                 Player.CurrentHealthPct <= 0.25))
            {
                return(new TrinityPower(SNOPower.Monk_BlindingFlash, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 1));
            }

            // Blinding Flash as a DEFENSE
            if (!UseOOCBuff && Player.PrimaryResource >= 10 && CombatBase.CanCast(SNOPower.Monk_BlindingFlash) &&
                Player.CurrentHealthPct <= 0.75 && TargetUtil.AnyMobsInRange(15, 1))
            {
                return(new TrinityPower(SNOPower.Monk_BlindingFlash, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 1));
            }

            // Breath of Heaven when needing healing or the buff
            if (!UseOOCBuff && (Player.CurrentHealthPct <= 0.6 || !GetHasBuff(SNOPower.Monk_BreathOfHeaven)) && CombatBase.CanCast(SNOPower.Monk_BreathOfHeaven) &&
                (Player.PrimaryResource >= 35 || (!CombatBase.CanCast(SNOPower.Monk_Serenity) && Player.PrimaryResource >= 25)))
            {
                return(new TrinityPower(SNOPower.Monk_BreathOfHeaven, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1));
            }

            // Breath of Heaven for spirit - Infused with Light
            if (!UseOOCBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Monk_BreathOfHeaven) && !GetHasBuff(SNOPower.Monk_BreathOfHeaven) && hasInfusedWithLight &&
                (TargetUtil.AnyMobsInRange(3, 20) || TargetUtil.IsEliteTargetInRange(20)) && Player.PrimaryResourcePct < 0.75)
            {
                return(new TrinityPower(SNOPower.Monk_BreathOfHeaven, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1));
            }


            // Seven Sided Strike
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated &&
                (TargetUtil.AnyElitesInRange(15, 1) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance <= 15f) || Player.CurrentHealthPct <= 0.55) &&
                CombatBase.CanCast(SNOPower.Monk_SevenSidedStrike, CombatBase.CanCastFlags.NoTimer) &&
                ((Player.PrimaryResource >= 50 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_SevenSidedStrike, 16f, CurrentTarget.Position, CurrentWorldDynamicId, -1, 2, 3));
            }

            // WayOfTheHundredFists: apply fists of fury DoT if we have Infused with Light buff + WotHF:FoF
            if (!UseOOCBuff && hasInfusedWithLight && hasFistsOfFury && GetHasBuff(SNOPower.Monk_BreathOfHeaven) && !CurrentTarget.HasDotDPS)
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_WayOfTheHundredFists, 14f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1));
            }


            // Sweeping winds spam
            if ((Player.PrimaryResource >= 75 || (Settings.Combat.Monk.HasInnaSet && Player.PrimaryResource >= 5)) &&
                CombatBase.CanCast(SNOPower.Monk_SweepingWind, CombatBase.CanCastFlags.NoTimer) && GetHasBuff(SNOPower.Monk_SweepingWind) &&
                DateTime.UtcNow.Subtract(SweepWindSpam).TotalMilliseconds >= 4000 && DateTime.UtcNow.Subtract(SweepWindSpam).TotalMilliseconds <= 5400)
            {
                SweepWindSpam = DateTime.UtcNow;
                return(new TrinityPower(SNOPower.Monk_SweepingWind, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 0));
            }

            bool  hasTranscendance      = HotbarSkills.PassiveSkills.Any(s => s == SNOPower.Monk_Passive_Transcendence);
            float minSweepingWindSpirit = Settings.Combat.Monk.HasInnaSet ? 5f : 75f;

            // Sweeping wind
            if (!UseOOCBuff && CombatBase.CanCast(SNOPower.Monk_SweepingWind) && !GetHasBuff(SNOPower.Monk_SweepingWind) &&
                ((TargetUtil.AnyElitesInRange(25, 1) || TargetUtil.AnyMobsInRange(20, 1) || Settings.Combat.Monk.HasInnaSet ||
                  (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance <= 25f)) &&
                 // Check our mantras, if we have them, are up first
                 Monk_HasMantraAbilityAndBuff() &&
                 // Check if either we don't have blinding flash, or we do and it's been cast in the last 8000ms
                 (TimeSinceUse(SNOPower.Monk_BlindingFlash) <= 8000 || CheckAbilityAndBuff(SNOPower.Monk_BlindingFlash) ||
                  TargetUtil.AnyElitesInRange(25, 1) && TimeSinceUse(SNOPower.Monk_BlindingFlash) <= 12500)) &&
                Player.PrimaryResource >= minSweepingWindSpirit)
            {
                SweepWindSpam = DateTime.UtcNow;
                return(new TrinityPower(SNOPower.Monk_SweepingWind, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 0));
            }

            // Sweeping Wind for Transcendance Health Regen
            if (CombatBase.CanCast(SNOPower.Monk_SweepingWind, CombatBase.CanCastFlags.NoTimer) &&
                Player.PrimaryResource >= minSweepingWindSpirit &&
                hasTranscendance && Settings.Combat.Monk.SpamSweepingWindOnLowHP &&
                Player.CurrentHealthPct <= V.F("Monk.SweepingWind.SpamOnLowHealthPct") &&
                TimeSinceUse(SNOPower.Monk_SweepingWind) > 500)
            {
                SweepWindSpam = DateTime.UtcNow;
                return(new TrinityPower(SNOPower.Monk_SweepingWind, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 0));
            }

            //skillDict.Add("BreathOfHeaven", SNOPower.Monk_BreathOfHeaven);
            //runeDict.Add("CircleOfScorn", 0);
            //runeDict.Add("CircleOfLife", 1);
            //runeDict.Add("BlazingWrath", 2);
            //runeDict.Add("InfusedWithLight", 3);
            //runeDict.Add("PenitentFlame", 4);

            // Exploding Palm
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated &&
                CombatBase.CanCast(SNOPower.Monk_ExplodingPalm, CombatBase.CanCastFlags.NoTimer) &&
                !SpellTracker.IsUnitTracked(CurrentTarget, SNOPower.Monk_ExplodingPalm) &&
                Player.PrimaryResource >= 40)
            {
                return(new TrinityPower(SNOPower.Monk_ExplodingPalm, 14f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 1, 1));
            }

            //SkillDict.Add("WaveOfLight", SNOPower.Monk_WaveOfLight);
            //RuneDict.Add("WallOfLight", 0);
            //RuneDict.Add("ExplosiveLight", 1);
            //RuneDict.Add("EmpoweredWave", 3);
            //RuneDict.Add("BlindingLight", 4);
            //RuneDict.Add("PillarOfTheAncients", 2);
            //bool hasEmpoweredWaveRune = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WaveOfLight && s.RuneIndex == 3);

            bool hasEmpoweredWaveRune = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_WaveOfLight && s.RuneIndex == 3);
            var  minWoLSpirit         = hasEmpoweredWaveRune ? 40 : 75;

            // Wave of light
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Monk_WaveOfLight) &&
                (TargetUtil.AnyMobsInRange(16f, Settings.Combat.Monk.MinWoLTrashCount) || TargetUtil.IsEliteTargetInRange(20f)) &&
                (Player.PrimaryResource >= minWoLSpirit && !IsWaitingForSpecial || Player.PrimaryResource > MinEnergyReserve) &&
                // optional check for SW stacks
                (Settings.Combat.Monk.SWBeforeWoL && (CheckAbilityAndBuff(SNOPower.Monk_SweepingWind) && GetBuffStacks(SNOPower.Monk_SweepingWind) == 3) || !Settings.Combat.Monk.SWBeforeWoL) &&
                Monk_HasMantraAbilityAndBuff())
            {
                var bestClusterPoint = TargetUtil.GetBestClusterPoint(15f, 15f);
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_WaveOfLight, 16f, bestClusterPoint, -1, CurrentTarget.ACDGuid, 0, 1));
            }

            //SkillDict.Add("CycloneStrike", SNOPower.Monk_CycloneStrike);
            //RuneDict.Add("EyeOfTheStorm", 3);
            //RuneDict.Add("Implosion", 1);
            //RuneDict.Add("Sunburst", 0);
            //RuneDict.Add("WallOfWind", 4);
            //RuneDict.Add("SoothingBreeze", 2);

            bool hasCycloneStikeEyeOfTheStorm = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CycloneStrike && s.RuneIndex == 3);
            bool hasCycloneStikeImposion      = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Monk_CycloneStrike && s.RuneIndex == 1);

            var cycloneStrikeRange  = hasCycloneStikeImposion ? 34f : 24f;
            var cycloneStrikeSpirit = hasCycloneStikeEyeOfTheStorm ? 30 : 50;

            // Cyclone Strike
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Monk_CycloneStrike) &&
                (
                    TargetUtil.AnyElitesInRange(cycloneStrikeRange, 1) ||
                    TargetUtil.AnyMobsInRange(cycloneStrikeRange, Settings.Combat.Monk.MinCycloneTrashCount) ||
                    (CurrentTarget.RadiusDistance >= 15f && CurrentTarget.RadiusDistance <= cycloneStrikeRange) // pull the current target into attack range
                ) &&
                (Player.PrimaryResource >= (cycloneStrikeSpirit + MinEnergyReserve)))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_CycloneStrike, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 2, 2));
            }

            // For tempest rush re-use
            if (!UseOOCBuff && Player.PrimaryResource >= 15 && CombatBase.CanCast(SNOPower.Monk_TempestRush) &&
                TimeSinceUse(SNOPower.Monk_TempestRush) <= 150 &&
                ((Settings.Combat.Monk.TROption != TempestRushOption.MovementOnly) &&
                 !(Settings.Combat.Monk.TROption == TempestRushOption.TrashOnly && TargetUtil.AnyElitesInRange(40f))))
            {
                GenerateMonkZigZag();
                MaintainTempestRush = true;
                const string trUse = "Continuing Tempest Rush for Combat";
                Monk_TempestRushStatus(trUse);
                return(new TrinityPower(SNOPower.Monk_TempestRush, 23f, CombatBase.ZigZagPosition, CurrentWorldDynamicId, -1, 0, 0));
            }

            // Tempest rush at elites or groups of mobs
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated && !Player.IsRooted && CombatBase.CanCast(SNOPower.Monk_TempestRush) &&
                ((Player.PrimaryResource >= Settings.Combat.Monk.TR_MinSpirit && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve) &&
                (Settings.Combat.Monk.TROption == TempestRushOption.Always ||
                 Settings.Combat.Monk.TROption == TempestRushOption.CombatOnly ||
                 (Settings.Combat.Monk.TROption == TempestRushOption.ElitesGroupsOnly && (TargetUtil.AnyElitesInRange(25) || TargetUtil.AnyMobsInRange(25, 2))) ||
                 (Settings.Combat.Monk.TROption == TempestRushOption.TrashOnly && !TargetUtil.AnyElitesInRange(90f) && TargetUtil.AnyMobsInRange(40f))))
            {
                GenerateMonkZigZag();
                MaintainTempestRush = true;
                const string trUse = "Starting Tempest Rush for Combat";
                Monk_TempestRushStatus(trUse);
                return(new TrinityPower(SNOPower.Monk_TempestRush, 23f, CombatBase.ZigZagPosition, CurrentWorldDynamicId, -1, 0, 0));
            }

            // Lashing Tail Kick
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_LashingTailKick) && !Player.IsIncapacitated &&
                // Either doesn't have sweeping wind, or does but the buff is already up
                (!Hotbar.Contains(SNOPower.Monk_SweepingWind) || (Hotbar.Contains(SNOPower.Monk_SweepingWind) && GetHasBuff(SNOPower.Monk_SweepingWind))) &&
                ((Player.PrimaryResource >= 65 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_LashingTailKick, 10f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 1, 1));
            }

            // Dashing Strike
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated && CurrentTarget.Distance >= 16f &&
                CombatBase.CanCast(SNOPower.X1_Monk_DashingStrike, CombatBase.CanCastFlags.NoTimer))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.X1_Monk_DashingStrike, Monk_MaxDashingStrikeRange, CurrentTarget.Position, CurrentWorldDynamicId, -1, 2, 2));
            }

            // 4 Mantra spam for the 4 second buff
            if (!UseOOCBuff && !IsCurrentlyAvoiding && !Player.IsIncapacitated && !Settings.Combat.Monk.DisableMantraSpam)
            {
                if (CombatBase.CanCast(SNOPower.X1_Monk_MantraOfConviction_v2) && !GetHasBuff(SNOPower.X1_Monk_MantraOfConviction_v2) &&
                    (Player.PrimaryResource >= 50) && CurrentTarget != null)
                {
                    return(new TrinityPower(SNOPower.X1_Monk_MantraOfConviction_v2));
                }

                if (CombatBase.CanCast(SNOPower.X1_Monk_MantraOfRetribution_v2) && !GetHasBuff(SNOPower.X1_Monk_MantraOfRetribution_v2) &&
                    (Player.PrimaryResource >= 50) && CurrentTarget != null)
                {
                    return(new TrinityPower(SNOPower.X1_Monk_MantraOfRetribution_v2));
                }
            }

            //Use Mantra of Healing active if health is low for shield.
            if (CombatBase.CanCast(SNOPower.X1_Monk_MantraOfHealing_v2) && Player.CurrentHealthPct <= V.F("Monk.MantraOfHealing.UseHealthPct") &&
                !Player.IsIncapacitated && !GetHasBuff(SNOPower.X1_Monk_MantraOfHealing_v2))
            {
                return(new TrinityPower(SNOPower.X1_Monk_MantraOfHealing_v2));
            }

            if (CombatBase.CanCast(SNOPower.X1_Monk_MantraOfEvasion_v2) && Player.CurrentHealthPct <= V.F("Monk.MantraOfHealing.UseHealthPct") &&
                !GetHasBuff(SNOPower.X1_Monk_MantraOfEvasion_v2) && CurrentTarget != null)
            {
                return(new TrinityPower(SNOPower.X1_Monk_MantraOfEvasion_v2));
            }


            /*
             * Dual/Trigen Monk section
             *
             * Cycle through Deadly Reach, Way of the Hundred Fists, and Fists of Thunder every 3 seconds to keep 8% passive buff up if we have Combination Strike
             *  - or -
             * Keep Foresight and Blazing Fists buffs up every 30/5 seconds
             */
            bool hasCombinationStrike = HotbarSkills.PassiveSkills.Any(s => s == SNOPower.Monk_Passive_CombinationStrike);
            bool isDualOrTriGen       = HotbarSkills.AssignedSkills.Count(s =>
                                                                          s.Power == SNOPower.Monk_DeadlyReach ||
                                                                          s.Power == SNOPower.Monk_WayOfTheHundredFists ||
                                                                          s.Power == SNOPower.Monk_FistsofThunder ||
                                                                          s.Power == SNOPower.Monk_CripplingWave) >= 2 && hasCombinationStrike;

            // interval in milliseconds for Generators
            int drInterval = 0;

            if (hasCombinationStrike)
            {
                drInterval = 2500;
            }
            else if (hasForesight)
            {
                drInterval = 29000;
            }

            int wothfInterval = 0;

            if (hasCombinationStrike)
            {
                wothfInterval = 2500;
            }
            else if (hasBlazingFists)
            {
                wothfInterval = 4500;
            }

            int cwInterval = 0;

            if (hasCombinationStrike)
            {
                cwInterval = 2500;
            }

            // Fists of Thunder:Thunder Clap - Fly to Target
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_FistsofThunder) && hasThunderClap && CurrentTarget.Distance > 16f)
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_FistsofThunder, 30f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Deadly Reach: Foresight, every 27 seconds or 2.7 seconds with combo strike
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_DeadlyReach) && (isDualOrTriGen || hasForesight) &&
                (SpellHistory.TimeSinceUse(SNOPower.Monk_DeadlyReach) > TimeSpan.FromMilliseconds(drInterval) ||
                 (SpellHistory.SpellUseCountInTime(SNOPower.Monk_DeadlyReach, TimeSpan.FromMilliseconds(27000)) < 3) && hasForesight))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_DeadlyReach, 16f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Way of the Hundred Fists: Blazing Fists, every 4-5ish seconds or if we don't have 3 stacks of the buff or or 2.7 seconds with combo strike
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_WayOfTheHundredFists) && (isDualOrTriGen || hasBlazingFists) &&
                (GetBuffStacks(SNOPower.Monk_WayOfTheHundredFists) < 3 ||
                 SpellHistory.TimeSinceUse(SNOPower.Monk_WayOfTheHundredFists) > TimeSpan.FromMilliseconds(wothfInterval)))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_WayOfTheHundredFists, 16f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Crippling Wave
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_CripplingWave) &&
                SpellHistory.TimeSinceUse(SNOPower.Monk_CripplingWave) > TimeSpan.FromMilliseconds(cwInterval))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_CripplingWave, 20f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Fists of Thunder
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_FistsofThunder))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_FistsofThunder, 30f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Deadly Reach normal
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_DeadlyReach))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_DeadlyReach, 16f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Way of the Hundred Fists normal
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_WayOfTheHundredFists))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_WayOfTheHundredFists, 16f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }

            // Crippling Wave Normal
            if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_CripplingWave))
            {
                Monk_TickSweepingWindSpam();
                return(new TrinityPower(SNOPower.Monk_CripplingWave, 30f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 3));
            }


            //// Fists of thunder as the primary, repeatable attack
            //if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_FistsofThunder)
            //    && (DateTime.UtcNow.Subtract(OtherThanDeadlyReach).TotalMilliseconds < 2700 && DateTime.UtcNow.Subtract(ForeSightFirstHit).TotalMilliseconds < 29000 || !Hotbar.Contains(SNOPower.Monk_DeadlyReach) || CurrentTarget.RadiusDistance > 12f ||
            //    !TargetUtil.AnyMobsInRange(50, 5) && !TargetUtil.AnyElitesInRange(50) && !WantToSwap))
            //{
            //    if (DateTime.UtcNow.Subtract(OtherThanDeadlyReach).TotalMilliseconds < 2700)
            //        OtherThanDeadlyReach = DateTime.UtcNow;
            //    Monk_TickSweepingWindSpam();
            //    return new TrinityPower(SNOPower.Monk_FistsofThunder, 30f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1);
            //}
            //// Crippling wave
            //if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_CripplingWave)
            //    && (DateTime.UtcNow.Subtract(OtherThanDeadlyReach).TotalMilliseconds < 2700 && DateTime.UtcNow.Subtract(ForeSightFirstHit).TotalMilliseconds < 29000 || !Hotbar.Contains(SNOPower.Monk_DeadlyReach)
            //    || !TargetUtil.AnyMobsInRange(50, 5) && !TargetUtil.AnyElitesInRange(50) && !WantToSwap))
            //{
            //    OtherThanDeadlyReach = DateTime.UtcNow;
            //    Monk_TickSweepingWindSpam();
            //    return new TrinityPower(SNOPower.Monk_CripplingWave, 14f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1);
            //}
            //// Way of hundred fists
            //if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_WayOfTheHundredFists)
            //    && (DateTime.UtcNow.Subtract(OtherThanDeadlyReach).TotalMilliseconds < 2700 && DateTime.UtcNow.Subtract(ForeSightFirstHit).TotalMilliseconds < 29000 || !Hotbar.Contains(SNOPower.Monk_DeadlyReach)
            //    || !TargetUtil.AnyMobsInRange(50, 5) && !TargetUtil.AnyElitesInRange(50) && !WantToSwap))
            //{
            //    OtherThanDeadlyReach = DateTime.UtcNow;
            //    Monk_TickSweepingWindSpam();
            //    return new TrinityPower(SNOPower.Monk_WayOfTheHundredFists, 14f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1);
            //}
            //// Deadly reach
            //if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Monk_DeadlyReach))
            //{
            //    if (DateTime.UtcNow.Subtract(ForeSightFirstHit).TotalMilliseconds > 29000)
            //    {
            //        ForeSightFirstHit = DateTime.UtcNow;
            //    }
            //    else if (DateTime.UtcNow.Subtract(ForeSight2).TotalMilliseconds > 400 && DateTime.UtcNow.Subtract(ForeSightFirstHit).TotalMilliseconds > 1400)
            //    {
            //        OtherThanDeadlyReach = DateTime.UtcNow;
            //    }
            //    if (DateTime.UtcNow.Subtract(ForeSight2).TotalMilliseconds > 2800)
            //    {
            //        ForeSight2 = DateTime.UtcNow;
            //    }
            //    Monk_TickSweepingWindSpam();
            //    return new TrinityPower(SNOPower.Monk_DeadlyReach, 16f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1);
            //}

            // Default attacks
            return(CombatBase.DefaultPower);
        }