/* * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Affero 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 Affero 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 . */ #include "Cell.h" #include "CellImpl.h" #include "CreatureScript.h" #include "GridNotifiers.h" #include "Pet.h" #include "SpellAuraEffects.h" #include "SpellAuras.h" #include "SpellMgr.h" #include "SpellScript.h" #include "SpellScriptLoader.h" /* * Scripts for spells with SPELLFAMILY_HUNTER, SPELLFAMILY_PET and SPELLFAMILY_GENERIC spells used by hunter players. * Ordered alphabetically using scriptname. * Scriptnames of files in this file should be prefixed with "spell_hun_". */ /// @todo: this import is not necessary for compilation and marked as unused by the IDE // however, for some reasons removing it would cause a damn linking issue // there is probably some underlying problem with imports which should properly addressed // see: https://github.com/azerothcore/azerothcore-wotlk/issues/9766 #include "GridNotifiersImpl.h" enum HunterSpells { SPELL_HUNTER_WYVERN_STING_DOT = 24131, SPELL_HUNTER_ASPECT_OF_THE_BEAST = 13161, SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET = 61669, SPELL_HUNTER_ASPECT_OF_THE_VIPER = 34074, SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE = 34075, SPELL_HUNTER_BESTIAL_WRATH = 19574, SPELL_HUNTER_CHIMERA_SHOT_SERPENT = 53353, SPELL_HUNTER_CHIMERA_SHOT_VIPER = 53358, SPELL_HUNTER_CHIMERA_SHOT_SCORPID = 53359, SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER = 56851, SPELL_HUNTER_IMPROVED_MEND_PET = 24406, SPELL_HUNTER_INVIGORATION_TRIGGERED = 53398, SPELL_HUNTER_MASTERS_CALL_TRIGGERED = 62305, SPELL_HUNTER_MISDIRECTION_PROC = 35079, SPELL_HUNTER_PET_LAST_STAND_TRIGGERED = 53479, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX = 55709, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711, SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED = 54045, SPELL_HUNTER_READINESS = 23989, SPELL_HUNTER_SNIPER_TRAINING_R1 = 53302, SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 = 64418, SPELL_HUNTER_VICIOUS_VIPER = 61609, SPELL_HUNTER_VIPER_ATTACK_SPEED = 60144, SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543, SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389, SPELL_LOCK_AND_LOAD_TRIGGER = 56453, SPELL_LOCK_AND_LOAD_MARKER = 67544, SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY = 38297, // Leggings of Beast Mastery }; class spell_hun_check_pet_los : public SpellScript { PrepareSpellScript(spell_hun_check_pet_los); SpellCastResult CheckCast() { Unit* pet = GetCaster()->GetGuardianPet(); if (!pet) pet = GetCaster()->GetCharm(); if (!pet) return SPELL_FAILED_NO_PET; if (!pet->IsAlive()) { SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_PET_IS_DEAD); return SPELL_FAILED_CUSTOM_ERROR; } if (!GetCaster()->IsWithinLOSInMap(pet)) return SPELL_FAILED_LINE_OF_SIGHT; return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_check_pet_los::CheckCast); } }; class spell_hun_cower : public AuraScript { PrepareAuraScript(spell_hun_cower); void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { if (AuraEffect* aurEff = GetUnitOwner()->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_PET, GetSpellInfo()->SpellIconID, EFFECT_0)) AddPct(amount, aurEff->GetAmount()); } void Register() override { DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_cower::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DECREASE_SPEED); } }; class spell_hun_wyvern_sting : public AuraScript { PrepareAuraScript(spell_hun_wyvern_sting) void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) caster->CastSpell(GetTarget(), sSpellMgr->GetSpellWithRank(SPELL_HUNTER_WYVERN_STING_DOT, GetSpellInfo()->GetRank()), true); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_hun_wyvern_sting::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); } }; class spell_hun_animal_handler : public AuraScript { PrepareAuraScript(spell_hun_animal_handler); void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { amount = 0; if (Unit* owner = GetUnitOwner()->GetOwner()) if (AuraEffect const* animalHandlerEff = owner->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 2234, EFFECT_1)) amount = animalHandlerEff->GetAmount(); } void Register() override { DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_animal_handler::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_ATTACK_POWER_PCT); } }; class spell_hun_generic_scaling : public AuraScript { PrepareAuraScript(spell_hun_generic_scaling); void CalculateResistanceAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { // xinef: pet inherits 40% of resistance from owner and 35% of armor if (Unit* owner = GetUnitOwner()->GetOwner()) { SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue); int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40; amount = CalculatePct(std::max(0, owner->GetResistance(schoolMask)), modifier); if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY) && schoolMask == SPELL_SCHOOL_MASK_NORMAL) { amount += 490; } } } void CalculateStatAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { if (Unit* owner = GetUnitOwner()->GetOwner()) { // xinef: by default pet inherits 45% of stamina int32 modifier = 45; // xinef: Wild Hunt bonus for stamina if (AuraEffect* wildHuntEff = GetUnitOwner()->GetDummyAuraEffect(SPELLFAMILY_PET, 3748, EFFECT_0)) AddPct(modifier, wildHuntEff->GetAmount()); amount = CalculatePct(std::max(0, owner->GetStat(Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue))), modifier); if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY)) { amount += 52; } } } void CalculateAPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { if (Unit* owner = GetUnitOwner()->GetOwner()) { // xinef: by default 22% of RAP int32 modifier = 22; // xinef: Wild Hunt bonus for AP if (AuraEffect* wildHuntEff = GetUnitOwner()->GetDummyAuraEffect(SPELLFAMILY_PET, 3748, EFFECT_1)) AddPct(modifier, wildHuntEff->GetAmount()); float ownerAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK); // Xinef: Hunter vs. Wild if (AuraEffect* HvWEff = owner->GetAuraEffect(SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT, SPELLFAMILY_HUNTER, 3647, EFFECT_0)) ownerAP += CalculatePct(owner->GetStat(STAT_STAMINA), HvWEff->GetAmount()); amount = CalculatePct(std::max(0, ownerAP), modifier); if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY)) { amount += 70; } } } void CalculateSPAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { if (Unit* owner = GetUnitOwner()->GetOwner()) { // xinef: by default 12.87% of RAP float modifier = 12.87f; // xinef: Wild Hunt bonus for AP if (AuraEffect* wildHuntEff = GetUnitOwner()->GetDummyAuraEffect(SPELLFAMILY_PET, 3748, EFFECT_1)) AddPct(modifier, wildHuntEff->GetAmount()); amount = CalculatePct(std::max(0, owner->GetTotalAttackPowerValue(RANGED_ATTACK)), modifier); // xinef: Update appropriate player field if (owner->IsPlayer()) owner->SetUInt32Value(PLAYER_PET_SPELL_POWER, (uint32)amount); } } void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude) { isPeriodic = true; amplitude = 2 * IN_MILLISECONDS; } void HandlePeriodic(AuraEffect const* aurEff) { PreventDefaultAction(); if (aurEff->GetAuraType() == SPELL_AURA_MOD_STAT && (aurEff->GetMiscValue() == STAT_STAMINA || aurEff->GetMiscValue() == STAT_INTELLECT)) { int32 currentAmount = aurEff->GetAmount(); int32 newAmount = GetEffect(aurEff->GetEffIndex())->CalculateAmount(GetCaster()); if (newAmount != currentAmount) { if (aurEff->GetMiscValue() == STAT_STAMINA) { uint32 actStat = GetUnitOwner()->GetHealth(); GetEffect(aurEff->GetEffIndex())->ChangeAmount(newAmount, false); GetUnitOwner()->SetHealth(std::min(GetUnitOwner()->GetMaxHealth(), actStat)); } else { uint32 actStat = GetUnitOwner()->GetPower(POWER_MANA); GetEffect(aurEff->GetEffIndex())->ChangeAmount(newAmount, false); GetUnitOwner()->SetPower(POWER_MANA, std::min(GetUnitOwner()->GetMaxPower(POWER_MANA), actStat)); } } } else GetEffect(aurEff->GetEffIndex())->RecalculateAmount(); } void Register() override { if (m_scriptSpellId != 34902) DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_generic_scaling::CalculateResistanceAmount, EFFECT_ALL, SPELL_AURA_MOD_RESISTANCE); else { DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_generic_scaling::CalculateStatAmount, EFFECT_ALL, SPELL_AURA_MOD_STAT); DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_generic_scaling::CalculateAPAmount, EFFECT_ALL, SPELL_AURA_MOD_ATTACK_POWER); DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_hun_generic_scaling::CalculateSPAmount, EFFECT_ALL, SPELL_AURA_MOD_DAMAGE_DONE); } DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_hun_generic_scaling::CalcPeriodic, EFFECT_ALL, SPELL_AURA_ANY); OnEffectPeriodic += AuraEffectPeriodicFn(spell_hun_generic_scaling::HandlePeriodic, EFFECT_ALL, SPELL_AURA_ANY); } }; // Taming the Beast quests (despawn creature after dismiss) class spell_hun_taming_the_beast : public AuraScript { PrepareAuraScript(spell_hun_taming_the_beast); void HandleOnEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* target = GetTarget()) { if (Creature* creature = target->ToCreature()) { creature->GetThreatMgr().ClearAllThreat(); } } } void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* target = GetTarget()) if (Creature* creature = target->ToCreature()) creature->DespawnOrUnsummon(1); } void Register() override { OnEffectApply += AuraEffectApplyFn(spell_hun_taming_the_beast::HandleOnEffectApply, EFFECT_0, SPELL_AURA_MOD_CHARM, AURA_EFFECT_HANDLE_REAL); OnEffectRemove += AuraEffectRemoveFn(spell_hun_taming_the_beast::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_MOD_CHARM, AURA_EFFECT_HANDLE_REAL); } }; // 13161 Aspect of the Beast class spell_hun_aspect_of_the_beast : public AuraScript { PrepareAuraScript(spell_hun_aspect_of_the_beast); bool Load() override { return GetCaster() && GetCaster()->IsPlayer(); } bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetCaster()) if (Player* caster = GetCaster()->ToPlayer()) if (Pet* pet = caster->GetPet()) pet->RemoveAurasDueToSpell(SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET); } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetCaster()) if (Player* caster = GetCaster()->ToPlayer()) if (caster->GetPet()) caster->CastSpell(caster, SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET, true); } void OnPetApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* pet = GetUnitOwner(); if (Unit* owner = pet->GetOwner()) if (owner->HasAura(SPELL_HUNTER_ASPECT_OF_THE_BEAST)) return; SetDuration(0); } void Register() override { if (m_scriptSpellId == 13161) { AfterEffectApply += AuraEffectApplyFn(spell_hun_aspect_of_the_beast::OnApply, EFFECT_0, SPELL_AURA_UNTRACKABLE, AURA_EFFECT_HANDLE_REAL); AfterEffectRemove += AuraEffectRemoveFn(spell_hun_aspect_of_the_beast::OnRemove, EFFECT_0, SPELL_AURA_UNTRACKABLE, AURA_EFFECT_HANDLE_REAL); } else AfterEffectApply += AuraEffectApplyFn(spell_hun_aspect_of_the_beast::OnPetApply, EFFECT_0, SPELL_AURA_UNTRACKABLE, AURA_EFFECT_HANDLE_REAL); } }; // 34074 - Aspect of the Viper class spell_hun_ascpect_of_the_viper : public AuraScript { PrepareAuraScript(spell_hun_ascpect_of_the_viper); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE, SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER, SPELL_HUNTER_VIPER_ATTACK_SPEED, SPELL_HUNTER_VICIOUS_VIPER }); } bool CheckProc(ProcEventInfo& procInfo) { SpellInfo const* spellInfo = procInfo.GetSpellInfo(); // Xinef: cannot proc from volley damage if (spellInfo && (spellInfo->SpellFamilyFlags[0] & 0x2000) && spellInfo->Effects[EFFECT_0].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) return false; return true; } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); uint32 maxMana = GetTarget()->GetMaxPower(POWER_MANA); int32 mana = CalculatePct(maxMana, GetTarget()->GetAttackTime(RANGED_ATTACK) / 1000.0f); if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER, EFFECT_0)) AddPct(mana, glyph->GetAmount()); GetTarget()->CastCustomSpell(SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, nullptr, aurEff); } void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { // Hunter T7 4P Bonus if (GetTarget()->HasAura(SPELL_HUNTER_VIPER_ATTACK_SPEED)) GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, nullptr, aurEff); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { // Hunter T7 4P Bonus if (GetTarget()->HasAura(SPELL_HUNTER_VIPER_ATTACK_SPEED)) GetTarget()->RemoveAurasDueToSpell(SPELL_HUNTER_VICIOUS_VIPER); } void Register() override { DoCheckProc += AuraCheckProcFn(spell_hun_ascpect_of_the_viper::CheckProc); OnEffectProc += AuraEffectProcFn(spell_hun_ascpect_of_the_viper::HandleProc, EFFECT_2, SPELL_AURA_DUMMY); AfterEffectApply += AuraEffectApplyFn(spell_hun_ascpect_of_the_viper::OnApply, EFFECT_0, SPELL_AURA_OBS_MOD_POWER, AURA_EFFECT_HANDLE_REAL); AfterEffectRemove += AuraEffectRemoveFn(spell_hun_ascpect_of_the_viper::OnRemove, EFFECT_0, SPELL_AURA_OBS_MOD_POWER, AURA_EFFECT_HANDLE_REAL); } }; // 53209 Chimera Shot class spell_hun_chimera_shot : public SpellScript { PrepareSpellScript(spell_hun_chimera_shot); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_CHIMERA_SHOT_SERPENT, SPELL_HUNTER_CHIMERA_SHOT_VIPER, SPELL_HUNTER_CHIMERA_SHOT_SCORPID }); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Unit* unitTarget = GetHitUnit()) { uint32 spellId = 0; int32 basePoint = 0; Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) { Aura* aura = i->second->GetBase(); if (aura->GetCasterGUID() != caster->GetGUID()) continue; // Search only Serpent Sting, Viper Sting, Scorpid Sting auras flag96 familyFlag = aura->GetSpellInfo()->SpellFamilyFlags; if (!(familyFlag[1] & 0x00000080 || familyFlag[0] & 0x0000C000)) continue; if (AuraEffect* aurEff = aura->GetEffect(0)) { // Serpent Sting - Instantly deals 40% of the damage done by your Serpent Sting. if (familyFlag[0] & 0x4000) { int32 TickCount = aurEff->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; basePoint = aurEff->GetAmount(); ApplyPct(basePoint, TickCount * 40); basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); } // Viper Sting - Instantly restores mana to you equal to 60% of the total amount drained by your Viper Sting. else if (familyFlag[1] & 0x00000080) { int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER; // Amount of one aura tick basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount())); int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; /// @todo: Caster uses unitTarget? if (basePoint > casterBasePoint) basePoint = casterBasePoint; ApplyPct(basePoint, TickCount * 60); } // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. else if (familyFlag[0] & 0x00008000) { if (caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown { if (caster->ToPlayer()->HasSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID)) break; caster->ToPlayer()->AddSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID, 0, 60000); } spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID; } // Refresh aura duration aura->RefreshDuration(); aurEff->ChangeAmount(aurEff->CalculateAmount(caster), false); } break; } if (spellId) caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); } } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_hun_chimera_shot::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; // -19572 - Improved Mend Pet class spell_hun_improved_mend_pet : public AuraScript { PrepareAuraScript(spell_hun_improved_mend_pet); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_IMPROVED_MEND_PET }); } bool CheckProc(ProcEventInfo& /*eventInfo*/) { return roll_chance_i(GetEffect(EFFECT_0)->GetAmount()); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_IMPROVED_MEND_PET, true, nullptr, aurEff); } void Register() override { DoCheckProc += AuraCheckProcFn(spell_hun_improved_mend_pet::CheckProc); OnEffectProc += AuraEffectProcFn(spell_hun_improved_mend_pet::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; // 53412 - Invigoration class spell_hun_invigoration : public SpellScript { PrepareSpellScript(spell_hun_invigoration); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_INVIGORATION_TRIGGERED }); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { if (Unit* unitTarget = GetHitUnit()) if (AuraEffect* aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 3487, 0)) if (roll_chance_i(aurEff->GetAmount())) unitTarget->CastSpell(unitTarget, SPELL_HUNTER_INVIGORATION_TRIGGERED, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_hun_invigoration::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; // 53478 - Last Stand Pet class spell_hun_last_stand_pet : public SpellScript { PrepareSpellScript(spell_hun_last_stand_pet); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_PET_LAST_STAND_TRIGGERED }); } void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); int32 healthModSpellBasePoints0 = int32(caster->CountPctFromMaxHealth(30)); caster->CastCustomSpell(caster, SPELL_HUNTER_PET_LAST_STAND_TRIGGERED, &healthModSpellBasePoints0, nullptr, nullptr, true, nullptr); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_hun_last_stand_pet::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; // 53271 - Masters Call class spell_hun_masters_call : public SpellScript { PrepareSpellScript(spell_hun_masters_call); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_MASTERS_CALL_TRIGGERED }); } SpellCastResult DoCheckCast() { Pet* pet = GetCaster()->ToPlayer()->GetPet(); if (!pet || !pet->IsAlive()) return SPELL_FAILED_NO_PET; // Do a mini Spell::CheckCasterAuras on the pet, no other way of doing this SpellCastResult result = SPELL_CAST_OK; uint32 const unitflag = pet->GetUnitFlags(); if (pet->GetCharmerGUID()) result = SPELL_FAILED_CHARMED; else if (unitflag & UNIT_FLAG_STUNNED) result = SPELL_FAILED_STUNNED; else if (unitflag & UNIT_FLAG_FLEEING) result = SPELL_FAILED_FLEEING; else if (unitflag & UNIT_FLAG_CONFUSED) result = SPELL_FAILED_CONFUSED; if (result != SPELL_CAST_OK) return result; Unit* target = GetExplTargetUnit(); if (!target) return SPELL_FAILED_BAD_TARGETS; if (!pet->IsWithinLOSInMap(target)) return SPELL_FAILED_LINE_OF_SIGHT; return SPELL_CAST_OK; } void HandleDummy(SpellEffIndex /*effIndex*/) { GetCaster()->ToPlayer()->GetPet()->CastSpell(GetHitUnit(), GetEffectValue(), true); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { GetHitUnit()->CastSpell((Unit*)nullptr, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, true); } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_masters_call::DoCheckCast); OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); OnEffectHitTarget += SpellEffectFn(spell_hun_masters_call::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; // 23989 - Readiness class spell_hun_readiness : public SpellScript { PrepareSpellScript(spell_hun_readiness); bool Load() override { return GetCaster()->IsPlayer(); } void HandleDummy(SpellEffIndex /*effIndex*/) { Player* caster = GetCaster()->ToPlayer(); // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath // force removal of the disarm cooldown caster->RemoveSpellCooldown(SPELL_HUNTER_CHIMERA_SHOT_SCORPID); SpellCooldowns& cooldowns = caster->GetSpellCooldownMap(); std::set> spellsToRemove; std::set categoriesToRemove; for (auto const& [spellId, cooldown] : cooldowns) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != SPELL_HUNTER_READINESS && spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH && spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU) { if (spellInfo->RecoveryTime > 0) spellsToRemove.insert(std::make_pair(spellInfo->Id, cooldown.needSendToClient)); if (spellInfo->CategoryRecoveryTime > 0) categoriesToRemove.insert(spellInfo->GetCategory()); } } // we can't remove spell cooldowns while iterating. for (auto const& [spellId, sendToClient] : spellsToRemove) caster->RemoveSpellCooldown(spellId, sendToClient); for (auto const& category : categoriesToRemove) caster->RemoveCategoryCooldown(category); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_hun_readiness::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; // 37506 - Scatter Shot class spell_hun_scatter_shot : public SpellScript { PrepareSpellScript(spell_hun_scatter_shot); bool Load() override { return GetCaster()->IsPlayer(); } void HandleDummy(SpellEffIndex /*effIndex*/) { Player* caster = GetCaster()->ToPlayer(); // break Auto Shot and autohit caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); caster->AttackStop(); caster->SendAttackSwingCancelAttack(); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_hun_scatter_shot::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; // -53302 - Sniper Training class spell_hun_sniper_training : public AuraScript { PrepareAuraScript(spell_hun_sniper_training); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_SNIPER_TRAINING_R1, SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 }); } void HandlePeriodic(AuraEffect const* aurEff) { PreventDefaultAction(); if (aurEff->GetAmount() <= 0) { if (!GetCaster() || !GetTarget()) { return; } Unit* target = GetTarget(); uint32 spellId = SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 + GetId() - SPELL_HUNTER_SNIPER_TRAINING_R1; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(spellId)) { Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(GetSpellInfo()) ? GetCaster() : target; triggerCaster->CastSpell(target, triggeredSpellInfo, true, 0, aurEff); } } } void HandleUpdatePeriodic(AuraEffect* aurEff) { if (Player* playerTarget = GetUnitOwner()->ToPlayer()) { int32 baseAmount = aurEff->GetBaseAmount(); int32 amount = playerTarget->isMoving() || aurEff->GetAmount() <= 0 ? playerTarget->CalculateSpellDamage(playerTarget, GetSpellInfo(), aurEff->GetEffIndex(), &baseAmount) : aurEff->GetAmount() - 1; aurEff->SetAmount(amount); } } void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_hun_sniper_training::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_hun_sniper_training::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; // 55709 - Pet Heart of the Phoenix class spell_hun_pet_heart_of_the_phoenix : public SpellScript { PrepareSpellScript(spell_hun_pet_heart_of_the_phoenix); bool Load() override { if (!GetCaster()->IsPet()) return false; return true; } bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF }); } SpellCastResult CheckCast() { Unit* caster = GetCaster(); if (caster->IsAlive()) return SPELL_FAILED_TARGET_NOT_DEAD; if (caster->HasAura(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) return SPELL_FAILED_CASTER_AURASTATE; return SPELL_CAST_OK; } void HandleScript(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (Unit* owner = caster->GetOwner()) if (!caster->HasAura(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) { owner->CastCustomSpell(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED, SPELLVALUE_BASE_POINT0, 100, caster, true); caster->CastSpell(caster, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF, true); } } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_pet_heart_of_the_phoenix::CheckCast); OnEffectHitTarget += SpellEffectFn(spell_hun_pet_heart_of_the_phoenix::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; // 54044 - Pet Carrion Feeder class spell_hun_pet_carrion_feeder : public SpellScript { PrepareSpellScript(spell_hun_pet_carrion_feeder); bool Load() override { if (!GetCaster()->IsPet()) return false; return true; } bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED }); } SpellCastResult CheckIfCorpseNear() { Unit* caster = GetCaster(); float max_range = GetSpellInfo()->GetMaxRange(false); WorldObject* result = nullptr; // search for nearby enemy corpse in range Acore::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); Acore::WorldObjectSearcher searcher(caster, result, check); Cell::VisitObjects(caster, searcher, max_range); if (!result) { return SPELL_FAILED_NO_EDIBLE_CORPSES; } return SPELL_CAST_OK; } void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); caster->CastSpell(caster, SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED, false); } void Register() override { OnEffectHit += SpellEffectFn(spell_hun_pet_carrion_feeder::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); OnCheckCast += SpellCheckCastFn(spell_hun_pet_carrion_feeder::CheckIfCorpseNear); } }; // 34477 - Misdirection class spell_hun_misdirection : public AuraScript { PrepareAuraScript(spell_hun_misdirection); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_MISDIRECTION_PROC }); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_HUNTER_MISDIRECTION_PROC)) GetTarget()->ResetRedirectThreat(); } bool CheckProc(ProcEventInfo& eventInfo) { // Do not trigger from Mend Pet if ((eventInfo.GetProcSpell() && (eventInfo.GetProcSpell()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000)) || (eventInfo.GetHealInfo() && (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000))) return false; return GetTarget()->GetRedirectThreatTarget(); } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) { PreventDefaultAction(); GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_MISDIRECTION_PROC, true, nullptr, aurEff); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); DoCheckProc += AuraCheckProcFn(spell_hun_misdirection::CheckProc); OnEffectProc += AuraEffectProcFn(spell_hun_misdirection::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); } }; // 35079 - Misdirection (Proc) class spell_hun_misdirection_proc : public AuraScript { PrepareAuraScript(spell_hun_misdirection_proc); void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { GetTarget()->ResetRedirectThreat(); } void Register() override { AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_proc::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 781 - Disengage class spell_hun_disengage : public SpellScript { PrepareSpellScript(spell_hun_disengage); SpellCastResult CheckCast() { Unit* caster = GetCaster(); if (caster->IsPlayer() && !caster->IsInCombat()) return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_disengage::CheckCast); } }; // 1515 - Tame Beast class spell_hun_tame_beast : public SpellScript { PrepareSpellScript(spell_hun_tame_beast); SpellCastResult CheckCast() { Unit* caster = GetCaster(); if (!caster->IsPlayer()) return SPELL_FAILED_DONT_REPORT; Player* player = GetCaster()->ToPlayer(); if (!GetExplTargetUnit()) { player->SendTameFailure(PET_TAME_INVALID_CREATURE); return SPELL_FAILED_DONT_REPORT; } if (Creature* target = GetExplTargetUnit()->ToCreature()) { if (target->GetLevel() > player->GetLevel()) { player->SendTameFailure(PET_TAME_TOO_HIGHLEVEL); return SPELL_FAILED_DONT_REPORT; } if (target->GetCreatureTemplate()->IsExotic() && !player->CanTameExoticPets()) { player->SendTameFailure(PET_TAME_CANT_CONTROL_EXOTIC); return SPELL_FAILED_DONT_REPORT; } if (!target->GetCreatureTemplate()->IsTameable(player->CanTameExoticPets())) { player->SendTameFailure(PET_TAME_NOT_TAMEABLE); return SPELL_FAILED_DONT_REPORT; } PetStable const* petStable = player->GetPetStable(); if (petStable) { if (petStable->CurrentPet) return SPELL_FAILED_ALREADY_HAVE_SUMMON; if (petStable->GetUnslottedHunterPet()) { caster->SendTameFailure(PET_TAME_TOO_MANY); return SPELL_FAILED_DONT_REPORT; } } if (player->GetCharmGUID()) { player->SendTameFailure(PET_TAME_ANOTHER_SUMMON_ACTIVE); return SPELL_FAILED_DONT_REPORT; } if (target->GetOwnerGUID()) { player->SendTameFailure(PET_TAME_CREATURE_ALREADY_OWNED); return SPELL_FAILED_DONT_REPORT; } } else { player->SendTameFailure(PET_TAME_INVALID_CREATURE); return SPELL_FAILED_DONT_REPORT; } return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_tame_beast::CheckCast); } }; // 60144 - Viper Attack Speed class spell_hun_viper_attack_speed : public AuraScript { PrepareAuraScript(spell_hun_viper_attack_speed); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_ASPECT_OF_THE_VIPER, SPELL_HUNTER_VICIOUS_VIPER }); } void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { if (GetTarget()->HasAura(SPELL_HUNTER_ASPECT_OF_THE_VIPER)) GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_VICIOUS_VIPER, true, nullptr, aurEff); } void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { // possible exploit GetTarget()->RemoveAurasDueToSpell(SPELL_HUNTER_VICIOUS_VIPER); } void Register() override { AfterEffectApply += AuraEffectApplyFn(spell_hun_viper_attack_speed::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); AfterEffectRemove += AuraEffectRemoveFn(spell_hun_viper_attack_speed::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 56841 - Glyph of Arcane Shot class spell_hun_glyph_of_arcane_shot : public AuraScript { PrepareAuraScript(spell_hun_glyph_of_arcane_shot); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT }); } bool CheckProc(ProcEventInfo& eventInfo) { if (Unit* procTarget = eventInfo.GetProcTarget()) { // Find Serpent Sting, Viper Sting, Scorpid Sting, Wyvern Sting const auto found = std::find_if(std::begin(procTarget->GetAppliedAuras()), std::end(procTarget->GetAppliedAuras()), [&](std::pair pair) { Aura const* aura = pair.second->GetBase(); return ((aura->GetCasterGUID() == GetTarget()->GetGUID()) && aura->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_HUNTER && aura->GetSpellInfo()->SpellFamilyFlags.HasFlag(0xC000, 0x1080)); }); if (found != std::end(procTarget->GetAppliedAuras())) { return true; } } return false; } void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* procSpell = eventInfo.GetSpellInfo(); if (!procSpell) { return; } int32 mana = procSpell->CalcPowerCost(GetTarget(), procSpell->GetSchoolMask()); ApplyPct(mana, aurEff->GetAmount()); GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget()); } void Register() override { DoCheckProc += AuraCheckProcFn(spell_hun_glyph_of_arcane_shot::CheckProc); OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_arcane_shot::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; // -42243 - Volley (Trigger one) class spell_hun_volley_trigger : public SpellScript { PrepareSpellScript(spell_hun_volley_trigger); void SelectTarget(std::list& targets) { // It's here because Volley is an AOE spell so there is no specific target to be attacked // Let's select one of our targets if (!targets.empty()) { _target = *(targets.begin()); } } void HandleFinish() { if (!_target) { return; } Unit* caster = GetCaster(); if (!caster || !caster->IsPlayer()) { return; } for (Unit::ControlSet::iterator itr = caster->m_Controlled.begin(); itr != caster->m_Controlled.end(); ++itr) { if (Unit* pet = *itr) { if (pet->IsAlive() && pet->IsCreature()) { pet->ToCreature()->AI()->OwnerAttacked(_target->ToUnit()); } } } } void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_volley_trigger::SelectTarget, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); AfterCast += SpellCastFn(spell_hun_volley_trigger::HandleFinish); } private: WorldObject* _target = nullptr; }; enum LocknLoadSpells { SPELL_FROST_TRAP_SLOW = 67035 }; // -56342 - Lock and Load class spell_hun_lock_and_load : public AuraScript { PrepareAuraScript(spell_hun_lock_and_load); bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_LOCK_AND_LOAD_TRIGGER, SPELL_LOCK_AND_LOAD_MARKER, SPELL_FROST_TRAP_SLOW }); } bool CheckTrapProc(ProcEventInfo& eventInfo) { SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); if (!spellInfo || !eventInfo.GetActor()) { return false; } // Black Arrow and Fire traps may trigger on periodic tick only. if (((spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FIRE) || (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_SHADOW)) && (spellInfo->Effects[0].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || spellInfo->Effects[1].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE)) { return true; } return IsTargetValid(spellInfo, eventInfo.GetProcTarget()) && !eventInfo.GetActor()->HasAura(SPELL_LOCK_AND_LOAD_MARKER); } bool IsTargetValid(SpellInfo const* spellInfo, Unit* target) { if (!spellInfo || !target) { return false; } // Don't check it for fire traps and black arrow, they proc on periodic only and not spell hit. // So it's wrong to check for immunity, it was already checked when the spell was applied. if ((spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FIRE) || (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_SHADOW)) { return false; } // HitMask for Frost Trap can't be checked correctly as it is. // That's because the talent is triggered by the spell that fires the trap (63487)... // ...and not the actual spell that applies the slow effect (67035). // So the IMMUNE result is never sent by the spell that triggers this. if (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_NATURE) { if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(SPELL_FROST_TRAP_SLOW)) { return !target->IsImmunedToSpell(triggerSpell); } } return true; } template void HandleProcs(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); if (!(eventInfo.GetTypeMask() & mask) || !spellInfo) { return; } // Also check if the proc from the fire traps and black arrow actually comes from the periodic ticks here. // Normally this wouldn't be required, but we are circumventing the current proc system limitations. if (((spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_FIRE) || (spellInfo->GetSchoolMask() & SPELL_SCHOOL_MASK_SHADOW)) && (spellInfo->Effects[0].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || spellInfo->Effects[1].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) && !(mask & PROC_FLAG_DONE_PERIODIC)) { return; } if (!roll_chance_i(aurEff->GetAmount())) { return; } Unit* caster = eventInfo.GetActor(); caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_TRIGGER, true); } void ApplyMarker(ProcEventInfo& eventInfo) { if (IsTargetValid(eventInfo.GetSpellInfo(), eventInfo.GetProcTarget())) { Unit* caster = eventInfo.GetActor(); caster->CastSpell(caster, SPELL_LOCK_AND_LOAD_MARKER, true); } } void Register() override { DoCheckProc += AuraCheckProcFn(spell_hun_lock_and_load::CheckTrapProc); OnEffectProc += AuraEffectProcFn(spell_hun_lock_and_load::HandleProcs, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); OnEffectProc += AuraEffectProcFn(spell_hun_lock_and_load::HandleProcs, EFFECT_1, SPELL_AURA_DUMMY); AfterProc += AuraProcFn(spell_hun_lock_and_load::ApplyMarker); } }; // 19577 - Intimidation class spell_hun_intimidation : public AuraScript { PrepareAuraScript(spell_hun_intimidation); bool CheckProc(ProcEventInfo& eventInfo) { if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo()) { return !spellInfo->IsPositive(); } return true; } void Register() override { DoCheckProc += AuraCheckProcFn(spell_hun_intimidation::CheckProc); } }; // 19574 - Bestial Wrath class spell_hun_bestial_wrath : public SpellScript { PrepareSpellScript(spell_hun_bestial_wrath); SpellCastResult CheckCast() { Unit* caster = GetCaster(); if (!caster || !caster->IsPlayer()) { return SPELL_FAILED_NO_VALID_TARGETS; } Pet* pet = caster->ToPlayer()->GetPet(); if (!pet) { return SPELL_FAILED_NO_PET; } if (!pet->IsAlive()) { SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_PET_IS_DEAD); return SPELL_FAILED_CUSTOM_ERROR; } return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_hun_bestial_wrath::CheckCast); } }; // -24604 - Furious Howl // 53434 - Call of the Wild class spell_hun_target_self_and_pet : public SpellScript { PrepareSpellScript(spell_hun_target_self_and_pet); bool Load() override { return GetCaster()->IsPet(); } void FilterTargets(std::list& targets) { targets.remove_if([&](WorldObject const* target) -> bool { return target != GetCaster() && target != GetCaster()->ToPet()->GetOwner(); }); } void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_target_self_and_pet::FilterTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_PARTY); } }; // -53301 - Explosive Shot class spell_hun_explosive_shot : public SpellScript { PrepareSpellScript(spell_hun_explosive_shot); void HandleFinish() { // Handling of explosive shot initial cast without LnL proc if (!GetCaster() || !GetCaster()->IsPlayer()) return; if (!GetCaster()->HasAura(SPELL_LOCK_AND_LOAD_TRIGGER)) GetSpell()->TakeAmmo(); } void Register() override { AfterCast += SpellCastFn(spell_hun_explosive_shot::HandleFinish); } }; void AddSC_hunter_spell_scripts() { RegisterSpellScript(spell_hun_check_pet_los); RegisterSpellScript(spell_hun_cower); RegisterSpellScript(spell_hun_wyvern_sting); RegisterSpellScript(spell_hun_animal_handler); RegisterSpellScript(spell_hun_generic_scaling); RegisterSpellScript(spell_hun_taming_the_beast); RegisterSpellScript(spell_hun_glyph_of_arcane_shot); RegisterSpellScript(spell_hun_aspect_of_the_beast); RegisterSpellScript(spell_hun_ascpect_of_the_viper); RegisterSpellScript(spell_hun_chimera_shot); RegisterSpellScript(spell_hun_disengage); RegisterSpellScript(spell_hun_improved_mend_pet); RegisterSpellScript(spell_hun_invigoration); RegisterSpellScript(spell_hun_last_stand_pet); RegisterSpellScript(spell_hun_masters_call); RegisterSpellScript(spell_hun_misdirection); RegisterSpellScript(spell_hun_misdirection_proc); RegisterSpellScript(spell_hun_pet_carrion_feeder); RegisterSpellScript(spell_hun_pet_heart_of_the_phoenix); RegisterSpellScript(spell_hun_readiness); RegisterSpellScript(spell_hun_scatter_shot); RegisterSpellScript(spell_hun_sniper_training); RegisterSpellScript(spell_hun_tame_beast); RegisterSpellScript(spell_hun_viper_attack_speed); RegisterSpellScript(spell_hun_volley_trigger); RegisterSpellScript(spell_hun_lock_and_load); RegisterSpellScript(spell_hun_intimidation); RegisterSpellScript(spell_hun_bestial_wrath); RegisterSpellScript(spell_hun_target_self_and_pet); RegisterSpellScript(spell_hun_explosive_shot); }