public static async Task <CoroutineResult> DrinkPotion() { if (!ZetaDia.IsInGame || ZetaDia.Globals.IsLoadingWorld || ZetaDia.Globals.IsPlayingCutscene || ZetaDia.IsInTown || SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion) <= TimeSpan.FromSeconds(30) || ZetaDia.Me == null || !ZetaDia.Me.IsFullyValid() || ZetaDia.Me.IsDead || Combat.TrinityCombat.Routines.Current == null) { return(CoroutineResult.NoAction); } if (ZetaDia.Me.HitpointsCurrentPct > Combat.TrinityCombat.Routines.Current.PotionHealthPct) { return(CoroutineResult.NoAction); } if (ZetaDia.Me.IsFeared || ZetaDia.Me.IsStunned || ZetaDia.Me.IsFrozen || ZetaDia.Me.IsBlind || ZetaDia.Me.CommonData .GetAttribute <bool>(ActorAttributeType.PowerImmobilize)) { s_logger.Warning($"[{nameof(DrinkPotion)}] Can't use potion while incapacitated!"); return(CoroutineResult.NoAction); } if (ActivePotion == null) { s_logger.Warning($"[{nameof(DrinkPotion)}] No Available potions!"); return(CoroutineResult.NoAction); } s_logger.Information($"[{nameof(DrinkPotion)}] Using Potion {ActivePotion.Name}"); InventoryManager.UseItem(ActivePotion.AnnId); SpellHistory.RecordSpell(new TrinityPower(SNOPower.DrinkHealthPotion)); SnapShot.Record(); return(CoroutineResult.Done); }
protected bool IsRestricted(SkillSettings settings, Skill skill) { if (Player.PrimaryResourcePct < settings.PrimaryResourcePct / 100) { return(true); } if (Player.SecondaryResourcePct < settings.SecondaryResourcePct / 100) { return(true); } if (Player.CurrentHealthPct > settings.HealthPct) { return(true); } if (SpellHistory.TimeSinceUse(skill.SNOPower).TotalMilliseconds < settings.RecastDelayMs) { return(true); } if (settings.ClusterSize > 0 && !TargetUtil.ClusterExists(15f, settings.ClusterSize)) { return(true); } if (settings.WaitForConvention == ConventionMode.GreaterRift && !Core.Rift.IsGreaterRift) { return(true); } if (settings.WaitForConvention != ConventionMode.Never && settings.ConventionCondition != null && !settings.ConventionCondition()) { return(true); } return(false); }
public static bool ShouldUsePotion() { if (Core.Player == null || Combat.TrinityCombat.Routines.Current == null) { return(false); } if (Core.Player.CurrentHealthPct > Combat.TrinityCombat.Routines.Current.PotionHealthPct) { return(false); } if (Core.Player.IsIncapacitated || !(Core.Player.CurrentHealthPct > 0) || Core.Player.IsInTown) { return(false); } if (SpellHistory.TimeSinceUse(SNOPower.DrinkHealthPotion) <= TimeSpan.FromSeconds(30)) { return(false); } return(Core.Player.CurrentHealthPct <= Combat.TrinityCombat.Routines.Current.PotionHealthPct); }
public TrinityPower GetOffensivePower() { TrinityPower power; Vector3 position; if (TrySpecialPower(out power)) { return(power); } if (Core.Buffs.HasCastingShrine) { if (Skills.Monk.BlindingFlash.CanCast() && Legendary.TheLawsOfSeph.IsEquipped && Player.PrimaryResource < Player.PrimaryResourceMax - 165) { return(BlindingFlash()); } if (Skills.Monk.MysticAlly.CanCast() && Runes.Monk.AirAlly.IsActive && Player.PrimaryResource < Player.PrimaryResourceMax - 200) { return(MysticAlly()); } if (Skills.Monk.DashingStrike.CanCast() && !Skills.Monk.DashingStrike.IsLastUsed) { return(DashingStrike(CurrentTarget.Position)); } if (Skills.Monk.LashingTailKick.CanCast()) { return(LashingTailKick(CurrentTarget)); } } // With sweeping armada try to keep distance in the sweet spot between 10-15yd if (Runes.Monk.SweepingArmada.IsActive) { var enoughTimePassed = SpellHistory.TimeSinceUse(SNOPower.Walk).TotalMilliseconds > 500; var isSoloElite = TargetUtil.ElitesInRange(25f) == 1 && !AnyUnitsInRange(25f); if (enoughTimePassed && isSoloElite && CurrentTarget.RadiusDistance <= 10f && !IsStuck) { if (Avoider.TryGetSafeSpot(out position, 12f + CurrentTarget.CollisionRadius, 30f, CurrentTarget.Position)) { Core.Logger.Log(LogCategory.Routine, $"Adjusting Distance for Sweeping Armarda RDist={CurrentTarget.RadiusDistance} Dist={ZetaDia.Me.Position.Distance(CurrentTarget.Position)}"); return(Walk(position, 2f)); } } } if (TrySecondaryPower(out power)) { return(power); } if (TryPrimaryPower(out power)) { return(power); } if (IsNoPrimary) { // Stay away from hostile units when Regen skills are on cooldown and under [50] Spirit if (Skills.Monk.BlindingFlash.IsActive && Legendary.TheLawsOfSeph.IsEquipped || Skills.Monk.MysticAlly.IsActive && Runes.Monk.AirAlly.IsActive) { var regenOnCooldown = !Skills.Monk.BlindingFlash.CanCast() && !Skills.Monk.MysticAlly.CanCast(); var needResource = Player.PrimaryResource < PrimaryEnergyReserve; if ((regenOnCooldown || needResource) && HostileMonsters.Any(u => u.Distance <= 12f)) { Core.Logger.Log(LogCategory.Routine, "Moving away - Low Spirit - Regen on Cooldown"); return(Walk(TargetUtil.GetLoiterPosition(CurrentTarget, 30f))); } } } return(Walk(TargetUtil.GetLoiterPosition(CurrentTarget, 25f))); }
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); }
//public static class FireballTracker //{ // public static Dictionary<int,TrinityActor> Fireballs = new Dictionary<int, TrinityActor>(); // private static DateTime _lastUseTime; // public static bool IsFireballPending { get; private set; } // public const int FireballSnoId = (int) SNOActor.zoltunKulle_fieryBoulder_model; // public const int PendingTimeoutMs = 1000; // public static void Update() // { // var lastUseTime = SpellHistory.PowerLastUsedTime(SNOPower.Monk_LashingTailKick); // var msSinceUse = DateTime.UtcNow.Subtract(lastUseTime).TotalMilliseconds; // if (lastUseTime != _lastUseTime) // { // Core.Logger.Log($"New LTK cast, waiting for fireball"); // IsFireballPending = msSinceUse < PendingTimeoutMs; // _lastUseTime = lastUseTime; // } // if (msSinceUse > PendingTimeoutMs && IsFireballPending) // { // Core.Logger.Log($"Fireball wait timed out"); // IsFireballPending = false; // } // foreach (var actor in Core.Actors.AllRActors.Where(a => a.Type == TrinityObjectType.ClientEffect)) // { // if (actor.ActorSnoId == FireballSnoId && !Fireballs.ContainsKey(actor.AnnId)) // { // Core.Logger.Log($"New Fireball Found Delay:{msSinceUse}ms"); // IsFireballPending = false; // Fireballs.Add(actor.AnnId, actor); // } // } // foreach (var fireball in Fireballs.ToList().Where(fireball => !fireball.Value.IsValid)) // { // Fireballs.Remove(fireball.Key); // } // } //} /* Speed Farm Solo Variant tested @ GR75 * [Trinity 2.55.668] ------ Equipped Non-Set Legendaries: Items=8, Sets=1 ------ * [Trinity 2.55.668] Item: SpiritStone: Gyana Na Kashu (222169) is Equipped * [Trinity 2.55.668] Item: Belt: Kyoshiro's Soul (298136) is Equipped * [Trinity 2.55.668] Item: Boots: Rivera Dancers (197224) is Equipped * [Trinity 2.55.668] Item: Ring: Obsidian Ring of the Zodiac (212588) is Equipped * [Trinity 2.55.668] Item: Ring: Unity (212581) is Equipped * [Trinity 2.55.668] Item: Bracer: Nemesis Bracers (298121) is Equipped * [Trinity 2.55.668] Item: FistWeapon: Scarbringer (130557) is Equipped * [Trinity 2.55.668] Item: FistWeapon: Vengeful Wind (403775) is Equipped * [Trinity 2.55.668] ------ Equipped in Kanai's Cube: Items=3 ------ * [Trinity 2.55.668] Item: SpiritStone: The Laws of Seph (299454) is Equipped * [Trinity 2.55.668] Item: Ring: Ring of Royal Grandeur (298094) is Equipped * [Trinity 2.55.668] Item: Sword: In-geom (410946) is Equipped * [Trinity 2.55.668] ------ Set: Monkey King's Garb : 5/6 Equipped. ActiveBonuses=3/3 ------ * [Trinity 2.55.668] Item: Shoulder: Sunwuko's Balance (336175) is Equipped * [Trinity 2.55.668] Item: Gloves: Sunwuko's Paws (336172) is Equipped * [Trinity 2.55.668] Item: Amulet: Sunwuko's Shines (336174) is Equipped * [Trinity 2.55.668] Item: Legs: Sunwuko's Leggings (429075) is Equipped * [Trinity 2.55.668] Item: Chest: Sunwuko's Soul (429167) is Equipped * [Trinity 2.55.668] ------ Active Skills / Runes ------ * [Trinity 2.55.668] Skill: Lashing Tail Kick Rune=Sweeping Armada Type=Spender * [Trinity 2.55.668] Skill: Blinding Flash Rune=Faith in the Light Type=Other * [Trinity 2.55.668] Skill: Dashing Strike Rune=Way of the Falling Star Type=Other * [Trinity 2.55.668] Skill: Mantra of Salvation Rune=Agility Type=Other * [Trinity 2.55.668] Skill: Sweeping Wind Rune=Inner Storm Type=Spender * [Trinity 2.55.668] Skill: Epiphany Rune=Desert Shroud Type=Other * [Trinity 2.55.668] ------ Passives ------ * [Trinity 2.55.668] Passive: Exalted Soul * [Trinity 2.55.668] Passive: Beacon of Ytar * [Trinity 2.55.668] Passive: Harmony * [Trinity 2.55.668] Passive: Momentum * * [Trinity 2.55.668] ------ Equipped Non-Set Legendaries: Items=6, Sets=2 ------ * [Trinity 2.55.668] Item: SpiritStone: Gyana Na Kashu (222169) is Equipped * [Trinity 2.55.668] Item: Belt: The Witching Hour (193670) is Equipped * [Trinity 2.55.668] Item: Boots: Rivera Dancers (197224) is Equipped * [Trinity 2.55.668] Item: Bracer: Spirit Guards (430290) is Equipped * [Trinity 2.55.668] Item: FistWeapon: Crystal Fist (175939) is Equipped * [Trinity 2.55.668] Item: FistWeapon: Scarbringer (130557) is Equipped * [Trinity 2.55.668] ------ Equipped in Kanai's Cube: Items=3 ------ * [Trinity 2.55.668] Item: SpiritStone: The Laws of Seph (299454) is Equipped * [Trinity 2.55.668] Item: Ring: Ring of Royal Grandeur (298094) is Equipped * [Trinity 2.55.668] Item: Daibo: Flying Dragon (197065) is Equipped * [Trinity 2.55.668] ------ Set: Bastions of Will : 2/2 Equipped. ActiveBonuses=1/1 ------ * [Trinity 2.55.668] Item: Ring: Focus (332209) is Equipped * [Trinity 2.55.668] Item: Ring: Restraint (332210) is Equipped * [Trinity 2.55.668] ------ Set: Monkey King's Garb : 5/6 Equipped. ActiveBonuses=3/3 ------ * [Trinity 2.55.668] Item: Shoulder: Sunwuko's Balance (336175) is Equipped * [Trinity 2.55.668] Item: Gloves: Sunwuko's Paws (336172) is Equipped * [Trinity 2.55.668] Item: Amulet: Sunwuko's Shines (336174) is Equipped * [Trinity 2.55.668] Item: Legs: Sunwuko's Leggings (429075) is Equipped * [Trinity 2.55.668] Item: Chest: Sunwuko's Soul (429167) is Equipped * [Trinity 2.55.668] ------ Active Skills / Runes ------ * [Trinity 2.55.668] Skill: Fists of Thunder Rune=Quickening Type=Generator * [Trinity 2.55.668] Skill: Lashing Tail Kick Rune=Sweeping Armada Type=Spender * [Trinity 2.55.668] Skill: Blinding Flash Rune=Faith in the Light Type=Other * [Trinity 2.55.668] Skill: Dashing Strike Rune=Blinding Speed Type=Other * [Trinity 2.55.668] Skill: Mantra of Salvation Rune=Agility Type=Other * [Trinity 2.55.668] Skill: Sweeping Wind Rune=Inner Storm Type=Spender * [Trinity 2.55.668] ------ Passives ------ * [Trinity 2.55.668] Passive: Exalted Soul * [Trinity 2.55.668] Passive: Seize the Initiative * [Trinity 2.55.668] Passive: The Guardian's Path * [Trinity 2.55.668] Passive: Beacon of Ytar * [Trinity 2.55.668][Routine] Need Spirit Gaurds Buff * */ public TrinityPower GetOffensivePower() { // 853: PowerBuff0VisualEffectNone (-3243) [ PowerSnoId: ItemPassive_Unique_Ring_903_x1: 402411 ] i:1 f:0 Value=1 // 865: PowerBuff2VisualEffectNone (-3231) [ PowerSnoId: ItemPassive_Unique_Ring_922_x1: 402461 ] i:0 f:0 Value=0 // 588: BuffIconStartTick2(-3508)[PowerSnoId: ItemPassive_Unique_Gem_018_x1: 428348] i: 79817 f: 0 Value = 79817 // 863: PowerBuff1VisualEffectD (-3233) [ PowerSnoId: Monk_LashingTailKick: 111676 ] i:1 f:0 Value=1 TrinityPower power; Vector3 position; //FireballTracker.Update(); //if (FireballTracker.IsFireballPending) //{ // Core.Logger.Log("Waiting for fireball"); // return new TrinityPower(SNOPower.None); //} if (TrySpecialPower(out power)) { return(power); } if (Core.Buffs.HasCastingShrine) { if (Skills.Monk.DashingStrike.CanCast() && !Skills.Monk.DashingStrike.IsLastUsed) { return(DashingStrike(CurrentTarget.Position)); } if (Skills.Monk.LashingTailKick.CanCast()) { return(LashingTailKick(CurrentTarget)); } } if (ShouldRefreshSpiritGuardsBuff) { Core.Logger.Log(LogCategory.Routine, "Need Spirit Gaurds Buff"); if (TryPrimaryClosestTarget(out power)) { return(power); } } if (ShouldRefreshBastiansGenerator) { Core.Logger.Log(LogCategory.Routine, "Need Bastians Buff"); if (TryPrimaryClosestTarget(out power)) { return(power); } } // With sweeping armada try to keep distance in the sweet spot between 10-15yd if (Runes.Monk.SweepingArmada.IsActive) { var enoughTimePassed = SpellHistory.TimeSinceUse(SNOPower.Walk).TotalMilliseconds > 500; var isSoloElite = TargetUtil.ElitesInRange(25f) == 1 && !AnyUnitsInRange(25f); if (enoughTimePassed && isSoloElite && CurrentTarget.RadiusDistance <= 10f && !IsStuck) { if (Avoider.TryGetSafeSpot(out position, 12f + CurrentTarget.CollisionRadius, 30f, CurrentTarget.Position)) { Core.Logger.Log(LogCategory.Routine, $"Adjusting Distance for Sweeping Armarda RDist={CurrentTarget.RadiusDistance} Dist={ZetaDia.Me.Position.Distance(CurrentTarget.Position)}"); return(Walk(position, 2f)); } } } if (TrySecondaryPower(out power)) { return(power); } if (TryPrimaryPower(out power)) { return(power); } if (IsNoPrimary) { // Stay away from units for belt to build stacks. if (Legendary.KyoshirosSoul.IsEquipped) { var needStacks = Skills.Monk.SweepingWind.BuffStacks < 3 && Player.PrimaryResourcePct <= 0.75f; var needResource = Player.PrimaryResource < PrimaryEnergyReserve; if ((needStacks || needResource) && HostileMonsters.Any(u => u.Distance <= 12f)) { Core.Logger.Log(LogCategory.Routine, "Moving away to build stacks"); return(Walk(TargetUtil.GetLoiterPosition(CurrentTarget, 30f))); } } } // SW Stacks but no mana, or skills cooldown maybe, hang out just outside range of target. Core.Logger.Log(LogCategory.Routine, "Can't cast anything."); return(Walk(TargetUtil.GetLoiterPosition(CurrentTarget, 25f))); }
private static TrinityPower GetDemonHunterPower(bool IsCurrentlyAvoiding, bool UseOOCBuff, bool UseDestructiblePower) { // Pick the best destructible power available if (UseDestructiblePower) { return(GetDemonHunterDestroyPower()); } MinEnergyReserve = 25; //Kridershot InternalName=x1_bow_norm_unique_09-137 GameBalanceID=1999595351 ItemLink: {c:ffff8000}Kridershot{/c} bool hasKridershot = ZetaDia.Me.Inventory.Equipped.Any(i => i.GameBalanceId == 1999595351); bool hasPunishment = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 0); // Spam Shadow Power if (Settings.Combat.DemonHunter.SpamShadowPower && CombatBase.CanCast(SNOPower.DemonHunter_ShadowPower) && !Player.IsIncapacitated && (!GetHasBuff(SNOPower.DemonHunter_ShadowPower) || Player.CurrentHealthPct <= PlayerEmergencyHealthPotionLimit) && // if we don't have the buff or our health is low ((!hasPunishment && Player.SecondaryResource >= 14) || (hasPunishment && Player.SecondaryResource >= 39)) && // Save some Discipline for Preparation (Settings.Combat.DemonHunter.SpamShadowPower && Player.SecondaryResource >= 28)) // When spamming Shadow Power, save some Discipline for emergencies { return(new TrinityPower(SNOPower.DemonHunter_ShadowPower)); } // NotSpam Shadow Power if (!UseOOCBuff && !Settings.Combat.DemonHunter.SpamShadowPower && CombatBase.CanCast(SNOPower.DemonHunter_ShadowPower) && !Player.IsIncapacitated && (!GetHasBuff(SNOPower.DemonHunter_ShadowPower) || Player.CurrentHealthPct <= PlayerEmergencyHealthPotionLimit) && // if we don't have the buff or our health is low ((!hasPunishment && Player.SecondaryResource >= 14) || (hasPunishment && Player.SecondaryResource >= 39)) && // Save some Discipline for Preparation (Player.CurrentHealthPct < 1f || Player.IsRooted || TargetUtil.AnyMobsInRange(15))) { return(new TrinityPower(SNOPower.DemonHunter_ShadowPower)); } // Vengeance if (!IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.X1_DemonHunter_Vengeance, CombatBase.CanCastFlags.NoTimer) && ((!Settings.Combat.DemonHunter.VengeanceElitesOnly && TargetUtil.AnyMobsInRange(60, 6)) || TargetUtil.IsEliteTargetInRange(60f))) { return(new TrinityPower(SNOPower.X1_DemonHunter_Vengeance)); } // Smoke Screen if ((!UseOOCBuff || Settings.Combat.DemonHunter.SpamSmokeScreen) && CombatBase.CanCast(SNOPower.DemonHunter_SmokeScreen) && !GetHasBuff(SNOPower.DemonHunter_ShadowPower) && Player.SecondaryResource >= 14 && ( (Player.CurrentHealthPct <= 0.50 || Player.IsRooted || TargetUtil.AnyMobsInRange(15) || Player.IsIncapacitated) || Settings.Combat.DemonHunter.SpamSmokeScreen )) { return(new TrinityPower(SNOPower.DemonHunter_SmokeScreen, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } int sentryCoolDown = SpellHistory.SpellUseCountInTime(SNOPower.DemonHunter_Sentry, TimeSpan.FromSeconds(24)) >= 4 ? 12 : 6; // Sentry Turret if (!UseOOCBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.DemonHunter_Sentry, CombatBase.CanCastFlags.NoTimer) && (TargetUtil.AnyElitesInRange(50) || TargetUtil.AnyMobsInRange(50, 2) || TargetUtil.IsEliteTargetInRange(50)) && Player.PrimaryResource >= 30 && (SpellHistory.TimeSinceUse(SNOPower.DemonHunter_Sentry) > TimeSpan.FromSeconds(sentryCoolDown) || SpellHistory.DistanceFromLastUsePosition(SNOPower.DemonHunter_Sentry) > 7.5)) { return(new TrinityPower(SNOPower.DemonHunter_Sentry, 65f, TargetUtil.GetBestClusterPoint())); } // Caltrops if (!UseOOCBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.DemonHunter_Caltrops) && Player.SecondaryResource >= 6 && TargetUtil.AnyMobsInRange(40)) { return(new TrinityPower(SNOPower.DemonHunter_Caltrops, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } // Preperation: restore 30 disc / 45 sec cd // Invigoration = 1 : passive + 15 disc / 45 sec cd // Punishment = 0 : Cost: 25 disc, restore 75 hatred / NO COOLDOWN // Battle Scars = 3 : instantly restore 40% health + restore 30 disc / 45 sec cd // Focused Mind = 2 : restore 45 disc over 15 sec / 45 sec cd // Backup plan = 4 : 30% chance Prep has no cooldown (remove cast timer) // Restore 75 hatred for 25 disc - NO COOLDOWN! //bool hasPunishment = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 0); bool hasInvigoration = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 1); bool hasBattleScars = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 3); bool hasFocusedMind = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 2); bool hasBackupPlan = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Preparation && s.RuneIndex == 4); float preperationTriggerRange = V.F("DemonHunter.PreperationTriggerRange"); if (((!UseOOCBuff && !Player.IsIncapacitated && (TargetUtil.AnyMobsInRange(preperationTriggerRange))) || Settings.Combat.DemonHunter.SpamPreparation || hasPunishment) && Hotbar.Contains(SNOPower.DemonHunter_Preparation)) { // Preperation w/ Punishment if (hasPunishment && CombatBase.CanCast(SNOPower.DemonHunter_Preparation, CombatBase.CanCastFlags.NoTimer) && Player.SecondaryResource >= 25 && Player.PrimaryResourceMissing >= 75 && TimeSinceUse(SNOPower.DemonHunter_Preparation) >= 1000) { return(new TrinityPower(SNOPower.DemonHunter_Preparation)); } // Preperation w/ Battle Scars - check for health only if (hasBattleScars && CombatBase.CanCast(SNOPower.DemonHunter_Preparation) && Player.CurrentHealthPct < 0.6) { return(new TrinityPower(SNOPower.DemonHunter_Preparation)); } // no rune || invigoration || focused mind || Backup Plan || Battle Scars (need Disc) if ((!hasPunishment) && CombatBase.CanCast(SNOPower.DemonHunter_Preparation) && Player.SecondaryResource <= 15 && TimeSinceUse(SNOPower.DemonHunter_Preparation) >= 1000) { return(new TrinityPower(SNOPower.DemonHunter_Preparation)); } } // SOURCE: Stede - http://www.thebuddyforum.com/demonbuddy-forum/plugins/trinity/155398-trinity-dh-companion-use-abilities.html#post1445496 // Companion On-Use Abilities Added in 2.0 bool hasSpider = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_DemonHunter_Companion && s.RuneIndex == 0); bool hasBat = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_DemonHunter_Companion && s.RuneIndex == 3); bool hasBoar = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_DemonHunter_Companion && s.RuneIndex == 1); bool hasFerret = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_DemonHunter_Companion && s.RuneIndex == 4); bool hasWolf = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_DemonHunter_Companion && s.RuneIndex == 2); if (!UseOOCBuff && !Player.IsIncapacitated && Hotbar.Contains(SNOPower.X1_DemonHunter_Companion)) { // Use Spider Slow on 4 or more trash mobs in an area or on Unique/Elite/Champion if (hasSpider && CombatBase.CanCast(SNOPower.X1_DemonHunter_Companion) && TargetUtil.ClusterExists(25f, 4) && TargetUtil.EliteOrTrashInRange(25f)) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion)); } //Use Bat when Hatred is Needed if (hasBat && CombatBase.CanCast(SNOPower.X1_DemonHunter_Companion) && Player.PrimaryResourceMissing >= 60) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion)); } // Use Boar Taunt on 3 or more trash mobs in an area or on Unique/Elite/Champion if (hasBoar && CombatBase.CanCast(SNOPower.X1_DemonHunter_Companion) && ((TargetUtil.ClusterExists(20f, 4) && TargetUtil.EliteOrTrashInRange(20f)) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.Distance <= 20f))) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion)); } // Ferrets used for picking up Health Globes when low on Health if (hasFerret && ObjectCache.Any(o => o.Type == GObjectType.HealthGlobe && o.Distance < 60f) && Player.CurrentHealthPct < PlayerEmergencyHealthPotionLimit) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion)); } // Use Wolf Howl on Unique/Elite/Champion - Would help for farming trash, but trash farming should not need this - Used on Elites to reduce Deaths per hour if (hasWolf && CombatBase.CanCast(SNOPower.X1_DemonHunter_Companion) && (TargetUtil.AnyMobsInRange(20) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance < 55f))) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion)); } } //skillDict.Add("EvasiveFire", SNOPower.DemonHunter_EvasiveFire); //runeDict.Add("Hardened", 0); //runeDict.Add("PartingGift", 2); //runeDict.Add("CoveringFire", 1); //runeDict.Add("Displace", 4); //runeDict.Add("Surge", 3); // Companion if (!Player.IsIncapacitated && CombatBase.CanCast(SNOPower.X1_DemonHunter_Companion) && TargetUtil.EliteOrTrashInRange(30f) && Player.SecondaryResource >= 10) { return(new TrinityPower(SNOPower.X1_DemonHunter_Companion, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 2, 1)); } // Marked for Death if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_MarkedForDeath) && Player.SecondaryResource >= 3 && (TargetUtil.AnyElitesInRange(40) || TargetUtil.AnyMobsInRange(40, 3) || ((CurrentTarget.IsEliteRareUnique || CurrentTarget.IsTreasureGoblin || CurrentTarget.IsBoss) && CurrentTarget.Radius <= 40 && CurrentTarget.RadiusDistance <= 40f))) { return(new TrinityPower(SNOPower.DemonHunter_MarkedForDeath, 40f, Vector3.Zero, CurrentWorldDynamicId, CurrentTarget.ACDGuid, 1, 1)); } // Vault if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_Vault) && !Player.IsRooted && !Player.IsIncapacitated && Settings.Combat.DemonHunter.VaultMode != Config.Combat.DemonHunterVaultMode.MovementOnly && // Only use vault to retreat if < level 60, or if in inferno difficulty for level 60's (Player.Level < 60 || Player.GameDifficulty > GameDifficulty.Master) && (CurrentTarget.RadiusDistance <= 10f || TargetUtil.AnyMobsInRange(10)) && // if we have ShadowPower and Disicpline is >= 16 // or if we don't have ShadoWpower and Discipline is >= 22 (Player.SecondaryResource >= (Hotbar.Contains(SNOPower.DemonHunter_ShadowPower) ? 22 : 16)) && TimeSinceUse(SNOPower.DemonHunter_Vault) >= Trinity.Settings.Combat.DemonHunter.VaultMovementDelay) { //Vector3 vNewTarget = MathEx.CalculatePointFrom(CurrentTarget.Position, Player.Position, -15f); // Lets find a smarter Vault position instead of just "backwards" //Vector3 vNewTarget = NavHelper.FindSafeZone(Trinity.Player.Position, true, false, null, false); Vector3 vNewTarget = NavHelper.MainFindSafeZone(Trinity.Player.Position, true, false, null, false); return(new TrinityPower(SNOPower.DemonHunter_Vault, 20f, vNewTarget, CurrentWorldDynamicId, -1, 1, 2)); } // Rain of Vengeance if (!UseOOCBuff && CombatBase.CanCast(SNOPower.DemonHunter_RainOfVengeance) && !Player.IsIncapacitated && (TargetUtil.ClusterExists(45f, 3) || TargetUtil.EliteOrTrashInRange(45f))) { var bestClusterPoint = TargetUtil.GetBestClusterPoint(45f, 65f, false, true); return(new TrinityPower(SNOPower.DemonHunter_RainOfVengeance, 0f, bestClusterPoint, CurrentWorldDynamicId, -1, 1, 1)); } // Cluster Arrow if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_ClusterArrow) && !Player.IsIncapacitated && Player.PrimaryResource >= 50) { return(new TrinityPower(SNOPower.DemonHunter_ClusterArrow, V.F("DemonHunter.ClusterArrow.UseRange"), CurrentTarget.ACDGuid)); } // Multi Shot if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_Multishot) && !Player.IsIncapacitated && Player.PrimaryResource >= 30 && (TargetUtil.AnyMobsInRange(40, 2) || CurrentTarget.IsBossOrEliteRareUnique || CurrentTarget.IsTreasureGoblin)) { return(new TrinityPower(SNOPower.DemonHunter_Multishot, 30f, CurrentTarget.Position, CurrentWorldDynamicId, -1, 1, 1)); } // Fan of Knives if (!UseOOCBuff && CombatBase.CanCast(SNOPower.DemonHunter_FanOfKnives) && !Player.IsIncapacitated && (TargetUtil.EliteOrTrashInRange(15) || TargetUtil.AnyTrashInRange(15f, 5, false))) { return(new TrinityPower(SNOPower.DemonHunter_FanOfKnives, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } // Strafe spam - similar to barbarian whirlwind routine if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_Strafe, CombatBase.CanCastFlags.NoTimer) && !Player.IsIncapacitated && !Player.IsRooted && Player.PrimaryResource >= Settings.Combat.DemonHunter.StrafeMinHatred) { bool shouldGetNewZigZag = (DateTime.UtcNow.Subtract(Trinity.LastChangedZigZag).TotalMilliseconds >= V.I("Barbarian.Whirlwind.ZigZagMaxTime") || CurrentTarget.ACDGuid != Trinity.LastZigZagUnitAcdGuid || CombatBase.ZigZagPosition.Distance2D(Player.Position) <= 5f); if (shouldGetNewZigZag) { var wwdist = V.F("Barbarian.Whirlwind.ZigZagDistance"); CombatBase.ZigZagPosition = TargetUtil.GetZigZagTarget(CurrentTarget.Position, wwdist); Trinity.LastZigZagUnitAcdGuid = CurrentTarget.ACDGuid; Trinity.LastChangedZigZag = DateTime.UtcNow; } int postCastTickDelay = TrinityPower.MillisecondsToTickDelay(250); return(new TrinityPower(SNOPower.DemonHunter_Strafe, 15f, CombatBase.ZigZagPosition, CurrentWorldDynamicId, -1, 0, postCastTickDelay)); } // Spike Trap if (!UseOOCBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.DemonHunter_SpikeTrap) && LastPowerUsed != SNOPower.DemonHunter_SpikeTrap && Player.PrimaryResource >= 30) { // For distant monsters, try to target a little bit in-front of them (as they run towards us), if it's not a treasure goblin float fExtraDistance = 0f; if (CurrentTarget.Distance > 17f && !CurrentTarget.IsTreasureGoblin) { fExtraDistance = CurrentTarget.Distance - 17f; if (fExtraDistance > 5f) { fExtraDistance = 5f; } if (CurrentTarget.Distance - fExtraDistance < 15f) { fExtraDistance -= 2; } } Vector3 vNewTarget = MathEx.CalculatePointFrom(CurrentTarget.Position, Player.Position, CurrentTarget.Distance - fExtraDistance); return(new TrinityPower(SNOPower.DemonHunter_SpikeTrap, 35f, vNewTarget, CurrentWorldDynamicId, -1, 1, 1)); } //skillDict.Add("ElementalArrow", SNOPower.DemonHunter_ElementalArrow); //runeDict.Add("BallLightning", 1); //runeDict.Add("FrostArrow", 0); //runeDict.Add("ScreamingSkull", 2); //runeDict.Add("LightningBolts", 4); //runeDict.Add("NetherTentacles", 3); var hasBallLightning = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 1); var hasFrostArrow = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 0); var hasScreamingSkull = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 2); var hasLightningBolts = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 4); var hasNetherTentacles = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_ElementalArrow && s.RuneIndex == 3); // Elemental Arrow if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_ElementalArrow) && SNOPowerUseTimer(SNOPower.DemonHunter_ElementalArrow) && !Player.IsIncapacitated && ((Player.PrimaryResource >= 10 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve || hasKridershot)) { return(new TrinityPower(SNOPower.DemonHunter_ElementalArrow, 65f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1)); } //skillDict.Add("Chakram", SNOPower.DemonHunter_Chakram); //runeDict.Add("TwinChakrams", 0); //runeDict.Add("Serpentine", 2); //runeDict.Add("RazorDisk", 3); //runeDict.Add("Boomerang", 1); //runeDict.Add("ShurikenCloud", 4); bool hasShurikenCloud = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.DemonHunter_Chakram && s.RuneIndex == 4); // Chakram normal attack if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Chakram) && !Player.IsIncapacitated && !hasShurikenCloud && ((Player.PrimaryResource >= 10 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve)) { return(new TrinityPower(SNOPower.DemonHunter_Chakram, 50f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1)); } // Chakram:Shuriken Cloud if (!Player.IsInTown && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Chakram) && !Player.IsIncapacitated && hasShurikenCloud && TimeSinceUse(SNOPower.DemonHunter_Chakram) >= 110000 && ((Player.PrimaryResource >= 10 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve)) { return(new TrinityPower(SNOPower.DemonHunter_Chakram, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 2, 2)); } // Rapid Fire if (!UseOOCBuff && !IsCurrentlyAvoiding && CombatBase.CanCast(SNOPower.DemonHunter_RapidFire, CombatBase.CanCastFlags.NoTimer) && !Player.IsIncapacitated && Player.PrimaryResource >= 16 && (Player.PrimaryResource >= Settings.Combat.DemonHunter.RapidFireMinHatred || CombatBase.LastPowerUsed == SNOPower.DemonHunter_RapidFire)) { // Players with grenades *AND* rapid fire should spam grenades at close-range instead if (Hotbar.Contains(SNOPower.DemonHunter_Grenades) && CurrentTarget.RadiusDistance <= 18f) { return(new TrinityPower(SNOPower.DemonHunter_Grenades, 18f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Now return rapid fire, if not sending grenades instead return(new TrinityPower(SNOPower.DemonHunter_RapidFire, 40f, CurrentTarget.Position)); } // Impale if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Impale) && !Player.IsIncapacitated && (!TargetUtil.AnyMobsInRange(12, 4)) && ((Player.PrimaryResource >= 25 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve) && CurrentTarget.RadiusDistance <= 50f) { return(new TrinityPower(SNOPower.DemonHunter_Impale, 50f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1)); } // Evasive Fire if (!UseOOCBuff && CombatBase.CanCast(SNOPower.X1_DemonHunter_EvasiveFire) && !Player.IsIncapacitated && (TargetUtil.AnyMobsInRange(10f) || DemonHunter_HasNoPrimary())) { float range = DemonHunter_HasNoPrimary() ? 70f : 0f; return(new TrinityPower(SNOPower.X1_DemonHunter_EvasiveFire, range, Vector3.Zero, -1, CurrentTarget.ACDGuid, 1, 1)); } // Hungering Arrow if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_HungeringArrow) && !Player.IsIncapacitated) { return(new TrinityPower(SNOPower.DemonHunter_HungeringArrow, 50f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Entangling shot if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.X1_DemonHunter_EntanglingShot) && !Player.IsIncapacitated) { return(new TrinityPower(SNOPower.X1_DemonHunter_EntanglingShot, 50f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Bola Shot if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Bolas) && !Player.IsIncapacitated) { return(new TrinityPower(SNOPower.DemonHunter_Bolas, 50f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1)); } // Grenades if (!UseOOCBuff && !IsCurrentlyAvoiding && Hotbar.Contains(SNOPower.DemonHunter_Grenades) && !Player.IsIncapacitated) { return(new TrinityPower(SNOPower.DemonHunter_Grenades, 40f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 5, 5)); } // Default attacks return(CombatBase.DefaultPower); }