/* * Copyright (C) 2012-2020 CypherCore * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using Framework.Constants; using Game.Entities; using Game.Spells; using System; using System.Collections.Generic; namespace Game.AI { public struct Spells { /* Generic */ public const uint AutoShot = 75; public const uint Shoot = 3018; public const uint Throw = 2764; public const uint Wand = 5019; /* Warrior - Generic */ public const uint BattleStance = 2457; public const uint BerserkerStance = 2458; public const uint DefensiveStance = 71; public const uint Charge = 11578; public const uint Intercept = 20252; public const uint EnragedRegen = 55694; public const uint IntimidatingShout = 5246; public const uint Pummel = 6552; public const uint ShieldBash = 72; public const uint Bloodrage = 2687; /* Warrior - Arms */ public const uint SweepingStrikes = 12328; public const uint MortalStrike = 12294; public const uint Bladestorm = 46924; public const uint Rend = 47465; public const uint Retaliation = 20230; public const uint ShatteringThrow = 64382; public const uint ThunderClap = 47502; /* Warrior - Fury */ public const uint DeathWish = 12292; public const uint Bloodthirst = 23881; public const uint PassiveTitansGrip = 46917; public const uint DemoShout = 47437; public const uint Execute = 47471; public const uint HeroicFury = 60970; public const uint Recklessness = 1719; public const uint PiercingHowl = 12323; /* Warrior - Protection */ public const uint Vigilance = 50720; public const uint Devastate = 20243; public const uint Shockwave = 46968; public const uint ConcussionBlow = 12809; public const uint Disarm = 676; public const uint LastStand = 12975; public const uint ShieldBlock = 2565; public const uint ShieldSlam = 47488; public const uint ShieldWall = 871; public const uint Reflection = 23920; /* Paladin - Generic */ public const uint PalAuraMastery = 31821; public const uint LayOnHands = 48788; public const uint BlessingOfMight = 48932; public const uint AvengingWrath = 31884; public const uint DivineProtection = 498; public const uint DivineShield = 642; public const uint HammerOfJustice = 10308; public const uint HandOfFreedom = 1044; public const uint HandOfProtection = 10278; public const uint HandOfSacrifice = 6940; /* Paladin - Holy*/ public const uint PassiveIllumination = 20215; public const uint HolyShock = 20473; public const uint BeaconOfLight = 53563; public const uint Consecration = 48819; public const uint FlashOfLight = 48785; public const uint HolyLight = 48782; public const uint DivineFavor = 20216; public const uint DivineIllumination = 31842; /* Paladin - Protection */ public const uint BlessOfSanc = 20911; public const uint HolyShield = 20925; public const uint AvengersShield = 48827; public const uint DivineSacrifice = 64205; public const uint HammerOfRighteous = 53595; public const uint RighteousFury = 25780; public const uint ShieldOfRighteous = 61411; /* Paladin - Retribution */ public const uint SealOfCommand = 20375; public const uint CrusaderStrike = 35395; public const uint DivineStorm = 53385; public const uint Judgement = 20271; public const uint HammerOfWrath = 48806; /* Hunter - Generic */ public const uint Deterrence = 19263; public const uint ExplosiveTrap = 49067; public const uint FreezingArrow = 60192; public const uint RapidFire = 3045; public const uint KillShot = 61006; public const uint MultiShot = 49048; public const uint ViperSting = 3034; /* Hunter - Beast Mastery */ public const uint BestialWrath = 19574; public const uint PassiveBeastWithin = 34692; public const uint PassiveBeastMastery = 53270; /* Hunter - Marksmanship */ public const uint AimedShot = 19434; public const uint PassiveTrueshotAura = 19506; public const uint ChimeraShot = 53209; public const uint ArcaneShot = 49045; public const uint SteadyShot = 49052; public const uint Readiness = 23989; public const uint SilencingShot = 34490; /* Hunter - Survival */ public const uint PassiveLockAndLoad = 56344; public const uint WyvernSting = 19386; public const uint ExplosiveShot = 53301; public const uint BlackArrow = 3674; /* Rogue - Generic */ public const uint Dismantle = 51722; public const uint Evasion = 26669; public const uint Kick = 1766; public const uint Vanish = 26889; public const uint Blind = 2094; public const uint CloakOfShadows = 31224; /* Rogue - Assassination */ public const uint ColdBlood = 14177; public const uint Mutilate = 1329; public const uint HungerForBlood = 51662; public const uint Envenom = 57993; /* Rogue - Combat */ public const uint SinisterStrike = 48637; public const uint BladeFlurry = 13877; public const uint AdrenalineRush = 13750; public const uint KillingSpree = 51690; public const uint Eviscerate = 48668; /* Rogue - Sublety */ public const uint Hemorrhage = 16511; public const uint Premeditation = 14183; public const uint ShadowDance = 51713; public const uint Preparation = 14185; public const uint Shadowstep = 36554; /* Priest - Generic */ public const uint FearWard = 6346; public const uint PowerWordFort = 48161; public const uint DivineSpirit = 48073; public const uint ShadowProtection = 48169; public const uint DivineHymn = 64843; public const uint HymnOfHope = 64901; public const uint ShadowWordDeath = 48158; public const uint PsychicScream = 10890; /* Priest - Discipline */ public const uint PassiveSoulWarding = 63574; public const uint PowerInfusion = 10060; public const uint Penance = 47540; public const uint PainSuppression = 33206; public const uint InnerFocus = 14751; public const uint PowerWordShield = 48066; /* Priest - Holy */ public const uint PassiveSpiritRedemption = 20711; public const uint DesperatePrayer = 19236; public const uint GuardianSpirit = 47788; public const uint FlashHeal = 48071; public const uint Renew = 48068; /* Priest - Shadow */ public const uint VampiricEmbrace = 15286; public const uint Shadowform = 15473; public const uint VampiricTouch = 34914; public const uint MindFlay = 15407; public const uint MindBlast = 48127; public const uint ShadowWordPain = 48125; public const uint DevouringPlague = 48300; public const uint Dispersion = 47585; /* Death Knight - Generic */ public const uint DeathGrip = 49576; public const uint Strangulate = 47476; public const uint EmpowerRuneWeap = 47568; public const uint IcebornFortitude = 48792; public const uint AntiMagicShell = 48707; public const uint DeathCoilDk = 49895; public const uint MindFreeze = 47528; public const uint IcyTouch = 49909; public const uint AuraFrostFever = 55095; public const uint PlagueStrike = 49921; public const uint AuraBloodPlague = 55078; public const uint Pestilence = 50842; /* Death Knight - Blood */ public const uint RuneTap = 48982; public const uint Hysteria = 49016; public const uint HeartStrike = 55050; public const uint DeathStrike = 49924; public const uint BloodStrike = 49930; public const uint MarkOfBlood = 49005; public const uint VampiricBlood = 55233; /* Death Knight - Frost */ public const uint PassiveIcyTalons = 50887; public const uint FrostStrike = 49143; public const uint HowlingBlast = 49184; public const uint UnbreakableArmor = 51271; public const uint Obliterate = 51425; public const uint Deathchill = 49796; /* Death Knight - Unholy */ public const uint PassiveUnholyBlight = 49194; public const uint PassiveMasterOfGhoul = 52143; public const uint ScourgeStrike = 55090; public const uint DeathAndDecay = 49938; public const uint AntiMagicZone = 51052; public const uint SummonGargoyle = 49206; /* Shaman - Generic */ public const uint Heroism = 32182; public const uint Bloodlust = 2825; public const uint GroundingTotem = 8177; /* Shaman - Elemental*/ public const uint PassiveElementalFocus = 16164; public const uint TotemOfWrath = 30706; public const uint Thunderstorm = 51490; public const uint LightningBolt = 49238; public const uint EarthShock = 49231; public const uint FlameShock = 49233; public const uint LavaBurst = 60043; public const uint ChainLightning = 49271; public const uint ElementalMastery = 16166; /* Shaman - Enhancement */ public const uint PassiveSpiritWeapons = 16268; public const uint LavaLash = 60103; public const uint FeralSpirit = 51533; public const uint AuraMaelstromWeapon = 53817; public const uint Stormstrike = 17364; public const uint ShamanisticRage = 30823; /* Shaman - Restoration*/ public const uint ShaNatureSwift = 591; public const uint ManaTideTotem = 590; public const uint EarthShield = 49284; public const uint Riptide = 61295; public const uint HealingWave = 49273; public const uint LesserHealWave = 49276; public const uint TidalForce = 55198; /* Mage - Generic */ public const uint DampenMagic = 43015; public const uint Evocation = 12051; public const uint ManaShield = 43020; public const uint MirrorImage = 55342; public const uint Spellsteal = 30449; public const uint Counterspell = 2139; public const uint IceBlock = 45438; /* Mage - Arcane */ public const uint FocusMagic = 54646; public const uint ArcanePower = 12042; public const uint ArcaneBarrage = 44425; public const uint ArcaneBlast = 42897; public const uint AuraArcaneBlast = 36032; public const uint ArcaneMissiles = 42846; public const uint PresenceOfMind = 12043; /* Mage - Fire */ public const uint Pyroblast = 11366; public const uint Combustion = 11129; public const uint LivingBomb = 44457; public const uint Fireball = 42833; public const uint FireBlast = 42873; public const uint DragonsBreath = 31661; public const uint BlastWave = 11113; /* Mage - Frost */ public const uint IcyVeins = 12472; public const uint IceBarrier = 11426; public const uint DeepFreeze = 44572; public const uint FrostNova = 42917; public const uint Frostbolt = 42842; public const uint ColdSnap = 11958; public const uint IceLance = 42914; /* Warlock - Generic */ public const uint Fear = 6215; public const uint HowlOfTerror = 17928; public const uint Corruption = 47813; public const uint DeathCoilW = 47860; public const uint ShadowBolt = 47809; public const uint Incinerate = 47838; public const uint Immolate = 47811; public const uint SeedOfCorruption = 47836; /* Warlock - Affliction */ public const uint PassiveSiphonLife = 63108; public const uint UnstableAffliction = 30108; public const uint Haunt = 48181; public const uint CurseOfAgony = 47864; public const uint DrainSoul = 47855; /* Warlock - Demonology */ public const uint SoulLink = 19028; public const uint DemonicEmpowerment = 47193; public const uint Metamorphosis = 59672; public const uint ImmolationAura = 50589; public const uint DemonCharge = 54785; public const uint AuraDecimation = 63167; public const uint AuraMoltenCore = 71165; public const uint SoulFire = 47825; /* Warlock - Destruction */ public const uint Shadowburn = 17877; public const uint Conflagrate = 17962; public const uint ChaosBolt = 50796; public const uint Shadowfury = 47847; /* Druid - Generic */ public const uint Barkskin = 22812; public const uint Innervate = 29166; /* Druid - Balance */ public const uint InsectSwarm = 5570; public const uint MoonkinForm = 24858; public const uint Starfall = 48505; public const uint Typhoon = 61384; public const uint AuraEclipseLunar = 48518; public const uint Moonfire = 48463; public const uint Starfire = 48465; public const uint Wrath = 48461; /* Druid - Feral */ public const uint CatForm = 768; public const uint SurvivalInstincts = 61336; public const uint Mangle = 33917; public const uint Berserk = 50334; public const uint MangleCat = 48566; public const uint FeralChargeCat = 49376; public const uint Rake = 48574; public const uint Rip = 49800; public const uint SavageRoar = 52610; public const uint TigerFury = 50213; public const uint Claw = 48570; public const uint Dash = 33357; public const uint Maim = 49802; /* Druid - Restoration */ public const uint Swiftmend = 18562; public const uint TreeOfLife = 33891; public const uint WildGrowth = 48438; public const uint NatureSwiftness = 17116; public const uint Tranquility = 48447; public const uint Nourish = 50464; public const uint HealingTouch = 48378; public const uint Rejuvenation = 48441; public const uint Regrowth = 48443; public const uint Lifebloom = 48451; } public class PlayerAI : UnitAI { protected new Player me; uint _selfSpec; bool _isSelfHealer; bool _isSelfRangedAttacker; public PlayerAI(Player player) : base(player) { me = player; _selfSpec = player.GetPrimarySpecialization(); _isSelfHealer = IsPlayerHealer(player); _isSelfRangedAttacker = IsPlayerRangedAttacker(player); } bool IsPlayerHealer(Player who) { if (!who) return false; return who.GetClass() switch { Class.Paladin => who.GetPrimarySpecialization() == (uint)TalentSpecialization.PaladinHoly, Class.Priest => who.GetPrimarySpecialization() == (uint)TalentSpecialization.PriestDiscipline || who.GetPrimarySpecialization() == (uint)TalentSpecialization.PriestHoly, Class.Shaman => who.GetPrimarySpecialization() == (uint)TalentSpecialization.ShamanRestoration, Class.Monk => who.GetPrimarySpecialization() == (uint)TalentSpecialization.MonkMistweaver, Class.Druid => who.GetPrimarySpecialization() == (uint)TalentSpecialization.DruidRestoration, _ => false, }; } bool IsPlayerRangedAttacker(Player who) { if (!who) return false; switch (who.GetClass()) { case Class.Warrior: case Class.Paladin: case Class.Rogue: case Class.Deathknight: default: return false; case Class.Mage: case Class.Warlock: return true; case Class.Hunter: { // check if we have a ranged weapon equipped Item rangedSlot = who.GetItemByPos(InventorySlots.Bag0, EquipmentSlot.Ranged); ItemTemplate rangedTemplate = rangedSlot ? rangedSlot.GetTemplate() : null; if (rangedTemplate != null) if (Convert.ToBoolean((1 << (int)rangedTemplate.GetSubClass()) & (int)ItemSubClassWeapon.MaskRanged)) return true; return false; } case Class.Priest: return who.GetPrimarySpecialization() == (uint)TalentSpecialization.PriestShadow; case Class.Shaman: return who.GetPrimarySpecialization() == (uint)TalentSpecialization.ShamanElemental; case Class.Druid: return who.GetPrimarySpecialization() == (uint)TalentSpecialization.DruidBalance; } } Tuple VerifySpellCast(uint spellId, Unit target) { // Find highest spell rank that we know uint knownRank, nextRank; if (me.HasSpell(spellId)) { // this will save us some lookups if the player has the highest rank (expected case) knownRank = spellId; nextRank = Global.SpellMgr.GetNextSpellInChain(spellId); } else { knownRank = 0; nextRank = Global.SpellMgr.GetFirstSpellInChain(spellId); } while (nextRank != 0 && me.HasSpell(nextRank)) { knownRank = nextRank; nextRank = Global.SpellMgr.GetNextSpellInChain(knownRank); } if (knownRank == 0) return null; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(knownRank, me.GetMap().GetDifficultyID()); if (spellInfo == null) return null; if (me.GetSpellHistory().HasGlobalCooldown(spellInfo)) return null; Spell spell = new(me, spellInfo, TriggerCastFlags.None); if (spell.CanAutoCast(target)) return Tuple.Create(spell, target); return null; } public Tuple VerifySpellCast(uint spellId, SpellTarget target) { Unit pTarget = null; switch (target) { case SpellTarget.None: break; case SpellTarget.Victim: pTarget = me.GetVictim(); if (!pTarget) return null; break; case SpellTarget.Charmer: pTarget = me.GetCharmer(); if (!pTarget) return null; break; case SpellTarget.Self: pTarget = me; break; } return VerifySpellCast(spellId, pTarget); } public Tuple SelectSpellCast(List, uint>> spells) { if (spells.Empty()) return null; uint totalWeights = 0; foreach (var wSpell in spells) totalWeights += wSpell.Item2; Tuple selected = null; uint randNum = RandomHelper.URand(0, totalWeights - 1); foreach (var wSpell in spells) { if (selected != null) { //delete wSpell.first.first; continue; } if (randNum < wSpell.Item2) selected = wSpell.Item1; else { randNum -= wSpell.Item2; //delete wSpell.first.first; } } spells.Clear(); return selected; } public void VerifyAndPushSpellCast(List, uint>> spells, uint spellId, T target, uint weight) where T : Unit { Tuple spell = VerifySpellCast(spellId, target); if (spell != null) spells.Add(Tuple.Create(spell, weight)); } public void DoCastAtTarget(Tuple spell) { SpellCastTargets targets = new(); targets.SetUnitTarget(spell.Item2); spell.Item1.Prepare(targets); } void DoRangedAttackIfReady() { if (me.HasUnitState(UnitState.Casting)) return; if (!me.IsAttackReady(WeaponAttackType.RangedAttack)) return; Unit victim = me.GetVictim(); if (!victim) return; uint rangedAttackSpell = 0; Item rangedItem = me.GetItemByPos(InventorySlots.Bag0, EquipmentSlot.Ranged); ItemTemplate rangedTemplate = rangedItem ? rangedItem.GetTemplate() : null; if (rangedTemplate != null) { switch ((ItemSubClassWeapon)rangedTemplate.GetSubClass()) { case ItemSubClassWeapon.Bow: case ItemSubClassWeapon.Gun: case ItemSubClassWeapon.Crossbow: rangedAttackSpell = Spells.Shoot; break; case ItemSubClassWeapon.Thrown: rangedAttackSpell = Spells.Throw; break; case ItemSubClassWeapon.Wand: rangedAttackSpell = Spells.Wand; break; } } if (rangedAttackSpell == 0) return; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(rangedAttackSpell, me.GetMap().GetDifficultyID()); if (spellInfo == null) return; Spell spell = new(me, spellInfo, TriggerCastFlags.CastDirectly); if (spell.CheckPetCast(victim) != SpellCastResult.SpellCastOk) return; SpellCastTargets targets = new(); targets.SetUnitTarget(victim); spell.Prepare(targets); me.ResetAttackTimer(WeaponAttackType.RangedAttack); } public void DoAutoAttackIfReady() { if (IsRangedAttacker()) DoRangedAttackIfReady(); else DoMeleeAttackIfReady(); } public void CancelAllShapeshifts() { List shapeshiftAuras = me.GetAuraEffectsByType(AuraType.ModShapeshift); List removableShapeshifts = new(); foreach (AuraEffect auraEff in shapeshiftAuras) { Aura aura = auraEff.GetBase(); if (aura == null) continue; SpellInfo auraInfo = aura.GetSpellInfo(); if (auraInfo == null) continue; if (auraInfo.HasAttribute(SpellAttr0.CantCancel)) continue; if (!auraInfo.IsPositive() || auraInfo.IsPassive()) continue; removableShapeshifts.Add(aura); } foreach (Aura aura in removableShapeshifts) me.RemoveOwnedAura(aura, AuraRemoveMode.Cancel); } public Creature GetCharmer() { if (me.GetCharmerGUID().IsCreature()) return ObjectAccessor.GetCreature(me, me.GetCharmerGUID()); return null; } // helper functions to determine player info public bool IsHealer(Player who = null) { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); } public bool IsRangedAttacker(Player who = null) { return (!who || who == me) ? _isSelfRangedAttacker : IsPlayerRangedAttacker(who); } public uint GetSpec(Player who = null) { return (!who || who == me) ? _selfSpec : who.GetPrimarySpecialization(); } public void SetIsRangedAttacker(bool state) { _isSelfRangedAttacker = state; } // this allows overriding of the default ranged attacker detection public virtual Unit SelectAttackTarget() { return me.GetCharmer() ? me.GetCharmer().GetVictim() : null; } public enum SpellTarget { None, Victim, Charmer, Self } } class SimpleCharmedPlayerAI : PlayerAI { const float CASTER_CHASE_DISTANCE = 28.0f; uint _castCheckTimer; bool _chaseCloser; bool _forceFacing; bool _isFollowing; public SimpleCharmedPlayerAI(Player player) : base(player) { _castCheckTimer = 2500; _chaseCloser = false; _forceFacing = true; } public override bool CanAIAttack(Unit who) { if (!me.IsValidAttackTarget(who) || who.HasBreakableByDamageCrowdControlAura()) return false; Unit charmer = me.GetCharmer(); if (charmer != null) if (!charmer.IsValidAttackTarget(who)) return false; return base.CanAIAttack(who); } public override Unit SelectAttackTarget() { Unit charmer = me.GetCharmer(); if (charmer) { UnitAI charmerAI = charmer.GetAI(); if (charmerAI != null) return charmerAI.SelectTarget(SelectAggroTarget.Random, 0, new ValidTargetSelectPredicate(this)); return charmer.GetVictim(); } return null; } Tuple SelectAppropriateCastForSpec() { List, uint>> spells = new(); /* switch (me.getClass()) { case CLASS_WARRIOR: if (!me.IsWithinMeleeRange(me.GetVictim())) { VerifyAndPushSpellCast(spells, SPELL_CHARGE, TARGET_VICTIM, 15); VerifyAndPushSpellCast(spells, SPELL_INTERCEPT, TARGET_VICTIM, 10); } VerifyAndPushSpellCast(spells, SPELL_ENRAGED_REGEN, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_INTIMIDATING_SHOUT, TARGET_VICTIM, 4); if (me.GetVictim() && me.GetVictim().HasUnitState(UNIT_STATE_CASTING)) { VerifyAndPushSpellCast(spells, SPELL_PUMMEL, TARGET_VICTIM, 15); VerifyAndPushSpellCast(spells, SPELL_SHIELD_BASH, TARGET_VICTIM, 15); } VerifyAndPushSpellCast(spells, SPELL_BLOODRAGE, TARGET_NONE, 5); switch (GetSpec()) { case TALENT_SPEC_WARRIOR_PROTECTION: VerifyAndPushSpellCast(spells, SPELL_SHOCKWAVE, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_CONCUSSION_BLOW, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_DISARM, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_LAST_STAND, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_SHIELD_BLOCK, TARGET_NONE, 1); VerifyAndPushSpellCast(spells, SPELL_SHIELD_SLAM, TARGET_VICTIM, 4); VerifyAndPushSpellCast(spells, SPELL_SHIELD_WALL, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_SPELL_REFLECTION, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_DEVASTATE, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_REND, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_THUNDER_CLAP, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_DEMO_SHOUT, TARGET_VICTIM, 1); break; case TALENT_SPEC_WARRIOR_ARMS: VerifyAndPushSpellCast(spells, SPELL_SWEEPING_STRIKES, TARGET_NONE, 2); VerifyAndPushSpellCast(spells, SPELL_MORTAL_STRIKE, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_BLADESTORM, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_REND, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_RETALIATION, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_SHATTERING_THROW, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_SWEEPING_STRIKES, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_THUNDER_CLAP, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_EXECUTE, TARGET_VICTIM, 15); break; case TALENT_SPEC_WARRIOR_FURY: VerifyAndPushSpellCast(spells, SPELL_DEATH_WISH, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_BLOODTHIRST, TARGET_VICTIM, 4); VerifyAndPushSpellCast(spells, SPELL_DEMO_SHOUT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_EXECUTE, TARGET_VICTIM, 15); VerifyAndPushSpellCast(spells, SPELL_HEROIC_FURY, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_RECKLESSNESS, TARGET_NONE, 8); VerifyAndPushSpellCast(spells, SPELL_PIERCING_HOWL, TARGET_VICTIM, 2); break; } break; case CLASS_PALADIN: VerifyAndPushSpellCast(spells, SPELL_AURA_MASTERY, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_LAY_ON_HANDS, TARGET_CHARMER, 8); VerifyAndPushSpellCast(spells, SPELL_BLESSING_OF_MIGHT, TARGET_CHARMER, 8); VerifyAndPushSpellCast(spells, SPELL_AVENGING_WRATH, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_DIVINE_PROTECTION, TARGET_NONE, 4); VerifyAndPushSpellCast(spells, SPELL_DIVINE_SHIELD, TARGET_NONE, 2); VerifyAndPushSpellCast(spells, SPELL_HAMMER_OF_JUSTICE, TARGET_VICTIM, 6); VerifyAndPushSpellCast(spells, SPELL_HAND_OF_FREEDOM, TARGET_SELF, 3); VerifyAndPushSpellCast(spells, SPELL_HAND_OF_PROTECTION, TARGET_SELF, 1); if (Creature* creatureCharmer = GetCharmer()) { if (creatureCharmer.IsDungeonBoss() || creatureCharmer.isWorldBoss()) VerifyAndPushSpellCast(spells, SPELL_HAND_OF_SACRIFICE, creatureCharmer, 10); else VerifyAndPushSpellCast(spells, SPELL_HAND_OF_PROTECTION, creatureCharmer, 3); } switch (GetSpec()) { case TALENT_SPEC_PALADIN_PROTECTION: VerifyAndPushSpellCast(spells, SPELL_HAMMER_OF_RIGHTEOUS, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_DIVINE_SACRIFICE, TARGET_NONE, 2); VerifyAndPushSpellCast(spells, SPELL_SHIELD_OF_RIGHTEOUS, TARGET_VICTIM, 4); VerifyAndPushSpellCast(spells, SPELL_JUDGEMENT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_CONSECRATION, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_HOLY_SHIELD, TARGET_NONE, 1); break; case TALENT_SPEC_PALADIN_HOLY: VerifyAndPushSpellCast(spells, SPELL_HOLY_SHOCK, TARGET_CHARMER, 3); VerifyAndPushSpellCast(spells, SPELL_HOLY_SHOCK, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_FLASH_OF_LIGHT, TARGET_CHARMER, 4); VerifyAndPushSpellCast(spells, SPELL_HOLY_LIGHT, TARGET_CHARMER, 3); VerifyAndPushSpellCast(spells, SPELL_DIVINE_FAVOR, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_DIVINE_ILLUMINATION, TARGET_NONE, 3); break; case TALENT_SPEC_PALADIN_RETRIBUTION: VerifyAndPushSpellCast(spells, SPELL_CRUSADER_STRIKE, TARGET_VICTIM, 4); VerifyAndPushSpellCast(spells, SPELL_DIVINE_STORM, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_JUDGEMENT, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_HAMMER_OF_WRATH, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_RIGHTEOUS_FURY, TARGET_NONE, 2); break; } break; case CLASS_HUNTER: VerifyAndPushSpellCast(spells, SPELL_DETERRENCE, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_EXPLOSIVE_TRAP, TARGET_NONE, 1); VerifyAndPushSpellCast(spells, SPELL_FREEZING_ARROW, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_RAPID_FIRE, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_KILL_SHOT, TARGET_VICTIM, 10); if (me.GetVictim() && me.GetVictim().getPowerType() == POWER_MANA && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_VIPER_STING, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_VIPER_STING, TARGET_VICTIM, 5); switch (GetSpec()) { case TALENT_SPEC_HUNTER_BEASTMASTER: VerifyAndPushSpellCast(spells, SPELL_AIMED_SHOT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_ARCANE_SHOT, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_STEADY_SHOT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_MULTI_SHOT, TARGET_VICTIM, 2); break; case TALENT_SPEC_HUNTER_MARKSMAN: VerifyAndPushSpellCast(spells, SPELL_AIMED_SHOT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_CHIMERA_SHOT, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_ARCANE_SHOT, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_STEADY_SHOT, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_READINESS, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_SILENCING_SHOT, TARGET_VICTIM, 5); break; case TALENT_SPEC_HUNTER_SURVIVAL: VerifyAndPushSpellCast(spells, SPELL_EXPLOSIVE_SHOT, TARGET_VICTIM, 8); VerifyAndPushSpellCast(spells, SPELL_BLACK_ARROW, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_MULTI_SHOT, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_STEADY_SHOT, TARGET_VICTIM, 1); break; } break; case CLASS_ROGUE: { VerifyAndPushSpellCast(spells, SPELL_DISMANTLE, TARGET_VICTIM, 8); VerifyAndPushSpellCast(spells, SPELL_EVASION, TARGET_NONE, 8); VerifyAndPushSpellCast(spells, SPELL_VANISH, TARGET_NONE, 4); VerifyAndPushSpellCast(spells, SPELL_BLIND, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_CLOAK_OF_SHADOWS, TARGET_NONE, 2); uint32 builder, finisher; switch (GetSpec()) { case TALENT_SPEC_ROGUE_ASSASSINATION: builder = SPELL_MUTILATE, finisher = SPELL_ENVENOM; VerifyAndPushSpellCast(spells, SPELL_COLD_BLOOD, TARGET_NONE, 20); break; case TALENT_SPEC_ROGUE_COMBAT: builder = SPELL_SINISTER_STRIKE, finisher = SPELL_EVISCERATE; VerifyAndPushSpellCast(spells, SPELL_ADRENALINE_RUSH, TARGET_NONE, 6); VerifyAndPushSpellCast(spells, SPELL_BLADE_FLURRY, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_KILLING_SPREE, TARGET_NONE, 25); break; case TALENT_SPEC_ROGUE_SUBTLETY: builder = SPELL_HEMORRHAGE, finisher = SPELL_EVISCERATE; VerifyAndPushSpellCast(spells, SPELL_PREPARATION, TARGET_NONE, 10); if (!me.IsWithinMeleeRange(me.GetVictim())) VerifyAndPushSpellCast(spells, SPELL_SHADOWSTEP, TARGET_VICTIM, 25); VerifyAndPushSpellCast(spells, SPELL_SHADOW_DANCE, TARGET_NONE, 10); break; } if (Unit* victim = me.GetVictim()) { if (victim.HasUnitState(UNIT_STATE_CASTING)) VerifyAndPushSpellCast(spells, SPELL_KICK, TARGET_VICTIM, 25); uint8 const cp = me.GetPower(POWER_COMBO_POINTS); if (cp >= 4) VerifyAndPushSpellCast(spells, finisher, TARGET_VICTIM, 10); if (cp <= 4) VerifyAndPushSpellCast(spells, builder, TARGET_VICTIM, 5); } break; } case CLASS_PRIEST: VerifyAndPushSpellCast(spells, SPELL_FEAR_WARD, TARGET_SELF, 2); VerifyAndPushSpellCast(spells, SPELL_POWER_WORD_FORT, TARGET_CHARMER, 1); VerifyAndPushSpellCast(spells, SPELL_DIVINE_SPIRIT, TARGET_CHARMER, 1); VerifyAndPushSpellCast(spells, SPELL_SHADOW_PROTECTION, TARGET_CHARMER, 2); VerifyAndPushSpellCast(spells, SPELL_DIVINE_HYMN, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_HYMN_OF_HOPE, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_SHADOW_WORD_DEATH, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_PSYCHIC_SCREAM, TARGET_VICTIM, 3); switch (GetSpec()) { case TALENT_SPEC_PRIEST_DISCIPLINE: VerifyAndPushSpellCast(spells, SPELL_POWER_WORD_SHIELD, TARGET_CHARMER, 3); VerifyAndPushSpellCast(spells, SPELL_INNER_FOCUS, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_PAIN_SUPPRESSION, TARGET_CHARMER, 15); VerifyAndPushSpellCast(spells, SPELL_POWER_INFUSION, TARGET_CHARMER, 10); VerifyAndPushSpellCast(spells, SPELL_PENANCE, TARGET_CHARMER, 3); VerifyAndPushSpellCast(spells, SPELL_FLASH_HEAL, TARGET_CHARMER, 1); break; case TALENT_SPEC_PRIEST_HOLY: VerifyAndPushSpellCast(spells, SPELL_DESPERATE_PRAYER, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_GUARDIAN_SPIRIT, TARGET_CHARMER, 5); VerifyAndPushSpellCast(spells, SPELL_FLASH_HEAL, TARGET_CHARMER, 1); VerifyAndPushSpellCast(spells, SPELL_RENEW, TARGET_CHARMER, 3); break; case TALENT_SPEC_PRIEST_SHADOW: if (!me.HasAura(SPELL_SHADOWFORM)) { VerifyAndPushSpellCast(spells, SPELL_SHADOWFORM, TARGET_NONE, 100); break; } if (Unit* victim = me.GetVictim()) { if (!victim.GetAuraApplicationOfRankedSpell(SPELL_VAMPIRIC_TOUCH, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_VAMPIRIC_TOUCH, TARGET_VICTIM, 4); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_SHADOW_WORD_PAIN, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_SHADOW_WORD_PAIN, TARGET_VICTIM, 3); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_DEVOURING_PLAGUE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_DEVOURING_PLAGUE, TARGET_VICTIM, 4); } VerifyAndPushSpellCast(spells, SPELL_MIND_BLAST, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_MIND_FLAY, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_DISPERSION, TARGET_NONE, 10); break; } break; case CLASS_DEATH_KNIGHT: { if (!me.IsWithinMeleeRange(me.GetVictim())) VerifyAndPushSpellCast(spells, SPELL_DEATH_GRIP, TARGET_VICTIM, 25); VerifyAndPushSpellCast(spells, SPELL_STRANGULATE, TARGET_VICTIM, 15); VerifyAndPushSpellCast(spells, SPELL_EMPOWER_RUNE_WEAP, TARGET_NONE, 5); VerifyAndPushSpellCast(spells, SPELL_ICEBORN_FORTITUDE, TARGET_NONE, 15); VerifyAndPushSpellCast(spells, SPELL_ANTI_MAGIC_SHELL, TARGET_NONE, 10); bool hasFF = false, hasBP = false; if (Unit* victim = me.GetVictim()) { if (victim.HasUnitState(UNIT_STATE_CASTING)) VerifyAndPushSpellCast(spells, SPELL_MIND_FREEZE, TARGET_VICTIM, 25); hasFF = !!victim.GetAuraApplicationOfRankedSpell(AURA_FROST_FEVER, me.GetGUID()), hasBP = !!victim.GetAuraApplicationOfRankedSpell(AURA_BLOOD_PLAGUE, me.GetGUID()); if (hasFF && hasBP) VerifyAndPushSpellCast(spells, SPELL_PESTILENCE, TARGET_VICTIM, 3); if (!hasFF) VerifyAndPushSpellCast(spells, SPELL_ICY_TOUCH, TARGET_VICTIM, 4); if (!hasBP) VerifyAndPushSpellCast(spells, SPELL_PLAGUE_STRIKE, TARGET_VICTIM, 4); } switch (GetSpec()) { case TALENT_SPEC_DEATHKNIGHT_BLOOD: VerifyAndPushSpellCast(spells, SPELL_RUNE_TAP, TARGET_NONE, 2); VerifyAndPushSpellCast(spells, SPELL_HYSTERIA, TARGET_SELF, 5); if (Creature* creatureCharmer = GetCharmer()) if (!creatureCharmer.IsDungeonBoss() && !creatureCharmer.isWorldBoss()) VerifyAndPushSpellCast(spells, SPELL_HYSTERIA, creatureCharmer, 15); VerifyAndPushSpellCast(spells, SPELL_HEART_STRIKE, TARGET_VICTIM, 2); if (hasFF && hasBP) VerifyAndPushSpellCast(spells, SPELL_DEATH_STRIKE, TARGET_VICTIM, 8); VerifyAndPushSpellCast(spells, SPELL_DEATH_COIL_DK, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_MARK_OF_BLOOD, TARGET_VICTIM, 20); VerifyAndPushSpellCast(spells, SPELL_VAMPIRIC_BLOOD, TARGET_NONE, 10); break; case TALENT_SPEC_DEATHKNIGHT_FROST: if (hasFF && hasBP) VerifyAndPushSpellCast(spells, SPELL_OBLITERATE, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_HOWLING_BLAST, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_UNBREAKABLE_ARMOR, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_DEATHCHILL, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_FROST_STRIKE, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_BLOOD_STRIKE, TARGET_VICTIM, 1); break; case TALENT_SPEC_DEATHKNIGHT_UNHOLY: if (hasFF && hasBP) VerifyAndPushSpellCast(spells, SPELL_SCOURGE_STRIKE, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_DEATH_AND_DECAY, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_ANTI_MAGIC_ZONE, TARGET_NONE, 8); VerifyAndPushSpellCast(spells, SPELL_SUMMON_GARGOYLE, TARGET_VICTIM, 7); VerifyAndPushSpellCast(spells, SPELL_BLOOD_STRIKE, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_DEATH_COIL_DK, TARGET_VICTIM, 3); break; } break; } case CLASS_SHAMAN: VerifyAndPushSpellCast(spells, SPELL_HEROISM, TARGET_NONE, 25); VerifyAndPushSpellCast(spells, SPELL_BLOODLUST, TARGET_NONE, 25); VerifyAndPushSpellCast(spells, SPELL_GROUNDING_TOTEM, TARGET_NONE, 2); switch (GetSpec()) { case TALENT_SPEC_SHAMAN_RESTORATION: if (Unit* charmer = me.GetCharmer()) if (!charmer.GetAuraApplicationOfRankedSpell(SPELL_EARTH_SHIELD, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_EARTH_SHIELD, charmer, 2); if (me.HasAura(SPELL_SHA_NATURE_SWIFT)) VerifyAndPushSpellCast(spells, SPELL_HEALING_WAVE, TARGET_CHARMER, 20); else VerifyAndPushSpellCast(spells, SPELL_LESSER_HEAL_WAVE, TARGET_CHARMER, 1); VerifyAndPushSpellCast(spells, SPELL_TIDAL_FORCE, TARGET_NONE, 4); VerifyAndPushSpellCast(spells, SPELL_SHA_NATURE_SWIFT, TARGET_NONE, 4); VerifyAndPushSpellCast(spells, SPELL_MANA_TIDE_TOTEM, TARGET_NONE, 3); break; case TALENT_SPEC_SHAMAN_ELEMENTAL: if (Unit* victim = me.GetVictim()) { if (victim.GetAuraOfRankedSpell(SPELL_FLAME_SHOCK, GetGUID())) VerifyAndPushSpellCast(spells, SPELL_LAVA_BURST, TARGET_VICTIM, 5); else VerifyAndPushSpellCast(spells, SPELL_FLAME_SHOCK, TARGET_VICTIM, 3); } VerifyAndPushSpellCast(spells, SPELL_CHAIN_LIGHTNING, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_LIGHTNING_BOLT, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_ELEMENTAL_MASTERY, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_THUNDERSTORM, TARGET_NONE, 3); break; case TALENT_SPEC_SHAMAN_ENHANCEMENT: if (Aura const* maelstrom = me.GetAura(AURA_MAELSTROM_WEAPON)) if (maelstrom.GetStackAmount() == 5) VerifyAndPushSpellCast(spells, SPELL_LIGHTNING_BOLT, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_STORMSTRIKE, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_EARTH_SHOCK, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_LAVA_LASH, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_SHAMANISTIC_RAGE, TARGET_NONE, 10); break; } break; case CLASS_MAGE: if (me.GetVictim() && me.GetVictim().HasUnitState(UNIT_STATE_CASTING)) VerifyAndPushSpellCast(spells, SPELL_COUNTERSPELL, TARGET_VICTIM, 25); VerifyAndPushSpellCast(spells, SPELL_DAMPEN_MAGIC, TARGET_CHARMER, 2); VerifyAndPushSpellCast(spells, SPELL_EVOCATION, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_MANA_SHIELD, TARGET_NONE, 1); VerifyAndPushSpellCast(spells, SPELL_MIRROR_IMAGE, TARGET_NONE, 3); VerifyAndPushSpellCast(spells, SPELL_SPELLSTEAL, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_ICE_BLOCK, TARGET_NONE, 1); VerifyAndPushSpellCast(spells, SPELL_ICY_VEINS, TARGET_NONE, 3); switch (GetSpec()) { case TALENT_SPEC_MAGE_ARCANE: if (Aura* abAura = me.GetAura(AURA_ARCANE_BLAST)) if (abAura.GetStackAmount() >= 3) VerifyAndPushSpellCast(spells, SPELL_ARCANE_MISSILES, TARGET_VICTIM, 7); VerifyAndPushSpellCast(spells, SPELL_ARCANE_BLAST, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_ARCANE_BARRAGE, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_ARCANE_POWER, TARGET_NONE, 8); VerifyAndPushSpellCast(spells, SPELL_PRESENCE_OF_MIND, TARGET_NONE, 7); break; case TALENT_SPEC_MAGE_FIRE: if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_LIVING_BOMB)) VerifyAndPushSpellCast(spells, SPELL_LIVING_BOMB, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_COMBUSTION, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_FIREBALL, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_FIRE_BLAST, TARGET_VICTIM, 1); VerifyAndPushSpellCast(spells, SPELL_DRAGONS_BREATH, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_BLAST_WAVE, TARGET_VICTIM, 1); break; case TALENT_SPEC_MAGE_FROST: VerifyAndPushSpellCast(spells, SPELL_DEEP_FREEZE, TARGET_VICTIM, 10); VerifyAndPushSpellCast(spells, SPELL_FROST_NOVA, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_FROSTBOLT, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_COLD_SNAP, TARGET_VICTIM, 5); if (me.GetVictim() && me.GetVictim().HasAuraState(AURA_STATE_FROZEN, nullptr, me)) VerifyAndPushSpellCast(spells, SPELL_ICE_LANCE, TARGET_VICTIM, 5); break; } break; case CLASS_WARLOCK: VerifyAndPushSpellCast(spells, SPELL_DEATH_COIL_W, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_FEAR, TARGET_VICTIM, 2); VerifyAndPushSpellCast(spells, SPELL_SEED_OF_CORRUPTION, TARGET_VICTIM, 4); VerifyAndPushSpellCast(spells, SPELL_HOWL_OF_TERROR, TARGET_NONE, 2); if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_CORRUPTION, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_CORRUPTION, TARGET_VICTIM, 10); switch (GetSpec()) { case TALENT_SPEC_WARLOCK_AFFLICTION: if (Unit* victim = me.GetVictim()) { VerifyAndPushSpellCast(spells, SPELL_SHADOW_BOLT, TARGET_VICTIM, 7); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_UNSTABLE_AFFLICTION, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_UNSTABLE_AFFLICTION, TARGET_VICTIM, 8); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_HAUNT, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_HAUNT, TARGET_VICTIM, 8); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_CURSE_OF_AGONY, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_CURSE_OF_AGONY, TARGET_VICTIM, 4); if (victim.HealthBelowPct(25)) VerifyAndPushSpellCast(spells, SPELL_DRAIN_SOUL, TARGET_VICTIM, 100); } break; case TALENT_SPEC_WARLOCK_DEMONOLOGY: VerifyAndPushSpellCast(spells, SPELL_METAMORPHOSIS, TARGET_NONE, 15); VerifyAndPushSpellCast(spells, SPELL_SHADOW_BOLT, TARGET_VICTIM, 7); if (me.HasAura(AURA_DECIMATION)) VerifyAndPushSpellCast(spells, SPELL_SOUL_FIRE, TARGET_VICTIM, 100); if (me.HasAura(SPELL_METAMORPHOSIS)) { VerifyAndPushSpellCast(spells, SPELL_IMMOLATION_AURA, TARGET_NONE, 30); if (!me.IsWithinMeleeRange(me.GetVictim())) VerifyAndPushSpellCast(spells, SPELL_DEMON_CHARGE, TARGET_VICTIM, 20); } if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_IMMOLATE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_IMMOLATE, TARGET_VICTIM, 5); if (me.HasAura(AURA_MOLTEN_CORE)) VerifyAndPushSpellCast(spells, SPELL_INCINERATE, TARGET_VICTIM, 10); break; case TALENT_SPEC_WARLOCK_DESTRUCTION: if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_IMMOLATE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_IMMOLATE, TARGET_VICTIM, 8); if (me.GetVictim() && me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_IMMOLATE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_CONFLAGRATE, TARGET_VICTIM, 8); VerifyAndPushSpellCast(spells, SPELL_SHADOWFURY, TARGET_VICTIM, 5); VerifyAndPushSpellCast(spells, SPELL_CHAOS_BOLT, TARGET_VICTIM, 10); VerifyAndPushSpellCast(spells, SPELL_SHADOWBURN, TARGET_VICTIM, 3); VerifyAndPushSpellCast(spells, SPELL_INCINERATE, TARGET_VICTIM, 7); break; } break; case CLASS_MONK: switch (GetSpec()) { case TALENT_SPEC_MONK_BREWMASTER: case TALENT_SPEC_MONK_BATTLEDANCER: case TALENT_SPEC_MONK_MISTWEAVER: break; } break; case CLASS_DRUID: VerifyAndPushSpellCast(spells, SPELL_INNERVATE, TARGET_CHARMER, 5); VerifyAndPushSpellCast(spells, SPELL_BARKSKIN, TARGET_NONE, 5); switch (GetSpec()) { case TALENT_SPEC_DRUID_RESTORATION: if (!me.HasAura(SPELL_TREE_OF_LIFE)) { CancelAllShapeshifts(); VerifyAndPushSpellCast(spells, SPELL_TREE_OF_LIFE, TARGET_NONE, 100); break; } VerifyAndPushSpellCast(spells, SPELL_TRANQUILITY, TARGET_NONE, 10); VerifyAndPushSpellCast(spells, SPELL_NATURE_SWIFTNESS, TARGET_NONE, 7); if (Creature* creatureCharmer = GetCharmer()) { VerifyAndPushSpellCast(spells, SPELL_NOURISH, creatureCharmer, 5); VerifyAndPushSpellCast(spells, SPELL_WILD_GROWTH, creatureCharmer, 5); if (!creatureCharmer.GetAuraApplicationOfRankedSpell(SPELL_REJUVENATION, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_REJUVENATION, creatureCharmer, 8); if (!creatureCharmer.GetAuraApplicationOfRankedSpell(SPELL_REGROWTH, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_REGROWTH, creatureCharmer, 8); uint8 lifebloomStacks = 0; if (Aura const* lifebloom = creatureCharmer.GetAura(SPELL_LIFEBLOOM, me.GetGUID())) lifebloomStacks = lifebloom.GetStackAmount(); if (lifebloomStacks < 3) VerifyAndPushSpellCast(spells, SPELL_LIFEBLOOM, creatureCharmer, 5); if (creatureCharmer.GetAuraApplicationOfRankedSpell(SPELL_REJUVENATION) || creatureCharmer.GetAuraApplicationOfRankedSpell(SPELL_REGROWTH)) VerifyAndPushSpellCast(spells, SPELL_SWIFTMEND, creatureCharmer, 10); if (me.HasAura(SPELL_NATURE_SWIFTNESS)) VerifyAndPushSpellCast(spells, SPELL_HEALING_TOUCH, creatureCharmer, 100); } break; case TALENT_SPEC_DRUID_BALANCE: { if (!me.HasAura(SPELL_MOONKIN_FORM)) { CancelAllShapeshifts(); VerifyAndPushSpellCast(spells, SPELL_MOONKIN_FORM, TARGET_NONE, 100); break; } uint32 const mainAttackSpell = me.HasAura(AURA_ECLIPSE_LUNAR) ? SPELL_STARFIRE : SPELL_WRATH; VerifyAndPushSpellCast(spells, SPELL_STARFALL, TARGET_NONE, 20); VerifyAndPushSpellCast(spells, mainAttackSpell, TARGET_VICTIM, 10); if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_INSECT_SWARM, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_INSECT_SWARM, TARGET_VICTIM, 7); if (me.GetVictim() && !me.GetVictim().GetAuraApplicationOfRankedSpell(SPELL_MOONFIRE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_MOONFIRE, TARGET_VICTIM, 5); if (me.GetVictim() && me.GetVictim().HasUnitState(UNIT_STATE_CASTING)) VerifyAndPushSpellCast(spells, SPELL_TYPHOON, TARGET_NONE, 15); break; } case TALENT_SPEC_DRUID_CAT: case TALENT_SPEC_DRUID_BEAR: if (!me.HasAura(SPELL_CAT_FORM)) { CancelAllShapeshifts(); VerifyAndPushSpellCast(spells, SPELL_CAT_FORM, TARGET_NONE, 100); break; } VerifyAndPushSpellCast(spells, SPELL_BERSERK, TARGET_NONE, 20); VerifyAndPushSpellCast(spells, SPELL_SURVIVAL_INSTINCTS, TARGET_NONE, 15); VerifyAndPushSpellCast(spells, SPELL_TIGER_FURY, TARGET_NONE, 15); VerifyAndPushSpellCast(spells, SPELL_DASH, TARGET_NONE, 5); if (Unit* victim = me.GetVictim()) { uint8 const cp = me.GetPower(POWER_COMBO_POINTS); if (victim.HasUnitState(UNIT_STATE_CASTING) && cp >= 1) VerifyAndPushSpellCast(spells, SPELL_MAIM, TARGET_VICTIM, 25); if (!me.IsWithinMeleeRange(victim)) VerifyAndPushSpellCast(spells, SPELL_FERAL_CHARGE_CAT, TARGET_VICTIM, 25); if (cp >= 4) VerifyAndPushSpellCast(spells, SPELL_RIP, TARGET_VICTIM, 50); if (cp <= 4) { VerifyAndPushSpellCast(spells, SPELL_MANGLE_CAT, TARGET_VICTIM, 10); VerifyAndPushSpellCast(spells, SPELL_CLAW, TARGET_VICTIM, 5); if (!victim.GetAuraApplicationOfRankedSpell(SPELL_RAKE, me.GetGUID())) VerifyAndPushSpellCast(spells, SPELL_RAKE, TARGET_VICTIM, 8); if (!me.HasAura(SPELL_SAVAGE_ROAR)) VerifyAndPushSpellCast(spells, SPELL_SAVAGE_ROAR, TARGET_NONE, 15); } } break; } break; case CLASS_DEMON_HUNTER: switch (GetSpec()) { case TALENT_SPEC_DEMON_HUNTER_HAVOC: case TALENT_SPEC_DEMON_HUNTER_VENGEANCE: break; } break; } */ return SelectSpellCast(spells); } public override void UpdateAI(uint diff) { Creature charmer = GetCharmer(); if (!charmer) return; //kill self if charm aura has infinite duration if (charmer.IsInEvadeMode()) { var auras = me.GetAuraEffectsByType(AuraType.ModCharm); foreach (var effect in auras) { if (effect.GetCasterGUID() == charmer.GetGUID() && effect.GetBase().IsPermanent()) { me.KillSelf(); return; } } } if (charmer.IsEngaged()) { Unit target = me.GetVictim(); if (!target || !CanAIAttack(target)) { target = SelectAttackTarget(); if (!target || !CanAIAttack(target)) { if (!_isFollowing) { _isFollowing = true; me.AttackStop(); me.CastStop(); if (me.HasUnitState(UnitState.Chase)) me.GetMotionMaster().Remove(MovementGeneratorType.Chase); me.GetMotionMaster().MoveFollow(charmer, SharedConst.PetFollowDist, SharedConst.PetFollowAngle); } return; } _isFollowing = false; if (IsRangedAttacker()) { _chaseCloser = !me.IsWithinLOSInMap(target); if (_chaseCloser) AttackStart(target); else AttackStartCaster(target, CASTER_CHASE_DISTANCE); } else AttackStart(target); _forceFacing = true; } if (me.IsStopped() && !me.HasUnitState(UnitState.CannotTurn)) { float targetAngle = me.GetAbsoluteAngle(target); if (_forceFacing || Math.Abs(me.GetOrientation() - targetAngle) > 0.4f) { me.SetFacingTo(targetAngle); _forceFacing = false; } } if (_castCheckTimer <= diff) { if (me.HasUnitState(UnitState.Casting)) _castCheckTimer = 0; else { if (IsRangedAttacker()) // chase to zero if the target isn't in line of sight { bool inLOS = me.IsWithinLOSInMap(target); if (_chaseCloser != !inLOS) { _chaseCloser = !inLOS; if (_chaseCloser) AttackStart(target); else AttackStartCaster(target, CASTER_CHASE_DISTANCE); } } Tuple shouldCast = SelectAppropriateCastForSpec(); if (shouldCast != null) DoCastAtTarget(shouldCast); _castCheckTimer = 500; } } else _castCheckTimer -= diff; DoAutoAttackIfReady(); } else if (!_isFollowing) { _isFollowing = true; me.AttackStop(); me.CastStop(); if (me.HasUnitState(UnitState.Chase)) me.GetMotionMaster().Remove(MovementGeneratorType.Chase); me.GetMotionMaster().MoveFollow(charmer, SharedConst.PetFollowDist, SharedConst.PetFollowAngle); } } public override void OnCharmed(bool isNew) { if (me.IsCharmed()) { me.CastStop(); me.AttackStop(); if (me.GetMotionMaster().Size() <= 1) // if there is no current movement (we dont want to erase/overwrite any existing stuff) me.GetMotionMaster().MovePoint(0, me.GetPosition(), false); // force re-sync of current position for all clients } else { me.CastStop(); me.AttackStop(); me.GetMotionMaster().Clear(MovementGeneratorPriority.Normal); } base.OnCharmed(isNew); } } struct ValidTargetSelectPredicate : ICheck { UnitAI _ai; public ValidTargetSelectPredicate(UnitAI ai) { _ai = ai; } public bool Invoke(Unit target) { return _ai.CanAIAttack(target); } } }