private static TrinityPower GetMonkDestroyPower() { if (Monk_TempestRushReady()) { return(new TrinityPower(SNOPower.Monk_TempestRush, 5f, Vector3.Zero, -1, -1, 0, 0)); } if (CombatBase.CanCast(SNOPower.X1_Monk_DashingStrike)) { return(new TrinityPower(SNOPower.X1_Monk_DashingStrike, Monk_MaxDashingStrikeRange, Vector3.Zero, -1, -1, 0, 0)); } if (CombatBase.CanCast(SNOPower.Monk_FistsofThunder)) { return(new TrinityPower(SNOPower.Monk_FistsofThunder, 5f, Vector3.Zero, -1, -1, 0, 0)); } if (CombatBase.CanCast(SNOPower.Monk_DeadlyReach)) { return(new TrinityPower(SNOPower.Monk_DeadlyReach, 5f, Vector3.Zero, -1, -1, 0, 0)); } if (CombatBase.CanCast(SNOPower.Monk_CripplingWave)) { return(new TrinityPower(SNOPower.Monk_CripplingWave, 5f, Vector3.Zero, -1, -1, 0, 0)); } if (CombatBase.CanCast(SNOPower.Monk_WayOfTheHundredFists)) { return(new TrinityPower(SNOPower.Monk_WayOfTheHundredFists, 5f, Vector3.Zero, -1, -1, 0, 0)); } return(CombatBase.DefaultPower); }
/// <summary> /// This will find a safe place to stand in both Kiting and Avoidance situations /// </summary> /// <param name="isStuck"></param> /// <param name="stuckAttempts"></param> /// <param name="dangerPoint"></param> /// <param name="shouldKite"></param> /// <param name="avoidDeath"></param> /// <returns></returns> internal static Vector3 FindSafeZone(bool isStuck, int stuckAttempts, Vector3 dangerPoint, bool shouldKite = false, IEnumerable <TrinityCacheObject> monsterList = null, bool avoidDeath = false) { if (!isStuck) { if (shouldKite && DateTime.UtcNow.Subtract(lastFoundSafeSpot).TotalMilliseconds <= 1500 && lastSafeZonePosition != Vector3.Zero) { return(lastSafeZonePosition); } else if (DateTime.UtcNow.Subtract(lastFoundSafeSpot).TotalMilliseconds <= 800 && lastSafeZonePosition != Vector3.Zero) { return(lastSafeZonePosition); } hasEmergencyTeleportUp = ( // Leap is available (!PlayerStatus.IsIncapacitated && CombatBase.CanCast(SNOPower.Barbarian_Leap)) || // Whirlwind is available (!PlayerStatus.IsIncapacitated && CombatBase.CanCast(SNOPower.Barbarian_Whirlwind) && ((PlayerStatus.PrimaryResource >= 10 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= Trinity.MinEnergyReserve)) || // Tempest rush is available (!PlayerStatus.IsIncapacitated && CombatBase.CanCast(SNOPower.Monk_TempestRush) && ((PlayerStatus.PrimaryResource >= 20 && !PlayerStatus.WaitingForReserveEnergy) || PlayerStatus.PrimaryResource >= Trinity.MinEnergyReserve)) || // Teleport is available (!PlayerStatus.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Teleport) && PlayerStatus.PrimaryResource >= 15) || // Archon Teleport is available (!PlayerStatus.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Archon_Teleport)) ); // Wizards can look for bee stings in range and try a wave of force to dispel them if (!shouldKite && PlayerStatus.ActorClass == ActorClass.Wizard && Hotbar.Contains(SNOPower.Wizard_WaveOfForce) && PlayerStatus.PrimaryResource >= 25 && DateTime.UtcNow.Subtract(CacheData.AbilityLastUsed[SNOPower.Wizard_WaveOfForce]).TotalMilliseconds >= CombatBase.GetSNOPowerUseDelay(SNOPower.Wizard_WaveOfForce) && !PlayerStatus.IsIncapacitated && CacheData.TimeBoundAvoidance.Count(u => u.ActorSNO == 5212 && u.Position.Distance(PlayerStatus.Position) <= 15f) >= 2 && ( //HotbarSkills.PassiveSkills.Contains(SNOPower.Wizard_Passive_CriticalMass) || PowerManager.CanCast(SNOPower.Wizard_WaveOfForce))) { ZetaDia.Me.UsePower(SNOPower.Wizard_WaveOfForce, Vector3.Zero, PlayerStatus.WorldDynamicID, -1); } } float highestWeight = 0f; if (monsterList == null) { monsterList = new List <TrinityCacheObject>(); } //Vector3 vBestLocation = FindSafeZone(dangerPoint, shouldKite, isStuck, monsterList, avoidDeath); Vector3 vBestLocation = MainFindSafeZone(dangerPoint, shouldKite, isStuck, monsterList, avoidDeath); highestWeight = 1; // Loop through distance-range steps if (highestWeight <= 0) { return(vBestLocation); } lastFoundSafeSpot = DateTime.UtcNow; lastSafeZonePosition = vBestLocation; return(vBestLocation); }
/// <summary> /// Check re-use timers on skills, returns true if we can use the power /// </summary> /// <param name="power">The power.</param> /// <param name="recheck">if set to <c>true</c> check again.</param> /// <returns> /// Returns whether or not we can use a skill, or if it's on our own internal Trinity cooldown timer /// </returns> public static bool SNOPowerUseTimer(SNOPower power, bool recheck = false) { if (TimeSinceUse(power) >= CombatBase.GetSNOPowerUseDelay(power)) { return(true); } if (recheck && TimeSinceUse(power) >= 150 && TimeSinceUse(power) <= 600) { return(true); } return(false); }
public void setTarget(bool isPlayer) { combatManager = FindObjectOfType <CombatManager>(); if (isPlayer) { target = combatManager.enemyCombat; } else { target = combatManager.playerCombat; } }
public void OnTriggerEnter2D(Collider2D collision) { if (collision.CompareTag(tagTarget)) { CombatBase col = collision.GetComponent <CombatBase>(); col.TakeDamage(damage); print("acertou> " + collision.name); DestroyBullet(); } if (collision.CompareTag("Obstacle")) { DestroyBullet(); } }
private static bool Wizard_HasFamiliar() { double timeSinceDeath = DateTime.UtcNow.Subtract(LastDeathTime).TotalMilliseconds; // We've died, no longer have familiar if (timeSinceDeath < CombatBase.TimeSincePowerUse(SNOPower.Wizard_Familiar)) { return(false); } // we've used it within the last 5 minutes, we should still have it if (CombatBase.TimeSincePowerUse(SNOPower.Wizard_Familiar) < (5 * 60 * 1000)) { return(true); } return(false); }
/// <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); } }
// Startet den Kampf public void startCombat(EnemyBase enemyType, GameObject enemyObject, int priority) { if (!inCombat) { HPPanel.SetActive(false); playerHPText.text = "HP " + player.getHP() + "/" + player.getFullHP(); hpPotion.text = "> " + player.getHPFlaskAmount() + "x Heiltrank"; Debug.Log(hpPotion.text); touchedEnemy = enemyObject; playerCamera.SetActive(false); battleCamera.SetActive(true); changeMenu(BattleMenu.Selection); switchSelection(); GameObject enemy = Instantiate(enemyList[(int)enemyType.GetEnemyType()], monsterPodium.transform); enemyCombat = enemy.GetComponent <CombatBase>(); playerCombat.setTarget(true); enemyCombat.setTarget(false); enemyBase = enemyType; canAttack = true; if (priority > 0) { isPlayersTurn = true; } else { isPlayersTurn = false; performEnemyAttack(); } setInCombat(true); enemyHPText.text = "HP " + enemyBase.getHP() + "/" + enemyBase.getFullHP(); reduceCooldowns(); } }
private static TrinityPower GetWizardPower(bool isCurrentlyAvoiding, bool useOocBuff, bool useDestructiblePower) { // Pick the best destructible power available if (useDestructiblePower) { if (!GetHasBuff(SNOPower.Wizard_Archon)) { return(GetWizardDestructablePower()); } if (CurrentTarget.RadiusDistance <= 10f) { return(new TrinityPower(SNOPower.Wizard_Archon_ArcaneStrike, 20f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } return(new TrinityPower(SNOPower.Wizard_Archon_DisintegrationWave, 19f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Wizards want to save up to a reserve of 65+ energy MinEnergyReserve = 45; if (!GetHasBuff(SNOPower.Wizard_Archon)) { bool hasIllusionist = HotbarSkills.PassiveSkills.Any(p => p == SNOPower.Wizard_Passive_Illusionist); // Illusionist speed boost if (hasIllusionist && useOocBuff) { // Slow Time on self for speed boost if (CombatBase.CanCast(SNOPower.Wizard_SlowTime)) { return(new TrinityPower(SNOPower.Wizard_SlowTime)); } // Mirror Image for speed boost if (CombatBase.CanCast(SNOPower.Wizard_MirrorImage)) { return(new TrinityPower(SNOPower.Wizard_MirrorImage)); } // Teleport already called from PlayerMover, not here (since it's a "movement" spell, not a buff) } bool hasCalamity = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Teleport && s.RuneIndex == 0); // Offensive Teleport: Calamity if (CombatBase.CanCast(SNOPower.Wizard_Teleport) && hasCalamity) { var bestClusterPoint = TargetUtil.GetBestClusterPoint(); return(new TrinityPower(SNOPower.Wizard_Teleport, 55f, bestClusterPoint)); } bool hasSafePassage = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Teleport && s.RuneIndex == 1); // Defensive Teleport: SafePassage if (CombatBase.CanCast(SNOPower.Wizard_Teleport) && hasSafePassage && TimeSinceUse(SNOPower.Wizard_Teleport) >= 5000 && Player.CurrentHealthPct <= 0.75 && (CurrentTarget.IsBossOrEliteRareUnique || TargetUtil.IsEliteTargetInRange(30f))) { return(new TrinityPower(SNOPower.Wizard_Teleport, 1f, Player.Position)); } // Black Hole experiment //spell steal //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/3/HotbarSlot1 None/-1/HotbarSlot2 //blazar //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/2/HotbarSlot1 None/-1/HotbarSlot2 //event horizon //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/1/HotbarSlot1 None/-1/HotbarSlot2 //absolute zero //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/4/HotbarSlot1 None/-1/HotbarSlot2 //super massive //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/0/HotbarSlot1 None/-1/HotbarSlot2 //no rune //[Trinity] Hotbar Skills (Skill/RuneIndex/Slot): Weapon_Ranged_Wand/-1/HotbarMouseLeft X1_Wizard_Wormhole/-1/HotbarSlot1 None/-1/HotbarSlot2 bool hasSupermassive = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.X1_Wizard_Wormhole && s.RuneIndex == 0); float blackholeRadius = hasSupermassive ? 20f : 15f; if (!useOocBuff && !isCurrentlyAvoiding && CombatBase.CanCast(SNOPower.X1_Wizard_Wormhole, CombatBase.CanCastFlags.NoTimer) && TargetUtil.ClusterExists(blackholeRadius, 45f, 4)) { return(new TrinityPower(SNOPower.X1_Wizard_Wormhole, 45f, TargetUtil.GetBestClusterUnit(blackholeRadius, 45f, 1, false).Position)); } bool arcaneDynamoPassiveReady = (HotbarSkills.PassiveSkills.Any(s => s == SNOPower.Wizard_Passive_ArcaneDynamo) && GetBuffStacks(SNOPower.Wizard_Passive_ArcaneDynamo) == 5); var bestMeteorClusterUnit = TargetUtil.GetBestClusterUnit(); // Meteor: Arcane Dynamo if (!useOocBuff && !Player.IsIncapacitated && !arcaneDynamoPassiveReady && CombatBase.CanCast(SNOPower.Wizard_Meteor, CombatBase.CanCastFlags.NoTimer) && (TargetUtil.EliteOrTrashInRange(65) || TargetUtil.ClusterExists(15f, 65, 2))) { return(new TrinityPower(SNOPower.Wizard_Meteor, 65f, bestMeteorClusterUnit.Position)); } // Diamond Skin SPAM if (!useOocBuff && CombatBase.CanCast(SNOPower.Wizard_DiamondSkin) && LastPowerUsed != SNOPower.Wizard_DiamondSkin && !GetHasBuff(SNOPower.Wizard_DiamondSkin) && (TargetUtil.AnyElitesInRange(25, 1) || TargetUtil.AnyMobsInRange(25, 1) || Player.CurrentHealthPct <= 0.90 || Player.IsIncapacitated || Player.IsRooted || CurrentTarget.RadiusDistance <= 40f)) { return(new TrinityPower(SNOPower.Wizard_DiamondSkin)); } // Diamond Skin off CD bool hasSleekShell = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_DiamondSkin && s.RuneIndex == 0); if (hasSleekShell && CombatBase.CanCast(SNOPower.Wizard_DiamondSkin)) { return(new TrinityPower(SNOPower.Wizard_DiamondSkin)); } // Slow Time for in combat if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_SlowTime, CombatBase.CanCastFlags.NoTimer) && (TargetUtil.AnyElitesInRange(25, 1) || TargetUtil.AnyMobsInRange(25, 2) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance <= 40f)) && (CombatBase.TimeSpanSincePowerUse(SNOPower.Wizard_SlowTime) > TimeSpan.FromSeconds(15) || SpellHistory.DistanceFromLastTarget(SNOPower.Wizard_SlowTime) > 30f)) { if (TargetUtil.AnyMobsInRange(20f)) { return(new TrinityPower(SNOPower.Wizard_SlowTime)); // cast of Self } return(new TrinityPower(SNOPower.Wizard_SlowTime, 55f, TargetUtil.GetBestClusterUnit(20f).Position)); } // Mirror Image @ half health or 5+ monsters or rooted/incapacitated or last elite left @25% health if (!useOocBuff && CombatBase.CanCast(SNOPower.Wizard_MirrorImage, CombatBase.CanCastFlags.NoTimer) && (Player.CurrentHealthPct <= PlayerEmergencyHealthPotionLimit || TargetUtil.AnyMobsInRange(30, 4) || Player.IsIncapacitated || Player.IsRooted || TargetUtil.AnyElitesInRange(30) || CurrentTarget.IsBossOrEliteRareUnique)) { return(new TrinityPower(SNOPower.Wizard_MirrorImage, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } // Familiar if (!Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Familiar) && Player.PrimaryResource >= 20 && !Wizard_HasFamiliar()) { return(new TrinityPower(SNOPower.Wizard_Familiar, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 2)); } // The three wizard armors, done in an else-if loop so it doesn't keep replacing one with the other if (!Player.IsIncapacitated && Player.PrimaryResource >= 25) { // Energy armor as priority cast if available and not buffed if (Hotbar.Contains(SNOPower.Wizard_EnergyArmor)) { if ((!GetHasBuff(SNOPower.Wizard_EnergyArmor) && PowerManager.CanCast(SNOPower.Wizard_EnergyArmor)) || (Hotbar.Contains(SNOPower.Wizard_Archon) && (!GetHasBuff(SNOPower.Wizard_EnergyArmor) || SNOPowerUseTimer(SNOPower.Wizard_EnergyArmor)))) { return(new TrinityPower(SNOPower.Wizard_EnergyArmor, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 2)); } } // Ice Armor else if (Hotbar.Contains(SNOPower.Wizard_IceArmor)) { if (!GetHasBuff(SNOPower.Wizard_IceArmor) && PowerManager.CanCast(SNOPower.Wizard_IceArmor)) { return(new TrinityPower(SNOPower.Wizard_IceArmor, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 2)); } } // Storm Armor else if (Hotbar.Contains(SNOPower.Wizard_StormArmor)) { if (!GetHasBuff(SNOPower.Wizard_StormArmor) && PowerManager.CanCast(SNOPower.Wizard_StormArmor)) { return(new TrinityPower(SNOPower.Wizard_StormArmor, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 2)); } } } // Magic Weapon (10 minutes) if (!Player.IsIncapacitated && Player.PrimaryResource >= 25 && CombatBase.CanCast(SNOPower.Wizard_MagicWeapon) && !GetHasBuff(SNOPower.Wizard_MagicWeapon)) { return(new TrinityPower(SNOPower.Wizard_MagicWeapon, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 2)); } // Hydra if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Hydra, CombatBase.CanCastFlags.NoTimer) && (CombatBase.TimeSpanSincePowerUse(SNOPower.Wizard_Hydra) > TimeSpan.FromSeconds(15) && SpellHistory.DistanceFromLastTarget(SNOPower.Wizard_Hydra) > 30f) && //LastPowerUsed != SNOPower.Wizard_Hydra && (TargetUtil.AnyElitesInRange(15, 1) || TargetUtil.AnyMobsInRange(15, 4) || (CurrentTarget.IsBossOrEliteRareUnique && CurrentTarget.RadiusDistance <= 15f)) && Player.PrimaryResource >= 15) { // 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.Wizard_Hydra, 30f, vNewTarget, CurrentWorldDynamicId, -1, 1, 2)); } // Archon if (!useOocBuff && !isCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Wizard_Archon, CombatBase.CanCastFlags.NoTimer) && Wizard_ShouldStartArchon()) { //CanCastArchon = false; //return new TrinityPower(SNOPower.Wizard_Archon, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 4, 5); // Familiar has been removed for now. Uncomment the three comments below relating to familiars to force re-buffing them int reserveArcanePower = 0; if (Hotbar.Contains(SNOPower.Wizard_MagicWeapon)) { reserveArcanePower += 25; } if (Hotbar.Contains(SNOPower.Wizard_Familiar)) { reserveArcanePower += 25; } if (Hotbar.Contains(SNOPower.Wizard_EnergyArmor) || Hotbar.Contains(SNOPower.Wizard_IceArmor) || Hotbar.Contains(SNOPower.Wizard_StormArmor)) { reserveArcanePower += 25; } bool hasBuffSpells = (Hotbar.Contains(SNOPower.Wizard_MagicWeapon) || Hotbar.Contains(SNOPower.Wizard_Familiar) || Hotbar.Contains(SNOPower.Wizard_EnergyArmor) || Hotbar.Contains(SNOPower.Wizard_IceArmor) || Hotbar.Contains(SNOPower.Wizard_StormArmor)); CanCastArchon = //Player.PrimaryResource >= reserveArcanePower || ( //hasBuffSpells && CheckAbilityAndBuff(SNOPower.Wizard_MagicWeapon) && (!Hotbar.Contains(SNOPower.Wizard_Familiar) || Wizard_HasFamiliar()) && CheckAbilityAndBuff(SNOPower.Wizard_EnergyArmor) && CheckAbilityAndBuff(SNOPower.Wizard_IceArmor) && CheckAbilityAndBuff(SNOPower.Wizard_StormArmor)); if (CanCastArchon) { Player.WaitingForReserveEnergy = false; CanCastArchon = false; ShouldRefreshHotbarAbilities = true; return(new TrinityPower(SNOPower.Wizard_Archon, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 4, 5)); } Player.WaitingForReserveEnergy = true; } // Explosive Blast if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_ExplosiveBlast, CombatBase.CanCastFlags.NoTimer) && Player.PrimaryResource >= 20) { return(new TrinityPower(SNOPower.Wizard_ExplosiveBlast, 12f, CurrentTarget.Position)); } //SkillDict.Add("Blizzard", SNOPower.Wizard_Blizzard); //RuneDict.Add("GraspingChill", 2); //RuneDict.Add("FrozenSolid", 4); //RuneDict.Add("Snowbound", 3); //RuneDict.Add("StarkWinter", 1); //RuneDict.Add("UnrelentingStorm", 0); bool hasSnowBoundRune = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Blizzard && s.RuneIndex == 3); // Blizzard if (!useOocBuff && !Player.IsIncapacitated && Hotbar.Contains(SNOPower.Wizard_Blizzard) && (TargetUtil.ClusterExists(18f, 90f, 2, false) || TargetUtil.AnyElitesInRange(40f) || TargetUtil.IsEliteTargetInRange(45f)) && (Player.PrimaryResource >= 40 || (hasSnowBoundRune && Player.PrimaryResource >= 20)) && SNOPowerUseTimer(SNOPower.Wizard_Blizzard)) { var bestClusterPoint = TargetUtil.GetBestClusterPoint(18f, 45f, false); return(new TrinityPower(SNOPower.Wizard_Blizzard, 45f, bestClusterPoint, CurrentWorldDynamicId, -1, 1, 1)); } bool hasArcaneDynamo = HotbarSkills.PassiveSkills.Any(s => s == SNOPower.Wizard_Passive_ArcaneDynamo); // Meteor - no arcane dynamo if (!useOocBuff && !Player.IsIncapacitated && !hasArcaneDynamo && CombatBase.CanCast(SNOPower.Wizard_Meteor, CombatBase.CanCastFlags.NoTimer) && (TargetUtil.EliteOrTrashInRange(65) || TargetUtil.ClusterExists(15f, 65, 2))) { return(new TrinityPower(SNOPower.Wizard_Meteor, 65f, bestMeteorClusterUnit.Position)); } //SkillDict.Add("FrostNova", SNOPower.Wizard_FrostNova); //RuneDict.Add("Shatter", 1); //RuneDict.Add("ColdSnap", 3); //RuneDict.Add("FrozenMist", 2); //RuneDict.Add("DeepFreeze", 4); //RuneDict.Add("BoneChill", 0); bool hasDeepFreeze = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_FrostNova && s.RuneIndex == 4); // Frost Nova if (!useOocBuff && CombatBase.CanCast(SNOPower.Wizard_FrostNova) && !Player.IsIncapacitated && ((hasDeepFreeze && TargetUtil.AnyMobsInRange(25, 5)) || (!hasDeepFreeze && (TargetUtil.AnyMobsInRange(25, 1) || Player.CurrentHealthPct <= 0.7)) && CurrentTarget.RadiusDistance <= 25f)) { return(new TrinityPower(SNOPower.Wizard_FrostNova, 20f, Vector3.Zero, CurrentWorldDynamicId, -1, 0, 2)); } // Check to see if we have a signature spell on our hotbar, for energy twister check bool bHasSignatureSpell = (Hotbar.Contains(SNOPower.Wizard_MagicMissile) || Hotbar.Contains(SNOPower.Wizard_ShockPulse) || Hotbar.Contains(SNOPower.Wizard_SpectralBlade) || Hotbar.Contains(SNOPower.Wizard_Electrocute)); //SkillDict.Add("EnergyTwister", SNOPower.Wizard_EnergyTwister); //RuneDict.Add("MistralBreeze", 3); //RuneDict.Add("GaleForce", 0); //RuneDict.Add("RagingStorm", 1); //RuneDict.Add("WickedWind", 4); //RuneDict.Add("StromChaser", 2); bool hasWickedWindRune = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_EnergyTwister && s.RuneIndex == 4); // Energy Twister SPAMS whenever 35 or more ap to generate Arcane Power if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_EnergyTwister) && Player.PrimaryResource >= 35 && // If using storm chaser, then force a signature spell every 1 stack of the buff, if we have a signature spell (!bHasSignatureSpell || GetBuffStacks(SNOPower.Wizard_EnergyTwister) < 1) && ((!hasWickedWindRune && CurrentTarget.RadiusDistance <= 25f) || (hasWickedWindRune && CurrentTarget.RadiusDistance <= 60f)) && (!Hotbar.Contains(SNOPower.Wizard_Electrocute) || !DataDictionary.FastMovingMonsterIds.Contains(CurrentTarget.ActorSNO))) { Vector3 bestClusterPoint = TargetUtil.GetBestClusterPoint(10f, 15f); const float twisterRange = 28f; return(new TrinityPower(SNOPower.Wizard_EnergyTwister, twisterRange, bestClusterPoint, CurrentWorldDynamicId, -1, 0, 0)); } // Wave of force if (!useOocBuff && !Player.IsIncapacitated && !isCurrentlyAvoiding && Player.PrimaryResource >= 25 && CombatBase.CanCast(SNOPower.Wizard_WaveOfForce, CombatBase.CanCastFlags.NoTimer)) { return(new TrinityPower(SNOPower.Wizard_WaveOfForce, 5f, CurrentTarget.Position, CurrentWorldDynamicId, -1, 1, 2)); } bool hasEntropy = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Disintegrate && s.RuneIndex == 2); float disintegrateRange = hasEntropy ? 10f : 35f; // Disintegrate if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Disintegrate) && ((Player.PrimaryResource >= 20 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve)) { return(new TrinityPower(SNOPower.Wizard_Disintegrate, disintegrateRange, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Arcane Orb if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_ArcaneOrb) && ((Player.PrimaryResource >= 30 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve)) { return(new TrinityPower(SNOPower.Wizard_ArcaneOrb, 35f, CurrentTarget.ACDGuid)); } // Arcane Torrent if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_ArcaneTorrent) && ((Player.PrimaryResource >= 16 && !Player.WaitingForReserveEnergy) || Player.PrimaryResource >= MinEnergyReserve)) { return(new TrinityPower(SNOPower.Wizard_ArcaneTorrent, 40f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } //skillDict.Add("RayOfFrost", SNOPower.Wizard_RayOfFrost); //runeDict.Add("Numb", 2); //runeDict.Add("SnowBlast", 0); //runeDict.Add("ColdBlood", 3); //runeDict.Add("SleetStorm", 1); //runeDict.Add("BlackIce", 4); bool hasSleetStorm = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_RayOfFrost && s.RuneIndex == 1); // Ray of Frost if (!useOocBuff && !isCurrentlyAvoiding && !Player.IsIncapacitated && Hotbar.Contains(SNOPower.Wizard_RayOfFrost) && Player.PrimaryResource >= 12 && !Player.WaitingForReserveEnergy) { float range = 50f; if (hasSleetStorm) { range = 5f; } return(new TrinityPower(SNOPower.Wizard_RayOfFrost, range, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 1)); } bool hasConflagrate = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_MagicMissile && s.RuneIndex == 2); // Magic Missile if (!useOocBuff && !isCurrentlyAvoiding && Hotbar.Contains(SNOPower.Wizard_MagicMissile)) { var bestPierceTarget = TargetUtil.GetBestPierceTarget(45f); int targetId; if (bestPierceTarget != null) { targetId = hasConflagrate ? bestPierceTarget.ACDGuid : CurrentTarget.ACDGuid; } else { targetId = CurrentTarget.ACDGuid; } return(new TrinityPower(SNOPower.Wizard_MagicMissile, 45f, targetId)); } // Shock Pulse if (!useOocBuff && !isCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Wizard_ShockPulse)) { return(new TrinityPower(SNOPower.Wizard_ShockPulse, 15f, CurrentTarget.ACDGuid)); } // Spectral Blade if (!useOocBuff && !isCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Wizard_SpectralBlade)) { return(new TrinityPower(SNOPower.Wizard_SpectralBlade, 14f, CurrentTarget.ACDGuid)); } // Electrocute if (!useOocBuff && !isCurrentlyAvoiding && CombatBase.CanCast(SNOPower.Wizard_Electrocute)) { return(new TrinityPower(SNOPower.Wizard_Electrocute, 40f, CurrentTarget.ACDGuid)); } // Default attacks return(CombatBase.DefaultPower); } else { bool cancelArchon = false; string reason = ""; if (Settings.Combat.Wizard.ArchonCancelOption == WizardArchonCancelOption.RebuffArmor && !Wizard_HasWizardArmor()) { reason += "Rebuff Armor "; cancelArchon = true; } if (Settings.Combat.Wizard.ArchonCancelOption == WizardArchonCancelOption.RebuffMagicWeaponFamiliar && (!CheckAbilityAndBuff(SNOPower.Wizard_MagicWeapon) || !Wizard_HasFamiliar())) { if (!CheckAbilityAndBuff(SNOPower.Wizard_MagicWeapon)) { reason += "Rebuff Magic Weapon "; } if (!Wizard_HasFamiliar()) { reason += "Rebuff Familiar "; } cancelArchon = true; } if (Settings.Combat.Wizard.ArchonCancelOption == WizardArchonCancelOption.Timer && DateTime.UtcNow.Subtract(CacheData.AbilityLastUsed[SNOPower.Wizard_Archon]).TotalSeconds >= Settings.Combat.Wizard.ArchonCancelSeconds) { reason += "Timer"; cancelArchon = true; } if (cancelArchon && Wizard_ShouldStartArchon()) { var archonBuff = ZetaDia.Me.GetBuff(SNOPower.Wizard_Archon); if (archonBuff != null && archonBuff.IsCancelable) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Behavior, "Canceling Archon: {0}", reason); // this actually cancels Archon archonBuff.Cancel(); // this SNOPower is fake - it isn't actually used, we're just putting it here to force a BehaviorTree return/recheck return(new TrinityPower(SNOPower.Wizard_Archon_Cancel, 0f, Vector3.Zero, -1, -1, -1, -1)); } } // Archon form // Archon Slow Time for in combat if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Archon_SlowTime, CombatBase.CanCastFlags.NoTimer) && (CombatBase.TimeSpanSincePowerUse(SNOPower.Wizard_Archon_SlowTime) > TimeSpan.FromSeconds(30))) { return(new TrinityPower(SNOPower.Wizard_Archon_SlowTime, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } // Archon Teleport in combat for kiting if (!useOocBuff && !isCurrentlyAvoiding && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Archon_Teleport, CombatBase.CanCastFlags.NoTimer) && Settings.Combat.Wizard.KiteLimit > 0 && // Try and teleport-retreat from 1 elite or 3+ greys or a boss at 15 foot range (TargetUtil.AnyElitesInRange(15, 1) || TargetUtil.AnyMobsInRange(15, 3) || (CurrentTarget.IsBoss && CurrentTarget.RadiusDistance <= 15f))) { Vector3 vNewTarget = MathEx.CalculatePointFrom(CurrentTarget.Position, Player.Position, -20f); return(new TrinityPower(SNOPower.Wizard_Archon_Teleport, 35f, vNewTarget)); } // Archon teleport in combat for no-kite if (!useOocBuff && !isCurrentlyAvoiding && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Archon_Teleport, CombatBase.CanCastFlags.NoTimer) && Settings.Combat.Wizard.KiteLimit == 0 && CurrentTarget.RadiusDistance >= 10f) { return(new TrinityPower(SNOPower.Wizard_Archon_Teleport, 35f, CurrentTarget.Position)); } //392694, 392695, 392696 == Arcane Strike, //392697, 392699, 392698 == Disintegration Wave //392692, 392693, 392691 == Arcane Blast, Ice Blast SNOPower beamPower = SNOPower.Wizard_Archon_ArcaneBlast, strikePower = SNOPower.Wizard_Archon_ArcaneStrike, blastPower = SNOPower.Wizard_Archon_DisintegrationWave; HotbarSkills beamSkill = HotbarSkills.AssignedSkills .FirstOrDefault(p => p.Power == SNOPower.Wizard_Archon_DisintegrationWave || p.Power == (SNOPower)392697 || p.Power == (SNOPower)392699 || p.Power == (SNOPower)392698); HotbarSkills strikeSkill = HotbarSkills.AssignedSkills .FirstOrDefault(p => p.Power == SNOPower.Wizard_Archon_ArcaneStrike || p.Power == (SNOPower)392694 || p.Power == (SNOPower)392695 || p.Power == (SNOPower)392696); HotbarSkills blastSkill = HotbarSkills.AssignedSkills .FirstOrDefault(p => p.Power == SNOPower.Wizard_Archon_ArcaneBlast || p.Power == (SNOPower)392692 || p.Power == (SNOPower)392693 || p.Power == (SNOPower)392691); if (beamSkill != null && beamSkill.Power != default(SNOPower)) { beamPower = beamSkill.Power; } if (strikeSkill != null && strikeSkill.Power != default(SNOPower)) { strikePower = strikeSkill.Power; } if (blastSkill != null && blastSkill.Power != default(SNOPower)) { blastPower = blastSkill.Power; } // Arcane Blast - 2 second cooldown, big AoE if (!useOocBuff && !Player.IsIncapacitated && CombatBase.CanCast(SNOPower.Wizard_Archon_ArcaneBlast, CombatBase.CanCastFlags.NoTimer) && TargetUtil.AnyMobsInRange(15, 1) && CurrentTarget.IsFacingPlayer) { return(new TrinityPower(blastPower, 0f, Vector3.Zero, CurrentWorldDynamicId, -1, 1, 1)); } // Disintegrate if (!useOocBuff && !isCurrentlyAvoiding && !Player.IsIncapacitated && (CurrentTarget.CountUnitsBehind(25f) > 2 || Settings.Combat.Wizard.NoArcaneStrike || Settings.Combat.Wizard.KiteLimit > 0)) { return(new TrinityPower(beamPower, 49f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } // Arcane Strike Rapid Spam at close-range only, and no AoE inbetween us and target if (!useOocBuff && !Player.IsIncapacitated && !Settings.Combat.Wizard.NoArcaneStrike && !CacheData.TimeBoundAvoidance.Any(aoe => MathUtil.IntersectsPath(aoe.Position, aoe.Radius, Player.Position, CurrentTarget.Position))) { return(new TrinityPower(strikePower, 7f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 1, 1)); } // Disintegrate as final option just in case if (!useOocBuff && !isCurrentlyAvoiding && !Player.IsIncapacitated) { return(new TrinityPower(beamPower, 49f, Vector3.Zero, -1, CurrentTarget.ACDGuid, 0, 0)); } return(new TrinityPower(SNOPower.None, -1, Vector3.Zero, -1, -1, 0, 0)); } }
/// <summary> /// Check if skill can and should be cast /// </summary> public bool CanCast() { return(CombatBase.CanCast(this)); }
/// <summary> /// Performs basic checks to see if we have and can cast a power (hotbar, power manager). Checks use timer for Wiz, DH, Monk /// </summary> public bool CanCast(CombatBase.CanCastFlags flags = CombatBase.CanCastFlags.All) { return(CombatBase.CanCast(SNOPower, flags)); }
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 void MoveTowards(Vector3 vMoveToTarget) { if (Trinity.Settings.Advanced.DisableAllMovement) { return; } if (!ZetaDia.IsInGame || !ZetaDia.Me.IsValid || ZetaDia.Me.IsDead || ZetaDia.IsLoadingWorld) { return; } if (UISafetyCheck()) { return; } TimeLastUsedPlayerMover = DateTime.UtcNow; LastMoveToTarget = vMoveToTarget; // Set the public variable vMoveToTarget = WarnAndLogLongPath(vMoveToTarget); // Store player current position // Store distance to current moveto target float destinationDistance = MyPosition.Distance2D(vMoveToTarget); // Do unstuckery things if (Trinity.Settings.Advanced.UnstuckerEnabled) { // See if we can reset the 10-limit unstuck counter, if >120 seconds since we last generated an unstuck location // this is used if we're NOT stuck... if (TotalAntiStuckAttempts > 1 && DateTime.UtcNow.Subtract(LastGeneratedStuckPosition).TotalSeconds >= 120) { TotalAntiStuckAttempts = 1; TimesReachedStuckPoint = 0; vSafeMovementLocation = Vector3.Zero; NavHelper.UsedStuckSpots = new List <GridPoint>(); Logger.Log(TrinityLogLevel.Info, LogCategory.Movement, "Resetting unstuck timers", true); } // See if we need to, and can, generate unstuck actions // check if we're stuck bool isStuck = UnstuckChecker(); if (isStuck) { // Record the time we last apparently couldn't move for a brief period of time LastRecordedAnyStuck = DateTime.UtcNow; // See if there's any stuck position to try and navigate to generated by random mover vSafeMovementLocation = UnstuckHandler(MyPosition, vMoveToTarget); if (vSafeMovementLocation == Vector3.Zero) { Logger.Log(TrinityLogLevel.Info, LogCategory.Movement, "Unable to find Unstuck point!", vSafeMovementLocation); return; } Logger.Log(TrinityLogLevel.Verbose, LogCategory.Movement, "SafeMovement Location set to {0}", vSafeMovementLocation); } // See if we can clear the total unstuckattempts if we haven't been stuck in over 6 minutes. if (DateTime.UtcNow.Subtract(LastRecordedAnyStuck).TotalSeconds >= 360) { TimesReachedMaxUnstucks = 0; } // Did we have a safe point already generated (eg from last loop through), if so use it as our current location instead if (vSafeMovementLocation != Vector3.Zero) { // Set our current movement target to the safe point we generated last cycle vMoveToTarget = vSafeMovementLocation; destinationDistance = MyPosition.Distance2D(vMoveToTarget); } // Get distance to current destination // Remove the stuck position if it's been reached, this bit of code also creates multiple stuck-patterns in an ever increasing amount if (vSafeMovementLocation != Vector3.Zero && destinationDistance <= 3f) { vSafeMovementLocation = Vector3.Zero; TimesReachedStuckPoint++; // Do we want to immediately generate a 2nd waypoint to "chain" anti-stucks in an ever-increasing path-length? if (TimesReachedStuckPoint <= TotalAntiStuckAttempts) { vSafeMovementLocation = NavHelper.FindSafeZone(true, TotalAntiStuckAttempts, MyPosition); vMoveToTarget = vSafeMovementLocation; } else { if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Info, LogCategory.UserInformation, "Clearing old route and trying new path find to: " + LastMoveToTarget.ToString()); } // Reset the path and allow a whole "New" unstuck generation next cycle TimesReachedStuckPoint = 0; // And cancel unstucking for 9 seconds so DB can try to navigate CancelUnstuckerForSeconds = (9 * TotalAntiStuckAttempts); if (CancelUnstuckerForSeconds < 20) { CancelUnstuckerForSeconds = 20; } LastCancelledUnstucker = DateTime.UtcNow; Navigator.Clear(); Navigator.MoveTo(LastMoveToTarget, "original destination", false); return; } } } // don't use special movement within 10 seconds of being stuck bool cancelSpecialMovementAfterStuck = DateTime.UtcNow.Subtract(LastGeneratedStuckPosition).TotalMilliseconds > 10000; // See if we can use abilities like leap etc. for movement out of combat, but not in town if (Trinity.Settings.Combat.Misc.AllowOOCMovement && !Trinity.Player.IsInTown && !Trinity.DontMoveMeIAmDoingShit && cancelSpecialMovementAfterStuck) { bool bTooMuchZChange = (Math.Abs(MyPosition.Z - vMoveToTarget.Z) >= 4f); // Whirlwind for a barb, special context only if (Trinity.Settings.Combat.Barbarian.SprintMode != BarbarianSprintMode.CombatOnly && Trinity.Hotbar.Contains(SNOPower.Barbarian_Whirlwind) && Trinity.ObjectCache.Any(u => u.IsUnit && MathUtil.IntersectsPath(u.Position, u.Radius + 5f, Trinity.Player.Position, vMoveToTarget)) && Trinity.Player.PrimaryResource >= V.F("Barbarian.Whirlwind.MinFury") && !Trinity.IsWaitingForSpecial && V.B("Barbarian.Whirlwind.UseForMovement")) { ZetaDia.Me.UsePower(SNOPower.Barbarian_Whirlwind, vMoveToTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Barbarian_Whirlwind); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Whirlwind for OOC movement, distance={0}", destinationDistance); } return; } // Leap movement for a barb if (Trinity.Settings.Combat.Barbarian.UseLeapOOC && Trinity.Hotbar.Contains(SNOPower.Barbarian_Leap) && PowerManager.CanCast(SNOPower.Barbarian_Leap) && !ShrinesInArea(vMoveToTarget)) { Vector3 vThisTarget = vMoveToTarget; if (destinationDistance > 35f) { vThisTarget = MathEx.CalculatePointFrom(vMoveToTarget, MyPosition, 35f); } ZetaDia.Me.UsePower(SNOPower.Barbarian_Leap, vThisTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Barbarian_Leap); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Leap for OOC movement, distance={0}", destinationDistance); } return; } // Furious Charge movement for a barb if (Trinity.Settings.Combat.Barbarian.UseChargeOOC && Trinity.Hotbar.Contains(SNOPower.Barbarian_FuriousCharge) && !bTooMuchZChange && destinationDistance >= 20f && PowerManager.CanCast(SNOPower.Barbarian_FuriousCharge) && !ShrinesInArea(vMoveToTarget)) { Vector3 vThisTarget = vMoveToTarget; if (destinationDistance > 35f) { vThisTarget = MathEx.CalculatePointFrom(vMoveToTarget, MyPosition, 35f); } ZetaDia.Me.UsePower(SNOPower.Barbarian_FuriousCharge, vThisTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Barbarian_FuriousCharge); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Furious Charge for OOC movement, distance={0}", destinationDistance); } return; } bool hasTacticalAdvantage = HotbarSkills.PassiveSkills.Any(s => s == SNOPower.DemonHunter_Passive_TacticalAdvantage); int vaultDelay = hasTacticalAdvantage ? 2000 : Trinity.Settings.Combat.DemonHunter.VaultMovementDelay; // DemonHunter Vault if (Trinity.Hotbar.Contains(SNOPower.DemonHunter_Vault) && !bTooMuchZChange && Trinity.Settings.Combat.DemonHunter.VaultMode != DemonHunterVaultMode.CombatOnly && CombatBase.TimeSincePowerUse(SNOPower.DemonHunter_Vault) > vaultDelay && destinationDistance >= 18f && PowerManager.CanCast(SNOPower.DemonHunter_Vault) && !ShrinesInArea(vMoveToTarget) && // Don't Vault into avoidance/monsters if we're kiting (CombatBase.PlayerKiteDistance <= 0 || (CombatBase.PlayerKiteDistance > 0 && (!CacheData.TimeBoundAvoidance.Any(a => a.Position.Distance(vMoveToTarget) <= CombatBase.PlayerKiteDistance) || (!CacheData.TimeBoundAvoidance.Any(a => MathEx.IntersectsPath(a.Position, a.Radius, Trinity.Player.Position, vMoveToTarget))) || !CacheData.MonsterObstacles.Any(a => a.Position.Distance(vMoveToTarget) <= CombatBase.PlayerKiteDistance)))) ) { Vector3 vThisTarget = vMoveToTarget; if (destinationDistance > 35f) { vThisTarget = MathEx.CalculatePointFrom(vMoveToTarget, MyPosition, 35f); } ZetaDia.Me.UsePower(SNOPower.DemonHunter_Vault, vThisTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.DemonHunter_Vault); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Vault for OOC movement, distance={0}", destinationDistance); } return; } // Tempest rush for a monk if (Trinity.Hotbar.Contains(SNOPower.Monk_TempestRush) && (Trinity.Settings.Combat.Monk.TROption == TempestRushOption.MovementOnly || Trinity.Settings.Combat.Monk.TROption == TempestRushOption.Always || (Trinity.Settings.Combat.Monk.TROption == TempestRushOption.TrashOnly && !TargetUtil.AnyElitesInRange(40f)))) { Vector3 vTargetAimPoint = vMoveToTarget; bool canRayCastTarget = true; vTargetAimPoint = TargetUtil.FindTempestRushTarget(); if (!CanChannelTempestRush && ((Trinity.Player.PrimaryResource >= Trinity.Settings.Combat.Monk.TR_MinSpirit && destinationDistance >= Trinity.Settings.Combat.Monk.TR_MinDist) || DateTime.UtcNow.Subtract(CacheData.AbilityLastUsed[SNOPower.Monk_TempestRush]).TotalMilliseconds <= 150) && canRayCastTarget && PowerManager.CanCast(SNOPower.Monk_TempestRush)) { CanChannelTempestRush = true; } else if ((CanChannelTempestRush && (Trinity.Player.PrimaryResource < 10f)) || !canRayCastTarget) { CanChannelTempestRush = false; } double lastUse = DateTime.UtcNow.Subtract(CacheData.AbilityLastUsed[SNOPower.Monk_TempestRush]).TotalMilliseconds; if (CanChannelTempestRush) { if (Trinity.SNOPowerUseTimer(SNOPower.Monk_TempestRush)) { LastTempestRushPosition = vTargetAimPoint; ZetaDia.Me.UsePower(SNOPower.Monk_TempestRush, vTargetAimPoint, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Monk_TempestRush); // simulate movement speed of 30 SpeedSensor lastSensor = SpeedSensors.OrderByDescending(s => s.Timestamp).FirstOrDefault(); SpeedSensors.Add(new SpeedSensor() { Location = MyPosition, TimeSinceLastMove = new TimeSpan(0, 0, 0, 0, 1000), Distance = 5f, WorldID = Trinity.CurrentWorldDynamicId }); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Tempest Rush for OOC movement, distance={0:0} spirit={1:0} cd={2} lastUse={3:0} V3={4} vAim={5}", destinationDistance, Trinity.Player.PrimaryResource, PowerManager.CanCast(SNOPower.Monk_TempestRush), lastUse, vMoveToTarget, vTargetAimPoint); } return; } else { return; } } else { if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Tempest rush failed!: {0:00.0} / {1} distance: {2:00.0} / {3} Raycast: {4} MS: {5:0.0} lastUse={6:0}", Trinity.Player.PrimaryResource, Trinity.Settings.Combat.Monk.TR_MinSpirit, destinationDistance, Trinity.Settings.Combat.Monk.TR_MinDist, canRayCastTarget, GetMovementSpeed(), lastUse); } Trinity.MaintainTempestRush = false; } // Always set this from PlayerMover Trinity.LastTempestRushLocation = vTargetAimPoint; } // Dashing Strike OOC if (CombatBase.CanCast(SNOPower.X1_Monk_DashingStrike) && Trinity.Settings.Combat.Monk.UseDashingStrikeOOC && destinationDistance > 15f) { ZetaDia.Me.UsePower(SNOPower.X1_Monk_DashingStrike, vMoveToTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.X1_Monk_DashingStrike); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Dashing Strike for OOC movement, distance={0}", destinationDistance); } } bool hasWormHole = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Teleport && s.RuneIndex == 4); bool hasCalamity = HotbarSkills.AssignedSkills.Any(s => s.Power == SNOPower.Wizard_Teleport && s.RuneIndex == 0); // Teleport for a wizard if (!hasCalamity && CombatBase.CanCast(SNOPower.Wizard_Teleport, CombatBase.CanCastFlags.NoTimer) && CombatBase.TimeSincePowerUse(SNOPower.Wizard_Teleport) > 250 && destinationDistance >= 10f && !ShrinesInArea(vMoveToTarget)) { var maxTeleportRange = 75f; Vector3 vThisTarget = vMoveToTarget; if (destinationDistance > maxTeleportRange) { vThisTarget = MathEx.CalculatePointFrom(vMoveToTarget, MyPosition, maxTeleportRange); } ZetaDia.Me.UsePower(SNOPower.Wizard_Teleport, vThisTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Wizard_Teleport); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Teleport for OOC movement, distance={0}", destinationDistance); } return; } // Archon Teleport for a wizard if (Trinity.Hotbar.Contains(SNOPower.Wizard_Archon_Teleport) && DateTime.UtcNow.Subtract(CacheData.AbilityLastUsed[SNOPower.Wizard_Archon_Teleport]).TotalMilliseconds >= CombatBase.GetSNOPowerUseDelay(SNOPower.Wizard_Archon_Teleport) && destinationDistance >= 20f && PowerManager.CanCast(SNOPower.Wizard_Archon_Teleport) && !ShrinesInArea(vMoveToTarget)) { Vector3 vThisTarget = vMoveToTarget; if (destinationDistance > 35f) { vThisTarget = MathEx.CalculatePointFrom(vMoveToTarget, MyPosition, 35f); } ZetaDia.Me.UsePower(SNOPower.Wizard_Archon_Teleport, vThisTarget, Trinity.CurrentWorldDynamicId, -1); SpellHistory.RecordSpell(SNOPower.Wizard_Archon_Teleport); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Using Archon Teleport for OOC movement, distance={0}", destinationDistance); } return; } } if (MyPosition.Distance2D(vMoveToTarget) > 1f) { // Default movement ZetaDia.Me.UsePower(SNOPower.Walk, vMoveToTarget, Trinity.CurrentWorldDynamicId, -1); if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Moved to:{0} dir:{1} Speed:{2:0.00} Dist:{3:0} ZDiff:{4:0} CanStand:{5} Raycast:{6}", NavHelper.PrettyPrintVector3(vMoveToTarget), MathUtil.GetHeadingToPoint(vMoveToTarget), MovementSpeed, MyPosition.Distance2D(vMoveToTarget), Math.Abs(MyPosition.Z - vMoveToTarget.Z), Trinity.MainGridProvider.CanStandAt(Trinity.MainGridProvider.WorldToGrid(vMoveToTarget.ToVector2())), !Navigator.Raycast(MyPosition, vMoveToTarget) ); } } else { if (Trinity.Settings.Advanced.LogCategories.HasFlag(LogCategory.Movement)) { Logger.Log(TrinityLogLevel.Debug, LogCategory.Movement, "Reached MoveTowards Destination {0} Current Speed: {1:0.0}", vMoveToTarget, MovementSpeed); } } }
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); }
//var enemyList = new HashSet<CombatBase>(); void TryAttack(CombatBase enemy) { enemy.TakeDamage(fDamage); }
/// <summary> /// This will find a safe place to stand in both Kiting and Avoidance situations /// </summary> /// <param name="isStuck"></param> /// <param name="stuckAttempts"></param> /// <param name="dangerPoint"></param> /// <param name="shouldKite"></param> /// <param name="avoidDeath"></param> /// <returns></returns> internal static Vector3 FindSafeZone(bool isStuck, int stuckAttempts, Vector3 dangerPoint, bool shouldKite = false, IEnumerable <TrinityCacheObject> monsterList = null, bool avoidDeath = false) { // Handle The Butcher's Lair var butcherFloorPanels = CacheData.TimeBoundAvoidance.Where(aoe => DataDictionary.ButcherFloorPanels.Contains(aoe.ActorSNO)).ToList(); if (butcherFloorPanels.Any()) { foreach (var safePoint in DataDictionary.ButcherPanelPositions.OrderBy(p => p.Value.Distance2DSqr(Trinity.Player.Position))) { // Floor panel with fire animation was added to cache if (butcherFloorPanels.Any(p => p.ActorSNO == safePoint.Key && p.Position.Distance2DSqr(safePoint.Value) <= 15f * 15f)) { continue; } // floor panel position is in Butcher animation avoidance (charging, chain hook) if (CacheData.TimeBoundAvoidance.Any(aoe => aoe.Position.Distance2D(safePoint.Value) < aoe.Radius)) { continue; } // no avoidance object in cache, this point is safe return(safePoint.Value); } // Don't fall back to regular avoidance return(Vector3.Zero); } if (!isStuck) { if (shouldKite && DateTime.UtcNow.Subtract(lastFoundSafeSpot).TotalMilliseconds <= 1500 && lastSafeZonePosition != Vector3.Zero) { return(lastSafeZonePosition); } if (DateTime.UtcNow.Subtract(lastFoundSafeSpot).TotalMilliseconds <= 800 && lastSafeZonePosition != Vector3.Zero) { return(lastSafeZonePosition); } hasEmergencyTeleportUp = (!Player.IsIncapacitated && ( // Leap is available (CombatBase.CanCast(SNOPower.Barbarian_Leap)) || // Whirlwind is available (CombatBase.CanCast(SNOPower.Barbarian_Whirlwind) && ((Player.PrimaryResource >= 10 && !CombatBase.IsWaitingForSpecial) || Player.PrimaryResource >= Trinity.MinEnergyReserve)) || // Tempest rush is available (CombatBase.CanCast(SNOPower.Monk_TempestRush) && ((Player.PrimaryResource >= 20 && !CombatBase.IsWaitingForSpecial) || Player.PrimaryResource >= Trinity.MinEnergyReserve)) || // Teleport is available (CombatBase.CanCast(SNOPower.Wizard_Teleport) && Player.PrimaryResource >= 15) || // Archon Teleport is available (CombatBase.CanCast(SNOPower.Wizard_Archon_Teleport)) )); // Wizards can look for bee stings in range and try a wave of force to dispel them if (!shouldKite && Player.ActorClass == ActorClass.Wizard && CombatBase.CanCast(SNOPower.Wizard_WaveOfForce) && !Player.IsIncapacitated && CacheData.TimeBoundAvoidance.Count(u => u.ActorSNO == 5212 && u.Position.Distance(Player.Position) <= 15f) >= 2 && ( //HotbarSkills.PassiveSkills.Contains(SNOPower.Wizard_Passive_CriticalMass) || PowerManager.CanCast(SNOPower.Wizard_WaveOfForce))) { ZetaDia.Me.UsePower(SNOPower.Wizard_WaveOfForce, Vector3.Zero, Player.WorldDynamicID, -1); } } float highestWeight = 0f; if (monsterList == null) { monsterList = new List <TrinityCacheObject>(); } //Vector3 vBestLocation = FindSafeZone(dangerPoint, shouldKite, isStuck, monsterList, avoidDeath); Vector3 vBestLocation = MainFindSafeZone(dangerPoint, shouldKite, isStuck, monsterList, avoidDeath); highestWeight = 1; // Loop through distance-range steps if (highestWeight <= 0) { return(vBestLocation); } lastFoundSafeSpot = DateTime.UtcNow; lastSafeZonePosition = vBestLocation; return(vBestLocation); }
// Save Configuration private void SaveConfiguration() { Settings.Save(); CombatBase.LoadCombatSettings(); }
// Load Configuration private void LoadConfiguration() { Settings.Load(); CombatBase.LoadCombatSettings(); }