/// <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); } }
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); }