protected override bool ShouldEnergyTwister(out TrinityActor target) { target = null; if (!Skills.Wizard.EnergyTwister.CanCast()) { return(false); } if (Skills.Wizard.EnergyTwister.TimeSinceUse < Settings.EnergyTwisterDelay) { return(false); } target = TargetUtil.BestEliteInRange(50, true); if (target != null) { return(true); } target = TargetUtil.BestAoeUnit(50, true); if (TargetUtil.BestAoeUnit(50, true) != null) { return(true); } target = TargetUtil.GetBestClusterUnit() ?? CurrentTarget; if (Skills.Wizard.Archon.CooldownRemaining < 2000 && TalRashaStacks < 3) { return(true); } target = TargetUtil.GetBestClusterUnit() ?? CurrentTarget; return(target != null); }
protected override bool ShouldAncientSpear(out TrinityActor target) { // Credit: phelon's raekor. target = null; if (!Skills.Barbarian.AncientSpear.CanCast()) { return(false); } if (Sets.TheLegacyOfRaekor.IsFullyEquipped && RaekorDamageStacks < 5) { return(false); } target = TargetUtil.BestAoeUnit(60, true).IsInLineOfSight ? TargetUtil.BestAoeUnit(60, true) : TargetUtil.GetBestClusterUnit(10, 60, false, true, false, true); if (target == null) { return(false); } return(target.Distance <= 60 && Player.PrimaryResourcePct > 0.95); }
/* Non-Archon skills below: Used for DPS and Building Tal Rasha Stacks * * Stacks are earned by casting an elemental skill: Lightning, Fire, Arcane and Cold. * Each stack lasts for 8 seconds, and they do not refresh each other. * Each stack adds: 750% damage to attacks, 25% All resistance, Cause a matching elemental meteor to fall [8 second cooldown] * Note that these skills do not need to actually deal damage to any enemies to proc a stack. */ protected override bool ShouldArcaneTorrent(out TrinityActor target) { target = null; if (!Skills.Wizard.ArcaneTorrent.CanCast()) { return(false); } if (Player.PrimaryResource < Settings.ArcaneResourceReserve) { return(false); } target = CurrentTarget; if (target.IsTreasureGoblin && target.Distance < Settings.ArcaneTorrentRange && target.IsInLineOfSight) { return(true); } target = TargetUtil.GetClosestUnit(Settings.ArcaneTorrentRange); if (target != null && (Player.CurrentHealthPct < Settings.EmergencyHealthPct) || IsBlocked || IsStuck) { return(true); } target = TargetUtil.BestAoeUnit(Settings.ArcaneTorrentRange, true); if (target != null && TalRashaStacks >= 2) { return(true); } return(target != null); }
protected override bool ShouldCripplingWave(out TrinityActor target) { target = null; if (!Skills.Monk.CripplingWave.CanCast()) { return(false); } target = TargetUtil.BestEliteInRange(45, true); if (target != null && target.Distance < 12) { return(true); } target = TargetUtil.BestAoeUnit(45, true); if (target != null && target.Distance < 12) //removed resource check here { return(true); } target = TargetUtil.BestAuraUnit(SNOPower.Monk_CripplingWave, 12f, true); if (target != null && target.Distance < 12) { return(true); } target = TargetUtil.GetClosestUnit(12f); return(target != null); }
protected virtual bool ShouldAncientSpear(out TrinityActor target) { target = null; var skill = Skills.Barbarian.AncientSpear; if (!skill.CanCast()) { return(false); } if (skill.IsLastUsed && IsMultiSpender && skill.TimeSinceUse < 250) { return(false); } target = TargetUtil.BestAoeUnit(60, true).IsInLineOfSight ? TargetUtil.BestAoeUnit(60, true) : TargetUtil.GetBestClusterUnit(10, 60, false, true, false, true); if (target == null) { return(false); } return(target.Distance <= 60 && Player.PrimaryResourcePct > 0.95); }
protected virtual bool ShouldInnerSanctuary() { if (!Skills.Monk.InnerSanctuary.CanCast()) { return(false); } if (HasInstantCooldowns && !Skills.Monk.InnerSanctuary.IsLastUsed) { return(true); } if (Core.Buffs.HasBuff(SNOPower.X1_Monk_InnerSanctuary)) { return(false); } if (Player.CurrentHealthPct > 0.9 && !TargetUtil.AnyElitesInRange(10f)) { return(false); } if (TargetUtil.BestAoeUnit(25, Player.IsInParty).Distance > 20) { return(false); } return(true); }
protected override bool ShouldBlackHole(out TrinityActor target) { target = null; if (!Skills.Wizard.BlackHole.CanCast()) { return(false); } if (Skills.Wizard.BlackHole.TimeSinceUse < Settings.BlackHoleDelay) { return(false); } target = TargetUtil.BestEliteInRange(50, true); if (target != null) { return(true); } target = TargetUtil.BestAoeUnit(50, true); if (TargetUtil.BestAoeUnit(50, true) != null) { return(true); } //Make sure that we get all of our Tal Stacks before Archon! target = TargetUtil.GetBestClusterUnit() ?? CurrentTarget; if (Skills.Wizard.Archon.CooldownRemaining < 2000 && TalRashaStacks < 3) { return(true); } return(target != null); }
protected override bool ShouldWallOfDeath(out TrinityActor target) { target = null; if (!Skills.WitchDoctor.WallOfDeath.CanCast()) { return(false); } target = TargetUtil.BestAoeUnit(35, true); return(target != null); }
protected override bool ShouldPiranhas(out TrinityActor target) { target = null; if (!Skills.WitchDoctor.Piranhas.CanCast()) { return(false); } target = Runes.WitchDoctor.WaveOfMutilation.IsActive ? TargetUtil.GetBestPierceTarget(25, true) : TargetUtil.BestAoeUnit(35, true); return(target != null); }
protected override bool ShouldInnerSanctuary() { if (!Skills.Monk.InnerSanctuary.CanCast()) { return(false); } if (Skills.Monk.InnerSanctuary.TimeSinceUse < Settings.InnerSanctuaryDelay) { return(false); } if (TargetUtil.BestAoeUnit(45, true).Distance > Settings.InnerSanctuaryMinRange) { return(false); } return(true); }
protected override bool ShouldAncientSpear(out TrinityActor target) { target = null; if (!Skills.Barbarian.AncientSpear.CanCast()) { return(false); } target = TargetUtil.BestAoeUnit(60, true).IsInLineOfSight ? TargetUtil.BestAoeUnit(60, true) : TargetUtil.GetBestClusterUnit(10, 60, false, true, false, true); // wait for 95% resource would cause max damage on boulder toss // but the cooldown reset time for leap is possibly more important? //return target.Distance <= 60 && Player.PrimaryResourcePct > 0.95; return(target?.Distance <= 60); }
protected virtual bool ShouldPiranhas(out TrinityActor target) { target = null; if (!Skills.WitchDoctor.Piranhas.CanCast()) { return(false); } if (Player.PrimaryResource < PrimaryEnergyReserve) { return(false); } target = Runes.WitchDoctor.WaveOfMutilation.IsActive ? TargetUtil.GetBestPierceTarget(25, true) : TargetUtil.BestAoeUnit(35, true); return(target != null); }
protected override bool ShouldEpiphany() { if (!AllowedToUse(Settings.Epiphany, Skills.Monk.Epiphany)) { return(false); } if (!Skills.Monk.Epiphany.CanCast()) { return(false); } if (HasInstantCooldowns && !Skills.Monk.Epiphany.IsLastUsed) { return(true); } if (TargetUtil.BestAoeUnit(45, true).Distance > 20) { return(false); } return(true); }
protected virtual bool ShouldEpiphany() { if (!Skills.Monk.Epiphany.CanCast()) { return(false); } if (HasInstantCooldowns && !Skills.Monk.Epiphany.IsLastUsed) { return(true); } if (Player.CurrentHealthPct > 0.9 && !TargetUtil.AnyElitesInRange(30f)) { return(false); } if (TargetUtil.BestAoeUnit(25, Player.IsInParty)?.Distance > 30 && !TargetUtil.AnyElitesInRange(20)) { return(false); } return(true); }
public TrinityPower GetOffensivePower() { // Ported from Phelon's Jade Harvester Routine TrinityPower power; TrinityActor target; Vector3 position; if (Settings.HarvestModeIC == HarvestMode.NonStop && Skills.WitchDoctor.SoulHarvest.CanCast() && TargetUtil.AnyMobsInRange(14f)) { return(SoulHarvest()); } if (ShouldPiranhas(out target)) { return(Piranhas(target)); } if (ShouldSoulHarvest(out position)) { if (Skills.WitchDoctor.SpiritWalk.CanCast()) { return(SpiritWalk()); } return(SoulHarvest(position)); } if (ShouldWallOfDeath(out target)) { return(WallOfDeath(target)); } if (ShouldLocustSwarm(out target)) { return(LocustSwarm(target)); } if (ShouldHaunt(out target)) { return(Haunt(target)); } if (TrySpecialPower(out power)) { return(power); } if (TrySecondaryPower(out power)) { return(power); } if (TryPrimaryPower(out power)) { return(power); } if (Player.HasBuff(SNOPower.Witchdoctor_SpiritWalk)) { if (Player.CurrentHealthPct < EmergencyHealthPct && TargetUtil.BestWalkLocation(35f, true).Distance(Player.Position) > 5) { return(new TrinityPower(SNOPower.Walk, 7f, TargetUtil.BestWalkLocation(45f, true))); } if (TargetUtil.BestDpsPosition(TargetUtil.BestAoeUnit(45, true).Position, 45f, true).Distance(Player.Position) > 5) { return(new TrinityPower(SNOPower.Walk, 3f, TargetUtil.BestDpsPosition(TargetUtil.BestAoeUnit(45, true).Position, 45f, true))); } } return(new TrinityPower(SNOPower.Walk, 3f, TargetUtil.BestDpsPosition(TargetUtil.BestAoeUnit(45, true).Position, 45f, true))); }
protected override bool ShouldFuriousCharge(out Vector3 position) { // Credit: phelon's raekor. position = Vector3.Zero; TrinityActor target = null; if (!Skills.Barbarian.FuriousCharge.CanCast()) { return(false); } var targetGoal = Math.Floor(5 * Core.Player.CooldownReductionPct); TrinityActor bestPierce = TargetUtil.GetBestPierceTarget(45); var bestPierceCount = bestPierce?.NearbyUnitsWithinDistance(7) ?? 0; TrinityActor bestTarget = TargetUtil.BestAoeUnit(45, true); var bestTargetCount = bestTarget?.NearbyUnitsWithinDistance(7) ?? 0; TrinityActor bestCluster = TargetUtil.GetBestClusterUnit(7, 45); var bestClusterCount = bestCluster?.NearbyUnitsWithinDistance(7) ?? 0; if (!Core.Buffs.HasCastingShrine) { if (bestTarget != null && TargetUtil.PierceHitsMonster(bestTarget.Position)) { if (bestTargetCount == 1 || bestTargetCount >= targetGoal) { position = GetPositionBehind(bestTarget.Position); return(true); } } if (bestPierce != null && bestCluster != null && TargetUtil.PierceHitsMonster(bestPierce.Position) && TargetUtil.PierceHitsMonster(bestCluster.Position)) { if (bestPierceCount == 1 || bestPierceCount >= targetGoal && bestClusterCount == 1 || bestClusterCount >= targetGoal) { if (bestClusterCount > bestPierceCount) { position = GetPositionBehind(bestCluster.Position); return(true); } position = GetPositionBehind(bestPierce.Position); return(true); } if (bestPierceCount != 1 && bestPierceCount < targetGoal && (bestClusterCount == 1 || bestClusterCount >= targetGoal)) { position = GetPositionBehind(bestCluster.Position); return(true); } } if (bestPierce != null && TargetUtil.PierceHitsMonster(bestPierce.Position)) { if (bestClusterCount != 1 && bestClusterCount < targetGoal && (bestPierceCount == 1 || bestPierceCount >= targetGoal)) { position = GetPositionBehind(bestPierce.Position); return(true); } } } position = GetPositionBehind(CurrentTarget.Position); return(true); }
public TrinityPower GetOffensivePower() { // Ported from Phelon's Cold Garg routine TrinityPower power; TrinityActor target; // Recast gargs if they are being lazy. var myGargs = TargetUtil.FindPets(PetType.Gargantuan); var distGargsToTarget = TargetUtil.Centroid(myGargs.Select(g => g.Position)).Distance(CurrentTarget.Position); if (distGargsToTarget > 30f && Player.PrimaryResourcePct > 0.5f && Skills.WitchDoctor.Gargantuan.CanCast()) { return(Gargantuan(CurrentTarget.Position)); } var bestDpsTarget = TargetUtil.BestAoeUnit(35f, true); Vector3 bestDpsPosition; if (Core.Player.HasBuff(SNOPower.Witchdoctor_SpiritWalk)) { if (Player.CurrentHealthPct < EmergencyHealthPct && TargetUtil.ClosestGlobe(35f, true) != null) { return(Walk(TargetUtil.ClosestGlobe(35f, true).Position)); } if (TargetUtil.BestBuffPosition(35f, bestDpsTarget.Position, false, out bestDpsPosition) && bestDpsPosition.Distance2D(Player.Position) > 6f) { return(Walk(bestDpsPosition)); } } if (TargetUtil.BestBuffPosition(12f, bestDpsTarget.Position, false, out bestDpsPosition) && (TargetUtil.UnitsBetweenLocations(Player.Position, bestDpsPosition).Count < 6 || Legendary.IllusoryBoots.IsEquipped) && bestDpsPosition.Distance2D(Player.Position) > 6f) { return(Walk(bestDpsPosition)); } if (TrySpecialPower(out power)) { return(power); } if (ShouldPiranhas(out target)) { return(Piranhas(target)); } if (ShouldWallOfDeath(out target)) { return(WallOfDeath(target)); } if (ShouldHaunt(out target)) { return(Haunt(target)); } if (TrySecondaryPower(out power)) { return(power); } if (TryPrimaryPower(out power)) { return(power); } if (Settings.KiteVariation == KiteVariation.DistantEmptySpace) { // Stand still for damage buff - defualt Avoider.SafeSpot includes logic // to suppress minor variations in safespot position if less than 12f if (Player.CurrentHealthPct > 0.8f && !TargetUtil.AnyMobsInRange(15f)) { return(Walk(Avoider.SafeSpot)); } return(Walk(TargetUtil.GetLoiterPosition(bestDpsTarget, 25f))); } //KiteVariation.NearTargetCluster return(Walk(Avoider.SafeSpot)); }
public TrinityPower GetOffensivePower() { TrinityPower power; Core.Logger.Log(LogCategory.Routine, $"FanBuff={IsFanBuffReady} TrashCluster={IsFanTrashCluster} EliteCluster={IsFanEliteCluster} Element={IsLightningElement} Crit%={Player.CriticalChancePct}"); if (Player.CurrentHealthPct < 0.2 && Skills.DemonHunter.FanOfKnives.CanCast()) { Core.Logger.Log(LogCategory.Routine, "About to die..."); return(FanOfKnives()); } if (ShouldFan()) { Core.Logger.Log(LogCategory.Routine, "Its time for the pain"); // +15% dmg var isWolfBuffReady = !Skills.DemonHunter.Companion.IsActive || Skills.DemonHunter.Companion.IsBuffActive; if (!isWolfBuffReady && Skills.DemonHunter.Companion.CanCast()) { return(Companion()); } // +40% dmg var isVengeanceReady = !Skills.DemonHunter.Vengeance.IsActive || Skills.DemonHunter.Vengeance.IsBuffActive; if (!isVengeanceReady && Skills.DemonHunter.Vengeance.CanCast()) { return(Vengeance()); } //if (!Player.IsMaxCriticalChance) //{ // return Walk(TargetUtil.BestAoeUnit(100f, true)); //} var clusterUnits = TargetUtil.GetBestClusterUnits().Where(u => u.IsElite || u.NearbyUnitsWithinDistance() > ClusterSize).Select(u => u.Position); var fanPosition = TargetUtil.GetCentroid(clusterUnits); // If we cant get there, dont miss the opportunity. if (IsReallyBlocked && TimeFromElementStart(Element.Lightning) > 3000) { Core.Logger.Log(LogCategory.Routine, "Deloying Blocked Fan"); return(FanOfKnives()); } return(FanOfKnives(fanPosition)); } if (!IsReallyBlocked) { var pullingUnit = HostileMonsters .Where(u => Math.Abs(u.HitPointsPct - 1) < float.Epsilon && (u.IsElite || u.NearbyUnitsWithinDistance(10f) > 3)) .OrderByDescending(u => u.Distance).FirstOrDefault(); if (pullingUnit != null) { Core.Logger.Log(LogCategory.Routine, "Pulling units"); return(Walk(pullingUnit)); } } if (IsBossFight && LordGreenStoneDamageStacks < 15) { Core.Logger.Log(LogCategory.Routine, "Attacking while waiting for fan"); if (TryPrimaryPower(out power)) { return(power); } } if (LordGreenStoneDamageStacks < 28 || !IsLightningElement) { Core.Logger.Log(LogCategory.Routine, "Hanging out near fan position"); return(Walk(TargetUtil.GetLoiterPosition(TargetUtil.BestAoeUnit(100f, true), 30f))); } Core.Logger.Log(LogCategory.Routine, "Moving to fan position"); return(Walk(TargetUtil.BestAoeUnit(100f, true))); }