server/src/game/SpellAuras.cpp
VladimirMangos c686697c2d [11623] Implement ClassFamilyMask as wrapper for uint64+uint32 spell family masks
Inspired by patch suggested by darkstalker

Also
* Remove existed enums for family masks as contra-productive for developement.
* Drop one from horrible hack checks in SpellMgr::IsNoStackSpellDueToSpell
  (spells for any fimilies with exactly 0x800 mask) I fail find useful cases
  for current spell data with this check. All cases expected work correct without it.
  If will some problems detected with this please report for fix in less strange way.
2011-06-11 21:20:42 +04:00

9684 lines
399 KiB
C++

/*
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Opcodes.h"
#include "Log.h"
#include "UpdateMask.h"
#include "World.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
#include "DynamicObject.h"
#include "Group.h"
#include "UpdateData.h"
#include "ObjectAccessor.h"
#include "Policies/SingletonImp.h"
#include "Totem.h"
#include "Creature.h"
#include "Formulas.h"
#include "BattleGround.h"
#include "CreatureAI.h"
#include "ScriptMgr.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Vehicle.h"
#include "CellImpl.h"
#define NULL_AURA_SLOT 0xFF
pAuraHandler AuraHandler[TOTAL_AURAS]=
{
&Aura::HandleNULL, // 0 SPELL_AURA_NONE
&Aura::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT
&Aura::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS
&Aura::HandlePeriodicDamage, // 3 SPELL_AURA_PERIODIC_DAMAGE
&Aura::HandleAuraDummy, // 4 SPELL_AURA_DUMMY
&Aura::HandleModConfuse, // 5 SPELL_AURA_MOD_CONFUSE
&Aura::HandleModCharm, // 6 SPELL_AURA_MOD_CHARM
&Aura::HandleModFear, // 7 SPELL_AURA_MOD_FEAR
&Aura::HandlePeriodicHeal, // 8 SPELL_AURA_PERIODIC_HEAL
&Aura::HandleModAttackSpeed, // 9 SPELL_AURA_MOD_ATTACKSPEED
&Aura::HandleModThreat, // 10 SPELL_AURA_MOD_THREAT
&Aura::HandleModTaunt, // 11 SPELL_AURA_MOD_TAUNT
&Aura::HandleAuraModStun, // 12 SPELL_AURA_MOD_STUN
&Aura::HandleModDamageDone, // 13 SPELL_AURA_MOD_DAMAGE_DONE
&Aura::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonusTaken and Unit::SpellBaseDamageBonusTaken
&Aura::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DealMeleeDamage
&Aura::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
&Aura::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_STEALTH_DETECT implemented in Unit::isVisibleForOrDetect
&Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
&Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
&Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH
&Aura::HandleAuraModTotalManaPercentRegen, // 21 SPELL_AURA_OBS_MOD_MANA
&Aura::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
&Aura::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
&Aura::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE
&Aura::HandleAuraModPacify, // 25 SPELL_AURA_MOD_PACIFY
&Aura::HandleAuraModRoot, // 26 SPELL_AURA_MOD_ROOT
&Aura::HandleAuraModSilence, // 27 SPELL_AURA_MOD_SILENCE
&Aura::HandleNoImmediateEffect, // 28 SPELL_AURA_REFLECT_SPELLS implement in Unit::SpellHitResult
&Aura::HandleAuraModStat, // 29 SPELL_AURA_MOD_STAT
&Aura::HandleAuraModSkill, // 30 SPELL_AURA_MOD_SKILL
&Aura::HandleAuraModIncreaseSpeed, // 31 SPELL_AURA_MOD_INCREASE_SPEED
&Aura::HandleAuraModIncreaseMountedSpeed, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
&Aura::HandleAuraModDecreaseSpeed, // 33 SPELL_AURA_MOD_DECREASE_SPEED
&Aura::HandleAuraModIncreaseHealth, // 34 SPELL_AURA_MOD_INCREASE_HEALTH
&Aura::HandleAuraModIncreaseEnergy, // 35 SPELL_AURA_MOD_INCREASE_ENERGY
&Aura::HandleAuraModShapeshift, // 36 SPELL_AURA_MOD_SHAPESHIFT
&Aura::HandleAuraModEffectImmunity, // 37 SPELL_AURA_EFFECT_IMMUNITY
&Aura::HandleAuraModStateImmunity, // 38 SPELL_AURA_STATE_IMMUNITY
&Aura::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
&Aura::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
&Aura::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
&Aura::HandleAuraProcTriggerSpell, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
&Aura::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
&Aura::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
&Aura::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
&Aura::HandleUnused, // 46 SPELL_AURA_46 (used in test spells 54054 and 54058, and spell 48050) (3.0.8a-3.2.2a)
&Aura::HandleAuraModParryPercent, // 47 SPELL_AURA_MOD_PARRY_PERCENT
&Aura::HandleNULL, // 48 SPELL_AURA_48 spell Napalm (area damage spell with additional delayed damage effect)
&Aura::HandleAuraModDodgePercent, // 49 SPELL_AURA_MOD_DODGE_PERCENT
&Aura::HandleNoImmediateEffect, // 50 SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT implemented in Unit::SpellCriticalHealingBonus
&Aura::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
&Aura::HandleAuraModCritPercent, // 52 SPELL_AURA_MOD_CRIT_PERCENT
&Aura::HandlePeriodicLeech, // 53 SPELL_AURA_PERIODIC_LEECH
&Aura::HandleModHitChance, // 54 SPELL_AURA_MOD_HIT_CHANCE
&Aura::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
&Aura::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM
&Aura::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
&Aura::HandleAuraModIncreaseSwimSpeed, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED
&Aura::HandleNoImmediateEffect, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE implemented in Unit::MeleeDamageBonusDone and Unit::SpellDamageBonusDone
&Aura::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE
&Aura::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE
&Aura::HandlePeriodicHealthFunnel, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL
&Aura::HandleUnused, // 63 unused (3.0.8a-3.2.2a) old SPELL_AURA_PERIODIC_MANA_FUNNEL
&Aura::HandlePeriodicManaLeech, // 64 SPELL_AURA_PERIODIC_MANA_LEECH
&Aura::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK
&Aura::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH
&Aura::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM
&Aura::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED
&Aura::HandleSchoolAbsorb, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalculateAbsorbAndResist
&Aura::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell 41560 that has only visual effect (3.2.2a)
&Aura::HandleModSpellCritChanceShool, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
&Aura::HandleModPowerCostPCT, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
&Aura::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL
&Aura::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult
&Aura::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE implemented in WorldSession::HandleMessagechatOpcode
&Aura::HandleFarSight, // 76 SPELL_AURA_FAR_SIGHT
&Aura::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY
&Aura::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED
&Aura::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
&Aura::HandleModPercentStat, // 80 SPELL_AURA_MOD_PERCENT_STAT
&Aura::HandleNoImmediateEffect, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT implemented in Unit::CalculateAbsorbAndResist
&Aura::HandleWaterBreathing, // 82 SPELL_AURA_WATER_BREATHING
&Aura::HandleModBaseResistance, // 83 SPELL_AURA_MOD_BASE_RESISTANCE
&Aura::HandleModRegen, // 84 SPELL_AURA_MOD_REGEN
&Aura::HandleModPowerRegen, // 85 SPELL_AURA_MOD_POWER_REGEN
&Aura::HandleChannelDeathItem, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM
&Aura::HandleDamagePercentTaken, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonusTaken and Unit::SpellDamageBonusTaken
&Aura::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT implemented in Player::RegenerateHealth
&Aura::HandlePeriodicDamagePCT, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
&Aura::HandleUnused, // 90 unused (3.0.8a-3.2.2a) old SPELL_AURA_MOD_RESIST_CHANCE
&Aura::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance
&Aura::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING
&Aura::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE
&Aura::HandleNoImmediateEffect, // 94 SPELL_AURA_INTERRUPT_REGEN implemented in Player::RegenerateAll
&Aura::HandleAuraGhost, // 95 SPELL_AURA_GHOST
&Aura::HandleNoImmediateEffect, // 96 SPELL_AURA_SPELL_MAGNET implemented in Unit::SelectMagnetTarget
&Aura::HandleManaShield, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalculateAbsorbAndResist
&Aura::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT
&Aura::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER
&Aura::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete 3.x? all player can see all auras now, but still have 2 spells including GM-spell (1852,2855)
&Aura::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT
&Aura::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonusDone
&Aura::HandleAuraModTotalThreat, //103 SPELL_AURA_MOD_TOTAL_THREAT
&Aura::HandleAuraWaterWalk, //104 SPELL_AURA_WATER_WALK
&Aura::HandleAuraFeatherFall, //105 SPELL_AURA_FEATHER_FALL
&Aura::HandleAuraHover, //106 SPELL_AURA_HOVER
&Aura::HandleAddModifier, //107 SPELL_AURA_ADD_FLAT_MODIFIER
&Aura::HandleAddModifier, //108 SPELL_AURA_ADD_PCT_MODIFIER
&Aura::HandleNoImmediateEffect, //109 SPELL_AURA_ADD_TARGET_TRIGGER
&Aura::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
&Aura::HandleNoImmediateEffect, //111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER implemented in Unit::SelectMagnetTarget
&Aura::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS implemented in diff functions.
&Aura::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonusTaken
&Aura::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonusTaken
&Aura::HandleNoImmediateEffect, //115 SPELL_AURA_MOD_HEALING implemented in Unit::SpellBaseHealingBonusTaken
&Aura::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT imppemented in Player::RegenerateAll and Player::RegenerateHealth
&Aura::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonusTaken
&Aura::HandleUnused, //119 unused (3.0.8a-3.2.2a) old SPELL_AURA_SHARE_PET_TRACKING
&Aura::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE
&Aura::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY
&Aura::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
&Aura::HandleModTargetResistance, //123 SPELL_AURA_MOD_TARGET_RESISTANCE
&Aura::HandleAuraModRangedAttackPower, //124 SPELL_AURA_MOD_RANGED_ATTACK_POWER
&Aura::HandleNoImmediateEffect, //125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonusTaken
&Aura::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonusTaken
&Aura::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonusDone
&Aura::HandleModPossessPet, //128 SPELL_AURA_MOD_POSSESS_PET
&Aura::HandleAuraModIncreaseSpeed, //129 SPELL_AURA_MOD_SPEED_ALWAYS
&Aura::HandleAuraModIncreaseMountedSpeed, //130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
&Aura::HandleNoImmediateEffect, //131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonusDone
&Aura::HandleAuraModIncreaseEnergyPercent, //132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
&Aura::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
&Aura::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
&Aura::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE
&Aura::HandleNoImmediateEffect, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT implemented in Unit::SpellHealingBonusDone
&Aura::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
&Aura::HandleModMeleeSpeedPct, //138 SPELL_AURA_MOD_MELEE_HASTE
&Aura::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION
&Aura::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE
&Aura::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
&Aura::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
&Aura::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
&Aura::HandleAuraSafeFall, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
&Aura::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS
&Aura::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE implemented in Player::CanTameExoticPets
&Aura::HandleModMechanicImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK implemented in Unit::IsImmuneToSpell and Unit::IsImmuneToSpellEffect (check part)
&Aura::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
&Aura::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK implemented in Spell::Delayed and Spell::DelayedChannel
&Aura::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
&Aura::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
&Aura::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance
&Aura::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT implemented in Unit::CalculateAbsorbAndResist
&Aura::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL implemented in Unit::isVisibleForOrDetect
&Aura::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING implemented in Player::getMaxTimer
&Aura::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN implemented in Player::CalculateReputationGain
&Aura::HandleUnused, //157 SPELL_AURA_PET_DAMAGE_MULTI (single test like spell 20782, also single for 214 aura)
&Aura::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
&Aura::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT implemented in Player::RewardHonor
&Aura::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT implemented in Player::RegenerateAll and Player::RegenerateHealth
&Aura::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
&Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS implemented in Unit::CalculateMeleeDamage and Unit::SpellCriticalDamageBonus
&Aura::HandleUnused, //164 unused (3.0.8a-3.2.2a), only one test spell 10654
&Aura::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonusDone
&Aura::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT
&Aura::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
&Aura::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonusDone, Unit::MeleeDamageBonusDone
&Aura::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus
&Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE different spells that ignore transformation effects
&Aura::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
&Aura::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
&Aura::HandleUnused, //173 unused (3.0.8a-3.2.2a) no spells, old SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
&Aura::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonusDone
&Aura::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonusDone
&Aura::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
&Aura::HandleNULL, //177 SPELL_AURA_AOE_CHARM (22 spells)
&Aura::HandleNoImmediateEffect, //178 SPELL_AURA_MOD_DEBUFF_RESISTANCE implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE implemented in Unit::SpellCriticalBonus
&Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonusDone
&Aura::HandleUnused, //181 unused (3.0.8a-3.2.2a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS
&Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
&Aura::HandleNoImmediateEffect, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746, implemented in ThreatCalcHelper::CalcThreat
&Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
&Aura::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
&Aura::HandleModRating, //189 SPELL_AURA_MOD_RATING
&Aura::HandleNoImmediateEffect, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN implemented in Player::CalculateReputationGain
&Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
&Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_MOD_MELEE_RANGED_HASTE
&Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_HASTE_ALL (in fact combat (any type attack) speed pct)
&Aura::HandleNoImmediateEffect, //194 SPELL_AURA_MOD_IGNORE_ABSORB_SCHOOL implement in Unit::CalcNotIgnoreAbsorbDamage
&Aura::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_IGNORE_ABSORB_FOR_SPELL implement in Unit::CalcNotIgnoreAbsorbDamage
&Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN (single spell 24818 in 3.2.2a)
&Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance
&Aura::HandleUnused, //198 unused (3.0.8a-3.2.2a) old SPELL_AURA_MOD_ALL_WEAPON_SKILLS
&Aura::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult
&Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_KILL_XP_PCT implemented in Player::GiveXP
&Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
&Aura::HandleNoImmediateEffect, //202 SPELL_AURA_IGNORE_COMBAT_RESULT implemented in Unit::MeleeSpellHitResult
&Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::SpellCriticalDamageBonus
&Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::SpellCriticalDamageBonus
&Aura::HandleNoImmediateEffect, //205 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_DAMAGE implemented in Unit::SpellCriticalDamageBonus
&Aura::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_FLIGHT_SPEED
&Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED
&Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_FLIGHT_SPEED_STACKING
&Aura::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_STACKING
&Aura::HandleAuraModIncreaseFlightSpeed, //210 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACKING
&Aura::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED_NOT_STACKING
&Aura::HandleAuraModRangedAttackPowerOfStatPercent, //212 SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
&Aura::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage
&Aura::HandleUnused, //214 Tamed Pet Passive (single test like spell 20782, also single for 157 aura)
&Aura::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION
&Aura::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS
&Aura::HandleUnused, //217 unused (3.0.8a-3.2.2a)
&Aura::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
&Aura::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
&Aura::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT
&Aura::HandleNULL, //221 ignored
&Aura::HandleUnused, //222 unused (3.0.8a-3.2.2a) only for spell 44586 that not used in real spell cast
&Aura::HandleNULL, //223 dummy code (cast damage spell to attacker) and another dymmy (jump to another nearby raid member)
&Aura::HandleUnused, //224 unused (3.0.8a-3.2.2a)
&Aura::HandleNoImmediateEffect, //225 SPELL_AURA_PRAYER_OF_MENDING
&Aura::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY
&Aura::HandlePeriodicTriggerSpellWithValue, //227 SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
&Aura::HandleNoImmediateEffect, //228 SPELL_AURA_DETECT_STEALTH
&Aura::HandleNoImmediateEffect, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE implemented in Unit::SpellDamageBonusTaken
&Aura::HandleAuraModIncreaseMaxHealth, //230 Commanding Shout
&Aura::HandleNoImmediateEffect, //231 SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE
&Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateAuraDuration
&Aura::HandleNULL, //233 set model id to the one of the creature with id m_modifier.m_miscvalue
&Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateAuraDuration
&Aura::HandleAuraModDispelResist, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
&Aura::HandleAuraControlVehicle, //236 SPELL_AURA_CONTROL_VEHICLE
&Aura::HandleModSpellDamagePercentFromAttackPower, //237 SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER implemented in Unit::SpellBaseDamageBonusDone
&Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonusDone
&Aura::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61
&Aura::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE
&Aura::HandleForceMoveForward, //241 Forces the caster to move forward
&Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING (only 2 test spels in 3.2.2a)
&Aura::HandleNULL, //243 faction reaction override spells
&Aura::HandleComprehendLanguage, //244 SPELL_AURA_COMPREHEND_LANGUAGE
&Aura::HandleNoImmediateEffect, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS implemented in Unit::CalculateAuraDuration
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL implemented in Unit::CalculateAuraDuration
&Aura::HandleAuraMirrorImage, //247 SPELL_AURA_MIRROR_IMAGE target to become a clone of the caster
&Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleAuraConvertRune, //249 SPELL_AURA_CONVERT_RUNE
&Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
&Aura::HandleNULL, //251 SPELL_AURA_MOD_ENEMY_DODGE
&Aura::HandleModCombatSpeedPct, //252 SPELL_AURA_SLOW_ALL
&Aura::HandleNoImmediateEffect, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE implemented in Unit::CalculateMeleeDamage
&Aura::HandleAuraModDisarm, //254 SPELL_AURA_MOD_DISARM_OFFHAND also disarm shield
&Aura::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonusTaken
&Aura::HandleNoReagentUseAura, //256 SPELL_AURA_NO_REAGENT_USE Use SpellClassMask for spell select
&Aura::HandleNULL, //257 SPELL_AURA_MOD_TARGET_RESIST_BY_SPELL_CLASS Use SpellClassMask for spell select
&Aura::HandleNULL, //258 SPELL_AURA_MOD_SPELL_VISUAL
&Aura::HandleNoImmediateEffect, //259 SPELL_AURA_MOD_PERIODIC_HEAL implemented in Unit::SpellHealingBonus
&Aura::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
&Aura::HandlePhase, //261 SPELL_AURA_PHASE undetectable invisibility? implemented in Unit::isVisibleForOrDetect
&Aura::HandleNoImmediateEffect, //262 SPELL_AURA_IGNORE_UNIT_STATE implemented in Unit::isIgnoreUnitState & Spell::CheckCast
&Aura::HandleNoImmediateEffect, //263 SPELL_AURA_ALLOW_ONLY_ABILITY implemented in Spell::CheckCasterAuras, lool enum IgnoreUnitState for known misc values
&Aura::HandleUnused, //264 unused (3.0.8a-3.2.2a)
&Aura::HandleUnused, //265 unused (3.0.8a-3.2.2a)
&Aura::HandleUnused, //266 unused (3.0.8a-3.2.2a)
&Aura::HandleNoImmediateEffect, //267 SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL implemented in Unit::IsImmuneToSpellEffect
&Aura::HandleAuraModAttackPowerOfStatPercent, //268 SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
&Aura::HandleNoImmediateEffect, //269 SPELL_AURA_MOD_IGNORE_DAMAGE_REDUCTION_SCHOOL implemented in Unit::CalcNotIgnoreDamageReduction
&Aura::HandleUnused, //270 SPELL_AURA_MOD_IGNORE_TARGET_RESIST (unused in 3.2.2a)
&Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonusTaken
&Aura::HandleNoImmediateEffect, //272 SPELL_AURA_MAELSTROM_WEAPON (unclear use for aura, it used in (3.2.2a...3.3.0) in single spell 53817 that spellmode stacked and charged spell expected to be drop as stack
&Aura::HandleNoImmediateEffect, //273 SPELL_AURA_X_RAY (client side implementation)
&Aura::HandleNULL, //274 proc free shot?
&Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select
&Aura::HandleNULL, //276 mod damage % mechanic?
&Aura::HandleNoImmediateEffect, //277 SPELL_AURA_MOD_MAX_AFFECTED_TARGETS Use SpellClassMask for spell select
&Aura::HandleAuraModDisarm, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon
&Aura::HandleNULL, //279 visual effects? 58836 and 57507
&Aura::HandleModTargetArmorPct, //280 SPELL_AURA_MOD_TARGET_ARMOR_PCT
&Aura::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN implemented in Player::RewardHonor
&Aura::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT
&Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonusTaken
&Aura::HandleNULL, //284 51 spells
&Aura::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage
&Aura::HandleNoImmediateEffect, //286 SPELL_AURA_ABILITY_PERIODIC_CRIT implemented in Aura::IsCritFromAbilityAura called from Aura::PeriodicTick
&Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult
&Aura::HandleNoImmediateEffect, //288 SPELL_AURA_MOD_PARRY_FROM_BEHIND_PERCENT percent from normal parry/deflect applied to from behind attack case (single spell used 67801, also look 4.1.0 spell 97574)
&Aura::HandleUnused, //289 unused (3.2.2a)
&Aura::HandleAuraModAllCritChance, //290 SPELL_AURA_MOD_ALL_CRIT_CHANCE
&Aura::HandleNoImmediateEffect, //291 SPELL_AURA_MOD_QUEST_XP_PCT implemented in Player::GiveXP
&Aura::HandleAuraOpenStable, //292 call stabled pet
&Aura::HandleAuraAddMechanicAbilities, //293 SPELL_AURA_ADD_MECHANIC_ABILITIES replaces target's action bars with a predefined spellset
&Aura::HandleAuraStopNaturalManaRegen, //294 SPELL_AURA_STOP_NATURAL_MANA_REGEN implemented in Player:Regenerate
&Aura::HandleUnused, //295 unused (3.2.2a)
&Aura::HandleNULL, //296 2 spells
&Aura::HandleNULL, //297 1 spell (counter spell school?)
&Aura::HandleUnused, //298 unused (3.2.2a)
&Aura::HandleUnused, //299 unused (3.2.2a)
&Aura::HandleNULL, //300 3 spells (share damage?)
&Aura::HandleNULL, //301 SPELL_AURA_HEAL_ABSORB 5 spells
&Aura::HandleUnused, //302 unused (3.2.2a)
&Aura::HandleNULL, //303 17 spells
&Aura::HandleNULL, //304 2 spells (alcohol effect?)
&Aura::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED
&Aura::HandleNULL, //306 1 spell
&Aura::HandleNULL, //307 absorb healing?
&Aura::HandleNULL, //308 new aura for hunter traps
&Aura::HandleNULL, //309 absorb healing?
&Aura::HandleNoImmediateEffect, //310 SPELL_AURA_MOD_PET_AOE_DAMAGE_AVOIDANCE implemented in Unit::SpellDamageBonusTaken
&Aura::HandleNULL, //311 0 spells in 3.3
&Aura::HandleNULL, //312 0 spells in 3.3
&Aura::HandleNULL, //313 0 spells in 3.3
&Aura::HandleNULL, //314 1 test spell (reduce duration of silince/magic)
&Aura::HandleNULL, //315 underwater walking
&Aura::HandleNULL //316 makes haste affect HOT/DOT ticks
};
static AuraType const frozenAuraTypes[] = { SPELL_AURA_MOD_ROOT, SPELL_AURA_MOD_STUN, SPELL_AURA_NONE };
Aura::Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target, Unit *caster, Item* castItem) :
m_spellmod(NULL), m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT),
m_effIndex(eff), m_positive(false), m_isPeriodic(false), m_isAreaAura(false),
m_isPersistent(false), m_in_use(0), m_spellAuraHolder(holder)
{
MANGOS_ASSERT(target);
MANGOS_ASSERT(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
m_currentBasePoints = currentBasePoints ? *currentBasePoints : spellproto->CalculateSimpleValue(eff);
m_positive = IsPositiveEffect(spellproto, m_effIndex);
m_applyTime = time(NULL);
int32 damage;
if (!caster)
damage = m_currentBasePoints;
else
{
damage = caster->CalculateSpellDamage(target, spellproto, m_effIndex, &m_currentBasePoints);
if (!damage && castItem && castItem->GetItemSuffixFactor())
{
ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
if (item_rand_suffix)
{
for (int k = 0; k < 3; ++k)
{
SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(item_rand_suffix->enchant_id[k]);
if (pEnchant)
{
for (int t = 0; t < 3; ++t)
{
if(pEnchant->spellid[t] != spellproto->Id)
continue;
damage = uint32((item_rand_suffix->prefix[k]*castItem->GetItemSuffixFactor()) / 10000 );
break;
}
}
if (damage)
break;
}
}
}
}
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura: construct Spellid : %u, Aura : %u Target : %d Damage : %d", spellproto->Id, spellproto->EffectApplyAuraName[eff], spellproto->EffectImplicitTargetA[eff], damage);
SetModifier(AuraType(spellproto->EffectApplyAuraName[eff]), damage, spellproto->EffectAmplitude[eff], spellproto->EffectMiscValue[eff]);
Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
// Apply periodic time mod
if (modOwner && m_modifier.periodictime)
modOwner->ApplySpellMod(spellproto->Id, SPELLMOD_ACTIVATION_TIME, m_modifier.periodictime);
// Start periodic on next tick or at aura apply
if (!(spellproto->AttributesEx5 & SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY))
m_periodicTimer = m_modifier.periodictime;
}
Aura::~Aura()
{
}
AreaAura::AreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target,
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem)
{
m_isAreaAura = true;
// caster==NULL in constructor args if target==caster in fact
Unit* caster_ptr = caster ? caster : target;
m_radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellproto->EffectRadiusIndex[m_effIndex]));
if(Player* modOwner = caster_ptr->GetSpellModOwner())
modOwner->ApplySpellMod(spellproto->Id, SPELLMOD_RADIUS, m_radius);
switch(spellproto->Effect[eff])
{
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
m_areaAuraType = AREA_AURA_PARTY;
if (target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->IsTotem())
m_modifier.m_auraname = SPELL_AURA_NONE;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
m_areaAuraType = AREA_AURA_RAID;
if (target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->IsTotem())
m_modifier.m_auraname = SPELL_AURA_NONE;
// Light's Beacon not applied to caster itself (TODO: more generic check for another similar spell if any?)
else if (target == caster_ptr && spellproto->Id == 53651)
m_modifier.m_auraname = SPELL_AURA_NONE;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
m_areaAuraType = AREA_AURA_FRIEND;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
m_areaAuraType = AREA_AURA_ENEMY;
if (target == caster_ptr)
m_modifier.m_auraname = SPELL_AURA_NONE; // Do not do any effect on self
break;
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
m_areaAuraType = AREA_AURA_PET;
break;
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
m_areaAuraType = AREA_AURA_OWNER;
if (target == caster_ptr)
m_modifier.m_auraname = SPELL_AURA_NONE;
break;
default:
sLog.outError("Wrong spell effect in AreaAura constructor");
MANGOS_ASSERT(false);
break;
}
}
AreaAura::~AreaAura()
{
}
PersistentAreaAura::PersistentAreaAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target,
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem)
{
m_isPersistent = true;
}
PersistentAreaAura::~PersistentAreaAura()
{
}
SingleEnemyTargetAura::SingleEnemyTargetAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target,
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem)
{
if (caster)
m_castersTargetGuid = caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)caster)->GetSelectionGuid() : caster->GetTargetGuid();
}
SingleEnemyTargetAura::~SingleEnemyTargetAura()
{
}
Unit* SingleEnemyTargetAura::GetTriggerTarget() const
{
return ObjectAccessor::GetUnit(*(m_spellAuraHolder->GetTarget()), m_castersTargetGuid);
}
Aura* CreateAura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target, Unit *caster, Item* castItem)
{
if (IsAreaAuraEffect(spellproto->Effect[eff]))
return new AreaAura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
uint32 triggeredSpellId = spellproto->EffectTriggerSpell[eff];
if(SpellEntry const* triggeredSpellInfo = sSpellStore.LookupEntry(triggeredSpellId))
for (int i = 0; i < MAX_EFFECT_INDEX; ++i)
if (triggeredSpellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_ENEMY)
return new SingleEnemyTargetAura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
return new Aura(spellproto, eff, currentBasePoints, holder, target, caster, castItem);
}
SpellAuraHolder* CreateSpellAuraHolder(SpellEntry const* spellproto, Unit *target, WorldObject *caster, Item *castItem)
{
return new SpellAuraHolder(spellproto, target, caster, castItem);
}
void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
{
m_modifier.m_auraname = t;
m_modifier.m_amount = a;
m_modifier.m_miscvalue = miscValue;
m_modifier.periodictime = pt;
}
void Aura::Update(uint32 diff)
{
if (m_isPeriodic)
{
m_periodicTimer -= diff;
if(m_periodicTimer <= 0) // tick also at m_periodicTimer==0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
{
// update before applying (aura can be removed in TriggerSpell or PeriodicTick calls)
m_periodicTimer += m_modifier.periodictime;
++m_periodicTick; // for some infinity auras in some cases can overflow and reset
PeriodicTick();
}
}
}
void AreaAura::Update(uint32 diff)
{
// update for the caster of the aura
if(GetCasterGuid() == GetTarget()->GetObjectGuid())
{
Unit* caster = GetTarget();
if( !caster->hasUnitState(UNIT_STAT_ISOLATED) )
{
Unit* owner = caster->GetCharmerOrOwner();
if (!owner)
owner = caster;
Spell::UnitList targets;
switch(m_areaAuraType)
{
case AREA_AURA_PARTY:
{
Group *pGroup = NULL;
if (owner->GetTypeId() == TYPEID_PLAYER)
pGroup = ((Player*)owner)->GetGroup();
if( pGroup)
{
uint8 subgroup = ((Player*)owner)->GetSubGroup();
for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* Target = itr->getSource();
if(Target && Target->isAlive() && Target->GetSubGroup()==subgroup && caster->IsFriendlyTo(Target))
{
if(caster->IsWithinDistInMap(Target, m_radius))
targets.push_back(Target);
Pet *pet = Target->GetPet();
if(pet && pet->isAlive() && caster->IsWithinDistInMap(pet, m_radius))
targets.push_back(pet);
}
}
}
else
{
// add owner
if( owner != caster && caster->IsWithinDistInMap(owner, m_radius) )
targets.push_back(owner);
// add caster's pet
Unit* pet = caster->GetPet();
if( pet && caster->IsWithinDistInMap(pet, m_radius))
targets.push_back(pet);
}
break;
}
case AREA_AURA_RAID:
{
Group *pGroup = NULL;
if (owner->GetTypeId() == TYPEID_PLAYER)
pGroup = ((Player*)owner)->GetGroup();
if( pGroup)
{
for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
Player* Target = itr->getSource();
if(Target && Target->isAlive() && caster->IsFriendlyTo(Target))
{
if(caster->IsWithinDistInMap(Target, m_radius))
targets.push_back(Target);
Pet *pet = Target->GetPet();
if(pet && pet->isAlive() && caster->IsWithinDistInMap(pet, m_radius))
targets.push_back(pet);
}
}
}
else
{
// add owner
if( owner != caster && caster->IsWithinDistInMap(owner, m_radius) )
targets.push_back(owner);
// add caster's pet
Unit* pet = caster->GetPet();
if( pet && caster->IsWithinDistInMap(pet, m_radius))
targets.push_back(pet);
}
break;
}
case AREA_AURA_FRIEND:
{
MaNGOS::AnyFriendlyUnitInObjectRangeCheck u_check(caster, m_radius);
MaNGOS::UnitListSearcher<MaNGOS::AnyFriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
Cell::VisitAllObjects(caster, searcher, m_radius);
break;
}
case AREA_AURA_ENEMY:
{
MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(caster, m_radius); // No GetCharmer in searcher
MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck> searcher(targets, u_check);
Cell::VisitAllObjects(caster, searcher, m_radius);
break;
}
case AREA_AURA_OWNER:
case AREA_AURA_PET:
{
if(owner != caster && caster->IsWithinDistInMap(owner, m_radius))
targets.push_back(owner);
break;
}
}
for(Spell::UnitList::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
{
// flag for seelction is need apply aura to current iteration target
bool apply = true;
// we need ignore present caster self applied are auras sometime
// in cases if this only auras applied for spell effect
Unit::SpellAuraHolderBounds spair = (*tIter)->GetSpellAuraHolderBounds(GetId());
for(Unit::SpellAuraHolderMap::const_iterator i = spair.first; i != spair.second; ++i)
{
if (i->second->IsDeleted())
continue;
Aura *aur = i->second->GetAuraByEffectIndex(m_effIndex);
if (!aur)
continue;
switch(m_areaAuraType)
{
case AREA_AURA_ENEMY:
// non caster self-casted auras (non stacked)
if(aur->GetModifier()->m_auraname != SPELL_AURA_NONE)
apply = false;
break;
case AREA_AURA_RAID:
// non caster self-casted auras (stacked from diff. casters)
if(aur->GetModifier()->m_auraname != SPELL_AURA_NONE || i->second->GetCasterGuid() == GetCasterGuid())
apply = false;
break;
default:
// in generic case not allow stacking area auras
apply = false;
break;
}
if(!apply)
break;
}
if(!apply)
continue;
if(SpellEntry const *actualSpellInfo = sSpellMgr.SelectAuraRankForLevel(GetSpellProto(), (*tIter)->getLevel()))
{
int32 actualBasePoints = m_currentBasePoints;
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
if(actualSpellInfo != GetSpellProto())
actualBasePoints = actualSpellInfo->CalculateSimpleValue(m_effIndex);
SpellAuraHolder *holder = (*tIter)->GetSpellAuraHolder(actualSpellInfo->Id, GetCasterGuid());
bool addedToExisting = true;
if (!holder)
{
holder = CreateSpellAuraHolder(actualSpellInfo, (*tIter), caster);
addedToExisting = false;
}
holder->SetAuraDuration(GetAuraDuration());
AreaAura *aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, holder, (*tIter), caster, NULL);
holder->AddAura(aur, m_effIndex);
if (addedToExisting)
{
(*tIter)->AddAuraToModList(aur);
holder->SetInUse(true);
aur->ApplyModifier(true,true);
holder->SetInUse(false);
}
else
(*tIter)->AddSpellAuraHolder(holder);
}
}
}
Aura::Update(diff);
}
else // aura at non-caster
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
Aura::Update(diff);
// remove aura if out-of-range from caster (after teleport for example)
// or caster is isolated or caster no longer has the aura
// or caster is (no longer) friendly
bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true);
if( !caster || caster->hasUnitState(UNIT_STAT_ISOLATED) ||
!caster->IsWithinDistInMap(target, m_radius) ||
!caster->HasAura(GetId(), GetEffIndex()) ||
caster->IsFriendlyTo(target) != needFriendly
)
{
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
else if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group
{
// not check group if target == owner or target == pet
if (caster->GetCharmerOrOwnerGuid() != target->GetObjectGuid() && caster->GetObjectGuid() != target->GetCharmerOrOwnerGuid())
{
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group *pGroup = check ? check->GetGroup() : NULL;
if( pGroup )
{
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if(!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
else
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
}
else if( m_areaAuraType == AREA_AURA_RAID) // TODO: fix me!
{
// not check group if target == owner or target == pet
if (caster->GetCharmerOrOwnerGuid() != target->GetObjectGuid() && caster->GetObjectGuid() != target->GetCharmerOrOwnerGuid())
{
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group *pGroup = check ? check->GetGroup() : NULL;
if( pGroup )
{
Player* checkTarget = target->GetCharmerOrOwnerPlayerOrPlayerItself();
if(!checkTarget)
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
else
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
}
else if (m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER)
{
if (target->GetObjectGuid() != caster->GetCharmerOrOwnerGuid())
target->RemoveSingleAuraFromSpellAuraHolder(GetId(), GetEffIndex(), GetCasterGuid());
}
}
}
void PersistentAreaAura::Update(uint32 diff)
{
bool remove = false;
// remove the aura if its caster or the dynamic object causing it was removed
// or if the target moves too far from the dynamic object
if(Unit *caster = GetCaster())
{
DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
if (dynObj)
{
if (!GetTarget()->IsWithinDistInMap(dynObj, dynObj->GetRadius()))
{
remove = true;
dynObj->RemoveAffected(GetTarget()); // let later reapply if target return to range
}
}
else
remove = true;
}
else
remove = true;
Aura::Update(diff);
if(remove)
GetTarget()->RemoveAura(GetId(), GetEffIndex());
}
void Aura::ApplyModifier(bool apply, bool Real)
{
AuraType aura = m_modifier.m_auraname;
GetHolder()->SetInUse(true);
SetInUse(true);
if(aura < TOTAL_AURAS)
(*this.*AuraHandler [aura])(apply, Real);
SetInUse(false);
GetHolder()->SetInUse(false);
}
bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
{
return spell->IsFitToFamily(SpellFamily(GetSpellProto()->SpellFamilyName), GetAuraSpellClassMask());
}
bool Aura::CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const
{
// Check EffectClassMask
ClassFamilyMask const& mask = GetAuraSpellClassMask();
// if no class mask defined, or spell_proc_event has SpellFamilyName=0 - allow proc
if (!useClassMask || !mask)
{
if (!(EventProcEx & PROC_EX_EX_TRIGGER_ALWAYS))
{
// Check for extra req (if none) and hit/crit
if (EventProcEx == PROC_EX_NONE)
{
// No extra req, so can trigger only for active (damage/healing present) and hit/crit
if((procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
return true;
else
return false;
}
else // Passive spells hits here only if resist/reflect/immune/evade
{
// Passive spells can`t trigger if need hit (exclude cases when procExtra include non-active flags)
if ((EventProcEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT) & procEx) && !active)
return false;
}
}
return true;
}
else
{
// SpellFamilyName check is performed in SpellMgr::IsSpellProcEventCanTriggeredBy and it is done once for whole holder
// note: SpellFamilyName is not checked if no spell_proc_event is defined
return mask.IsFitToFamilyMask(spell->SpellFamilyFlags);
}
}
void Aura::ReapplyAffectedPassiveAuras( Unit* target, bool owner_mode )
{
// we need store cast item guids for self casted spells
// expected that not exist permanent auras from stackable auras from different items
std::map<uint32, ObjectGuid> affectedSelf;
std::set<uint32> affectedAuraCaster;
for(Unit::SpellAuraHolderMap::const_iterator itr = target->GetSpellAuraHolderMap().begin(); itr != target->GetSpellAuraHolderMap().end(); ++itr)
{
// permanent passive or permanent area aura
// passive spells can be affected only by own or owner spell mods)
if ((itr->second->IsPermanent() && (owner_mode && itr->second->IsPassive() || itr->second->IsAreaAura())) &&
// non deleted and not same aura (any with same spell id)
!itr->second->IsDeleted() && itr->second->GetId() != GetId() &&
// and affected by aura
isAffectedOnSpell(itr->second->GetSpellProto()))
{
// only applied by self or aura caster
if (itr->second->GetCasterGuid() == target->GetObjectGuid())
affectedSelf[itr->second->GetId()] = itr->second->GetCastItemGuid();
else if (itr->second->GetCasterGuid() == GetCasterGuid())
affectedAuraCaster.insert(itr->second->GetId());
}
}
if (!affectedSelf.empty())
{
Player* pTarget = target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : NULL;
for(std::map<uint32, ObjectGuid>::const_iterator map_itr = affectedSelf.begin(); map_itr != affectedSelf.end(); ++map_itr)
{
Item* item = pTarget && map_itr->second ? pTarget->GetItemByGuid(map_itr->second) : NULL;
target->RemoveAurasDueToSpell(map_itr->first);
target->CastSpell(target, map_itr->first, true, item);
}
}
if (!affectedAuraCaster.empty())
{
Unit* caster = GetCaster();
for(std::set<uint32>::const_iterator set_itr = affectedAuraCaster.begin(); set_itr != affectedAuraCaster.end(); ++set_itr)
{
target->RemoveAurasDueToSpell(*set_itr);
if (caster)
caster->CastSpell(GetTarget(), *set_itr, true);
}
}
}
struct ReapplyAffectedPassiveAurasHelper
{
explicit ReapplyAffectedPassiveAurasHelper(Aura* _aura) : aura(_aura) {}
void operator()(Unit* unit) const { aura->ReapplyAffectedPassiveAuras(unit, true); }
Aura* aura;
};
void Aura::ReapplyAffectedPassiveAuras()
{
// not reapply spell mods with charges (use original value because processed and at remove)
if (GetSpellProto()->procCharges)
return;
// not reapply some spell mods ops (mostly speedup case)
switch (m_modifier.m_miscvalue)
{
case SPELLMOD_DURATION:
case SPELLMOD_CHARGES:
case SPELLMOD_NOT_LOSE_CASTING_TIME:
case SPELLMOD_CASTING_TIME:
case SPELLMOD_COOLDOWN:
case SPELLMOD_COST:
case SPELLMOD_ACTIVATION_TIME:
case SPELLMOD_GLOBAL_COOLDOWN:
return;
}
// reapply talents to own passive persistent auras
ReapplyAffectedPassiveAuras(GetTarget(), true);
// re-apply talents/passives/area auras applied to pet/totems (it affected by player spellmods)
GetTarget()->CallForAllControlledUnits(ReapplyAffectedPassiveAurasHelper(this), CONTROLLED_PET|CONTROLLED_TOTEMS);
// re-apply talents/passives/area auras applied to group members (it affected by player spellmods)
if (Group* group = ((Player*)GetTarget())->GetGroup())
for(GroupReference *itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* member = itr->getSource())
if (member != GetTarget() && member->IsInMap(GetTarget()))
ReapplyAffectedPassiveAuras(member, false);
}
/*********************************************************/
/*** BASIC AURA FUNCTION ***/
/*********************************************************/
void Aura::HandleAddModifier(bool apply, bool Real)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER || !Real)
return;
if(m_modifier.m_miscvalue >= MAX_SPELLMOD)
return;
if (apply)
{
SpellEntry const* spellProto = GetSpellProto();
// Add custom charges for some mod aura
switch (spellProto->Id)
{
case 17941: // Shadow Trance
case 22008: // Netherwind Focus
case 31834: // Light's Grace
case 34754: // Clearcasting
case 34936: // Backlash
case 44401: // Missile Barrage
case 48108: // Hot Streak
case 51124: // Killing Machine
case 54741: // Firestarter
case 57761: // Fireball!
case 64823: // Elune's Wrath (Balance druid t8 set
GetHolder()->SetAuraCharges(1);
break;
}
m_spellmod = new SpellModifier(
SpellModOp(m_modifier.m_miscvalue),
SpellModType(m_modifier.m_auraname), // SpellModType value == spell aura types
m_modifier.m_amount,
this,
// prevent expire spell mods with (charges > 0 && m_stackAmount > 1)
// all this spell expected expire not at use but at spell proc event check
GetSpellProto()->StackAmount > 1 ? 0 : GetHolder()->GetAuraCharges());
// Everlasting Affliction, overwrite wrong data, if will need more better restore support of spell_affect table
if (spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellIconID == 3169)
{
// Corruption and Unstable Affliction
m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000010000000002));
}
// Improved Flametongue Weapon, overwrite wrong data, maybe time re-add table
else if (spellProto->Id == 37212)
{
// Flametongue Weapon (Passive)
m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000000000200000));
}
}
((Player*)GetTarget())->AddSpellMod(m_spellmod, apply);
ReapplyAffectedPassiveAuras();
}
void Aura::TriggerSpell()
{
ObjectGuid casterGUID = GetCasterGuid();
Unit* triggerTarget = GetTriggerTarget();
if (!casterGUID || !triggerTarget)
return;
// generic casting code with custom spells and target/caster customs
uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
SpellEntry const *auraSpellInfo = GetSpellProto();
uint32 auraId = auraSpellInfo->Id;
Unit* target = GetTarget();
// specific code for cases with no trigger spell provided in field
if (triggeredSpellInfo == NULL)
{
switch(auraSpellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch(auraId)
{
case 812: // Periodic Mana Burn
{
trigger_spell_id = 25779; // Mana Burn
// expected selection current fight target
triggerTarget = GetTarget()->getVictim();
if (!triggerTarget || triggerTarget->GetMaxPower(POWER_MANA) <= 0)
return;
triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
if (!triggeredSpellInfo)
return;
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(triggeredSpellInfo->rangeIndex);
float max_range = GetSpellMaxRange(srange);
if (!triggerTarget->IsWithinDist(GetTarget(),max_range))
return;
break;
}
// // Polymorphic Ray
// case 6965: break;
case 9712: // Thaumaturgy Channel
trigger_spell_id = 21029;
break;
// // Egan's Blaster
// case 17368: break;
// // Haunted
// case 18347: break;
// // Ranshalla Waiting
// case 18953: break;
// // Inferno
// case 19695: break;
// // Frostwolf Muzzle DND
// case 21794: break;
// // Alterac Ram Collar DND
// case 21866: break;
// // Celebras Waiting
// case 21916: break;
case 23170: // Brood Affliction: Bronze
{
target->CastSpell(target, 23171, true, NULL, this);
return;
}
case 23184: // Mark of Frost
case 25041: // Mark of Nature
{
std::list<Player*> targets;
// spells existed in 1.x.x; 23183 - mark of frost; 25042 - mark of nature; both had radius of 100.0 yards in 1.x.x DBC
// spells are used by Azuregos and the Emerald dragons in order to put a stun debuff on the players which resurrect during the encounter
// in order to implement the missing spells we need to make a grid search for hostile players and check their auras; if they are marked apply debuff
// Mark of Frost or Mark of Nature
uint32 markSpellId = auraId == 23184 ? 23182 : 25040;
// Aura of Frost or Aura of Nature
uint32 debufSpellId = auraId == 23184 ? 23186 : 25043;
MaNGOS::AnyPlayerInObjectRangeWithAuraCheck u_check(GetTarget(), 100.0f, markSpellId);
MaNGOS::PlayerListSearcher<MaNGOS::AnyPlayerInObjectRangeWithAuraCheck > checker(targets, u_check);
Cell::VisitWorldObjects(GetTarget(), checker, 100.0f);
for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
(*itr)->CastSpell((*itr), debufSpellId, true, NULL, NULL, casterGUID);
return;
}
case 23493: // Restoration
{
uint32 heal = triggerTarget->GetMaxHealth() / 10;
uint32 absorb = 0;
triggerTarget->CalculateHealAbsorb(heal, &absorb);
triggerTarget->DealHeal(triggerTarget, heal - absorb, auraSpellInfo, false, absorb);
if (int32 mana = triggerTarget->GetMaxPower(POWER_MANA))
{
mana /= 10;
triggerTarget->EnergizeBySpell(triggerTarget, 23493, mana, POWER_MANA);
}
return;
}
// // Stoneclaw Totem Passive TEST
// case 23792: break;
// // Axe Flurry
// case 24018: break;
// // Mark of Arlokk
// case 24210: break;
// // Restoration
// case 24379: break;
// // Happy Pet
// case 24716: break;
// // Dream Fog
// case 24780: break;
// // Cannon Prep
// case 24832: break;
case 24834: // Shadow Bolt Whirl
{
uint32 spellForTick[8] = { 24820, 24821, 24822, 24823, 24835, 24836, 24837, 24838 };
uint32 tick = GetAuraTicks();
if(tick < 8)
{
trigger_spell_id = spellForTick[tick];
// casted in left/right (but triggered spell have wide forward cone)
float forward = target->GetOrientation();
float angle = target->GetOrientation() + ( tick % 2 == 0 ? M_PI_F / 2 : - M_PI_F / 2);
target->SetOrientation(angle);
triggerTarget->CastSpell(triggerTarget, trigger_spell_id, true, NULL, this, casterGUID);
target->SetOrientation(forward);
}
return;
}
// // Stink Trap
// case 24918: break;
// // Agro Drones
// case 25152: break;
case 25371: // Consume
{
int32 bpDamage = triggerTarget->GetMaxHealth()*10/100;
triggerTarget->CastCustomSpell(triggerTarget, 25373, &bpDamage, NULL, NULL, true, NULL, this, casterGUID);
return;
}
// // Pain Spike
// case 25572: break;
// // Rotate 360
// case 26009: break;
// // Rotate -360
// case 26136: break;
// // Consume
// case 26196: break;
// // Berserk
// case 26615: break;
// // Defile
// case 27177: break;
// // Teleport: IF/UC
// case 27601: break;
// // Five Fat Finger Exploding Heart Technique
// case 27673: break;
// // Nitrous Boost
// case 27746: break;
// // Steam Tank Passive
// case 27747: break;
case 27808: // Frost Blast
{
int32 bpDamage = triggerTarget->GetMaxHealth()*26/100;
triggerTarget->CastCustomSpell(triggerTarget, 29879, &bpDamage, NULL, NULL, true, NULL, this, casterGUID);
return;
}
// // Detonate Mana
// case 27819: break;
// // Controller Timer
// case 28095: break;
// // Stalagg Chain
// case 28096: break;
// // Stalagg Tesla Passive
// case 28097: break;
// // Feugen Tesla Passive
// case 28109: break;
// // Feugen Chain
// case 28111: break;
// // Mark of Didier
// case 28114: break;
// // Communique Timer, camp
// case 28346: break;
// // Icebolt
// case 28522: break;
// // Silithyst
// case 29519: break;
case 29528: // Inoculate Nestlewood Owlkin
// prevent error reports in case ignored player target
if (triggerTarget->GetTypeId() != TYPEID_UNIT)
return;
break;
// // Overload
// case 29768: break;
// // Return Fire
// case 29788: break;
// // Return Fire
// case 29793: break;
// // Return Fire
// case 29794: break;
// // Guardian of Icecrown Passive
// case 29897: break;
case 29917: // Feed Captured Animal
trigger_spell_id = 29916;
break;
// // Flame Wreath
// case 29946: break;
// // Flame Wreath
// case 29947: break;
// // Mind Exhaustion Passive
// case 30025: break;
// // Nether Beam - Serenity
// case 30401: break;
case 30427: // Extract Gas
{
Unit* caster = GetCaster();
if (!caster)
return;
// move loot to player inventory and despawn target
if (caster->GetTypeId() ==TYPEID_PLAYER &&
triggerTarget->GetTypeId() == TYPEID_UNIT &&
((Creature*)triggerTarget)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD)
{
Player* player = (Player*)caster;
Creature* creature = (Creature*)triggerTarget;
// missing lootid has been reported on startup - just return
if (!creature->GetCreatureInfo()->SkinLootId)
return;
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true);
creature->ForcedDespawn();
}
return;
}
case 30576: // Quake
trigger_spell_id = 30571;
break;
// // Burning Maul
// case 30598: break;
// // Regeneration
// case 30799:
// case 30800:
// case 30801:
// break;
// // Despawn Self - Smoke cloud
// case 31269: break;
// // Time Rift Periodic
// case 31320: break;
// // Corrupt Medivh
// case 31326: break;
case 31347: // Doom
{
target->CastSpell(target,31350,true);
target->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
case 31373: // Spellcloth
{
// Summon Elemental after create item
triggerTarget->SummonCreature(17870, 0.0f, 0.0f, 0.0f, triggerTarget->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
return;
}
// // Bloodmyst Tesla
// case 31611: break;
case 31944: // Doomfire
{
int32 damage = m_modifier.m_amount * ((GetAuraDuration() + m_modifier.periodictime) / GetAuraMaxDuration());
triggerTarget->CastCustomSpell(triggerTarget, 31969, &damage, NULL, NULL, true, NULL, this, casterGUID);
return;
}
// // Teleport Test
// case 32236: break;
// // Earthquake
// case 32686: break;
// // Possess
// case 33401: break;
// // Draw Shadows
// case 33563: break;
// // Murmur's Touch
// case 33711: break;
case 34229: // Flame Quills
{
// cast 24 spells 34269-34289, 34314-34316
for(uint32 spell_id = 34269; spell_id != 34290; ++spell_id)
triggerTarget->CastSpell(triggerTarget, spell_id, true, NULL, this, casterGUID);
for(uint32 spell_id = 34314; spell_id != 34317; ++spell_id)
triggerTarget->CastSpell(triggerTarget, spell_id, true, NULL, this, casterGUID);
return;
}
// // Gravity Lapse
// case 34480: break;
// // Tornado
// case 34683: break;
// // Frostbite Rotate
// case 34748: break;
// // Arcane Flurry
// case 34821: break;
// // Interrupt Shutdown
// case 35016: break;
// // Interrupt Shutdown
// case 35176: break;
// // Inferno
// case 35268: break;
// // Salaadin's Tesla
// case 35515: break;
// // Ethereal Channel (Red)
// case 35518: break;
// // Nether Vapor
// case 35879: break;
// // Dark Portal Storm
// case 36018: break;
// // Burning Maul
// case 36056: break;
// // Living Grove Defender Lifespan
// case 36061: break;
// // Professor Dabiri Talks
// case 36064: break;
// // Kael Gaining Power
// case 36091: break;
// // They Must Burn Bomb Aura
// case 36344: break;
// // They Must Burn Bomb Aura (self)
// case 36350: break;
// // Stolen Ravenous Ravager Egg
// case 36401: break;
// // Activated Cannon
// case 36410: break;
// // Stolen Ravenous Ravager Egg
// case 36418: break;
// // Enchanted Weapons
// case 36510: break;
// // Cursed Scarab Periodic
// case 36556: break;
// // Cursed Scarab Despawn Periodic
// case 36561: break;
// // Vision Guide
// case 36573: break;
// // Cannon Charging (platform)
// case 36785: break;
// // Cannon Charging (self)
// case 36860: break;
case 37027: // Remote Toy
trigger_spell_id = 37029;
break;
// // Mark of Death
// case 37125: break;
// // Arcane Flurry
// case 37268: break;
// // Spout
// case 37429: break;
// // Spout
// case 37430: break;
// // Karazhan - Chess NPC AI, Snapshot timer
// case 37440: break;
// // Karazhan - Chess NPC AI, action timer
// case 37504: break;
// // Karazhan - Chess: Is Square OCCUPIED aura (DND)
// case 39400: break;
// // Banish
// case 37546: break;
// // Shriveling Gaze
// case 37589: break;
// // Fake Aggro Radius (2 yd)
// case 37815: break;
// // Corrupt Medivh
// case 37853: break;
case 38495: // Eye of Grillok
{
target->CastSpell(target, 38530, true);
return;
}
case 38554: // Absorb Eye of Grillok (Zezzak's Shard)
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
if (Unit* caster = GetCaster())
caster->CastSpell(caster, 38495, true, NULL, this);
else
return;
Creature* creatureTarget = (Creature*)target;
creatureTarget->ForcedDespawn();
return;
}
// // Magic Sucker Device timer
// case 38672: break;
// // Tomb Guarding Charging
// case 38751: break;
// // Murmur's Touch
// case 38794: break;
case 39105: // Activate Nether-wraith Beacon (31742 Nether-wraith Beacon item)
{
float fX, fY, fZ;
triggerTarget->GetClosePoint(fX, fY, fZ, triggerTarget->GetObjectBoundingRadius(), 20.0f);
triggerTarget->SummonCreature(22408, fX, fY, fZ, triggerTarget->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
return;
}
// // Drain World Tree Visual
// case 39140: break;
// // Quest - Dustin's Undead Dragon Visual aura
// case 39259: break;
// // Hellfire - The Exorcism, Jules releases darkness, aura
// case 39306: break;
// // Inferno
// case 39346: break;
// // Enchanted Weapons
// case 39489: break;
// // Shadow Bolt Whirl
// case 39630: break;
// // Shadow Bolt Whirl
// case 39634: break;
// // Shadow Inferno
// case 39645: break;
case 39857: // Tear of Azzinoth Summon Channel - it's not really supposed to do anything,and this only prevents the console spam
trigger_spell_id = 39856;
break;
// // Soulgrinder Ritual Visual (Smashed)
// case 39974: break;
// // Simon Game Pre-game timer
// case 40041: break;
// // Knockdown Fel Cannon: The Aggro Check Aura
// case 40113: break;
// // Spirit Lance
// case 40157: break;
// // Demon Transform 2
// case 40398: break;
// // Demon Transform 1
// case 40511: break;
// // Ancient Flames
// case 40657: break;
// // Ethereal Ring Cannon: Cannon Aura
// case 40734: break;
// // Cage Trap
// case 40760: break;
// // Random Periodic
// case 40867: break;
// // Prismatic Shield
// case 40879: break;
// // Aura of Desire
// case 41350: break;
// // Dementia
// case 41404: break;
// // Chaos Form
// case 41629: break;
// // Alert Drums
// case 42177: break;
// // Spout
// case 42581: break;
// // Spout
// case 42582: break;
// // Return to the Spirit Realm
// case 44035: break;
// // Curse of Boundless Agony
// case 45050: break;
// // Earthquake
// case 46240: break;
case 46736: // Personalized Weather
trigger_spell_id = 46737;
break;
// // Stay Submerged
// case 46981: break;
// // Dragonblight Ram
// case 47015: break;
// // Party G.R.E.N.A.D.E.
// case 51510: break;
// // Horseman Abilities
// case 52347: break;
// // GPS (Greater drake Positioning System)
// case 53389: break;
// // WotLK Prologue Frozen Shade Summon Aura
// case 53459: break;
// // WotLK Prologue Frozen Shade Speech
// case 53460: break;
// // WotLK Prologue Dual-plagued Brain Summon Aura
// case 54295: break;
// // WotLK Prologue Dual-plagued Brain Speech
// case 54299: break;
// // Rotate 360 (Fast)
// case 55861: break;
// // Shadow Sickle
// case 56702: break;
// // Portal Periodic
// case 58008: break;
// // Destroy Door Seal
// case 58040: break;
// // Draw Magic
// case 58185: break;
// // Food
// case 58886: break;
// // Shadow Sickle
// case 59103: break;
// // Time Bomb
// case 59376: break;
// // Whirlwind Visual
// case 59551: break;
// // Hearstrike
// case 59783: break;
// // Z Check
// case 61678: break;
// // isDead Check
// case 61976: break;
// // Start the Engine
// case 62432: break;
// // Enchanted Broom
// case 62571: break;
// // Mulgore Hatchling
// case 62586: break;
// Durotar Scorpion
case 62679:
trigger_spell_id = auraSpellInfo->CalculateSimpleValue(m_effIndex);
break;
// // Fighting Fish
// case 62833: break;
// // Shield Level 1
// case 63130: break;
// // Shield Level 2
// case 63131: break;
// // Shield Level 3
// case 63132: break;
// // Food
// case 64345: break;
// // Remove Player from Phase
// case 64445: break;
// // Food
// case 65418: break;
// // Food
// case 65419: break;
// // Food
// case 65420: break;
// // Food
// case 65421: break;
// // Food
// case 65422: break;
// // Rolling Throw
// case 67546: break;
// // Gunship Cannon Fire
// case 70017: break;
// // Ice Tomb
// case 70157: break;
// // Mana Barrier
// case 70842: break;
// // Summon Timer: Suppresser
// case 70912: break;
// // Aura of Darkness
// case 71110: break;
// // Aura of Darkness
// case 71111: break;
// // Ball of Flames Visual
// case 71706: break;
// // Summon Broken Frostmourne
// case 74081: break;
default:
break;
}
break;
}
case SPELLFAMILY_MAGE:
{
switch(auraId)
{
case 66: // Invisibility
// Here need periodic trigger reducing threat spell (or do it manually)
return;
default:
break;
}
break;
}
// case SPELLFAMILY_WARRIOR:
// {
// switch(auraId)
// {
// // Wild Magic
// case 23410: break;
// // Corrupted Totems
// case 23425: break;
// default:
// break;
// }
// break;
// }
// case SPELLFAMILY_PRIEST:
// {
// switch(auraId)
// {
// // Blue Beam
// case 32930: break;
// // Fury of the Dreghood Elders
// case 35460: break;
// default:
// break;
// }
// break;
// }
case SPELLFAMILY_HUNTER:
{
switch (auraId)
{
case 53302: // Sniper training
case 53303:
case 53304:
if (triggerTarget->GetTypeId() != TYPEID_PLAYER)
return;
// Reset reapply counter at move
if (((Player*)triggerTarget)->isMoving())
{
m_modifier.m_amount = 6;
return;
}
// We are standing at the moment
if (m_modifier.m_amount > 0)
{
--m_modifier.m_amount;
return;
}
// select rank of buff
switch(auraId)
{
case 53302: trigger_spell_id = 64418; break;
case 53303: trigger_spell_id = 64419; break;
case 53304: trigger_spell_id = 64420; break;
}
// If aura is active - no need to continue
if (triggerTarget->HasAura(trigger_spell_id))
return;
break;
default:
break;
}
break;
}
case SPELLFAMILY_DRUID:
{
switch(auraId)
{
case 768: // Cat Form
// trigger_spell_id not set and unknown effect triggered in this case, ignoring for while
return;
case 22842: // Frenzied Regeneration
case 22895:
case 22896:
case 26999:
{
int32 LifePerRage = GetModifier()->m_amount;
int32 lRage = target->GetPower(POWER_RAGE);
if (lRage > 100) // rage stored as rage*10
lRage = 100;
target->ModifyPower(POWER_RAGE, -lRage);
int32 FRTriggerBasePoints = int32(lRage*LifePerRage/10);
target->CastCustomSpell(target, 22845, &FRTriggerBasePoints, NULL, NULL, true, NULL, this);
return;
}
default:
break;
}
break;
}
// case SPELLFAMILY_HUNTER:
// {
// switch(auraId)
// {
// //Frost Trap Aura
// case 13810:
// return;
// //Rizzle's Frost Trap
// case 39900:
// return;
// // Tame spells
// case 19597: // Tame Ice Claw Bear
// case 19676: // Tame Snow Leopard
// case 19677: // Tame Large Crag Boar
// case 19678: // Tame Adult Plainstrider
// case 19679: // Tame Prairie Stalker
// case 19680: // Tame Swoop
// case 19681: // Tame Dire Mottled Boar
// case 19682: // Tame Surf Crawler
// case 19683: // Tame Armored Scorpid
// case 19684: // Tame Webwood Lurker
// case 19685: // Tame Nightsaber Stalker
// case 19686: // Tame Strigid Screecher
// case 30100: // Tame Crazed Dragonhawk
// case 30103: // Tame Elder Springpaw
// case 30104: // Tame Mistbat
// case 30647: // Tame Barbed Crawler
// case 30648: // Tame Greater Timberstrider
// case 30652: // Tame Nightstalker
// return;
// default:
// break;
// }
// break;
// }
case SPELLFAMILY_SHAMAN:
{
switch(auraId)
{
case 28820: // Lightning Shield (The Earthshatterer set trigger after cast Lighting Shield)
{
// Need remove self if Lightning Shield not active
Unit::SpellAuraHolderMap const& auras = triggerTarget->GetSpellAuraHolderMap();
for(Unit::SpellAuraHolderMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
SpellEntry const* spell = itr->second->GetSpellProto();
if (spell->SpellFamilyName == SPELLFAMILY_SHAMAN &&
(spell->SpellFamilyFlags & UI64LIT(0x0000000000000400)))
return;
}
triggerTarget->RemoveAurasDueToSpell(28820);
return;
}
case 38443: // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus)
{
if (triggerTarget->IsAllTotemSlotsUsed())
triggerTarget->CastSpell(triggerTarget, 38437, true, NULL, this);
else
triggerTarget->RemoveAurasDueToSpell(38437);
return;
}
default:
break;
}
break;
}
default:
break;
}
// Reget trigger spell proto
triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
}
else
{
// Spell exist but require custom code
switch(auraId)
{
case 9347: // Mortal Strike
{
// expected selection current fight target
triggerTarget = GetTarget()->getVictim();
if (!triggerTarget)
return;
// avoid triggering for far target
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(triggeredSpellInfo->rangeIndex);
float max_range = GetSpellMaxRange(srange);
if (!triggerTarget->IsWithinDist(GetTarget(),max_range))
return;
break;
}
case 1010: // Curse of Idiocy
{
// TODO: spell casted by result in correct way mostly
// BUT:
// 1) target show casting at each triggered cast: target don't must show casting animation for any triggered spell
// but must show affect apply like item casting
// 2) maybe aura must be replace by new with accumulative stat mods instead stacking
// prevent cast by triggered auras
if (casterGUID == triggerTarget->GetObjectGuid())
return;
// stop triggering after each affected stats lost > 90
int32 intelectLoss = 0;
int32 spiritLoss = 0;
Unit::AuraList const& mModStat = triggerTarget->GetAurasByType(SPELL_AURA_MOD_STAT);
for(Unit::AuraList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i)
{
if ((*i)->GetId() == 1010)
{
switch((*i)->GetModifier()->m_miscvalue)
{
case STAT_INTELLECT: intelectLoss += (*i)->GetModifier()->m_amount; break;
case STAT_SPIRIT: spiritLoss += (*i)->GetModifier()->m_amount; break;
default: break;
}
}
}
if (intelectLoss <= -90 && spiritLoss <= -90)
return;
break;
}
case 16191: // Mana Tide
{
triggerTarget->CastCustomSpell(triggerTarget, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this);
return;
}
case 33525: // Ground Slam
triggerTarget->CastSpell(triggerTarget, trigger_spell_id, true, NULL, this, casterGUID);
return;
case 38736: // Rod of Purification - for quest 10839 (Veil Skith: Darkstone of Terokk)
{
if (Unit* caster = GetCaster())
caster->CastSpell(triggerTarget, trigger_spell_id, true, NULL, this);
return;
}
case 53563: // Beacon of Light
// original caster must be target (beacon)
target->CastSpell(target, trigger_spell_id, true, NULL, this, target->GetObjectGuid());
return;
case 56654: // Rapid Recuperation (triggered energize have baspioints == 0)
case 58882:
{
int32 mana = target->GetMaxPower(POWER_MANA) * m_modifier.m_amount / 100;
triggerTarget->CastCustomSpell(triggerTarget, trigger_spell_id, &mana, NULL, NULL, true, NULL, this);
return;
}
}
}
Unit* triggerCaster = triggerTarget;
WorldObject* triggerTargetObject = NULL;
// for channeled spell cast applied from aura owner to channel target (persistent aura affects already applied to true target)
// come periodic casts applied to targets, so need seelct proper caster (ex. 15790)
if (IsChanneledSpell(GetSpellProto()) && GetSpellProto()->Effect[GetEffIndex()] != SPELL_EFFECT_PERSISTENT_AREA_AURA)
{
// interesting 2 cases: periodic aura at caster of channeled spell
if (target->GetObjectGuid() == casterGUID)
{
triggerCaster = target;
if (WorldObject* channelTarget = target->GetMap()->GetWorldObject(target->GetChannelObjectGuid()))
{
if (channelTarget->isType(TYPEMASK_UNIT))
triggerTarget = (Unit*)channelTarget;
else
triggerTargetObject = channelTarget;
}
}
// or periodic aura at caster channel target
else if (Unit* caster = GetCaster())
{
if (target->GetObjectGuid() == caster->GetChannelObjectGuid())
{
triggerCaster = caster;
triggerTarget = target;
}
}
}
// All ok cast by default case
if (triggeredSpellInfo)
{
if (triggerTargetObject)
triggerCaster->CastSpell(triggerTargetObject->GetPositionX(), triggerTargetObject->GetPositionY(), triggerTargetObject->GetPositionZ(),
triggeredSpellInfo, true, NULL, this, casterGUID);
else
triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this, casterGUID);
}
else
{
if (Unit* caster = GetCaster())
{
if (triggerTarget->GetTypeId() != TYPEID_UNIT || !sScriptMgr.OnEffectDummy(caster, GetId(), GetEffIndex(), (Creature*)triggerTarget))
sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
}
}
}
void Aura::TriggerSpellWithValue()
{
ObjectGuid casterGuid = GetCasterGuid();
Unit* target = GetTriggerTarget();
if (!casterGuid || !target)
return;
// generic casting code with custom spells and target/caster customs
uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
int32 basepoints0 = GetModifier()->m_amount;
target->CastCustomSpell(target, trigger_spell_id, &basepoints0, NULL, NULL, true, NULL, this, casterGuid);
}
/*********************************************************/
/*** AURA EFFECTS ***/
/*********************************************************/
void Aura::HandleAuraDummy(bool apply, bool Real)
{
// spells required only Real aura add/remove
if (!Real)
return;
Unit *target = GetTarget();
// AT APPLY
if (apply)
{
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
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 (target->CanHaveThreatList())
if (Unit* caster = GetCaster())
target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
return;
case 7057: // Haunting Spirits
// expected to tick with 30 sec period (tick part see in Aura::PeriodicTick)
m_isPeriodic = true;
m_modifier.periodictime = 30*IN_MILLISECONDS;
m_periodicTimer = m_modifier.periodictime;
return;
case 10255: // Stoned
{
if (Unit* caster = GetCaster())
{
if (caster->GetTypeId() != TYPEID_UNIT)
return;
caster->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
caster->addUnitState(UNIT_STAT_ROOT);
}
return;
}
case 13139: // net-o-matic
// root to self part of (root_target->charge->root_self sequence
if (Unit* caster = GetCaster())
caster->CastSpell(caster, 13138, true, NULL, this);
return;
case 31606: // Stormcrow Amulet
{
CreatureInfo const * cInfo = ObjectMgr::GetCreatureTemplate(17970);
// we must assume db or script set display id to native at ending flight (if not, target is stuck with this model)
if (cInfo)
target->SetDisplayId(Creature::ChooseDisplayId(cInfo));
return;
}
case 32045: // Soul Charge
case 32051:
case 32052:
{
// max duration is 2 minutes, but expected to be random duration
// real time randomness is unclear, using max 30 seconds here
// see further down for expire of this aura
GetHolder()->SetAuraDuration(urand(1, 30)*IN_MILLISECONDS);
return;
}
// Gender spells
case 38224: // Illidari Agent Illusion
case 37096: // Blood Elf Illusion
case 46354: // Blood Elf Illusion
{
uint8 gender = target->getGender();
uint32 spellId;
switch (GetId())
{
case 38224: spellId = (gender == GENDER_MALE ? 38225 : 38227); break;
case 37096: spellId = (gender == GENDER_MALE ? 37092 : 37094); break;
case 46354: spellId = (gender == GENDER_MALE ? 46355 : 46356); break;
default: return;
}
target->CastSpell(target, spellId, true, NULL, this);
return;
}
case 39850: // Rocket Blast
if (roll_chance_i(20)) // backfire stun
target->CastSpell(target, 51581, true, NULL, this);
return;
case 43873: // Headless Horseman Laugh
target->PlayDistanceSound(11965);
return;
case 45963: // Call Alliance Deserter
{
// Escorting Alliance Deserter
if (target->GetMiniPet())
target->CastSpell(target, 45957, true);
return;
}
case 46699: // Requires No Ammo
if (target->GetTypeId() == TYPEID_PLAYER)
// not use ammo and not allow use
((Player*)target)->RemoveAmmo();
return;
case 47190: // Toalu'u's Spiritual Incense
target->CastSpell(target, 47189, true, NULL, this);
// allow script to process further (text)
break;
case 48025: // Headless Horseman's Mount
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 51621, 48024, 51617, 48023, 0);
return;
case 48143: // Forgotten Aura
// See Death's Door
target->CastSpell(target, 48814, true, NULL, this);
return;
case 51405: // Digging for Treasure
target->HandleEmote(EMOTE_STATE_WORK);
// Pet will be following owner, this makes him stop
target->addUnitState(UNIT_STAT_STUNNED);
return;
case 54729: // Winged Steed of the Ebon Blade
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 54726, 54727, 0);
return;
case 62061: // Festive Holiday Mount
if (target->HasAuraType(SPELL_AURA_MOUNTED))
// Reindeer Transformation
target->CastSpell(target, 25860, true, NULL, this);
return;
case 62109: // Tails Up: Aura
target->setFaction(1990); // Ambient (hostile)
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
return;
case 63624: // Learn a Second Talent Specialization
// Teach Learn Talent Specialization Switches, required for client triggered casts, allow after 30 sec delay
if (target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->learnSpell(63680, false);
return;
case 63651: // Revert to One Talent Specialization
// Teach Learn Talent Specialization Switches, remove
if (target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->removeSpell(63680);
return;
case 71342: // Big Love Rocket
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 71344, 71345, 71346, 71347, 0);
return;
case 71563: // Deadly Precision
target->CastSpell(target, 71564, true, NULL, this);
return;
case 72286: // Invincible
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 72281, 72282, 72283, 72284, 0);
return;
case 74856: // Blazing Hippogryph
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 74854, 74855, 0);
return;
case 75614: // Celestial Steed
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 75619, 75620, 75617, 75618, 76153);
return;
case 75973: // X-53 Touring Rocket
Spell::SelectMountByAreaAndSkill(target, GetSpellProto(), 0, 0, 75957, 75972, 76154);
return;
}
break;
}
case SPELLFAMILY_WARRIOR:
{
switch(GetId())
{
case 41099: // Battle Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 41102, true, NULL, this);
// Battle Aura
target->CastSpell(target, 41106, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 32614);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
case 41100: // Berserker Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 41102, true, NULL, this);
// Berserker Aura
target->CastSpell(target, 41107, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 32614);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
case 41101: // Defensive Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 41102, true, NULL, this);
// Defensive Aura
target->CastSpell(target, 41105, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 32604);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 31467);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
case 53790: // Defensive Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 59526, true, NULL, this);
// Defensive Aura
target->CastSpell(target, 41105, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 43625);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 39384);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
case 53791: // Berserker Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 59526, true, NULL, this);
// Berserker Aura
target->CastSpell(target, 41107, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 43625);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 43625);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
case 53792: // Battle Stance
{
if (target->GetTypeId() != TYPEID_UNIT)
return;
// Stance Cooldown
target->CastSpell(target, 59526, true, NULL, this);
// Battle Aura
target->CastSpell(target, 41106, true, NULL, this);
// equipment
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_0, 43623);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_1, 0);
((Creature*)target)->SetVirtualItem(VIRTUAL_ITEM_SLOT_2, 0);
return;
}
}
// Overpower
if (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000004))
{
// Must be casting target
if (!target->IsNonMeleeSpellCasted(false))
return;
Unit* caster = GetCaster();
if (!caster)
return;
Unit::AuraList const& modifierAuras = caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
for(Unit::AuraList::const_iterator itr = modifierAuras.begin(); itr != modifierAuras.end(); ++itr)
{
// Unrelenting Assault
if ((*itr)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARRIOR && (*itr)->GetSpellProto()->SpellIconID == 2775)
{
switch ((*itr)->GetSpellProto()->Id)
{
case 46859: // Unrelenting Assault, rank 1
target->CastSpell(target,64849,true,NULL,(*itr));
break;
case 46860: // Unrelenting Assault, rank 2
target->CastSpell(target,64850,true,NULL,(*itr));
break;
default:
break;
}
break;
}
}
return;
}
break;
}
case SPELLFAMILY_MAGE:
break;
case SPELLFAMILY_HUNTER:
{
switch(GetId())
{
case 34026: // Kill Command
target->CastSpell(target, 34027, true, NULL, this);
return;
}
break;
}
case SPELLFAMILY_SHAMAN:
{
switch(GetId())
{
case 55198: // Tidal Force
target->CastSpell(target, 55166, true, NULL, this);
return;
}
// Earth Shield
if ((GetSpellProto()->SpellFamilyFlags & UI64LIT(0x40000000000)))
{
// prevent double apply bonuses
if (target->GetTypeId() != TYPEID_PLAYER || !((Player*)target)->GetSession()->PlayerLoading())
{
if (Unit* caster = GetCaster())
{
m_modifier.m_amount = caster->SpellHealingBonusDone(target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
m_modifier.m_amount = target->SpellHealingBonusTaken(caster, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
}
}
return;
}
break;
}
}
}
// AT REMOVE
else
{
if (IsQuestTameSpell(GetId()) && target->isAlive())
{
Unit* caster = GetCaster();
if (!caster || !caster->isAlive())
return;
uint32 finalSpellId = 0;
switch(GetId())
{
case 19548: finalSpellId = 19597; break;
case 19674: finalSpellId = 19677; break;
case 19687: finalSpellId = 19676; break;
case 19688: finalSpellId = 19678; break;
case 19689: finalSpellId = 19679; break;
case 19692: finalSpellId = 19680; break;
case 19693: finalSpellId = 19684; break;
case 19694: finalSpellId = 19681; break;
case 19696: finalSpellId = 19682; break;
case 19697: finalSpellId = 19683; break;
case 19699: finalSpellId = 19685; break;
case 19700: finalSpellId = 19686; break;
case 30646: finalSpellId = 30647; break;
case 30653: finalSpellId = 30648; break;
case 30654: finalSpellId = 30652; break;
case 30099: finalSpellId = 30100; break;
case 30102: finalSpellId = 30103; break;
case 30105: finalSpellId = 30104; break;
}
if (finalSpellId)
caster->CastSpell(target, finalSpellId, true, NULL, this);
return;
}
switch(GetId())
{
case 10255: // Stoned
{
if (Unit* caster = GetCaster())
{
if (caster->GetTypeId() != TYPEID_UNIT)
return;
// see dummy effect of spell 10254 for removal of flags etc
caster->CastSpell(caster, 10254, true);
}
return;
}
case 12479: // Hex of Jammal'an
target->CastSpell(target, 12480, true, NULL, this);
return;
case 12774: // (DND) Belnistrasz Idol Shutdown Visual
{
if (m_removeMode == AURA_REMOVE_BY_DEATH)
return;
// Idom Rool Camera Shake <- wtf, don't drink while making spellnames?
if (Unit* caster = GetCaster())
caster->CastSpell(caster, 12816, true);
return;
}
case 28169: // Mutating Injection
{
// Mutagen Explosion
target->CastSpell(target, 28206, true, NULL, this);
// Poison Cloud
target->CastSpell(target, 28240, true, NULL, this);
return;
}
case 32045: // Soul Charge
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 32054, true, NULL, this);
return;
}
case 32051: // Soul Charge
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 32057, true, NULL, this);
return;
}
case 32052: // Soul Charge
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 32053, true, NULL, this);
return;
}
case 32286: // Focus Target Visual
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 32301, true, NULL, this);
return;
}
case 35079: // Misdirection, triggered buff
case 59628: // Tricks of the Trade, triggered buff
{
if (Unit* pCaster = GetCaster())
pCaster->getHostileRefManager().ResetThreatRedirection();
return;
}
case 36730: // Flame Strike
{
target->CastSpell(target, 36731, true, NULL, this);
return;
}
case 41099: // Battle Stance
{
// Battle Aura
target->RemoveAurasDueToSpell(41106);
return;
}
case 41100: // Berserker Stance
{
// Berserker Aura
target->RemoveAurasDueToSpell(41107);
return;
}
case 41101: // Defensive Stance
{
// Defensive Aura
target->RemoveAurasDueToSpell(41105);
return;
}
case 42454: // Captured Totem
{
if (m_removeMode == AURA_REMOVE_BY_DEFAULT)
{
if (target->getDeathState() != CORPSE)
return;
Unit* pCaster = GetCaster();
if (!pCaster)
return;
// Captured Totem Test Credit
if (Player* pPlayer = pCaster->GetCharmerOrOwnerPlayerOrPlayerItself())
pPlayer->CastSpell(pPlayer, 42455, true);
}
return;
}
case 42517: // Beam to Zelfrax
{
// expecting target to be a dummy creature
Creature* pSummon = target->SummonCreature(23864, 0.0f, 0.0f, 0.0f, target->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
Unit* pCaster = GetCaster();
if (pSummon && pCaster)
pSummon->GetMotionMaster()->MovePoint(0, pCaster->GetPositionX(), pCaster->GetPositionY(), pCaster->GetPositionZ());
return;
}
case 43969: // Feathered Charm
{
// Steelfeather Quest Credit, Are there any requirements for this, like area?
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 43984, true);
return;
}
case 44191: // Flame Strike
{
if (target->GetMap()->IsDungeon())
{
uint32 spellId = target->GetMap()->IsRegularDifficulty() ? 44190 : 46163;
target->CastSpell(target, spellId, true, NULL, this);
}
return;
}
case 45934: // Dark Fiend
{
// Kill target if dispelled
if (m_removeMode==AURA_REMOVE_BY_DISPEL)
target->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
case 45963: // Call Alliance Deserter
{
// Escorting Alliance Deserter
target->RemoveAurasDueToSpell(45957);
return;
}
case 46308: // Burning Winds
{
// casted only at creatures at spawn
target->CastSpell(target, 47287, true, NULL, this);
return;
}
case 50141: // Blood Oath
{
// Blood Oath
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 50001, true, NULL, this);
return;
}
case 51405: // Digging for Treasure
{
const uint32 spell_list[7] =
{
51441, // hare
51397, // crystal
51398, // armor
51400, // gem
51401, // platter
51402, // treasure
51443 // bug
};
target->CastSpell(target, spell_list[urand(0,6)], true);
target->HandleEmote(EMOTE_STATE_NONE);
target->clearUnitState(UNIT_STAT_STUNNED);
return;
}
case 51870: // Collect Hair Sample
{
if (Unit* pCaster = GetCaster())
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
pCaster->CastSpell(target, 51872, true, NULL, this);
}
return;
}
case 52098: // Charge Up
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 52092, true, NULL, this);
return;
}
case 53039: // Deploy Parachute
{
// Crusader Parachute
target->RemoveAurasDueToSpell(53031);
return;
}
case 53790: // Defensive Stance
{
// Defensive Aura
target->RemoveAurasDueToSpell(41105);
return;
}
case 53791: // Berserker Stance
{
// Berserker Aura
target->RemoveAurasDueToSpell(41107);
return;
}
case 53792: // Battle Stance
{
// Battle Aura
target->RemoveAurasDueToSpell(41106);
return;
}
case 56511: // Towers of Certain Doom: Tower Bunny Smoke Flare Effect
{
// Towers of Certain Doom: Skorn Cannonfire
if (m_removeMode == AURA_REMOVE_BY_DEFAULT)
target->CastSpell(target, 43069, true);
return;
}
case 58600: // Restricted Flight Area
{
AreaTableEntry const* area = GetAreaEntryByAreaID(target->GetAreaId());
// Dalaran restricted flight zone (recheck before apply unmount)
if (area && target->GetTypeId() == TYPEID_PLAYER && (area->flags & AREA_FLAG_CANNOT_FLY) &&
((Player*)target)->IsFreeFlying() && !((Player*)target)->isGameMaster())
{
target->CastSpell(target, 58601, true); // Remove Flight Auras (also triggered Parachute (45472))
}
return;
}
case 68839: // Corrupt Soul
{
// Knockdown Stun
target->CastSpell(target, 68848, true, NULL, this);
// Draw Corrupted Soul
target->CastSpell(target, 68846, true, NULL, this);
return;
}
}
// Living Bomb
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x2000000000000)))
{
if (m_removeMode == AURA_REMOVE_BY_EXPIRE || m_removeMode == AURA_REMOVE_BY_DISPEL)
target->CastSpell(target,m_modifier.m_amount,true,NULL,this);
return;
}
}
// AT APPLY & REMOVE
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch(GetId())
{
case 6606: // Self Visual - Sleep Until Cancelled (DND)
{
if (apply)
{
target->SetStandState(UNIT_STAND_STATE_SLEEP);
target->addUnitState(UNIT_STAT_ROOT);
}
else
{
target->clearUnitState(UNIT_STAT_ROOT);
target->SetStandState(UNIT_STAND_STATE_STAND);
}
return;
}
case 11196: // Recently Bandaged
target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply);
return;
case 24658: // Unstable Power
{
if (apply)
{
Unit* caster = GetCaster();
if (!caster)
return;
caster->CastSpell(target, 24659, true, NULL, NULL, GetCasterGuid());
}
else
target->RemoveAurasDueToSpell(24659);
return;
}
case 24661: // Restless Strength
{
if (apply)
{
Unit* caster = GetCaster();
if (!caster)
return;
caster->CastSpell(target, 24662, true, NULL, NULL, GetCasterGuid());
}
else
target->RemoveAurasDueToSpell(24662);
return;
}
case 29266: // Permanent Feign Death
case 31261: // Permanent Feign Death (Root)
case 37493: // Feign Death
case 52593: // Bloated Abomination Feign Death
case 55795: // Falling Dragon Feign Death
case 57626: // Feign Death
case 57685: // Permanent Feign Death
case 58768: // Permanent Feign Death (Freeze Jumpend)
case 58806: // Permanent Feign Death (Drowned Anim)
case 58951: // Permanent Feign Death
case 64461: // Permanent Feign Death (No Anim) (Root)
case 65985: // Permanent Feign Death (Root Silence Pacify)
case 70592: // Permanent Feign Death
case 70628: // Permanent Feign Death
case 70630: // Frozen Aftermath - Feign Death
case 71598: // Feign Death
{
// Unclear what the difference really is between them.
// Some has effect1 that makes the difference, however not all.
// Some appear to be used depending on creature location, in water, at solid ground, in air/suspended, etc
// For now, just handle all the same way
if (target->GetTypeId() == TYPEID_UNIT)
target->SetFeignDeath(apply);
return;
}
case 35356: // Spawn Feign Death
case 35357: // Spawn Feign Death
case 42557: // Feign Death
case 51329: // Feign Death
{
if (target->GetTypeId() == TYPEID_UNIT)
{
// Flags not set like it's done in SetFeignDeath()
// UNIT_DYNFLAG_DEAD does not appear with these spells.
// All of the spells appear to be present at spawn and not used to feign in combat or similar.
if (apply)
{
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
target->addUnitState(UNIT_STAT_DIED);
}
else
{
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
target->clearUnitState(UNIT_STAT_DIED);
}
}
return;
}
case 40133: //Summon Fire Elemental
{
Unit* caster = GetCaster();
if (!caster)
return;
Unit *owner = caster->GetOwner();
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
{
if (apply)
owner->CastSpell(owner, 8985, true);
else
((Player*)owner)->RemovePet(PET_SAVE_REAGENTS);
}
return;
}
case 40132: //Summon Earth Elemental
{
Unit* caster = GetCaster();
if (!caster)
return;
Unit *owner = caster->GetOwner();
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
{
if (apply)
owner->CastSpell(owner, 19704, true);
else
((Player*)owner)->RemovePet(PET_SAVE_REAGENTS);
}
return;
}
case 40214: //Dragonmaw Illusion
{
if (apply)
{
target->CastSpell(target, 40216, true);
target->CastSpell(target, 42016, true);
}
else
{
target->RemoveAurasDueToSpell(40216);
target->RemoveAurasDueToSpell(42016);
}
return;
}
case 42515: // Jarl Beam
{
// aura animate dead (fainted) state for the duration, but we need to animate the death itself (correct way below?)
if (Unit* pCaster = GetCaster())
pCaster->ApplyModFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH, apply);
// Beam to Zelfrax at remove
if (!apply)
target->CastSpell(target, 42517, true);
return;
}
case 43874: // Scourge Mur'gul Camp: Force Shield Arcane Purple x3
target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE, apply);
if (apply)
target->addUnitState(UNIT_STAT_ROOT);
return;
case 47178: // Plague Effect Self
target->SetFeared(apply, GetCasterGuid(), GetId());
return;
case 56422: // Nerubian Submerge
// not known if there are other things todo, only flag are confirmed valid
target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE, apply);
return;
case 58204: // LK Intro VO (1)
if (target->GetTypeId() == TYPEID_PLAYER)
{
// Play part 1
if (apply)
target->PlayDirectSound(14970, (Player *)target);
// continue in 58205
else
target->CastSpell(target, 58205, true);
}
return;
case 58205: // LK Intro VO (2)
if (target->GetTypeId() == TYPEID_PLAYER)
{
// Play part 2
if (apply)
target->PlayDirectSound(14971, (Player *)target);
// Play part 3
else
target->PlayDirectSound(14972, (Player *)target);
}
return;
case 40131:
case 27978:
if (apply)
target->m_AuraFlags |= UNIT_AURAFLAG_ALIVE_INVISIBLE;
else
target->m_AuraFlags |= ~UNIT_AURAFLAG_ALIVE_INVISIBLE;
return;
}
break;
}
case SPELLFAMILY_MAGE:
break;
case SPELLFAMILY_WARLOCK:
{
// Haunt
if (GetSpellProto()->SpellIconID == 3172 && (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0004000000000000)))
{
// NOTE: for avoid use additional field damage stored in dummy value (replace unused 100%
if (apply)
m_modifier.m_amount = 0; // use value as damage counter instead redundant 100% percent
else
{
int32 bp0 = m_modifier.m_amount;
if (Unit* caster = GetCaster())
target->CastCustomSpell(caster, 48210, &bp0, NULL, NULL, true, NULL, this);
}
}
break;
}
case SPELLFAMILY_PRIEST:
{
// Pain and Suffering
if (GetSpellProto()->SpellIconID == 2874 && target->GetTypeId()==TYPEID_PLAYER)
{
if (apply)
{
// Reduce backfire damage (dot damage) from Shadow Word: Death
// aura have wrong effectclassmask, so use hardcoded value
m_spellmod = new SpellModifier(SPELLMOD_DOT,SPELLMOD_PCT,m_modifier.m_amount,GetId(),UI64LIT(0x0000200000000000));
}
((Player*)target)->AddSpellMod(m_spellmod, apply);
return;
}
break;
}
case SPELLFAMILY_DRUID:
{
switch(GetId())
{
case 34246: // Idol of the Emerald Queen
case 60779: // Idol of Lush Moss
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
if (apply)
// dummy not have proper effectclassmask
m_spellmod = new SpellModifier(SPELLMOD_DOT,SPELLMOD_FLAT,m_modifier.m_amount/7,GetId(),UI64LIT(0x001000000000));
((Player*)target)->AddSpellMod(m_spellmod, apply);
return;
}
case 52610: // Savage Roar
{
if (apply)
{
if (target->GetShapeshiftForm() != FORM_CAT)
return;
target->CastSpell(target, 62071, true);
}
else
target->RemoveAurasDueToSpell(62071);
return;
}
case 61336: // Survival Instincts
{
if(apply)
{
if (!target->IsInFeralForm())
return;
int32 bp0 = int32(target->GetMaxHealth() * m_modifier.m_amount / 100);
target->CastCustomSpell(target, 50322, &bp0, NULL, NULL, true);
}
else
target->RemoveAurasDueToSpell(50322);
return;
}
}
// Lifebloom
if (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x1000000000))
{
if (apply)
{
if (Unit* caster = GetCaster())
{
// prevent double apply bonuses
if (target->GetTypeId() != TYPEID_PLAYER || !((Player*)target)->GetSession()->PlayerLoading())
{
m_modifier.m_amount = caster->SpellHealingBonusDone(target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
m_modifier.m_amount = target->SpellHealingBonusTaken(caster, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
}
}
}
else
{
// Final heal on duration end
if (m_removeMode != AURA_REMOVE_BY_EXPIRE)
return;
// final heal
if (target->IsInWorld() && GetStackAmount() > 0)
{
int32 amount = m_modifier.m_amount;
target->CastCustomSpell(target, 33778, &amount, NULL, NULL, true, NULL, this, GetCasterGuid());
if (Unit* caster = GetCaster())
{
int32 returnmana = (GetSpellProto()->ManaCostPercentage * caster->GetCreateMana() / 100) * GetStackAmount() / 2;
caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, this, GetCasterGuid());
}
}
}
return;
}
// Predatory Strikes
if (target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563)
{
((Player*)target)->UpdateAttackPowerAndDamage();
return;
}
// Improved Moonkin Form
if (GetSpellProto()->SpellIconID == 2855)
{
uint32 spell_id;
switch(GetId())
{
case 48384: spell_id = 50170; break; //Rank 1
case 48395: spell_id = 50171; break; //Rank 2
case 48396: spell_id = 50172; break; //Rank 3
default:
sLog.outError("HandleAuraDummy: Not handled rank of IMF (Spell: %u)",GetId());
return;
}
if (apply)
{
if (target->GetShapeshiftForm() != FORM_MOONKIN)
return;
target->CastSpell(target, spell_id, true);
}
else
target->RemoveAurasDueToSpell(spell_id);
return;
}
break;
}
case SPELLFAMILY_ROGUE:
switch(GetId())
{
case 57934: // Tricks of the Trade, main spell
{
if (apply)
GetHolder()->SetAuraCharges(1); // not have proper charges set in spell data
else
{
// used for direct in code aura removes and spell proc event charges expire
if (m_removeMode != AURA_REMOVE_BY_DEFAULT)
target->getHostileRefManager().ResetThreatRedirection();
}
return;
}
}
break;
case SPELLFAMILY_HUNTER:
switch(GetId())
{
case 34477: // Misdirection, main spell
{
if (apply)
GetHolder()->SetAuraCharges(1); // not have proper charges set in spell data
else
{
// used for direct in code aura removes and spell proc event charges expire
if (m_removeMode != AURA_REMOVE_BY_DEFAULT)
target->getHostileRefManager().ResetThreatRedirection();
}
return;
}
}
break;
case SPELLFAMILY_PALADIN:
switch(GetId())
{
case 20911: // Blessing of Sanctuary
case 25899: // Greater Blessing of Sanctuary
{
if (apply)
target->CastSpell(target, 67480, true, NULL, this);
else
target->RemoveAurasDueToSpell(67480);
return;
}
}
break;
case SPELLFAMILY_SHAMAN:
{
switch(GetId())
{
case 6495: // Sentry Totem
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
Totem* totem = target->GetTotem(TOTEM_SLOT_AIR);
if (totem && apply)
((Player*)target)->GetCamera().SetView(totem);
else
((Player*)target)->GetCamera().ResetView();
return;
}
}
break;
}
}
// pet auras
if (PetAura const* petSpell = sSpellMgr.GetPetAura(GetId(), m_effIndex))
{
if (apply)
target->AddPetAura(petSpell);
else
target->RemovePetAura(petSpell);
return;
}
if (GetEffIndex() == EFFECT_INDEX_0 && target->GetTypeId() == TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = sSpellMgr.GetSpellAreaForAuraMapBounds(GetId());
if (saBounds.first != saBounds.second)
{
uint32 zone, area;
target->GetZoneAndAreaId(zone, area);
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
// some auras remove at aura remove
if (!itr->second->IsFitToRequirements((Player*)target, zone, area))
target->RemoveAurasDueToSpell(itr->second->spellId);
// some auras applied at aura apply
else if (itr->second->autocast)
{
if (!target->HasAura(itr->second->spellId, EFFECT_INDEX_0))
target->CastSpell(target, itr->second->spellId, true);
}
}
}
}
// script has to "handle with care", only use where data are not ok to use in the above code.
if (target->GetTypeId() == TYPEID_UNIT)
sScriptMgr.OnAuraDummy(this, apply);
}
void Aura::HandleAuraMounted(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
Unit *target = GetTarget();
if(apply)
{
CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(m_modifier.m_miscvalue);
if(!ci)
{
sLog.outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need it modelid)", m_modifier.m_miscvalue);
return;
}
uint32 display_id = Creature::ChooseDisplayId(ci);
CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelRandomGender(display_id);
if (minfo)
display_id = minfo->modelid;
target->Mount(display_id, GetId());
}
else
{
target->Unmount(true);
}
}
void Aura::HandleAuraWaterWalk(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
WorldPacket data;
if(apply)
data.Initialize(SMSG_MOVE_WATER_WALK, 8+4);
else
data.Initialize(SMSG_MOVE_LAND_WALK, 8+4);
data << GetTarget()->GetPackGUID();
data << uint32(0);
GetTarget()->SendMessageToSet(&data, true);
}
void Aura::HandleAuraFeatherFall(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
Unit *target = GetTarget();
WorldPacket data;
if(apply)
data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4);
else
data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4);
data << target->GetPackGUID();
data << uint32(0);
target->SendMessageToSet(&data, true);
// start fall from current height
if(!apply && target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->SetFallInformation(0, target->GetPositionZ());
}
void Aura::HandleAuraHover(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
WorldPacket data;
if(apply)
data.Initialize(SMSG_MOVE_SET_HOVER, 8+4);
else
data.Initialize(SMSG_MOVE_UNSET_HOVER, 8+4);
data << GetTarget()->GetPackGUID();
data << uint32(0);
GetTarget()->SendMessageToSet(&data, true);
}
void Aura::HandleWaterBreathing(bool /*apply*/, bool /*Real*/)
{
// update timers in client
if(GetTarget()->GetTypeId()==TYPEID_PLAYER)
((Player*)GetTarget())->UpdateMirrorTimers();
}
void Aura::HandleAuraModShapeshift(bool apply, bool Real)
{
if(!Real)
return;
uint32 modelid = 0;
Powers PowerType = POWER_MANA;
ShapeshiftForm form = ShapeshiftForm(m_modifier.m_miscvalue);
Unit *target = GetTarget();
SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
if (!ssEntry)
{
sLog.outError("Unknown shapeshift form %u in spell %u", form, GetId());
return;
}
if (ssEntry->modelID_A)
{
// i will asume that creatures will always take the defined model from the dbc
// since no field in creature_templates describes wether an alliance or
// horde modelid should be used at shapeshifting
if (target->GetTypeId() != TYPEID_PLAYER)
modelid = ssEntry->modelID_A;
else
{
// players are a bit different since the dbc has seldomly an horde modelid
if (Player::TeamForRace(target->getRace()) == HORDE)
{
if (ssEntry->modelID_H)
modelid = ssEntry->modelID_H; // 3.2.3 only the moonkin form has this information
else // get model for race
modelid = sObjectMgr.GetModelForRace(ssEntry->modelID_A, target->getRaceMask());
}
// nothing found in above, so use default
if (!modelid)
modelid = ssEntry->modelID_A;
}
}
// remove polymorph before changing display id to keep new display id
switch (form)
{
case FORM_CAT:
case FORM_TREE:
case FORM_TRAVEL:
case FORM_AQUA:
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_FLIGHT_EPIC:
case FORM_FLIGHT:
case FORM_MOONKIN:
{
// remove movement affects
target->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT, GetHolder());
Unit::AuraList const& slowingAuras = target->GetAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
for (Unit::AuraList::const_iterator iter = slowingAuras.begin(); iter != slowingAuras.end();)
{
SpellEntry const* aurSpellInfo = (*iter)->GetSpellProto();
uint32 aurMechMask = GetAllSpellMechanicMask(aurSpellInfo);
// If spell that caused this aura has Croud Control or Daze effect
if ((aurMechMask & MECHANIC_NOT_REMOVED_BY_SHAPESHIFT) ||
// some Daze spells have these parameters instead of MECHANIC_DAZE (skip snare spells)
(aurSpellInfo->SpellIconID == 15 && aurSpellInfo->Dispel == 0 &&
(aurMechMask & (1 << (MECHANIC_SNARE-1))) == 0))
{
++iter;
continue;
}
// All OK, remove aura now
target->RemoveAurasDueToSpellByCancel(aurSpellInfo->Id);
iter = slowingAuras.begin();
}
// and polymorphic affects
if (target->IsPolymorphed())
target->RemoveAurasDueToSpell(target->getTransForm());
break;
}
default:
break;
}
if (apply)
{
// remove other shapeshift before applying a new one
target->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT, GetHolder());
// need send to client not form active state, or at re-apply form client go crazy
target->SendForcedObjectUpdate();
if (modelid > 0)
target->SetDisplayId(modelid);
// now only powertype must be set
switch (form)
{
case FORM_CAT:
PowerType = POWER_ENERGY;
break;
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_BATTLESTANCE:
case FORM_BERSERKERSTANCE:
case FORM_DEFENSIVESTANCE:
PowerType = POWER_RAGE;
break;
default:
break;
}
if (PowerType != POWER_MANA)
{
// reset power to default values only at power change
if (target->getPowerType() != PowerType)
target->setPowerType(PowerType);
switch (form)
{
case FORM_CAT:
case FORM_BEAR:
case FORM_DIREBEAR:
{
// get furor proc chance
int32 furorChance = 0;
Unit::AuraList const& mDummy = target->GetAurasByType(SPELL_AURA_DUMMY);
for (Unit::AuraList::const_iterator i = mDummy.begin(); i != mDummy.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellIconID == 238)
{
furorChance = (*i)->GetModifier()->m_amount;
break;
}
}
if (m_modifier.m_miscvalue == FORM_CAT)
{
// Furor chance is now amount allowed to save energy for cat form
// without talent it reset to 0
if ((int32)target->GetPower(POWER_ENERGY) > furorChance)
{
target->SetPower(POWER_ENERGY, 0);
target->CastCustomSpell(target, 17099, &furorChance, NULL, NULL, true, NULL, this);
}
}
else if(furorChance) // only if talent known
{
target->SetPower(POWER_RAGE, 0);
if(irand(1,100) <= furorChance)
target->CastSpell(target, 17057, true, NULL, this);
}
break;
}
case FORM_BATTLESTANCE:
case FORM_DEFENSIVESTANCE:
case FORM_BERSERKERSTANCE:
{
uint32 Rage_val = 0;
// Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch)
if(target->GetTypeId() == TYPEID_PLAYER)
{
PlayerSpellMap const& sp_list = ((Player *)target)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
{
if(itr->second.state == PLAYERSPELL_REMOVED) continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139)
Rage_val += target->CalculateSpellDamage(target, spellInfo, EFFECT_INDEX_0) * 10;
}
}
if (target->GetPower(POWER_RAGE) > Rage_val)
target->SetPower(POWER_RAGE, Rage_val);
break;
}
default:
break;
}
}
target->SetShapeshiftForm(form);
// a form can give the player a new castbar with some spells.. this is a clientside process..
// serverside just needs to register the new spells so that player isn't kicked as cheater
if (target->GetTypeId() == TYPEID_PLAYER)
for (uint32 i = 0; i < 8; ++i)
if (ssEntry->spellId[i])
((Player*)target)->addSpell(ssEntry->spellId[i], true, false, false, false);
}
else
{
if(modelid > 0)
target->SetDisplayId(target->GetNativeDisplayId());
if(target->getClass() == CLASS_DRUID)
target->setPowerType(POWER_MANA);
target->SetShapeshiftForm(FORM_NONE);
switch(form)
{
// Nordrassil Harness - bonus
case FORM_BEAR:
case FORM_DIREBEAR:
case FORM_CAT:
if(Aura* dummy = target->GetDummyAura(37315) )
target->CastSpell(target, 37316, true, NULL, dummy);
break;
// Nordrassil Regalia - bonus
case FORM_MOONKIN:
if(Aura* dummy = target->GetDummyAura(37324) )
target->CastSpell(target, 37325, true, NULL, dummy);
break;
default:
break;
}
// look at the comment in apply-part
if (target->GetTypeId() == TYPEID_PLAYER)
for (uint32 i = 0; i < 8; ++i)
if (ssEntry->spellId[i])
((Player*)target)->removeSpell(ssEntry->spellId[i], false, false, false);
}
// adding/removing linked auras
// add/remove the shapeshift aura's boosts
HandleShapeshiftBoosts(apply);
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->InitDataForForm();
}
void Aura::HandleAuraTransform(bool apply, bool Real)
{
Unit *target = GetTarget();
if (apply)
{
// special case (spell specific functionality)
if (m_modifier.m_miscvalue == 0)
{
switch (GetId())
{
case 16739: // Orb of Deception
{
uint32 orb_model = target->GetNativeDisplayId();
switch(orb_model)
{
// Troll Female
case 1479: target->SetDisplayId(10134); break;
// Troll Male
case 1478: target->SetDisplayId(10135); break;
// Tauren Male
case 59: target->SetDisplayId(10136); break;
// Human Male
case 49: target->SetDisplayId(10137); break;
// Human Female
case 50: target->SetDisplayId(10138); break;
// Orc Male
case 51: target->SetDisplayId(10139); break;
// Orc Female
case 52: target->SetDisplayId(10140); break;
// Dwarf Male
case 53: target->SetDisplayId(10141); break;
// Dwarf Female
case 54: target->SetDisplayId(10142); break;
// NightElf Male
case 55: target->SetDisplayId(10143); break;
// NightElf Female
case 56: target->SetDisplayId(10144); break;
// Undead Female
case 58: target->SetDisplayId(10145); break;
// Undead Male
case 57: target->SetDisplayId(10146); break;
// Tauren Female
case 60: target->SetDisplayId(10147); break;
// Gnome Male
case 1563: target->SetDisplayId(10148); break;
// Gnome Female
case 1564: target->SetDisplayId(10149); break;
// BloodElf Female
case 15475: target->SetDisplayId(17830); break;
// BloodElf Male
case 15476: target->SetDisplayId(17829); break;
// Dranei Female
case 16126: target->SetDisplayId(17828); break;
// Dranei Male
case 16125: target->SetDisplayId(17827); break;
default: break;
}
break;
}
case 42365: // Murloc costume
target->SetDisplayId(21723);
break;
//case 44186: // Gossip NPC Appearance - All, Brewfest
//break;
//case 48305: // Gossip NPC Appearance - All, Spirit of Competition
//break;
case 50517: // Dread Corsair
case 51926: // Corsair Costume
{
// expected for players
uint32 race = target->getRace();
switch(race)
{
case RACE_HUMAN:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25037 : 25048);
break;
case RACE_ORC:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25039 : 25050);
break;
case RACE_DWARF:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25034 : 25045);
break;
case RACE_NIGHTELF:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25038 : 25049);
break;
case RACE_UNDEAD:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25042 : 25053);
break;
case RACE_TAUREN:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25040 : 25051);
break;
case RACE_GNOME:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25035 : 25046);
break;
case RACE_TROLL:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25041 : 25052);
break;
case RACE_GOBLIN: // not really player race (3.x), but model exist
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25036 : 25047);
break;
case RACE_BLOODELF:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25032 : 25043);
break;
case RACE_DRAENEI:
target->SetDisplayId(target->getGender() == GENDER_MALE ? 25033 : 25044);
break;
}
break;
}
//case 50531: // Gossip NPC Appearance - All, Pirate Day
//break;
//case 51010: // Dire Brew
//break;
//case 53806: // Pygmy Oil
//break;
//case 62847: // NPC Appearance - Valiant 02
//break;
//case 62852: // NPC Appearance - Champion 01
//break;
//case 63965: // NPC Appearance - Champion 02
//break;
//case 63966: // NPC Appearance - Valiant 03
//break;
case 65386: // Honor the Dead
case 65495:
{
switch(target->getGender())
{
case GENDER_MALE:
target->SetDisplayId(29203); // Chapman
break;
case GENDER_FEMALE:
case GENDER_NONE:
target->SetDisplayId(29204); // Catrina
break;
}
break;
}
//case 65511: // Gossip NPC Appearance - Brewfest
//break;
//case 65522: // Gossip NPC Appearance - Winter Veil
//break;
//case 65523: // Gossip NPC Appearance - Default
//break;
//case 65524: // Gossip NPC Appearance - Lunar Festival
//break;
//case 65525: // Gossip NPC Appearance - Hallow's End
//break;
//case 65526: // Gossip NPC Appearance - Midsummer
//break;
//case 65527: // Gossip NPC Appearance - Spirit of Competition
//break;
case 65528: // Gossip NPC Appearance - Pirates' Day
{
// expecting npc's using this spell to have models with race info.
uint32 race = GetCreatureModelRace(target->GetNativeDisplayId());
// random gender, regardless of current gender
switch(race)
{
case RACE_HUMAN:
target->SetDisplayId(roll_chance_i(50) ? 25037 : 25048);
break;
case RACE_ORC:
target->SetDisplayId(roll_chance_i(50) ? 25039 : 25050);
break;
case RACE_DWARF:
target->SetDisplayId(roll_chance_i(50) ? 25034 : 25045);
break;
case RACE_NIGHTELF:
target->SetDisplayId(roll_chance_i(50) ? 25038 : 25049);
break;
case RACE_UNDEAD:
target->SetDisplayId(roll_chance_i(50) ? 25042 : 25053);
break;
case RACE_TAUREN:
target->SetDisplayId(roll_chance_i(50) ? 25040 : 25051);
break;
case RACE_GNOME:
target->SetDisplayId(roll_chance_i(50) ? 25035 : 25046);
break;
case RACE_TROLL:
target->SetDisplayId(roll_chance_i(50) ? 25041 : 25052);
break;
case RACE_GOBLIN:
target->SetDisplayId(roll_chance_i(50) ? 25036 : 25047);
break;
case RACE_BLOODELF:
target->SetDisplayId(roll_chance_i(50) ? 25032 : 25043);
break;
case RACE_DRAENEI:
target->SetDisplayId(roll_chance_i(50) ? 25033 : 25044);
break;
}
break;
}
case 65529: // Gossip NPC Appearance - Day of the Dead (DotD)
// random, regardless of current gender
target->SetDisplayId(roll_chance_i(50) ? 29203 : 29204);
break;
//case 66236: // Incinerate Flesh
//break;
//case 69999: // [DND] Swap IDs
//break;
//case 70764: // Citizen Costume (note: many spells w/same name)
//break;
//case 71309: // [DND] Spawn Portal
//break;
case 71450: // Crown Parcel Service Uniform
target->SetDisplayId(target->getGender() == GENDER_MALE ? 31002 : 31003);
break;
//case 75531: // Gnomeregan Pride
//break;
//case 75532: // Darkspear Pride
//break;
default:
sLog.outError("Aura::HandleAuraTransform, spell %u does not have creature entry defined, need custom defined model.", GetId());
break;
}
}
else
{
uint32 model_id;
CreatureInfo const * ci = ObjectMgr::GetCreatureTemplate(m_modifier.m_miscvalue);
if (!ci)
{
model_id = 16358; // pig pink ^_^
sLog.outError("Auras: unknown creature id = %d (only need its modelid) Form Spell Aura Transform in Spell ID = %d", m_modifier.m_miscvalue, GetId());
}
else
model_id = Creature::ChooseDisplayId(ci); // Will use the default model here
// Polymorph (sheep/penguin case)
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellProto()->SpellIconID == 82)
if (Unit* caster = GetCaster())
if (caster->HasAura(52648)) // Glyph of the Penguin
model_id = 26452;
target->SetDisplayId(model_id);
// creature case, need to update equipment
if (ci && target->GetTypeId() == TYPEID_UNIT)
((Creature*)target)->LoadEquipment(ci->equipmentId, true);
// Dragonmaw Illusion (set mount model also)
if(GetId()==42016 && target->GetMountID() && !target->GetAurasByType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED).empty())
target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
}
// update active transform spell only not set or not overwriting negative by positive case
if (!target->getTransForm() || !IsPositiveSpell(GetId()) || IsPositiveSpell(target->getTransForm()))
target->setTransForm(GetId());
// polymorph case
if (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())
((Player*)target)->setRegenTimer(1*IN_MILLISECONDS);
//dismount polymorphed target (after patch 2.4.2)
if (target->IsMounted())
target->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED, GetHolder());
}
}
else
{
// ApplyModifier(true) will reapply it if need
target->setTransForm(0);
target->SetDisplayId(target->GetNativeDisplayId());
// apply default equipment for creature case
if (target->GetTypeId() == TYPEID_UNIT)
((Creature*)target)->LoadEquipment(((Creature*)target)->GetCreatureInfo()->equipmentId, true);
// re-apply some from still active with preference negative cases
Unit::AuraList const& otherTransforms = target->GetAurasByType(SPELL_AURA_TRANSFORM);
if (!otherTransforms.empty())
{
// look for other transform auras
Aura* handledAura = *otherTransforms.begin();
for(Unit::AuraList::const_iterator i = otherTransforms.begin();i != otherTransforms.end(); ++i)
{
// negative auras are preferred
if (!IsPositiveSpell((*i)->GetSpellProto()->Id))
{
handledAura = *i;
break;
}
}
handledAura->ApplyModifier(true);
}
// Dragonmaw Illusion (restore mount model)
if (GetId() == 42016 && target->GetMountID() == 16314)
{
if (!target->GetAurasByType(SPELL_AURA_MOUNTED).empty())
{
uint32 cr_id = target->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetModifier()->m_miscvalue;
if (CreatureInfo const* ci = ObjectMgr::GetCreatureTemplate(cr_id))
{
uint32 display_id = Creature::ChooseDisplayId(ci);
CreatureModelInfo const *minfo = sObjectMgr.GetCreatureModelRandomGender(display_id);
if (minfo)
display_id = minfo->modelid;
target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, display_id);
}
}
}
}
}
void Aura::HandleForceReaction(bool apply, bool Real)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
if(!Real)
return;
Player* player = (Player*)GetTarget();
uint32 faction_id = m_modifier.m_miscvalue;
ReputationRank faction_rank = ReputationRank(m_modifier.m_amount);
player->GetReputationMgr().ApplyForceReaction(faction_id, faction_rank, apply);
player->GetReputationMgr().SendForceReactions();
// stop fighting if at apply forced rank friendly or at remove real rank friendly
if ((apply && faction_rank >= REP_FRIENDLY) || (!apply && player->GetReputationRank(faction_id) >= REP_FRIENDLY))
player->StopAttackFaction(faction_id);
}
void Aura::HandleAuraModSkill(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
uint32 prot=GetSpellProto()->EffectMiscValue[m_effIndex];
int32 points = GetModifier()->m_amount;
((Player*)GetTarget())->ModifySkillBonus(prot, (apply ? points: -points), m_modifier.m_auraname == SPELL_AURA_MOD_SKILL_TALENT);
if(prot == SKILL_DEFENSE)
((Player*)GetTarget())->UpdateDefenseBonusesMod();
}
void Aura::HandleChannelDeathItem(bool apply, bool Real)
{
if (Real && !apply)
{
if (m_removeMode != AURA_REMOVE_BY_DEATH)
return;
// Item amount
if (m_modifier.m_amount <= 0)
return;
SpellEntry const *spellInfo = GetSpellProto();
if (spellInfo->EffectItemType[m_effIndex] == 0)
return;
Unit* victim = GetTarget();
Unit* caster = GetCaster();
if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
// Soul Shard (target req.)
if (spellInfo->EffectItemType[m_effIndex] == 6265)
{
// Only from non-grey units
if (!((Player*)caster)->isHonorOrXPTarget(victim) ||
(victim->GetTypeId() == TYPEID_UNIT && !((Player*)caster)->isAllowedToLoot((Creature*)victim)))
return;
}
//Adding items
uint32 noSpaceForCount = 0;
uint32 count = m_modifier.m_amount;
ItemPosCountVec dest;
InventoryResult msg = ((Player*)caster)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->EffectItemType[m_effIndex], count, &noSpaceForCount);
if( msg != EQUIP_ERR_OK )
{
count-=noSpaceForCount;
((Player*)caster)->SendEquipError( msg, NULL, NULL, spellInfo->EffectItemType[m_effIndex] );
if (count==0)
return;
}
Item* newitem = ((Player*)caster)->StoreNewItem(dest, spellInfo->EffectItemType[m_effIndex], true);
((Player*)caster)->SendNewItem(newitem, count, true, true);
// Soul Shard (glyph bonus)
if (spellInfo->EffectItemType[m_effIndex] == 6265)
{
// Glyph of Soul Shard
if (caster->HasAura(58070) && roll_chance_i(40))
caster->CastSpell(caster, 58068, true, NULL, this);
}
}
}
void Aura::HandleBindSight(bool apply, bool /*Real*/)
{
Unit* caster = GetCaster();
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
Camera& camera = ((Player*)caster)->GetCamera();
if (apply)
camera.SetView(GetTarget());
else
camera.ResetView();
}
void Aura::HandleFarSight(bool apply, bool /*Real*/)
{
Unit* caster = GetCaster();
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
Camera& camera = ((Player*)caster)->GetCamera();
if (apply)
camera.SetView(GetTarget());
else
camera.ResetView();
}
void Aura::HandleAuraTrackCreatures(bool apply, bool /*Real*/)
{
if (GetTarget()->GetTypeId()!=TYPEID_PLAYER)
return;
if (apply)
GetTarget()->RemoveNoStackAurasDueToAuraHolder(GetHolder());
if (apply)
GetTarget()->SetFlag(PLAYER_TRACK_CREATURES, uint32(1) << (m_modifier.m_miscvalue-1));
else
GetTarget()->RemoveFlag(PLAYER_TRACK_CREATURES, uint32(1) << (m_modifier.m_miscvalue-1));
}
void Aura::HandleAuraTrackResources(bool apply, bool /*Real*/)
{
if (GetTarget()->GetTypeId()!=TYPEID_PLAYER)
return;
if (apply)
GetTarget()->RemoveNoStackAurasDueToAuraHolder(GetHolder());
if (apply)
GetTarget()->SetFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (m_modifier.m_miscvalue-1));
else
GetTarget()->RemoveFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (m_modifier.m_miscvalue-1));
}
void Aura::HandleAuraTrackStealthed(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId()!=TYPEID_PLAYER)
return;
if(apply)
GetTarget()->RemoveNoStackAurasDueToAuraHolder(GetHolder());
GetTarget()->ApplyModByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_TRACK_STEALTHED, apply);
}
void Aura::HandleAuraModScale(bool apply, bool /*Real*/)
{
GetTarget()->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X, float(m_modifier.m_amount), apply);
GetTarget()->UpdateModelData();
}
void Aura::HandleModPossess(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
// not possess yourself
if (GetCasterGuid() == target->GetObjectGuid())
return;
Unit* caster = GetCaster();
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
Player* p_caster = (Player*)caster;
Camera& camera = p_caster->GetCamera();
if( apply )
{
target->addUnitState(UNIT_STAT_CONTROLLED);
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
target->SetCharmerGuid(p_caster->GetObjectGuid());
target->setFaction(p_caster->getFaction());
// target should became visible at SetView call(if not visible before):
// otherwise client\p_caster will ignore packets from the target(SetClientControl for example)
camera.SetView(target);
p_caster->SetCharm(target);
p_caster->SetClientControl(target, 1);
p_caster->SetMover(target);
target->CombatStop(true);
target->DeleteThreatList();
target->getHostileRefManager().deleteReferences();
if(CharmInfo *charmInfo = target->InitCharmInfo(target))
{
charmInfo->InitPossessCreateSpells();
charmInfo->SetReactState(REACT_PASSIVE);
charmInfo->SetCommandState(COMMAND_STAY);
}
p_caster->PossessSpellInitialize();
if(target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)target)->AIM_Initialize();
}
else if(target->GetTypeId() == TYPEID_PLAYER)
{
((Player*)target)->SetClientControl(target, 0);
}
}
else
{
p_caster->SetCharm(NULL);
p_caster->SetClientControl(target, 0);
p_caster->SetMover(NULL);
// there is a possibility that target became invisible for client\p_caster at ResetView call:
// it must be called after movement control unapplying, not before! the reason is same as at aura applying
camera.ResetView();
p_caster->RemovePetActionBar();
// on delete only do caster related effects
if(m_removeMode == AURA_REMOVE_BY_DELETE)
return;
target->clearUnitState(UNIT_STAT_CONTROLLED);
target->CombatStop(true);
target->DeleteThreatList();
target->getHostileRefManager().deleteReferences();
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
target->SetCharmerGuid(ObjectGuid());
if(target->GetTypeId() == TYPEID_PLAYER)
{
((Player*)target)->setFactionForRace(target->getRace());
((Player*)target)->SetClientControl(target, 1);
}
else if(target->GetTypeId() == TYPEID_UNIT)
{
CreatureInfo const *cinfo = ((Creature*)target)->GetCreatureInfo();
target->setFaction(cinfo->faction_A);
}
if(target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)target)->AIM_Initialize();
if (((Creature*)target)->AI())
((Creature*)target)->AI()->AttackedBy(caster);
}
}
}
void Aura::HandleModPossessPet(bool apply, bool Real)
{
if(!Real)
return;
Unit* caster = GetCaster();
if (!caster || caster->GetTypeId() != TYPEID_PLAYER)
return;
Unit* target = GetTarget();
if (target->GetTypeId() != TYPEID_UNIT || !((Creature*)target)->IsPet())
return;
Pet* pet = (Pet*)target;
Player* p_caster = (Player*)caster;
Camera& camera = p_caster->GetCamera();
if (apply)
{
pet->addUnitState(UNIT_STAT_CONTROLLED);
// target should became visible at SetView call(if not visible before):
// otherwise client\p_caster will ignore packets from the target(SetClientControl for example)
camera.SetView(pet);
p_caster->SetCharm(pet);
p_caster->SetClientControl(pet, 1);
((Player*)caster)->SetMover(pet);
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
pet->StopMoving();
pet->GetMotionMaster()->Clear(false);
pet->GetMotionMaster()->MoveIdle();
}
else
{
p_caster->SetCharm(NULL);
p_caster->SetClientControl(pet, 0);
p_caster->SetMover(NULL);
// there is a possibility that target became invisible for client\p_caster at ResetView call:
// it must be called after movement control unapplying, not before! the reason is same as at aura applying
camera.ResetView();
// on delete only do caster related effects
if(m_removeMode == AURA_REMOVE_BY_DELETE)
return;
pet->clearUnitState(UNIT_STAT_CONTROLLED);
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED);
pet->AttackStop();
// out of range pet dismissed
if (!pet->IsWithinDistInMap(p_caster, pet->GetMap()->GetVisibilityDistance()))
{
p_caster->RemovePet(PET_SAVE_REAGENTS);
}
else
{
pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
pet->AddSplineFlag(SPLINEFLAG_WALKMODE);
}
}
}
void Aura::HandleAuraModPetTalentsPoints(bool /*Apply*/, bool Real)
{
if(!Real)
return;
// Recalculate pet talent points
if (Pet *pet=GetTarget()->GetPet())
pet->InitTalentForLevel();
}
void Aura::HandleModCharm(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
// not charm yourself
if (GetCasterGuid() == target->GetObjectGuid())
return;
Unit* caster = GetCaster();
if(!caster)
return;
if( apply )
{
// is it really need after spell check checks?
target->RemoveSpellsCausingAura(SPELL_AURA_MOD_CHARM, GetHolder());
target->RemoveSpellsCausingAura(SPELL_AURA_MOD_POSSESS, GetHolder());
target->SetCharmerGuid(GetCasterGuid());
target->setFaction(caster->getFaction());
target->CastStop(target == caster ? GetId() : 0);
caster->SetCharm(target);
target->CombatStop(true);
target->DeleteThreatList();
target->getHostileRefManager().deleteReferences();
if(target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)target)->AIM_Initialize();
CharmInfo *charmInfo = target->InitCharmInfo(target);
charmInfo->InitCharmCreateSpells();
charmInfo->SetReactState( REACT_DEFENSIVE );
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
{
CreatureInfo const *cinfo = ((Creature*)target)->GetCreatureInfo();
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
{
// creature with pet number expected have class set
if(target->GetByteValue(UNIT_FIELD_BYTES_0, 1)==0)
{
if(cinfo->unit_class==0)
sLog.outErrorDb("Creature (Entry: %u) have unit_class = 0 but used in charmed spell, that will be result client crash.",cinfo->Entry);
else
sLog.outError("Creature (Entry: %u) have unit_class = %u but at charming have class 0!!! that will be result client crash.",cinfo->Entry,cinfo->unit_class);
target->SetByteValue(UNIT_FIELD_BYTES_0, 1, CLASS_MAGE);
}
//just to enable stat window
charmInfo->SetPetNumber(sObjectMgr.GeneratePetNumber(), true);
//if charmed two demons the same session, the 2nd gets the 1st one's name
target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL)));
}
}
}
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->CharmSpellInitialize();
}
else
{
target->SetCharmerGuid(ObjectGuid());
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->setFactionForRace(target->getRace());
else
{
CreatureInfo const *cinfo = ((Creature*)target)->GetCreatureInfo();
// restore faction
if(((Creature*)target)->IsPet())
{
if(Unit* owner = target->GetOwner())
target->setFaction(owner->getFaction());
else if(cinfo)
target->setFaction(cinfo->faction_A);
}
else if(cinfo) // normal creature
target->setFaction(cinfo->faction_A);
// restore UNIT_FIELD_BYTES_0
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
{
// DB must have proper class set in field at loading, not req. restore, including workaround case at apply
// m_target->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class);
if(target->GetCharmInfo())
target->GetCharmInfo()->SetPetNumber(0, true);
else
sLog.outError("Aura::HandleModCharm: target (GUID: %u TypeId: %u) has a charm aura but no charm info!", target->GetGUIDLow(), target->GetTypeId());
}
}
caster->SetCharm(NULL);
if(caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->RemovePetActionBar();
target->CombatStop(true);
target->DeleteThreatList();
target->getHostileRefManager().deleteReferences();
if(target->GetTypeId() == TYPEID_UNIT)
{
((Creature*)target)->AIM_Initialize();
if (((Creature*)target)->AI())
((Creature*)target)->AI()->AttackedBy(caster);
}
}
}
void Aura::HandleModConfuse(bool apply, bool Real)
{
if(!Real)
return;
GetTarget()->SetConfused(apply, GetCasterGuid(), GetId());
}
void Aura::HandleModFear(bool apply, bool Real)
{
if (!Real)
return;
GetTarget()->SetFeared(apply, GetCasterGuid(), GetId());
}
void Aura::HandleFeignDeath(bool apply, bool Real)
{
if(!Real)
return;
GetTarget()->SetFeignDeath(apply, GetCasterGuid(), GetId());
}
void Aura::HandleAuraModDisarm(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
if(!apply && target->HasAuraType(GetModifier()->m_auraname))
return;
uint32 flags;
uint32 field;
WeaponAttackType attack_type;
switch (GetModifier()->m_auraname)
{
default:
case SPELL_AURA_MOD_DISARM:
{
field = UNIT_FIELD_FLAGS;
flags = UNIT_FLAG_DISARMED;
attack_type = BASE_ATTACK;
break;
}
case SPELL_AURA_MOD_DISARM_OFFHAND:
{
field = UNIT_FIELD_FLAGS_2;
flags = UNIT_FLAG2_DISARM_OFFHAND;
attack_type = OFF_ATTACK;
break;
}
case SPELL_AURA_MOD_DISARM_RANGED:
{
field = UNIT_FIELD_FLAGS_2;
flags = UNIT_FLAG2_DISARM_RANGED;
attack_type = RANGED_ATTACK;
break;
}
}
target->ApplyModFlag(field, flags, apply);
if (target->GetTypeId() != TYPEID_PLAYER)
return;
// main-hand attack speed already set to special value for feral form already and don't must change and reset at remove.
if (target->IsInFeralForm())
return;
if (apply)
target->SetAttackTime(attack_type, BASE_ATTACK_TIME);
else
((Player *)target)->SetRegularAttackTime();
target->UpdateDamagePhysical(attack_type);
}
void Aura::HandleAuraModStun(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
if (apply)
{
// Frost stun aura -> freeze/unfreeze target
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
target->ModifyAuraState(AURA_STATE_FROZEN, apply);
target->addUnitState(UNIT_STAT_STUNNED);
target->SetTargetGuid(ObjectGuid());
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
target->CastStop(target->GetObjectGuid() == GetCasterGuid() ? GetId() : 0);
// Creature specific
if(target->GetTypeId() != TYPEID_PLAYER)
target->StopMoving();
else
{
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
target->SetStandState(UNIT_STAND_STATE_STAND);// in 1.5 client
}
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
data << target->GetPackGUID();
data << uint32(0);
target->SendMessageToSet(&data, true);
// Summon the Naj'entus Spine GameObject on target if spell is Impaling Spine
if(GetId() == 39837)
{
GameObject* pObj = new GameObject;
if(pObj->Create(target->GetMap()->GenerateLocalLowGuid(HIGHGUID_GAMEOBJECT), 185584, target->GetMap(), target->GetPhaseMask(),
target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, GO_ANIMPROGRESS_DEFAULT, GO_STATE_READY))
{
pObj->SetRespawnTime(GetAuraDuration()/IN_MILLISECONDS);
pObj->SetSpellId(GetId());
target->AddGameObject(pObj);
target->GetMap()->Add(pObj);
}
else
delete pObj;
}
}
else
{
// Frost stun aura -> freeze/unfreeze target
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{
bool found_another = false;
for(AuraType const* itr = &frozenAuraTypes[0]; *itr != SPELL_AURA_NONE; ++itr)
{
Unit::AuraList const& auras = target->GetAurasByType(*itr);
for(Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{
found_another = true;
break;
}
}
if(found_another)
break;
}
if(!found_another)
target->ModifyAuraState(AURA_STATE_FROZEN, apply);
}
// Real remove called after current aura remove from lists, check if other similar auras active
if(target->HasAuraType(SPELL_AURA_MOD_STUN))
return;
target->clearUnitState(UNIT_STAT_STUNNED);
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
if(!target->hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
{
if(target->getVictim() && target->isAlive())
target->SetTargetGuid(target->getVictim()->GetObjectGuid());
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4);
data << target->GetPackGUID();
data << uint32(0);
target->SendMessageToSet(&data, true);
}
// Wyvern Sting
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000100000000000))
{
Unit* caster = GetCaster();
if( !caster || caster->GetTypeId()!=TYPEID_PLAYER )
return;
uint32 spell_id = 0;
switch(GetId())
{
case 19386: spell_id = 24131; break;
case 24132: spell_id = 24134; break;
case 24133: spell_id = 24135; break;
case 27068: spell_id = 27069; break;
case 49011: spell_id = 49009; break;
case 49012: spell_id = 49010; break;
default:
sLog.outError("Spell selection called for unexpected original spell %u, new spell for this spell family?",GetId());
return;
}
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell_id);
if(!spellInfo)
return;
caster->CastSpell(target,spellInfo,true,NULL,this);
return;
}
}
}
void Aura::HandleModStealth(bool apply, bool Real)
{
Unit *target = GetTarget();
if (apply)
{
// drop flag at stealth in bg
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
// only at real aura add
if (Real)
{
target->SetStandFlags(UNIT_STAND_FLAGS_CREEP);
if (target->GetTypeId()==TYPEID_PLAYER)
target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH);
// apply only if not in GM invisibility (and overwrite invisibility state)
if (target->GetVisibility()!=VISIBILITY_OFF)
{
target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
target->SetVisibility(VISIBILITY_GROUP_STEALTH);
}
// apply full stealth period bonuses only at first stealth aura in stack
if(target->GetAurasByType(SPELL_AURA_MOD_STEALTH).size()<=1)
{
Unit::AuraList const& mDummyAuras = target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
{
// Master of Subtlety
if ((*i)->GetSpellProto()->SpellIconID == 2114)
{
target->RemoveAurasDueToSpell(31666);
int32 bp = (*i)->GetModifier()->m_amount;
target->CastCustomSpell(target,31665,&bp,NULL,NULL,true);
}
// Overkill
else if ((*i)->GetId() == 58426 && GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000400000))
{
target->CastSpell(target, 58427, true);
}
}
}
}
}
else
{
if (!Real)
return;
// Vanish (triggered, normal stealth need apply before remove advanced stealth)
if (target->GetTypeId() == TYPEID_PLAYER && m_removeMode == AURA_REMOVE_BY_EXPIRE &&
GetSpellProto()->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x000000000800)))
{
uint32 spellId = 1784; // Stealth
// reset cooldown on it if needed
if (((Player*)target)->HasSpellCooldown(spellId))
((Player*)target)->RemoveSpellCooldown(spellId);
target->CastSpell(target, spellId, true);
}
// only at real aura remove of _last_ SPELL_AURA_MOD_STEALTH
if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH))
{
// if no GM invisibility
if (target->GetVisibility()!=VISIBILITY_OFF)
{
target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP);
if (target->GetTypeId()==TYPEID_PLAYER)
target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH);
// restore invisibility if any
if (target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY))
{
target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
}
else
target->SetVisibility(VISIBILITY_ON);
}
// apply delayed talent bonus remover at last stealth aura remove
Unit::AuraList const& mDummyAuras = target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
{
// Master of Subtlety
if ((*i)->GetSpellProto()->SpellIconID == 2114)
target->CastSpell(target, 31666, true);
// Overkill
else if ((*i)->GetId() == 58426 && GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000400000))
{
if (SpellAuraHolder* holder = target->GetSpellAuraHolder(58427))
{
holder->SetAuraMaxDuration(20*IN_MILLISECONDS);
holder->RefreshHolder();
}
}
}
}
}
}
void Aura::HandleInvisibility(bool apply, bool Real)
{
Unit *target = GetTarget();
if (apply)
{
target->m_invisibilityMask |= (1 << m_modifier.m_miscvalue);
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
if (Real && target->GetTypeId()==TYPEID_PLAYER)
{
// apply glow vision
target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
}
// apply only if not in GM invisibility and not stealth
if (target->GetVisibility() == VISIBILITY_ON)
{
// Aura not added yet but visibility code expect temporary add aura
target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
}
}
else
{
// recalculate value at modifier remove (current aura already removed)
target->m_invisibilityMask = 0;
Unit::AuraList const& auras = target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
target->m_invisibilityMask |= (1 << (*itr)->GetModifier()->m_miscvalue);
// only at real aura remove and if not have different invisibility auras.
if (Real && target->m_invisibilityMask == 0)
{
// remove glow vision
if (target->GetTypeId() == TYPEID_PLAYER)
target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
// apply only if not in GM invisibility & not stealthed while invisible
if (target->GetVisibility() != VISIBILITY_OFF)
{
// if have stealth aura then already have stealth visibility
if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH))
target->SetVisibility(VISIBILITY_ON);
}
}
if (GetId() == 48809) // Binding Life
target->CastSpell(target, GetSpellProto()->CalculateSimpleValue(m_effIndex), true);
}
}
void Aura::HandleInvisibilityDetect(bool apply, bool Real)
{
Unit *target = GetTarget();
if(apply)
{
target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue);
}
else
{
// recalculate value at modifier remove (current aura already removed)
target->m_detectInvisibilityMask = 0;
Unit::AuraList const& auras = target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
target->m_detectInvisibilityMask |= (1 << (*itr)->GetModifier()->m_miscvalue);
}
if(Real && target->GetTypeId()==TYPEID_PLAYER)
((Player*)target)->GetCamera().UpdateVisibilityForOwner();
}
void Aura::HandleAuraModRoot(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
Unit *target = GetTarget();
if (apply)
{
// Frost root aura -> freeze/unfreeze target
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
target->ModifyAuraState(AURA_STATE_FROZEN, apply);
target->addUnitState(UNIT_STAT_ROOT);
target->SetTargetGuid(ObjectGuid());
//Save last orientation
if( target->getVictim() )
target->SetOrientation(target->GetAngle(target->getVictim()));
if(target->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
data << target->GetPackGUID();
data << (uint32)2;
target->SendMessageToSet(&data, true);
//Clear unit movement flags
((Player*)target)->m_movementInfo.SetMovementFlags(MOVEFLAG_NONE);
}
else
target->StopMoving();
}
else
{
// Frost root aura -> freeze/unfreeze target
if (GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{
bool found_another = false;
for(AuraType const* itr = &frozenAuraTypes[0]; *itr != SPELL_AURA_NONE; ++itr)
{
Unit::AuraList const& auras = target->GetAurasByType(*itr);
for(Unit::AuraList::const_iterator i = auras.begin(); i != auras.end(); ++i)
{
if( GetSpellSchoolMask((*i)->GetSpellProto()) & SPELL_SCHOOL_MASK_FROST)
{
found_another = true;
break;
}
}
if(found_another)
break;
}
if(!found_another)
target->ModifyAuraState(AURA_STATE_FROZEN, apply);
}
// Real remove called after current aura remove from lists, check if other similar auras active
if(target->HasAuraType(SPELL_AURA_MOD_ROOT))
return;
target->clearUnitState(UNIT_STAT_ROOT);
if(!target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
{
if(target->getVictim() && target->isAlive())
target->SetTargetGuid(target->getVictim()->GetObjectGuid());
if(target->GetTypeId() == TYPEID_PLAYER)
{
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
data << target->GetPackGUID();
data << (uint32)2;
target->SendMessageToSet(&data, true);
}
}
}
}
void Aura::HandleAuraModSilence(bool apply, bool Real)
{
// only at real add/remove aura
if(!Real)
return;
Unit *target = GetTarget();
if(apply)
{
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED);
// Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE
for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i)))
if(spell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
// Stop spells on prepare or casting state
target->InterruptSpell(CurrentSpellTypes(i), false);
}
else
{
// Real remove called after current aura remove from lists, check if other similar auras active
if(target->HasAuraType(SPELL_AURA_MOD_SILENCE))
return;
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED);
}
}
void Aura::HandleModThreat(bool apply, bool Real)
{
// only at real add/remove aura
if (!Real)
return;
Unit *target = GetTarget();
if (!target->isAlive())
return;
int level_diff = 0;
int multiplier = 0;
switch (GetId())
{
// Arcane Shroud
case 26400:
level_diff = target->getLevel() - 60;
multiplier = 2;
break;
// The Eye of Diminution
case 28862:
level_diff = target->getLevel() - 60;
multiplier = 1;
break;
}
if (level_diff > 0)
m_modifier.m_amount += multiplier * level_diff;
if (target->GetTypeId() == TYPEID_PLAYER)
for(int8 x=0;x < MAX_SPELL_SCHOOL;x++)
if (m_modifier.m_miscvalue & int32(1<<x))
ApplyPercentModFloatVar(target->m_threatModifier[x], float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
{
// only at real add/remove aura
if (!Real)
return;
Unit *target = GetTarget();
if (!target->isAlive() || target->GetTypeId() != TYPEID_PLAYER)
return;
Unit* caster = GetCaster();
if (!caster || !caster->isAlive())
return;
float threatMod = apply ? float(m_modifier.m_amount) : float(-m_modifier.m_amount);
target->getHostileRefManager().threatAssist(caster, threatMod, GetSpellProto());
}
void Aura::HandleModTaunt(bool apply, bool Real)
{
// only at real add/remove aura
if (!Real)
return;
Unit *target = GetTarget();
if (!target->isAlive() || !target->CanHaveThreatList())
return;
Unit* caster = GetCaster();
if (!caster || !caster->isAlive())
return;
if (apply)
target->TauntApply(caster);
else
{
// When taunt aura fades out, mob will switch to previous target if current has less than 1.1 * secondthreat
target->TauntFadeOut(caster);
}
}
/*********************************************************/
/*** MODIFY SPEED ***/
/*********************************************************/
void Aura::HandleAuraModIncreaseSpeed(bool /*apply*/, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
GetTarget()->UpdateSpeed(MOVE_RUN, true);
}
void Aura::HandleAuraModIncreaseMountedSpeed(bool apply, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
target->UpdateSpeed(MOVE_RUN, true);
// Festive Holiday Mount
if (apply && GetSpellProto()->SpellIconID != 1794 && target->HasAura(62061))
// Reindeer Transformation
target->CastSpell(target, 25860, true, NULL, this);
}
void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
// Enable Fly mode for flying mounts
if (m_modifier.m_auraname == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)
{
WorldPacket data;
if(apply)
data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
else
data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
data << target->GetPackGUID();
data << uint32(0); // unknown
target->SendMessageToSet(&data, true);
//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->HasAura(42016, EFFECT_INDEX_0) && target->GetMountID())
target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
// Festive Holiday Mount
if (apply && GetSpellProto()->SpellIconID != 1794 && target->HasAura(62061))
// Reindeer Transformation
target->CastSpell(target, 25860, true, NULL, this);
}
// Swift Flight Form check for higher speed flying mounts
if (apply && target->GetTypeId() == TYPEID_PLAYER && GetSpellProto()->Id == 40121)
{
for (PlayerSpellMap::const_iterator iter = ((Player*)target)->GetSpellMap().begin(); iter != ((Player*)target)->GetSpellMap().end(); ++iter)
{
if (iter->second.state != PLAYERSPELL_REMOVED)
{
bool changedSpeed = false;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(iter->first);
for(int i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if(spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED)
{
int32 mountSpeed = spellInfo->CalculateSimpleValue(SpellEffectIndex(i));
if (mountSpeed > m_modifier.m_amount)
{
m_modifier.m_amount = mountSpeed;
changedSpeed = true;
break;
}
}
}
if (changedSpeed)
break;
}
}
}
target->UpdateSpeed(MOVE_FLIGHT, true);
}
void Aura::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
GetTarget()->UpdateSpeed(MOVE_SWIM, true);
}
void Aura::HandleAuraModDecreaseSpeed(bool apply, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
if (apply)
{
// Gronn Lord's Grasp, becomes stoned
if (GetId() == 33572)
{
if (GetStackAmount() >= 5 && !target->HasAura(33652))
target->CastSpell(target, 33652, true);
}
}
target->UpdateSpeed(MOVE_RUN, true);
target->UpdateSpeed(MOVE_SWIM, true);
target->UpdateSpeed(MOVE_FLIGHT, true);
}
void Aura::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
target->UpdateSpeed(MOVE_RUN, true);
target->UpdateSpeed(MOVE_SWIM, true);
target->UpdateSpeed(MOVE_FLIGHT, true);
}
/*********************************************************/
/*** IMMUNITY ***/
/*********************************************************/
void Aura::HandleModMechanicImmunity(bool apply, bool /*Real*/)
{
uint32 misc = m_modifier.m_miscvalue;
// Forbearance
// in DBC wrong mechanic immune since 3.0.x
if (GetId() == 25771)
misc = MECHANIC_IMMUNE_SHIELD;
Unit *target = GetTarget();
if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
{
uint32 mechanic = 1 << (misc-1);
// immune movement impairment and loss of control (spell data have special structure for mark this case)
if (IsSpellRemoveAllMovementAndControlLossEffects(GetSpellProto()))
mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
target->RemoveAurasAtMechanicImmunity(mechanic, GetId());
}
target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,misc,apply);
// Bestial Wrath
if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellIconID == 1680)
{
// The Beast Within cast on owner if talent present
if (Unit* owner = target->GetOwner())
{
// Search talent The Beast Within
Unit::AuraList const& dummyAuras = owner->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
for(Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellIconID == 2229)
{
if (apply)
owner->CastSpell(owner, 34471, true, NULL, this);
else
owner->RemoveAurasDueToSpell(34471);
break;
}
}
}
}
// Heroic Fury (Intercept cooldown remove)
else if (apply && GetSpellProto()->Id == 60970 && target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->RemoveSpellCooldown(20252, true);
}
void Aura::HandleModMechanicImmunityMask(bool apply, bool /*Real*/)
{
uint32 mechanic = m_modifier.m_miscvalue;
if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
GetTarget()->RemoveAurasAtMechanicImmunity(mechanic,GetId());
// check implemented in Unit::IsImmuneToSpell and Unit::IsImmuneToSpellEffect
}
//this method is called whenever we add / remove aura which gives m_target some imunity to some spell effect
void Aura::HandleAuraModEffectImmunity(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
// when removing flag aura, handle flag drop
if( !apply && target->GetTypeId() == TYPEID_PLAYER
&& (GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION) )
{
if( BattleGround *bg = ((Player*)target)->GetBattleGround() )
bg->EventPlayerDroppedFlag(((Player*)target));
}
target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, m_modifier.m_miscvalue, apply);
}
void Aura::HandleAuraModStateImmunity(bool apply, bool Real)
{
if(apply && Real && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
{
Unit::AuraList const& auraList = GetTarget()->GetAurasByType(AuraType(m_modifier.m_miscvalue));
for(Unit::AuraList::const_iterator itr = auraList.begin(); itr != auraList.end();)
{
if (auraList.front() != this) // skip itself aura (it already added)
{
GetTarget()->RemoveAurasDueToSpell(auraList.front()->GetId());
itr = auraList.begin();
}
else
++itr;
}
}
GetTarget()->ApplySpellImmune(GetId(), IMMUNITY_STATE, m_modifier.m_miscvalue, apply);
}
void Aura::HandleAuraModSchoolImmunity(bool apply, bool Real)
{
Unit* target = GetTarget();
target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, m_modifier.m_miscvalue, apply);
// remove all flag auras (they are positive, but they must be removed when you are immune)
if( GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
&& GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_DAMAGE_REDUCED_SHIELD )
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
// TODO: optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else
if( Real && apply
&& GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY
&& IsPositiveSpell(GetId()) ) //Only positive immunity removes auras
{
uint32 school_mask = m_modifier.m_miscvalue;
Unit::SpellAuraHolderMap& Auras = target->GetSpellAuraHolderMap();
for(Unit::SpellAuraHolderMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
{
next = iter;
++next;
SpellEntry const *spell = iter->second->GetSpellProto();
if((GetSpellSchoolMask(spell) & school_mask)//Check for school mask
&& !( spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) //Spells unaffected by invulnerability
&& !iter->second->IsPositive() //Don't remove positive spells
&& spell->Id != GetId() ) //Don't remove self
{
target->RemoveAurasDueToSpell(spell->Id);
if(Auras.empty())
break;
else
next = Auras.begin();
}
}
}
if( Real && GetSpellProto()->Mechanic == MECHANIC_BANISH )
{
if( apply )
target->addUnitState(UNIT_STAT_ISOLATED);
else
target->clearUnitState(UNIT_STAT_ISOLATED);
}
}
void Aura::HandleAuraModDmgImmunity(bool apply, bool /*Real*/)
{
GetTarget()->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, m_modifier.m_miscvalue, apply);
}
void Aura::HandleAuraModDispelImmunity(bool apply, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
GetTarget()->ApplySpellDispelImmunity(GetSpellProto(), DispelType(m_modifier.m_miscvalue), apply);
}
void Aura::HandleAuraProcTriggerSpell(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
switch (GetId())
{
// some spell have charges by functionality not have its in spell data
case 28200: // Ascendance (Talisman of Ascendance trinket)
if(apply)
GetHolder()->SetAuraCharges(6);
break;
case 50720: // Vigilance (threat transfering)
if (apply)
{
if (Unit* caster = GetCaster())
target->CastSpell(caster, 59665, true);
}
else
target->getHostileRefManager().ResetThreatRedirection();
break;
default:
break;
}
}
void Aura::HandleAuraModStalked(bool apply, bool /*Real*/)
{
// used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND
if(apply)
GetTarget()->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
else
GetTarget()->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
}
/*********************************************************/
/*** PERIODIC ***/
/*********************************************************/
void Aura::HandlePeriodicTriggerSpell(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
Unit *target = GetTarget();
if (!apply)
{
switch(GetId())
{
case 66: // Invisibility
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
target->CastSpell(target, 32612, true, NULL, this);
return;
case 42783: // Wrath of the Astrom...
if (m_removeMode == AURA_REMOVE_BY_EXPIRE && GetEffIndex() + 1 < MAX_EFFECT_INDEX)
target->CastSpell(target, GetSpellProto()->CalculateSimpleValue(SpellEffectIndex(GetEffIndex()+1)), true);
return;
case 46221: // Animal Blood
if (target->GetTypeId() == TYPEID_PLAYER && m_removeMode == AURA_REMOVE_BY_DEFAULT && target->IsInWater())
{
float position_z = target->GetTerrain()->GetWaterLevel(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
// Spawn Blood Pool
target->CastSpell(target->GetPositionX(), target->GetPositionY(), position_z, 63471, true);
}
return;
case 51912: // Ultra-Advanced Proto-Typical Shortening Blaster
if (m_removeMode == AURA_REMOVE_BY_EXPIRE)
{
if (Unit* pCaster = GetCaster())
pCaster->CastSpell(target, GetSpellProto()->EffectTriggerSpell[GetEffIndex()], true, NULL, this);
}
return;
default:
break;
}
}
}
void Aura::HandlePeriodicTriggerSpellWithValue(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
}
void Aura::HandlePeriodicEnergize(bool apply, bool Real)
{
if (!Real)
return;
Unit *target = GetTarget();
// For prevent double apply bonuses
bool loading = (target->GetTypeId() == TYPEID_PLAYER && ((Player*)target)->GetSession()->PlayerLoading());
if (apply && !loading)
{
switch (GetId())
{
case 54833: // Glyph of Innervate (value%/2 of casters base mana)
{
if (Unit* caster = GetCaster())
m_modifier.m_amount = int32(caster->GetCreateMana() * GetBasePoints() / (200 * GetAuraMaxTicks()));
break;
}
case 29166: // Innervate (value% of casters base mana)
{
if (Unit* caster = GetCaster())
{
// Glyph of Innervate
if (caster->HasAura(54832))
caster->CastSpell(caster,54833,true,NULL,this);
m_modifier.m_amount = int32(caster->GetCreateMana() * GetBasePoints() / (100 * GetAuraMaxTicks()));
}
break;
}
case 48391: // Owlkin Frenzy 2% base mana
m_modifier.m_amount = target->GetCreateMana() * 2 / 100;
break;
case 57669: // Replenishment (0.2% from max)
case 61782: // Infinite Replenishment
m_modifier.m_amount = target->GetMaxPower(POWER_MANA) * 2 / 1000;
break;
default:
break;
}
}
m_isPeriodic = apply;
}
void Aura::HandleAuraPowerBurn(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
}
void Aura::HandleAuraPeriodicDummy(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
// For prevent double apply bonuses
bool loading = (target->GetTypeId() == TYPEID_PLAYER && ((Player*)target)->GetSession()->PlayerLoading());
SpellEntry const*spell = GetSpellProto();
switch( spell->SpellFamilyName)
{
case SPELLFAMILY_ROGUE:
{
if(!apply)
{
switch(spell->Id)
{
// Master of Subtlety
case 31666: target->RemoveAurasDueToSpell(31665); break;
}
}
break;
}
case SPELLFAMILY_HUNTER:
{
Unit* caster = GetCaster();
// Explosive Shot
if (apply && !loading && caster)
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 14 / 100);
break;
}
}
m_isPeriodic = apply;
}
void Aura::HandlePeriodicHeal(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
Unit *target = GetTarget();
// For prevent double apply bonuses
bool loading = (target->GetTypeId() == TYPEID_PLAYER && ((Player*)target)->GetSession()->PlayerLoading());
// Custom damage calculation after
if (apply)
{
if(loading)
return;
Unit *caster = GetCaster();
if (!caster)
return;
// Gift of the Naaru (have diff spellfamilies)
if (GetSpellProto()->SpellIconID == 329 && GetSpellProto()->SpellVisual[0] == 7625)
{
int32 ap = int32 (0.22f * caster->GetTotalAttackPowerValue(BASE_ATTACK));
int32 holy = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(GetSpellProto()));
if (holy < 0)
holy = 0;
holy = int32(holy * 377 / 1000);
m_modifier.m_amount += ap > holy ? ap : holy;
}
// Lifeblood
else if (GetSpellProto()->SpellIconID == 3088 && GetSpellProto()->SpellVisual[0] == 8145)
{
int32 healthBonus = int32 (0.0032f * caster->GetMaxHealth());
m_modifier.m_amount += healthBonus;
}
m_modifier.m_amount = caster->SpellHealingBonusDone(target, GetSpellProto(), m_modifier.m_amount, DOT, GetStackAmount());
}
}
void Aura::HandleDamagePercentTaken(bool apply, bool Real)
{
m_isPeriodic = apply;
Unit* target = GetTarget();
if (!Real)
return;
// For prevent double apply bonuses
bool loading = (target->GetTypeId() == TYPEID_PLAYER && ((Player*)target)->GetSession()->PlayerLoading());
if (apply)
{
if (loading)
return;
// Hand of Salvation (only it have this aura and mask)
if (GetSpellProto()->IsFitToFamily(SPELLFAMILY_PALADIN, UI64LIT(0x0000000000000100)))
{
// Glyph of Salvation
if (target->GetObjectGuid() == GetCasterGuid())
if (Aura* aur = target->GetAura(63225, EFFECT_INDEX_0))
m_modifier.m_amount -= aur->GetModifier()->m_amount;
}
}
}
void Aura::HandlePeriodicDamage(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
m_isPeriodic = apply;
Unit *target = GetTarget();
SpellEntry const* spellProto = GetSpellProto();
// For prevent double apply bonuses
bool loading = (target->GetTypeId() == TYPEID_PLAYER && ((Player*)target)->GetSession()->PlayerLoading());
// Custom damage calculation after
if (apply)
{
if(loading)
return;
Unit *caster = GetCaster();
if (!caster)
return;
switch (spellProto->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
{
// Rend
if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000020))
{
// $0.2*(($MWB+$mwb)/2+$AP/14*$MWS) bonus per tick
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 mws = caster->GetAttackTime(BASE_ATTACK);
float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK,MINDAMAGE);
float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK,MAXDAMAGE);
m_modifier.m_amount+=int32(((mwb_min+mwb_max)/2+ap*mws/14000)*0.2f);
// If used while target is above 75% health, Rend does 35% more damage
if (spellProto->CalculateSimpleValue(EFFECT_INDEX_1) !=0 &&
target->GetHealth() > target->GetMaxHealth() * spellProto->CalculateSimpleValue(EFFECT_INDEX_1) / 100)
m_modifier.m_amount += m_modifier.m_amount * spellProto->CalculateSimpleValue(EFFECT_INDEX_2) / 100;
}
break;
}
case SPELLFAMILY_DRUID:
{
// Rip
if (spellProto->SpellFamilyFlags & UI64LIT(0x000000000000800000))
{
// 0.01*$AP*cp
if (caster->GetTypeId() != TYPEID_PLAYER)
break;
uint8 cp = ((Player*)caster)->GetComboPoints();
// Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
if((*itr)->GetId()==34241)
{
m_modifier.m_amount += cp * (*itr)->GetModifier()->m_amount;
break;
}
}
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * cp / 100);
}
break;
}
case SPELLFAMILY_ROGUE:
{
// Rupture
if (spellProto->SpellFamilyFlags & UI64LIT(0x000000000000100000))
{
if (caster->GetTypeId() != TYPEID_PLAYER)
break;
//1 point : ${($m1+$b1*1+0.015*$AP)*4} damage over 8 secs
//2 points: ${($m1+$b1*2+0.024*$AP)*5} damage over 10 secs
//3 points: ${($m1+$b1*3+0.03*$AP)*6} damage over 12 secs
//4 points: ${($m1+$b1*4+0.03428571*$AP)*7} damage over 14 secs
//5 points: ${($m1+$b1*5+0.0375*$AP)*8} damage over 16 secs
float AP_per_combo[6] = {0.0f, 0.015f, 0.024f, 0.03f, 0.03428571f, 0.0375f};
uint8 cp = ((Player*)caster)->GetComboPoints();
if (cp > 5) cp = 5;
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]);
}
break;
}
case SPELLFAMILY_PALADIN:
{
// Holy Vengeance / Blood Corruption
if (spellProto->SpellFamilyFlags & UI64LIT(0x0000080000000000) && spellProto->SpellVisual[0] == 7902)
{
// AP * 0.025 + SPH * 0.013 bonus per tick
float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
int32 holy = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto));
if (holy < 0)
holy = 0;
m_modifier.m_amount += int32(GetStackAmount()) * (int32(ap * 0.025f) + int32(holy * 13 / 1000));
}
break;
}
default:
break;
}
if(m_modifier.m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
{
// SpellDamageBonusDone for magic spells
if(spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
m_modifier.m_amount = caster->SpellDamageBonusDone(target, GetSpellProto(), m_modifier.m_amount, DOT, GetStackAmount());
// MeleeDamagebonusDone for weapon based spells
else
{
WeaponAttackType attackType = GetWeaponAttackType(GetSpellProto());
m_modifier.m_amount = caster->MeleeDamageBonusDone(target, m_modifier.m_amount, attackType, GetSpellProto(), DOT, GetStackAmount());
}
}
}
// remove time effects
else
{
// Parasitic Shadowfiend - handle summoning of two Shadowfiends on DoT expire
if(spellProto->Id == 41917)
target->CastSpell(target, 41915, true);
}
}
void Aura::HandlePeriodicDamagePCT(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
}
void Aura::HandlePeriodicLeech(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
// For prevent double apply bonuses
bool loading = (GetTarget()->GetTypeId() == TYPEID_PLAYER && ((Player*)GetTarget())->GetSession()->PlayerLoading());
// Custom damage calculation after
if (apply)
{
if(loading)
return;
Unit *caster = GetCaster();
if (!caster)
return;
m_modifier.m_amount = caster->SpellDamageBonusDone(GetTarget(), GetSpellProto(), m_modifier.m_amount, DOT, GetStackAmount());
}
}
void Aura::HandlePeriodicManaLeech(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
}
void Aura::HandlePeriodicHealthFunnel(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
// For prevent double apply bonuses
bool loading = (GetTarget()->GetTypeId() == TYPEID_PLAYER && ((Player*)GetTarget())->GetSession()->PlayerLoading());
// Custom damage calculation after
if (apply)
{
if(loading)
return;
Unit *caster = GetCaster();
if (!caster)
return;
m_modifier.m_amount = caster->SpellDamageBonusDone(GetTarget(), GetSpellProto(), m_modifier.m_amount, DOT, GetStackAmount());
}
}
/*********************************************************/
/*** MODIFY STATS ***/
/*********************************************************/
/********************************/
/*** RESISTANCE ***/
/********************************/
void Aura::HandleAuraModResistanceExclusive(bool apply, bool /*Real*/)
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
if(m_modifier.m_miscvalue & int32(1<<x))
{
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(m_modifier.m_amount), apply);
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
GetTarget()->ApplyResistanceBuffModsMod(SpellSchools(x), m_positive, float(m_modifier.m_amount), apply);
}
}
}
void Aura::HandleAuraModResistance(bool apply, bool /*Real*/)
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
if(m_modifier.m_miscvalue & int32(1<<x))
{
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(m_modifier.m_amount), apply);
if(GetTarget()->GetTypeId() == TYPEID_PLAYER || ((Creature*)GetTarget())->IsPet())
GetTarget()->ApplyResistanceBuffModsMod(SpellSchools(x), m_positive, float(m_modifier.m_amount), apply);
}
}
}
void Aura::HandleAuraModBaseResistancePCT(bool apply, bool /*Real*/)
{
// only players have base stats
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
{
//pets only have base armor
if(((Creature*)GetTarget())->IsPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
GetTarget()->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(m_modifier.m_amount), apply);
}
else
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
if(m_modifier.m_miscvalue & int32(1<<x))
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(m_modifier.m_amount), apply);
}
}
}
void Aura::HandleModResistancePercent(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
for(int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
{
if(m_modifier.m_miscvalue & int32(1<<i))
{
target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
if(target->GetTypeId() == TYPEID_PLAYER || ((Creature*)target)->IsPet())
{
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, float(m_modifier.m_amount), apply);
target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, float(m_modifier.m_amount), apply);
}
}
}
}
void Aura::HandleModBaseResistance(bool apply, bool /*Real*/)
{
// only players have base stats
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
{
//only pets have base stats
if(((Creature*)GetTarget())->IsPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
GetTarget()->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
else
{
for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
if(m_modifier.m_miscvalue & (1<<i))
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
}
/********************************/
/*** STAT ***/
/********************************/
void Aura::HandleAuraModStat(bool apply, bool /*Real*/)
{
if (m_modifier.m_miscvalue < -2 || m_modifier.m_miscvalue > 4)
{
sLog.outError("WARNING: Spell %u effect %u have unsupported misc value (%i) for SPELL_AURA_MOD_STAT ",GetId(),GetEffIndex(),m_modifier.m_miscvalue);
return;
}
for(int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
// -1 or -2 is all stats ( misc < -2 checked in function beginning )
if (m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue == i)
{
//m_target->ApplyStatMod(Stats(i), m_modifier.m_amount,apply);
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(m_modifier.m_amount), apply);
if(GetTarget()->GetTypeId() == TYPEID_PLAYER || ((Creature*)GetTarget())->IsPet())
GetTarget()->ApplyStatBuffMod(Stats(i), float(m_modifier.m_amount), apply);
}
}
}
void Aura::HandleModPercentStat(bool apply, bool /*Real*/)
{
if (m_modifier.m_miscvalue < -1 || m_modifier.m_miscvalue > 4)
{
sLog.outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
return;
}
// only players have base stats
if (GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
GetTarget()->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_modifier.m_amount), apply);
}
}
void Aura::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Magic damage modifiers implemented in Unit::SpellDamageBonusDone
// This information for client side use only
// Recalculate bonus
((Player*)GetTarget())->UpdateSpellDamageAndHealingBonus();
}
void Aura::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Recalculate bonus
((Player*)GetTarget())->UpdateSpellDamageAndHealingBonus();
}
void Aura::HandleAuraModDispelResist(bool apply, bool Real)
{
if(!Real || !apply)
return;
if(GetId() == 33206)
GetTarget()->CastSpell(GetTarget(), 44416, true, NULL, this, GetCasterGuid());
}
void Aura::HandleModSpellDamagePercentFromAttackPower(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Magic damage modifiers implemented in Unit::SpellDamageBonusDone
// This information for client side use only
// Recalculate bonus
((Player*)GetTarget())->UpdateSpellDamageAndHealingBonus();
}
void Aura::HandleModSpellHealingPercentFromAttackPower(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Recalculate bonus
((Player*)GetTarget())->UpdateSpellDamageAndHealingBonus();
}
void Aura::HandleModHealingDone(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// implemented in Unit::SpellHealingBonusDone
// this information is for client side only
((Player*)GetTarget())->UpdateSpellDamageAndHealingBonus();
}
void Aura::HandleModTotalPercentStat(bool apply, bool /*Real*/)
{
if (m_modifier.m_miscvalue < -1 || m_modifier.m_miscvalue > 4)
{
sLog.outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid");
return;
}
Unit *target = GetTarget();
//save current and max HP before applying aura
uint32 curHPValue = target->GetHealth();
uint32 maxHPValue = target->GetMaxHealth();
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
{
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
{
target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
if(target->GetTypeId() == TYPEID_PLAYER || ((Creature*)target)->IsPet())
target->ApplyStatPercentBuffMod(Stats(i), float(m_modifier.m_amount), apply );
}
}
//recalculate current HP/MP after applying aura modifications (only for spells with 0x10 flag)
if ((m_modifier.m_miscvalue == STAT_STAMINA) && (maxHPValue > 0) && (GetSpellProto()->Attributes & 0x10))
{
// newHP = (curHP / maxHP) * newMaxHP = (newMaxHP * curHP) / maxHP -> which is better because no int -> double -> int conversion is needed
uint32 newHPValue = (target->GetMaxHealth() * curHPValue) / maxHPValue;
target->SetHealth(newHPValue);
}
}
void Aura::HandleAuraModResistenceOfStatPercent(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
if(m_modifier.m_miscvalue != SPELL_SCHOOL_MASK_NORMAL)
{
// support required adding replace UpdateArmor by loop by UpdateResistence at intellect update
// and include in UpdateResistence same code as in UpdateArmor for aura mod apply.
sLog.outError("Aura SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT(182) need adding support for non-armor resistances!");
return;
}
// Recalculate Armor
GetTarget()->UpdateArmor();
}
/********************************/
/*** HEAL & ENERGIZE ***/
/********************************/
void Aura::HandleAuraModTotalHealthPercentRegen(bool apply, bool /*Real*/)
{
m_isPeriodic = apply;
}
void Aura::HandleAuraModTotalManaPercentRegen(bool apply, bool /*Real*/)
{
if(m_modifier.periodictime == 0)
m_modifier.periodictime = 1000;
m_periodicTimer = m_modifier.periodictime;
m_isPeriodic = apply;
}
void Aura::HandleModRegen(bool apply, bool /*Real*/) // eating
{
if(m_modifier.periodictime == 0)
m_modifier.periodictime = 5000;
m_periodicTimer = 5000;
m_isPeriodic = apply;
}
void Aura::HandleModPowerRegen(bool apply, bool Real) // drinking
{
if (!Real)
return;
Powers pt = GetTarget()->getPowerType();
if(m_modifier.periodictime == 0)
{
// Anger Management (only spell use this aura for rage)
if (pt == POWER_RAGE)
m_modifier.periodictime = 3000;
else
m_modifier.periodictime = 2000;
}
m_periodicTimer = 5000;
if (GetTarget()->GetTypeId() == TYPEID_PLAYER && m_modifier.m_miscvalue == POWER_MANA)
((Player*)GetTarget())->UpdateManaRegen();
m_isPeriodic = apply;
}
void Aura::HandleModPowerRegenPCT(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if (GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Update manaregen value
if (m_modifier.m_miscvalue == POWER_MANA)
((Player*)GetTarget())->UpdateManaRegen();
}
void Aura::HandleModManaRegen(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if (GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
//Note: an increase in regen does NOT cause threat.
((Player*)GetTarget())->UpdateManaRegen();
}
void Aura::HandleComprehendLanguage(bool apply, bool /*Real*/)
{
if(apply)
GetTarget()->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
else
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
}
void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
{
Unit *target = GetTarget();
// Special case with temporary increase max/current health
switch(GetId())
{
case 12976: // Warrior Last Stand triggered spell
case 28726: // Nightmare Seed ( Nightmare Seed )
case 31616: // Nature's Guardian
case 34511: // Valor (Bulwark of Kings, Bulwark of the Ancient Kings)
case 44055: case 55915: case 55917: case 67596: // Tremendous Fortitude (Battlemaster's Alacrity)
case 50322: // Survival Instincts
case 53479: // Hunter pet - Last Stand
case 54443: // Demonic Empowerment (Voidwalker)
case 55233: // Vampiric Blood
case 59465: // Brood Rage (Ahn'Kahet)
{
if(Real)
{
if(apply)
{
// Demonic Empowerment (Voidwalker) & Vampiric Blood - special cases, store percent in data
// recalculate to full amount at apply for proper remove
if (GetId() == 54443 || GetId() == 55233)
m_modifier.m_amount = target->GetMaxHealth() * m_modifier.m_amount / 100;
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
target->ModifyHealth(m_modifier.m_amount);
}
else
{
if (int32(target->GetHealth()) > m_modifier.m_amount)
target->ModifyHealth(-m_modifier.m_amount);
else
target->SetHealth(1);
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
}
return;
}
}
// generic case
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModIncreaseMaxHealth(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
uint32 oldhealth = target->GetHealth();
double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth();
target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
// refresh percentage
if(oldhealth > 0)
{
uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage));
if(newhealth==0)
newhealth = 1;
target->SetHealth(newhealth);
}
}
void Aura::HandleAuraModIncreaseEnergy(bool apply, bool Real)
{
Unit *target = GetTarget();
Powers powerType = target->getPowerType();
if(int32(powerType) != m_modifier.m_miscvalue)
return;
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
// Special case with temporary increase max/current power (percent)
if (GetId()==64904) // Hymn of Hope
{
if(Real)
{
uint32 val = target->GetPower(powerType);
target->HandleStatModifier(unitMod, TOTAL_PCT, float(m_modifier.m_amount), apply);
target->SetPower(powerType, apply ? val*(100+m_modifier.m_amount)/100 : val*100/(100+m_modifier.m_amount));
}
return;
}
// generic flat case
target->HandleStatModifier(unitMod, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModIncreaseEnergyPercent(bool apply, bool /*Real*/)
{
Powers powerType = GetTarget()->getPowerType();
if(int32(powerType) != m_modifier.m_miscvalue)
return;
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
GetTarget()->HandleStatModifier(unitMod, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModIncreaseHealthPercent(bool apply, bool /*Real*/)
{
GetTarget()->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraIncreaseBaseHealthPercent(bool apply, bool /*Real*/)
{
GetTarget()->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(m_modifier.m_amount), apply);
}
/********************************/
/*** FIGHT ***/
/********************************/
void Aura::HandleAuraModParryPercent(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateParryPercentage();
}
void Aura::HandleAuraModDodgePercent(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateDodgePercentage();
//sLog.outError("BONUS DODGE CHANCE: + %f", float(m_modifier.m_amount));
}
void Aura::HandleAuraModBlockPercent(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateBlockPercentage();
//sLog.outError("BONUS BLOCK CHANCE: + %f", float(m_modifier.m_amount));
}
void Aura::HandleAuraModRegenInterrupt(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateManaRegen();
}
void Aura::HandleAuraModCritPercent(bool apply, bool Real)
{
Unit *target = GetTarget();
if(target->GetTypeId() != TYPEID_PLAYER)
return;
// apply item specific bonuses for already equipped weapon
if(Real)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)target)->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply);
}
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// m_modifier.m_miscvalue comparison with item generated damage types
if (GetSpellProto()->EquippedItemClass == -1)
{
((Player*)target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
((Player*)target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
((Player*)target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
}
void Aura::HandleModHitChance(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
if(target->GetTypeId() == TYPEID_PLAYER)
{
((Player*)target)->UpdateMeleeHitChances();
((Player*)target)->UpdateRangedHitChances();
}
else
{
target->m_modMeleeHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
target->m_modRangedHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
}
}
void Aura::HandleModSpellHitChance(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
((Player*)GetTarget())->UpdateSpellHitChances();
}
else
{
GetTarget()->m_modSpellHitChance += apply ? m_modifier.m_amount: (-m_modifier.m_amount);
}
}
void Aura::HandleModSpellCritChance(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
{
((Player*)GetTarget())->UpdateAllSpellCritChances();
}
else
{
GetTarget()->m_baseSpellCritChance += apply ? m_modifier.m_amount:(-m_modifier.m_amount);
}
}
void Aura::HandleModSpellCritChanceShool(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
for(int school = SPELL_SCHOOL_NORMAL; school < MAX_SPELL_SCHOOL; ++school)
if (m_modifier.m_miscvalue & (1<<school))
((Player*)GetTarget())->UpdateSpellCritChance(school);
}
/********************************/
/*** ATTACK SPEED ***/
/********************************/
void Aura::HandleModCastingSpeed(bool apply, bool /*Real*/)
{
GetTarget()->ApplyCastTimePercentMod(float(m_modifier.m_amount),apply);
}
void Aura::HandleModMeleeRangedSpeedPct(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(m_modifier.m_amount), apply);
}
void Aura::HandleModCombatSpeedPct(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
target->ApplyCastTimePercentMod(float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(m_modifier.m_amount), apply);
}
void Aura::HandleModAttackSpeed(bool apply, bool /*Real*/)
{
GetTarget()->ApplyAttackTimePercentMod(BASE_ATTACK,float(m_modifier.m_amount),apply);
}
void Aura::HandleModMeleeSpeedPct(bool apply, bool /*Real*/)
{
Unit *target = GetTarget();
target->ApplyAttackTimePercentMod(BASE_ATTACK, float(m_modifier.m_amount), apply);
target->ApplyAttackTimePercentMod(OFF_ATTACK, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModRangedHaste(bool apply, bool /*Real*/)
{
GetTarget()->ApplyAttackTimePercentMod(RANGED_ATTACK, float(m_modifier.m_amount), apply);
}
void Aura::HandleRangedAmmoHaste(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
GetTarget()->ApplyAttackTimePercentMod(RANGED_ATTACK, float(m_modifier.m_amount), apply);
}
/********************************/
/*** ATTACK POWER ***/
/********************************/
void Aura::HandleAuraModAttackPower(bool apply, bool /*Real*/)
{
GetTarget()->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModRangedAttackPower(bool apply, bool /*Real*/)
{
if((GetTarget()->getClassMask() & CLASSMASK_WAND_USERS)!=0)
return;
GetTarget()->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModAttackPowerPercent(bool apply, bool /*Real*/)
{
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
GetTarget()->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModRangedAttackPowerPercent(bool apply, bool /*Real*/)
{
if((GetTarget()->getClassMask() & CLASSMASK_WAND_USERS)!=0)
return;
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
GetTarget()->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraModRangedAttackPowerOfStatPercent(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
// Recalculate bonus
if(GetTarget()->GetTypeId() == TYPEID_PLAYER && !(GetTarget()->getClassMask() & CLASSMASK_WAND_USERS))
((Player*)GetTarget())->UpdateAttackPowerAndDamage(true);
}
void Aura::HandleAuraModAttackPowerOfStatPercent(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
// Recalculate bonus
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
((Player*)GetTarget())->UpdateAttackPowerAndDamage(false);
}
void Aura::HandleAuraModAttackPowerOfArmor(bool /*apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
// Recalculate bonus
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
((Player*)GetTarget())->UpdateAttackPowerAndDamage(false);
}
/********************************/
/*** DAMAGE BONUS ***/
/********************************/
void Aura::HandleModDamageDone(bool apply, bool Real)
{
Unit *target = GetTarget();
// apply item specific bonuses for already equipped weapon
if(Real && target->GetTypeId() == TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)target)->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
// m_modifier.m_miscvalue is bitmask of spell schools
// 1 ( 0-bit ) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// m_modifier.m_miscvalue comparison with item generated damage types
if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) != 0)
{
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)
{
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(m_modifier.m_amount), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
if(target->GetTypeId() == TYPEID_PLAYER)
{
if(m_positive)
target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, m_modifier.m_amount, apply);
else
target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, m_modifier.m_amount, apply);
}
}
// Skip non magic case for speedup
if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if( GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0 )
{
// wand magic case (skip generic to all item spell bonuses)
// done in Player::_ApplyWeaponDependentAuraMods
// Skip item specific requirements for not wand magic damage
return;
}
// Magic damage modifiers implemented in Unit::SpellDamageBonusDone
// This information for client side use only
if(target->GetTypeId() == TYPEID_PLAYER)
{
if(m_positive)
{
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
{
if((m_modifier.m_miscvalue & (1<<i)) != 0)
target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, m_modifier.m_amount, apply);
}
}
else
{
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
{
if((m_modifier.m_miscvalue & (1<<i)) != 0)
target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, m_modifier.m_amount, apply);
}
}
Pet* pet = target->GetPet();
if(pet)
pet->UpdateAttackPowerAndDamage();
}
}
void Aura::HandleModDamagePercentDone(bool apply, bool Real)
{
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "AURA MOD DAMAGE type:%u negative:%u", m_modifier.m_miscvalue, m_positive ? 0 : 1);
Unit *target = GetTarget();
// apply item specific bonuses for already equipped weapon
if(Real && target->GetTypeId() == TYPEID_PLAYER)
{
for(int i = 0; i < MAX_ATTACK; ++i)
if(Item* pItem = ((Player*)target)->GetWeaponForAttack(WeaponAttackType(i),true,false))
((Player*)target)->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply);
}
// m_modifier.m_miscvalue is bitmask of spell schools
// 1 ( 0-bit ) - normal school damage (SPELL_SCHOOL_MASK_NORMAL)
// 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wand
// 127 - full bitmask any damages
//
// mods must be applied base at equipped weapon class and subclass comparison
// with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask
// m_modifier.m_miscvalue comparison with item generated damage types
if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) != 0)
{
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER)
{
target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
else
{
// done in Player::_ApplyWeaponDependentAuraMods
}
// For show in client
if(target->GetTypeId() == TYPEID_PLAYER)
target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, m_modifier.m_amount/100.0f, apply);
}
// Skip non magic case for speedup
if((m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_MAGIC) == 0)
return;
if( GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0 )
{
// wand magic case (skip generic to all item spell bonuses)
// done in Player::_ApplyWeaponDependentAuraMods
// Skip item specific requirements for not wand magic damage
return;
}
// Magic damage percent modifiers implemented in Unit::SpellDamageBonusDone
// Send info to client
if(target->GetTypeId() == TYPEID_PLAYER)
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
target->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i, m_modifier.m_amount/100.0f, apply);
}
void Aura::HandleModOffhandDamagePercent(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "AURA MOD OFFHAND DAMAGE");
GetTarget()->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
}
/********************************/
/*** POWER COST ***/
/********************************/
void Aura::HandleModPowerCostPCT(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
float amount = m_modifier.m_amount/100.0f;
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
if(m_modifier.m_miscvalue & (1<<i))
GetTarget()->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + i, amount, apply);
}
void Aura::HandleModPowerCost(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
if(m_modifier.m_miscvalue & (1<<i))
GetTarget()->ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + i, m_modifier.m_amount, apply);
}
void Aura::HandleNoReagentUseAura(bool /*Apply*/, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
if(target->GetTypeId() != TYPEID_PLAYER)
return;
ClassFamilyMask mask;
Unit::AuraList const& noReagent = target->GetAurasByType(SPELL_AURA_NO_REAGENT_USE);
for(Unit::AuraList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i)
mask |= (*i)->GetAuraSpellClassMask();
target->SetUInt64Value(PLAYER_NO_REAGENT_COST_1+0, mask.Flags);
target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask.Flags2);
}
/*********************************************************/
/*** OTHERS ***/
/*********************************************************/
void Aura::HandleShapeshiftBoosts(bool apply)
{
uint32 spellId1 = 0;
uint32 spellId2 = 0;
uint32 HotWSpellId = 0;
uint32 MasterShaperSpellId = 0;
ShapeshiftForm form = ShapeshiftForm(GetModifier()->m_miscvalue);
Unit *target = GetTarget();
switch(form)
{
case FORM_CAT:
spellId1 = 3025;
HotWSpellId = 24900;
MasterShaperSpellId = 48420;
break;
case FORM_TREE:
spellId1 = 5420;
spellId2 = 34123;
MasterShaperSpellId = 48422;
break;
case FORM_TRAVEL:
spellId1 = 5419;
break;
case FORM_AQUA:
spellId1 = 5421;
break;
case FORM_BEAR:
spellId1 = 1178;
spellId2 = 21178;
HotWSpellId = 24899;
MasterShaperSpellId = 48418;
break;
case FORM_DIREBEAR:
spellId1 = 9635;
spellId2 = 21178;
HotWSpellId = 24899;
MasterShaperSpellId = 48418;
break;
case FORM_BATTLESTANCE:
spellId1 = 21156;
break;
case FORM_DEFENSIVESTANCE:
spellId1 = 7376;
break;
case FORM_BERSERKERSTANCE:
spellId1 = 7381;
break;
case FORM_MOONKIN:
spellId1 = 24905;
spellId2 = 69366;
MasterShaperSpellId = 48421;
break;
case FORM_FLIGHT:
spellId1 = 33948;
spellId2 = 34764;
break;
case FORM_FLIGHT_EPIC:
spellId1 = 40122;
spellId2 = 40121;
break;
case FORM_METAMORPHOSIS:
spellId1 = 54817;
spellId2 = 54879;
break;
case FORM_SPIRITOFREDEMPTION:
spellId1 = 27792;
spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation.
break;
case FORM_SHADOW:
spellId1 = 49868;
if(target->GetTypeId() == TYPEID_PLAYER) // Spell 49868 have same category as main form spell and share cooldown
((Player*)target)->RemoveSpellCooldown(49868);
break;
case FORM_GHOSTWOLF:
spellId1 = 67116;
break;
case FORM_AMBIENT:
case FORM_GHOUL:
case FORM_STEALTH:
case FORM_CREATURECAT:
case FORM_CREATUREBEAR:
break;
}
if(apply)
{
if (spellId1)
target->CastSpell(target, spellId1, true, NULL, this );
if (spellId2)
target->CastSpell(target, spellId2, true, NULL, this);
if (target->GetTypeId() == TYPEID_PLAYER)
{
const PlayerSpellMap& sp_list = ((Player *)target)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
{
if (itr->second.state == PLAYERSPELL_REMOVED) continue;
if (itr->first==spellId1 || itr->first==spellId2) continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (!spellInfo || !IsNeedCastSpellAtFormApply(spellInfo, form))
continue;
target->CastSpell(target, itr->first, true, NULL, this);
}
// remove auras that do not require shapeshift, but are not active in this specific form (like Improved Barkskin)
Unit::SpellAuraHolderMap& tAuras = target->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
SpellEntry const *spellInfo = itr->second->GetSpellProto();
if (itr->second->IsPassive() && (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT)
&& (spellInfo->StancesNot & (1<<(form-1))))
{
target->RemoveAurasDueToSpell(itr->second->GetId());
itr = tAuras.begin();
}
else
++itr;
}
// Master Shapeshifter
if (MasterShaperSpellId)
{
Unit::AuraList const& ShapeShifterAuras = target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = ShapeShifterAuras.begin(); i != ShapeShifterAuras.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellIconID == 2851)
{
int32 ShiftMod = (*i)->GetModifier()->m_amount;
target->CastCustomSpell(target, MasterShaperSpellId, &ShiftMod, NULL, NULL, true);
break;
}
}
}
// Leader of the Pack
if (((Player*)target)->HasSpell(17007))
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932);
if (spellInfo && spellInfo->Stances & (1<<(form-1)))
target->CastSpell(target, 24932, true, NULL, this);
}
// Savage Roar
if (form == FORM_CAT && ((Player*)target)->HasAura(52610))
target->CastSpell(target, 62071, true);
// Survival of the Fittest (Armor part)
if (form == FORM_BEAR || form == FORM_DIREBEAR)
{
Unit::AuraList const& modAuras = target->GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
for (Unit::AuraList::const_iterator i = modAuras.begin(); i != modAuras.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
(*i)->GetSpellProto()->SpellIconID == 961)
{
int32 bp = (*i)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_2);
if (bp)
target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, NULL, this);
break;
}
}
}
// Improved Moonkin Form
if (form == FORM_MOONKIN)
{
Unit::AuraList const& dummyAuras = target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID &&
(*i)->GetSpellProto()->SpellIconID == 2855)
{
uint32 spell_id = 0;
switch((*i)->GetId())
{
case 48384:spell_id=50170;break;//Rank 1
case 48395:spell_id=50171;break;//Rank 2
case 48396:spell_id=50172;break;//Rank 3
default:
sLog.outError("Aura::HandleShapeshiftBoosts: Not handled rank of IMF (Spell: %u)",(*i)->GetId());
break;
}
if(spell_id)
target->CastSpell(target, spell_id, true, NULL, this);
break;
}
}
}
// Heart of the Wild
if (HotWSpellId)
{
Unit::AuraList const& mModTotalStatPct = target->GetAurasByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
for(Unit::AuraList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i)
{
if ((*i)->GetSpellProto()->SpellIconID == 240 && (*i)->GetModifier()->m_miscvalue == 3)
{
int32 HotWMod = (*i)->GetModifier()->m_amount;
if(GetModifier()->m_miscvalue == FORM_CAT)
HotWMod /= 2;
target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this);
break;
}
}
}
}
}
else
{
if(spellId1)
target->RemoveAurasDueToSpell(spellId1);
if(spellId2)
target->RemoveAurasDueToSpell(spellId2);
if(MasterShaperSpellId)
target->RemoveAurasDueToSpell(MasterShaperSpellId);
if (target->GetTypeId() == TYPEID_PLAYER)
{
// re-apply passive spells that don't need shapeshift but were inactive in current form:
const PlayerSpellMap& sp_list = ((Player *)target)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
{
if (itr->second.state == PLAYERSPELL_REMOVED) continue;
if (itr->first==spellId1 || itr->first==spellId2) continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (!spellInfo || !IsPassiveSpell(spellInfo))
continue;
if ((spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) && spellInfo->StancesNot & (1<<(form-1)))
target->CastSpell(target, itr->first, true, NULL, this);
}
}
Unit::SpellAuraHolderMap& tAuras = target->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
{
if (itr->second->IsRemovedOnShapeLost())
{
target->RemoveAurasDueToSpell(itr->second->GetId());
itr = tAuras.begin();
}
else
++itr;
}
}
}
void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_UNIT)
return;
CreatureInfo const * ci = ObjectMgr::GetCreatureTemplate(GetTarget()->GetEntry());
if(ci && ci->type == CREATURE_TYPE_BEAST)
GetTarget()->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply);
}
void Aura::HandleAuraUntrackable(bool apply, bool /*Real*/)
{
if(apply)
GetTarget()->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
else
GetTarget()->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
}
void Aura::HandleAuraModPacify(bool apply, bool /*Real*/)
{
if (apply)
GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
else
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
}
void Aura::HandleAuraModPacifyAndSilence(bool apply, bool Real)
{
HandleAuraModPacify(apply, Real);
HandleAuraModSilence(apply, Real);
}
void Aura::HandleAuraGhost(bool apply, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
if(apply)
{
GetTarget()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
}
else
{
GetTarget()->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
}
}
void Aura::HandleAuraAllowFlight(bool apply, bool Real)
{
// all applied/removed only at real aura add/remove
if(!Real)
return;
// allow fly
WorldPacket data;
if(apply)
data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
else
data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
data << GetTarget()->GetPackGUID();
data << uint32(0); // unk
GetTarget()->SendMessageToSet(&data, true);
}
void Aura::HandleModRating(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (m_modifier.m_miscvalue & (1 << rating))
((Player*)GetTarget())->ApplyRatingMod(CombatRating(rating), m_modifier.m_amount, apply);
}
void Aura::HandleModRatingFromStat(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
// Just recalculate ratings
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (m_modifier.m_miscvalue & (1 << rating))
((Player*)GetTarget())->ApplyRatingMod(CombatRating(rating), 0, apply);
}
void Aura::HandleForceMoveForward(bool apply, bool Real)
{
if(!Real)
return;
if(apply)
GetTarget()->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
else
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
}
void Aura::HandleAuraModExpertise(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateExpertise(BASE_ATTACK);
((Player*)GetTarget())->UpdateExpertise(OFF_ATTACK);
}
void Aura::HandleModTargetResistance(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
// applied to damage as HandleNoImmediateEffect in Unit::CalculateAbsorbAndResist and Unit::CalcArmorReducedDamage
// show armor penetration
if (target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE, m_modifier.m_amount, apply);
// show as spell penetration only full spell penetration bonuses (all resistances except armor and holy
if (target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_SPELL)==SPELL_SCHOOL_MASK_SPELL)
target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, m_modifier.m_amount, apply);
}
void Aura::HandleShieldBlockValue(bool apply, bool /*Real*/)
{
BaseModType modType = FLAT_MOD;
if(m_modifier.m_auraname == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT)
modType = PCT_MOD;
if(GetTarget()->GetTypeId() == TYPEID_PLAYER)
((Player*)GetTarget())->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(m_modifier.m_amount), apply);
}
void Aura::HandleAuraRetainComboPoints(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
Player *target = (Player*)GetTarget();
// combo points was added in SPELL_EFFECT_ADD_COMBO_POINTS handler
// remove only if aura expire by time (in case combo points amount change aura removed without combo points lost)
if (!apply && m_removeMode == AURA_REMOVE_BY_EXPIRE && target->GetComboTargetGuid())
if (Unit* unit = ObjectAccessor::GetUnit(*GetTarget(),target->GetComboTargetGuid()))
target->AddComboPoints(unit, -m_modifier.m_amount);
}
void Aura::HandleModUnattackable( bool Apply, bool Real )
{
if(Real && Apply)
{
GetTarget()->CombatStop();
GetTarget()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
}
GetTarget()->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE,Apply);
}
void Aura::HandleSpiritOfRedemption( bool apply, bool Real )
{
// spells required only Real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
// prepare spirit state
if(apply)
{
if(target->GetTypeId()==TYPEID_PLAYER)
{
// disable breath/etc timers
((Player*)target)->StopMirrorTimers();
// set stand state (expected in this form)
if(!target->IsStandState())
target->SetStandState(UNIT_STAND_STATE_STAND);
}
target->SetHealth(1);
}
// die at aura end
else
target->DealDamage(target, target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, GetSpellProto(), false);
}
void Aura::HandleSchoolAbsorb(bool apply, bool Real)
{
if(!Real)
return;
Unit* caster = GetCaster();
if(!caster)
return;
Unit *target = GetTarget();
SpellEntry const* spellProto = GetSpellProto();
if (apply)
{
// prevent double apply bonuses
if (target->GetTypeId()!=TYPEID_PLAYER || !((Player*)target)->GetSession()->PlayerLoading())
{
float DoneActualBenefit = 0.0f;
switch(spellProto->SpellFamilyName)
{
case SPELLFAMILY_PRIEST:
// Power Word: Shield
if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001))
{
//+80.68% from +spell bonus
DoneActualBenefit = caster->SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto)) * 0.8068f;
//Borrowed Time
Unit::AuraList const& borrowedTime = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = borrowedTime.begin(); itr != borrowedTime.end(); ++itr)
{
SpellEntry const* i_spell = (*itr)->GetSpellProto();
if(i_spell->SpellFamilyName==SPELLFAMILY_PRIEST && i_spell->SpellIconID == 2899 && i_spell->EffectMiscValue[(*itr)->GetEffIndex()] == 24)
{
DoneActualBenefit += DoneActualBenefit * (*itr)->GetModifier()->m_amount / 100;
break;
}
}
}
break;
case SPELLFAMILY_MAGE:
// Frost Ward, Fire Ward
if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000108)))
//+10% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto)) * 0.1f;
// Ice Barrier
else if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000100000000)))
//+80.67% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto)) * 0.8067f;
break;
case SPELLFAMILY_WARLOCK:
// Shadow Ward
if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00000040))
//+30% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(spellProto)) * 0.30f;
break;
case SPELLFAMILY_PALADIN:
// Sacred Shield
// (check not strictly needed, only Sacred Shield has SPELL_AURA_SCHOOL_ABSORB in SPELLFAMILY_PALADIN at this time)
if (spellProto->IsFitToFamilyMask(UI64LIT(0x0008000000000000)))
{
// +75% from spell power
DoneActualBenefit = caster->SpellBaseHealingBonusDone(GetSpellSchoolMask(spellProto)) * 0.75f;
}
break;
default:
break;
}
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit;
}
}
else
{
if (caster &&
// Power Word: Shield
spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && spellProto->Mechanic == MECHANIC_SHIELD &&
(spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) &&
// completely absorbed or dispelled
(m_removeMode == AURA_REMOVE_BY_SHIELD_BREAK || m_removeMode == AURA_REMOVE_BY_DISPEL))
{
Unit::AuraList const& vDummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
{
SpellEntry const* vSpell = (*itr)->GetSpellProto();
// Rapture (main spell)
if(vSpell->SpellFamilyName == SPELLFAMILY_PRIEST && vSpell->SpellIconID == 2894 && vSpell->Effect[EFFECT_INDEX_1])
{
switch((*itr)->GetEffIndex())
{
case EFFECT_INDEX_0:
{
// energize caster
int32 manapct1000 = 5 * ((*itr)->GetModifier()->m_amount + sSpellMgr.GetSpellRank(vSpell->Id));
int32 basepoints0 = caster->GetMaxPower(POWER_MANA) * manapct1000 / 1000;
caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true);
break;
}
case EFFECT_INDEX_1:
{
// energize target
if (!roll_chance_i((*itr)->GetModifier()->m_amount) || caster->HasAura(63853))
break;
switch(target->getPowerType())
{
case POWER_RUNIC_POWER:
target->CastSpell(target, 63652, true, NULL, NULL, GetCasterGuid());
break;
case POWER_RAGE:
target->CastSpell(target, 63653, true, NULL, NULL, GetCasterGuid());
break;
case POWER_MANA:
{
int32 basepoints0 = target->GetMaxPower(POWER_MANA) * 2 / 100;
target->CastCustomSpell(target, 63654, &basepoints0, NULL, NULL, true);
break;
}
case POWER_ENERGY:
target->CastSpell(target, 63655, true, NULL, NULL, GetCasterGuid());
break;
default:
break;
}
//cooldown aura
caster->CastSpell(caster, 63853, true);
break;
}
default:
sLog.outError("Changes in R-dummy spell???: effect 3");
break;
}
}
}
}
}
}
void Aura::PeriodicTick()
{
Unit *target = GetTarget();
SpellEntry const* spellProto = GetSpellProto();
switch(m_modifier.m_auraname)
{
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
{
// don't damage target if not alive, possible death persistent effects
if (!target->isAlive())
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
if( spellProto->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA &&
pCaster->SpellHitResult(target, spellProto, false) != SPELL_MISS_NONE)
return;
// Check for immune (not use charges)
if(target->IsImmunedToDamage(GetSpellSchoolMask(spellProto)))
return;
// some auras remove at specific health level or more
if(m_modifier.m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
{
switch(GetId())
{
case 43093: case 31956: case 38801:
case 35321: case 38363: case 39215:
case 48920:
{
if(target->GetHealth() == target->GetMaxHealth() )
{
target->RemoveAurasDueToSpell(GetId());
return;
}
break;
}
case 38772:
{
uint32 percent =
GetEffIndex() < EFFECT_INDEX_2 && spellProto->Effect[GetEffIndex()] == SPELL_EFFECT_DUMMY ?
pCaster->CalculateSpellDamage(target, spellProto, SpellEffectIndex(GetEffIndex() + 1)) :
100;
if(target->GetHealth() * 100 >= target->GetMaxHealth() * percent )
{
target->RemoveAurasDueToSpell(GetId());
return;
}
break;
}
default:
break;
}
}
uint32 absorb = 0;
uint32 resist = 0;
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
// ignore non positive values (can be result apply spellmods to aura damage
uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
uint32 pdamage;
if(m_modifier.m_auraname == SPELL_AURA_PERIODIC_DAMAGE)
pdamage = amount;
else
pdamage = uint32(target->GetMaxHealth()*amount/100);
// SpellDamageBonus for magic spells
if(spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE || spellProto->DmgClass == SPELL_DAMAGE_CLASS_MAGIC)
pdamage = target->SpellDamageBonusTaken(pCaster, spellProto, pdamage, DOT, GetStackAmount());
// MeleeDamagebonus for weapon based spells
else
{
WeaponAttackType attackType = GetWeaponAttackType(spellProto);
pdamage = target->MeleeDamageBonusTaken(pCaster, pdamage, attackType, spellProto, DOT, GetStackAmount());
}
// Calculate armor mitigation if it is a physical spell
// But not for bleed mechanic spells
if (GetSpellSchoolMask(spellProto) & SPELL_SCHOOL_MASK_NORMAL &&
GetEffectMechanic(spellProto, m_effIndex) != MECHANIC_BLEED)
{
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(target, pdamage);
cleanDamage.damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
// Curse of Agony damage-per-tick calculation
if (spellProto->SpellFamilyName==SPELLFAMILY_WARLOCK && (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000400)) && spellProto->SpellIconID==544)
{
// 1..4 ticks, 1/2 from normal tick damage
if (GetAuraTicks() <= 4)
pdamage = pdamage/2;
// 9..12 ticks, 3/2 from normal tick damage
else if(GetAuraTicks() >= 9)
pdamage += (pdamage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks
// 5..8 ticks have normal tick damage
}
// This method can modify pdamage
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
// send critical in hit info for threat calculation
if (isCrit)
{
cleanDamage.hitOutCome = MELEE_HIT_CRIT;
// Resilience - reduce crit damage
pdamage -= target->GetSpellCritDamageReduction(pdamage);
}
// only from players
// FIXME: need use SpellDamageBonus instead?
if (pCaster->GetTypeId() == TYPEID_PLAYER)
pdamage -= target->GetSpellDamageReduction(pdamage);
target->CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED));
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s attacked %s for %u dmg inflicted by %u abs is %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, GetId(),absorb);
pCaster->DealDamageMods(target, pdamage, &absorb);
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC; // | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
uint32 procEx = isCrit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT;
pdamage = (pdamage <= absorb + resist) ? 0 : (pdamage - absorb - resist);
uint32 overkill = pdamage > target->GetHealth() ? pdamage - target->GetHealth() : 0;
SpellPeriodicAuraLogInfo pInfo(this, pdamage, overkill, absorb, resist, 0.0f, isCrit);
target->SendPeriodicAuraLog(&pInfo);
if (pdamage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, pdamage, BASE_ATTACK, spellProto);
pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, true);
// Drain Soul (chance soul shard)
if (pCaster->GetTypeId() == TYPEID_PLAYER && spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellFamilyFlags & UI64LIT(0x0000000000004000))
{
// Only from non-grey units
if (roll_chance_i(10) && // 1-2 from drain with final and without glyph, 0-1 from damage
((Player*)pCaster)->isHonorOrXPTarget(target) &&
(target->GetTypeId() != TYPEID_UNIT || ((Player*)pCaster)->isAllowedToLoot((Creature*)target)))
{
pCaster->CastSpell(pCaster, 43836, true, NULL, this);
}
}
break;
}
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
{
// don't damage target if not alive, possible death persistent effects
if (!target->isAlive())
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
if(!pCaster->isAlive())
return;
if( spellProto->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA &&
pCaster->SpellHitResult(target, spellProto, false) != SPELL_MISS_NONE)
return;
// Check for immune
if(target->IsImmunedToDamage(GetSpellSchoolMask(spellProto)))
return;
uint32 absorb=0;
uint32 resist=0;
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
//Calculate armor mitigation if it is a physical spell
if (GetSpellSchoolMask(spellProto) & SPELL_SCHOOL_MASK_NORMAL)
{
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(target, pdamage);
cleanDamage.damage += pdamage - pdamageReductedArmor;
pdamage = pdamageReductedArmor;
}
pdamage = target->SpellDamageBonusTaken(pCaster, spellProto, pdamage, DOT, GetStackAmount());
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
// send critical in hit info for threat calculation
if (isCrit)
{
cleanDamage.hitOutCome = MELEE_HIT_CRIT;
// Resilience - reduce crit damage
pdamage -= target->GetSpellCritDamageReduction(pdamage);
}
// only from players
// FIXME: need use SpellDamageBonus instead?
if (GetCasterGuid().IsPlayer())
pdamage -= target->GetSpellDamageReduction(pdamage);
target->CalculateDamageAbsorbAndResist(pCaster, GetSpellSchoolMask(spellProto), DOT, pdamage, &absorb, &resist, !(spellProto->AttributesEx2 & SPELL_ATTR_EX2_CANT_REFLECTED));
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s health leech of %s for %u dmg inflicted by %u abs is %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, GetId(),absorb);
pCaster->DealDamageMods(target, pdamage, &absorb);
pCaster->SendSpellNonMeleeDamageLog(target, GetId(), pdamage, GetSpellSchoolMask(spellProto), absorb, resist, false, 0, isCrit);
float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1;
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC; // | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
uint32 procEx = isCrit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT;
pdamage = (pdamage <= absorb + resist) ? 0 : (pdamage-absorb-resist);
if (pdamage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, pdamage, BASE_ATTACK, spellProto);
int32 new_damage = pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, false);
if (!target->isAlive() && pCaster->IsNonMeleeSpellCasted(false))
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i)
if (Spell* spell = pCaster->GetCurrentSpell(CurrentSpellTypes(i)))
if (spell->m_spellInfo->Id == GetId())
spell->cancel();
if(Player *modOwner = pCaster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier);
int32 heal = pCaster->SpellHealingBonusTaken(pCaster, spellProto, int32(new_damage * multiplier), DOT, GetStackAmount());
uint32 absorbHeal = 0;
pCaster->CalculateHealAbsorb(heal, &absorbHeal);
int32 gain = pCaster->DealHeal(pCaster, heal - absorbHeal, spellProto, false, absorbHeal);
pCaster->getHostileRefManager().threatAssist(pCaster, gain * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
break;
}
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
{
// don't heal target if not alive, mostly death persistent effects from items
if (!target->isAlive())
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
// heal for caster damage (must be alive)
if(target != pCaster && spellProto->SpellVisual[0] == 163 && !pCaster->isAlive())
return;
// ignore non positive values (can be result apply spellmods to aura damage
uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
uint32 pdamage;
if(m_modifier.m_auraname==SPELL_AURA_OBS_MOD_HEALTH)
pdamage = uint32(target->GetMaxHealth() * amount / 100);
else
{
pdamage = amount;
// Wild Growth (1/7 - 6 + 2*ramainTicks) %
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellIconID == 2864)
{
int32 ticks = GetAuraMaxTicks();
int32 remainingTicks = ticks - GetAuraTicks();
int32 addition = int32(amount)*ticks*(-6+2*remainingTicks)/100;
if (GetAuraTicks() != 1)
// Item - Druid T10 Restoration 2P Bonus
if (Aura *aura = pCaster->GetAura(70658, EFFECT_INDEX_0))
addition += abs(int32((addition * aura->GetModifier()->m_amount) / ((ticks-1)* 100)));
pdamage = int32(pdamage) + addition;
}
}
pdamage = target->SpellHealingBonusTaken(pCaster, spellProto, pdamage, DOT, GetStackAmount());
// This method can modify pdamage
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
uint32 absorbHeal = 0;
pCaster->CalculateHealAbsorb(pdamage, &absorbHeal);
pdamage -= absorbHeal;
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s heal of %s for %u health (absorbed %u) inflicted by %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, absorbHeal, GetId());
int32 gain = target->ModifyHealth(pdamage);
SpellPeriodicAuraLogInfo pInfo(this, pdamage, (pdamage - uint32(gain)), absorbHeal, 0, 0.0f, isCrit);
target->SendPeriodicAuraLog(&pInfo);
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;
uint32 procEx = PROC_EX_PERIODIC_POSITIVE | (isCrit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT);
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, gain, BASE_ATTACK, spellProto);
// add HoTs to amount healed in bgs
if( pCaster->GetTypeId() == TYPEID_PLAYER )
if( BattleGround *bg = ((Player*)pCaster)->GetBattleGround() )
bg->UpdatePlayerScore(((Player*)pCaster), SCORE_HEALING_DONE, gain);
target->getHostileRefManager().threatAssist(pCaster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
// heal for caster damage
if(target != pCaster && spellProto->SpellVisual[0] == 163)
{
uint32 dmg = spellProto->manaPerSecond;
if(pCaster->GetHealth() <= dmg && pCaster->GetTypeId()==TYPEID_PLAYER)
{
pCaster->RemoveAurasDueToSpell(GetId());
// finish current generic/channeling spells, don't affect autorepeat
pCaster->FinishSpell(CURRENT_GENERIC_SPELL);
pCaster->FinishSpell(CURRENT_CHANNELED_SPELL);
}
else
{
uint32 damage = gain;
uint32 absorb = 0;
pCaster->DealDamageMods(pCaster, damage, &absorb);
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(spellProto), absorb, 0, false, 0, false);
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
}
}
// uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HEAL;
// uint32 procVictim = 0;//ROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_TAKEN_HEAL;
// ignore item heals
// if(procSpell && !haveCastItem)
// pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
break;
}
case SPELL_AURA_PERIODIC_MANA_LEECH:
{
// don't damage target if not alive, possible death persistent effects
if (!target->isAlive())
return;
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
return;
Powers power = Powers(m_modifier.m_miscvalue);
// power type might have changed between aura applying and tick (druid's shapeshift)
if(target->getPowerType() != power)
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
if(!pCaster->isAlive())
return;
if( GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA &&
pCaster->SpellHitResult(target, spellProto, false) != SPELL_MISS_NONE)
return;
// Check for immune (not use charges)
if(target->IsImmunedToDamage(GetSpellSchoolMask(spellProto)))
return;
// ignore non positive values (can be result apply spellmods to aura damage
uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
// Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana)
// It's mana percent cost spells, m_modifier.m_amount is percent drain from target
if (spellProto->ManaCostPercentage)
{
// max value
uint32 maxmana = pCaster->GetMaxPower(power) * pdamage * 2 / 100;
pdamage = target->GetMaxPower(power) * pdamage / 100;
if(pdamage > maxmana)
pdamage = maxmana;
}
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s power leech of %s for %u dmg inflicted by %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, GetId());
int32 drain_amount = target->GetPower(power) > pdamage ? pdamage : target->GetPower(power);
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
if (power == POWER_MANA)
drain_amount -= target->GetSpellCritDamageReduction(drain_amount);
target->ModifyPower(power, -drain_amount);
float gain_multiplier = 0;
if(pCaster->GetMaxPower(power) > 0)
{
gain_multiplier = spellProto->EffectMultipleValue[GetEffIndex()];
if(Player *modOwner = pCaster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, gain_multiplier);
}
SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier);
target->SendPeriodicAuraLog(&pInfo);
if (int32 gain_amount = int32(drain_amount * gain_multiplier))
{
int32 gain = pCaster->ModifyPower(power, gain_amount);
if (GetId() == 5138) // Drain Mana
if (Aura* petPart = GetHolder()->GetAuraByEffectIndex(EFFECT_INDEX_1))
if (int pet_gain = gain_amount * petPart->GetModifier()->m_amount / 100)
pCaster->CastCustomSpell(pCaster, 32554, &pet_gain, NULL, NULL, true);
target->AddThreat(pCaster, float(gain) * 0.5f, pInfo.critical, GetSpellSchoolMask(spellProto), spellProto);
}
break;
}
case SPELL_AURA_PERIODIC_ENERGIZE:
{
// don't energize target if not alive, possible death persistent effects
if (!target->isAlive())
return;
// ignore non positive values (can be result apply spellmods to aura damage
uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s energize %s for %u dmg inflicted by %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, GetId());
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
break;
Powers power = Powers(m_modifier.m_miscvalue);
if(target->GetMaxPower(power) == 0)
break;
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, 0, 0, 0.0f);
target->SendPeriodicAuraLog(&pInfo);
int32 gain = target->ModifyPower(power,pdamage);
if(Unit* pCaster = GetCaster())
target->getHostileRefManager().threatAssist(pCaster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
break;
}
case SPELL_AURA_OBS_MOD_MANA:
{
// don't energize target if not alive, possible death persistent effects
if (!target->isAlive())
return;
// ignore non positive values (can be result apply spellmods to aura damage
uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
uint32 pdamage = uint32(target->GetMaxPower(POWER_MANA) * amount / 100);
DETAIL_FILTER_LOG(LOG_FILTER_PERIODIC_AFFECTS, "PeriodicTick: %s energize %s for %u mana inflicted by %u",
GetCasterGuid().GetString().c_str(), target->GetGuidStr().c_str(), pdamage, GetId());
if(target->GetMaxPower(POWER_MANA) == 0)
break;
SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, 0, 0, 0.0f);
target->SendPeriodicAuraLog(&pInfo);
int32 gain = target->ModifyPower(POWER_MANA, pdamage);
if(Unit* pCaster = GetCaster())
target->getHostileRefManager().threatAssist(pCaster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
break;
}
case SPELL_AURA_POWER_BURN_MANA:
{
// don't mana burn target if not alive, possible death persistent effects
if (!target->isAlive())
return;
Unit *pCaster = GetCaster();
if(!pCaster)
return;
// Check for immune (not use charges)
if(target->IsImmunedToDamage(GetSpellSchoolMask(spellProto)))
return;
int32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
Powers powerType = Powers(m_modifier.m_miscvalue);
if(!target->isAlive() || target->getPowerType() != powerType)
return;
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
if (powerType == POWER_MANA)
pdamage -= target->GetSpellCritDamageReduction(pdamage);
uint32 gain = uint32(-target->ModifyPower(powerType, -pdamage));
gain = uint32(gain * spellProto->EffectMultipleValue[GetEffIndex()]);
// maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
SpellNonMeleeDamage damageInfo(pCaster, target, spellProto->Id, SpellSchoolMask(spellProto->SchoolMask));
pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
damageInfo.target->CalculateAbsorbResistBlock(pCaster, &damageInfo, spellProto);
pCaster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
// Set trigger flag
uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC; // | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE);
if (damageInfo.damage)
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
pCaster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
pCaster->DealSpellDamage(&damageInfo, true);
break;
}
case SPELL_AURA_MOD_REGEN:
{
// don't heal target if not alive, possible death persistent effects
if (!target->isAlive())
return;
int32 gain = target->ModifyHealth(m_modifier.m_amount);
if (Unit *caster = GetCaster())
target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f * sSpellMgr.GetSpellThreatMultiplier(spellProto), spellProto);
break;
}
case SPELL_AURA_MOD_POWER_REGEN:
{
// don't energize target if not alive, possible death persistent effects
if (!target->isAlive())
return;
Powers pt = target->getPowerType();
if(int32(pt) != m_modifier.m_miscvalue)
return;
if ( spellProto->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED )
{
// eating anim
target->HandleEmoteCommand(EMOTE_ONESHOT_EAT);
}
else if( GetId() == 20577 )
{
// cannibalize anim
target->HandleEmoteCommand(EMOTE_STATE_CANNIBALIZE);
}
// Anger Management
// amount = 1+ 16 = 17 = 3,4*5 = 10,2*5/3
// so 17 is rounded amount for 5 sec tick grow ~ 1 range grow in 3 sec
if(pt == POWER_RAGE)
target->ModifyPower(pt, m_modifier.m_amount * 3 / 5);
break;
}
// Here tick dummy auras
case SPELL_AURA_DUMMY: // some spells have dummy aura
case SPELL_AURA_PERIODIC_DUMMY:
{
PeriodicDummyTick();
break;
}
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
{
TriggerSpell();
break;
}
case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
{
TriggerSpellWithValue();
break;
}
default:
break;
}
}
void Aura::PeriodicDummyTick()
{
SpellEntry const* spell = GetSpellProto();
Unit *target = GetTarget();
switch (spell->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch (spell->Id)
{
// Forsaken Skills
case 7054:
{
// Possibly need cast one of them (but
// 7038 Forsaken Skill: Swords
// 7039 Forsaken Skill: Axes
// 7040 Forsaken Skill: Daggers
// 7041 Forsaken Skill: Maces
// 7042 Forsaken Skill: Staves
// 7043 Forsaken Skill: Bows
// 7044 Forsaken Skill: Guns
// 7045 Forsaken Skill: 2H Axes
// 7046 Forsaken Skill: 2H Maces
// 7047 Forsaken Skill: 2H Swords
// 7048 Forsaken Skill: Defense
// 7049 Forsaken Skill: Fire
// 7050 Forsaken Skill: Frost
// 7051 Forsaken Skill: Holy
// 7053 Forsaken Skill: Shadow
return;
}
case 7057: // Haunting Spirits
if (roll_chance_i(33))
target->CastSpell(target,m_modifier.m_amount,true,NULL,this);
return;
// // Panda
// case 19230: break;
// // Gossip NPC Periodic - Talk
// case 33208: break;
// // Gossip NPC Periodic - Despawn
// case 33209: break;
// // Steal Weapon
// case 36207: break;
// // Simon Game START timer, (DND)
// case 39993: break;
// // Knockdown Fel Cannon: break; The Aggro Burst
// case 40119: break;
// // Old Mount Spell
// case 40154: break;
// // Magnetic Pull
// case 40581: break;
// // Ethereal Ring: break; The Bolt Burst
// case 40801: break;
// // Crystal Prison
// case 40846: break;
// // Copy Weapon
// case 41054: break;
// // Dementia
// case 41404: break;
// // Ethereal Ring Visual, Lightning Aura
// case 41477: break;
// // Ethereal Ring Visual, Lightning Aura (Fork)
// case 41525: break;
// // Ethereal Ring Visual, Lightning Jumper Aura
// case 41567: break;
// // No Man's Land
// case 41955: break;
// // Headless Horseman - Fire
// case 42074: break;
// // Headless Horseman - Visual - Large Fire
// case 42075: break;
// // Headless Horseman - Start Fire, Periodic Aura
// case 42140: break;
// // Ram Speed Boost
// case 42152: break;
// // Headless Horseman - Fires Out Victory Aura
// case 42235: break;
// // Pumpkin Life Cycle
// case 42280: break;
// // Brewfest Request Chick Chuck Mug Aura
// case 42537: break;
// // Squashling
// case 42596: break;
// // Headless Horseman Climax, Head: Periodic
// case 42603: break;
// // Fire Bomb
// case 42621: break;
// // Headless Horseman - Conflagrate, Periodic Aura
// case 42637: break;
// // Headless Horseman - Create Pumpkin Treats Aura
// case 42774: break;
// // Headless Horseman Climax - Summoning Rhyme Aura
// case 42879: break;
// // Tricky Treat
// case 42919: break;
// // Giddyup!
// case 42924: break;
// // Ram - Trot
// case 42992: break;
// // Ram - Canter
// case 42993: break;
// // Ram - Gallop
// case 42994: break;
// // Ram Level - Neutral
// case 43310: break;
// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17
// case 43884: break;
// // Wretched!
// case 43963: break;
// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17
// case 44000: break;
// // Energy Feedback
// case 44328: break;
// // Romantic Picnic
// case 45102: break;
// // Romantic Picnic
// case 45123: break;
// // Looking for Love
// case 45124: break;
// // Kite - Lightning Strike Kite Aura
// case 45197: break;
// // Rocket Chicken
// case 45202: break;
// // Copy Offhand Weapon
// case 45205: break;
// // Upper Deck - Kite - Lightning Periodic Aura
// case 45207: break;
// // Kite -Sky Lightning Strike Kite Aura
// case 45251: break;
// // Ribbon Pole Dancer Check Aura
// case 45390: break;
// // Holiday - Midsummer, Ribbon Pole Periodic Visual
// case 45406: break;
// // Parachute
// case 45472: break;
// // Alliance Flag, Extra Damage Debuff
// case 45898: break;
// // Horde Flag, Extra Damage Debuff
// case 45899: break;
// // Ahune - Summoning Rhyme Aura
// case 45926: break;
// // Ahune - Slippery Floor
// case 45945: break;
// // Ahune's Shield
// case 45954: break;
// // Nether Vapor Lightning
// case 45960: break;
// // Darkness
// case 45996: break;
case 46041: // Summon Blood Elves Periodic
target->CastSpell(target, 46037, true, NULL, this);
target->CastSpell(target, roll_chance_i(50) ? 46038 : 46039, true, NULL, this);
target->CastSpell(target, 46040, true, NULL, this);
return;
// // Transform Visual Missile Periodic
// case 46205: break;
// // Find Opening Beam End
// case 46333: break;
// // Ice Spear Control Aura
// case 46371: break;
// // Hailstone Chill
// case 46458: break;
// // Hailstone Chill, Internal
// case 46465: break;
// // Chill, Internal Shifter
// case 46549: break;
// // Summon Ice Spear Knockback Delayer
// case 46878: break;
// // Burninate Effect
// case 47214: break;
// // Fizzcrank Practice Parachute
// case 47228: break;
// // Send Mug Control Aura
// case 47369: break;
// // Direbrew's Disarm (precast)
// case 47407: break;
// // Mole Machine Port Schedule
// case 47489: break;
// case 47941: break; // Crystal Spike
// case 48200: break; // Healer Aura
case 48630: // Summon Gauntlet Mobs Periodic
case 59275: // Below may need some adjustment, pattern for amount of summon and where is not verified 100% (except for odd/even tick)
{
bool chance = roll_chance_i(50);
target->CastSpell(target, chance ? 48631 : 48632, true, NULL, this);
if (GetAuraTicks() % 2) // which doctor at odd tick
target->CastSpell(target, chance ? 48636 : 48635, true, NULL, this);
else // or harponeer, at even tick
target->CastSpell(target, chance ? 48634 : 48633, true, NULL, this);
return;
}
// case 49313: break; // Proximity Mine Area Aura
// // Mole Machine Portal Schedule
// case 49466: break;
// case 49555: break; // Corpse Explode
// case 49592: break; // Temporal Rift
// case 49957: break; // Cutting Laser
// case 50085: break; // Slow Fall
// // Listening to Music
// case 50493: break;
// // Love Rocket Barrage
// case 50530: break;
case 50789: // Summon iron dwarf (left or right)
case 59860:
target->CastSpell(target, roll_chance_i(50) ? 50790 : 50791, true, NULL, this);
return;
case 50792: // Summon iron trogg (left or right)
case 59859:
target->CastSpell(target, roll_chance_i(50) ? 50793 : 50794, true, NULL, this);
return;
case 50801: // Summon malformed ooze (left or right)
case 59858:
target->CastSpell(target, roll_chance_i(50) ? 50802 : 50803, true, NULL, this);
return;
case 50824: // Summon earthen dwarf
target->CastSpell(target, roll_chance_i(50) ? 50825 : 50826, true, NULL, this);
return;
case 52441: // Cool Down
target->CastSpell(target, 52443, true);
return;
case 53035: // Summon Anub'ar Champion Periodic (Azjol Nerub)
target->CastSpell(target, 53014, true); // Summon Anub'ar Champion
return;
case 53036: // Summon Anub'ar Necromancer Periodic (Azjol Nerub)
target->CastSpell(target, 53015, true); // Summon Anub'ar Necromancer
return;
case 53037: // Summon Anub'ar Crypt Fiend Periodic (Azjol Nerub)
target->CastSpell(target, 53016, true); // Summon Anub'ar Crypt Fiend
return;
case 53520: // Carrion Beetles
target->CastSpell(target, 53521, true, NULL, this);
target->CastSpell(target, 53521, true, NULL, this);
return;
case 55592: // Clean
switch(urand(0,2))
{
case 0: target->CastSpell(target, 55731, true); break;
case 1: target->CastSpell(target, 55738, true); break;
case 2: target->CastSpell(target, 55739, true); break;
}
return;
// Exist more after, need add later
default:
break;
}
// Drink (item drink spells)
if (GetEffIndex() > EFFECT_INDEX_0 && spell->EffectApplyAuraName[GetEffIndex()-1] == SPELL_AURA_MOD_POWER_REGEN)
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
// Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus
if (Aura* aura = GetHolder()->GetAuraByEffectIndex(SpellEffectIndex(GetEffIndex() - 1)))
{
aura->GetModifier()->m_amount = m_modifier.m_amount;
((Player*)target)->UpdateManaRegen();
// Disable continue
m_isPeriodic = false;
return;
}
return;
}
// Prey on the Weak
if (spell->SpellIconID == 2983)
{
Unit *victim = target->getVictim();
if (victim && (target->GetHealth() * 100 / target->GetMaxHealth() > victim->GetHealth() * 100 / victim->GetMaxHealth()))
{
if(!target->HasAura(58670))
{
int32 basepoints = GetBasePoints();
target->CastCustomSpell(target, 58670, &basepoints, 0, 0, true);
}
}
else
target->RemoveAurasDueToSpell(58670);
}
break;
}
case SPELLFAMILY_MAGE:
{
// Mirror Image
// if (spell->Id == 55342)
// return;
break;
}
case SPELLFAMILY_DRUID:
{
switch (spell->Id)
{
// Frenzied Regeneration
case 22842:
{
// Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health.
// Should be manauser
if (target->getPowerType() != POWER_RAGE)
return;
uint32 rage = target->GetPower(POWER_RAGE);
// Nothing todo
if (rage == 0)
return;
int32 mod = (rage < 100) ? rage : 100;
int32 points = target->CalculateSpellDamage(target, spell, EFFECT_INDEX_1);
int32 regen = target->GetMaxHealth() * (mod * points / 10) / 1000;
target->CastCustomSpell(target, 22845, &regen, NULL, NULL, true, NULL, this);
target->SetPower(POWER_RAGE, rage-mod);
return;
}
// Force of Nature
case 33831:
return;
default:
break;
}
break;
}
case SPELLFAMILY_ROGUE:
{
switch (spell->Id)
{
// Killing Spree
case 51690:
{
if (target->hasUnitState(UNIT_STAT_STUNNED) || target->isFeared())
return;
Spell::UnitList targets;
{
// eff_radius ==0
float radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spell->rangeIndex));
MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck u_check(target, target, radius);
MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck> checker(targets, u_check);
Cell::VisitAllObjects(target, checker, radius);
}
if(targets.empty())
return;
Spell::UnitList::const_iterator itr = targets.begin();
std::advance(itr, rand()%targets.size());
Unit* victim = *itr;
target->CastSpell(victim, 57840, true);
target->CastSpell(victim, 57841, true);
return;
}
default:
break;
}
break;
}
case SPELLFAMILY_HUNTER:
{
// Explosive Shot
if (spell->SpellFamilyFlags & UI64LIT(0x8000000000000000))
{
target->CastCustomSpell(target, 53352, &m_modifier.m_amount, 0, 0, true, 0, this, GetCasterGuid());
return;
}
switch (spell->Id)
{
// Harpooner's Mark
// case 40084:
// return;
// Feeding Frenzy Rank 1 & 2
case 53511:
case 53512:
{
Unit* victim = target->getVictim();
if( victim && victim->GetHealth() * 100 < victim->GetMaxHealth() * 35 )
target->CastSpell(target, spell->Id == 53511 ? 60096 : 60097, true, NULL, this);
return;
}
default:
break;
}
break;
}
case SPELLFAMILY_SHAMAN:
{
// Astral Shift
if (spell->Id == 52179)
{
// Periodic need for remove visual on stun/fear/silence lost
if (!target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED))
target->RemoveAurasDueToSpell(52179);
return;
}
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
// Death and Decay
if (spell->SpellFamilyFlags & UI64LIT(0x0000000000000020))
{
if (Unit *caster = GetCaster())
caster->CastCustomSpell(target, 52212, &m_modifier.m_amount, NULL, NULL, true, NULL, this);
return;
}
// Raise Dead
// if (spell->SpellFamilyFlags & UI64LIT(0x0000000000001000))
// return;
// Chains of Ice
if (spell->SpellFamilyFlags & UI64LIT(0x0000400000000000))
{
// Get 0 effect aura
Aura *slow = target->GetAura(GetId(), EFFECT_INDEX_0);
if (slow)
{
slow->ApplyModifier(false, true);
Modifier *mod = slow->GetModifier();
mod->m_amount+= m_modifier.m_amount;
if (mod->m_amount > 0) mod->m_amount = 0;
slow->ApplyModifier(true, true);
}
return;
}
// Summon Gargoyle
// if (spell->SpellFamilyFlags & UI64LIT(0x0000008000000000))
// return;
// Death Rune Mastery
// if (spell->SpellFamilyFlags & UI64LIT(0x0000000000004000))
// return;
// Bladed Armor
if (spell->SpellIconID == 2653)
{
// Increases your attack power by $s1 for every $s2 armor value you have.
// Calculate AP bonus (from 1 efect of this spell)
int32 apBonus = m_modifier.m_amount * target->GetArmor() / target->CalculateSpellDamage(target, spell, EFFECT_INDEX_1);
target->CastCustomSpell(target, 61217, &apBonus, &apBonus, NULL, true, NULL, this);
return;
}
// Reaping
// if (spell->SpellIconID == 22)
// return;
// Blood of the North
// if (spell->SpellIconID == 30412)
// return;
// Hysteria
if (spell->SpellFamilyFlags & UI64LIT(0x0000000020000000))
{
// damage not expected to be show in logs, not any damage spell related to damage apply
uint32 deal = m_modifier.m_amount * target->GetMaxHealth() / 100;
target->DealDamage(target, deal, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
break;
}
default:
break;
}
}
void Aura::HandlePreventFleeing(bool apply, bool Real)
{
if(!Real)
return;
Unit::AuraList const& fearAuras = GetTarget()->GetAurasByType(SPELL_AURA_MOD_FEAR);
if( !fearAuras.empty() )
{
if (apply)
GetTarget()->SetFeared(false, fearAuras.front()->GetCasterGuid());
else
GetTarget()->SetFeared(true);
}
}
void Aura::HandleManaShield(bool apply, bool Real)
{
if(!Real)
return;
// prevent double apply bonuses
if(apply && (GetTarget()->GetTypeId()!=TYPEID_PLAYER || !((Player*)GetTarget())->GetSession()->PlayerLoading()))
{
if(Unit* caster = GetCaster())
{
float DoneActualBenefit = 0.0f;
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
if(GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000008000))
{
// Mana Shield
// +50% from +spd bonus
DoneActualBenefit = caster->SpellBaseDamageBonusDone(GetSpellSchoolMask(GetSpellProto())) * 0.5f;
break;
}
break;
default:
break;
}
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit;
}
}
}
void Aura::HandleArenaPreparation(bool apply, bool Real)
{
if(!Real)
return;
if(apply)
GetTarget()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
else
GetTarget()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
}
/**
* Such auras are applied from a caster(=player) to a vehicle.
* This has been verified using spell #49256
*/
void Aura::HandleAuraControlVehicle(bool apply, bool Real)
{
if(!Real)
return;
Unit* target = GetTarget();
if (!target->IsVehicle())
return;
// TODO: Check for free seat
Unit *caster = GetCaster();
if (!caster)
return;
if (apply)
{
if (caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->RemovePet(PET_SAVE_AS_CURRENT);
//caster->EnterVehicle(target);
}
else
{
// some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them
caster->RemoveAurasDueToSpell(GetId());
//caster->ExitVehicle();
if (caster->GetTypeId() == TYPEID_PLAYER)
((Player*)caster)->ResummonPetTemporaryUnSummonedIfAny();
}
}
void Aura::HandleAuraAddMechanicAbilities(bool apply, bool Real)
{
if (!Real)
return;
Unit* target = GetTarget();
if (!target || target->GetTypeId() != TYPEID_PLAYER) // only players should be affected by this aura
return;
uint16 i_OverrideSetId = GetMiscValue();
const OverrideSpellDataEntry *spellSet = sOverrideSpellDataStore.LookupEntry(i_OverrideSetId);
if (!spellSet)
return;
if (apply)
{
// spell give the player a new castbar with some spells.. this is a clientside process..
// serverside just needs to register the new spells so that player isn't kicked as cheater
for (int i = 0; i < MAX_OVERRIDE_SPELLS; i++)
if (uint32 spellId = spellSet->Spells[i])
static_cast<Player*>(target)->addSpell(spellId, true, false, false, false);
target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, i_OverrideSetId);
}
else
{
target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, 0);
for (int i = 0; i < MAX_OVERRIDE_SPELLS; i++)
if (uint32 spellId = spellSet->Spells[i])
static_cast<Player*>(target)->removeSpell(spellId, false , false, false);
}
}
void Aura::HandleAuraOpenStable(bool apply, bool Real)
{
if(!Real || GetTarget()->GetTypeId() != TYPEID_PLAYER || !GetTarget()->IsInWorld())
return;
Player* player = (Player*)GetTarget();
if (apply)
player->GetSession()->SendStablePet(player->GetObjectGuid());
// client auto close stable dialog at !apply aura
}
void Aura::HandleAuraMirrorImage(bool apply, bool Real)
{
if (!Real)
return;
// Target of aura should always be creature (ref Spell::CheckCast)
Creature* pCreature = (Creature*)GetTarget();
if (apply)
{
// Caster can be player or creature, the unit who pCreature will become an clone of.
Unit* caster = GetCaster();
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, caster->getRace());
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, caster->getClass());
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, caster->getGender());
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, caster->getPowerType());
pCreature->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CLONED);
pCreature->SetDisplayId(caster->GetNativeDisplayId());
}
else
{
const CreatureInfo* cinfo = pCreature->GetCreatureInfo();
const CreatureModelInfo* minfo = sObjectMgr.GetCreatureModelInfo(pCreature->GetNativeDisplayId());
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 0, 0);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 1, cinfo->unit_class);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
pCreature->SetByteValue(UNIT_FIELD_BYTES_0, 3, 0);
pCreature->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CLONED);
pCreature->SetDisplayId(pCreature->GetNativeDisplayId());
}
}
void Aura::HandleAuraConvertRune(bool apply, bool Real)
{
if(!Real)
return;
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
Player *plr = (Player*)GetTarget();
if(plr->getClass() != CLASS_DEATH_KNIGHT)
return;
RuneType runeFrom = RuneType(GetSpellProto()->EffectMiscValue[m_effIndex]);
RuneType runeTo = RuneType(GetSpellProto()->EffectMiscValueB[m_effIndex]);
if (apply)
{
for(uint32 i = 0; i < MAX_RUNES; ++i)
{
if (plr->GetCurrentRune(i) == runeFrom && !plr->GetRuneCooldown(i))
{
plr->ConvertRune(i, runeTo);
break;
}
}
}
else
{
for(uint32 i = 0; i < MAX_RUNES; ++i)
{
if(plr->GetCurrentRune(i) == runeTo && plr->GetBaseRune(i) == runeFrom)
{
plr->ConvertRune(i, runeFrom);
break;
}
}
}
}
void Aura::HandlePhase(bool apply, bool Real)
{
if(!Real)
return;
Unit *target = GetTarget();
// always non stackable
if(apply)
{
Unit::AuraList const& phases = target->GetAurasByType(SPELL_AURA_PHASE);
if(!phases.empty())
target->RemoveAurasDueToSpell(phases.front()->GetId(), GetHolder());
}
target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL, true);
// no-phase is also phase state so same code for apply and remove
if (GetEffIndex() == EFFECT_INDEX_0 && target->GetTypeId() == TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = sSpellMgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone, area;
target->GetZoneAndAreaId(zone, area);
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
// some auras remove at aura remove
if(!itr->second->IsFitToRequirements((Player*)target, zone, area))
target->RemoveAurasDueToSpell(itr->second->spellId);
// some auras applied at aura apply
else if(itr->second->autocast)
{
if (!target->HasAura(itr->second->spellId, EFFECT_INDEX_0))
target->CastSpell(target, itr->second->spellId, true);
}
}
}
}
}
void Aura::HandleAuraSafeFall( bool Apply, bool Real )
{
// implemented in WorldSession::HandleMovementOpcodes
// only special case
if(Apply && Real && GetId() == 32474 && GetTarget()->GetTypeId() == TYPEID_PLAYER)
((Player*)GetTarget())->ActivateTaxiPathTo(506, GetId());
}
bool Aura::IsCritFromAbilityAura(Unit* caster, uint32& damage)
{
Unit::AuraList const& auras = caster->GetAurasByType(SPELL_AURA_ABILITY_PERIODIC_CRIT);
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
{
if (!(*itr)->isAffectedOnSpell(GetSpellProto()))
continue;
if (!caster->IsSpellCrit(GetTarget(), GetSpellProto(), GetSpellSchoolMask(GetSpellProto())))
break;
damage = caster->SpellCriticalDamageBonus(GetSpellProto(), damage, GetTarget());
return true;
}
return false;
}
void Aura::HandleModTargetArmorPct(bool /*apply*/, bool /*Real*/)
{
if(GetTarget()->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)GetTarget())->UpdateArmorPenetration();
}
void Aura::HandleAuraModAllCritChance(bool apply, bool Real)
{
// spells required only Real aura add/remove
if(!Real)
return;
Unit *target = GetTarget();
if(target->GetTypeId() != TYPEID_PLAYER)
return;
((Player*)target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
((Player*)target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
((Player*)target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
// included in Player::UpdateSpellCritChance calculation
((Player*)target)->UpdateAllSpellCritChances();
}
void Aura::HandleAuraStopNaturalManaRegen(bool apply, bool real)
{
if (!real)
return;
GetTarget()->ApplyModFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER, !apply && !GetTarget()->IsUnderLastManaUseEffect());
}
bool Aura::IsLastAuraOnHolder()
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (i != GetEffIndex() && GetHolder()->m_auras[i])
return false;
return true;
}
bool Aura::HasMechanic(uint32 mechanic) const
{
return GetSpellProto()->Mechanic == mechanic ||
GetSpellProto()->EffectMechanic[m_effIndex] == mechanic;
}
SpellAuraHolder::SpellAuraHolder(SpellEntry const* spellproto, Unit *target, WorldObject *caster, Item *castItem) :
m_spellProto(spellproto), m_target(target), m_castItemGuid(castItem ? castItem->GetObjectGuid() : ObjectGuid()),
m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1), m_procCharges(0),
m_stackAmount(1), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE), m_timeCla(1000),
m_permanent(false), m_isRemovedOnShapeLost(true), m_deleted(false), m_in_use(0)
{
MANGOS_ASSERT(target);
MANGOS_ASSERT(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
if(!caster)
m_casterGuid = target->GetObjectGuid();
else
{
// remove this assert when not unit casters will be supported
MANGOS_ASSERT(caster->isType(TYPEMASK_UNIT))
m_casterGuid = caster->GetObjectGuid();
}
m_applyTime = time(NULL);
m_isPassive = IsPassiveSpell(spellproto);
m_isDeathPersist = IsDeathPersistentSpell(spellproto);
m_isSingleTarget = IsSingleTargetSpell(spellproto);
m_procCharges = spellproto->procCharges;
m_isRemovedOnShapeLost = (GetCasterGuid() == m_target->GetObjectGuid() &&
m_spellProto->Stances &&
!(m_spellProto->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) &&
!(m_spellProto->Attributes & SPELL_ATTR_NOT_SHAPESHIFT));
Unit* unitCaster = caster && caster->isType(TYPEMASK_UNIT) ? (Unit*)caster : NULL;
m_duration = m_maxDuration = CalculateSpellDuration(spellproto, unitCaster);
if (m_maxDuration == -1 || (m_isPassive && spellproto->DurationIndex == 0))
m_permanent = true;
if (unitCaster)
{
if (Player* modOwner = unitCaster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
}
// some custom stack values at aura holder create
switch (m_spellProto->Id)
{
// some auras applied with max stack
case 24575: // Brittle Armor
case 24659: // Unstable Power
case 24662: // Restless Strength
case 26464: // Mercurial Shield
case 34027: // Kill Command
case 55166: // Tidal Force
case 58914: // Kill Command (pet part)
case 64455: // Feral Essence
case 71564: // Deadly Precision
case 74396: // Fingers of Frost
m_stackAmount = m_spellProto->StackAmount;
break;
}
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
m_auras[i] = NULL;
}
void SpellAuraHolder::AddAura(Aura *aura, SpellEffectIndex index)
{
m_auras[index] = aura;
m_auraFlags |= (1 << index);
}
void SpellAuraHolder::RemoveAura(SpellEffectIndex index)
{
m_auras[index] = NULL;
m_auraFlags &= ~(1 << index);
}
void SpellAuraHolder::ApplyAuraModifiers(bool apply, bool real)
{
for (int32 i = 0; i < MAX_EFFECT_INDEX && !IsDeleted(); ++i)
if (Aura *aur = GetAuraByEffectIndex(SpellEffectIndex(i)))
aur->ApplyModifier(apply, real);
}
void SpellAuraHolder::_AddSpellAuraHolder()
{
if (!GetId())
return;
if(!m_target)
return;
// Try find slot for aura
uint8 slot = NULL_AURA_SLOT;
// Lookup free slot
if (m_target->GetVisibleAurasCount() < MAX_AURAS)
{
Unit::VisibleAuraMap const& visibleAuras = m_target->GetVisibleAuras();
for(uint8 i = 0; i < MAX_AURAS; ++i)
{
Unit::VisibleAuraMap::const_iterator itr = visibleAuras.find(i);
if (itr == visibleAuras.end())
{
slot = i;
// update for out of range group members (on 1 slot use)
m_target->UpdateAuraForGroup(slot);
break;
}
}
}
Unit* caster = GetCaster();
// set infinity cooldown state for spells
if(caster && caster->GetTypeId() == TYPEID_PLAYER)
{
if (m_spellProto->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
{
Item* castItem = m_castItemGuid ? ((Player*)caster)->GetItemByGuid(m_castItemGuid) : NULL;
((Player*)caster)->AddSpellAndCategoryCooldowns(m_spellProto,castItem ? castItem->GetEntry() : 0, NULL,true);
}
}
uint8 flags = 0;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (m_auras[i])
flags |= (1 << i);
}
flags |= ((GetCasterGuid() == GetTarget()->GetObjectGuid()) ? AFLAG_NOT_CASTER : AFLAG_NONE) | ((GetSpellMaxDuration(m_spellProto) > 0) ? AFLAG_DURATION : AFLAG_NONE) | (IsPositive() ? AFLAG_POSITIVE : AFLAG_NEGATIVE);
SetAuraFlags(flags);
SetAuraLevel(caster ? caster->getLevel() : sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
if (IsNeedVisibleSlot(caster))
{
SetAuraSlot( slot );
if(slot < MAX_AURAS) // slot found send data to client
{
SetVisibleAura(false);
SendAuraUpdate(false);
}
//*****************************************************
// Update target aura state flag on holder apply
// TODO: Make it easer
//*****************************************************
// Sitdown on apply aura req seated
if (m_spellProto->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !m_target->IsSitState())
m_target->SetStandState(UNIT_STAND_STATE_SIT);
// register aura diminishing on apply
if (getDiminishGroup() != DIMINISHING_NONE )
m_target->ApplyDiminishingAura(getDiminishGroup(), true);
// Update Seals information
if (IsSealSpell(m_spellProto))
m_target->ModifyAuraState(AURA_STATE_JUDGEMENT, true);
// Conflagrate aura state on Immolate and Shadowflame
if (m_spellProto->IsFitToFamily(SPELLFAMILY_WARLOCK, UI64LIT(0x0000000000000004), 0x00000002))
m_target->ModifyAuraState(AURA_STATE_CONFLAGRATE, true);
// Faerie Fire (druid versions)
if (m_spellProto->IsFitToFamily(SPELLFAMILY_DRUID, UI64LIT(0x0000000000000400)))
m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE, true);
// Victorious
if (m_spellProto->IsFitToFamily(SPELLFAMILY_WARRIOR, UI64LIT(0x0004000000000000)))
m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, true);
// Swiftmend state on Regrowth & Rejuvenation
if (m_spellProto->IsFitToFamily(SPELLFAMILY_DRUID, UI64LIT(0x0000000000000050)))
m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
// Deadly poison aura state
if (m_spellProto->IsFitToFamily(SPELLFAMILY_ROGUE, UI64LIT(0x0000000000010000)))
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON, true);
// Enrage aura state
if (m_spellProto->Dispel == DISPEL_ENRAGE)
m_target->ModifyAuraState(AURA_STATE_ENRAGE, true);
// Bleeding aura state
if (GetAllSpellMechanicMask(m_spellProto) & (1 << (MECHANIC_BLEED-1)))
m_target->ModifyAuraState(AURA_STATE_BLEEDING, true);
}
}
void SpellAuraHolder::_RemoveSpellAuraHolder()
{
// Remove all triggered by aura spells vs unlimited duration
// except same aura replace case
if(m_removeMode!=AURA_REMOVE_BY_STACK)
CleanupTriggeredSpells();
Unit* caster = GetCaster();
if(caster && IsPersistent())
{
DynamicObject *dynObj = caster->GetDynObject(GetId());
if (dynObj)
dynObj->RemoveAffected(m_target);
}
//passive auras do not get put in slots - said who? ;)
// Note: but totem can be not accessible for aura target in time remove (to far for find in grid)
//if(m_isPassive && !(caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->IsTotem()))
// return;
uint8 slot = GetAuraSlot();
if(slot >= MAX_AURAS) // slot not set
return;
if(m_target->GetVisibleAura(slot) == 0)
return;
// unregister aura diminishing (and store last time)
if (getDiminishGroup() != DIMINISHING_NONE )
m_target->ApplyDiminishingAura(getDiminishGroup(), false);
SetAuraFlags(AFLAG_NONE);
SetAuraLevel(0);
SetVisibleAura(true);
if (m_removeMode != AURA_REMOVE_BY_DELETE)
{
SendAuraUpdate(true);
// update for out of range group members
m_target->UpdateAuraForGroup(slot);
//*****************************************************
// Update target aura state flag (at last aura remove)
//*****************************************************
// Enrage aura state
if(m_spellProto->Dispel == DISPEL_ENRAGE)
m_target->ModifyAuraState(AURA_STATE_ENRAGE, false);
// Bleeding aura state
if (GetAllSpellMechanicMask(m_spellProto) & (1 << (MECHANIC_BLEED-1)))
{
bool found = false;
Unit::SpellAuraHolderMap const& holders = m_target->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator itr = holders.begin(); itr != holders.end(); ++itr)
{
if (GetAllSpellMechanicMask(itr->second->GetSpellProto()) & (1 << (MECHANIC_BLEED-1)))
{
found = true;
break;
}
}
if (!found)
m_target->ModifyAuraState(AURA_STATE_BLEEDING, false);
}
uint32 removeState = 0;
ClassFamilyMask removeFamilyFlag = m_spellProto->SpellFamilyFlags;
switch(m_spellProto->SpellFamilyName)
{
case SPELLFAMILY_PALADIN:
if (IsSealSpell(m_spellProto))
removeState = AURA_STATE_JUDGEMENT; // Update Seals information
break;
case SPELLFAMILY_WARLOCK:
// Conflagrate aura state on Immolate and Shadowflame,
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000004), 0x00000002))
{
removeFamilyFlag = ClassFamilyMask(UI64LIT(0x0000000000000004), 0x00000002);
removeState = AURA_STATE_CONFLAGRATE;
}
break;
case SPELLFAMILY_DRUID:
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000400)))
removeState = AURA_STATE_FAERIE_FIRE; // Faerie Fire (druid versions)
else if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000050)))
{
removeFamilyFlag = ClassFamilyMask(UI64LIT(0x00000000000050));
removeState = AURA_STATE_SWIFTMEND; // Swiftmend aura state
}
break;
case SPELLFAMILY_WARRIOR:
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0004000000000000)))
removeState = AURA_STATE_WARRIOR_VICTORY_RUSH; // Victorious
break;
case SPELLFAMILY_ROGUE:
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000010000)))
removeState = AURA_STATE_DEADLY_POISON; // Deadly poison aura state
break;
case SPELLFAMILY_HUNTER:
if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x1000000000000000)))
removeState = AURA_STATE_FAERIE_FIRE; // Sting (hunter versions)
}
// Remove state (but need check other auras for it)
if (removeState)
{
bool found = false;
Unit::SpellAuraHolderMap const& holders = m_target->GetSpellAuraHolderMap();
for (Unit::SpellAuraHolderMap::const_iterator i = holders.begin(); i != holders.end(); ++i)
{
SpellEntry const *auraSpellInfo = (*i).second->GetSpellProto();
if (auraSpellInfo->IsFitToFamily(SpellFamily(m_spellProto->SpellFamilyName), removeFamilyFlag))
{
found = true;
break;
}
}
// this was last holder
if(!found)
m_target->ModifyAuraState(AuraState(removeState), false);
}
// reset cooldown state for spells
if(caster && caster->GetTypeId() == TYPEID_PLAYER)
{
if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
// note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
((Player*)caster)->SendCooldownEvent(GetSpellProto());
}
}
}
void SpellAuraHolder::CleanupTriggeredSpells()
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (!m_spellProto->EffectApplyAuraName[i])
continue;
uint32 tSpellId = m_spellProto->EffectTriggerSpell[i];
if(!tSpellId)
continue;
SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId);
if(!tProto)
continue;
if(GetSpellDuration(tProto) != -1)
continue;
// needed for spell 43680, maybe others
// TODO: is there a spell flag, which can solve this in a more sophisticated way?
if (m_spellProto->EffectApplyAuraName[i] == SPELL_AURA_PERIODIC_TRIGGER_SPELL &&
GetSpellDuration(m_spellProto) == int32(m_spellProto->EffectAmplitude[i]))
continue;
m_target->RemoveAurasDueToSpell(tSpellId);
}
}
bool SpellAuraHolder::ModStackAmount(int32 num)
{
uint32 protoStackAmount = m_spellProto->StackAmount;
// Can`t mod
if (!protoStackAmount)
return true;
// Modify stack but limit it
int32 stackAmount = m_stackAmount + num;
if (stackAmount > (int32)protoStackAmount)
stackAmount = protoStackAmount;
else if (stackAmount <=0) // Last aura from stack removed
{
m_stackAmount = 0;
return true; // need remove aura
}
// Update stack amount
SetStackAmount(stackAmount);
return false;
}
void SpellAuraHolder::SetStackAmount(uint32 stackAmount)
{
Unit *target = GetTarget();
Unit *caster = GetCaster();
if (!target || !caster)
return;
bool refresh = stackAmount >= m_stackAmount;
if (stackAmount != m_stackAmount)
{
m_stackAmount = stackAmount;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
if (Aura *aur = m_auras[i])
{
int32 bp = aur->GetBasePoints();
int32 amount = m_stackAmount * caster->CalculateSpellDamage(target, m_spellProto, SpellEffectIndex(i), &bp);
// Reapply if amount change
if (amount != aur->GetModifier()->m_amount)
{
aur->ApplyModifier(false, true);
aur->GetModifier()->m_amount = amount;
aur->ApplyModifier(true, true);
}
}
}
}
if (refresh)
// Stack increased refresh duration
RefreshHolder();
else
// Stack decreased only send update
SendAuraUpdate(false);
}
Unit* SpellAuraHolder::GetCaster() const
{
if(GetCasterGuid() == m_target->GetObjectGuid())
return m_target;
return ObjectAccessor::GetUnit(*m_target, m_casterGuid);// player will search at any maps
}
bool SpellAuraHolder::IsWeaponBuffCoexistableWith(SpellAuraHolder const* ref) const
{
// only item casted spells
if (!GetCastItemGuid())
return false;
// Exclude Debuffs
if (!IsPositive())
return false;
// Exclude Non-generic Buffs [ie: Runeforging] and Executioner-Enchant
if (GetSpellProto()->SpellFamilyName != SPELLFAMILY_GENERIC || GetId() == 42976)
return false;
// Exclude Stackable Buffs [ie: Blood Reserve]
if (GetSpellProto()->StackAmount)
return false;
// only self applied player buffs
if (m_target->GetTypeId() != TYPEID_PLAYER || m_target->GetObjectGuid() != GetCasterGuid())
return false;
Item* castItem = ((Player*)m_target)->GetItemByGuid(GetCastItemGuid());
if (!castItem)
return false;
// Limit to Weapon-Slots
if (!castItem->IsEquipped() ||
(castItem->GetSlot() != EQUIPMENT_SLOT_MAINHAND && castItem->GetSlot() != EQUIPMENT_SLOT_OFFHAND))
return false;
// form different weapons
return ref->GetCastItemGuid() && ref->GetCastItemGuid() != GetCastItemGuid();
}
bool SpellAuraHolder::IsNeedVisibleSlot(Unit const* caster) const
{
bool totemAura = caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->IsTotem();
if (m_spellProto->procFlags)
return true;
else if (HasAuraWithTriggerEffect(m_spellProto))
return true;
else if (IsSpellHaveAura(m_spellProto, SPELL_AURA_MOD_IGNORE_SHAPESHIFT))
return true;
else if (IsSpellHaveAura(m_spellProto, SPELL_AURA_IGNORE_UNIT_STATE))
return true;
// passive auras (except totem auras) do not get placed in the slots
return !m_isPassive || totemAura || HasAreaAuraEffect(m_spellProto);
}
void SpellAuraHolder::BuildUpdatePacket(WorldPacket& data) const
{
data << uint8(GetAuraSlot());
data << uint32(GetId());
uint8 auraFlags = GetAuraFlags();
data << uint8(auraFlags);
data << uint8(GetAuraLevel());
uint32 stackCount = m_procCharges ? m_procCharges*m_stackAmount : m_stackAmount;
data << uint8(stackCount <= 255 ? stackCount : 255);
if(!(auraFlags & AFLAG_NOT_CASTER))
{
data << GetCasterGuid().WriteAsPacked();
}
if(auraFlags & AFLAG_DURATION)
{
data << uint32(GetAuraMaxDuration());
data << uint32(GetAuraDuration());
}
}
void SpellAuraHolder::SendAuraUpdate(bool remove) const
{
WorldPacket data(SMSG_AURA_UPDATE);
data << m_target->GetPackGUID();
if(remove)
{
data << uint8(GetAuraSlot());
data << uint32(0);
}
else
BuildUpdatePacket(data);
m_target->SendMessageToSet(&data, true);
}
void SpellAuraHolder::HandleSpellSpecificBoosts(bool apply)
{
bool cast_at_remove = false; // if spell must be casted at last aura from stack remove
uint32 spellId1 = 0;
uint32 spellId2 = 0;
uint32 spellId3 = 0;
uint32 spellId4 = 0;
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
switch(GetId())
{
case 50720: // Vigilance (warrior spell but not have warrior family)
{
spellId1 = 68066; // Damage Reduction
break;
}
case 57350: // Illusionary Barrier
{
if (!apply && m_target->getPowerType() == POWER_MANA)
{
cast_at_remove = true;
spellId1 = 60242; // Darkmoon Card: Illusion
}
else
return;
break;
}
case 58914: // Kill Command, pet aura
{
// Removal is needed here because the dummy aura handler is applied / removed at stacks change
if (!apply)
if(Unit* caster = GetCaster())
caster->RemoveAurasDueToSpell(34027);
return;
}
case 62692: // Aura of Despair
{
spellId1 = 64848;
break;
}
case 71905: // Soul Fragment
{
if (!apply)
{
spellId1 = 72521; // Shadowmourne Visual Low
spellId2 = 72523; // Shadowmourne Visual High
}
else
return;
break;
}
default:
return;
}
break;
}
case SPELLFAMILY_MAGE:
{
// Ice Barrier (non stacking from one caster)
if (m_spellProto->SpellIconID == 32)
{
if ((!apply && m_removeMode == AURA_REMOVE_BY_DISPEL) || m_removeMode == AURA_REMOVE_BY_SHIELD_BREAK)
{
Unit::AuraList const& dummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
// Shattered Barrier
if ((*itr)->GetSpellProto()->SpellIconID == 2945)
{
cast_at_remove = true;
// first rank have 50% chance
if ((*itr)->GetId() != 44745 || roll_chance_i(50))
spellId1 = 55080;
break;
}
}
}
else
return;
break;
}
switch(GetId())
{
case 11129: // Combustion (remove triggered aura stack)
{
if(!apply)
spellId1 = 28682;
else
return;
break;
}
case 28682: // Combustion (remove main aura)
{
if(!apply)
spellId1 = 11129;
else
return;
break;
}
case 44401: // Missile Barrage (triggered)
case 48108: // Hot Streak (triggered)
case 57761: // Fireball! (Brain Freeze triggered)
{
// consumed aura
if (!apply && m_removeMode != AURA_REMOVE_BY_EXPIRE)
{
Unit* caster = GetCaster();
// Item - Mage T10 2P Bonus
if (!caster || !caster->HasAura(70752))
return;
cast_at_remove = true;
spellId1 = 70753; // Pushing the Limit
}
else
return;
break;
}
case 74396: // Fingers of Frost (remove main aura)
{
if (!apply)
spellId1 = 44544;
else
return;
break;
}
default:
return;
}
break;
}
case SPELLFAMILY_WARRIOR:
{
if(!apply)
{
// Remove Blood Frenzy only if target no longer has any Deep Wound or Rend (applying is handled by procs)
if (GetSpellProto()->Mechanic != MECHANIC_BLEED)
return;
// If target still has one of Warrior's bleeds, do nothing
Unit::AuraList const& PeriodicDamage = m_target->GetAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
for(Unit::AuraList::const_iterator i = PeriodicDamage.begin(); i != PeriodicDamage.end(); ++i)
if( (*i)->GetCasterGuid() == GetCasterGuid() &&
(*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARRIOR &&
(*i)->GetSpellProto()->Mechanic == MECHANIC_BLEED)
return;
spellId1 = 30069; // Blood Frenzy (Rank 1)
spellId2 = 30070; // Blood Frenzy (Rank 2)
}
break;
}
case SPELLFAMILY_WARLOCK:
{
// Fear (non stacking)
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000040000000000))
{
if(!apply)
{
Unit* caster = GetCaster();
if(!caster)
return;
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
SpellEntry const* dummyEntry = (*itr)->GetSpellProto();
// Improved Fear
if (dummyEntry->SpellFamilyName == SPELLFAMILY_WARLOCK && dummyEntry->SpellIconID == 98)
{
cast_at_remove = true;
switch((*itr)->GetModifier()->m_amount)
{
// Rank 1
case 0: spellId1 = 60946; break;
// Rank 1
case 1: spellId1 = 60947; break;
}
break;
}
}
}
else
return;
}
// Shadowflame (DoT)
else if (m_spellProto->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00000002))
{
// Glyph of Shadowflame
Unit* caster;
if(!apply)
spellId1 = 63311;
else if(((caster = GetCaster())) && caster->HasAura(63310))
spellId1 = 63311;
else
return;
}
else
return;
break;
}
case SPELLFAMILY_PRIEST:
{
// Shadow Word: Pain (need visual check fro skip improvement talent) or Vampiric Touch
if ((m_spellProto->SpellIconID == 234 && m_spellProto->SpellVisual[0]) || m_spellProto->SpellIconID == 2213)
{
if (!apply && m_removeMode == AURA_REMOVE_BY_DISPEL)
{
Unit* caster = GetCaster();
if(!caster)
return;
Unit::AuraList const& dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
// Shadow Affinity
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST
&& (*itr)->GetSpellProto()->SpellIconID == 178)
{
// custom cast code
int32 basepoints0 = (*itr)->GetModifier()->m_amount * caster->GetCreateMana() / 100;
caster->CastCustomSpell(caster, 64103, &basepoints0, NULL, NULL, true, NULL);
return;
}
}
}
else
return;
}
// Power Word: Shield
else if (apply && m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001) && m_spellProto->Mechanic == MECHANIC_SHIELD)
{
Unit* caster = GetCaster();
if(!caster)
return;
// Glyph of Power Word: Shield
if (Aura* glyph = caster->GetAura(55672, EFFECT_INDEX_0))
{
Aura *shield = GetAuraByEffectIndex(EFFECT_INDEX_0);
int32 heal = (glyph->GetModifier()->m_amount * shield->GetModifier()->m_amount)/100;
caster->CastCustomSpell(m_target, 56160, &heal, NULL, NULL, true, 0, shield);
}
return;
}
switch(GetId())
{
// Abolish Disease (remove 1 more poison effect with Body and Soul)
case 552:
{
if(apply)
{
int chance =0;
Unit::AuraList const& dummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
SpellEntry const* dummyEntry = (*itr)->GetSpellProto();
// Body and Soul (talent ranks)
if (dummyEntry->SpellFamilyName == SPELLFAMILY_PRIEST && dummyEntry->SpellIconID == 2218 &&
dummyEntry->SpellVisual[0]==0)
{
chance = (*itr)->GetSpellProto()->CalculateSimpleValue(EFFECT_INDEX_1);
break;
}
}
if(roll_chance_i(chance))
spellId1 = 64134; // Body and Soul (periodic dispel effect)
}
else
spellId1 = 64134; // Body and Soul (periodic dispel effect)
break;
}
// Dispersion mana reg and immunity
case 47585:
spellId1 = 60069; // Dispersion
spellId2 = 63230; // Dispersion
break;
default:
return;
}
break;
}
case SPELLFAMILY_DRUID:
{
// Barkskin
if (GetId()==22812 && m_target->HasAura(63057)) // Glyph of Barkskin
spellId1 = 63058; // Glyph - Barkskin 01
else if (!apply && GetId() == 5229) // Enrage (Druid Bear)
spellId1 = 51185; // King of the Jungle (Enrage damage aura)
else
return;
break;
}
case SPELLFAMILY_ROGUE:
// Sprint (skip non player casted spells by category)
if (GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000040) && GetSpellProto()->Category == 44)
{
if(!apply || m_target->HasAura(58039)) // Glyph of Blurred Speed
spellId1 = 61922; // Sprint (waterwalk)
else
return;
}
else
return;
break;
case SPELLFAMILY_HUNTER:
{
switch (GetId())
{
case 19574: // Bestial Wrath - immunity
case 34471: // The Beast Within - immunity
{
spellId1 = 24395;
spellId2 = 24396;
spellId3 = 24397;
spellId4 = 26592;
break;
}
case 34027: // Kill Command, owner aura (spellmods)
{
if (apply)
{
if (m_target->HasAura(35029)) // Focused Fire, rank 1
spellId1 = 60110; // Kill Command, Focused Fire rank 1 bonus
else if (m_target->HasAura(35030)) // Focused Fire, rank 2
spellId1 = 60113; // Kill Command, Focused Fire rank 2 bonus
else
return;
}
else
{
spellId1 = 34026; // Kill Command, owner casting aura
spellId2 = 60110; // Kill Command, Focused Fire rank 1 bonus
spellId3 = 60113; // Kill Command, Focused Fire rank 2 bonus
if (Unit* pet = m_target->GetPet())
pet->RemoveAurasDueToSpell(58914); // Kill Command, pet aura
}
break;
}
case 35029: // Focused Fire, rank 1
{
if (apply && !m_target->HasAura(34027)) // Kill Command, owner casting aura
return;
spellId1 = 60110; // Kill Command, Focused Fire rank 1 bonus
break;
}
case 35030: // Focused Fire, rank 2
{
if (apply && !m_target->HasAura(34027)) // Kill Command, owner casting aura
return;
spellId1 = 60113; // Kill Command, Focused Fire rank 2 bonus
break;
}
default:
// Freezing Trap Effect
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000008))
{
if(!apply)
{
Unit *caster = GetCaster();
// Glyph of Freezing Trap
if (caster && caster->HasAura(56845))
{
cast_at_remove = true;
spellId1 = 61394;
}
else
return;
}
else
return;
}
// Aspect of the Dragonhawk dodge
else if (GetSpellProto()->IsFitToFamilyMask(UI64LIT(0x0000000000000000), 0x00001000))
{
spellId1 = 61848;
// triggered spell have same category as main spell and cooldown
if (apply && m_target->GetTypeId()==TYPEID_PLAYER)
((Player*)m_target)->RemoveSpellCooldown(61848);
}
else
return;
break;
}
break;
}
case SPELLFAMILY_PALADIN:
{
if (m_spellProto->Id == 31884) // Avenging Wrath
{
if(!apply)
spellId1 = 57318; // Sanctified Wrath (triggered)
else
{
int32 percent = 0;
Unit::AuraList const& dummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
if ((*itr)->GetSpellProto()->SpellIconID == 3029)
{
percent = (*itr)->GetModifier()->m_amount;
break;
}
}
// apply in special way
if(percent)
{
spellId1 = 57318; // Sanctified Wrath (triggered)
// prevent aura deletion, specially in multi-boost case
SetInUse(true);
m_target->CastCustomSpell(m_target, spellId1, &percent, &percent, NULL, true, NULL);
SetInUse(false);
}
return;
}
break;
}
// Only process on player casting paladin aura
// all aura bonuses applied also in aura area effect way to caster
if (GetCasterGuid() != m_target->GetObjectGuid() || !GetCasterGuid().IsPlayer())
return;
if (GetSpellSpecific(m_spellProto->Id) != SPELL_AURA)
return;
// Sanctified Retribution and Swift Retribution (they share one aura), but not Retribution Aura (already gets modded)
if ((GetSpellProto()->SpellFamilyFlags & UI64LIT(0x0000000000000008))==0)
spellId1 = 63531; // placeholder for talent spell mods
// Improved Concentration Aura (auras bonus)
spellId2 = 63510; // placeholder for talent spell mods
// Improved Devotion Aura (auras bonus)
spellId3 = 63514; // placeholder for talent spell mods
break;
}
case SPELLFAMILY_DEATHKNIGHT:
{
// second part of spell apply
switch (GetId())
{
case 49039: spellId1 = 50397; break; // Lichborne
case 48263: // Frost Presence
case 48265: // Unholy Presence
case 48266: // Blood Presence
{
// else part one per 3 pair
if (GetId()==48263 || GetId()==48265) // Frost Presence or Unholy Presence
{
// Improved Blood Presence
int32 heal_pct = 0;
if (apply)
{
Unit::AuraList const& bloodAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = bloodAuras.begin(); itr != bloodAuras.end(); ++itr)
{
// skip same icon
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT &&
(*itr)->GetSpellProto()->SpellIconID == 2636)
{
heal_pct = (*itr)->GetModifier()->m_amount;
break;
}
}
}
if (heal_pct)
m_target->CastCustomSpell(m_target, 63611, &heal_pct, NULL, NULL, true, NULL, NULL, GetCasterGuid());
else
m_target->RemoveAurasDueToSpell(63611);
}
else
spellId1 = 63611; // Improved Blood Presence, trigger for heal
if (GetId()==48263 || GetId()==48266) // Frost Presence or Blood Presence
{
// Improved Unholy Presence
int32 power_pct = 0;
if (apply)
{
Unit::AuraList const& unholyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = unholyAuras.begin(); itr != unholyAuras.end(); ++itr)
{
// skip same icon
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT &&
(*itr)->GetSpellProto()->SpellIconID == 2633)
{
power_pct = (*itr)->GetModifier()->m_amount;
break;
}
}
}
if (power_pct || !apply)
spellId2 = 49772; // Unholy Presence, speed part, spell1 used for Improvement presence fit to own presence
}
else
spellId1 = 49772; // Unholy Presence move speed
if (GetId()==48265 || GetId()==48266) // Unholy Presence or Blood Presence
{
// Improved Frost Presence
int32 stamina_pct = 0;
if (apply)
{
Unit::AuraList const& frostAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = frostAuras.begin(); itr != frostAuras.end(); ++itr)
{
// skip same icon
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT &&
(*itr)->GetSpellProto()->SpellIconID == 2632)
{
stamina_pct = (*itr)->GetModifier()->m_amount;
break;
}
}
}
if (stamina_pct)
m_target->CastCustomSpell(m_target, 61261, &stamina_pct, NULL, NULL, true, NULL, NULL, GetCasterGuid());
else
m_target->RemoveAurasDueToSpell(61261);
}
else
spellId1 = 61261; // Frost Presence, stamina
if (GetId()==48265) // Unholy Presence
{
// Improved Unholy Presence, special case for own presence
int32 power_pct = 0;
if (apply)
{
Unit::AuraList const& unholyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = unholyAuras.begin(); itr != unholyAuras.end(); ++itr)
{
// skip same icon
if ((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT &&
(*itr)->GetSpellProto()->SpellIconID == 2633)
{
power_pct = (*itr)->GetModifier()->m_amount;
break;
}
}
}
if (power_pct)
{
int32 bp = 5;
m_target->CastCustomSpell(m_target, 63622, &bp, &bp, &bp, true, NULL, NULL, GetCasterGuid());
m_target->CastCustomSpell(m_target, 65095, &bp, NULL, NULL, true, NULL, NULL, GetCasterGuid());
}
else
{
m_target->RemoveAurasDueToSpell(63622);
m_target->RemoveAurasDueToSpell(65095);
}
}
break;
}
}
// Improved Blood Presence
if (GetSpellProto()->SpellIconID == 2636 && m_isPassive)
{
// if presence active: Frost Presence or Unholy Presence
if (apply && (m_target->HasAura(48263) || m_target->HasAura(48265)))
{
Aura* aura = GetAuraByEffectIndex(EFFECT_INDEX_0);
if (!aura)
return;
int32 bp = aura->GetModifier()->m_amount;
m_target->CastCustomSpell(m_target, 63611, &bp, NULL, NULL, true, NULL, NULL, GetCasterGuid());
}
else
m_target->RemoveAurasDueToSpell(63611);
return;
}
// Improved Frost Presence
if (GetSpellProto()->SpellIconID == 2632 && m_isPassive)
{
// if presence active: Unholy Presence or Blood Presence
if (apply && (m_target->HasAura(48265) || m_target->HasAura(48266)))
{
Aura* aura = GetAuraByEffectIndex(EFFECT_INDEX_0);
if (!aura)
return;
int32 bp0 = aura->GetModifier()->m_amount;
int32 bp1 = 0; // disable threat mod part for not Frost Presence case
m_target->CastCustomSpell(m_target, 61261, &bp0, &bp1, NULL, true, NULL, NULL, GetCasterGuid());
}
else
m_target->RemoveAurasDueToSpell(61261);
return;
}
// Improved Unholy Presence
if (GetSpellProto()->SpellIconID == 2633 && m_isPassive)
{
// if presence active: Unholy Presence
if (apply && m_target->HasAura(48265))
{
int32 bp = 5;
m_target->CastCustomSpell(m_target, 63622, &bp, &bp, &bp, true, NULL, NULL, GetCasterGuid());
m_target->CastCustomSpell(m_target, 65095, &bp, NULL, NULL, true, NULL, NULL, GetCasterGuid());
}
else
{
m_target->RemoveAurasDueToSpell(63622);
m_target->RemoveAurasDueToSpell(65095);
}
// if presence active: Frost Presence or Blood Presence
if (!apply || m_target->HasAura(48263) || m_target->HasAura(48266))
spellId1 = 49772;
else
return;
break;
}
break;
}
default:
return;
}
// prevent aura deletion, specially in multi-boost case
SetInUse(true);
if (apply || cast_at_remove)
{
if (spellId1)
m_target->CastSpell(m_target, spellId1, true, NULL, NULL, GetCasterGuid());
if (spellId2 && !IsDeleted())
m_target->CastSpell(m_target, spellId2, true, NULL, NULL, GetCasterGuid());
if (spellId3 && !IsDeleted())
m_target->CastSpell(m_target, spellId3, true, NULL, NULL, GetCasterGuid());
if (spellId4 && !IsDeleted())
m_target->CastSpell(m_target, spellId4, true, NULL, NULL, GetCasterGuid());
}
else
{
if (spellId1)
m_target->RemoveAurasByCasterSpell(spellId1, GetCasterGuid());
if (spellId2)
m_target->RemoveAurasByCasterSpell(spellId2, GetCasterGuid());
if (spellId3)
m_target->RemoveAurasByCasterSpell(spellId3, GetCasterGuid());
if (spellId4)
m_target->RemoveAurasByCasterSpell(spellId4, GetCasterGuid());
}
SetInUse(false);
}
SpellAuraHolder::~SpellAuraHolder()
{
// note: auras in delete list won't be affected since they clear themselves from holder when adding to deletedAuraslist
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aur = m_auras[i])
delete aur;
}
void SpellAuraHolder::Update(uint32 diff)
{
if (m_duration > 0)
{
m_duration -= diff;
if (m_duration < 0)
m_duration = 0;
m_timeCla -= diff;
if (m_timeCla <= 0)
{
if (Unit* caster = GetCaster())
{
Powers powertype = Powers(GetSpellProto()->powerType);
int32 manaPerSecond = GetSpellProto()->manaPerSecond + GetSpellProto()->manaPerSecondPerLevel * caster->getLevel();
m_timeCla = 1*IN_MILLISECONDS;
if (manaPerSecond)
{
if (powertype == POWER_HEALTH)
caster->ModifyHealth(-manaPerSecond);
else
caster->ModifyPower(powertype, -manaPerSecond);
}
}
}
}
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aura = m_auras[i])
aura->UpdateAura(diff);
// Channeled aura required check distance from caster
if(IsChanneledSpell(m_spellProto) && GetCasterGuid() != m_target->GetObjectGuid())
{
Unit* caster = GetCaster();
if(!caster)
{
m_target->RemoveAurasByCasterSpell(GetId(), GetCasterGuid());
return;
}
// need check distance for channeled target only
if (caster->GetChannelObjectGuid() == m_target->GetObjectGuid())
{
// Get spell range
float max_range = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
if(Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RANGE, max_range, NULL);
if(!caster->IsWithinDistInMap(m_target, max_range))
{
caster->InterruptSpell(CURRENT_CHANNELED_SPELL);
return;
}
}
}
}
void SpellAuraHolder::RefreshHolder()
{
SetAuraDuration(GetAuraMaxDuration());
SendAuraUpdate(false);
}
void SpellAuraHolder::SetAuraMaxDuration(int32 duration)
{
m_maxDuration = duration;
// possible overwrite persistent state
if (duration > 0)
{
if (!(IsPassive() && GetSpellProto()->DurationIndex == 0))
SetPermanent(false);
SetAuraFlags(GetAuraFlags() | AFLAG_DURATION);
}
else
SetAuraFlags(GetAuraFlags() & ~AFLAG_DURATION);
}
bool SpellAuraHolder::HasMechanic(uint32 mechanic) const
{
if (mechanic == m_spellProto->Mechanic)
return true;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (m_auras[i] && m_spellProto->EffectMechanic[i] == mechanic)
return true;
return false;
}
bool SpellAuraHolder::HasMechanicMask(uint32 mechanicMask) const
{
if (mechanicMask & (1 << (m_spellProto->Mechanic - 1)))
return true;
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (m_auras[i] && m_spellProto->EffectMechanic[i] && ((1 << (m_spellProto->EffectMechanic[i] -1)) & mechanicMask))
return true;
return false;
}
bool SpellAuraHolder::IsPersistent() const
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aur = m_auras[i])
if (aur->IsPersistent())
return true;
return false;
}
bool SpellAuraHolder::IsAreaAura() const
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aur = m_auras[i])
if (aur->IsAreaAura())
return true;
return false;
}
bool SpellAuraHolder::IsPositive() const
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (Aura *aur = m_auras[i])
if (!aur->IsPositive())
return false;
return true;
}
bool SpellAuraHolder::IsEmptyHolder() const
{
for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
if (m_auras[i])
return false;
return true;
}
void SpellAuraHolder::UnregisterSingleCastHolder()
{
if (IsSingleTarget())
{
if(Unit* caster = GetCaster())
caster->GetSingleCastSpellTargets().erase(GetSpellProto());
m_isSingleTarget = false;
}
}