/* * This file is part of the TrinityCore 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 General Public License as published by the * Free Software Foundation; either version 2 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 . */ #include "SpellAuraEffects.h" #include "Battlefield.h" #include "BattlefieldMgr.h" #include "Battleground.h" #include "BattlegroundPackets.h" #include "CellImpl.h" #include "CharmInfo.h" #include "Common.h" #include "Containers.h" #include "DB2Stores.h" #include "GridNotifiersImpl.h" #include "Item.h" #include "Log.h" #include "MiscPackets.h" #include "MotionMaster.h" #include "MovementPackets.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "OutdoorPvPMgr.h" #include "Pet.h" #include "PhasingHandler.h" #include "Player.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "Spell.h" #include "SpellHistory.h" #include "SpellMgr.h" #include "SpellScript.h" #include "ThreatManager.h" #include "Unit.h" #include "Util.h" #include "Vehicle.h" #include "Weather.h" #include "WorldPacket.h" #include "WorldSession.h" #include #include class Aura; // // EFFECT HANDLER NOTES // // in aura handler there should be check for modes: // AURA_EFFECT_HANDLE_REAL set // AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK set // AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK set - aura is recalculated or is just applied/removed - need to redo all things related to m_amount // AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK - logical or of above conditions // AURA_EFFECT_HANDLE_STAT - set when stats are reapplied // such checks will speedup trinity change amount/send for client operations // because for change amount operation packets will not be send // aura effect handlers shouldn't contain any AuraEffect or Aura object modifications NonDefaultConstructible AuraEffectHandler[TOTAL_AURAS]= { &AuraEffect::HandleNULL, // 0 SPELL_AURA_NONE &AuraEffect::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT &AuraEffect::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS &AuraEffect::HandleNoImmediateEffect, // 3 SPELL_AURA_PERIODIC_DAMAGE implemented in AuraEffect::PeriodicTick &AuraEffect::HandleAuraDummy, // 4 SPELL_AURA_DUMMY &AuraEffect::HandleModConfuse, // 5 SPELL_AURA_MOD_CONFUSE &AuraEffect::HandleModCharm, // 6 SPELL_AURA_MOD_CHARM &AuraEffect::HandleModFear, // 7 SPELL_AURA_MOD_FEAR &AuraEffect::HandleNoImmediateEffect, // 8 SPELL_AURA_PERIODIC_HEAL implemented in AuraEffect::PeriodicTick &AuraEffect::HandleModAttackSpeed, // 9 SPELL_AURA_MOD_ATTACKSPEED &AuraEffect::HandleModThreat, // 10 SPELL_AURA_MOD_THREAT &AuraEffect::HandleModTaunt, // 11 SPELL_AURA_MOD_TAUNT &AuraEffect::HandleAuraModStun, // 12 SPELL_AURA_MOD_STUN &AuraEffect::HandleModDamageDone, // 13 SPELL_AURA_MOD_DAMAGE_DONE &AuraEffect::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus &AuraEffect::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage &AuraEffect::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH &AuraEffect::HandleModStealthDetect, // 17 SPELL_AURA_MOD_DETECT &AuraEffect::HandleModInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY &AuraEffect::HandleModInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECT &AuraEffect::HandleNoImmediateEffect, // 20 SPELL_AURA_OBS_MOD_HEALTH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 21 SPELL_AURA_OBS_MOD_POWER implemented in AuraEffect::PeriodicTick &AuraEffect::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE &AuraEffect::HandleNoImmediateEffect, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 24 SPELL_AURA_PERIODIC_ENERGIZE implemented in AuraEffect::PeriodicTick &AuraEffect::HandleAuraModPacify, // 25 SPELL_AURA_MOD_PACIFY &AuraEffect::HandleAuraModRoot, // 26 SPELL_AURA_MOD_ROOT &AuraEffect::HandleAuraModSilence, // 27 SPELL_AURA_MOD_SILENCE &AuraEffect::HandleNoImmediateEffect, // 28 SPELL_AURA_REFLECT_SPELLS implement in Unit::SpellHitResult &AuraEffect::HandleAuraModStat, // 29 SPELL_AURA_MOD_STAT &AuraEffect::HandleAuraModSkill, // 30 SPELL_AURA_MOD_SKILL &AuraEffect::HandleAuraModIncreaseSpeed, // 31 SPELL_AURA_MOD_INCREASE_SPEED &AuraEffect::HandleAuraModIncreaseMountedSpeed, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED &AuraEffect::HandleAuraModDecreaseSpeed, // 33 SPELL_AURA_MOD_DECREASE_SPEED &AuraEffect::HandleAuraModIncreaseHealth, // 34 SPELL_AURA_MOD_INCREASE_HEALTH &AuraEffect::HandleAuraModIncreaseEnergy, // 35 SPELL_AURA_MOD_INCREASE_ENERGY &AuraEffect::HandleAuraModShapeshift, // 36 SPELL_AURA_MOD_SHAPESHIFT &AuraEffect::HandleAuraModEffectImmunity, // 37 SPELL_AURA_EFFECT_IMMUNITY &AuraEffect::HandleAuraModStateImmunity, // 38 SPELL_AURA_STATE_IMMUNITY &AuraEffect::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY &AuraEffect::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY &AuraEffect::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY &AuraEffect::HandleNoImmediateEffect, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in AuraEffect::HandleProc &AuraEffect::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in AuraEffect::HandleProc &AuraEffect::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES &AuraEffect::HandleNULL, // 45 SPELL_AURA_TRACK_RESOURCES implemented clientside &AuraEffect::HandleNULL, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a) &AuraEffect::HandleAuraModParryPercent, // 47 SPELL_AURA_MOD_PARRY_PERCENT &AuraEffect::HandleNoImmediateEffect, // 48 SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT &AuraEffect::HandleAuraModDodgePercent, // 49 SPELL_AURA_MOD_DODGE_PERCENT &AuraEffect::HandleNoImmediateEffect, // 50 SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT implemented in Unit::SpellCriticalHealingBonus &AuraEffect::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT &AuraEffect::HandleAuraModWeaponCritPercent, // 52 SPELL_AURA_MOD_WEAPON_CRIT_PERCENT &AuraEffect::HandleNoImmediateEffect, // 53 SPELL_AURA_PERIODIC_LEECH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 54 SPELL_AURA_MOD_HIT_CHANCE implemented in Unit::MeleeSpellMissChance &AuraEffect::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE &AuraEffect::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM &AuraEffect::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE &AuraEffect::HandleAuraModIncreaseSwimSpeed, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED &AuraEffect::HandleNoImmediateEffect, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus &AuraEffect::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE &AuraEffect::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE &AuraEffect::HandleNoImmediateEffect, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, // 63 SPELL_AURA_MOD_ADDITIONAL_POWER_COST implemented in SpellInfo::CalcPowerCost &AuraEffect::HandleNoImmediateEffect, // 64 SPELL_AURA_PERIODIC_MANA_LEECH implemented in AuraEffect::PeriodicTick &AuraEffect::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK &AuraEffect::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH &AuraEffect::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM &AuraEffect::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED &AuraEffect::HandleNoImmediateEffect, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist &AuraEffect::HandleNoImmediateEffect, // 70 SPELL_AURA_PERIODIC_WEAPON_PERCENT_DAMAGE implemented in AuraEffect::PeriodicTick &AuraEffect::HandleStoreTeleportReturnPoint, // 71 SPELL_AURA_STORE_TELEPORT_RETURN_POINT &AuraEffect::HandleNoImmediateEffect, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT &AuraEffect::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL &AuraEffect::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult &AuraEffect::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE &AuraEffect::HandleNoImmediateEffect, // 76 SPELL_AURA_FAR_SIGHT &AuraEffect::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY &AuraEffect::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED &AuraEffect::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE &AuraEffect::HandleModPercentStat, // 80 SPELL_AURA_MOD_PERCENT_STAT &AuraEffect::HandleNoImmediateEffect, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT implemented in Unit::CalcAbsorbResist &AuraEffect::HandleWaterBreathing, // 82 SPELL_AURA_WATER_BREATHING &AuraEffect::HandleModBaseResistance, // 83 SPELL_AURA_MOD_BASE_RESISTANCE &AuraEffect::HandleNoImmediateEffect, // 84 SPELL_AURA_MOD_REGEN implemented in Player::RegenerateHealth &AuraEffect::HandleModPowerRegen, // 85 SPELL_AURA_MOD_POWER_REGEN implemented in Player::Regenerate &AuraEffect::HandleChannelDeathItem, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM &AuraEffect::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus &AuraEffect::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT implemented in Player::RegenerateHealth &AuraEffect::HandleNoImmediateEffect, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT &AuraEffect::HandleUnused, // 90 unused (4.3.4) old SPELL_AURA_MOD_RESIST_CHANCE &AuraEffect::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING &AuraEffect::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE &AuraEffect::HandleNoImmediateEffect, // 94 SPELL_AURA_INTERRUPT_REGEN implemented in Player::Regenerate &AuraEffect::HandleAuraGhost, // 95 SPELL_AURA_GHOST &AuraEffect::HandleNoImmediateEffect, // 96 SPELL_AURA_SPELL_MAGNET implemented in Unit::GetMagicHitRedirectTarget &AuraEffect::HandleNoImmediateEffect, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalcAbsorbResist &AuraEffect::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT &AuraEffect::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER &AuraEffect::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now, but still have spells including GM-spell &AuraEffect::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT &AuraEffect::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus &AuraEffect::HandleAuraModTotalThreat, //103 SPELL_AURA_MOD_TOTAL_THREAT &AuraEffect::HandleAuraWaterWalk, //104 SPELL_AURA_WATER_WALK &AuraEffect::HandleAuraFeatherFall, //105 SPELL_AURA_FEATHER_FALL &AuraEffect::HandleAuraHover, //106 SPELL_AURA_HOVER &AuraEffect::HandleNoImmediateEffect, //107 SPELL_AURA_ADD_FLAT_MODIFIER implemented in AuraEffect::CalculateSpellMod() &AuraEffect::HandleNoImmediateEffect, //108 SPELL_AURA_ADD_PCT_MODIFIER implemented in AuraEffect::CalculateSpellMod() &AuraEffect::HandleNoImmediateEffect, //109 SPELL_AURA_ADD_TARGET_TRIGGER &AuraEffect::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT implemented in Player::Regenerate, Creature::Regenerate &AuraEffect::HandleNoImmediateEffect, //111 SPELL_AURA_INTERCEPT_MELEE_RANGED_ATTACKS implemented in Unit::GetMeleeHitRedirectTarget &AuraEffect::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS &AuraEffect::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus &AuraEffect::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus &AuraEffect::HandleNoImmediateEffect, //115 SPELL_AURA_MOD_HEALING implemented in Unit::SpellBaseHealingBonusForVictim &AuraEffect::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT &AuraEffect::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult &AuraEffect::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonus &AuraEffect::HandleAuraPvpTalents, //119 SPELL_AURA_PVP_TALENTS &AuraEffect::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE &AuraEffect::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY &AuraEffect::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT &AuraEffect::HandleModTargetResistance, //123 SPELL_AURA_MOD_TARGET_RESISTANCE &AuraEffect::HandleAuraModRangedAttackPower, //124 SPELL_AURA_MOD_RANGED_ATTACK_POWER &AuraEffect::HandleNoImmediateEffect, //125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus &AuraEffect::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus &AuraEffect::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus &AuraEffect::HandleAuraModFixate, //128 SPELL_AURA_MOD_FIXATE &AuraEffect::HandleAuraModIncreaseSpeed, //129 SPELL_AURA_MOD_SPEED_ALWAYS &AuraEffect::HandleAuraModIncreaseMountedSpeed, //130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS &AuraEffect::HandleNoImmediateEffect, //131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus &AuraEffect::HandleAuraModIncreaseEnergyPercent, //132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT &AuraEffect::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT &AuraEffect::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT &AuraEffect::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE &AuraEffect::HandleModHealingDonePct, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT &AuraEffect::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE &AuraEffect::HandleModMeleeSpeedPct, //138 SPELL_AURA_MOD_MELEE_HASTE &AuraEffect::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION &AuraEffect::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE &AuraEffect::HandleUnused, //141 SPELL_AURA_141 &AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT &AuraEffect::HandleModRecoveryRateBySpellLabel, //143 SPELL_AURA_MOD_RECOVERY_RATE_BY_SPELL_LABEL also implemented in SpellHistory::StartCooldown &AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes &AuraEffect::HandleAuraModIncreaseHealthPercent, //145 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT2 &AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE &AuraEffect::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK &AuraEffect::HandleModChargeRecoveryRate, //148 SPELL_AURA_MOD_CHARGE_RECOVERY_RATE also implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK &AuraEffect::HandleShieldBlockValuePercent, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT &AuraEffect::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &AuraEffect::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance &AuraEffect::HandleNoImmediateEffect, //153 SPELL_AURA_MOD_AUTOATTACK_RANGE implemented in Unit::IsWithinMeleeRange &AuraEffect::HandleModStealthLevel, //154 SPELL_AURA_MOD_STEALTH_LEVEL &AuraEffect::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING &AuraEffect::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN &AuraEffect::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI &AuraEffect::HandleAuraAllowTalentSwapping, //158 SPELL_AURA_ALLOW_TALENT_SWAPPING &AuraEffect::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell &AuraEffect::HandleUnused, //160 Unused (4.3.4) old SPELL_AURA_MOD_AOE_AVOIDANCE &AuraEffect::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT &AuraEffect::HandleNoImmediateEffect, //162 SPELL_AURA_POWER_BURN implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS &AuraEffect::HandleForceBreathBar, //164 SPELL_AURA_FORCE_BREATH_BAR &AuraEffect::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus &AuraEffect::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT &AuraEffect::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT &AuraEffect::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus &AuraEffect::HandleSetFFAPvP, //169 SPELL_AURA_SET_FFA_PVP implemented in Player::UpdatePvPState &AuraEffect::HandleDetectAmore, //170 SPELL_AURA_DETECT_AMORE used to detect various spells that change visual of units for aura target &AuraEffect::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK &AuraEffect::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK &AuraEffect::HandleNoImmediateEffect, //173 SPELL_AURA_MOD_CHARGE_RECOVERY_RATE_BY_TYPE_MASK implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus &AuraEffect::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus &AuraEffect::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end &AuraEffect::HandleCharmConvert, //177 SPELL_AURA_AOE_CHARM &AuraEffect::HandleAuraModMaxPowerPct, //178 SPELL_AURA_MOD_MAX_POWER_PCT &AuraEffect::HandleAuraModPowerDisplay, //179 SPELL_AURA_MOD_POWER_DISPLAY &AuraEffect::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus &AuraEffect::HandleNULL, //181 SPELL_AURA_MOD_SPELL_CURRENCY_REAGENTS_COUNT_PCT &AuraEffect::HandleSuppressItemPassiveEffectBySpellLabel, //182 SPELL_AURA_SUPPRESS_ITEM_PASSIVE_EFFECT_BY_SPELL_LABEL &AuraEffect::HandleNoImmediateEffect, //183 SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH implemented in Unit::GetUnitCriticalChance, Unit::GetUnitSpellCriticalChance &AuraEffect::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult &AuraEffect::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance &AuraEffect::HandleNULL, //188 SPELL_AURA_MOD_UI_HEALING_RANGE handled clientside - affects UnitInRange lua function only &AuraEffect::HandleModRating, //189 SPELL_AURA_MOD_RATING &AuraEffect::HandleNoImmediateEffect, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN implemented in Player::CalculateReputationGain &AuraEffect::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED &AuraEffect::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_MOD_MELEE_RANGED_HASTE &AuraEffect::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct) &AuraEffect::HandleNoImmediateEffect, //194 SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL implemented in Unit::CalcAbsorbResist &AuraEffect::HandleLearnSpell, //195 SPELL_AURA_LEARN_SPELL &AuraEffect::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN - flat mod of spell cooldowns &AuraEffect::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance &AuraEffect::HandleNoImmediateEffect, //198 SPELL_AURA_MOD_COMBAT_RATING_FROM_COMBAT_RATING implemented in Player::UpdateRating &AuraEffect::HandleUnused, //199 unused (4.3.4) old SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT &AuraEffect::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::RewardPlayerAndGroupAtKill &AuraEffect::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode... &AuraEffect::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst &AuraEffect::HandleNoImmediateEffect, //203 SPELL_AURA_PREVENT_INTERRUPT implemented in SpellInfo::CanBeInterrupted &AuraEffect::HandleNULL, //204 SPELL_AURA_PREVENT_CORPSE_RELEASE &AuraEffect::HandleNoImmediateEffect, //205 SPELL_AURA_MOD_CHARGE_RECOVERY_BY_TYPE_MASK implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED &AuraEffect::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &AuraEffect::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED &AuraEffect::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS &AuraEffect::HandleAuraModIncreaseFlightSpeed, //210 SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS &AuraEffect::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK &AuraEffect::HandleNoImmediateEffect, //212 SPELL_AURA_MOD_HONOR_GAIN_PCT_FROM_SOURCE implemented in Player::RewardHonor &AuraEffect::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage &AuraEffect::HandleNULL, //214 Tamed Pet Passive &AuraEffect::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION &AuraEffect::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS &AuraEffect::HandleModMeleeSpeedPct, //217 SPELL_AURA_MOD_MELEE_HASTE_2 &AuraEffect::HandleNoImmediateEffect, //218 SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL implemented in AuraEffect::CalculateSpellMod() &AuraEffect::HandleNoImmediateEffect, //219 SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL implemented in AuraEffect::CalculateSpellMod() &AuraEffect::HandleNULL, //220 SPELL_AURA_MOD_ABILITY_SCHOOL_MASK &AuraEffect::HandleModDetaunt, //221 SPELL_AURA_MOD_DETAUNT &AuraEffect::HandleNoImmediateEffect, //222 SPELL_AURA_REMOVE_TRANSMOG_COST implemented in WorldSession::HandleTransmogrifyItems &AuraEffect::HandleNoImmediateEffect, //223 SPELL_AURA_REMOVE_BARBER_SHOP_COST implemented in Player::GetBarberShopCost &AuraEffect::HandleNULL, //224 SPELL_AURA_MOD_TRAIT_NODE_ENTRY_RANK &AuraEffect::HandleNULL, //225 SPELL_AURA_MOD_VISIBILITY_RANGE &AuraEffect::HandleNoImmediateEffect, //226 SPELL_AURA_PERIODIC_DUMMY implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE implemented in AuraEffect::PeriodicTick &AuraEffect::HandleNoImmediateEffect, //228 SPELL_AURA_DETECT_STEALTH stealth detection &AuraEffect::HandleNoImmediateEffect, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE &AuraEffect::HandleAuraModIncreaseHealth, //230 SPELL_AURA_MOD_INCREASE_HEALTH_2 &AuraEffect::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE &AuraEffect::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration &AuraEffect::HandleUnused, //233 set model id to the one of the creature with id GetMiscValue() - clientside &AuraEffect::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration &AuraEffect::HandleNULL, //235 SPELL_AURA_MOD_HOVER_NO_HEIGHT_OFFSET handled clientside &AuraEffect::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE &AuraEffect::HandleNULL, //237 SPELL_AURA_237 &AuraEffect::HandleNULL, //238 SPELL_AURA_238 &AuraEffect::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61 &AuraEffect::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE &AuraEffect::HandleForceMoveForward, //241 SPELL_AURA_FORCE_MOVE_FORWARD Forces the caster to move forward &AuraEffect::HandleNULL, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING - 2 test spells: 44183 and 44182 &AuraEffect::HandleAuraModFaction, //243 SPELL_AURA_MOD_FACTION &AuraEffect::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE &AuraEffect::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL &AuraEffect::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK implemented in Spell::EffectApplyAura &AuraEffect::HandleAuraCloneCaster, //247 SPELL_AURA_CLONE_CASTER &AuraEffect::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNoImmediateEffect, //249 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE_BY_TARGET_AURA_MECHANIC implemented in Unit::SpellDamagePctDone and Unit::MeleeDamagePctDone &AuraEffect::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2 &AuraEffect::HandleNoImmediateEffect, //251 SPELL_AURA_MOD_ENEMY_DODGE implemented in Unit::GetUnitDodgeChance &AuraEffect::HandleModCombatSpeedPct, //252 SPELL_AURA_252 Is there any difference between this and SPELL_AURA_MELEE_SLOW ? maybe not stacking mod? &AuraEffect::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::isBlockCritical &AuraEffect::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND &AuraEffect::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonus &AuraEffect::HandleNoReagentUseAura, //256 SPELL_AURA_NO_REAGENT_USE Use SpellClassMask for spell select &AuraEffect::HandleNULL, //257 SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS Use SpellClassMask for spell select &AuraEffect::HandleNoImmediateEffect, //258 SPELL_AURA_OVERRIDE_SUMMONED_OBJECT implemented in Spell::EffectTransmitted &AuraEffect::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_HOT_PCT implemented in Unit::SpellHealingBonusTaken &AuraEffect::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code &AuraEffect::HandlePhase, //261 SPELL_AURA_PHASE &AuraEffect::HandleNoImmediateEffect, //262 SPELL_AURA_ABILITY_IGNORE_AURASTATE implemented in Spell::CheckCast &AuraEffect::HandleNoImmediateEffect, //263 SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES implemented in Spell::CheckCast &AuraEffect::HandleNoImmediateEffect, //264 SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES implemented in Spell::CheckCast, Unit::AttackerStateUpdate &AuraEffect::HandleUnused, //265 unused (4.3.4) &AuraEffect::HandleSetVignette, //266 SPELL_AURA_SET_VIGNETTE &AuraEffect::HandleNoImmediateEffect, //267 SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL implemented in Unit::IsImmunedToSpellEffect &AuraEffect::HandleModArmorPctFromStat, //268 SPELL_AURA_MOD_ARMOR_PCT_FROM_STAT also implemented in Player::UpdateArmor() &AuraEffect::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage &AuraEffect::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonusTaken and Unit::MeleeDamageBonusTaken &AuraEffect::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonusTaken and Unit::MeleeDamageBonusTaken &AuraEffect::HandleNULL, //272 SPELL_AURA_MOD_BLOCK_VALUE_PCT &AuraEffect::HandleUnused, //273 clientside &AuraEffect::HandleNULL, //274 SPELL_AURA_MOD_BLOCK_VALUE_FLAT &AuraEffect::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select &AuraEffect::HandleNULL, //276 mod damage % mechanic? &AuraEffect::HandleUnused, //277 unused (4.3.4) old SPELL_AURA_MOD_MAX_AFFECTED_TARGETS &AuraEffect::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon &AuraEffect::HandleNoImmediateEffect, //279 SPELL_AURA_INITIALIZE_IMAGES &AuraEffect::HandleNoImmediateEffect, //280 SPELL_AURA_MOD_ARMOR_PENETRATION_PCT implemented in Unit::CalcArmorReducedDamage &AuraEffect::HandleNoImmediateEffect, //281 SPELL_AURA_PROVIDE_SPELL_FOCUS implemented in Spell::CheckCast &AuraEffect::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_MOD_BASE_HEALTH_PCT &AuraEffect::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus &AuraEffect::HandleAuraLinked, //284 SPELL_AURA_LINKED &AuraEffect::HandleAuraLinked, //285 SPELL_AURA_LINKED_2 &AuraEffect::HandleModRecoveryRate, //286 SPELL_AURA_MOD_RECOVERY_RATE also implemented in SpellHistory::StartCooldown &AuraEffect::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult &AuraEffect::HandleNoImmediateEffect, //288 SPELL_AURA_IGNORE_HIT_DIRECTION implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNoImmediateEffect, //289 SPELL_AURA_PREVENT_DURABILITY_LOSS implemented in Player::DurabilityPointsLoss &AuraEffect::HandleAuraModCritPct, //290 SPELL_AURA_MOD_CRIT_PCT &AuraEffect::HandleNoImmediateEffect, //291 SPELL_AURA_MOD_XP_QUEST_PCT implemented in Player::RewardQuest &AuraEffect::HandleAuraOpenStable, //292 SPELL_AURA_OPEN_STABLE &AuraEffect::HandleAuraOverrideSpells, //293 SPELL_AURA_OVERRIDE_SPELLS auras which probably add set of abilities to their target based on it's miscvalue &AuraEffect::HandleNoImmediateEffect, //294 SPELL_AURA_PREVENT_REGENERATE_POWER implemented in Player::Regenerate(Powers power) &AuraEffect::HandleNoImmediateEffect, //295 SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonusTaken, Unit::SpellDamageBonusTaken &AuraEffect::HandleAuraSetVehicle, //296 SPELL_AURA_SET_VEHICLE_ID sets vehicle on target &AuraEffect::HandleAuraModRootAndDisableGravity, //297 SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY &AuraEffect::HandleAuraModStunAndDisableGravity, //298 SPELL_AURA_MOD_STUN_DISABLE_GRAVITY &AuraEffect::HandleUnused, //299 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //300 SPELL_AURA_SHARE_DAMAGE_PCT implemented in Unit::DealDamage &AuraEffect::HandleNoImmediateEffect, //301 SPELL_AURA_SCHOOL_HEAL_ABSORB implemented in Unit::CalcHealAbsorb &AuraEffect::HandleUnused, //302 unused (4.3.4) &AuraEffect::HandleNoImmediateEffect, //303 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus &AuraEffect::HandleAuraModFakeInebriation, //304 SPELL_AURA_MOD_DRUNK &AuraEffect::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED &AuraEffect::HandleNoImmediateEffect, //306 SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER implemented in Unit::GetUnitCriticalChance and Unit::GetUnitSpellCriticalChance &AuraEffect::HandleNoImmediateEffect, //307 SPELL_AURA_CAST_WHILE_WALKING_BY_SPELL_LABEL implemented in Unit::CanCastSpellWhileMoving &AuraEffect::HandleNoImmediateEffect, //308 SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES implemented in Unit::GetUnitSpellCriticalChance &AuraEffect::HandleNULL, //309 SPELL_AURA_MOD_RESILIENCE &AuraEffect::HandleNoImmediateEffect, //310 SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE implemented in Spell::CalculateDamageDone &AuraEffect::HandleNULL, //311 SPELL_AURA_IGNORE_COMBAT &AuraEffect::HandleNULL, //312 SPELL_AURA_ANIM_REPLACEMENT_SET implemented clientside &AuraEffect::HandleNULL, //313 SPELL_AURA_MOUNT_ANIM_REPLACEMENT_SET implemented clientside &AuraEffect::HandlePreventResurrection, //314 SPELL_AURA_PREVENT_RESURRECTION todo &AuraEffect::HandleNoImmediateEffect, //315 SPELL_AURA_UNDERWATER_WALKING todo &AuraEffect::HandleNoImmediateEffect, //316 SPELL_AURA_SCHOOL_ABSORB_OVERKILL implemented in Unit::DealDamage() &AuraEffect::HandleNULL, //317 SPELL_AURA_MOD_SPELL_POWER_PCT &AuraEffect::HandleMastery, //318 SPELL_AURA_MASTERY &AuraEffect::HandleModMeleeSpeedPct, //319 SPELL_AURA_MOD_MELEE_HASTE_3 &AuraEffect::HandleNULL, //320 SPELL_AURA_320 &AuraEffect::HandleAuraModNoActions, //321 SPELL_AURA_MOD_NO_ACTIONS &AuraEffect::HandleNoImmediateEffect, //322 SPELL_AURA_INTERFERE_ENEMY_TARGETING implemented in Spell::CheckCast &AuraEffect::HandleUnused, //323 unused (4.3.4) &AuraEffect::HandleNULL, //324 SPELL_AURA_OVERRIDE_UNLOCKED_AZERITE_ESSENCE_RANK &AuraEffect::HandleUnused, //325 SPELL_AURA_LEARN_PVP_TALENT &AuraEffect::HandlePhaseGroup, //326 SPELL_AURA_PHASE_GROUP &AuraEffect::HandlePhaseAlwaysVisible, //327 SPELL_AURA_PHASE_ALWAYS_VISIBLE &AuraEffect::HandleTriggerSpellOnPowerPercent, //328 SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT &AuraEffect::HandleNULL, //329 SPELL_AURA_MOD_POWER_GAIN_PCT &AuraEffect::HandleNoImmediateEffect, //330 SPELL_AURA_CAST_WHILE_WALKING implemented in Unit::CanCastSpellWhileMoving &AuraEffect::HandleAuraForceWeather, //331 SPELL_AURA_FORCE_WEATHER &AuraEffect::HandleNoImmediateEffect, //332 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS implemented in Unit::GetCastSpellInfo &AuraEffect::HandleNoImmediateEffect, //333 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED implemented in Unit::GetCastSpellInfo &AuraEffect::HandleNoImmediateEffect, //334 SPELL_AURA_MOD_AUTOATTACK_CRIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst &AuraEffect::HandleNULL, //335 SPELL_AURA_335 &AuraEffect::HandleMountRestrictions, //336 SPELL_AURA_MOUNT_RESTRICTIONS implemented in Unit::GetMountCapability &AuraEffect::HandleNoImmediateEffect, //337 SPELL_AURA_MOD_VENDOR_ITEMS_PRICES &AuraEffect::HandleNoImmediateEffect, //338 SPELL_AURA_MOD_DURABILITY_LOSS &AuraEffect::HandleNoImmediateEffect, //339 SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET implemented in Unit::GetUnitCriticalChance and Unit::GetUnitSpellCriticalChance &AuraEffect::HandleNULL, //340 SPELL_AURA_MOD_RESURRECTED_HEALTH_BY_GUILD_MEMBER &AuraEffect::HandleModSpellCategoryCooldown, //341 SPELL_AURA_MOD_SPELL_CATEGORY_COOLDOWN &AuraEffect::HandleModMeleeRangedSpeedPct, //342 SPELL_AURA_MOD_MELEE_RANGED_HASTE_2 &AuraEffect::HandleNoImmediateEffect, //343 SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER - Implemented in Unit::MeleeDamageBonusTaken &AuraEffect::HandleNoImmediateEffect, //344 SPELL_AURA_MOD_AUTOATTACK_DAMAGE - Implemented in Unit::MeleeDamageBonusDone &AuraEffect::HandleNoImmediateEffect, //345 SPELL_AURA_BYPASS_ARMOR_FOR_CASTER &AuraEffect::HandleEnableAltPower, //346 SPELL_AURA_ENABLE_ALT_POWER &AuraEffect::HandleNoImmediateEffect, //347 SPELL_AURA_MOD_SPELL_COOLDOWN_BY_HASTE implemented in SpellHistory::StartCooldown &AuraEffect::HandleNoImmediateEffect, //348 SPELL_AURA_MOD_MONEY_GAIN implemented in WorldSession::HandleLootMoneyOpcode &AuraEffect::HandleNoImmediateEffect, //349 SPELL_AURA_MOD_CURRENCY_GAIN implemented in Player::ModifyCurrency &AuraEffect::HandleNULL, //350 SPELL_AURA_350 &AuraEffect::HandleNULL, //351 SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT &AuraEffect::HandleNULL, //352 SPELL_AURA_352 &AuraEffect::HandleNULL, //353 SPELL_AURA_MOD_CAMOUFLAGE &AuraEffect::HandleNoImmediateEffect, //354 SPELL_AURA_MOD_HEALING_DONE_PCT_VERSUS_TARGET_HEALTH implemented in Unit::SpellHealingPctDone &AuraEffect::HandleNULL, //355 SPELL_AURA_MOD_CASTING_SPEED &AuraEffect::HandleNoImmediateEffect, //356 SPELL_AURA_PROVIDE_TOTEM_CATEGORY implemented in Player::HasItemTotemCategory &AuraEffect::HandleNULL, //357 SPELL_AURA_ENABLE_BOSS1_UNIT_FRAME &AuraEffect::HandleNULL, //358 SPELL_AURA_358 &AuraEffect::HandleNoImmediateEffect, //359 SPELL_AURA_MOD_HEALING_DONE_VERSUS_AURASTATE implemented in Unit::SpellHealingPctDone &AuraEffect::HandleNULL, //360 SPELL_AURA_PROC_TRIGGER_SPELL_COPY &AuraEffect::HandleNoImmediateEffect, //361 SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL implemented in Unit::AttackerStateUpdate &AuraEffect::HandleUnused, //362 unused (4.3.4) &AuraEffect::HandleNULL, //363 SPELL_AURA_MOD_NEXT_SPELL &AuraEffect::HandleUnused, //364 unused (4.3.4) &AuraEffect::HandleNULL, //365 SPELL_AURA_MAX_FAR_CLIP_PLANE &AuraEffect::HandleOverrideSpellPowerByAttackPower, //366 SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT &AuraEffect::HandleNULL, //367 SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_RANGED_SPELL &AuraEffect::HandleUnused, //368 unused (4.3.4) &AuraEffect::HandleNULL, //369 SPELL_AURA_ENABLE_POWER_BAR_TIMER &AuraEffect::HandleNULL, //370 SPELL_AURA_SPELL_OVERRIDE_NAME_GROUP &AuraEffect::HandleNULL, //371 &AuraEffect::HandleNULL, //372 SPELL_AURA_OVERRIDE_MOUNT_FROM_SET &AuraEffect::HandleNULL, //373 SPELL_AURA_MOD_SPEED_NO_CONTROL &AuraEffect::HandleNoImmediateEffect, //374 SPELL_AURA_MODIFY_FALL_DAMAGE_PCT implemented in Player::HandleFall &AuraEffect::HandleNULL, //375 SPELL_AURA_HIDE_MODEL_AND_EQUIPEMENT_SLOTS implemented clientside &AuraEffect::HandleNULL, //376 SPELL_AURA_MOD_CURRENCY_GAIN_FROM_SOURCE &AuraEffect::HandleNoImmediateEffect, //377 SPELL_AURA_CAST_WHILE_WALKING_ALL implemented in Unit::CanCastSpellWhileMoving &AuraEffect::HandleModPossessPet, //378 SPELL_AURA_MOD_POSSESS_PET &AuraEffect::HandleModManaRegenPct, //379 SPELL_AURA_MOD_MANA_REGEN_PCT implemented in Player::UpdateManaRegen &AuraEffect::HandleNULL, //380 &AuraEffect::HandleNULL, //381 SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_PET &AuraEffect::HandleNULL, //382 SPELL_AURA_MOD_PET_STAT_PCT &AuraEffect::HandleNoImmediateEffect, //383 SPELL_AURA_IGNORE_SPELL_COOLDOWN implemented in SpellHistory::HasCooldown &AuraEffect::HandleNULL, //384 &AuraEffect::HandleNULL, //385 &AuraEffect::HandleNULL, //386 &AuraEffect::HandleNULL, //387 &AuraEffect::HandleNULL, //388 SPELL_AURA_MOD_TAXI_FLIGHT_SPEED &AuraEffect::HandleNULL, //389 &AuraEffect::HandleNULL, //390 &AuraEffect::HandleNULL, //391 &AuraEffect::HandleNULL, //392 &AuraEffect::HandleNULL, //393 SPELL_AURA_BLOCK_SPELLS_IN_FRONT &AuraEffect::HandleShowConfirmationPrompt, //394 SPELL_AURA_SHOW_CONFIRMATION_PROMPT &AuraEffect::HandleCreateAreaTrigger, //395 SPELL_AURA_AREA_TRIGGER &AuraEffect::HandleTriggerSpellOnPowerAmount, //396 SPELL_AURA_TRIGGER_SPELL_ON_POWER_AMOUNT &AuraEffect::HandleBattlegroundPlayerPosition, //397 SPELL_AURA_BATTLEGROUND_PLAYER_POSITION_FACTIONAL &AuraEffect::HandleBattlegroundPlayerPosition, //398 SPELL_AURA_BATTLEGROUND_PLAYER_POSITION &AuraEffect::HandleNULL, //399 SPELL_AURA_MOD_TIME_RATE &AuraEffect::HandleAuraModSkill, //400 SPELL_AURA_MOD_SKILL_2 &AuraEffect::HandleAuraActAsControlZone, //401 SPELL_AURA_ACT_AS_CONTROL_ZONE &AuraEffect::HandleAuraModOverridePowerDisplay, //402 SPELL_AURA_MOD_OVERRIDE_POWER_DISPLAY &AuraEffect::HandleNoImmediateEffect, //403 SPELL_AURA_OVERRIDE_SPELL_VISUAL implemented in Unit::GetCastSpellXSpellVisualId &AuraEffect::HandleOverrideAttackPowerBySpellPower, //404 SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT &AuraEffect::HandleModRatingPct, //405 SPELL_AURA_MOD_RATING_PCT &AuraEffect::HandleNoImmediateEffect, //406 SPELL_AURA_KEYBOUND_OVERRIDE implemented in WorldSession::HandleKeyboundOverride &AuraEffect::HandleNULL, //407 SPELL_AURA_MOD_FEAR_2 &AuraEffect::HandleUnused, //408 SPELL_AURA_SET_ACTION_BUTTON_SPELL_COUNT clientside &AuraEffect::HandleAuraCanTurnWhileFalling, //409 SPELL_AURA_CAN_TURN_WHILE_FALLING &AuraEffect::HandleNULL, //410 &AuraEffect::HandleNoImmediateEffect, //411 SPELL_AURA_MOD_MAX_CHARGES implemented in SpellHistory::GetMaxCharges &AuraEffect::HandleNULL, //412 &AuraEffect::HandleNULL, //413 SPELL_AURA_MOD_RANGED_ATTACK_DEFLECT_CHANCE &AuraEffect::HandleNULL, //414 SPELL_AURA_MOD_RANGED_ATTACK_BLOCK_CHANCE_IN_FRONT &AuraEffect::HandleNULL, //415 &AuraEffect::HandleNoImmediateEffect, //416 SPELL_AURA_MOD_COOLDOWN_BY_HASTE_REGEN implemented in SpellHistory::StartCooldown &AuraEffect::HandleNoImmediateEffect, //417 SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN implemented in Spell::TriggerGlobalCooldown &AuraEffect::HandleAuraModMaxPower, //418 SPELL_AURA_MOD_MAX_POWER &AuraEffect::HandleAuraModIncreaseBaseManaPercent, //419 SPELL_AURA_MOD_BASE_MANA_PCT &AuraEffect::HandleNoImmediateEffect, //420 SPELL_AURA_MOD_BATTLE_PET_XP_PCT - Implemented in BattlePetMgr::GrantBattlePetExperience &AuraEffect::HandleNULL, //421 SPELL_AURA_MOD_ABSORB_EFFECTS_DONE_PCT &AuraEffect::HandleNULL, //422 SPELL_AURA_MOD_ABSORB_EFFECTS_TAKEN_PCT &AuraEffect::HandleModManaCostPct, //423 SPELL_AURA_MOD_MANA_COST_PCT &AuraEffect::HandleNULL, //424 SPELL_AURA_CASTER_IGNORE_LOS &AuraEffect::HandleNULL, //425 &AuraEffect::HandleNULL, //426 &AuraEffect::HandleNULL, //427 SPELL_AURA_SCALE_PLAYER_LEVEL &AuraEffect::HandleLinkedSummon, //428 SPELL_AURA_LINKED_SUMMON &AuraEffect::HandleNULL, //429 SPELL_AURA_MOD_SUMMON_DAMAGE &AuraEffect::HandlePlayScene, //430 SPELL_AURA_PLAY_SCENE &AuraEffect::HandleModOverrideZonePVPType, //431 SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE &AuraEffect::HandleNULL, //432 &AuraEffect::HandleNULL, //433 &AuraEffect::HandleNULL, //434 &AuraEffect::HandleNULL, //435 &AuraEffect::HandleNoImmediateEffect, //436 SPELL_AURA_MOD_ENVIRONMENTAL_DAMAGE_TAKEN implemented in Player::EnvironmentalDamage &AuraEffect::HandleAuraModMinimumSpeedRate, //437 SPELL_AURA_MOD_MINIMUM_SPEED_RATE &AuraEffect::HandleNULL, //438 SPELL_AURA_PRELOAD_PHASE &AuraEffect::HandleNULL, //439 &AuraEffect::HandleNULL, //440 SPELL_AURA_MOD_MULTISTRIKE_DAMAGE &AuraEffect::HandleNULL, //441 SPELL_AURA_MOD_MULTISTRIKE_CHANCE &AuraEffect::HandleNULL, //442 SPELL_AURA_MOD_READINESS &AuraEffect::HandleNULL, //443 SPELL_AURA_MOD_LEECH &AuraEffect::HandleNULL, //444 &AuraEffect::HandleNULL, //445 &AuraEffect::HandleModAdvFlying, //446 SPELL_AURA_ADV_FLYING &AuraEffect::HandleNoImmediateEffect, //447 SPELL_AURA_MOD_XP_FROM_CREATURE_TYPE implemented in KillRewarder::_RewardXP &AuraEffect::HandleNULL, //448 &AuraEffect::HandleNULL, //449 &AuraEffect::HandleNULL, //450 &AuraEffect::HandleOverridePetSpecs, //451 SPELL_AURA_OVERRIDE_PET_SPECS &AuraEffect::HandleNULL, //452 &AuraEffect::HandleNoImmediateEffect, //453 SPELL_AURA_CHARGE_RECOVERY_MOD implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //454 SPELL_AURA_CHARGE_RECOVERY_MULTIPLIER implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleAuraModRoot, //455 SPELL_AURA_MOD_ROOT_2 &AuraEffect::HandleNoImmediateEffect, //456 SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //457 SPELL_AURA_CHARGE_RECOVERY_AFFECTED_BY_HASTE_REGEN implemented in SpellHistory::GetChargeRecoveryTime &AuraEffect::HandleNoImmediateEffect, //458 SPELL_AURA_IGNORE_DUAL_WIELD_HIT_PENALTY implemented in Unit::MeleeSpellMissChance &AuraEffect::HandleIgnoreMovementForces, //459 SPELL_AURA_IGNORE_MOVEMENT_FORCES &AuraEffect::HandleNULL, //460 SPELL_AURA_RESET_COOLDOWNS_ON_DUEL_START &AuraEffect::HandleNULL, //461 &AuraEffect::HandleNULL, //462 SPELL_AURA_MOD_HEALING_AND_ABSORB_FROM_CASTER &AuraEffect::HandleNULL, //463 SPELL_AURA_CONVERT_CRIT_RATING_PCT_TO_PARRY_RATING used by Riposte &AuraEffect::HandleNULL, //464 SPELL_AURA_MOD_ATTACK_POWER_OF_BONUS_ARMOR &AuraEffect::HandleModBonusArmor, //465 SPELL_AURA_MOD_BONUS_ARMOR &AuraEffect::HandleModBonusArmorPercent, //466 SPELL_AURA_MOD_BONUS_ARMOR_PCT &AuraEffect::HandleModStatBonusPercent, //467 SPELL_AURA_MOD_STAT_BONUS_PCT &AuraEffect::HandleTriggerSpellOnHealthPercent, //468 SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_PCT &AuraEffect::HandleShowConfirmationPrompt, //469 SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY &AuraEffect::HandleNULL, //470 SPELL_AURA_MOD_AURA_TIME_RATE_BY_SPELL_LABEL &AuraEffect::HandleModVersatilityByPct, //471 SPELL_AURA_MOD_VERSATILITY &AuraEffect::HandleNULL, //472 &AuraEffect::HandleNoImmediateEffect, //473 SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT implemented in Player::DurabilityPointLossForEquipSlot &AuraEffect::HandleNULL, //474 SPELL_AURA_REPLACE_ITEM_BONUS_TREE &AuraEffect::HandleAllowUsingGameobjectsWhileMounted, //475 SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED &AuraEffect::HandleNULL, //476 SPELL_AURA_MOD_CURRENCY_GAIN_LOOTED &AuraEffect::HandleNULL, //477 &AuraEffect::HandleNULL, //478 &AuraEffect::HandleNULL, //479 &AuraEffect::HandleNULL, //480 SPELL_AURA_MOD_ARTIFACT_ITEM_LEVEL &AuraEffect::HandleNoImmediateEffect, //481 SPELL_AURA_CONVERT_CONSUMED_RUNE implemented in Spell::TakeRunePower &AuraEffect::HandleNULL, //482 &AuraEffect::HandleNULL, //483 SPELL_AURA_SUPPRESS_TRANSFORMS &AuraEffect::HandleNoImmediateEffect, //484 SPELL_AURA_ALLOW_INTERRUPT_SPELL implemented in SpellInfo::CanBeInterrupted &AuraEffect::HandleModMovementForceMagnitude, //485 SPELL_AURA_MOD_MOVEMENT_FORCE_MAGNITUDE &AuraEffect::HandleNoImmediateEffect, //486 SPELL_AURA_INTERFERE_ALL_TARGETING implemented in Spell::CheckCast &AuraEffect::HandleCosmeticMounted, //487 SPELL_AURA_COSMETIC_MOUNTED &AuraEffect::HandleAuraDisableGravity, //488 SPELL_AURA_DISABLE_GRAVITY &AuraEffect::HandleModAlternativeDefaultLanguage, //489 SPELL_AURA_MOD_ALTERNATIVE_DEFAULT_LANGUAGE &AuraEffect::HandleNULL, //490 &AuraEffect::HandleNoImmediateEffect, //491 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor &AuraEffect::HandleNULL, //492 &AuraEffect::HandleNULL, //493 &AuraEffect::HandleNULL, //494 SPELL_AURA_SET_POWER_POINT_CHARGE &AuraEffect::HandleTriggerSpellOnExpire, //495 SPELL_AURA_TRIGGER_SPELL_ON_EXPIRE &AuraEffect::HandleNULL, //496 SPELL_AURA_ALLOW_CHANGING_EQUIPMENT_IN_TORGHAST &AuraEffect::HandleNULL, //497 SPELL_AURA_MOD_ANIMA_GAIN &AuraEffect::HandleNULL, //498 SPELL_AURA_CURRENCY_LOSS_PCT_ON_DEATH &AuraEffect::HandleNULL, //499 SPELL_AURA_MOD_RESTED_XP_CONSUMPTION &AuraEffect::HandleNoImmediateEffect, //500 SPELL_AURA_IGNORE_SPELL_CHARGE_COOLDOWN implemented in SpellHistory::ConsumeCharge &AuraEffect::HandleNULL, //501 SPELL_AURA_MOD_CRITICAL_DAMAGE_TAKEN_FROM_CASTER &AuraEffect::HandleNULL, //502 SPELL_AURA_MOD_VERSATILITY_DAMAGE_DONE_BENEFIT &AuraEffect::HandleNULL, //503 SPELL_AURA_MOD_VERSATILITY_HEALING_DONE_BENEFIT &AuraEffect::HandleNoImmediateEffect, //504 SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER implemented in Unit::SpellHealingBonusTaken &AuraEffect::HandleNULL, //505 SPELL_AURA_MOD_PLAYER_CHOICE_REROLLS &AuraEffect::HandleDisableInertia, //506 SPELL_AURA_DISABLE_INERTIA &AuraEffect::HandleNoImmediateEffect, //507 SPELL_AURA_MOD_DAMAGE_TAKEN_BY_LABEL implemented in Unit::SpellDamageBonusTaken &AuraEffect::HandleNULL, //508 &AuraEffect::HandleNULL, //509 &AuraEffect::HandleNULL, //510 SPELL_AURA_MODIFIED_RAID_INSTANCE &AuraEffect::HandleNULL, //511 SPELL_AURA_APPLY_PROFESSION_EFFECT &AuraEffect::HandleNULL, //512 &AuraEffect::HandleAuraModAdvFlyingSpeed, //513 SPELL_AURA_MOD_ADV_FLYING_AIR_FRICTION &AuraEffect::HandleAuraModAdvFlyingSpeed, //514 SPELL_AURA_MOD_ADV_FLYING_MAX_VEL &AuraEffect::HandleAuraModAdvFlyingSpeed, //515 SPELL_AURA_MOD_ADV_FLYING_LIFT_COEF &AuraEffect::HandleNULL, //516 &AuraEffect::HandleNULL, //517 &AuraEffect::HandleAuraModAdvFlyingSpeed, //518 SPELL_AURA_MOD_ADV_FLYING_ADD_IMPULSE_MAX_SPEED &AuraEffect::HandleNULL, //519 SPELL_AURA_MOD_COOLDOWN_RECOVERY_RATE_ALL &AuraEffect::HandleAuraModAdvFlyingSpeed, //520 SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE &AuraEffect::HandleAuraModAdvFlyingSpeed, //521 SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_DOWN &AuraEffect::HandleAuraModAdvFlyingSpeed, //522 SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP &AuraEffect::HandleNULL, //523 &AuraEffect::HandleAuraModAdvFlyingSpeed, //524 SPELL_AURA_MOD_ADV_FLYING_OVER_MAX_DECELERATION &AuraEffect::HandleNULL, //525 SPELL_AURA_DISPLAY_PROFESSION_EQUIPMENT &AuraEffect::HandleNULL, //526 &AuraEffect::HandleNULL, //527 &AuraEffect::HandleNULL, //528 SPELL_AURA_ALLOW_BLOCKING_SPELLS &AuraEffect::HandleNULL, //529 SPELL_AURA_MOD_SPELL_BLOCK_CHANCE &AuraEffect::HandleNULL, //530 &AuraEffect::HandleNULL, //531 &AuraEffect::HandleNULL, //532 &AuraEffect::HandleNULL, //533 SPELL_AURA_DISABLE_NAVIGATION &AuraEffect::HandleNULL, //534 &AuraEffect::HandleNULL, //535 &AuraEffect::HandleNoImmediateEffect, //536 SPELL_AURA_IGNORE_SPELL_CREATURE_TYPE_REQUIREMENTS implemented in SpellInfo::CheckTargetCreatureType &AuraEffect::HandleNoImmediateEffect, //537 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER_BY_LABEL implemented in Unit::SpellDamageBonusTaken &AuraEffect::HandleUnused, //538 SPELL_AURA_MOD_FAKE_INEBRIATION_MOVEMENT_ONLY handled clientside &AuraEffect::HandleNoImmediateEffect, //539 SPELL_AURA_ALLOW_MOUNT_IN_COMBAT implemented in SpellInfo::CanBeUsedInCombat &AuraEffect::HandleNULL, //540 SPELL_AURA_MOD_SUPPORT_STAT &AuraEffect::HandleModRequiredMountCapabilityFlags, //541 SPELL_AURA_MOD_REQUIRED_MOUNT_CAPABILITY_FLAGS &AuraEffect::HandleNULL, //542 SPELL_AURA_TRIGGER_SPELL_ON_STACK_AMOUNT &AuraEffect::HandleNULL, //543 &AuraEffect::HandleNULL, //544 &AuraEffect::HandleSetCantSwim, //545 SPELL_AURA_MOVE_SET_CANT_SWIM &AuraEffect::HandleNULL, //546 &AuraEffect::HandleNULL, //547 &AuraEffect::HandleNULL, //548 &AuraEffect::HandleNULL, //549 &AuraEffect::HandleNULL, //550 &AuraEffect::HandleNULL, //551 &AuraEffect::HandleNULL, //552 &AuraEffect::HandleNULL, //553 &AuraEffect::HandleNULL, //554 &AuraEffect::HandleNULL, //555 &AuraEffect::HandleNULL, //556 &AuraEffect::HandleNULL, //557 &AuraEffect::HandleNULL, //558 &AuraEffect::HandleNULL, //559 &AuraEffect::HandleNULL, //560 &AuraEffect::HandleNULL, //561 &AuraEffect::HandleNULL, //562 &AuraEffect::HandleNULL, //563 &AuraEffect::HandleNULL, //564 &AuraEffect::HandleNULL, //565 &AuraEffect::HandleNULL, //566 &AuraEffect::HandleNULL, //567 &AuraEffect::HandleNULL, //568 &AuraEffect::HandleNULL, //569 &AuraEffect::HandleNULL, //570 &AuraEffect::HandleNULL, //571 &AuraEffect::HandleNULL, //572 &AuraEffect::HandleNULL, //573 &AuraEffect::HandleNULL, //574 &AuraEffect::HandleNULL, //575 &AuraEffect::HandleNULL, //576 &AuraEffect::HandleNULL, //577 &AuraEffect::HandleNULL, //578 &AuraEffect::HandleNULL, //579 &AuraEffect::HandleNULL, //580 &AuraEffect::HandleNULL, //581 &AuraEffect::HandleNULL, //582 &AuraEffect::HandleNULL, //583 &AuraEffect::HandleNULL, //584 &AuraEffect::HandleNULL, //585 &AuraEffect::HandleNULL, //586 &AuraEffect::HandleNULL, //587 &AuraEffect::HandleNULL, //588 &AuraEffect::HandleNULL, //589 &AuraEffect::HandleNULL, //590 &AuraEffect::HandleNULL, //591 &AuraEffect::HandleNULL, //592 &AuraEffect::HandleNULL, //593 &AuraEffect::HandleNULL, //594 &AuraEffect::HandleNULL, //595 &AuraEffect::HandleNULL, //596 &AuraEffect::HandleNULL, //597 &AuraEffect::HandleNULL, //598 &AuraEffect::HandleNULL, //599 &AuraEffect::HandleNULL, //600 &AuraEffect::HandleNULL, //601 &AuraEffect::HandleNULL, //602 &AuraEffect::HandleNULL, //603 &AuraEffect::HandleNULL, //604 &AuraEffect::HandleNULL, //605 &AuraEffect::HandleNULL, //606 &AuraEffect::HandleNULL, //607 &AuraEffect::HandleNULL, //608 &AuraEffect::HandleNULL, //609 &AuraEffect::HandleNULL, //610 &AuraEffect::HandleNULL, //611 &AuraEffect::HandleNULL, //612 &AuraEffect::HandleNULL, //613 &AuraEffect::HandleNULL, //614 &AuraEffect::HandleNULL, //615 &AuraEffect::HandleNULL, //616 &AuraEffect::HandleNULL, //617 &AuraEffect::HandleNULL, //618 &AuraEffect::HandleNULL, //619 &AuraEffect::HandleNULL, //620 &AuraEffect::HandleNULL, //621 &AuraEffect::HandleNULL, //622 &AuraEffect::HandleNULL, //623 &AuraEffect::HandleNULL, //624 &AuraEffect::HandleNULL, //625 &AuraEffect::HandleNULL, //626 &AuraEffect::HandleNULL, //627 &AuraEffect::HandleNULL, //628 &AuraEffect::HandleNULL, //629 &AuraEffect::HandleNULL, //630 &AuraEffect::HandleNULL, //631 &AuraEffect::HandleNULL, //632 &AuraEffect::HandleNULL, //633 &AuraEffect::HandleNULL, //634 &AuraEffect::HandleNULL, //635 &AuraEffect::HandleNULL, //636 &AuraEffect::HandleNoImmediateEffect, //637 SPELL_AURA_MOD_EXPLORATION_EXPERIENCE implemented in Player::CheckAreaExplore &AuraEffect::HandleNoImmediateEffect, //638 SPELL_AURA_MOD_CRITICAL_BLOCK_AMOUNT implemented in Unit::CalculateMeleeDamage andUnit::CalculateSpellDamageTaken &AuraEffect::HandleNULL, //639 &AuraEffect::HandleNULL, //640 &AuraEffect::HandleNULL, //641 &AuraEffect::HandleNULL, //642 &AuraEffect::HandleNULL, //643 SPELL_AURA_MOD_RANGED_ATTACK_SPEED_FLAT &AuraEffect::HandleNULL, //644 &AuraEffect::HandleNULL, //645 }; AuraEffect::AuraEffect(Aura* base, SpellEffectInfo const& spellEfffectInfo, int32 const* baseAmount, Unit* caster) : m_base(base), m_spellInfo(base->GetSpellInfo()), m_effectInfo(spellEfffectInfo), m_spellmod(nullptr), m_baseAmount(baseAmount ? *baseAmount : spellEfffectInfo.CalcBaseValue(caster, base->GetType() == UNIT_AURA_TYPE ? base->GetOwner()->ToUnit() : nullptr, base->GetCastItemId(), base->GetCastItemLevel())), _amount(), _periodicTimer(0), _period(0), _ticksDone(0), m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); _amount = CalculateAmount(caster); CalculateSpellMod(); } AuraEffect::~AuraEffect() { delete m_spellmod; } template void AuraEffect::GetTargetList(Container& targetContainer) const { Aura::ApplicationMap const& targetMap = GetBase()->GetApplicationMap(); // remove all targets which were not added to new list - they no longer deserve area aura for (auto appIter = targetMap.begin(); appIter != targetMap.end(); ++appIter) { if (appIter->second->HasEffect(GetEffIndex())) targetContainer.push_back(appIter->second->GetTarget()); } } template void AuraEffect::GetApplicationList(Container& applicationContainer) const { Aura::ApplicationMap const& targetMap = GetBase()->GetApplicationMap(); for (auto appIter = targetMap.begin(); appIter != targetMap.end(); ++appIter) { if (appIter->second->HasEffect(GetEffIndex())) applicationContainer.push_back(appIter->second); } } int32 AuraEffect::CalculateAmount(Unit* caster) { Unit* unitOwner = GetBase()->GetOwner()->ToUnit(); // default amount calculation int32 amount = GetSpellEffectInfo().CalcValue(caster, &m_baseAmount, unitOwner, nullptr, GetBase()->GetCastItemId(), GetBase()->GetCastItemLevel()); // custom amount calculations go here switch (GetAuraType()) { // crowd control auras case SPELL_AURA_MOD_CONFUSE: case SPELL_AURA_MOD_FEAR: case SPELL_AURA_MOD_STUN: case SPELL_AURA_MOD_ROOT: case SPELL_AURA_TRANSFORM: case SPELL_AURA_MOD_ROOT_2: m_canBeRecalculated = false; if (!m_spellInfo->ProcFlags) break; amount = int32(unitOwner->CountPctFromMaxHealth(10)); break; case SPELL_AURA_SCHOOL_ABSORB: m_canBeRecalculated = false; if (!caster || !unitOwner) break; amount = caster->SpellAbsorbBonusDone(unitOwner, m_spellInfo, amount, m_effectInfo, 1, this); amount = unitOwner->SpellAbsorbBonusTaken(caster, m_spellInfo, amount); break; case SPELL_AURA_MANA_SHIELD: m_canBeRecalculated = false; break; case SPELL_AURA_MOUNTED: { uint32 mountType = uint32(GetMiscValueB()); if (MountEntry const* mountEntry = sDB2Manager.GetMount(GetId())) mountType = mountEntry->MountTypeID; if (MountCapabilityEntry const* mountCapability = unitOwner->GetMountCapability(mountType)) amount = mountCapability->ID; break; } case SPELL_AURA_SHOW_CONFIRMATION_PROMPT_WITH_DIFFICULTY: if (caster) amount = caster->GetMap()->GetDifficultyID(); m_canBeRecalculated = false; break; default: break; } if (GetSpellInfo()->HasAttribute(SPELL_ATTR10_ROLLING_PERIODIC)) { Unit::AuraEffectList const& periodicAuras = unitOwner->GetAuraEffectsByType(GetAuraType()); if (uint32 totalTicks = GetTotalTicks()) { amount = std::accumulate(std::begin(periodicAuras), std::end(periodicAuras), amount, [&](int32 val, AuraEffect const* aurEff) { if (aurEff->GetCasterGUID() == GetCasterGUID() && aurEff->GetId() == GetId() && aurEff->GetEffIndex() == GetEffIndex()) val += aurEff->GetEstimatedAmount().value_or(aurEff->GetAmount()) * static_cast(aurEff->GetRemainingTicks()) / static_cast(totalTicks); return val; }); } } GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated); if (!GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking)) amount *= GetBase()->GetStackAmount(); _estimatedAmount = CalculateEstimatedAmount(caster, amount); return amount; } Optional AuraEffect::CalculateEstimatedAmount(Unit const* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, int32 amount, uint8 stack, AuraEffect const* aurEff) { uint32 stackAmountForBonuses = !spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? stack : 1; switch (spellEffectInfo.ApplyAuraName) { case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_LEECH: return caster->SpellDamageBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses, nullptr, aurEff); case SPELL_AURA_PERIODIC_HEAL: return caster->SpellHealingBonusDone(target, spellInfo, amount, DOT, spellEffectInfo, stackAmountForBonuses, nullptr, aurEff); default: break; } return {}; } Optional AuraEffect::CalculateEstimatedAmount(Unit const* caster, int32 amount) const { if (!caster || GetBase()->GetType() != UNIT_AURA_TYPE) return {}; return CalculateEstimatedAmount(caster, GetBase()->GetUnitOwner(), GetSpellInfo(), GetSpellEffectInfo(), amount, GetBase()->GetStackAmount(), this); } float AuraEffect::CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* target, SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, float amount, uint8 stack) { int32 maxDuration = Aura::CalcMaxDuration(spellInfo, caster, nullptr); if (maxDuration <= 0) return 0.0f; int32 period = spellEffectInfo.ApplyAuraPeriod; if (!period) return 0.0f; if (Player* modOwner = caster->GetSpellModOwner()) modOwner->ApplySpellMod(spellInfo, SpellModOp::Period, period); // Haste modifies periodic time of channeled spells if (spellInfo->IsChanneled()) caster->ModSpellDurationTime(spellInfo, period); else if (spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) period = int32(period * caster->m_unitData->ModCastingSpeed); else if (spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC)) period = int32(period * caster->m_unitData->ModHaste); if (!period) return 0.0f; float totalTicks = float(maxDuration) / period; if (spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD)) totalTicks += 1.0f; return totalTicks * CalculateEstimatedAmount(caster, target, spellInfo, spellEffectInfo, amount, stack, nullptr).value_or(amount); } uint32 AuraEffect::GetTotalTicks() const { uint32 totalTicks = 0; if (_period && !GetBase()->IsPermanent()) { totalTicks = static_cast(GetBase()->GetMaxDuration() / _period); if (m_spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD)) ++totalTicks; } return totalTicks; } void AuraEffect::ResetPeriodic(bool resetPeriodicTimer /*= false*/) { _ticksDone = 0; if (resetPeriodicTimer) { _periodicTimer = 0; // Start periodic on next tick or at aura apply if (m_spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD)) _periodicTimer = _period; } } void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= true*/, bool load /*= false*/) { _period = GetSpellEffectInfo().ApplyAuraPeriod; // prepare periodics switch (GetAuraType()) { case SPELL_AURA_OBS_MOD_POWER: case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_OBS_MOD_HEALTH: case SPELL_AURA_PERIODIC_TRIGGER_SPELL: case SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT: case SPELL_AURA_PERIODIC_ENERGIZE: case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: case SPELL_AURA_PERIODIC_MANA_LEECH: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: case SPELL_AURA_POWER_BURN: case SPELL_AURA_PERIODIC_DUMMY: case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: m_isPeriodic = true; break; default: break; } GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, _period); if (!m_isPeriodic) return; Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr; // Apply casting time mods if (_period) { // Apply periodic time mod if (modOwner) modOwner->ApplySpellMod(GetSpellInfo(), SpellModOp::Period, _period); if (caster) { // Haste modifies periodic time of channeled spells if (m_spellInfo->IsChanneled()) caster->ModSpellDurationTime(m_spellInfo, _period); else if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) _period = int32(_period * caster->m_unitData->ModCastingSpeed); else if (m_spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC)) _period = int32(_period * caster->m_unitData->ModHaste); } } else // prevent infinite loop on Update m_isPeriodic = false; if (load) // aura loaded from db { if (_period && !GetBase()->IsPermanent()) { uint32 elapsedTime = GetBase()->GetMaxDuration() - GetBase()->GetDuration(); _ticksDone = elapsedTime / uint32(_period); _periodicTimer = elapsedTime % uint32(_period); } if (m_spellInfo->HasAttribute(SPELL_ATTR5_EXTRA_INITIAL_PERIOD)) ++_ticksDone; } else // aura just created or reapplied { // reset periodic timer on aura create or reapply // we don't reset periodic timers when aura is triggered by proc ResetPeriodic(resetPeriodicTimer); } } void AuraEffect::CalculateSpellMod() { switch (GetAuraType()) { case SPELL_AURA_ADD_FLAT_MODIFIER: case SPELL_AURA_ADD_PCT_MODIFIER: if (!m_spellmod) { SpellModifierByClassMask* spellmod = new SpellModifierByClassMask(GetBase()); spellmod->op = SpellModOp(GetMiscValue()); spellmod->type = GetAuraType() == SPELL_AURA_ADD_PCT_MODIFIER ? SPELLMOD_PCT : SPELLMOD_FLAT; spellmod->spellId = GetId(); spellmod->mask = GetSpellEffectInfo().SpellClassMask; m_spellmod = spellmod; } static_cast(m_spellmod)->value = GetAmount(); break; case SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL: if (!m_spellmod) { SpellFlatModifierByLabel* spellmod = new SpellFlatModifierByLabel(GetBase()); spellmod->op = SpellModOp(GetMiscValue()); spellmod->type = SPELLMOD_LABEL_FLAT; spellmod->spellId = GetId(); spellmod->value.ModIndex = GetMiscValue(); spellmod->value.LabelID = GetMiscValueB(); m_spellmod = spellmod; } static_cast(m_spellmod)->value.ModifierValue = GetAmount(); break; case SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL: if (!m_spellmod) { SpellPctModifierByLabel* spellmod = new SpellPctModifierByLabel(GetBase()); spellmod->op = SpellModOp(GetMiscValue()); spellmod->type = SPELLMOD_LABEL_PCT; spellmod->spellId = GetId(); spellmod->value.ModIndex = GetMiscValue(); spellmod->value.LabelID = GetMiscValueB(); m_spellmod = spellmod; } static_cast(m_spellmod)->value.ModifierValue = 1.0f + CalculatePct(1.0f, GetAmount()); break; default: break; } GetBase()->CallScriptEffectCalcSpellModHandlers(this, m_spellmod); // validate modifier if (m_spellmod) { bool isValid = true; auto logErrors = [&] { return std::ranges::any_of(GetBase()->m_loadedScripts, [](AuraScript const* script) { return script->DoEffectCalcSpellMod.size() > 0; }); }; if (AsUnderlyingType(m_spellmod->op) >= MAX_SPELLMOD) { isValid = false; if (logErrors()) TC_LOG_ERROR("spells.aura.effect", "Aura script for spell id {} created invalid spell modifier op {}", GetId(), AsUnderlyingType(m_spellmod->op)); } if (m_spellmod->type >= SPELLMOD_END) { isValid = false; if (logErrors()) TC_LOG_ERROR("spells.aura.effect", "Aura script for spell id {} created invalid spell modifier type {}", GetId(), AsUnderlyingType(m_spellmod->type)); } if (!isValid) { delete m_spellmod; m_spellmod = nullptr; } } } void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply, AuraEffect const* triggeredBy /* = nullptr */) { // Reapply if amount change uint8 handleMask = 0; if (newAmount != GetAmount()) handleMask |= AURA_EFFECT_HANDLE_CHANGE_AMOUNT; if (onStackOrReapply) handleMask |= AURA_EFFECT_HANDLE_REAPPLY; if (!handleMask) return; std::vector effectApplications; GetApplicationList(effectApplications); for (AuraApplication* aurApp : effectApplications) { aurApp->GetTarget()->_RegisterAuraEffect(this, false); HandleEffect(aurApp, handleMask, false, triggeredBy); } if (handleMask & AURA_EFFECT_HANDLE_CHANGE_AMOUNT) { if (!mark) _amount = newAmount; else SetAmount(newAmount); CalculateSpellMod(); } for (AuraApplication* aurApp : effectApplications) { if (aurApp->GetRemoveMode() != AURA_REMOVE_NONE) continue; aurApp->GetTarget()->_RegisterAuraEffect(this, true); HandleEffect(aurApp, handleMask, true, triggeredBy); } if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType())) GetBase()->SetNeedClientUpdateForTargets(); } void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply, AuraEffect const* triggeredBy /*= nullptr*/) { // check if call is correct, we really don't want using bitmasks here (with 1 exception) ASSERT(mode == AURA_EFFECT_HANDLE_REAL || mode == AURA_EFFECT_HANDLE_SEND_FOR_CLIENT || mode == AURA_EFFECT_HANDLE_CHANGE_AMOUNT || mode == AURA_EFFECT_HANDLE_STAT || mode == AURA_EFFECT_HANDLE_SKILL || mode == AURA_EFFECT_HANDLE_REAPPLY || mode == (AURA_EFFECT_HANDLE_CHANGE_AMOUNT | AURA_EFFECT_HANDLE_REAPPLY)); // register/unregister effect in lists in case of real AuraEffect apply/remove // registration/unregistration is done always before real effect handling (some effect handlers code is depending on this) if (mode & AURA_EFFECT_HANDLE_REAL) aurApp->GetTarget()->_RegisterAuraEffect(this, apply); // real aura apply/remove, handle modifier if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) ApplySpellMod(aurApp->GetTarget(), apply, triggeredBy); // call scripts helping/replacing effect handlers bool prevented = false; if (apply) prevented = GetBase()->CallScriptEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode); else prevented = GetBase()->CallScriptEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode); // check if script events have removed the aura already if (apply && aurApp->GetRemoveMode()) return; // call default effect handler if it wasn't prevented if (!prevented) (*this.*AuraEffectHandler[GetAuraType()].Value)(aurApp, mode, apply); // check if the default handler reemoved the aura if (apply && aurApp->GetRemoveMode()) return; // call scripts triggering additional events after apply/remove if (apply) GetBase()->CallScriptAfterEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode); else GetBase()->CallScriptAfterEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode); } void AuraEffect::HandleEffect(Unit* target, uint8 mode, bool apply, AuraEffect const* triggeredBy /*= nullptr*/) { AuraApplication* aurApp = GetBase()->GetApplicationOfTarget(target->GetGUID()); ASSERT(aurApp); HandleEffect(aurApp, mode, apply, triggeredBy); } void AuraEffect::ApplySpellMod(Unit* target, bool apply, AuraEffect const* triggeredBy /*= nullptr*/) { if (!m_spellmod || target->GetTypeId() != TYPEID_PLAYER) return; target->ToPlayer()->AddSpellMod(m_spellmod, apply); // Auras with charges do not mod amount of passive auras if (GetBase()->IsUsingCharges()) return; // reapply some passive spells after add/remove related spellmods // Warning: it is a dead loop if 2 auras each other amount-shouldn't happen Optional recalculateEffectIndex; switch (SpellModOp(GetMiscValue())) { case SpellModOp::Points: break; case SpellModOp::PointsIndex0: recalculateEffectIndex = EFFECT_0; break; case SpellModOp::PointsIndex1: recalculateEffectIndex = EFFECT_1; break; case SpellModOp::PointsIndex2: recalculateEffectIndex = EFFECT_2; break; case SpellModOp::PointsIndex3: recalculateEffectIndex = EFFECT_3; break; case SpellModOp::PointsIndex4: recalculateEffectIndex = EFFECT_4; break; default: return; } if (!triggeredBy) triggeredBy = this; ObjectGuid guid = target->GetGUID(); for (auto& [_, aurApp] : target->GetAppliedAuras()) { Aura* aura = aurApp->GetBase(); // only passive and permament auras-active auras should have amount set on spellcast and not be affected // if aura is cast by others, it will not be affected if ((!aura->IsPassive() && !aura->IsPermanent() && !GetSpellInfo()->IsUpdatingTemporaryAuraValuesBySpellMod()) || aura->GetCasterGUID() != guid || !aura->GetSpellInfo()->IsAffectedBySpellMods() || !aura->GetSpellInfo()->IsAffectedBySpellMod(m_spellmod)) continue; if (recalculateEffectIndex) { if (AuraEffect* aurEff = aura->GetEffect(*recalculateEffectIndex)) if (aurEff != triggeredBy) aurEff->RecalculateAmount(triggeredBy); } else for (AuraEffect* aurEff : aura->GetAuraEffects()) if (aurEff != triggeredBy) aurEff->RecalculateAmount(triggeredBy); } } void AuraEffect::Update(uint32 diff, Unit* caster) { if (!m_isPeriodic || (GetBase()->GetDuration() < 0 && !GetBase()->IsPassive() && !GetBase()->IsPermanent())) return; uint32 totalTicks = GetTotalTicks(); _periodicTimer += diff; while (_periodicTimer >= _period) { _periodicTimer -= _period; if (!GetBase()->IsPermanent() && (_ticksDone + 1) > totalTicks) break; ++_ticksDone; GetBase()->CallScriptEffectUpdatePeriodicHandlers(this); std::vector effectApplications; GetApplicationList(effectApplications); // tick on targets of effects for (AuraApplication* aurApp : effectApplications) PeriodicTick(aurApp, caster); } } float AuraEffect::GetCritChanceFor(Unit const* caster, Unit const* target) const { return target->SpellCritChanceTaken(caster, nullptr, this, GetSpellInfo()->GetSchoolMask(), CalcPeriodicCritChance(caster), GetSpellInfo()->GetAttackType()); } bool AuraEffect::IsAffectingSpell(SpellInfo const* spell) const { if (!spell) return false; // Check family name and EffectClassMask if (!spell->IsAffected(m_spellInfo->SpellFamilyName, GetSpellEffectInfo().SpellClassMask)) return false; return true; } void AuraEffect::SendTickImmune(Unit* target, Unit* caster) const { if (caster) caster->SendSpellDamageImmune(target, m_spellInfo->Id, true); } void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const { bool prevented = GetBase()->CallScriptEffectPeriodicHandlers(this, aurApp); if (prevented) return; Unit* target = aurApp->GetTarget(); // Update serverside orientation of tracking channeled auras on periodic update ticks // exclude players because can turn during channeling and shouldn't desync orientation client/server if (caster && !caster->IsPlayer() && m_spellInfo->IsChanneled() && m_spellInfo->HasAttribute(SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL) && caster->m_unitData->ChannelObjects.size()) { ObjectGuid const channelGuid = caster->m_unitData->ChannelObjects[0]; if (channelGuid != caster->GetGUID()) if (WorldObject const* objectTarget = ObjectAccessor::GetWorldObject(*caster, channelGuid)) caster->SetInFront(objectTarget); } switch (GetAuraType()) { case SPELL_AURA_PERIODIC_DUMMY: // handled via scripts break; case SPELL_AURA_PERIODIC_TRIGGER_SPELL: HandlePeriodicTriggerSpellAuraTick(target, caster); break; case SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT: // Don't actually do anything - client will trigger casts of these spells by itself break; case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: HandlePeriodicTriggerSpellWithValueAuraTick(target, caster); break; case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_WEAPON_PERCENT_DAMAGE: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: HandlePeriodicDamageAurasTick(target, caster); break; case SPELL_AURA_PERIODIC_LEECH: HandlePeriodicHealthLeechAuraTick(target, caster); break; case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: HandlePeriodicHealthFunnelAuraTick(target, caster); break; case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_OBS_MOD_HEALTH: HandlePeriodicHealAurasTick(target, caster); break; case SPELL_AURA_PERIODIC_MANA_LEECH: HandlePeriodicManaLeechAuraTick(target, caster); break; case SPELL_AURA_OBS_MOD_POWER: HandleObsModPowerAuraTick(target, caster); break; case SPELL_AURA_PERIODIC_ENERGIZE: HandlePeriodicEnergizeAuraTick(target, caster); break; case SPELL_AURA_POWER_BURN: HandlePeriodicPowerBurnAuraTick(target, caster); break; default: break; } } bool AuraEffect::CheckEffectProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) const { bool result = GetBase()->CallScriptCheckEffectProcHandlers(this, aurApp, eventInfo); if (!result) return false; SpellInfo const* spellInfo = eventInfo.GetSpellInfo(); switch (GetAuraType()) { case SPELL_AURA_MOD_CONFUSE: case SPELL_AURA_MOD_FEAR: case SPELL_AURA_MOD_STUN: case SPELL_AURA_MOD_ROOT: case SPELL_AURA_TRANSFORM: { DamageInfo* damageInfo = eventInfo.GetDamageInfo(); if (!damageInfo || !damageInfo->GetDamage()) return false; // Spell own damage at apply won't break CC if (spellInfo && spellInfo == GetSpellInfo()) { Aura* aura = GetBase(); // called from spellcast, should not have ticked yet if (aura->GetDuration() == aura->GetMaxDuration()) return false; } break; } case SPELL_AURA_MECHANIC_IMMUNITY: case SPELL_AURA_MOD_MECHANIC_RESISTANCE: // compare mechanic if (!spellInfo || !(spellInfo->GetAllEffectsMechanicMask() & (UI64LIT(1) << GetMiscValue()))) return false; break; case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: // skip melee hits and instant cast spells if (!eventInfo.GetProcSpell() || !eventInfo.GetProcSpell()->GetCastTime()) return false; break; case SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER: case SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER: // Compare casters if (GetCasterGUID() != eventInfo.GetActor()->GetGUID()) return false; break; case SPELL_AURA_MOD_POWER_COST_SCHOOL: case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: { // Skip melee hits and spells with wrong school or zero cost if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue()) // School Check || !eventInfo.GetProcSpell()) return false; // Costs Check std::vector const& costs = eventInfo.GetProcSpell()->GetPowerCost(); if (std::ranges::none_of(costs, [](SpellPowerCost const& cost) { return cost.Amount > 0; })) return false; break; } case SPELL_AURA_REFLECT_SPELLS_SCHOOL: // Skip melee hits and spells with wrong school if (!spellInfo || !(spellInfo->GetSchoolMask() & GetMiscValue())) return false; break; case SPELL_AURA_PROC_TRIGGER_SPELL: case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: { // Don't proc extra attacks while already processing extra attack spell uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { if (triggeredSpellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) { uint32 lastExtraAttackSpell = eventInfo.GetActor()->GetLastExtraAttackSpell(); // Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves if (lastExtraAttackSpell == triggerSpellId) return false; } } break; } case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: // skip spells that can't crit if (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT)) return false; break; default: break; } return result; } void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo); if (prevented) return; switch (GetAuraType()) { // CC Auras which use their amount to drop // Are there any more auras which need this? case SPELL_AURA_MOD_CONFUSE: case SPELL_AURA_MOD_FEAR: case SPELL_AURA_MOD_STUN: case SPELL_AURA_MOD_ROOT: case SPELL_AURA_TRANSFORM: case SPELL_AURA_MOD_ROOT_2: HandleBreakableCCAuraProc(aurApp, eventInfo); break; case SPELL_AURA_DUMMY: case SPELL_AURA_PROC_TRIGGER_SPELL: HandleProcTriggerSpellAuraProc(aurApp, eventInfo); break; case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: HandleProcTriggerSpellWithValueAuraProc(aurApp, eventInfo); break; case SPELL_AURA_PROC_TRIGGER_DAMAGE: HandleProcTriggerDamageAuraProc(aurApp, eventInfo); break; default: break; } GetBase()->CallScriptAfterEffectProcHandlers(this, aurApp, eventInfo); } void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const { uint32 spellId = 0; uint32 spellId2 = 0; uint32 spellId3 = 0; uint32 spellId4 = 0; switch (GetMiscValue()) { case FORM_CAT_FORM: spellId = 3025; spellId2 = 48629; spellId3 = 106840; spellId4 = 113636; break; case FORM_TREE_OF_LIFE: spellId = 5420; spellId2 = 81097; break; case FORM_TRAVEL_FORM: spellId = 5419; break; case FORM_AQUATIC_FORM: spellId = 5421; break; case FORM_BEAR_FORM: case FORM_DIRE_BEAR_FORM: spellId = 1178; spellId2 = 21178; spellId3 = 106829; spellId4 = 106899; break; case FORM_FLIGHT_FORM: spellId = 33948; spellId2 = 34764; break; case FORM_FLIGHT_FORM_EPIC: spellId = 40122; spellId2 = 40121; break; case FORM_SPIRIT_OF_REDEMPTION: spellId = 27792; spellId2 = 27795; spellId3 = 62371; break; case FORM_SHADOWFORM: if (target->HasAura(107906)) // Glyph of Shadow spellId = 107904; else if (target->HasAura(126745)) // Glyph of Shadowy Friends spellId = 142024; else spellId = 107903; break; case FORM_GHOST_WOLF: if (target->HasAura(58135)) // Glyph of Spectral Wolf spellId = 160942; break; case FORM_GHOUL: case FORM_AMBIENT: case FORM_STEALTH: case FORM_BATTLE_STANCE: case FORM_DEFENSIVE_STANCE: case FORM_BERSERKER_STANCE: case FORM_MOONKIN_FORM: case FORM_METAMORPHOSIS: break; default: break; } if (apply) { if (spellId) target->CastSpell(target, spellId, this); if (spellId2) target->CastSpell(target, spellId2, this); if (spellId3) target->CastSpell(target, spellId3, this); if (spellId4) target->CastSpell(target, spellId4, this); if (target->GetTypeId() == TYPEID_PLAYER) { Player* plrTarget = target->ToPlayer(); PlayerSpellMap const& sp_list = plrTarget->GetSpellMap(); for (auto itr = sp_list.begin(); itr != sp_list.end(); ++itr) { if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled) continue; if (itr->first == spellId || itr->first == spellId2 || itr->first == spellId3 || itr->first == spellId4) continue; SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE); if (!spellInfo || !(spellInfo->IsPassive() || spellInfo->HasAttribute(SPELL_ATTR0_DO_NOT_DISPLAY_SPELLBOOK_AURA_ICON_COMBAT_LOG))) continue; if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1))) target->CastSpell(target, itr->first, this); } } } else { if (spellId) target->RemoveOwnedAura(spellId, target->GetGUID()); if (spellId2) target->RemoveOwnedAura(spellId2, target->GetGUID()); if (spellId3) target->RemoveOwnedAura(spellId3, target->GetGUID()); if (spellId4) target->RemoveOwnedAura(spellId4, target->GetGUID()); Unit::AuraEffectList const& shapeshifts = target->GetAuraEffectsByType(SPELL_AURA_MOD_SHAPESHIFT); AuraEffect const* newAura = nullptr; // Iterate through all the shapeshift auras that the target has, if there is another aura with SPELL_AURA_MOD_SHAPESHIFT, then this aura is being removed due to that one being applied for (AuraEffect const* aurEff : shapeshifts) { if (aurEff != this) { newAura = aurEff; break; } } Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); for (auto itr = tAuras.begin(); itr != tAuras.end();) { // Use the new aura to see on what stance the target will be uint64 newStance = newAura ? (UI64LIT(1) << (newAura->GetMiscValue() - 1)) : 0; // If the stances are not compatible with the spell, remove it if (itr->second->GetBase()->IsRemovedOnShapeLost(target) && !(itr->second->GetBase()->GetSpellInfo()->Stances & newStance)) target->RemoveAura(itr); else ++itr; } } } /*********************************************************/ /*** AURA EFFECT HANDLERS ***/ /*********************************************************/ /**************************************/ /*** VISIBILITY & PHASES ***/ /**************************************/ void AuraEffect::HandleModInvisibilityDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); InvisibilityType type = InvisibilityType(GetMiscValue()); if (apply) { target->m_invisibilityDetect.AddFlag(type); target->m_invisibilityDetect.AddValue(type, GetAmount()); } else { if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY_DETECT)) target->m_invisibilityDetect.DelFlag(type); target->m_invisibilityDetect.AddValue(type, -GetAmount()); } // call functions which may have additional effects after changing state of unit if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); InvisibilityType type = InvisibilityType(GetMiscValue()); if (apply) { // apply glow vision if (type == INVISIBILITY_GENERAL) if (Player* playerTarget = target->ToPlayer()) playerTarget->AddAuraVision(PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); target->m_invisibility.AddFlag(type); target->m_invisibility.AddValue(type, GetAmount()); target->SetVisFlag(UNIT_VIS_FLAGS_INVISIBLE); } else { if (!target->HasAuraTypeWithMiscvalue(SPELL_AURA_MOD_INVISIBILITY, type)) { // if not have invisibility auras of type INVISIBILITY_GENERAL // remove glow vision if (type == INVISIBILITY_GENERAL) if (Player* playerTarget = target->ToPlayer()) playerTarget->RemoveAuraVision(PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); target->m_invisibility.DelFlag(type); } if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) target->RemoveVisFlag(UNIT_VIS_FLAGS_INVISIBLE); target->m_invisibility.AddValue(type, -GetAmount()); } // call functions which may have additional effects after changing state of unit if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) { // drop flag at invisibiliy in bg target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); StealthType type = StealthType(GetMiscValue()); if (apply) { target->m_stealthDetect.AddFlag(type); target->m_stealthDetect.AddValue(type, GetAmount()); } else { if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH_DETECT)) target->m_stealthDetect.DelFlag(type); target->m_stealthDetect.AddValue(type, -GetAmount()); } // call functions which may have additional effects after changing state of unit if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); StealthType type = StealthType(GetMiscValue()); if (apply) { target->m_stealth.AddFlag(type); target->m_stealth.AddValue(type, GetAmount()); target->SetVisFlag(UNIT_VIS_FLAGS_STEALTHED); if (Player * playerTarget = target->ToPlayer()) playerTarget->AddAuraVision(PLAYER_FIELD_BYTE2_STEALTH); } else { target->m_stealth.AddValue(type, -GetAmount()); if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH { target->m_stealth.DelFlag(type); target->RemoveVisFlag(UNIT_VIS_FLAGS_STEALTHED); if (Player * playerTarget = target->ToPlayer()) playerTarget->RemoveAuraVision(PLAYER_FIELD_BYTE2_STEALTH); } } // call functions which may have additional effects after changing state of unit if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) { // drop flag at stealth in bg target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); StealthType type = StealthType(GetMiscValue()); if (apply) target->m_stealth.AddValue(type, GetAmount()); else target->m_stealth.AddValue(type, -GetAmount()); // call functions which may have additional effects after changing state of unit if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleDetectAmore(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; if (apply) { if (Player* playerTarget = target->ToPlayer()) { playerTarget->AddAuraVision(PlayerFieldByte2Flags(1 << (GetMiscValue() - 1))); } } else { if (target->HasAuraType(SPELL_AURA_DETECT_AMORE)) { Unit::AuraEffectList const& amoreAuras = target->GetAuraEffectsByType(SPELL_AURA_DETECT_AMORE); for (Unit::AuraEffectList::const_iterator i = amoreAuras.begin(); i != amoreAuras.end(); ++i) { if (GetMiscValue() == (*i)->GetMiscValue()) return; } } if (Player* playerTarget = target->ToPlayer()) playerTarget->RemoveAuraVision(PlayerFieldByte2Flags(1 << (GetMiscValue() - 1))); } } void AuraEffect::HandleSpiritOfRedemption(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // prepare spirit state if (apply) { if (target->GetTypeId() == TYPEID_PLAYER) { // set stand state (expected in this form) if (!target->IsStandState()) target->SetStandState(UNIT_STAND_STATE_STAND); } } // die at aura end else if (target->IsAlive()) // call functions which may have additional effects after changing state of unit target->setDeathState(JUST_DIED); } void AuraEffect::HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) { target->SetPlayerFlag(PLAYER_FLAGS_GHOST); target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); } else { if (target->HasAuraType(SPELL_AURA_GHOST)) return; target->RemovePlayerFlag(PLAYER_FLAGS_GHOST); target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } } void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) PhasingHandler::AddPhase(target, uint32(GetMiscValueB()), true); else PhasingHandler::RemovePhase(target, uint32(GetMiscValueB()), true); } void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) PhasingHandler::AddPhaseGroup(target, uint32(GetMiscValueB()), true); else PhasingHandler::RemovePhaseGroup(target, uint32(GetMiscValueB()), true); } void AuraEffect::HandlePhaseAlwaysVisible(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (!apply) PhasingHandler::SetAlwaysVisible(target, true, true); else { if (target->HasAuraType(SPELL_AURA_PHASE_ALWAYS_VISIBLE) || (target->IsPlayer() && target->ToPlayer()->IsGameMaster())) return; PhasingHandler::SetAlwaysVisible(target, false, true); } } /**********************/ /*** UNIT MODEL ***/ /**********************/ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK)) return; SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(GetMiscValue()); ASSERT(shapeInfo, "Spell %u uses unknown ShapeshiftForm (%u).", GetId(), GetMiscValue()); Unit* target = aurApp->GetTarget(); ShapeshiftForm form = ShapeshiftForm(GetMiscValue()); uint32 modelid = target->GetModelForForm(form, GetId()); if (apply) { // remove polymorph before changing display id to keep new display id switch (form) { case FORM_CAT_FORM: case FORM_TREE_OF_LIFE: case FORM_TRAVEL_FORM: case FORM_AQUATIC_FORM: case FORM_BEAR_FORM: case FORM_DIRE_BEAR_FORM: case FORM_FLIGHT_FORM_EPIC: case FORM_FLIGHT_FORM: case FORM_MOONKIN_FORM: { // remove movement affects target->RemoveAurasByShapeShift(); // and polymorphic affects if (target->IsPolymorphed()) target->RemoveAurasDueToSpell(target->GetTransformSpell()); break; } default: break; } // remove other shapeshift before applying a new one target->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT, ObjectGuid::Empty, GetBase()); // stop handling the effect if it was removed by linked event if (aurApp->GetRemoveMode()) return; ShapeshiftForm prevForm = target->GetShapeshiftForm(); target->SetShapeshiftForm(form); // add the shapeshift aura's boosts if (prevForm != form) HandleShapeshiftBoosts(target, true); if (modelid > 0) { SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->GetTransformSpell(), GetBase()->GetCastDifficulty()); if (!transformSpellInfo || !GetSpellInfo()->IsPositive()) target->SetDisplayId(modelid); } if (!shapeInfo->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance)) target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Shapeshifting, GetSpellInfo()); } else { // reset model id if no other auras present // may happen when aura is applied on linked event on aura removal if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) { target->SetShapeshiftForm(FORM_NONE); if (target->GetClass() == CLASS_DRUID) { // Remove movement impairing effects also when shifting out target->RemoveAurasByShapeShift(); } } if (modelid > 0) target->RestoreDisplayId(target->IsMounted()); switch (form) { // Nordrassil Harness - bonus case FORM_BEAR_FORM: case FORM_DIRE_BEAR_FORM: case FORM_CAT_FORM: if (AuraEffect* dummy = target->GetAuraEffect(37315, 0)) target->CastSpell(target, 37316, dummy); break; // Nordrassil Regalia - bonus case FORM_MOONKIN_FORM: if (AuraEffect* dummy = target->GetAuraEffect(37324, 0)) target->CastSpell(target, 37325, dummy); break; default: break; } // remove the shapeshift aura's boosts HandleShapeshiftBoosts(target, false); } if (Player* playerTarget = target->ToPlayer()) { playerTarget->SendMovementSetCollisionHeight(playerTarget->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Force); playerTarget->InitDataForForm(); } else target->UpdateDisplayPower(); if (target->GetClass() == CLASS_DRUID) { // Dash if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, flag128(0, 0, 0x8))) aurEff->RecalculateAmount(); // Disarm handling // If druid shifts while being disarmed we need to deal with that since forms aren't affected by disarm // and also HandleAuraModDisarm is not triggered if (!target->CanUseAttackType(BASE_ATTACK)) { if (Item* pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem, apply); } } // stop handling the effect if it was removed by linked event if (apply && aurApp->GetRemoveMode()) return; if (target->GetTypeId() == TYPEID_PLAYER) { // Learn spells for shapeshift form - no need to send action bars or add spells to spellbook for (uint8 i = 0; i < MAX_SHAPESHIFT_SPELLS; ++i) { if (!shapeInfo->PresetSpellID[i]) continue; if (apply) target->ToPlayer()->AddTemporarySpell(shapeInfo->PresetSpellID[i]); else target->ToPlayer()->RemoveTemporarySpell(shapeInfo->PresetSpellID[i]); } } } void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) { // update active transform spell only when transform not set or not overwriting negative by positive case SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(target->GetTransformSpell(), GetBase()->GetCastDifficulty()); if (!transformSpellInfo || !GetSpellInfo()->IsPositive() || transformSpellInfo->IsPositive()) { target->SetTransformSpell(GetId()); // special case (spell specific functionality) if (GetMiscValue() == 0) { Gender gender = target->GetNativeGender(); switch (GetId()) { // Orb of Deception case 16739: { if (target->GetTypeId() != TYPEID_PLAYER) return; switch (target->GetRace()) { // Blood Elf case RACE_BLOODELF: target->SetDisplayId(gender == GENDER_FEMALE ? 17830 : 17829); break; // Orc case RACE_ORC: target->SetDisplayId(gender == GENDER_FEMALE ? 10140 : 10139); break; // Troll case RACE_TROLL: target->SetDisplayId(gender == GENDER_FEMALE ? 10134 : 10135); break; // Tauren case RACE_TAUREN: target->SetDisplayId(gender == GENDER_FEMALE ? 10147 : 10136); break; // Undead case RACE_UNDEAD_PLAYER: target->SetDisplayId(gender == GENDER_FEMALE ? 10145 : 10146); break; // Draenei case RACE_DRAENEI: target->SetDisplayId(gender == GENDER_FEMALE ? 17828 : 17827); break; // Dwarf case RACE_DWARF: target->SetDisplayId(gender == GENDER_FEMALE ? 10142 : 10141); break; // Gnome case RACE_GNOME: target->SetDisplayId(gender == GENDER_FEMALE ? 10149 : 10148); break; // Human case RACE_HUMAN: target->SetDisplayId(gender == GENDER_FEMALE ? 10138 : 10137); break; // Night Elf case RACE_NIGHTELF: target->SetDisplayId(gender == GENDER_FEMALE ? 10144 : 10143); break; default: break; } break; } // Murloc costume case 42365: target->SetDisplayId(21723); break; // Dread Corsair case 50517: // Corsair Costume case 51926: { if (target->GetTypeId() != TYPEID_PLAYER) return; switch (target->GetRace()) { // Blood Elf case RACE_BLOODELF: target->SetDisplayId(gender == GENDER_MALE ? 25032 : 25043); break; // Orc case RACE_ORC: target->SetDisplayId(gender == GENDER_MALE ? 25039 : 25050); break; // Troll case RACE_TROLL: target->SetDisplayId(gender == GENDER_MALE ? 25041 : 25052); break; // Tauren case RACE_TAUREN: target->SetDisplayId(gender == GENDER_MALE ? 25040 : 25051); break; // Undead case RACE_UNDEAD_PLAYER: target->SetDisplayId(gender == GENDER_MALE ? 25042 : 25053); break; // Draenei case RACE_DRAENEI: target->SetDisplayId(gender == GENDER_MALE ? 25033 : 25044); break; // Dwarf case RACE_DWARF: target->SetDisplayId(gender == GENDER_MALE ? 25034 : 25045); break; // Gnome case RACE_GNOME: target->SetDisplayId(gender == GENDER_MALE ? 25035 : 25046); break; // Human case RACE_HUMAN: target->SetDisplayId(gender == GENDER_MALE ? 25037 : 25048); break; // Night Elf case RACE_NIGHTELF: target->SetDisplayId(gender == GENDER_MALE ? 25038 : 25049); break; default: break; } break; } // Pygmy Oil case 53806: target->SetDisplayId(22512); break; // Honor the Dead case 65386: case 65495: target->SetDisplayId(gender == GENDER_MALE ? 29203 : 29204); break; // Darkspear Pride case 75532: target->SetDisplayId(gender == GENDER_MALE ? 31737 : 31738); break; // Gnomeregan Pride case 75531: target->SetDisplayId(gender == GENDER_MALE ? 31654 : 31655); break; default: break; } } else { CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(GetMiscValue()); if (!ci) { target->SetDisplayId(16358); // pig pink ^_^ TC_LOG_ERROR("spells.aura.effect", "Auras: unknown creature id = {} (only need its modelid) From Spell Aura Transform in Spell ID = {}", GetMiscValue(), GetId()); } else { uint32 model_id = 0; // choose a model, based on trigger flag if (uint32 modelid = ObjectMgr::ChooseDisplayId(ci)->CreatureDisplayID) model_id = modelid; target->SetDisplayId(model_id); // Dragonmaw Illusion (set mount model also) if (GetId() == 42016 && target->GetMountDisplayId() && !target->GetAuraEffectsByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty()) target->SetMountDisplayId(16314); } } } // polymorph case if ((mode & AURA_EFFECT_HANDLE_REAL) && target->GetTypeId() == TYPEID_PLAYER && target->IsPolymorphed()) { // for players, start regeneration after 1s (in polymorph fast regeneration case) // only if caster is Player (after patch 2.4.2) if (GetCasterGUID().IsPlayer()) target->ToPlayer()->setRegenTimerCount(1*IN_MILLISECONDS); //dismount polymorphed target (after patch 2.4.2) if (target->IsMounted()) target->RemoveAurasByType(SPELL_AURA_MOUNTED); } target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::Transform); } else { // HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true) will reapply it if need if (target->GetTransformSpell() == GetId()) target->SetTransformSpell(0); target->RestoreDisplayId(target->IsMounted()); // Dragonmaw Illusion (restore mount model) if (GetId() == 42016 && target->GetMountDisplayId() == 16314) { if (!target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty()) { uint32 cr_id = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(cr_id)) { CreatureModel model = *ObjectMgr::ChooseDisplayId(ci); sObjectMgr->GetCreatureModelRandomGender(&model, ci); target->SetMountDisplayId(model.CreatureDisplayID); } } } } } void AuraEffect::HandleAuraModScale(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; aurApp->GetTarget()->RecalculateObjectScale(); } void AuraEffect::HandleAuraCloneCaster(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) { Unit* caster = GetCaster(); if (!caster || caster == target) return; // What must be cloned? at least display and scale target->SetDisplayId(caster->GetDisplayId()); //target->SetObjectScale(caster->GetObjectScale()); // we need retail info about how scaling is handled (aura maybe?) target->SetUnitFlag2(UNIT_FLAG2_MIRROR_IMAGE); } else { target->SetDisplayId(target->GetNativeDisplayId()); target->RemoveUnitFlag2(UNIT_FLAG2_MIRROR_IMAGE); } } /************************/ /*** FIGHT ***/ /************************/ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) { auto isAffectedByFeignDeath = [](Unit const* attacker) { Creature const* attackerCreature = attacker->ToCreature(); return !attackerCreature || !attackerCreature->IsIgnoringFeignDeath(); }; std::vector targets; Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityRange()); Trinity::UnitListSearcher searcher(target, targets, u_check); Cell::VisitAllObjects(target, searcher, target->GetMap()->GetVisibilityRange()); for (Unit* unit : targets) { if (!unit->HasUnitState(UNIT_STATE_CASTING)) continue; if (!isAffectedByFeignDeath(unit)) continue; for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) { if (unit->GetCurrentSpell(i) && unit->GetCurrentSpell(i)->m_targets.GetUnitTargetGUID() == target->GetGUID()) { unit->InterruptSpell(CurrentSpellTypes(i), false); } } } for (auto const& [guid, ref] : target->GetThreatManager().GetThreatenedByMeList()) if (isAffectedByFeignDeath(ref->GetOwner())) ref->ScaleThreat(0.0f); if (target->GetMap()->IsDungeon()) // feign death does not remove combat in dungeons { target->AttackStop(); if (Player* targetPlayer = target->ToPlayer()) targetPlayer->SendAttackSwingCancelAttack(); } else target->CombatStop(false, false, isAffectedByFeignDeath); // prevent interrupt message if (GetCasterGUID() == target->GetGUID() && target->GetCurrentSpell(CURRENT_GENERIC_SPELL)) target->FinishSpell(CURRENT_GENERIC_SPELL, SPELL_FAILED_INTERRUPTED); target->InterruptNonMeleeSpells(true); // stop handling the effect if it was removed by linked event if (aurApp->GetRemoveMode()) return; target->SetUnitFlag(UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT); target->SetUnitFlag2(UNIT_FLAG2_FEIGN_DEATH); target->SetUnitFlag3(UNIT_FLAG3_FAKE_DEAD); target->AddUnitState(UNIT_STATE_DIED); if (Creature* creature = target->ToCreature()) creature->SetReactState(REACT_PASSIVE); } else { target->RemoveUnitFlag(UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT); target->RemoveUnitFlag2(UNIT_FLAG2_FEIGN_DEATH); target->RemoveUnitFlag3(UNIT_FLAG3_FAKE_DEAD); target->ClearUnitState(UNIT_STATE_DIED); if (Creature* creature = target->ToCreature()) creature->InitializeReactState(); } } void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (!apply && target->HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) return; if (apply) target->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2); else target->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE_2); // call functions which may have additional effects after changing state of unit if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) { if (target->GetMap()->IsDungeon()) { target->AttackStop(); if (Player* targetPlayer = target->ToPlayer()) targetPlayer->SendAttackSwingCancelAttack(); } else target->CombatStop(); } } void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); AuraType type = GetAuraType(); bool(*flagChangeFunc)(Unit* u) = nullptr; uint32 slot; WeaponAttackType attType; switch (type) { case SPELL_AURA_MOD_DISARM: if (apply) flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag(UNIT_FLAG_DISARMED)) { return false; } u->SetUnitFlag(UNIT_FLAG_DISARMED); return true; }; else flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM)) { return false; } u->RemoveUnitFlag(UNIT_FLAG_DISARMED); return true; }; slot = EQUIPMENT_SLOT_MAINHAND; attType = BASE_ATTACK; break; case SPELL_AURA_MOD_DISARM_OFFHAND: if (apply) flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND)) { return false; } u->SetUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); return true; }; else flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM_OFFHAND)) { return false; } u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_OFFHAND); return true; }; slot = EQUIPMENT_SLOT_OFFHAND; attType = OFF_ATTACK; break; case SPELL_AURA_MOD_DISARM_RANGED: if (apply) flagChangeFunc = [](Unit* u) { if (u->HasUnitFlag2(UNIT_FLAG2_DISARM_RANGED)) { return false; } u->SetUnitFlag2(UNIT_FLAG2_DISARM_RANGED); return true; }; else flagChangeFunc = [](Unit* u) { if (u->HasAuraType(SPELL_AURA_MOD_DISARM_RANGED)) { return false; } u->RemoveUnitFlag2(UNIT_FLAG2_DISARM_RANGED); return true; }; slot = EQUIPMENT_SLOT_MAINHAND; attType = RANGED_ATTACK; break; default: return; } // set/remove flag before weapon bonuses so it's properly reflected in CanUseAttackType if (flagChangeFunc) if (!flagChangeFunc(target)) //Prevent handling aura twice return; // Handle damage modification, shapeshifted druids are not affected if (target->GetTypeId() == TYPEID_PLAYER && !target->IsInFeralForm()) { Player* player = target->ToPlayer(); if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) { WeaponAttackType const attackType = Player::GetAttackBySlot(slot, item->GetTemplate()->GetInventoryType()); player->ApplyItemDependentAuras(item, !apply); if (attackType != MAX_ATTACK) { player->_ApplyWeaponDamage(slot, item, !apply); if (!apply) // apply case already handled on item dependent aura removal (if any) player->UpdateWeaponDependentAuras(attackType); } } } if (target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->GetCurrentEquipmentId()) target->UpdateDamagePhysical(attType); } static void InterruptSpellsWithPreventionTypeOnAuraApply(Unit* target, SpellPreventionType preventionType) { // Stop cast only spells vs PreventionType for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i))) if (spell->m_spellInfo->PreventionType & preventionType) // Stop spells on prepare or casting state target->InterruptSpell(CurrentSpellTypes(i), false); } void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) { target->SetSilencedSchoolMask(SpellSchoolMask(GetMiscValue())); // call functions which may have additional effects after changing state of unit InterruptSpellsWithPreventionTypeOnAuraApply(target, SPELL_PREVENTION_TYPE_SILENCE); } else { int32 silencedSchoolMask = 0; for (AuraEffect const* auraEffect : target->GetAuraEffectsByType(SPELL_AURA_MOD_SILENCE)) silencedSchoolMask |= auraEffect->GetMiscValue(); for (AuraEffect const* auraEffect : target->GetAuraEffectsByType(SPELL_AURA_MOD_PACIFY_SILENCE)) silencedSchoolMask |= auraEffect->GetMiscValue(); target->ReplaceAllSilencedSchoolMask(SpellSchoolMask(silencedSchoolMask)); } } void AuraEffect::HandleAuraModPacify(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) { target->SetUnitFlag(UNIT_FLAG_PACIFIED); // call functions which may have additional effects after changing state of unit InterruptSpellsWithPreventionTypeOnAuraApply(target, SPELL_PREVENTION_TYPE_PACIFY); } else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(SPELL_AURA_MOD_PACIFY) || target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) return; target->RemoveUnitFlag(UNIT_FLAG_PACIFIED); } } void AuraEffect::HandleAuraModPacifyAndSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); // Vengeance of the Blue Flight (@todo REMOVE THIS!) /// @workaround if (m_spellInfo->Id == 45839) { if (apply) target->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); else target->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); } if (!(apply)) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) return; } HandleAuraModPacify(aurApp, mode, apply); HandleAuraModSilence(aurApp, mode, apply); } void AuraEffect::HandleAuraModNoActions(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) { target->SetUnitFlag2(UNIT_FLAG2_NO_ACTIONS); // call functions which may have additional effects after chainging state of unit InterruptSpellsWithPreventionTypeOnAuraApply(target, SPELL_PREVENTION_TYPE_NO_ACTIONS); } else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(SPELL_AURA_MOD_NO_ACTIONS)) return; target->RemoveUnitFlag2(UNIT_FLAG2_NO_ACTIONS); } } /****************************/ /*** TRACKING ***/ /****************************/ void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->SetTrackCreatureFlag(uint32(1) << (GetMiscValue() - 1)); else target->RemoveTrackCreatureFlag(uint32(1) << (GetMiscValue() - 1)); } void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (!(apply)) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } if (apply) target->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_TRACK_STEALTHED); else target->RemovePlayerLocalFlag(PLAYER_LOCAL_FLAG_TRACK_STEALTHED); } void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); // used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND if (apply) target->SetDynamicFlag(UNIT_DYNFLAG_TRACK_UNIT); else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (!target->HasAuraType(GetAuraType())) target->RemoveDynamicFlag(UNIT_DYNFLAG_TRACK_UNIT); } // call functions which may have additional effects after changing state of unit if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) target->SetVisFlag(UNIT_VIS_FLAGS_UNTRACKABLE); else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; target->RemoveVisFlag(UNIT_VIS_FLAGS_UNTRACKABLE); } } /****************************/ /*** SKILLS & TALENTS ***/ /****************************/ void AuraEffect::HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_SKILL))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; uint32 prot = GetMiscValue(); int32 points = GetAmount(); if (prot == SKILL_DEFENSE) return; target->ModifySkillBonus(prot, (apply ? points : -points), GetAuraType() == SPELL_AURA_MOD_SKILL_TALENT); } void AuraEffect::HandleAuraAllowTalentSwapping(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_REAL))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->SetUnitFlag2(UNIT_FLAG2_ALLOW_CHANGING_TALENTS); else if (!target->HasAuraType(GetAuraType())) target->RemoveUnitFlag2(UNIT_FLAG2_ALLOW_CHANGING_TALENTS); } /****************************/ /*** MOVEMENT ***/ /****************************/ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) { if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK) { uint32 creatureEntry = GetMiscValue(); uint32 displayId = 0; uint32 vehicleId = 0; if (MountEntry const* mountEntry = sDB2Manager.GetMount(GetId())) { if (DB2Manager::MountXDisplayContainer const* mountDisplays = sDB2Manager.GetMountDisplays(mountEntry->ID)) { if (mountEntry->GetFlags().HasFlag(MountFlags::IsSelfMount)) { displayId = DISPLAYID_HIDDEN_MOUNT; } else { DB2Manager::MountXDisplayContainer usableDisplays; std::copy_if(mountDisplays->begin(), mountDisplays->end(), std::back_inserter(usableDisplays), [target](MountXDisplayEntry const* mountDisplay) { if (Player* playerTarget = target->ToPlayer()) return ConditionMgr::IsPlayerMeetingCondition(playerTarget, mountDisplay->PlayerConditionID); return true; }); if (!usableDisplays.empty()) displayId = Trinity::Containers::SelectRandomContainerElement(usableDisplays)->CreatureDisplayInfoID; } } // TODO: CREATE TABLE mount_vehicle (mountId, vehicleCreatureId) for future mounts that are vehicles (new mounts no longer have proper data in MiscValue) //if (MountVehicle const* mountVehicle = sObjectMgr->GetMountVehicle(mountEntry->Id)) // creatureEntry = mountVehicle->VehicleCreatureId; if (mode & AURA_EFFECT_HANDLE_REAL && !mountEntry->GetFlags().HasFlag(MountFlags::MountEquipmentEffectsSuppressed)) { if (Player* playerTarget = target->ToPlayer()) { auto mountEquipmentItr = std::ranges::find_if(sMountEquipmentStore, [&](int32 equipmentSpell) { return playerTarget->HasSpell(equipmentSpell); }, &MountEquipmentEntry::LearnedBySpell); if (mountEquipmentItr != sMountEquipmentStore.end()) playerTarget->CastSpell(playerTarget, mountEquipmentItr->BuffSpell, this); } } } if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry)) { vehicleId = creatureInfo->VehicleId; if (!displayId) { CreatureModel model = *ObjectMgr::ChooseDisplayId(creatureInfo); sObjectMgr->GetCreatureModelRandomGender(&model, creatureInfo); displayId = model.CreatureDisplayID; } //some spell has one aura of mount and one of vehicle for (SpellEffectInfo const& effect : GetSpellInfo()->GetEffects()) if (effect.IsEffect(SPELL_EFFECT_SUMMON) && effect.MiscValue == GetMiscValue()) displayId = 0; } target->Mount(displayId, vehicleId, creatureEntry); } // cast speed aura if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) { if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount())) { target->SetFlightCapabilityID(mountCapability->FlightCapabilityID, true); target->CastSpell(target, mountCapability->ModSpellAuraID, this); } } } else { if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK) target->Dismount(); //some mounts like Headless Horseman's Mount or broom stick are skill based spell // need to remove ALL arura related to mounts, this will stop client crash with broom stick // and never endless flying after using Headless Horseman's Mount if (mode & AURA_EFFECT_HANDLE_REAL) { target->RemoveAurasByType(SPELL_AURA_MOUNTED); for (MountEquipmentEntry const* mountEquipmentStore : sMountEquipmentStore) target->RemoveOwnedAura(mountEquipmentStore->BuffSpell); } if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) // remove speed aura if (MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(GetAmount())) target->RemoveAurasDueToSpell(mountCapability->ModSpellAuraID, target->GetGUID()); target->SetFlightCapabilityID(0, true); } } void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) return; } target->SetCanTransitionBetweenSwimAndFly(apply); if (target->SetCanFly(apply)) { if (!apply && !target->IsGravityDisabled()) target->GetMotionMaster()->MoveFall(); } } void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetWaterWalking(apply); } void AuraEffect::HandleAuraFeatherFall(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetFeatherFall(apply); // start fall from current height if (!apply && target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->SetFallInformation(0, target->GetPositionZ()); } void AuraEffect::HandleAuraHover(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetHover(apply); //! Sets movementflags } void AuraEffect::HandleWaterBreathing(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); // update timers in client if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateMirrorTimers(); } void AuraEffect::HandleForceMoveForward(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) target->SetUnitFlag2(UNIT_FLAG2_FORCE_MOVEMENT); else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; target->RemoveUnitFlag2(UNIT_FLAG2_FORCE_MOVEMENT); } } void AuraEffect::HandleAuraCanTurnWhileFalling(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetCanTurnWhileFalling(apply); } void AuraEffect::HandleModAdvFlying(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); target->SetCanDoubleJump(apply || target->HasAura(SPELL_DH_DOUBLE_JUMP)); target->SetCanFly(apply); target->SetCanAdvFly(apply); } void AuraEffect::HandleIgnoreMovementForces(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetIgnoreMovementForces(apply); } void AuraEffect::HandleDisableInertia(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetDisableInertia(apply); } void AuraEffect::HandleSetCantSwim(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } target->SetMoveCantSwim(apply); } /****************************/ /*** THREAT ***/ /****************************/ void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; aurApp->GetTarget()->GetThreatManager().UpdateMySpellSchoolModifiers(); } void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!target->IsAlive() || target->GetTypeId() != TYPEID_PLAYER) return; Unit* caster = GetCaster(); if (caster && caster->IsAlive()) caster->GetThreatManager().UpdateMyTempModifiers(); } void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (!target->IsAlive() || !target->CanHaveThreatList()) return; target->GetThreatManager().TauntUpdate(); } void AuraEffect::HandleModDetaunt(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* caster = GetCaster(); Unit* target = aurApp->GetTarget(); if (!caster || !caster->IsAlive() || !target->IsAlive() || !caster->CanHaveThreatList()) return; caster->GetThreatManager().TauntUpdate(); } void AuraEffect::HandleAuraModFixate(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* caster = GetCaster(); Unit* target = aurApp->GetTarget(); if (!caster || !caster->IsAlive() || !target->IsAlive() || !caster->CanHaveThreatList()) return; if (apply) caster->GetThreatManager().FixateTarget(target); else caster->GetThreatManager().ClearFixate(); } /*****************************/ /*** CONTROL ***/ /*****************************/ void AuraEffect::HandleModConfuse(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_CONFUSED); if (apply) target->GetThreatManager().EvaluateSuppressed(); } void AuraEffect::HandleModFear(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_FLEEING); } void AuraEffect::HandleAuraModStun(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_STUNNED); if (apply) target->GetThreatManager().EvaluateSuppressed(); } void AuraEffect::HandleAuraModRoot(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_ROOT); } void AuraEffect::HandlePreventFleeing(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); // Since patch 3.0.2 this mechanic no longer affects fear effects. It will ONLY prevent humanoids from fleeing due to low health. if (!apply || target->HasAuraType(SPELL_AURA_MOD_FEAR)) return; /// TODO: find a way to cancel fleeing for assistance. /// Currently this will only stop creatures fleeing due to low health that could not find nearby allies to flee towards. target->SetControlled(false, UNIT_STATE_FLEEING); } static void HandleAuraDisableGravity(Unit* target, bool apply) { // Do not remove DisableGravity if there are more than this auraEffect of that kind on the unit or if it's a creature with DisableGravity on its movement template. if (!apply) if (target->HasAuraType(SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY) || target->HasAuraType(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY) || target->HasAuraType(SPELL_AURA_DISABLE_GRAVITY) || (target->IsCreature() && target->ToCreature()->IsFloating())) return; if (target->SetDisableGravity(apply)) if (!apply && !target->IsFlying()) target->GetMotionMaster()->MoveFall(); } void AuraEffect::HandleAuraModRootAndDisableGravity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_ROOT); ::HandleAuraDisableGravity(target, apply); } void AuraEffect::HandleAuraModStunAndDisableGravity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->SetControlled(apply, UNIT_STATE_STUNNED); if (apply) target->GetThreatManager().EvaluateSuppressed(); ::HandleAuraDisableGravity(target, apply); } void AuraEffect::HandleAuraDisableGravity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); ::HandleAuraDisableGravity(target, apply); } /***************************/ /*** CHARM ***/ /***************************/ void AuraEffect::HandleModPossess(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); Unit* caster = GetCaster(); // no support for posession AI yet if (caster && caster->GetTypeId() == TYPEID_UNIT) { HandleModCharm(aurApp, mode, apply); return; } if (apply) target->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); else target->RemoveCharmedBy(caster); } void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* caster = GetCaster(); if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; // seems it may happen that when removing it is no longer owner's pet //if (caster->ToPlayer()->GetPet() != target) // return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_UNIT || !target->IsPet()) return; Pet* pet = target->ToPet(); if (apply) { if (caster->ToPlayer()->GetPet() != pet) return; pet->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); } else { pet->RemoveCharmedBy(caster); if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityRange())) pet->Remove(PET_SAVE_NOT_IN_SLOT, true); else { // Reinitialize the pet bar or it will appear greyed out caster->ToPlayer()->PetSpellInitialize(); // TODO: remove this if (!pet->GetVictim() && !pet->GetCharmInfo()->HasCommandState(COMMAND_STAY)) pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, pet->GetFollowAngle()); } } } void AuraEffect::HandleModCharm(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); Unit* caster = GetCaster(); if (apply) target->SetCharmedBy(caster, CHARM_TYPE_CHARM, aurApp); else target->RemoveCharmedBy(caster); } void AuraEffect::HandleCharmConvert(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); Unit* caster = GetCaster(); if (apply) target->SetCharmedBy(caster, CHARM_TYPE_CONVERT, aurApp); else target->RemoveCharmedBy(caster); } /** * Such auras are applied from a caster(=player) to a vehicle. * This has been verified using spell #49256 */ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); if (!target->IsVehicle()) return; Unit* caster = GetCaster(); if (!caster || caster == target) return; if (apply) { // Currently spells that have base points 0 and DieSides 0 = "0/0" exception are pushed to -1, // however the idea of 0/0 is to ingore flag VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT and -1 checks for it, // so this break such spells or most of them. // Current formula about m_amount: effect base points + dieside - 1 // TO DO: Reasearch more about 0/0 and fix it. caster->_EnterVehicle(target->GetVehicleKit(), GetAmount() - 1, aurApp); } else { // Remove pending passengers before exiting vehicle - might cause an Uninstall target->GetVehicleKit()->RemovePendingEventsForPassenger(caster); if (GetId() == 53111) // Devour Humanoid { Unit::Kill(target, caster); if (caster->GetTypeId() == TYPEID_UNIT) caster->ToCreature()->DespawnOrUnsummon(); } bool seatChange = (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT) // Seat change on the same direct vehicle || target->HasAuraTypeWithCaster(SPELL_AURA_CONTROL_VEHICLE, caster->GetGUID()); // Seat change to a proxy vehicle (for example turret mounted on a siege engine) if (!seatChange) caster->_ExitVehicle(); else target->GetVehicleKit()->RemovePassenger(caster); // Only remove passenger from vehicle without launching exit movement or despawning the vehicle // some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them caster->RemoveAurasDueToSpell(GetId()); } } /*********************************************************/ /*** MODIFY SPEED ***/ /*********************************************************/ void AuraEffect::HandleAuraModIncreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_RUN); } void AuraEffect::HandleAuraModIncreaseMountedSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const { HandleAuraModIncreaseSpeed(aurApp, mode, apply); } void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) target->UpdateSpeed(MOVE_FLIGHT); //! Update ability to fly if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK && (apply || (!target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !target->HasAuraType(SPELL_AURA_FLY)))) { target->SetCanTransitionBetweenSwimAndFly(apply); if (target->SetCanFly(apply)) if (!apply && !target->IsGravityDisabled()) target->GetMotionMaster()->MoveFall(); } //! Someone should clean up these hacks and remove it from this function. It doesn't even belong here. if (mode & AURA_EFFECT_HANDLE_REAL) { //Players on flying mounts must be immune to polymorph if (target->GetTypeId() == TYPEID_PLAYER) target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); // Dragonmaw Illusion (overwrite mount model, mounted aura already applied) if (apply && target->HasAuraEffect(42016, 0) && target->GetMountDisplayId()) target->SetMountDisplayId(16314); } } } void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_SWIM); } void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_RUN); target->UpdateSpeed(MOVE_SWIM); target->UpdateSpeed(MOVE_FLIGHT); target->UpdateSpeed(MOVE_RUN_BACK); target->UpdateSpeed(MOVE_SWIM_BACK); target->UpdateSpeed(MOVE_FLIGHT_BACK); } void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_RUN); target->UpdateSpeed(MOVE_SWIM); target->UpdateSpeed(MOVE_FLIGHT); } void AuraEffect::HandleAuraModMinimumSpeedRate(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); target->UpdateSpeed(MOVE_RUN); } void AuraEffect::HandleModMovementForceMagnitude(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; aurApp->GetTarget()->UpdateMovementForcesModMagnitude(); } void AuraEffect::HandleAuraModAdvFlyingSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); switch (GetAuraType()) { case SPELL_AURA_MOD_ADV_FLYING_AIR_FRICTION: target->UpdateAdvFlyingSpeed(ADV_FLYING_AIR_FRICTION, true); break; case SPELL_AURA_MOD_ADV_FLYING_MAX_VEL: target->UpdateAdvFlyingSpeed(ADV_FLYING_MAX_VEL, true); break; case SPELL_AURA_MOD_ADV_FLYING_LIFT_COEF: target->UpdateAdvFlyingSpeed(ADV_FLYING_LIFT_COEFFICIENT, true); break; case SPELL_AURA_MOD_ADV_FLYING_ADD_IMPULSE_MAX_SPEED: target->UpdateAdvFlyingSpeed(ADV_FLYING_ADD_IMPULSE_MAX_SPEED, true); break; case SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE: target->UpdateAdvFlyingSpeed(ADV_FLYING_BANKING_RATE, true); break; case SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_DOWN: target->UpdateAdvFlyingSpeed(ADV_FLYING_PITCHING_RATE_DOWN, true); break; case SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP: target->UpdateAdvFlyingSpeed(ADV_FLYING_PITCHING_RATE_UP, true); break; case SPELL_AURA_MOD_ADV_FLYING_OVER_MAX_DECELERATION: target->UpdateAdvFlyingSpeed(ADV_FLYING_OVER_MAX_DECELERATION, true); break; default: break; } } /*********************************************************/ /*** IMMUNITY ***/ /*********************************************************/ void AuraEffect::HandleModMechanicImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); // when removing flag aura, handle flag drop // TODO: this should be handled in aura script for flag spells using AfterEffectRemove hook Player* player = target->ToPlayer(); if (!apply && player && GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::StealthOrInvis)) { if (!player->InBattleground()) sOutdoorPvPMgr->HandleDropFlag(player, GetSpellInfo()->Id); } } void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); // TODO: should be changed to a proc script on flag spell (they have "Taken positive" proc flags in db2) { if (apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL) target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); // remove all flag auras (they are positive, but they must be removed when you are immune) if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT) && GetSpellInfo()->HasAttribute(SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE)) target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } if (apply) { target->SetUnitFlag(UNIT_FLAG_IMMUNE); target->GetThreatManager().EvaluateSuppressed(); } else { // do not remove unit flag if there are more than this auraEffect of that kind on unit if (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_DAMAGE_IMMUNITY)) return; target->RemoveUnitFlag(UNIT_FLAG_IMMUNE); } } void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); if (apply) { target->SetUnitFlag(UNIT_FLAG_IMMUNE); target->GetThreatManager().EvaluateSuppressed(); } else { // do not remove unit flag if there are more than this auraEffect of that kind on unit if (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_SCHOOL_IMMUNITY)) return; target->RemoveUnitFlag(UNIT_FLAG_IMMUNE); } } void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); } /*********************************************************/ /*** MODIFY STATS ***/ /*********************************************************/ /********************************/ /*** RESISTANCE ***/ /********************************/ void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) if (GetMiscValue() & (1 << x)) target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) { //pets only have base armor if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) { if (apply) target->ApplyStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, SPELL_SCHOOL_MASK_NORMAL); target->SetStatPctModifier(UNIT_MOD_ARMOR, BASE_PCT, amount); } } } else { for (uint8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; ++x) { if (GetMiscValue() & (1 << x)) { if (apply) target->ApplyStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_BASE_RESISTANCE_PCT, 1 << x); target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, amount); } } } } } void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) { if (GetMiscValue() & (1 << i)) { float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_RESISTANCE_PCT, 1 << i); if (target->GetPctModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT) == amount) continue; target->SetStatPctModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, amount); } } } void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) { //pets only have base armor if (target->IsPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) target->HandleStatFlatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); } else { for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) if (GetMiscValue() & (1 << i)) target->HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); } } void AuraEffect::HandleModTargetResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; // applied to damage as HandleNoImmediateEffect in Unit::CalcAbsorbResist and Unit::CalcArmorReducedDamage // show armor penetration if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) target->ApplyModTargetPhysicalResistance(GetAmount(), apply); // show as spell penetration only full spell penetration bonuses (all resistances except armor and holy if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_SPELL) == SPELL_SCHOOL_MASK_SPELL) target->ApplyModTargetResistance(GetAmount(), apply); } /********************************/ /*** STAT ***/ /********************************/ void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; if (GetMiscValue() < -2 || GetMiscValue() > 4) { TC_LOG_ERROR("spells.aura.effect", "WARNING: Spell {} effect {} has an unsupported misc value ({}) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue()); return; } Unit* target = aurApp->GetTarget(); int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_STAT, true, GetMiscValue()); if (std::abs(spellGroupVal) >= std::abs(GetAmount())) return; for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { // -1 or -2 is all stats (misc < -2 checked in function beginning) if (GetMiscValue() < 0 || GetMiscValue() == i) { if (spellGroupVal) { target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(spellGroupVal), !apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) target->UpdateStatBuffMod(Stats(i)); } target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) target->UpdateStatBuffMod(Stats(i)); } } } void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (GetMiscValue() < -1 || GetMiscValue() > 4) { TC_LOG_ERROR("spells.aura.effect", "WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); return; } // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) return; for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValue() == i || GetMiscValue() == -1) { if (apply) target->ApplyStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [i](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValue() == i || aurEff->GetMiscValue() == -1) return true; return false; }); target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, amount); } } } } void AuraEffect::HandleModSpellDamagePercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // Magic damage modifiers implemented in Unit::SpellDamageBonus // This information for client side use only // Recalculate bonus target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } void AuraEffect::HandleModSpellHealingPercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // Recalculate bonus target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // implemented in Unit::SpellHealingBonus // this information is for client side only target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } void AuraEffect::HandleModHealingDonePct(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; if (Player* player = aurApp->GetTarget()->ToPlayer()) player->UpdateHealingDonePercentMod(); } void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // save current health state float healthPct = target->GetHealthPct(); bool zeroHealth = !target->IsAlive(); // players in corpse state may mean two different states: /// 1. player just died but did not release (in this case health == 0) /// 2. player is corpse running (ie ghost) (in this case health == 1) if (target->getDeathState() == CORPSE) zeroHealth = (target->GetHealth() == 0); for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValueB() & 1 << i || !GetMiscValueB()) // 0 is also used for all stats { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [i](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValueB() & 1 << i || !aurEff->GetMiscValueB()) return true; return false; }); if (target->GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT) == amount) continue; target->SetStatPctModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, amount); if (target->GetTypeId() == TYPEID_PLAYER || target->IsPet()) target->UpdateStatBuffMod(Stats(i)); } } // recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_ABILITY 0x00000010 flag) // this check is total bullshit i think if ((GetMiscValueB() & 1 << STAT_STAMINA || !GetMiscValueB()) && (m_spellInfo->HasAttribute(SPELL_ATTR0_IS_ABILITY))) target->SetHealth(std::max(CalculatePct(target->GetMaxHealth(), healthPct), (zeroHealth ? 0 : 1))); } void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; target->ToPlayer()->UpdateExpertise(BASE_ATTACK); target->ToPlayer()->UpdateExpertise(OFF_ATTACK); } // Increase armor by % of your void AuraEffect::HandleModArmorPctFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; // only players have primary stats Player* player = aurApp->GetTarget()->ToPlayer(); if (!player) return; player->UpdateArmor(); } void AuraEffect::HandleModBonusArmor(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; aurApp->GetTarget()->HandleStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleModBonusArmorPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; aurApp->GetTarget()->UpdateArmor(); } void AuraEffect::HandleModStatBonusPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (GetMiscValue() < -1 || GetMiscValue() > 4) { TC_LOG_ERROR("spells", "WARNING: Misc Value for SPELL_AURA_MOD_STAT_BONUS_PCT not valid"); return; } // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) return; for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { if (GetMiscValue() == i || GetMiscValue() == -1) { target->HandleStatFlatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT_EXCLUDE_CREATE, float(GetAmount()), apply); target->UpdateStatBuffMod(Stats(i)); } } } void AuraEffect::HandleOverrideSpellPowerByAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; target->ApplyModOverrideSpellPowerByAPPercent(float(GetAmount()), apply); target->UpdateSpellDamageAndHealingBonus(); } void AuraEffect::HandleOverrideAttackPowerBySpellPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; target->ApplyModOverrideAPBySpellPowerPercent(float(GetAmount()), apply); target->UpdateAttackPowerAndDamage(); target->UpdateAttackPowerAndDamage(true); } void AuraEffect::HandleModVersatilityByPct(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; if (Player* target = aurApp->GetTarget()->ToPlayer()) { target->SetVersatilityBonus(target->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY)); target->UpdateHealingDonePercentMod(); target->UpdateVersatilityDamageDone(); } } void AuraEffect::HandleAuraModMaxPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + GetMiscValue()); target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } /********************************/ /*** HEAL & ENERGIZE ***/ /********************************/ void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // Update manaregen value if (GetMiscValue() == POWER_MANA) target->ToPlayer()->UpdateManaRegen(); else if (GetMiscValue() == POWER_RUNES) target->ToPlayer()->UpdateAllRunesRegen(); // other powers are not immediate effects - implemented in Player::Regenerate, Creature::Regenerate } void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const { HandleModPowerRegen(aurApp, mode, apply); } void AuraEffect::HandleModManaRegenPct(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (!target->IsPlayer()) return; target->ToPlayer()->UpdateManaRegen(); } void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); int32 const amt = apply ? GetAmount() : -GetAmount(); if (amt < 0) target->ModifyHealth(std::max(1 - target->GetHealth(), amt)); target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, GetAmount(), apply); if (amt > 0) target->ModifyHealth(amt); } void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); float percent = target->GetHealthPct(); target->HandleStatFlatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); // refresh percentage if (target->GetHealth() > 0) { uint32 newHealth = std::max(target->CountPctFromMaxHealth(int32(percent)), 1); target->SetHealth(newHealth); } } void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + GetMiscValue()); target->HandleStatFlatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); Powers powerType = Powers(GetMiscValue()); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + GetMiscValue()); // Save old powers for further calculation int32 oldPower = target->GetPower(powerType); int32 oldMaxPower = target->GetMaxPower(powerType); // Handle aura effect for max power if (apply) target->ApplyStatPctModifier(unitMod, TOTAL_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, [powerType](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValue() == powerType) return true; return false; }); amount *= target->GetTotalAuraMultiplier(SPELL_AURA_MOD_MAX_POWER_PCT, [powerType](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValue() == powerType) return true; return false; }); target->SetStatPctModifier(unitMod, TOTAL_PCT, amount); } // Calculate the current power change int32 change = target->GetMaxPower(powerType) - oldMaxPower; change = (oldPower + change) - target->GetPower(powerType); target->ModifyPower(powerType, change); } void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // Unit will keep hp% after MaxHealth being modified if unit is alive. float percent = target->GetHealthPct(); if (apply) target->ApplyStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT) * target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT2); target->SetStatPctModifier(UNIT_MOD_HEALTH, TOTAL_PCT, amount); } if (target->GetHealth() > 0) { uint32 newHealth = std::max(CalculatePct(target->GetMaxHealth(), percent), 1); target->SetHealth(newHealth); } } void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (apply) target->ApplyStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_HEALTH_PCT); target->SetStatPctModifier(UNIT_MOD_HEALTH, BASE_PCT, amount); } } void AuraEffect::HandleAuraModIncreaseBaseManaPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (apply) target->ApplyStatPctModifier(UNIT_MOD_MANA, BASE_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_BASE_MANA_PCT); target->SetStatPctModifier(UNIT_MOD_MANA, BASE_PCT, amount); } } void AuraEffect::HandleModManaCostPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; aurApp->GetTarget()->ApplyModManaCostMultiplier(GetAmount() / 100.0f, apply); } void AuraEffect::HandleAuraModPowerDisplay(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK)) return; if (GetMiscValue() >= MAX_POWERS) return; if (apply) aurApp->GetTarget()->RemoveAurasByType(GetAuraType(), ObjectGuid::Empty, GetBase()); aurApp->GetTarget()->UpdateDisplayPower(); } void AuraEffect::HandleAuraModOverridePowerDisplay(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(GetMiscValue()); if (!powerDisplay) return; Unit* target = aurApp->GetTarget(); if (target->GetPowerIndex(Powers(powerDisplay->ActualType)) == MAX_POWERS) return; if (apply) { target->RemoveAurasByType(GetAuraType(), ObjectGuid::Empty, GetBase()); target->SetOverrideDisplayPowerId(powerDisplay->ID); } else target->SetOverrideDisplayPowerId(0); } void AuraEffect::HandleAuraModMaxPowerPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit * target = aurApp->GetTarget(); if (!target->IsPlayer()) return; Powers powerType = Powers(GetMiscValue()); UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + GetMiscValue()); // Save old powers for further calculation int32 oldPower = target->GetPower(powerType); int32 oldMaxPower = target->GetMaxPower(powerType); // Handle aura effect for max power if (apply) target->ApplyStatPctModifier(unitMod, TOTAL_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_MAX_POWER_PCT, [powerType](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValue() == powerType) return true; return false; }); amount *= target->GetTotalAuraMultiplier(SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT, [powerType](AuraEffect const* aurEff) -> bool { if (aurEff->GetMiscValue() == powerType) return true; return false; }); target->SetStatPctModifier(unitMod, TOTAL_PCT, amount); } // Calculate the current power change int32 change = target->GetMaxPower(powerType) - oldMaxPower; change = (oldPower + change) - target->GetPower(powerType); target->ModifyPower(powerType, change); } void AuraEffect::HandleTriggerSpellOnHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL) || !apply) return; Unit* target = aurApp->GetTarget(); int32 thresholdPct = GetAmount(); uint32 triggerSpell = GetSpellEffectInfo().TriggerSpell; switch (AuraTriggerOnHealthChangeDirection(GetMiscValue())) { case AuraTriggerOnHealthChangeDirection::Above: if (!target->HealthAbovePct(thresholdPct)) return; break; case AuraTriggerOnHealthChangeDirection::Below: if (!target->HealthBelowPct(thresholdPct)) return; break; default: break; } target->CastSpell(target, triggerSpell, this); } /********************************/ /*** FIGHT ***/ /********************************/ void AuraEffect::HandleAuraModParryPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; target->ToPlayer()->UpdateParryPercentage(); } void AuraEffect::HandleAuraModDodgePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; target->ToPlayer()->UpdateDodgePercentage(); } void AuraEffect::HandleAuraModBlockPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; target->ToPlayer()->UpdateBlockPercentage(); } void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (!target->IsPlayer()) return; target->ToPlayer()->UpdateManaRegen(); } void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; target->UpdateAllWeaponDependentCritAuras(); } void AuraEffect::HandleModSpellHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateSpellHitChances(); else target->m_modSpellHitChance += (apply) ? GetAmount() : (-GetAmount()); } void AuraEffect::HandleModSpellCritChance(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->UpdateSpellCritChance(); else target->m_baseSpellCritChance += apply ? GetAmount() : -GetAmount(); } void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) { target->m_baseSpellCritChance += apply ? GetAmount() : -GetAmount(); return; } target->ToPlayer()->UpdateAllWeaponDependentCritAuras(); // included in Player::UpdateSpellCritChance calculation target->ToPlayer()->UpdateSpellCritChance(); } /********************************/ /*** ATTACK SPEED ***/ /********************************/ void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // Do not apply such auras in normal way if (GetAmount() >= 1000) { if (apply) target->SetInstantCast(true); else { // only SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK can have this high amount // it's some rare case that you have 2 auras like that, but just in case ;) bool remove = true; Unit::AuraEffectList const& castingSpeedNotStack = target->GetAuraEffectsByType(SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK); for (AuraEffect const* aurEff : castingSpeedNotStack) { if (aurEff != this && aurEff->GetAmount() >= 1000) { remove = false; break; } } if (remove) target->SetInstantCast(false); } return; } int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, GetAuraType()); if (std::abs(spellGroupVal) >= std::abs(GetAmount())) return; if (spellGroupVal) target->ApplyCastTimePercentMod(float(spellGroupVal), !apply); target->ApplyCastTimePercentMod((float)GetAmount(), apply); } void AuraEffect::HandleModMeleeRangedSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply); target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); } void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MELEE_SLOW); if (std::abs(spellGroupVal) >= std::abs(GetAmount())) return; if (spellGroupVal) { target->ApplyCastTimePercentMod(float(spellGroupVal), !apply); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(spellGroupVal), !apply); } target->ApplyCastTimePercentMod(float(GetAmount()), apply); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply); } void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->UpdateDamagePhysical(BASE_ATTACK); } void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); int32 spellGroupVal = target->GetHighestExclusiveSameEffectSpellGroupValue(this, SPELL_AURA_MOD_MELEE_HASTE); if (std::abs(spellGroupVal) >= std::abs(GetAmount())) return; if (spellGroupVal) { target->ApplyAttackTimePercentMod(BASE_ATTACK, float(spellGroupVal), !apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(spellGroupVal), !apply); } target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); } void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; //! ToDo: Haste auras with the same handler _CAN'T_ stack together Unit* target = aurApp->GetTarget(); target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); } /********************************/ /*** COMBAT RATING ***/ /********************************/ void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) if (GetMiscValue() & (1 << rating)) target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply); } void AuraEffect::HandleModRatingPct(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; // Just recalculate ratings for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) if (GetMiscValue() & (1 << rating)) target->ToPlayer()->UpdateRating(CombatRating(rating)); } /********************************/ /*** ATTACK POWER ***/ /********************************/ void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if ((target->GetClassMask() & CLASSMASK_WAND_USERS) != 0) return; target->HandleStatFlatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 if (apply) target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_ATTACK_POWER_PCT); target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, amount); } } void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if ((target->GetClassMask() & CLASSMASK_WAND_USERS) != 0) return; //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 if (apply) target->ApplyStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT); target->SetStatPctModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, amount); } } /********************************/ /*** DAMAGE BONUS ***/ /********************************/ void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) target->UpdateAllDamageDoneMods(); // Magic damage modifiers implemented in Unit::SpellBaseDamageBonusDone // This information for client side use only if (Player* playerTarget = target->ToPlayer()) { for (uint16 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) if (GetMiscValue() & (1 << i)) { if (GetAmount() >= 0) playerTarget->ApplyModDamageDonePos(SpellSchools(i), GetAmount(), apply); else playerTarget->ApplyModDamageDoneNeg(SpellSchools(i), GetAmount(), apply); } if (Guardian* pet = playerTarget->GetGuardianPet()) pet->UpdateAttackPowerAndDamage(); } } void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // also handles spell group stacks if (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) target->UpdateAllDamagePctDoneMods(); if (Player* thisPlayer = target->ToPlayer()) { for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i) { if (GetMiscValue() & (1 << i)) { // only aura type modifying PLAYER_FIELD_MOD_DAMAGE_DONE_PCT float amount = thisPlayer->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, 1 << i); thisPlayer->SetModDamageDonePercent(i, amount); } } } } void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); // also handles spell group stacks target->UpdateDamagePctDoneMods(OFF_ATTACK); } void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; if (Player* player = aurApp->GetTarget()->ToPlayer()) player->HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(GetAmount()), apply); } void AuraEffect::HandleShieldBlockValuePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->ApplyBaseModPctValue(SHIELD_BLOCK_VALUE, float(GetAmount())); else { float amount = target->GetTotalAuraMultiplier(SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT); target->SetBaseModPctValue(SHIELD_BLOCK_VALUE, amount); } } /********************************/ /*** POWER COST ***/ /********************************/ void AuraEffect::HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; // handled in SpellInfo::CalcPowerCost, this is only for client UI if (!(GetMiscValueB() & (1 << POWER_MANA))) return; Unit* target = aurApp->GetTarget(); for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) if (GetMiscValue() & (1 << i)) target->ApplyModManaCostModifier(SpellSchools(i), GetAmount(), apply); } void AuraEffect::HandleArenaPreparation(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) target->SetUnitFlag(UNIT_FLAG_PREPARATION); else { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; target->RemoveUnitFlag(UNIT_FLAG_PREPARATION); } target->ModifyAuraState(AURA_STATE_ARENA_PREPARATION, apply); } void AuraEffect::HandleNoReagentUseAura(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER) return; flag128 mask; Unit::AuraEffectList const& noReagent = target->GetAuraEffectsByType(SPELL_AURA_NO_REAGENT_USE); for (Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i) mask |= (*i)->GetSpellEffectInfo().SpellClassMask; target->ToPlayer()->SetNoRegentCostMask(mask); } /*********************************************************/ /*** OTHERS ***/ /*********************************************************/ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_REAPPLY))) return; Unit* target = aurApp->GetTarget(); Unit* caster = GetCaster(); // pet auras if (target->GetTypeId() == TYPEID_PLAYER && (mode & AURA_EFFECT_HANDLE_REAL)) { if (PetAura const* petSpell = sSpellMgr->GetPetAura(GetId(), GetEffIndex())) { if (apply) target->ToPlayer()->AddPetAura(petSpell); else target->ToPlayer()->RemovePetAura(petSpell); } } if (mode & (AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY)) { // AT APPLY if (apply) { switch (GetId()) { case 1515: // Tame beast // FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness if (caster && target->CanHaveThreatList()) target->GetThreatManager().AddThreat(caster, 10.0f); break; case 13139: // net-o-matic // root to self part of (root_target->charge->root_self sequence if (caster) caster->CastSpell(caster, 13138, this); break; case 34026: // kill command { Unit* pet = target->GetGuardianPet(); if (!pet) break; target->CastSpell(target, 34027, this); // set 3 stacks and 3 charges (to make all auras not disappear at once) Aura* owner_aura = target->GetAura(34027, GetCasterGUID()); Aura* pet_aura = pet->GetAura(58914, GetCasterGUID()); if (owner_aura) { owner_aura->SetStackAmount(owner_aura->GetSpellInfo()->StackAmount); if (pet_aura) { pet_aura->SetCharges(0); pet_aura->SetStackAmount(owner_aura->GetSpellInfo()->StackAmount); } } break; } case 37096: // Blood Elf Illusion { if (caster) { if (caster->GetGender() == GENDER_FEMALE) caster->CastSpell(target, 37095, this); // Blood Elf Disguise else caster->CastSpell(target, 37093, this); } break; } case 39850: // Rocket Blast if (roll_chance_i(20)) // backfire stun target->CastSpell(target, 51581, this); break; case 43873: // Headless Horseman Laugh target->PlayDistanceSound(11965); break; case 46354: // Blood Elf Illusion if (caster) { if (caster->GetGender() == GENDER_FEMALE) caster->CastSpell(target, 46356, this); else caster->CastSpell(target, 46355, this); } break; case 46361: // Reinforced Net if (caster) target->GetMotionMaster()->MoveFall(); break; } } // AT REMOVE else { switch (m_spellInfo->SpellFamilyName) { case SPELLFAMILY_GENERIC: switch (GetId()) { case 43681: // Inactive { if (target->GetTypeId() != TYPEID_PLAYER || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) return; if (target->GetMap()->IsBattleground()) target->ToPlayer()->LeaveBattleground(); break; } case 46308: // Burning Winds cast only at creatures at spawn target->CastSpell(target, 47287, this); break; case 52172: // Coyote Spirit Despawn Aura case 60244: // Blood Parrot Despawn Aura target->CastSpell(nullptr, GetAmount(), this); break; case 91604: // Restricted Flight Area if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) target->CastSpell(target, 58601, this); break; } break; case SPELLFAMILY_DEATHKNIGHT: // Summon Gargoyle (Dismiss Gargoyle at remove) if (GetId() == 61777) target->CastSpell(target, GetAmount(), this); break; default: break; } } } // AT APPLY & REMOVE switch (m_spellInfo->SpellFamilyName) { case SPELLFAMILY_GENERIC: { if (!(mode & AURA_EFFECT_HANDLE_REAL)) break; switch (GetId()) { // Recently Bandaged case 11196: target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); break; // Unstable Power case 24658: { uint32 spellId = 24659; if (apply && caster) { SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId, GetBase()->GetCastDifficulty()); CastSpellExtraArgs args; args.TriggerFlags = TRIGGERED_FULL_MASK; args.OriginalCaster = GetCasterGUID(); args.OriginalCastId = GetBase()->GetCastId(); args.CastDifficulty = GetBase()->GetCastDifficulty(); for (uint32 i = 0; i < spell->StackAmount; ++i) caster->CastSpell(target, spell->Id, args); break; } target->RemoveAurasDueToSpell(spellId); break; } // Restless Strength case 24661: { uint32 spellId = 24662; if (apply && caster) { SpellInfo const* spell = sSpellMgr->AssertSpellInfo(spellId, GetBase()->GetCastDifficulty()); CastSpellExtraArgs args; args.TriggerFlags = TRIGGERED_FULL_MASK; args.OriginalCaster = GetCasterGUID(); args.OriginalCastId = GetBase()->GetCastId(); args.CastDifficulty = GetBase()->GetCastDifficulty(); for (uint32 i = 0; i < spell->StackAmount; ++i) caster->CastSpell(target, spell->Id, args); break; } target->RemoveAurasDueToSpell(spellId); break; } // Tag Murloc case 30877: { // Tag/untag Blacksilt Scout target->SetEntry(apply ? 17654 : 17326); break; } case 57819: // Argent Champion case 57820: // Ebon Champion case 57821: // Champion of the Kirin Tor case 57822: // Wyrmrest Champion { if (!caster || caster->GetTypeId() != TYPEID_PLAYER) break; uint32 FactionID = 0; if (apply) { switch (m_spellInfo->Id) { case 57819: FactionID = 1106; break; // Argent Crusade case 57820: FactionID = 1098; break; // Knights of the Ebon Blade case 57821: FactionID = 1090; break; // Kirin Tor case 57822: FactionID = 1091; break; // The Wyrmrest Accord } } caster->ToPlayer()->SetChampioningFaction(FactionID); break; } // LK Intro VO (1) case 58204: if (target->GetTypeId() == TYPEID_PLAYER) { // Play part 1 if (apply) target->PlayDirectSound(14970, target->ToPlayer()); // continue in 58205 else target->CastSpell(target, 58205, this); } break; // LK Intro VO (2) case 58205: if (target->GetTypeId() == TYPEID_PLAYER) { // Play part 2 if (apply) target->PlayDirectSound(14971, target->ToPlayer()); // Play part 3 else target->PlayDirectSound(14972, target->ToPlayer()); } break; } break; } case SPELLFAMILY_MAGE: { //if (!(mode & AURA_EFFECT_HANDLE_REAL)) //break; break; } case SPELLFAMILY_PRIEST: { //if (!(mode & AURA_EFFECT_HANDLE_REAL)) //break; break; } case SPELLFAMILY_DRUID: { //if (!(mode & AURA_EFFECT_HANDLE_REAL)) //break; break; } case SPELLFAMILY_SHAMAN: { //if (!(mode & AURA_EFFECT_HANDLE_REAL)) //break; break; } case SPELLFAMILY_PALADIN: // if (!(mode & AURA_EFFECT_HANDLE_REAL)) // break; break; case SPELLFAMILY_DEATHKNIGHT: { //if (!(mode & AURA_EFFECT_HANDLE_REAL)) // break; break; } } } void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; if (apply || aurApp->GetRemoveMode() != AURA_REMOVE_BY_DEATH) return; Unit* caster = GetCaster(); if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; Player* plCaster = caster->ToPlayer(); Unit* target = aurApp->GetTarget(); // Item amount if (GetAmount() <= 0) return; if (GetSpellEffectInfo().ItemType == 0) return; // Soul Shard if (GetSpellEffectInfo().ItemType == 6265) { // Soul Shard only from units that grant XP or honor if (!plCaster->isHonorOrXPTarget(target) || (target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->isTappedBy(plCaster))) return; } //Adding items uint32 noSpaceForCount = 0; uint32 count = GetAmount(); ItemPosCountVec dest; InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellEffectInfo().ItemType, count, &noSpaceForCount); if (msg != EQUIP_ERR_OK) { count -= noSpaceForCount; plCaster->SendEquipError(msg, nullptr, nullptr, GetSpellEffectInfo().ItemType); if (count == 0) return; } if (Item* newitem = plCaster->StoreNewItem(dest, GetSpellEffectInfo().ItemType, true)) plCaster->SendNewItem(newitem, count, true, true); } void AuraEffect::HandleBindSight(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); Unit* caster = GetCaster(); if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; caster->ToPlayer()->SetViewpoint(target, apply); } void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); Player* player = target->ToPlayer(); if (!player) return; uint32 factionId = GetMiscValue(); ReputationRank factionRank = ReputationRank(GetAmount()); player->GetReputationMgr().ApplyForceReaction(factionId, factionRank, apply); // stop fighting at apply (if forced rank friendly) or at remove (if real rank friendly) if ((apply && factionRank >= REP_FRIENDLY) || (!apply && player->GetReputationRank(factionId) >= REP_FRIENDLY)) player->StopAttackFaction(factionId); } void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; } if (target->GetCreatureType() == CREATURE_TYPE_BEAST) { if (apply) target->SetDynamicFlag(UNIT_DYNFLAG_SPECIALINFO); else target->RemoveDynamicFlag(UNIT_DYNFLAG_SPECIALINFO); } } void AuraEffect::HandleAuraModFaction(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) { target->SetFaction(GetMiscValue()); if (target->GetTypeId() == TYPEID_PLAYER) target->RemoveUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED); } else { target->RestoreFaction(); if (target->GetTypeId() == TYPEID_PLAYER) target->SetUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED); } } void AuraEffect::HandleLearnSpell(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* player = aurApp->GetTarget()->ToPlayer(); if (!player) return; if (apply) player->LearnSpell(GetMiscValue(), true, 0, true); else player->RemoveSpell(GetMiscValue(), false, false, true); } void AuraEffect::HandleComprehendLanguage(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) target->SetUnitFlag2(UNIT_FLAG2_COMPREHEND_LANG); else { if (target->HasAuraType(GetAuraType())) return; target->RemoveUnitFlag2(UNIT_FLAG2_COMPREHEND_LANG); } } void AuraEffect::HandleModAlternativeDefaultLanguage(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) target->SetUnitFlag3(UNIT_FLAG3_ALTERNATIVE_DEFAULT_LANGUAGE); else { if (target->HasAuraType(GetAuraType())) return; target->RemoveUnitFlag3(UNIT_FLAG3_ALTERNATIVE_DEFAULT_LANGUAGE); } } void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, bool apply) const { Unit* target = aurApp->GetTarget(); uint32 triggeredSpellId = GetSpellEffectInfo().TriggerSpell; SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggeredSpellId, GetBase()->GetCastDifficulty()); if (!triggeredSpellInfo) return; Unit* caster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCaster() : target; if (!caster) return; if (mode & AURA_EFFECT_HANDLE_REAL) { if (apply) { CastSpellExtraArgs args(this); if (GetAmount()) // If amount avalible cast with basepoints (Crypt Fever for example) args.AddSpellMod(SPELLVALUE_BASE_POINT0, GetAmount()); caster->CastSpell(target, triggeredSpellId, args); } else { ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); target->RemoveAura(triggeredSpellId, casterGUID); } } else if (mode & AURA_EFFECT_HANDLE_REAPPLY && apply) { ObjectGuid casterGUID = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? GetCasterGUID() : target->GetGUID(); // change the stack amount to be equal to stack amount of our aura if (Aura* triggeredAura = target->GetAura(triggeredSpellId, casterGUID)) triggeredAura->ModStackAmount(GetBase()->GetStackAmount() - triggeredAura->GetStackAmount()); } } void AuraEffect::HandleTriggerSpellOnPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL) || !apply) return; Unit* target = aurApp->GetTarget(); int32 effectAmount = GetAmount(); uint32 triggerSpell = GetSpellEffectInfo().TriggerSpell; int32 maxPower = target->GetMaxPower(Powers(GetMiscValue())); if (!maxPower) return; float powerAmountPct = GetPctOf(target->GetPower(Powers(GetMiscValue())), maxPower); switch (AuraTriggerOnPowerChangeDirection(GetMiscValueB())) { case AuraTriggerOnPowerChangeDirection::Gain: if (powerAmountPct < effectAmount) return; break; case AuraTriggerOnPowerChangeDirection::Loss: if (powerAmountPct > effectAmount) return; break; default: break; } target->CastSpell(target, triggerSpell, this); } void AuraEffect::HandleTriggerSpellOnPowerAmount(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL) || !apply) return; Unit* target = aurApp->GetTarget(); int32 effectAmount = GetAmount(); uint32 triggerSpell = GetSpellEffectInfo().TriggerSpell; float powerAmount = target->GetPower(Powers(GetMiscValue())); switch (AuraTriggerOnPowerChangeDirection(GetMiscValueB())) { case AuraTriggerOnPowerChangeDirection::Gain: if (powerAmount < effectAmount) return; break; case AuraTriggerOnPowerChangeDirection::Loss: if (powerAmount > effectAmount) return; break; default: break; } target->CastSpell(target, triggerSpell, this); } void AuraEffect::HandleTriggerSpellOnExpire(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL) || apply || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) return; Unit* caster = aurApp->GetTarget(); // MiscValue (Caster): // 0 - Aura target // 1 - Aura caster // 2 - ? Aura target is always TARGET_UNIT_CASTER so we consider the same behavior as MiscValue 1 uint32 casterType = uint32(GetMiscValue()); if (casterType > 0) caster = GetCaster(); if (caster) caster->CastSpell(aurApp->GetTarget(), GetSpellEffectInfo().TriggerSpell, this); } void AuraEffect::HandleAuraOpenStable(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) return; if (apply) target->ToPlayer()->SetStableMaster(target->GetGUID()); // client auto close stable dialog at !apply aura } void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) { target->m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK); target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, GetAmount()); if (Player* playerTarget = target->ToPlayer()) playerTarget->ApplyModFakeInebriation(GetAmount(), true); } else { bool removeDetect = !target->HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE); target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, -GetAmount()); if (Player* playerTarget = target->ToPlayer()) { playerTarget->ApplyModFakeInebriation(GetAmount(), false); if (removeDetect) removeDetect = !playerTarget->GetDrunkValue(); } if (removeDetect) target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); } // call functions which may have additional effects after changing state of unit if (target->IsInWorld()) target->UpdateObjectVisibility(); } void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target || !target->IsInWorld()) return; uint32 overrideId = uint32(GetMiscValue()); if (apply) { target->SetOverrideSpellsId(overrideId); if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) if (uint32 spellId = overrideSpells->Spells[i]) target->AddTemporarySpell(spellId); } else { target->SetOverrideSpellsId(0); if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) if (uint32 spellId = overrideSpells->Spells[i]) target->RemoveTemporarySpell(spellId); } } void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (!target->IsInWorld()) return; uint32 vehicleId = GetMiscValue(); target->RemoveVehicleKit(); if (apply) { if (!target->CreateVehicleKit(vehicleId, 0)) return; } else { if (Creature* creature = target->ToCreature()) if (uint32 originalVehicleId = creature->GetCreatureTemplate()->VehicleId) creature->CreateVehicleKit(originalVehicleId, creature->GetEntry()); } if (target->GetTypeId() != TYPEID_PLAYER) return; if (apply) target->ToPlayer()->SendOnCancelExpectedVehicleRideAura(); } void AuraEffect::HandleSetVignette(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; aurApp->GetTarget()->SetVignette(apply ? GetMiscValue() : 0); } void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->RemovePlayerLocalFlag(PLAYER_LOCAL_FLAG_RELEASE_TIMER); else if (!target->GetMap()->Instanceable()) target->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_RELEASE_TIMER); } void AuraEffect::HandleMastery(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; target->UpdateMastery(); } void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) const { uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (triggerSpellId == 0) { TC_LOG_WARN("spells.aura.effect.nospell", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell {} [EffectIndex: {}] does not have triggered spell.", GetId(), GetEffIndex()); return; } if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) { triggerCaster->CastSpell(target, triggerSpellId, CastSpellExtraArgsInit{ .TriggerFlags = TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_POWER_COST | TRIGGERED_IGNORE_REAGENT_COST), .TriggeringAura = this }); TC_LOG_DEBUG("spells.aura.effect", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell {} Trigger {}", GetId(), triggeredSpellInfo->Id); } } else TC_LOG_ERROR("spells.aura.effect.nospell", "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell {} has non-existent spell {} in EffectTriggered[{}] and is therefore not triggered.", GetId(), triggerSpellId, GetEffIndex()); } void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const { uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (triggerSpellId == 0) { TC_LOG_WARN("spells.aura.effect.nospell", "AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick: Spell {} [EffectIndex: {}] does not have triggered spell.", GetId(), GetEffIndex()); return; } if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { if (Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(m_spellInfo) ? caster : target) { CastSpellExtraArgs args(this); args.SetTriggerFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_POWER_COST | TRIGGERED_IGNORE_REAGENT_COST)); for (std::size_t i = 0; i < triggeredSpellInfo->GetEffects().size(); ++i) args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), GetAmount()); triggerCaster->CastSpell(target, triggerSpellId, args); TC_LOG_DEBUG("spells.aura.effect", "AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick: Spell {} Trigger {}", GetId(), triggeredSpellInfo->Id); } } else TC_LOG_ERROR("spells.aura.effect.nospell","AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick: Spell {} has non-existent spell {} in EffectTriggered[{}] and is therefore not triggered.", GetId(), triggerSpellId, GetEffIndex()); } void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const { if (!target->IsAlive()) return; if (target->IsImmunedToDamage(caster, GetSpellInfo(), &GetSpellEffectInfo())) { SendTickImmune(target, caster); return; } // Consecrate ticks can miss and will not show up in the combat log // dynobj auras must always have a caster if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) && ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE) return; CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1; // ignore negative values (can be result apply spellmods to aura damage uint32 damage = std::max(GetAmount(), 0); // Script Hook For HandlePeriodicDamageAurasTick -- Allow scripts to change the Damage pre class mitigation calculations sScriptMgr->ModifyPeriodicDamageAurasTick(target, caster, damage); switch (GetAuraType()) { case SPELL_AURA_PERIODIC_DAMAGE: { if (caster) damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_GENERIC) { switch (GetId()) { case 70911: // Unbound Plague case 72854: // Unbound Plague case 72855: // Unbound Plague case 72856: // Unbound Plague damage *= uint32(pow(1.25f, int32(_ticksDone))); break; default: break; } } break; } case SPELL_AURA_PERIODIC_WEAPON_PERCENT_DAMAGE: { WeaponAttackType attackType = GetSpellInfo()->GetAttackType(); damage = CalculatePct(caster->CalculateDamage(attackType, false, true), GetAmount()); // Add melee damage bonuses (also check for negative) if (caster) damage = caster->MeleeDamageBonusDone(target, damage, attackType, DOT, GetSpellInfo(), &GetSpellEffectInfo(), GetSpellEffectInfo().Mechanic, GetSpellInfo()->GetSchoolMask(), nullptr, this); damage = target->MeleeDamageBonusTaken(caster, damage, attackType, DOT, GetSpellInfo()); break; } case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: // ceil obtained value, it may happen that 10 ticks for 10% damage may not kill owner damage = uint32(ceil(CalculatePct(target->GetMaxHealth(), damage))); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); break; default: break; } bool crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target); // Calculate armor mitigation if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo())) { uint32 damageReducedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetAttackType(), GetBase()->GetCasterLevel()); cleanDamage.mitigated_damage += damage - damageReducedArmor; damage = damageReducedArmor; } if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS)) { if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || GetSpellInfo()->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)) damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, (caster && !caster->IsControlledByPlayer()) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)); } int32 dmg = damage; if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS) && caster && caster->CanApplyResilience()) Unit::ApplyResilience(target, &dmg); damage = dmg; DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, BASE_ATTACK); Unit::CalcAbsorbResist(damageInfo); damage = damageInfo.GetDamage(); uint32 absorb = damageInfo.GetAbsorb(); uint32 resist = damageInfo.GetResist(); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} attacked {} for {} dmg inflicted by {} absorb is {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), damage, GetId(), absorb); Unit::DealDamageMods(caster, target, damage, &absorb); // Set trigger flag ProcFlagsInit procAttacker = PROC_FLAG_DEAL_HARMFUL_PERIODIC; ProcFlagsInit procVictim = PROC_FLAG_TAKE_HARMFUL_PERIODIC; ProcFlagsHit hitMask = damageInfo.GetHitMask(); if (damage) { hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE; } int32 overkill = damage - target->GetHealth(); if (overkill < 0) overkill = 0; SpellPeriodicAuraLogInfo pInfo(this, damage, dmg, overkill, absorb, resist, 0.0f, crit); Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true); Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); target->SendPeriodicAuraLog(&pInfo); } bool AuraEffect::IsAreaAuraEffect() const { return GetSpellEffectInfo().IsAreaAuraEffect(); } void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const { if (!target->IsAlive()) return; if (target->IsImmunedToDamage(caster, GetSpellInfo(), &GetSpellEffectInfo())) { SendTickImmune(target, caster); return; } // dynobj auras must always have a caster if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) && ASSERT_NOTNULL(caster)->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE) return; CleanDamage cleanDamage = CleanDamage(0, 0, GetSpellInfo()->GetAttackType(), MELEE_HIT_NORMAL); uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1; // ignore negative values (can be result apply spellmods to aura damage uint32 damage = std::max(GetAmount(), 0); if (caster) damage = caster->SpellDamageBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this); damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, DOT); bool crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) damage = Unit::SpellCriticalDamageBonus(caster, m_spellInfo, damage, target); // Calculate armor mitigation if (Unit::IsDamageReducedByArmor(GetSpellInfo()->GetSchoolMask(), GetSpellInfo())) { uint32 damageReducedArmor = Unit::CalcArmorReducedDamage(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetAttackType(), GetBase()->GetCasterLevel()); cleanDamage.mitigated_damage += damage - damageReducedArmor; damage = damageReducedArmor; } if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS)) { if (GetSpellEffectInfo().IsTargetingArea() || GetSpellEffectInfo().IsAreaAuraEffect() || GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) || GetSpellInfo()->HasAttribute(SPELL_ATTR5_TREAT_AS_AREA_EFFECT) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)) damage = target->CalculateAOEAvoidance(damage, m_spellInfo->SchoolMask, (caster && !caster->IsControlledByPlayer()) || GetSpellInfo()->HasAttribute(SPELL_ATTR7_TREAT_AS_NPC_AOE)); } int32 dmg = damage; if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS) && caster && caster->CanApplyResilience()) Unit::ApplyResilience(target, &dmg); damage = dmg; DamageInfo damageInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask(), DOT, GetSpellInfo()->GetAttackType()); Unit::CalcAbsorbResist(damageInfo); uint32 absorb = damageInfo.GetAbsorb(); uint32 resist = damageInfo.GetResist(); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} health leech of {} for {} dmg inflicted by {} abs is {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), damage, GetId(), absorb); Unit::DealDamageMods(caster, target, damage, &absorb); // SendSpellNonMeleeDamageLog expects non-absorbed/non-resisted damage SpellNonMeleeDamage log(caster, target, GetSpellInfo(), GetBase()->GetSpellVisual(), GetSpellInfo()->GetSchoolMask(), GetBase()->GetCastId()); log.damage = damage; log.originalDamage = dmg; log.absorb = absorb; log.resist = resist; log.periodicLog = true; if (crit) log.HitInfo |= SPELL_HIT_TYPE_CRIT; // Set trigger flag ProcFlagsInit procAttacker = PROC_FLAG_DEAL_HARMFUL_PERIODIC; ProcFlagsInit procVictim = PROC_FLAG_TAKE_HARMFUL_PERIODIC; ProcFlagsHit hitMask = damageInfo.GetHitMask(); if (damage) { hitMask |= crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE; } int32 new_damage = Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), false); Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_DAMAGE, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &damageInfo, nullptr); // process caster heal from now on (must be in world) if (!caster || !caster->IsAlive()) return; float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster); uint32 heal = caster->SpellHealingBonusDone(caster, GetSpellInfo(), uint32(new_damage * gainMultiplier), DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this); heal = caster->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT); HealInfo healInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); caster->HealBySpell(healInfo); caster->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); Unit::ProcSkillsAndAuras(caster, caster, PROC_FLAG_DEAL_HELPFUL_PERIODIC, PROC_FLAG_TAKE_HELPFUL_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); caster->SendSpellNonMeleeDamageLog(&log); } void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const { if (!caster || !caster->IsAlive() || !target->IsAlive()) return; if (target->IsImmunedToAuraPeriodicTick(caster, this)) { SendTickImmune(target, caster); return; } uint32 damage = std::max(GetAmount(), 0); // do not kill health donator if (caster->GetHealth() < damage) damage = caster->GetHealth() - 1; if (!damage) return; caster->ModifyHealth(-(int32)damage); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: donator {} target {} damage {}.", caster->GetEntry(), target->GetEntry(), damage); float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster); damage = int32(damage * gainMultiplier); HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); caster->HealBySpell(healInfo); Unit::ProcSkillsAndAuras(caster, target, PROC_FLAG_DEAL_HARMFUL_PERIODIC, PROC_FLAG_TAKE_HARMFUL_PERIODIC, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, PROC_HIT_NORMAL, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const { if (!target->IsAlive()) return; if (target->IsImmunedToAuraPeriodicTick(caster, this)) { SendTickImmune(target, caster); return; } // don't regen when permanent aura target has full power if (GetBase()->IsPermanent() && target->IsFullHealth()) return; uint32 stackAmountForBonuses = !GetSpellEffectInfo().EffectAttributes.HasFlag(SpellEffectAttributes::SuppressPointsStacking) ? GetBase()->GetStackAmount() : 1; // ignore negative values (can be result apply spellmods to aura damage uint32 damage = std::max(GetAmount(), 0); if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) damage = uint32(target->CountPctFromMaxHealth(damage)); else if (caster) damage = caster->SpellHealingBonusDone(target, GetSpellInfo(), damage, DOT, GetSpellEffectInfo(), stackAmountForBonuses, nullptr, this); damage = target->SpellHealingBonusTaken(caster, GetSpellInfo(), damage, DOT); bool crit = roll_chance_f(GetCritChanceFor(caster, target)); if (crit) damage = Unit::SpellCriticalHealingBonus(caster, m_spellInfo, damage, target); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} heal of {} for {} health inflicted by {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), damage, GetId()); uint32 heal = damage; HealInfo healInfo(caster, target, damage, GetSpellInfo(), GetSpellInfo()->GetSchoolMask()); Unit::CalcHealAbsorb(healInfo); Unit::DealHeal(healInfo); SpellPeriodicAuraLogInfo pInfo(this, heal, damage, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); target->SendPeriodicAuraLog(&pInfo); if (caster) target->GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); // %-based heal - does not proc auras if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) return; ProcFlagsInit procAttacker = PROC_FLAG_DEAL_HELPFUL_PERIODIC; ProcFlagsInit procVictim = PROC_FLAG_TAKE_HELPFUL_PERIODIC; ProcFlagsHit hitMask = crit ? PROC_HIT_CRITICAL : PROC_HIT_NORMAL; // ignore item heals if (GetBase()->GetCastItemGUID().IsEmpty()) Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, PROC_SPELL_TYPE_HEAL, PROC_SPELL_PHASE_HIT, hitMask, nullptr, nullptr, &healInfo); } void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const { Powers powerType = Powers(GetMiscValue()); if (!caster || !caster->IsAlive() || !target->IsAlive() || target->GetPowerType() != powerType) return; if (target->IsImmunedToAuraPeriodicTick(caster, this)) { SendTickImmune(target, caster); return; } if (GetSpellEffectInfo().IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA) && caster->SpellHitResult(target, GetSpellInfo(), false, true) != SPELL_MISS_NONE) return; // ignore negative values (can be result apply spellmods to aura damage int32 drainAmount = std::max(GetAmount(), 0); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} power leech of {} for {} dmg inflicted by {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), drainAmount, GetId()); int32 drainedAmount = -target->ModifyPower(powerType, -drainAmount); float gainMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster); SpellPeriodicAuraLogInfo pInfo(this, drainedAmount, drainAmount, 0, 0, 0, gainMultiplier, false); int32 gainAmount = int32(drainedAmount * gainMultiplier); int32 gainedAmount = 0; if (gainAmount) { gainedAmount = caster->ModifyPower(powerType, gainAmount); // energize is not modified by threat modifiers if (!GetSpellInfo()->HasAttribute(SPELL_ATTR4_NO_HELPFUL_THREAT)) target->GetThreatManager().AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellInfo(), true); } // Drain Mana - Mana Feed effect if (caster->GetGuardianPet() && m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags[0] & 0x00000010) { int32 manaFeedVal = 0; if (AuraEffect const* aurEff = GetBase()->GetEffect(EFFECT_1)) manaFeedVal = aurEff->GetAmount(); if (manaFeedVal > 0) { int32 feedAmount = CalculatePct(gainedAmount, manaFeedVal); CastSpellExtraArgs args(this); args.AddSpellMod(SPELLVALUE_BASE_POINT0, feedAmount); caster->CastSpell(caster, 32554, args); } } target->SendPeriodicAuraLog(&pInfo); } void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const { Powers powerType; if (GetMiscValue() == POWER_ALL) powerType = target->GetPowerType(); else powerType = Powers(GetMiscValue()); if (!target->IsAlive() || !target->GetMaxPower(powerType)) return; if (target->IsImmunedToAuraPeriodicTick(caster, this)) { SendTickImmune(target, caster); return; } // don't regen when permanent aura and limit is already reached if (GetBase()->IsPermanent()) { if (GetAmount() >= 0) { if (target->GetPower(powerType) >= target->GetMaxPower(powerType)) return; } else if (target->GetPower(powerType) <= target->GetMinPower(powerType)) return; } int32 amount = GetAmount() * target->GetMaxPower(powerType) / 100; TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} energize {} for {} dmg inflicted by {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), amount, GetId()); SpellPeriodicAuraLogInfo pInfo(this, amount, amount, 0, 0, 0, 0.0f, false); int32 gain = target->ModifyPower(powerType, amount); if (caster) target->GetThreatManager().ForwardThreatForAssistingMe(caster, std::abs(float(gain) * 0.5f), GetSpellInfo(), true); target->SendPeriodicAuraLog(&pInfo); } void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) const { Powers powerType = Powers(GetMiscValue()); if (!target->IsAlive() || !target->GetMaxPower(powerType)) return; if (target->IsImmunedToAuraPeriodicTick(caster, this)) { SendTickImmune(target, caster); return; } // don't regen when permanent aura target has full power if (GetBase()->IsPermanent() && target->GetPower(powerType) == target->GetMaxPower(powerType)) return; // ignore negative values (can be result apply spellmods to aura damage int32 amount = std::max(GetAmount(), 0); SpellPeriodicAuraLogInfo pInfo(this, amount, amount, 0, 0, 0, 0.0f, false); TC_LOG_DEBUG("spells.aura.effect", "PeriodicTick: {} energize {} for {} dmg inflicted by {}", GetCasterGUID().ToString(), target->GetGUID().ToString(), amount, GetId()); int32 gain = target->ModifyPower(powerType, amount); target->SendPeriodicAuraLog(&pInfo); if (caster) target->GetThreatManager().ForwardThreatForAssistingMe(caster, float(gain)*0.5f, GetSpellInfo(), true); } void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const { Powers powerType = Powers(GetMiscValue()); if (!caster || !target->IsAlive() || target->GetPowerType() != powerType) return; if (target->IsImmunedToDamage(caster, GetSpellInfo(), &GetSpellEffectInfo())) { SendTickImmune(target, caster); return; } // ignore negative values (can be result apply spellmods to aura damage int32 damage = std::max(GetAmount(), 0); uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); float dmgMultiplier = GetSpellEffectInfo().CalcValueMultiplier(caster); SpellInfo const* spellProto = GetSpellInfo(); // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG SpellNonMeleeDamage damageInfo(caster, target, spellProto, GetBase()->GetSpellVisual(), spellProto->SchoolMask, GetBase()->GetCastId()); damageInfo.periodicLog = true; // no SpellDamageBonus for burn mana caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb); // Set trigger flag ProcFlagsInit procAttacker = PROC_FLAG_DEAL_HARMFUL_PERIODIC; ProcFlagsInit procVictim = PROC_FLAG_TAKE_HARMFUL_PERIODIC; ProcFlagsHit hitMask = createProcHitMask(&damageInfo, SPELL_MISS_NONE); ProcFlagsSpellType spellTypeMask = PROC_SPELL_TYPE_NO_DMG_HEAL; if (damageInfo.damage) { procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE; spellTypeMask |= PROC_SPELL_TYPE_DAMAGE; } caster->DealSpellDamage(&damageInfo, true); DamageInfo dotDamageInfo(damageInfo, DOT, BASE_ATTACK, hitMask); Unit::ProcSkillsAndAuras(caster, target, procAttacker, procVictim, spellTypeMask, PROC_SPELL_PHASE_HIT, hitMask, nullptr, &dotDamageInfo, nullptr); caster->SendSpellNonMeleeDamageLog(&damageInfo); } float AuraEffect::CalcPeriodicCritChance(Unit const* caster) const { if (!caster || !GetBase()->CanPeriodicTickCrit()) return 0.0f; Player* modOwner = caster->GetSpellModOwner(); if (!modOwner) return 0.0f; float critChance = modOwner->SpellCritChanceDone(nullptr, this, GetSpellInfo()->GetSchoolMask(), GetSpellInfo()->GetAttackType()); return std::max(0.0f, critChance); } void AuraEffect::HandleBreakableCCAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { int32 const damageLeft = GetAmount() - static_cast(eventInfo.GetDamageInfo()->GetDamage()); if (damageLeft <= 0) aurApp->GetTarget()->RemoveAura(aurApp); else ChangeAmount(damageLeft); } void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { Unit* triggerCaster = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) triggerTarget = eventInfo.GetActor(); uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (triggerSpellId == 0) { TC_LOG_WARN("spells.aura.effect.nospell", "AuraEffect::HandleProcTriggerSpellAuraProc: Spell {} [EffectIndex: {}] does not have triggered spell.", GetId(), GetEffIndex()); return; } if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { TC_LOG_DEBUG("spells.aura.effect", "AuraEffect::HandleProcTriggerSpellAuraProc: Triggering spell {} from aura {} proc", triggeredSpellInfo->Id, GetId()); triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo->Id, CastSpellExtraArgs(this) .SetTriggeringSpell(eventInfo.GetProcSpell()) .SetTriggerFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_POWER_COST | TRIGGERED_IGNORE_REAGENT_COST))); } else if (triggerSpellId && GetAuraType() != SPELL_AURA_DUMMY) TC_LOG_ERROR("spells.aura.effect.nospell","AuraEffect::HandleProcTriggerSpellAuraProc: Spell {} has non-existent spell {} in EffectTriggered[{}] and is therefore not triggered.", GetId(), triggerSpellId, GetEffIndex()); } void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { Unit* triggerCaster = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) triggerTarget = eventInfo.GetActor(); uint32 triggerSpellId = GetSpellEffectInfo().TriggerSpell; if (triggerSpellId == 0) { TC_LOG_WARN("spells.aura.effect.nospell", "AuraEffect::HandleProcTriggerSpellAuraProc: Spell {} [EffectIndex: {}] does not have triggered spell.", GetId(), GetEffIndex()); return; } if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId, GetBase()->GetCastDifficulty())) { CastSpellExtraArgs args(this); args.SetTriggerFlags(TRIGGERED_FULL_MASK & ~(TRIGGERED_IGNORE_POWER_COST | TRIGGERED_IGNORE_REAGENT_COST)); args.SetTriggeringSpell(eventInfo.GetProcSpell()); args.AddSpellMod(SPELLVALUE_BASE_POINT0, GetAmount()); triggerCaster->CastSpell(triggerTarget, triggerSpellId, args); TC_LOG_DEBUG("spells.aura.effect", "AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Triggering spell {} with value {} from aura {} proc", triggeredSpellInfo->Id, GetAmount(), GetId()); } else TC_LOG_ERROR("spells.aura.effect.nospell","AuraEffect::HandleProcTriggerSpellWithValueAuraProc: Spell {} has non-existent spell {} in EffectTriggered[{}] and is therefore not triggered.", GetId(), triggerSpellId, GetEffIndex()); } void AuraEffect::HandleProcTriggerDamageAuraProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { Unit* target = aurApp->GetTarget(); Unit* triggerTarget = eventInfo.GetProcTarget(); if (triggerTarget->IsImmunedToDamage(target, GetSpellInfo(), &GetSpellEffectInfo())) { SendTickImmune(triggerTarget, target); return; } SpellNonMeleeDamage damageInfo(target, triggerTarget, GetSpellInfo(), GetBase()->GetSpellVisual(), GetSpellInfo()->SchoolMask, GetBase()->GetCastId()); uint32 damage = target->SpellDamageBonusDone(triggerTarget, GetSpellInfo(), GetAmount(), SPELL_DIRECT_DAMAGE, GetSpellEffectInfo(), 1, nullptr, this); damage = triggerTarget->SpellDamageBonusTaken(target, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); target->CalculateSpellDamageTaken(&damageInfo, damage, GetSpellInfo()); Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb); TC_LOG_DEBUG("spells.aura.effect", "AuraEffect::HandleProcTriggerDamageAuraProc: Triggering {} spell damage from aura {} proc", damage, GetId()); target->DealSpellDamage(&damageInfo, true); target->SendSpellNonMeleeDamageLog(&damageInfo); } void AuraEffect::HandleAuraForceWeather(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->SendDirectMessage(WorldPackets::Misc::Weather(WeatherState(GetMiscValue()), 1.0f).Write()); else target->GetMap()->SendZoneWeather(target->GetZoneId(), target); } void AuraEffect::HandleEnableAltPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; uint32 altPowerId = GetMiscValue(); UnitPowerBarEntry const* powerEntry = sUnitPowerBarStore.LookupEntry(altPowerId); if (!powerEntry) return; if (apply) aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, powerEntry->MaxPower); else aurApp->GetTarget()->SetMaxPower(POWER_ALTERNATE_POWER, 0); } void AuraEffect::HandleModSpellCategoryCooldown(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->AddSpellCategoryCooldownMod(GetMiscValue(), GetAmount()); else target->RemoveSpellCategoryCooldownMod(GetMiscValue(), GetAmount()); } void AuraEffect::HandleModRecoveryRate(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; float rate = 100.0f / (std::max(GetAmount(), -99.0f) + 100.0f); aurApp->GetTarget()->GetSpellHistory()->UpdateCooldownRecoveryRate([&](SpellHistory::CooldownEntry const& cooldown) { return IsAffectingSpell(sSpellMgr->GetSpellInfo(cooldown.SpellId, DIFFICULTY_NONE)); }, rate, apply); } void AuraEffect::HandleModRecoveryRateBySpellLabel(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; float rate = 100.0f / (std::max(GetAmount(), -99.0f) + 100.0f); aurApp->GetTarget()->GetSpellHistory()->UpdateCooldownRecoveryRate([&](SpellHistory::CooldownEntry const& cooldown) { SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(cooldown.SpellId, DIFFICULTY_NONE); return spellInfo->HasLabel(GetMiscValue()) || (GetMiscValueB() && spellInfo->HasLabel(GetMiscValueB())); }, rate, apply); } void AuraEffect::HandleModChargeRecoveryRate(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; float rate = 100.0f / (std::max(GetAmount(), -99.0f) + 100.0f); aurApp->GetTarget()->GetSpellHistory()->UpdateChargeRecoveryRate(GetMiscValue(), rate, apply); } void AuraEffect::HandleShowConfirmationPrompt(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* player = aurApp->GetTarget()->ToPlayer(); if (!player) return; if (apply) player->AddTemporarySpell(GetSpellEffectInfo().TriggerSpell); else player->RemoveTemporarySpell(GetSpellEffectInfo().TriggerSpell); } void AuraEffect::HandleOverridePetSpecs(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* player = aurApp->GetTarget()->ToPlayer(); if (!player) return; if (player->GetClass() != CLASS_HUNTER) return; Pet* pet = player->GetPet(); if (!pet) return; ChrSpecializationEntry const* currSpec = sChrSpecializationStore.LookupEntry(pet->GetSpecialization()); if (!currSpec) return; pet->SetSpecialization(sDB2Manager.GetChrSpecializationByIndex(apply ? PET_SPEC_OVERRIDE_CLASS_INDEX : 0, currSpec->OrderIndex)->ID); } void AuraEffect::HandleAllowUsingGameobjectsWhileMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED); else if (!target->HasAuraType(SPELL_AURA_ALLOW_USING_GAMEOBJECTS_WHILE_MOUNTED)) target->RemovePlayerLocalFlag(PLAYER_LOCAL_FLAG_CAN_USE_OBJECTS_MOUNTED); } void AuraEffect::HandlePlayScene(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* player = aurApp->GetTarget()->ToPlayer(); if (!player) return; if (apply) player->GetSceneMgr().PlayScene(GetMiscValue()); else { if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) { if (Optional sceneInstanceId = player->GetSceneMgr().GetInstanceIdBySceneId(GetMiscValue())) player->GetSceneMgr().OnSceneComplete(*sceneInstanceId); } player->GetSceneMgr().CancelSceneBySceneId(GetMiscValue()); } } void AuraEffect::HandleCreateAreaTrigger(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); if (apply) { AreaTriggerCreatePropertiesId createPropertiesId = { uint32(GetMiscValue()), false }; AreaTrigger::CreateAreaTrigger(createPropertiesId, *target, GetBase()->GetDuration(), GetCaster(), target, GetBase()->GetSpellVisual(), GetSpellInfo(), nullptr, this); } else { if (Unit* caster = GetCaster()) caster->RemoveAreaTrigger(this); } } void AuraEffect::HandleAuraPvpTalents(AuraApplication const* auraApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; if (Player* target = auraApp->GetTarget()->ToPlayer()) { if (apply) target->TogglePvpTalents(true); else if (!target->HasAuraType(SPELL_AURA_PVP_TALENTS)) target->TogglePvpTalents(false); } } void AuraEffect::HandleLinkedSummon(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(GetSpellEffectInfo().TriggerSpell, GetBase()->GetCastDifficulty()); if (!triggerSpellInfo) return; // on apply cast summon spell if (apply) { CastSpellExtraArgs args(this); args.CastDifficulty = triggerSpellInfo->Difficulty; target->CastSpell(target, triggerSpellInfo->Id, args); } // on unapply we need to search for and remove the summoned creature else { std::vector summonedEntries; for (SpellEffectInfo const& spellEffect : triggerSpellInfo->GetEffects()) if (spellEffect.IsEffect(SPELL_EFFECT_SUMMON)) if (uint32 summonEntry = spellEffect.MiscValue) summonedEntries.push_back(summonEntry); // we don't know if there can be multiple summons for the same effect, so consider only 1 summon for each effect // most of the spells have multiple effects with the same summon spell id for multiple spawns, so right now it's safe to assume there's only 1 spawn per effect for (uint32 summonEntry : summonedEntries) { std::list nearbyEntries; target->GetCreatureListWithEntryInGrid(nearbyEntries, summonEntry); for (auto creature : nearbyEntries) { if (creature->GetOwnerGUID() == target->GetGUID()) { creature->DespawnOrUnsummon(); break; } else if (TempSummon* tempSummon = creature->ToTempSummon()) { if (tempSummon->GetSummonerGUID() == target->GetGUID()) { tempSummon->DespawnOrUnsummon(); break; } } } } } } void AuraEffect::HandleSetFFAPvP(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; target->UpdatePvPState(true); } void AuraEffect::HandleModOverrideZonePVPType(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (apply) target->SetOverrideZonePVPType(ZonePVPTypeOverride(GetMiscValue())); else if (target->HasAuraType(SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE)) target->SetOverrideZonePVPType(ZonePVPTypeOverride(target->GetAuraEffectsByType(SPELL_AURA_MOD_OVERRIDE_ZONE_PVP_TYPE).front()->GetMiscValue())); else target->SetOverrideZonePVPType(ZonePVPTypeOverride::None); target->UpdateHostileAreaState(sAreaTableStore.LookupEntry(target->GetZoneId())); target->UpdatePvPState(); } void AuraEffect::HandleBattlegroundPlayerPosition(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* target = aurApp->GetTarget()->ToPlayer(); if (!target) return; if (!apply && aurApp->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT) { if (GetCasterGUID().IsGameObject()) { if (GameObjectTemplate const* gobTemplate = sObjectMgr->GetGameObjectTemplate(GetCasterGUID().GetEntry())) { if (gobTemplate->type == GAMEOBJECT_TYPE_NEW_FLAG) { if (GameObject* gameObjectCaster = target->GetMap()->GetGameObject(GetCasterGUID())) { gameObjectCaster->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Dropped, target)); if (GameObject* droppedFlag = gameObjectCaster->SummonGameObject(gameObjectCaster->GetGOInfo()->newflag.FlagDrop, target->GetPosition(), QuaternionData::fromEulerAnglesZYX(target->GetOrientation(), 0.f, 0.f), Seconds(gameObjectCaster->GetGOInfo()->newflag.ExpireDuration / 1000), GO_SUMMON_TIMED_DESPAWN)) droppedFlag->SetOwnerGUID(gameObjectCaster->GetGUID()); } } else if (gobTemplate->type == GAMEOBJECT_TYPE_FLAGSTAND) { if (ZoneScript* zonescript = target->FindZoneScript()) zonescript->OnFlagDropped(GetCasterGUID(), target); } } } } BattlegroundMap* battlegroundMap = target->GetMap()->ToBattlegroundMap(); if (!battlegroundMap) return; Battleground* bg = battlegroundMap->GetBG(); if (!bg) return; if (apply) { WorldPackets::Battleground::BattlegroundPlayerPosition playerPosition; playerPosition.Guid = target->GetGUID(); playerPosition.ArenaSlot = static_cast(GetMiscValue()); playerPosition.Pos = target->GetPosition(); if (GetAuraType() == SPELL_AURA_BATTLEGROUND_PLAYER_POSITION_FACTIONAL) playerPosition.IconID = target->GetEffectiveTeam() == ALLIANCE ? PLAYER_POSITION_ICON_HORDE_FLAG : PLAYER_POSITION_ICON_ALLIANCE_FLAG; else if (GetAuraType() == SPELL_AURA_BATTLEGROUND_PLAYER_POSITION) playerPosition.IconID = target->GetEffectiveTeam() == ALLIANCE ? PLAYER_POSITION_ICON_ALLIANCE_FLAG : PLAYER_POSITION_ICON_HORDE_FLAG; else TC_LOG_WARN("spell.auras", "Unknown aura effect {} handled by HandleBattlegroundPlayerPosition.", GetAuraType()); bg->AddPlayerPosition(playerPosition); } else bg->RemovePlayerPosition(target->GetGUID()); } void AuraEffect::HandleStoreTeleportReturnPoint(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* playerTarget = aurApp->GetTarget()->ToPlayer(); if (!playerTarget) return; if (apply) playerTarget->AddStoredAuraTeleportLocation(GetSpellInfo()->Id); else if (!playerTarget->GetSession()->isLogingOut()) playerTarget->RemoveStoredAuraTeleportLocation(GetSpellInfo()->Id); } void AuraEffect::HandleMountRestrictions(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; aurApp->GetTarget()->UpdateMountCapability(); } void AuraEffect::HandleCosmeticMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; if (apply) aurApp->GetTarget()->SetCosmeticMountDisplayId(GetMiscValue()); else aurApp->GetTarget()->SetCosmeticMountDisplayId(0); // set cosmetic mount to 0, even if multiple auras are active; tested with zandalari racial + divine steed Player* playerTarget = aurApp->GetTarget()->ToPlayer(); if (!playerTarget) return; playerTarget->SendMovementSetCollisionHeight(playerTarget->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Force); } void AuraEffect::HandleModRequiredMountCapabilityFlags(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* playerTarget = aurApp->GetTarget()->ToPlayer(); if (!playerTarget) return; if (apply) playerTarget->SetRequiredMountCapabilityFlag(GetMiscValue()); else { int32 mountCapabilityFlags = 0; for (AuraEffect* otherAura : playerTarget->GetAuraEffectsByType(GetAuraType())) mountCapabilityFlags |= otherAura->GetMiscValue(); playerTarget->ReplaceAllRequiredMountCapabilityFlags(mountCapabilityFlags); } } void AuraEffect::HandleSuppressItemPassiveEffectBySpellLabel(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; std::vector suppressedAuras; for (Unit::AuraMap::value_type const& appliedAura : aurApp->GetTarget()->GetOwnedAuras()) if (appliedAura.second->GetSpellInfo()->HasLabel(GetMiscValue())) suppressedAuras.push_back(appliedAura.second); // Refresh applications for (Aura* aura : suppressedAuras) aura->ApplyForTargets(); } void AuraEffect::HandleForceBreathBar(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Player* playerTarget = aurApp->GetTarget()->ToPlayer(); if (!playerTarget) return; playerTarget->UpdatePositionData(); } void AuraEffect::HandleAuraActAsControlZone(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* auraOwner = aurApp->GetTarget(); if (!apply) { auraOwner->RemoveGameObject(GetSpellInfo()->Id, true); return; } GameObjectTemplate const* gameobjectTemplate = sObjectMgr->GetGameObjectTemplate(GetMiscValue()); if (!gameobjectTemplate) { TC_LOG_WARN("spells.aura.effect", "AuraEffect::HanldeAuraActAsControlZone: Spell {} [EffectIndex: {}] does not have an existing gameobject template.", GetId(), GetEffIndex()); return; } if (gameobjectTemplate->type != GAMEOBJECT_TYPE_CONTROL_ZONE) { TC_LOG_WARN("spells.aura.effect", "AuraEffect::HanldeAuraActAsControlZone: Spell {} [EffectIndex: {}] has a gameobject template ({}) that is not a control zone.", GetId(), GetEffIndex(), gameobjectTemplate->entry); return; } if (gameobjectTemplate->displayId) { TC_LOG_WARN("spell.aura.effect", "AuraEffect::HanldeAuraActAsControlZone: Spell {} [EffectIndex: {}] has a gameobject template ({}) that has a display id. Only invisible gameobjects are supported.", GetId(), GetEffIndex(), gameobjectTemplate->entry); return; } if (GameObject* controlZone = auraOwner->SummonGameObject(gameobjectTemplate->entry, auraOwner->GetPosition(), QuaternionData::fromEulerAnglesZYX(aurApp->GetTarget()->GetOrientation(), 0.f, 0.f), 24h, GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)) controlZone->SetSpellId(GetSpellInfo()->Id); } template TC_GAME_API void AuraEffect::GetTargetList(std::list&) const; template TC_GAME_API void AuraEffect::GetTargetList(std::deque&) const; template TC_GAME_API void AuraEffect::GetTargetList(std::vector&) const; template TC_GAME_API void AuraEffect::GetApplicationList(std::list&) const; template TC_GAME_API void AuraEffect::GetApplicationList(std::deque&) const; template TC_GAME_API void AuraEffect::GetApplicationList(std::vector&) const;