mirror of
https://github.com/mangosfour/server.git
synced 2025-12-29 07:37:05 +00:00
Move apply cooldown for like spells to aura apply (GO registering for owner in GO summon spell case)
Store "infinity" cooldown for like spells, ignore it at save and reapply it at aura loading.
Note: one problem still exist for like spells: at loading/far teleport spell icon lost diabled state at client.
Need sedn some unknown data in SendInitialPacketsBeforeAddToMap or SendInitialPacketsAfterAddToMap for restore it state.
6699 lines
262 KiB
C++
6699 lines
262 KiB
C++
/*
|
|
* Copyright (C) 2005-2009 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 "SpellAuras.h"
|
|
#include "DynamicObject.h"
|
|
#include "Group.h"
|
|
#include "UpdateData.h"
|
|
#include "MapManager.h"
|
|
#include "ObjectAccessor.h"
|
|
#include "Policies/SingletonImp.h"
|
|
#include "Totem.h"
|
|
#include "Creature.h"
|
|
#include "Formulas.h"
|
|
#include "BattleGround.h"
|
|
#include "CreatureAI.h"
|
|
#include "Util.h"
|
|
#include "GridNotifiers.h"
|
|
#include "GridNotifiersImpl.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::MeleeDamageBonus and Unit::SpellDamageBonus
|
|
&Aura::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage
|
|
&Aura::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
|
|
&Aura::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_STEALTH_DETECT
|
|
&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)
|
|
&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_BONUS
|
|
&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::MeleeDamageBonus and Unit::SpellDamageBonus
|
|
&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) 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::CalcAbsorbResist
|
|
&Aura::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect
|
|
&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
|
|
&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
|
|
&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::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
|
|
&Aura::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
|
|
&Aura::HandlePeriodicDamagePCT, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
|
|
&Aura::HandleUnused, // 90 unused (3.0.8a) 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 Spell::SelectMagnetTarget
|
|
&Aura::HandleManaShield, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalcAbsorbResist
|
|
&Aura::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT
|
|
&Aura::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER
|
|
&Aura::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now, but still have spells including GM-spell
|
|
&Aura::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT
|
|
&Aura::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
|
|
&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::HandleAddTargetTrigger, //109 SPELL_AURA_ADD_TARGET_TRIGGER
|
|
&Aura::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
|
|
&Aura::HandleNULL, //111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER chance redirect attack to caster
|
|
&Aura::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
|
|
&Aura::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
|
|
&Aura::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
|
|
&Aura::HandleNoImmediateEffect, //115 SPELL_AURA_MOD_HEALING implemented in Unit::SpellBaseHealingBonusForVictim
|
|
&Aura::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT
|
|
&Aura::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult
|
|
&Aura::HandleNoImmediateEffect, //118 SPELL_AURA_MOD_HEALING_PCT implemented in Unit::SpellHealingBonus
|
|
&Aura::HandleUnused, //119 unused (3.0.8a) 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::MeleeDamageBonus
|
|
&Aura::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
|
|
&Aura::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
|
|
&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::MeleeDamageBonus
|
|
&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::SpellHealingBonus
|
|
&Aura::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
|
|
&Aura::HandleHaste, //138 SPELL_AURA_MOD_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::HandleNoImmediateEffect, //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
|
|
&Aura::HandleNULL, //147 SPELL_AURA_ADD_CREATURE_IMMUNITY
|
|
&Aura::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
|
|
&Aura::HandleNoImmediateEffect, //149 SPELL_AURA_REDUCE_PUSHBACK
|
|
&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
|
|
&Aura::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL
|
|
&Aura::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING
|
|
&Aura::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN
|
|
&Aura::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI
|
|
&Aura::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
|
|
&Aura::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell
|
|
&Aura::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemented in Unit::MagicSpellHitResult
|
|
&Aura::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
|
|
&Aura::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
|
|
&Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
|
|
&Aura::HandleUnused, //164 unused (3.0.8a), only one test spell
|
|
&Aura::HandleNoImmediateEffect, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
|
|
&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::SpellDamageBonus, Unit::MeleeDamageBonus
|
|
&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) 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::SpellBaseDamageBonus
|
|
&Aura::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus
|
|
&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
|
|
&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::SpellDamageBonus
|
|
&Aura::HandleUnused, //181 unused (3.0.8a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS
|
|
&Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
|
|
&Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746
|
|
&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::HandleNULL, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
|
|
&Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
|
|
&Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
|
|
&Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
|
|
&Aura::HandleNULL, //194 SPELL_AURA_MOD_IGNORE_ABSORB_SCHOOL
|
|
&Aura::HandleNoImmediateEffect, //195 SPELL_AURA_MOD_IGNORE_ABSORB_FOR_SPELL implement in Unit::CalculateSpellDamage
|
|
&Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN
|
|
&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) 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_XP_PCT implemented in Player::GiveXP
|
|
&Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
|
|
&Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
|
|
&Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
|
|
&Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
|
|
&Aura::HandleNULL, //205 vulnerable to school dmg?
|
|
&Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED
|
|
&Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
|
|
&Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_SPEED_FLIGHT, used only in spell: Flight Form (Passive)
|
|
&Aura::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
|
|
&Aura::HandleNULL, //210 Commentator's Command
|
|
&Aura::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
|
|
&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::HandleNULL, //214 Tamed Pet Passive
|
|
&Aura::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION
|
|
&Aura::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS
|
|
&Aura::HandleUnused, //217 unused (3.0.8a)
|
|
&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) only for spell 44586 that not used in real spell cast
|
|
&Aura::HandleNULL, //223 Cold Stare
|
|
&Aura::HandleUnused, //224 unused (3.0.8a)
|
|
&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 stealth detection
|
|
&Aura::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
|
|
&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::CalculateSpellDuration
|
|
&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::CalculateSpellDuration
|
|
&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::SpellBaseDamageBonus
|
|
&Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus
|
|
&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 player to move forward
|
|
&Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING
|
|
&Aura::HandleNULL, //243 faction reaction override spells
|
|
&Aura::HandleComprehendLanguage, //244 Comprehend language
|
|
&Aura::HandleNULL, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS
|
|
&Aura::HandleNoImmediateEffect, //246 SPELL_AURA_MOD_DURATION_OF_EFFECTS_BY_DISPEL
|
|
&Aura::HandleNULL, //247 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::HandleNULL, //252 haste all?
|
|
&Aura::HandleNULL, //253 SPELL_AURA_MOD_BLOCK_CRIT_CHANCE
|
|
&Aura::HandleNULL, //254 SPELL_AURA_MOD_DISARM_SHIELD disarm Shield
|
|
&Aura::HandleNoImmediateEffect, //255 SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT implemented in Unit::SpellDamageBonus
|
|
&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::HandleNULL, //259 corrupt healing over time spell
|
|
&Aura::HandleNoImmediateEffect, //260 SPELL_AURA_SCREEN_EFFECT (miscvalue = id in ScreenEffect.dbc) not required any code
|
|
&Aura::HandlePhase, //261 SPELL_AURA_PHASE undetactable invisibility? implemented in Unit::isVisibleForOrDetect
|
|
&Aura::HandleNULL, //262
|
|
&Aura::HandleNULL, //263 SPELL_AURA_ALLOW_ONLY_ABILITY player can use only abilities set in SpellClassMask
|
|
&Aura::HandleUnused, //264 unused (3.0.8a)
|
|
&Aura::HandleUnused, //265 unused (3.0.8a)
|
|
&Aura::HandleUnused, //266 unused (3.0.8a)
|
|
&Aura::HandleNoImmediateEffect, //267 SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL implemented in Unit::IsImmunedToSpellEffect
|
|
&Aura::HandleAuraModAttackPowerOfStatPercent, //268 SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT
|
|
&Aura::HandleNULL, //269 ignore DR effects?
|
|
&Aura::HandleNULL, //270 SPELL_AURA_MOD_IGNORE_TARGET_RESIST
|
|
&Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus
|
|
&Aura::HandleNULL, //272 reduce spell cast time?
|
|
&Aura::HandleNULL, //273
|
|
&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::HandleNULL, //278 SPELL_AURA_MOD_DISARM_RANGED disarm ranged weapon
|
|
&Aura::HandleNULL, //279 visual effects? 58836 and 57507
|
|
&Aura::HandleNULL, //280 SPELL_AURA_MOD_TARGET_ARMOR_PCT
|
|
&Aura::HandleNULL, //281 SPELL_AURA_MOD_HONOR_GAIN
|
|
&Aura::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT
|
|
&Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus
|
|
&Aura::HandleUnused, //284 not used by any spells (3.08a)
|
|
&Aura::HandleUnused, //285 not used by any spells (3.08a)
|
|
&Aura::HandleUnused, //286 not used by any spells (3.08a)
|
|
&Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult
|
|
&Aura::HandleUnused, //288 not used by any spells (3.09) except 1 test spell.
|
|
};
|
|
|
|
static AuraType const frozenAuraTypes[] = { SPELL_AURA_MOD_ROOT, SPELL_AURA_MOD_STUN, SPELL_AURA_NONE };
|
|
|
|
Aura::Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem) :
|
|
m_spellmod(NULL), m_caster_guid(0), m_castItemGuid(castItem?castItem->GetGUID():0), m_target(target),
|
|
m_timeCla(1000), m_periodicTimer(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE),
|
|
m_effIndex(eff), m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1), m_procCharges(0), m_stackAmount(1),
|
|
m_positive(false), m_permanent(false), m_isPeriodic(false), m_isAreaAura(false), m_isPersistent(false),
|
|
m_updated(false), m_isRemovedOnShapeLost(true), m_in_use(false)
|
|
{
|
|
assert(target);
|
|
|
|
assert(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
|
|
|
|
m_spellProto = spellproto;
|
|
|
|
m_currentBasePoints = currentBasePoints ? *currentBasePoints : m_spellProto->EffectBasePoints[eff];
|
|
|
|
m_isPassive = IsPassiveSpell(GetId());
|
|
m_positive = IsPositiveEffect(GetId(), m_effIndex);
|
|
|
|
m_applyTime = time(NULL);
|
|
|
|
int32 damage;
|
|
if(!caster)
|
|
{
|
|
m_caster_guid = target->GetGUID();
|
|
damage = m_currentBasePoints+1; // stored value-1
|
|
m_maxduration = target->CalculateSpellDuration(m_spellProto, m_effIndex, target);
|
|
}
|
|
else
|
|
{
|
|
m_caster_guid = caster->GetGUID();
|
|
|
|
damage = caster->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,target);
|
|
m_maxduration = caster->CalculateSpellDuration(m_spellProto, m_effIndex, target);
|
|
|
|
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] == m_spellProto->Id)
|
|
{
|
|
damage = uint32((item_rand_suffix->prefix[k]*castItem->GetItemSuffixFactor()) / 10000 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(damage)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(m_maxduration == -1 || m_isPassive && m_spellProto->DurationIndex == 0)
|
|
m_permanent = true;
|
|
|
|
Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
|
|
|
|
if(!m_permanent && modOwner)
|
|
{
|
|
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxduration);
|
|
// Get zero duration aura after - need set m_maxduration > 0 for apply/remove aura work
|
|
if (m_maxduration<=0)
|
|
m_maxduration = 1;
|
|
}
|
|
|
|
m_duration = m_maxduration;
|
|
|
|
sLog.outDebug("Aura: construct Spellid : %u, Aura : %u Duration : %d Target : %d Damage : %d", m_spellProto->Id, m_spellProto->EffectApplyAuraName[eff], m_maxduration, m_spellProto->EffectImplicitTargetA[eff],damage);
|
|
|
|
m_effIndex = eff;
|
|
SetModifier(AuraType(m_spellProto->EffectApplyAuraName[eff]), damage, m_spellProto->EffectAmplitude[eff], m_spellProto->EffectMiscValue[eff]);
|
|
|
|
// Apply periodic time mod
|
|
if(modOwner && m_modifier.periodictime)
|
|
modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_modifier.periodictime);
|
|
|
|
// Start periodic on next tick or at aura apply
|
|
if (!(m_spellProto->AttributesEx5 & SPELL_ATTR_EX5_START_PERIODIC_AT_APPLY))
|
|
m_periodicTimer += m_modifier.periodictime;
|
|
|
|
m_isDeathPersist = IsDeathPersistentSpell(m_spellProto);
|
|
|
|
m_procCharges = m_spellProto->procCharges;
|
|
if(modOwner)
|
|
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
|
|
|
|
m_isRemovedOnShapeLost = (m_caster_guid==m_target->GetGUID() &&
|
|
m_spellProto->Stances &&
|
|
!(m_spellProto->AttributesEx2 & SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT) &&
|
|
!(m_spellProto->Attributes & SPELL_ATTR_NOT_SHAPESHIFT));
|
|
}
|
|
|
|
Aura::~Aura()
|
|
{
|
|
}
|
|
|
|
AreaAura::AreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
|
|
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, 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(GetSpellProto()->EffectRadiusIndex[m_effIndex]));
|
|
if(Player* modOwner = caster_ptr->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(GetId(), 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;
|
|
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");
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
AreaAura::~AreaAura()
|
|
{
|
|
}
|
|
|
|
PersistentAreaAura::PersistentAreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
|
|
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
|
|
{
|
|
m_isPersistent = true;
|
|
}
|
|
|
|
PersistentAreaAura::~PersistentAreaAura()
|
|
{
|
|
}
|
|
|
|
SingleEnemyTargetAura::SingleEnemyTargetAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
|
|
Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
|
|
{
|
|
if (caster)
|
|
m_casters_target_guid = caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)caster)->GetSelection() : caster->GetUInt64Value(UNIT_FIELD_TARGET);
|
|
else
|
|
m_casters_target_guid = 0;
|
|
}
|
|
|
|
SingleEnemyTargetAura::~SingleEnemyTargetAura()
|
|
{
|
|
}
|
|
|
|
Unit* SingleEnemyTargetAura::GetTriggerTarget() const
|
|
{
|
|
return ObjectAccessor::GetUnit(*m_target, m_casters_target_guid);
|
|
}
|
|
|
|
Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem)
|
|
{
|
|
if (IsAreaAuraEffect(spellproto->Effect[eff]))
|
|
return new AreaAura(spellproto, eff, currentBasePoints, target, caster, castItem);
|
|
|
|
uint32 triggeredSpellId = spellproto->EffectTriggerSpell[eff];
|
|
|
|
if(SpellEntry const* triggeredSpellInfo = sSpellStore.LookupEntry(triggeredSpellId))
|
|
for (int i = 0; i < 3; ++i)
|
|
if (triggeredSpellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_ENEMY)
|
|
return new SingleEnemyTargetAura(spellproto, eff, currentBasePoints, target, caster, castItem);
|
|
|
|
return new Aura(spellproto, eff, currentBasePoints, target, caster, castItem);
|
|
}
|
|
|
|
Unit* Aura::GetCaster() const
|
|
{
|
|
if(m_caster_guid==m_target->GetGUID())
|
|
return m_target;
|
|
|
|
//return ObjectAccessor::GetUnit(*m_target,m_caster_guid);
|
|
//must return caster even if it's in another grid/map
|
|
Unit *unit = ObjectAccessor::GetObjectInWorld(m_caster_guid, (Unit*)NULL);
|
|
return unit && unit->IsInWorld() ? unit : NULL;
|
|
}
|
|
|
|
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_duration > 0)
|
|
{
|
|
m_duration -= diff;
|
|
if (m_duration < 0)
|
|
m_duration = 0;
|
|
m_timeCla -= diff;
|
|
|
|
// GetEffIndex()==0 prevent double/triple apply manaPerSecond/manaPerSecondPerLevel to same spell with many auras
|
|
// all spells with manaPerSecond/manaPerSecondPerLevel have aura in effect 0
|
|
if(GetEffIndex()==0 && m_timeCla <= 0)
|
|
{
|
|
if(Unit* caster = GetCaster())
|
|
{
|
|
Powers powertype = Powers(m_spellProto->powerType);
|
|
int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel();
|
|
m_timeCla = 1*IN_MILISECONDS;
|
|
if (manaPerSecond)
|
|
{
|
|
if(powertype==POWER_HEALTH)
|
|
caster->ModifyHealth(-manaPerSecond);
|
|
else
|
|
caster->ModifyPower(powertype,-manaPerSecond);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Channeled aura required check distance from caster
|
|
if(IsChanneledSpell(m_spellProto) && m_caster_guid != m_target->GetGUID())
|
|
{
|
|
Unit* caster = GetCaster();
|
|
if(!caster)
|
|
{
|
|
m_target->RemoveAura(GetId(),GetEffIndex());
|
|
return;
|
|
}
|
|
|
|
// Get spell range
|
|
float radius;
|
|
SpellModOp mod;
|
|
if (m_spellProto->EffectRadiusIndex[GetEffIndex()])
|
|
{
|
|
radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellProto->EffectRadiusIndex[GetEffIndex()]));
|
|
mod = SPELLMOD_RADIUS;
|
|
}
|
|
else
|
|
{
|
|
radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
|
|
mod = SPELLMOD_RANGE;
|
|
}
|
|
|
|
if(Player* modOwner = caster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(GetId(), mod, radius,NULL);
|
|
|
|
if(!caster->IsWithinDistInMap(m_target,radius))
|
|
{
|
|
m_target->RemoveAura(GetId(),GetEffIndex());
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(m_isPeriodic && (m_duration >= 0 || m_isPassive || m_permanent))
|
|
{
|
|
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;
|
|
PeriodicTick();
|
|
}
|
|
}
|
|
}
|
|
|
|
void AreaAura::Update(uint32 diff)
|
|
{
|
|
// update for the caster of the aura
|
|
if(m_caster_guid == m_target->GetGUID())
|
|
{
|
|
Unit* caster = m_target;
|
|
|
|
if( !caster->hasUnitState(UNIT_STAT_ISOLATED) )
|
|
{
|
|
Unit* owner = caster->GetCharmerOrOwner();
|
|
if (!owner)
|
|
owner = caster;
|
|
std::list<Unit *> 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)
|
|
{
|
|
uint8 subgroup = ((Player*)owner)->GetSubGroup();
|
|
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:
|
|
{
|
|
CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
|
|
Cell cell(p);
|
|
cell.data.Part.reserved = ALL_DISTRICT;
|
|
cell.SetNoCreate();
|
|
|
|
MaNGOS::AnyFriendlyUnitInObjectRangeCheck u_check(caster, owner, m_radius);
|
|
MaNGOS::UnitListSearcher<MaNGOS::AnyFriendlyUnitInObjectRangeCheck> searcher(caster,targets, u_check);
|
|
TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyFriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
|
|
TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyFriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
|
|
CellLock<GridReadGuard> cell_lock(cell, p);
|
|
cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap());
|
|
cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap());
|
|
break;
|
|
}
|
|
case AREA_AURA_ENEMY:
|
|
{
|
|
CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
|
|
Cell cell(p);
|
|
cell.data.Part.reserved = ALL_DISTRICT;
|
|
cell.SetNoCreate();
|
|
|
|
MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(caster, owner, m_radius); // No GetCharmer in searcher
|
|
MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck> searcher(caster, targets, u_check);
|
|
TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
|
|
TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
|
|
CellLock<GridReadGuard> cell_lock(cell, p);
|
|
cell_lock->Visit(cell_lock, world_unit_searcher, *caster->GetMap());
|
|
cell_lock->Visit(cell_lock, grid_unit_searcher, *caster->GetMap());
|
|
break;
|
|
}
|
|
case AREA_AURA_OWNER:
|
|
case AREA_AURA_PET:
|
|
{
|
|
if(owner != caster)
|
|
targets.push_back(owner);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
|
|
{
|
|
if((*tIter)->HasAura(GetId(), m_effIndex))
|
|
continue;
|
|
|
|
if(SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel()))
|
|
{
|
|
int32 actualBasePoints = m_currentBasePoints;
|
|
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
|
|
if(actualSpellInfo != GetSpellProto())
|
|
actualBasePoints = actualSpellInfo->EffectBasePoints[m_effIndex];
|
|
AreaAura *aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, (*tIter), caster, NULL);
|
|
aur->SetAuraDuration(GetAuraDuration());
|
|
(*tIter)->AddAura(aur);
|
|
}
|
|
}
|
|
}
|
|
Aura::Update(diff);
|
|
}
|
|
else // aura at non-caster
|
|
{
|
|
Unit * tmp_target = m_target;
|
|
Unit* caster = GetCaster();
|
|
uint32 tmp_spellId = GetId(), tmp_effIndex = m_effIndex;
|
|
|
|
// WARNING: the aura may get deleted during the update
|
|
// DO NOT access its members after update!
|
|
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(tmp_target, m_radius) ||
|
|
!caster->HasAura(tmp_spellId, tmp_effIndex) ||
|
|
caster->IsFriendlyTo(tmp_target) != needFriendly
|
|
)
|
|
{
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
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() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID())
|
|
{
|
|
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
|
|
|
Group *pGroup = check ? check->GetGroup() : NULL;
|
|
if( pGroup )
|
|
{
|
|
Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself();
|
|
if(!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
else
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
}
|
|
else if( m_areaAuraType == AREA_AURA_RAID) // TODO: fix me!
|
|
{
|
|
// not check group if target == owner or target == pet
|
|
if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID())
|
|
{
|
|
Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
|
|
|
Group *pGroup = check ? check->GetGroup() : NULL;
|
|
if( pGroup )
|
|
{
|
|
Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself();
|
|
if(!checkTarget)
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
else
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
}
|
|
else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER )
|
|
{
|
|
if( tmp_target->GetGUID() != caster->GetCharmerOrOwnerGUID() )
|
|
tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
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
|
|
Unit *caster = GetCaster();
|
|
if (caster)
|
|
{
|
|
DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
|
|
if (dynObj)
|
|
{
|
|
if (!m_target->IsWithinDistInMap(dynObj, dynObj->GetRadius()))
|
|
remove = true;
|
|
}
|
|
else
|
|
remove = true;
|
|
}
|
|
else
|
|
remove = true;
|
|
|
|
Unit *tmp_target = m_target;
|
|
uint32 tmp_id = GetId(), tmp_index = GetEffIndex();
|
|
|
|
// WARNING: the aura may get deleted during the update
|
|
// DO NOT access its members after update!
|
|
Aura::Update(diff);
|
|
|
|
if(remove)
|
|
tmp_target->RemoveAura(tmp_id, tmp_index);
|
|
}
|
|
|
|
void Aura::ApplyModifier(bool apply, bool Real)
|
|
{
|
|
AuraType aura = m_modifier.m_auraname;
|
|
|
|
m_in_use = true;
|
|
if(aura<TOTAL_AURAS)
|
|
(*this.*AuraHandler [aura])(apply,Real);
|
|
m_in_use = false;
|
|
}
|
|
|
|
void Aura::_AddAura()
|
|
{
|
|
if (!GetId())
|
|
return;
|
|
if(!m_target)
|
|
return;
|
|
|
|
// Second aura if some spell
|
|
bool secondaura = false;
|
|
// Try find slot for aura
|
|
uint8 slot = NULL_AURA_SLOT;
|
|
// Lookup for some spell auras (and get slot from it)
|
|
for(uint8 i = 0; i < m_effIndex; i++)
|
|
{
|
|
Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
|
|
for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
|
|
{
|
|
// allow use single slot only by auras from same caster
|
|
if(itr->second->GetCasterGUID()==GetCasterGUID())
|
|
{
|
|
slot = itr->second->GetAuraSlot();
|
|
secondaura = true;
|
|
break;
|
|
}
|
|
}
|
|
if (secondaura)
|
|
break;
|
|
}
|
|
// Lookup free slot
|
|
if (!secondaura && 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);
|
|
}
|
|
}
|
|
|
|
// passive auras (except totem auras) do not get placed in the slots
|
|
// area auras with SPELL_AURA_NONE are not shown on target
|
|
if((!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) &&
|
|
(m_spellProto->Effect[GetEffIndex()] != SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || m_target != caster))
|
|
{
|
|
SetAuraSlot( slot );
|
|
if(slot < MAX_AURAS) // slot found send data to client
|
|
{
|
|
SetAura(false);
|
|
SetAuraFlags((1 << GetEffIndex()) | AFLAG_NOT_CASTER | ((GetAuraMaxDuration() > 0) ? AFLAG_DURATION : AFLAG_NONE) | (IsPositive() ? AFLAG_POSITIVE : AFLAG_NEGATIVE));
|
|
SetAuraLevel(caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
|
|
SendAuraUpdate(false);
|
|
}
|
|
|
|
//*****************************************************
|
|
// Update target aura state flag (at 1 aura apply)
|
|
// TODO: Make it easer
|
|
//*****************************************************
|
|
if (!secondaura)
|
|
{
|
|
// 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
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellProto->SpellFamilyFlags & 4)
|
|
m_target->ModifyAuraState(AURA_STATE_IMMOLATE, true);
|
|
|
|
// Faerie Fire (druid versions)
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags & 0x0000000000000400LL)
|
|
m_target->ModifyAuraState(AURA_STATE_FAERIE_FIRE, true);
|
|
|
|
// Victorious
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags & 0x0004000000000000LL)
|
|
m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, true);
|
|
|
|
// Swiftmend state on Regrowth & Rejuvenation
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellFamilyFlags & 0x50 )
|
|
m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
|
|
|
|
// Deadly poison aura state
|
|
if(m_spellProto->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellProto->SpellFamilyFlags & 0x10000)
|
|
m_target->ModifyAuraState(AURA_STATE_DEADLY_POISON, true);
|
|
|
|
// Enrage aura state
|
|
if(m_spellProto->Dispel == DISPEL_ENRAGE)
|
|
m_target->ModifyAuraState(AURA_STATE_ENRAGE, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::_RemoveAura()
|
|
{
|
|
// 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(), GetEffIndex());
|
|
if (dynObj)
|
|
dynObj->RemoveAffected(m_target);
|
|
}
|
|
|
|
//passive auras do not get put in slots
|
|
// 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;
|
|
|
|
bool lastaura = true;
|
|
|
|
// find other aura in same slot (current already removed from list)
|
|
for(uint8 i = 0; i < 3; i++)
|
|
{
|
|
Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
|
|
for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
|
|
{
|
|
if(itr->second->GetAuraSlot()==slot)
|
|
{
|
|
lastaura = false;
|
|
break;
|
|
}
|
|
}
|
|
if(!lastaura)
|
|
break;
|
|
}
|
|
|
|
// only remove icon when the last aura of the spell is removed (current aura already removed from list)
|
|
if (lastaura)
|
|
{
|
|
// unregister aura diminishing (and store last time)
|
|
if (getDiminishGroup() != DIMINISHING_NONE )
|
|
m_target->ApplyDiminishingAura(getDiminishGroup(),false);
|
|
|
|
SetAura(true);
|
|
SetAuraFlags(AFLAG_NONE);
|
|
SetAuraLevel(0);
|
|
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);
|
|
|
|
uint32 removeState = 0;
|
|
switch(m_spellProto->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_PALADIN:
|
|
if (IsSealSpell(m_spellProto))
|
|
removeState = AURA_STATE_JUDGEMENT; // Update Seals information
|
|
break;
|
|
case SPELLFAMILY_WARLOCK:
|
|
if(m_spellProto->SpellFamilyFlags & 4)
|
|
removeState = AURA_STATE_IMMOLATE; // Conflagrate aura state
|
|
break;
|
|
case SPELLFAMILY_DRUID:
|
|
if(m_spellProto->SpellFamilyFlags & 0x0000000000000400LL)
|
|
removeState = AURA_STATE_FAERIE_FIRE; // Faerie Fire (druid versions)
|
|
else if(m_spellProto->SpellFamilyFlags & 0x50)
|
|
removeState = AURA_STATE_SWIFTMEND; // Swiftmend aura state
|
|
break;
|
|
case SPELLFAMILY_WARRIOR:
|
|
if(m_spellProto->SpellFamilyFlags & 0x0004000000000000LL)
|
|
removeState = AURA_STATE_WARRIOR_VICTORY_RUSH; // Victorious
|
|
break;
|
|
case SPELLFAMILY_ROGUE:
|
|
if(m_spellProto->SpellFamilyFlags & 0x10000)
|
|
removeState = AURA_STATE_DEADLY_POISON; // Deadly poison aura state
|
|
break;
|
|
case SPELLFAMILY_HUNTER:
|
|
if(m_spellProto->SpellFamilyFlags & 0x1000000000000000LL)
|
|
removeState = AURA_STATE_FAERIE_FIRE; // Sting (hunter versions)
|
|
|
|
}
|
|
// Remove state (but need check other auras for it)
|
|
if (removeState)
|
|
{
|
|
bool found = false;
|
|
Unit::AuraMap& Auras = m_target->GetAuras();
|
|
for(Unit::AuraMap::iterator i = Auras.begin(); i != Auras.end(); ++i)
|
|
{
|
|
SpellEntry const *auraSpellInfo = (*i).second->GetSpellProto();
|
|
if(auraSpellInfo->SpellFamilyName == m_spellProto->SpellFamilyName &&
|
|
auraSpellInfo->SpellFamilyFlags == m_spellProto->SpellFamilyFlags )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
// this has been last aura
|
|
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 existed cases)
|
|
((Player*)caster)->SendCooldownEvent(GetSpellProto());
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::SendAuraUpdate(bool remove)
|
|
{
|
|
WorldPacket data(SMSG_AURA_UPDATE);
|
|
data.append(m_target->GetPackGUID());
|
|
data << uint8(GetAuraSlot());
|
|
data << uint32(remove ? 0 : GetId());
|
|
|
|
if(remove)
|
|
{
|
|
m_target->SendMessageToSet(&data, true);
|
|
return;
|
|
}
|
|
|
|
uint8 auraFlags = GetAuraFlags();
|
|
data << uint8(auraFlags);
|
|
data << uint8(GetAuraLevel());
|
|
data << uint8(m_procCharges ? m_procCharges : m_stackAmount);
|
|
|
|
if(!(auraFlags & AFLAG_NOT_CASTER))
|
|
{
|
|
data << uint8(0); // pguid
|
|
}
|
|
|
|
if(auraFlags & AFLAG_DURATION)
|
|
{
|
|
data << uint32(GetAuraMaxDuration());
|
|
data << uint32(GetAuraDuration());
|
|
}
|
|
|
|
m_target->SendMessageToSet(&data, true);
|
|
}
|
|
|
|
void Aura::SetStackAmount(uint8 stackAmount)
|
|
{
|
|
if (stackAmount != m_stackAmount)
|
|
{
|
|
Unit *target = GetTarget();
|
|
Unit *caster = GetCaster();
|
|
if (!target || !caster)
|
|
return;
|
|
m_stackAmount = stackAmount;
|
|
int32 amount = m_stackAmount * caster->CalculateSpellDamage(m_spellProto, m_effIndex, m_currentBasePoints, target);
|
|
// Reapply if amount change
|
|
if (amount!=m_modifier.m_amount)
|
|
{
|
|
ApplyModifier(false, true);
|
|
m_modifier.m_amount = amount;
|
|
ApplyModifier(true, true);
|
|
}
|
|
}
|
|
RefreshAura();
|
|
}
|
|
|
|
bool Aura::modStackAmount(int32 num)
|
|
{
|
|
// Can`t mod
|
|
if (!m_spellProto->StackAmount)
|
|
return true;
|
|
|
|
// Modify stack but limit it
|
|
int32 stackAmount = m_stackAmount + num;
|
|
if (stackAmount > m_spellProto->StackAmount)
|
|
stackAmount = m_spellProto->StackAmount;
|
|
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 Aura::RefreshAura()
|
|
{
|
|
m_duration = m_maxduration;
|
|
SendAuraUpdate(false);
|
|
}
|
|
|
|
bool Aura::isAffectedOnSpell(SpellEntry const *spell) const
|
|
{
|
|
// Check family name
|
|
if (spell->SpellFamilyName != m_spellProto->SpellFamilyName)
|
|
return false;
|
|
// Check EffectClassMask
|
|
uint32 const *ptr = getAuraSpellClassMask();
|
|
if (((uint64*)ptr)[0] & spell->SpellFamilyFlags)
|
|
return true;
|
|
if (ptr[2] & spell->SpellFamilyFlags2)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** BASIC AURA FUNCTION ***/
|
|
/*********************************************************/
|
|
void Aura::HandleAddModifier(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER || !Real)
|
|
return;
|
|
|
|
if(m_modifier.m_miscvalue >= MAX_SPELLMOD)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
// Add custom charges for some mod aura
|
|
switch (m_spellProto->Id)
|
|
{
|
|
case 17941: // Shadow Trance
|
|
case 22008: // Netherwind Focus
|
|
case 31834: // Light's Grace
|
|
case 34754: // Clearcasting
|
|
case 34936: // Backlash
|
|
case 48108: // Hot Streak
|
|
case 54741: // Firestarter
|
|
case 57761: // Fireball!
|
|
SetAuraCharges(1);
|
|
break;
|
|
}
|
|
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->op = SpellModOp(m_modifier.m_miscvalue);
|
|
mod->value = m_modifier.m_amount;
|
|
mod->type = SpellModType(m_modifier.m_auraname); // SpellModType value == spell aura types
|
|
mod->spellId = GetId();
|
|
|
|
uint32 const *ptr;
|
|
SpellAffectEntry const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
|
|
if (spellAffect)
|
|
ptr = &spellAffect->SpellClassMask[0];
|
|
else
|
|
{
|
|
switch (m_effIndex)
|
|
{
|
|
case 0: ptr = &m_spellProto->EffectSpellClassMaskA[0]; break;
|
|
case 1: ptr = &m_spellProto->EffectSpellClassMaskB[0]; break;
|
|
case 2: ptr = &m_spellProto->EffectSpellClassMaskC[0]; break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
mod->mask = (uint64)ptr[0] | (uint64)ptr[1]<<32;
|
|
mod->mask2= (uint64)ptr[2];
|
|
mod->charges = m_procCharges;
|
|
|
|
m_spellmod = mod;
|
|
}
|
|
|
|
uint64 spellFamilyMask = m_spellmod->mask;
|
|
|
|
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
|
|
|
// reapply some passive spells after add/remove related spellmods
|
|
if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && (spellFamilyMask & 0x0000100000000000LL))
|
|
{
|
|
m_target->RemoveAurasDueToSpell(45471);
|
|
|
|
if(apply)
|
|
m_target->CastSpell(m_target,45471,true);
|
|
}
|
|
}
|
|
void Aura::HandleAddTargetTrigger(bool apply, bool Real)
|
|
{
|
|
// Use SpellModifier structure for check
|
|
// used only fields:
|
|
// spellId, mask, mask2
|
|
if (apply)
|
|
{
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->spellId = GetId();
|
|
|
|
uint32 const *ptr;
|
|
SpellAffectEntry const *spellAffect = spellmgr.GetSpellAffect(GetId(), m_effIndex);
|
|
if (spellAffect)
|
|
ptr = &spellAffect->SpellClassMask[0];
|
|
else
|
|
{
|
|
switch (m_effIndex)
|
|
{
|
|
case 0: ptr = &m_spellProto->EffectSpellClassMaskA[0]; break;
|
|
case 1: ptr = &m_spellProto->EffectSpellClassMaskB[0]; break;
|
|
case 2: ptr = &m_spellProto->EffectSpellClassMaskC[0]; break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
mod->mask = (uint64)ptr[0] | (uint64)ptr[1]<<32;
|
|
mod->mask2= (uint64)ptr[2];
|
|
m_spellmod = mod;
|
|
}
|
|
else
|
|
{
|
|
delete m_spellmod;
|
|
m_spellmod = NULL;
|
|
}
|
|
}
|
|
|
|
void Aura::TriggerSpell()
|
|
{
|
|
Unit* caster = GetCaster();
|
|
Unit* target = GetTriggerTarget();
|
|
|
|
if(!caster || !target)
|
|
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;
|
|
|
|
// specific code for cases with no trigger spell provided in field
|
|
if (triggeredSpellInfo == NULL)
|
|
{
|
|
switch(auraSpellInfo->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
switch(auraId)
|
|
{
|
|
// Firestone Passive (1-5 ranks)
|
|
case 758:
|
|
case 17945:
|
|
case 17947:
|
|
case 17949:
|
|
case 27252:
|
|
{
|
|
if (caster->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
Item* item = ((Player*)caster)->GetWeaponForAttack(BASE_ATTACK);
|
|
if (!item)
|
|
return;
|
|
uint32 enchant_id = 0;
|
|
switch (GetId())
|
|
{
|
|
case 758: enchant_id = 1803; break; // Rank 1
|
|
case 17945: enchant_id = 1823; break; // Rank 2
|
|
case 17947: enchant_id = 1824; break; // Rank 3
|
|
case 17949: enchant_id = 1825; break; // Rank 4
|
|
case 27252: enchant_id = 2645; break; // Rank 5
|
|
default:
|
|
return;
|
|
}
|
|
// remove old enchanting before applying new
|
|
((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false);
|
|
item->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, m_modifier.periodictime+1000, 0);
|
|
// add new enchanting
|
|
((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true);
|
|
return;
|
|
}
|
|
// // Periodic Mana Burn
|
|
// case 812: break;
|
|
// // Polymorphic Ray
|
|
// case 6965: break;
|
|
// // Fire Nova (1-7 ranks)
|
|
// case 8350:
|
|
// case 8508:
|
|
// case 8509:
|
|
// case 11312:
|
|
// case 11313:
|
|
// case 25540:
|
|
// case 25544:
|
|
// break;
|
|
// Thaumaturgy Channel
|
|
case 9712: 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;
|
|
// Brood Affliction: Bronze
|
|
case 23170:
|
|
{
|
|
m_target->CastSpell(m_target, 23171, true, 0, this);
|
|
return;
|
|
}
|
|
// // Mark of Frost
|
|
// case 23184: break;
|
|
// Restoration
|
|
case 23493:
|
|
{
|
|
int32 heal = caster->GetMaxHealth() / 10;
|
|
caster->ModifyHealth( heal );
|
|
caster->SendHealSpellLog(caster, 23493, heal);
|
|
|
|
int32 mana = caster->GetMaxPower(POWER_MANA);
|
|
if (mana)
|
|
{
|
|
mana /= 10;
|
|
caster->ModifyPower( POWER_MANA, mana );
|
|
caster->SendEnergizeSpellLog(caster, 23493, mana, POWER_MANA);
|
|
}
|
|
break;
|
|
}
|
|
// // 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;
|
|
// // Shadow Bolt Whirl
|
|
// case 24834: break;
|
|
// // Stink Trap
|
|
// case 24918: break;
|
|
// // Mark of Nature
|
|
// case 25041: break;
|
|
// // Agro Drones
|
|
// case 25152: break;
|
|
// // Consume
|
|
// case 25371: break;
|
|
// // 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;
|
|
// // Frost Blast
|
|
// case 27808: break;
|
|
// // 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;
|
|
// // Inoculate Nestlewood Owlkin
|
|
case 29528: trigger_spell_id = 28713; 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;
|
|
// Feed Captured Animal
|
|
case 29917: 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;
|
|
// Extract Gas
|
|
case 30427:
|
|
{
|
|
// move loot to player inventory and despawn target
|
|
if(caster->GetTypeId() ==TYPEID_PLAYER &&
|
|
target->GetTypeId() == TYPEID_UNIT &&
|
|
((Creature*)target)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD)
|
|
{
|
|
Player* player = (Player*)caster;
|
|
Creature* creature = (Creature*)target;
|
|
// missing lootid has been reported on startup - just return
|
|
if (!creature->GetCreatureInfo()->SkinLootId)
|
|
return;
|
|
|
|
player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId,LootTemplates_Skinning,true);
|
|
|
|
creature->setDeathState(JUST_DIED);
|
|
creature->RemoveCorpse();
|
|
creature->SetHealth(0); // just for nice GM-mode view
|
|
}
|
|
return;
|
|
break;
|
|
}
|
|
// Quake
|
|
case 30576: 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;
|
|
// Doom
|
|
case 31347:
|
|
{
|
|
m_target->CastSpell(m_target,31350,true);
|
|
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
|
return;
|
|
}
|
|
// Spellcloth
|
|
case 31373:
|
|
{
|
|
// Summon Elemental after create item
|
|
caster->SummonCreature(17870, 0, 0, 0, caster->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
|
|
return;
|
|
}
|
|
// // Bloodmyst Tesla
|
|
// case 31611: break;
|
|
// // Doomfire
|
|
// case 31944: break;
|
|
// // Teleport Test
|
|
// case 32236: break;
|
|
// // Earthquake
|
|
// case 32686: break;
|
|
// // Possess
|
|
// case 33401: break;
|
|
// // Draw Shadows
|
|
// case 33563: break;
|
|
// // Murmur's Touch
|
|
// case 33711: break;
|
|
// Flame Quills
|
|
case 34229:
|
|
{
|
|
// cast 24 spells 34269-34289, 34314-34316
|
|
for(uint32 spell_id = 34269; spell_id != 34290; ++spell_id)
|
|
caster->CastSpell(m_target,spell_id,true);
|
|
for(uint32 spell_id = 34314; spell_id != 34317; ++spell_id)
|
|
caster->CastSpell(m_target,spell_id,true);
|
|
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;
|
|
// Remote Toy
|
|
case 37027: 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;
|
|
// Eye of Grillok
|
|
case 38495:
|
|
{
|
|
m_target->CastSpell(m_target, 38530, true);
|
|
return;
|
|
}
|
|
// Absorb Eye of Grillok (Zezzak's Shard)
|
|
case 38554:
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
caster->CastSpell(caster, 38495, true);
|
|
|
|
Creature* creatureTarget = (Creature*)m_target;
|
|
|
|
creatureTarget->setDeathState(JUST_DIED);
|
|
creatureTarget->RemoveCorpse();
|
|
creatureTarget->SetHealth(0); // just for nice GM-mode view
|
|
return;
|
|
}
|
|
// // Magic Sucker Device timer
|
|
// case 38672: break;
|
|
// // Tomb Guarding Charging
|
|
// case 38751: break;
|
|
// // Murmur's Touch
|
|
// case 38794: break;
|
|
// // Activate Nether-wraith Beacon (31742 Nether-wraith Beacon item)
|
|
// case 39105: break;
|
|
// // 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;
|
|
// Tear of Azzinoth Summon Channel - it's not really supposed to do anything,and this only prevents the console spam
|
|
case 39857: 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;
|
|
// Personalized Weather
|
|
case 46736: 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;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_MAGE:
|
|
{
|
|
switch(auraId)
|
|
{
|
|
// Invisibility
|
|
case 66:
|
|
// Here need periodic triger 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_DRUID:
|
|
{
|
|
switch(auraId)
|
|
{
|
|
// Cat Form
|
|
// trigger_spell_id not set and unknown effect triggered in this case, ignoring for while
|
|
case 768:
|
|
return;
|
|
// Frenzied Regeneration
|
|
case 22842:
|
|
case 22895:
|
|
case 22896:
|
|
case 26999:
|
|
{
|
|
int32 LifePerRage = GetModifier()->m_amount;
|
|
|
|
int32 lRage = m_target->GetPower(POWER_RAGE);
|
|
if(lRage > 100) // rage stored as rage*10
|
|
lRage = 100;
|
|
m_target->ModifyPower(POWER_RAGE, -lRage);
|
|
int32 FRTriggerBasePoints = int32(lRage*LifePerRage/10);
|
|
m_target->CastCustomSpell(m_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)
|
|
{
|
|
// Lightning Shield (The Earthshatterer set trigger after cast Lighting Shield)
|
|
case 28820:
|
|
{
|
|
// Need remove self if Lightning Shield not active
|
|
Unit::AuraMap const& auras = target->GetAuras();
|
|
for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
{
|
|
SpellEntry const* spell = itr->second->GetSpellProto();
|
|
if( spell->SpellFamilyName == SPELLFAMILY_SHAMAN &&
|
|
spell->SpellFamilyFlags & 0x0000000000000400L)
|
|
return;
|
|
}
|
|
target->RemoveAurasDueToSpell(28820);
|
|
return;
|
|
}
|
|
// Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus)
|
|
case 38443:
|
|
{
|
|
bool all = true;
|
|
for(int i = 0; i < MAX_TOTEM; ++i)
|
|
{
|
|
if(!caster->m_TotemSlot[i])
|
|
{
|
|
all = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(all)
|
|
caster->CastSpell(caster,38437,true);
|
|
else
|
|
caster->RemoveAurasDueToSpell(38437);
|
|
return;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
// Reget trigger spell proto
|
|
triggeredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
|
|
if(triggeredSpellInfo == NULL)
|
|
{
|
|
sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Spell exist but require custom code
|
|
switch(auraId)
|
|
{
|
|
// Curse of Idiocy
|
|
case 1010:
|
|
{
|
|
// 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(m_caster_guid == m_target->GetGUID())
|
|
return;
|
|
|
|
// stop triggering after each affected stats lost > 90
|
|
int32 intelectLoss = 0;
|
|
int32 spiritLoss = 0;
|
|
|
|
Unit::AuraList const& mModStat = m_target->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;
|
|
|
|
caster = target;
|
|
break;
|
|
}
|
|
// Mana Tide
|
|
case 16191:
|
|
{
|
|
caster->CastCustomSpell(target, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// All ok cast by default case
|
|
caster->CastSpell(target, triggeredSpellInfo, true, 0, this);
|
|
}
|
|
|
|
void Aura::TriggerSpellWithValue()
|
|
{
|
|
Unit* caster = GetCaster();
|
|
Unit* target = GetTriggerTarget();
|
|
|
|
if(!caster || !target)
|
|
return;
|
|
|
|
// generic casting code with custom spells and target/caster customs
|
|
uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
|
|
int32 basepoints0 = this->GetModifier()->m_amount;
|
|
|
|
caster->CastCustomSpell(target, trigger_spell_id, &basepoints0, 0, 0, true, 0, this);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** AURA EFFECTS ***/
|
|
/*********************************************************/
|
|
|
|
void Aura::HandleAuraDummy(bool apply, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
|
|
// AT APPLY
|
|
if(apply)
|
|
{
|
|
switch(GetId())
|
|
{
|
|
case 1515: // Tame beast
|
|
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
|
|
if( caster && m_target->CanHaveThreatList())
|
|
m_target->AddThreat(caster, 10.0f);
|
|
return;
|
|
case 13139: // net-o-matic
|
|
// root to self part of (root_target->charge->root_self sequence
|
|
if(caster)
|
|
caster->CastSpell(caster,13138,true,NULL,this);
|
|
return;
|
|
case 39850: // Rocket Blast
|
|
if(roll_chance_i(20)) // backfire stun
|
|
m_target->CastSpell(m_target, 51581, true, NULL, this);
|
|
return;
|
|
case 43873: // Headless Horseman Laugh
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)caster)->PlaySound(11965, false);
|
|
return;
|
|
case 46354: // Blood Elf Illusion
|
|
if(caster)
|
|
{
|
|
switch(caster->getGender())
|
|
{
|
|
case GENDER_FEMALE:
|
|
caster->CastSpell(m_target,46356,true,NULL,this);
|
|
break;
|
|
case GENDER_MALE:
|
|
caster->CastSpell(m_target,46355,true,NULL,this);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
case 46699: // Requires No Ammo
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use
|
|
return;
|
|
}
|
|
|
|
// Earth Shield
|
|
if ( caster && GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags & 0x40000000000LL))
|
|
{
|
|
// prevent double apply bonuses
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
|
|
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
|
|
return;
|
|
}
|
|
|
|
// some auras applied at aura apply
|
|
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
|
|
if(saBounds.first != saBounds.second)
|
|
{
|
|
uint32 zone = m_target->GetZoneId();
|
|
uint32 area = m_target->GetAreaId();
|
|
|
|
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
|
if(itr->second->autocast && itr->second->IsFitToRequirements((Player*)m_target,zone,area))
|
|
if( !m_target->HasAura(itr->second->spellId,0) )
|
|
m_target->CastSpell(m_target,itr->second->spellId,true);
|
|
}
|
|
}
|
|
}
|
|
// AT REMOVE
|
|
else
|
|
{
|
|
if( m_target->GetTypeId() == TYPEID_PLAYER &&
|
|
( GetSpellProto()->Effect[0]==72 || GetSpellProto()->Effect[0]==6 &&
|
|
( GetSpellProto()->EffectApplyAuraName[0]==1 || GetSpellProto()->EffectApplyAuraName[0]==128 ) ) )
|
|
{
|
|
// spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425
|
|
((Player*)m_target)->SetFarSightGUID(0);
|
|
WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
|
|
((Player*)m_target)->GetSession()->SendPacket(&data);
|
|
return;
|
|
}
|
|
|
|
if( (IsQuestTameSpell(GetId())) && caster && caster->isAlive() && m_target->isAlive())
|
|
{
|
|
uint32 finalSpelId = 0;
|
|
switch(GetId())
|
|
{
|
|
case 19548: finalSpelId = 19597; break;
|
|
case 19674: finalSpelId = 19677; break;
|
|
case 19687: finalSpelId = 19676; break;
|
|
case 19688: finalSpelId = 19678; break;
|
|
case 19689: finalSpelId = 19679; break;
|
|
case 19692: finalSpelId = 19680; break;
|
|
case 19693: finalSpelId = 19684; break;
|
|
case 19694: finalSpelId = 19681; break;
|
|
case 19696: finalSpelId = 19682; break;
|
|
case 19697: finalSpelId = 19683; break;
|
|
case 19699: finalSpelId = 19685; break;
|
|
case 19700: finalSpelId = 19686; break;
|
|
case 30646: finalSpelId = 30647; break;
|
|
case 30653: finalSpelId = 30648; break;
|
|
case 30654: finalSpelId = 30652; break;
|
|
case 30099: finalSpelId = 30100; break;
|
|
case 30102: finalSpelId = 30103; break;
|
|
case 30105: finalSpelId = 30104; break;
|
|
}
|
|
|
|
if(finalSpelId)
|
|
caster->CastSpell(m_target,finalSpelId,true,NULL,this);
|
|
return;
|
|
}
|
|
|
|
switch(GetId())
|
|
{
|
|
case 2584: // Waiting to Resurrect
|
|
{
|
|
// Waiting to resurrect spell cancel, we must remove player from resurrect queue
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
|
|
bg->RemovePlayerFromResurrectQueue(m_target->GetGUID());
|
|
return;
|
|
}
|
|
case 45934: // Dark Fiend
|
|
{
|
|
// Kill target if dispelled
|
|
if (m_removeMode==AURA_REMOVE_BY_DISPEL)
|
|
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
|
return;
|
|
}
|
|
case 46308: // Burning Winds
|
|
{
|
|
// casted only at creatures at spawn
|
|
m_target->CastSpell(m_target,47287,true,NULL,this);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (caster && m_removeMode == AURA_REMOVE_BY_DEATH)
|
|
{
|
|
// Stop caster Arcane Missle chanelling on death
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE &&
|
|
m_spellProto->SpellFamilyFlags&0x0000000000000800LL)
|
|
{
|
|
caster->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
|
return;
|
|
}
|
|
// Stop caster Penance chanelling on death
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST &&
|
|
m_spellProto->SpellFamilyFlags2 & 0x00000080)
|
|
{
|
|
caster->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// some auras remove at aura remove
|
|
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
|
|
if(saBounds.first != saBounds.second)
|
|
{
|
|
uint32 zone = m_target->GetZoneId();
|
|
uint32 area = m_target->GetAreaId();
|
|
|
|
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
|
|
if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
|
|
m_target->RemoveAurasDueToSpell(itr->second->spellId);
|
|
}
|
|
}
|
|
}
|
|
|
|
// AT APPLY & REMOVE
|
|
|
|
switch(m_spellProto->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
// Unstable Power
|
|
if( GetId()==24658 )
|
|
{
|
|
uint32 spellId = 24659;
|
|
if (apply)
|
|
{
|
|
const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
|
|
if (!spell)
|
|
return;
|
|
for (int i=0; i < spell->StackAmount; ++i)
|
|
caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
|
|
return;
|
|
}
|
|
m_target->RemoveAurasDueToSpell(spellId);
|
|
return;
|
|
}
|
|
// Restless Strength
|
|
if( GetId()==24661 )
|
|
{
|
|
uint32 spellId = 24662;
|
|
if (apply)
|
|
{
|
|
const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
|
|
if (!spell)
|
|
return;
|
|
for (int i=0; i < spell->StackAmount; ++i)
|
|
caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
|
|
return;
|
|
}
|
|
m_target->RemoveAurasDueToSpell(spellId);
|
|
return;
|
|
}
|
|
//Summon Fire Elemental
|
|
if (GetId() == 40133 && caster)
|
|
{
|
|
Unit *owner = caster->GetOwner();
|
|
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if(apply)
|
|
owner->CastSpell(owner,8985,true);
|
|
else
|
|
((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//Summon Earth Elemental
|
|
if (GetId() == 40132 && caster)
|
|
{
|
|
Unit *owner = caster->GetOwner();
|
|
if (owner && owner->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if(apply)
|
|
owner->CastSpell(owner,19704,true);
|
|
else
|
|
((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_MAGE:
|
|
{
|
|
break;
|
|
}
|
|
case SPELLFAMILY_PRIEST:
|
|
{
|
|
// Pain and Suffering
|
|
if( m_spellProto->SpellIconID == 2874 && m_target->GetTypeId()==TYPEID_PLAYER )
|
|
{
|
|
if(apply)
|
|
{
|
|
// Reduce backfire damage (dot damage) from Shadow Word: Death
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->op = SPELLMOD_DOT;
|
|
mod->value = m_modifier.m_amount;
|
|
mod->type = SPELLMOD_PCT;
|
|
mod->spellId = GetId();
|
|
mod->mask = 0x0000000200000000LL;
|
|
mod->mask2= 0LL;
|
|
m_spellmod = mod;
|
|
}
|
|
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DRUID:
|
|
{
|
|
// Lifebloom
|
|
if ( GetSpellProto()->SpellFamilyFlags & 0x1000000000LL )
|
|
{
|
|
if ( apply )
|
|
{
|
|
if ( caster )
|
|
// prevent double apply bonuses
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
|
|
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
|
|
}
|
|
else
|
|
{
|
|
// Final heal only on dispelled or duration end
|
|
if ( !(GetAuraDuration() <= 0 || m_removeMode==AURA_REMOVE_BY_DISPEL) )
|
|
return;
|
|
|
|
// have a look if there is still some other Lifebloom dummy aura
|
|
Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
|
|
for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); ++itr)
|
|
if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
|
|
(*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL)
|
|
return;
|
|
|
|
// final heal
|
|
if(m_target->IsInWorld() && m_stackAmount > 0)
|
|
{
|
|
int32 amount = m_modifier.m_amount / m_stackAmount;
|
|
m_target->CastCustomSpell(m_target,33778,&amount,NULL,NULL,true,NULL,this,GetCasterGUID());
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Predatory Strikes
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563)
|
|
{
|
|
((Player*)m_target)->UpdateAttackPowerAndDamage();
|
|
return;
|
|
}
|
|
// Idol of the Emerald Queen
|
|
if ( GetId() == 34246 && m_target->GetTypeId()==TYPEID_PLAYER )
|
|
{
|
|
if(apply)
|
|
{
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->op = SPELLMOD_DOT;
|
|
mod->value = m_modifier.m_amount/7;
|
|
mod->type = SPELLMOD_FLAT;
|
|
mod->spellId = GetId();
|
|
mod->mask = 0x001000000000LL;
|
|
mod->mask2= 0LL;
|
|
|
|
m_spellmod = mod;
|
|
}
|
|
|
|
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
// Improved Aspect of the Viper
|
|
if( GetId()==38390 && m_target->GetTypeId()==TYPEID_PLAYER )
|
|
{
|
|
if(apply)
|
|
{
|
|
// + effect value for Aspect of the Viper
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->op = SPELLMOD_EFFECT1;
|
|
mod->value = m_modifier.m_amount;
|
|
mod->type = SPELLMOD_FLAT;
|
|
mod->spellId = GetId();
|
|
mod->mask = 0x4000000000000LL;
|
|
mod->mask2= 0LL;
|
|
|
|
m_spellmod = mod;
|
|
}
|
|
|
|
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_SHAMAN:
|
|
{
|
|
// Improved Weapon Totems
|
|
if( GetSpellProto()->SpellIconID == 57 && m_target->GetTypeId()==TYPEID_PLAYER )
|
|
{
|
|
if(apply)
|
|
{
|
|
SpellModifier *mod = new SpellModifier;
|
|
mod->op = SPELLMOD_EFFECT1;
|
|
mod->value = m_modifier.m_amount;
|
|
mod->type = SPELLMOD_PCT;
|
|
mod->spellId = GetId();
|
|
switch (m_effIndex)
|
|
{
|
|
case 0:
|
|
mod->mask = 0x00200000000LL; // Windfury Totem
|
|
mod->mask2= 0LL;
|
|
break;
|
|
case 1:
|
|
mod->mask = 0x00400000000LL; // Flametongue Totem
|
|
mod->mask2= 0LL;
|
|
break;
|
|
}
|
|
|
|
m_spellmod = mod;
|
|
}
|
|
|
|
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// pet auras
|
|
if(PetAura const* petSpell = spellmgr.GetPetAura(GetId()))
|
|
{
|
|
if(apply)
|
|
m_target->AddPetAura(petSpell);
|
|
else
|
|
m_target->RemovePetAura(petSpell);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraMounted(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
if(apply)
|
|
{
|
|
CreatureInfo const* ci = objmgr.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 team = 0;
|
|
if (m_target->GetTypeId()==TYPEID_PLAYER)
|
|
team = ((Player*)m_target)->GetTeam();
|
|
|
|
uint32 display_id = objmgr.ChooseDisplayId(team,ci);
|
|
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
|
|
if (minfo)
|
|
display_id = minfo->modelid;
|
|
|
|
m_target->Mount(display_id);
|
|
}
|
|
else
|
|
{
|
|
m_target->Unmount();
|
|
}
|
|
}
|
|
|
|
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.append(m_target->GetPackGUID());
|
|
data << uint32(0);
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
|
|
void Aura::HandleAuraFeatherFall(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
WorldPacket data;
|
|
if(apply)
|
|
data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4);
|
|
else
|
|
data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4);
|
|
data.append(m_target->GetPackGUID());
|
|
data << (uint32)0;
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
|
|
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.append(m_target->GetPackGUID());
|
|
data << uint32(0);
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
|
|
void Aura::HandleWaterBreathing(bool apply, bool Real)
|
|
{
|
|
if(!apply && !m_target->HasAuraType(SPELL_AURA_WATER_BREATHING))
|
|
{
|
|
// update for enable timer in case not moving target
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER && m_target->IsInWorld())
|
|
{
|
|
((Player*)m_target)->UpdateUnderwaterState(m_target->GetMap(),m_target->GetPositionX(),m_target->GetPositionY(),m_target->GetPositionZ());
|
|
((Player*)m_target)->HandleDrowning();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModShapeshift(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
uint32 modelid = 0;
|
|
Powers PowerType = POWER_MANA;
|
|
ShapeshiftForm form = ShapeshiftForm(m_modifier.m_miscvalue);
|
|
switch(form)
|
|
{
|
|
case FORM_CAT:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 892;
|
|
else
|
|
modelid = 8571;
|
|
PowerType = POWER_ENERGY;
|
|
break;
|
|
case FORM_TRAVEL:
|
|
modelid = 632;
|
|
break;
|
|
case FORM_AQUA:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 2428;
|
|
else
|
|
modelid = 2428;
|
|
break;
|
|
case FORM_BEAR:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 2281;
|
|
else
|
|
modelid = 2289;
|
|
PowerType = POWER_RAGE;
|
|
break;
|
|
case FORM_GHOUL:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 10045;
|
|
break;
|
|
case FORM_DIREBEAR:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 2281;
|
|
else
|
|
modelid = 2289;
|
|
PowerType = POWER_RAGE;
|
|
break;
|
|
case FORM_CREATUREBEAR:
|
|
modelid = 902;
|
|
break;
|
|
case FORM_GHOSTWOLF:
|
|
modelid = 4613;
|
|
break;
|
|
case FORM_FLIGHT:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 20857;
|
|
else
|
|
modelid = 20872;
|
|
break;
|
|
case FORM_MOONKIN:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 15374;
|
|
else
|
|
modelid = 15375;
|
|
break;
|
|
case FORM_FLIGHT_EPIC:
|
|
if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
|
|
modelid = 21243;
|
|
else
|
|
modelid = 21244;
|
|
break;
|
|
case FORM_METAMORPHOSIS:
|
|
modelid = 25277;
|
|
break;
|
|
case FORM_AMBIENT:
|
|
case FORM_SHADOW:
|
|
case FORM_STEALTH:
|
|
break;
|
|
case FORM_TREE:
|
|
modelid = 864;
|
|
break;
|
|
case FORM_BATTLESTANCE:
|
|
case FORM_BERSERKERSTANCE:
|
|
case FORM_DEFENSIVESTANCE:
|
|
PowerType = POWER_RAGE;
|
|
break;
|
|
case FORM_SPIRITOFREDEMPTION:
|
|
modelid = 16031;
|
|
break;
|
|
default:
|
|
sLog.outError("Auras: Unknown Shapeshift Type: %u", m_modifier.m_miscvalue);
|
|
}
|
|
|
|
// 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
|
|
m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
|
|
m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
|
|
|
|
// and polymorphic affects
|
|
if(m_target->IsPolymorphed())
|
|
m_target->RemoveAurasDueToSpell(m_target->getTransForm());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(apply)
|
|
{
|
|
// remove other shapeshift before applying a new one
|
|
if(m_target->m_ShapeShiftFormSpellId)
|
|
m_target->RemoveAurasDueToSpell(m_target->m_ShapeShiftFormSpellId,this);
|
|
|
|
m_target->SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
|
|
|
|
if(modelid > 0)
|
|
m_target->SetDisplayId(modelid);
|
|
|
|
if(PowerType != POWER_MANA)
|
|
{
|
|
// reset power to default values only at power change
|
|
if(m_target->getPowerType()!=PowerType)
|
|
m_target->setPowerType(PowerType);
|
|
|
|
switch(form)
|
|
{
|
|
case FORM_CAT:
|
|
case FORM_BEAR:
|
|
case FORM_DIREBEAR:
|
|
{
|
|
// get furor proc chance
|
|
uint32 FurorChance = 0;
|
|
Unit::AuraList const& mDummy = m_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)
|
|
{
|
|
m_target->SetPower(POWER_ENERGY,0);
|
|
if(urand(1,100) <= FurorChance)
|
|
m_target->CastSpell(m_target,17099,true,NULL,this);
|
|
}
|
|
else
|
|
{
|
|
m_target->SetPower(POWER_RAGE,0);
|
|
if(urand(1,100) <= FurorChance)
|
|
m_target->CastSpell(m_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(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
PlayerSpellMap const& sp_list = ((Player *)m_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 += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10;
|
|
}
|
|
}
|
|
|
|
if (m_target->GetPower(POWER_RAGE) > Rage_val)
|
|
m_target->SetPower(POWER_RAGE,Rage_val);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_target->m_ShapeShiftFormSpellId = GetId();
|
|
m_target->m_form = form;
|
|
}
|
|
else
|
|
{
|
|
if(modelid > 0)
|
|
m_target->SetDisplayId(m_target->GetNativeDisplayId());
|
|
m_target->SetByteValue(UNIT_FIELD_BYTES_2, 3, FORM_NONE);
|
|
if(m_target->getClass() == CLASS_DRUID)
|
|
m_target->setPowerType(POWER_MANA);
|
|
m_target->m_ShapeShiftFormSpellId = 0;
|
|
m_target->m_form = FORM_NONE;
|
|
|
|
switch(form)
|
|
{
|
|
// Nordrassil Harness - bonus
|
|
case FORM_BEAR:
|
|
case FORM_DIREBEAR:
|
|
case FORM_CAT:
|
|
{
|
|
if(Aura* dummy = m_target->GetDummyAura(37315) )
|
|
m_target->CastSpell(m_target,37316,true,NULL,dummy);
|
|
break;
|
|
}
|
|
// Nordrassil Regalia - bonus
|
|
case FORM_MOONKIN:
|
|
{
|
|
if(Aura* dummy = m_target->GetDummyAura(37324) )
|
|
m_target->CastSpell(m_target,37325,true,NULL,dummy);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// adding/removing linked auras
|
|
// add/remove the shapeshift aura's boosts
|
|
HandleShapeshiftBoosts(apply);
|
|
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
((Player*)m_target)->InitDataForForm();
|
|
}
|
|
|
|
void Aura::HandleAuraTransform(bool apply, bool Real)
|
|
{
|
|
if (apply)
|
|
{
|
|
// special case (spell specific functionality)
|
|
if(m_modifier.m_miscvalue==0)
|
|
{
|
|
// player applied only
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
switch(GetId())
|
|
{
|
|
// Orb of Deception
|
|
case 16739:
|
|
{
|
|
uint32 orb_model = m_target->GetNativeDisplayId();
|
|
switch(orb_model)
|
|
{
|
|
// Troll Female
|
|
case 1479: m_target->SetDisplayId(10134); break;
|
|
// Troll Male
|
|
case 1478: m_target->SetDisplayId(10135); break;
|
|
// Tauren Male
|
|
case 59: m_target->SetDisplayId(10136); break;
|
|
// Human Male
|
|
case 49: m_target->SetDisplayId(10137); break;
|
|
// Human Female
|
|
case 50: m_target->SetDisplayId(10138); break;
|
|
// Orc Male
|
|
case 51: m_target->SetDisplayId(10139); break;
|
|
// Orc Female
|
|
case 52: m_target->SetDisplayId(10140); break;
|
|
// Dwarf Male
|
|
case 53: m_target->SetDisplayId(10141); break;
|
|
// Dwarf Female
|
|
case 54: m_target->SetDisplayId(10142); break;
|
|
// NightElf Male
|
|
case 55: m_target->SetDisplayId(10143); break;
|
|
// NightElf Female
|
|
case 56: m_target->SetDisplayId(10144); break;
|
|
// Undead Female
|
|
case 58: m_target->SetDisplayId(10145); break;
|
|
// Undead Male
|
|
case 57: m_target->SetDisplayId(10146); break;
|
|
// Tauren Female
|
|
case 60: m_target->SetDisplayId(10147); break;
|
|
// Gnome Male
|
|
case 1563: m_target->SetDisplayId(10148); break;
|
|
// Gnome Female
|
|
case 1564: m_target->SetDisplayId(10149); break;
|
|
// BloodElf Female
|
|
case 15475: m_target->SetDisplayId(17830); break;
|
|
// BloodElf Male
|
|
case 15476: m_target->SetDisplayId(17829); break;
|
|
// Dranei Female
|
|
case 16126: m_target->SetDisplayId(17828); break;
|
|
// Dranei Male
|
|
case 16125: m_target->SetDisplayId(17827); break;
|
|
default: break;
|
|
}
|
|
break;
|
|
}
|
|
// Murloc costume
|
|
case 42365: m_target->SetDisplayId(21723); break;
|
|
default: break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CreatureInfo const * ci = objmgr.GetCreatureTemplate(m_modifier.m_miscvalue);
|
|
if(!ci)
|
|
{
|
|
//pig pink ^_^
|
|
m_target->SetDisplayId(16358);
|
|
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
|
|
{
|
|
// Will use the default model here
|
|
m_target->SetDisplayId(ci->DisplayID_A);
|
|
|
|
// Dragonmaw Illusion (set mount model also)
|
|
if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED).empty())
|
|
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
|
|
}
|
|
m_target->setTransForm(GetId());
|
|
}
|
|
|
|
// polymorph case
|
|
if( Real && m_target->GetTypeId() == TYPEID_PLAYER && m_target->IsPolymorphed())
|
|
{
|
|
// for players, start regeneration after 1s (in polymorph fast regeneration case)
|
|
// only if caster is Player (after patch 2.4.2)
|
|
if(IS_PLAYER_GUID(GetCasterGUID()) )
|
|
((Player*)m_target)->setRegenTimer(1*IN_MILISECONDS);
|
|
|
|
//dismount polymorphed target (after patch 2.4.2)
|
|
if (m_target->IsMounted())
|
|
m_target->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Unit::AuraList const& otherTransforms = m_target->GetAurasByType(SPELL_AURA_TRANSFORM);
|
|
if(otherTransforms.empty())
|
|
{
|
|
m_target->SetDisplayId(m_target->GetNativeDisplayId());
|
|
m_target->setTransForm(0);
|
|
}
|
|
else
|
|
{
|
|
// 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 && m_target->GetMountID()==16314)
|
|
{
|
|
if(!m_target->GetAurasByType(SPELL_AURA_MOUNTED).empty())
|
|
{
|
|
uint32 cr_id = m_target->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetModifier()->m_miscvalue;
|
|
if(CreatureInfo const* ci = objmgr.GetCreatureTemplate(cr_id))
|
|
{
|
|
uint32 team = 0;
|
|
if (m_target->GetTypeId()==TYPEID_PLAYER)
|
|
team = ((Player*)m_target)->GetTeam();
|
|
|
|
uint32 display_id = objmgr.ChooseDisplayId(team,ci);
|
|
CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
|
|
if (minfo)
|
|
display_id = minfo->modelid;
|
|
|
|
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,display_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleForceReaction(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(!Real)
|
|
return;
|
|
|
|
Player* player = (Player*)m_target;
|
|
|
|
uint32 faction_id = m_modifier.m_miscvalue;
|
|
uint32 faction_rank = m_modifier.m_amount;
|
|
|
|
if(apply)
|
|
player->m_forcedReactions[faction_id] = ReputationRank(faction_rank);
|
|
else
|
|
player->m_forcedReactions.erase(faction_id);
|
|
|
|
WorldPacket data;
|
|
data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+player->m_forcedReactions.size()*(4+4));
|
|
data << uint32(player->m_forcedReactions.size());
|
|
for(ForcedReactions::const_iterator itr = player->m_forcedReactions.begin(); itr != player->m_forcedReactions.end(); ++itr)
|
|
{
|
|
data << uint32(itr->first); // faction_id (Faction.dbc)
|
|
data << uint32(itr->second); // reputation rank
|
|
}
|
|
player->SendDirectMessage(&data);
|
|
}
|
|
|
|
void Aura::HandleAuraModSkill(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
uint32 prot=GetSpellProto()->EffectMiscValue[m_effIndex];
|
|
int32 points = GetModifier()->m_amount;
|
|
|
|
((Player*)m_target)->ModifySkillBonus(prot,(apply ? points: -points),m_modifier.m_auraname==SPELL_AURA_MOD_SKILL_TALENT);
|
|
if(prot == SKILL_DEFENSE)
|
|
((Player*)m_target)->UpdateDefenseBonusesMod();
|
|
}
|
|
|
|
void Aura::HandleChannelDeathItem(bool apply, bool Real)
|
|
{
|
|
if(Real && !apply)
|
|
{
|
|
Unit* caster = GetCaster();
|
|
Unit* victim = GetTarget();
|
|
if(!caster || caster->GetTypeId() != TYPEID_PLAYER || !victim || 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;
|
|
|
|
// Soul Shard only from non-grey units
|
|
if( spellInfo->EffectItemType[m_effIndex] == 6265 &&
|
|
(victim->getLevel() <= MaNGOS::XP::GetGrayLevel(caster->getLevel()) ||
|
|
victim->GetTypeId()==TYPEID_UNIT && !((Player*)caster)->isAllowedToLoot((Creature*)victim)) )
|
|
return;
|
|
//Adding items
|
|
uint32 noSpaceForCount = 0;
|
|
uint32 count = m_modifier.m_amount;
|
|
|
|
ItemPosCountVec dest;
|
|
uint8 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 );
|
|
if (count==0)
|
|
return;
|
|
}
|
|
|
|
Item* newitem = ((Player*)caster)->StoreNewItem(dest, spellInfo->EffectItemType[m_effIndex], true);
|
|
((Player*)caster)->SendNewItem(newitem, count, true, false);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleBindSight(bool apply, bool Real)
|
|
{
|
|
Unit* caster = GetCaster();
|
|
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)caster)->SetFarSightGUID(apply ? m_target->GetGUID() : 0);
|
|
}
|
|
|
|
void Aura::HandleFarSight(bool apply, bool Real)
|
|
{
|
|
Unit* caster = GetCaster();
|
|
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)caster)->SetFarSightGUID(apply ? m_target->GetGUID() : 0);
|
|
}
|
|
|
|
void Aura::HandleAuraTrackCreatures(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
m_target->RemoveNoStackAurasDueToAura(this);
|
|
m_target->SetUInt32Value(PLAYER_TRACK_CREATURES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1) : 0 );
|
|
}
|
|
|
|
void Aura::HandleAuraTrackResources(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
m_target->RemoveNoStackAurasDueToAura(this);
|
|
m_target->SetUInt32Value(PLAYER_TRACK_RESOURCES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1): 0 );
|
|
}
|
|
|
|
void Aura::HandleAuraTrackStealthed(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
m_target->RemoveNoStackAurasDueToAura(this);
|
|
|
|
m_target->ApplyModFlag(PLAYER_FIELD_BYTES,PLAYER_FIELD_BYTE_TRACK_STEALTHED,apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModScale(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_modifier.m_amount,apply);
|
|
}
|
|
|
|
void Aura::HandleModPossess(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(m_target->getLevel() > m_modifier.m_amount)
|
|
return;
|
|
|
|
// not possess yourself
|
|
if(GetCasterGUID() == m_target->GetGUID())
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
if(!caster)
|
|
return;
|
|
|
|
if( apply )
|
|
{
|
|
m_target->SetCharmerGUID(GetCasterGUID());
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
|
|
caster->SetCharm(m_target);
|
|
|
|
m_target->CombatStop();
|
|
m_target->DeleteThreatList();
|
|
if(m_target->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
m_target->StopMoving();
|
|
m_target->GetMotionMaster()->Clear();
|
|
m_target->GetMotionMaster()->MoveIdle();
|
|
CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
|
|
charmInfo->InitPossessCreateSpells();
|
|
}
|
|
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
((Player*)caster)->PossessSpellInitialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_target->SetCharmerGUID(0);
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)m_target)->setFactionForRace(m_target->getRace());
|
|
else if(m_target->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
|
}
|
|
|
|
caster->SetCharm(0);
|
|
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
WorldPacket data(SMSG_PET_SPELLS, 8);
|
|
data << uint64(0);
|
|
data << uint32(0);
|
|
((Player*)caster)->GetSession()->SendPacket(&data);
|
|
}
|
|
if(m_target->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
((Creature*)m_target)->AIM_Initialize();
|
|
|
|
if (((Creature*)m_target)->AI())
|
|
((Creature*)m_target)->AI()->AttackStart(caster);
|
|
}
|
|
}
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)caster)->SetFarSightGUID(apply ? m_target->GetGUID() : 0);
|
|
}
|
|
|
|
void Aura::HandleModPossessPet(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Pet *pet = caster->GetPet();
|
|
if(!pet || pet != m_target)
|
|
return;
|
|
|
|
if(apply)
|
|
pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
|
|
else
|
|
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24);
|
|
|
|
((Player*)caster)->SetFarSightGUID(apply ? pet->GetGUID() : NULL);
|
|
((Player*)caster)->SetCharm(apply ? pet : NULL);
|
|
((Player*)caster)->SetClientControl(pet, apply ? 1 : 0);
|
|
|
|
if(apply)
|
|
{
|
|
pet->StopMoving();
|
|
pet->GetMotionMaster()->Clear();
|
|
pet->GetMotionMaster()->MoveIdle();
|
|
}
|
|
else
|
|
{
|
|
pet->AttackStop();
|
|
pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
|
pet->SetUnitMovementFlags(MOVEMENTFLAG_NONE);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModPetTalentsPoints(bool Apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
// Recalculate pet tlaent points
|
|
if (Pet *pet=m_target->GetPet())
|
|
pet->InitTalentForLevel();
|
|
}
|
|
|
|
void Aura::HandleModCharm(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
// not charm yourself
|
|
if(GetCasterGUID() == m_target->GetGUID())
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
if(!caster)
|
|
return;
|
|
|
|
if(int32(m_target->getLevel()) <= m_modifier.m_amount)
|
|
{
|
|
if( apply )
|
|
{
|
|
m_target->SetCharmerGUID(GetCasterGUID());
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
|
|
m_target->CastStop(m_target==caster ? GetId() : 0);
|
|
caster->SetCharm(m_target);
|
|
|
|
m_target->CombatStop();
|
|
m_target->DeleteThreatList();
|
|
|
|
if(m_target->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
((Creature*)m_target)->AIM_Initialize();
|
|
CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
|
|
charmInfo->InitCharmCreateSpells();
|
|
charmInfo->SetReactState( REACT_DEFENSIVE );
|
|
|
|
if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
|
|
{
|
|
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
|
if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
|
|
{
|
|
//to prevent client crash
|
|
m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
|
|
//just to enable stat window
|
|
charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
|
|
//if charmed two demons the same session, the 2nd gets the 1st one's name
|
|
m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
|
|
}
|
|
}
|
|
}
|
|
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
((Player*)caster)->CharmSpellInitialize();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_target->SetCharmerGUID(0);
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)m_target)->setFactionForRace(m_target->getRace());
|
|
else
|
|
{
|
|
CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
|
|
|
|
// restore faction
|
|
if(((Creature*)m_target)->isPet())
|
|
{
|
|
if(Unit* owner = m_target->GetOwner())
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
|
|
else if(cinfo)
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
|
}
|
|
else if(cinfo) // normal creature
|
|
m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
|
|
|
|
// restore UNIT_FIELD_BYTES_0
|
|
if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
|
|
{
|
|
CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
|
|
if(cainfo && cainfo->bytes0 != 0)
|
|
m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
|
|
else
|
|
m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
|
|
|
|
if(m_target->GetCharmInfo())
|
|
m_target->GetCharmInfo()->SetPetNumber(0, true);
|
|
else
|
|
sLog.outError("Aura::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", m_target->GetGUID(), m_target->GetTypeId());
|
|
}
|
|
}
|
|
|
|
caster->SetCharm(0);
|
|
|
|
if(caster->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
WorldPacket data(SMSG_PET_SPELLS, 8);
|
|
data << uint64(0);
|
|
data << uint32(0);
|
|
((Player*)caster)->GetSession()->SendPacket(&data);
|
|
}
|
|
if(m_target->GetTypeId() == TYPEID_UNIT)
|
|
{
|
|
((Creature*)m_target)->AIM_Initialize();
|
|
if (((Creature*)m_target)->AI())
|
|
((Creature*)m_target)->AI()->AttackStart(caster);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModConfuse(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->SetConfused(apply, GetCasterGUID(), GetId());
|
|
}
|
|
|
|
void Aura::HandleModFear(bool apply, bool Real)
|
|
{
|
|
if (!Real)
|
|
return;
|
|
|
|
m_target->SetFeared(apply, GetCasterGUID(), GetId());
|
|
}
|
|
|
|
void Aura::HandleFeignDeath(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if( apply )
|
|
{
|
|
/*
|
|
WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9);
|
|
data<<m_target->GetGUID();
|
|
data<<uint8(0);
|
|
m_target->SendMessageToSet(&data,true);
|
|
*/
|
|
// blizz like 2.0.x
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
|
|
// blizz like 2.0.x
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
|
|
// blizz like 2.0.x
|
|
m_target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
|
|
|
|
m_target->addUnitState(UNIT_STAT_DIED);
|
|
m_target->CombatStop();
|
|
|
|
// prevent interrupt message
|
|
if(m_caster_guid==m_target->GetGUID() && m_target->m_currentSpells[CURRENT_GENERIC_SPELL])
|
|
m_target->m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
|
|
m_target->InterruptNonMeleeSpells(true);
|
|
m_target->getHostilRefManager().deleteReferences();
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9);
|
|
data<<m_target->GetGUID();
|
|
data<<uint8(1);
|
|
m_target->SendMessageToSet(&data,true);
|
|
*/
|
|
// blizz like 2.0.x
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29);
|
|
// blizz like 2.0.x
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
|
|
// blizz like 2.0.x
|
|
m_target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
|
|
|
|
m_target->clearUnitState(UNIT_STAT_DIED);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModDisarm(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(!apply && m_target->HasAuraType(SPELL_AURA_MOD_DISARM))
|
|
return;
|
|
|
|
// not sure for it's correctness
|
|
if(apply)
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED);
|
|
else
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED);
|
|
|
|
// only at real add/remove aura
|
|
if (m_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 (((Player *)m_target)->IsInFeralForm())
|
|
return;
|
|
|
|
if (apply)
|
|
m_target->SetAttackTime(BASE_ATTACK,BASE_ATTACK_TIME);
|
|
else
|
|
((Player *)m_target)->SetRegularAttackTime();
|
|
|
|
m_target->UpdateDamagePhysical(BASE_ATTACK);
|
|
}
|
|
|
|
void Aura::HandleAuraModStun(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if (apply)
|
|
{
|
|
// Frost stun aura -> freeze/unfreeze target
|
|
if (GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
|
|
m_target->ModifyAuraState(AURA_STATE_FROZEN, apply);
|
|
|
|
m_target->addUnitState(UNIT_STAT_STUNNED);
|
|
m_target->SetUInt64Value(UNIT_FIELD_TARGET, 0);
|
|
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
|
m_target->CastStop(m_target->GetGUID() == GetCasterGUID() ? GetId() : 0);
|
|
|
|
// Creature specific
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
((Creature*)m_target)->StopMoving();
|
|
else
|
|
m_target->SetUnitMovementFlags(0); //Clear movement flags
|
|
|
|
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8);
|
|
|
|
data.append(m_target->GetPackGUID());
|
|
data << uint32(0);
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
else
|
|
{
|
|
// Frost stun aura -> freeze/unfreeze target
|
|
if (GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
|
|
{
|
|
bool found_another = false;
|
|
for(AuraType const* itr = &frozenAuraTypes[0]; *itr != SPELL_AURA_NONE; ++itr)
|
|
{
|
|
Unit::AuraList const& auras = m_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)
|
|
m_target->ModifyAuraState(AURA_STATE_FROZEN, apply);
|
|
}
|
|
|
|
// Real remove called after current aura remove from lists, check if other similar auras active
|
|
if(m_target->HasAuraType(SPELL_AURA_MOD_STUN))
|
|
return;
|
|
|
|
m_target->clearUnitState(UNIT_STAT_STUNNED);
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
|
|
|
if(!m_target->hasUnitState(UNIT_STAT_ROOT)) // prevent allow move if have also root effect
|
|
{
|
|
if(m_target->getVictim() && m_target->isAlive())
|
|
m_target->SetUInt64Value(UNIT_FIELD_TARGET,m_target->getVictim()->GetGUID() );
|
|
|
|
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 8+4);
|
|
data.append(m_target->GetPackGUID());
|
|
data << uint32(0);
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
|
|
// Wyvern Sting
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellProto->SpellFamilyFlags & 0x0000100000000000LL)
|
|
{
|
|
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(m_target,spellInfo,true,NULL,this);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModStealth(bool apply, bool Real)
|
|
{
|
|
if(apply)
|
|
{
|
|
// drop flag at stealth in bg
|
|
if(Real && m_target->GetTypeId()==TYPEID_PLAYER && ((Player*)m_target)->InBattleGround())
|
|
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
|
|
bg->EventPlayerDroppedFlag((Player*)m_target);
|
|
|
|
// only at real aura add
|
|
if(Real)
|
|
{
|
|
m_target->SetStandFlags(UNIT_STAND_FLAGS_CREEP);
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
m_target->SetFlag(PLAYER_FIELD_BYTES2, 0x2000);
|
|
|
|
// apply only if not in GM invisibility (and overwrite invisibility state)
|
|
if(m_target->GetVisibility()!=VISIBILITY_OFF)
|
|
{
|
|
m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
|
|
m_target->SetVisibility(VISIBILITY_GROUP_STEALTH);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// only at real aura remove
|
|
if(Real)
|
|
{
|
|
// if last SPELL_AURA_MOD_STEALTH and no GM invisibility
|
|
if(!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH) && m_target->GetVisibility()!=VISIBILITY_OFF)
|
|
{
|
|
m_target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP);
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
m_target->RemoveFlag(PLAYER_FIELD_BYTES2, 0x2000);
|
|
|
|
// restore invisibility if any
|
|
if(m_target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY))
|
|
{
|
|
m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
|
|
m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
|
|
}
|
|
else
|
|
m_target->SetVisibility(VISIBILITY_ON);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Master of Subtlety
|
|
Unit::AuraList const& mDummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
|
|
for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
|
|
{
|
|
if ((*i)->GetSpellProto()->SpellIconID == 2114)
|
|
{
|
|
if (apply)
|
|
{
|
|
int32 bp = (*i)->GetModifier()->m_amount;
|
|
m_target->CastCustomSpell(m_target,31665,&bp,NULL,NULL,true);
|
|
}
|
|
else
|
|
m_target->CastSpell(m_target,31666,true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleInvisibility(bool apply, bool Real)
|
|
{
|
|
if(apply)
|
|
{
|
|
m_target->m_invisibilityMask |= (1 << m_modifier.m_miscvalue);
|
|
|
|
if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
// apply glow vision
|
|
m_target->SetFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
|
|
|
|
// drop flag at invisible in bg
|
|
if(((Player*)m_target)->InBattleGround())
|
|
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
|
|
bg->EventPlayerDroppedFlag((Player*)m_target);
|
|
}
|
|
|
|
// apply only if not in GM invisibility and not stealth
|
|
if(m_target->GetVisibility()==VISIBILITY_ON)
|
|
{
|
|
// Aura not added yet but visibility code expect temporary add aura
|
|
m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT);
|
|
m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// recalculate value at modifier remove (current aura already removed)
|
|
m_target->m_invisibilityMask = 0;
|
|
Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
|
|
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
m_target->m_invisibilityMask |= (1 << m_modifier.m_miscvalue);
|
|
|
|
// only at real aura remove and if not have different invisibility auras.
|
|
if(Real && m_target->m_invisibilityMask==0)
|
|
{
|
|
// remove glow vision
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
m_target->RemoveFlag(PLAYER_FIELD_BYTES2,PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW);
|
|
|
|
// apply only if not in GM invisibility & not stealthed while invisible
|
|
if(m_target->GetVisibility()!=VISIBILITY_OFF)
|
|
{
|
|
// if have stealth aura then already have stealth visibility
|
|
if(!m_target->HasAuraType(SPELL_AURA_MOD_STEALTH))
|
|
m_target->SetVisibility(VISIBILITY_ON);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleInvisibilityDetect(bool apply, bool Real)
|
|
{
|
|
if(apply)
|
|
{
|
|
m_target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue);
|
|
}
|
|
else
|
|
{
|
|
// recalculate value at modifier remove (current aura already removed)
|
|
m_target->m_detectInvisibilityMask = 0;
|
|
Unit::AuraList const& auras = m_target->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION);
|
|
for(Unit::AuraList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
|
m_target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue);
|
|
}
|
|
if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
ObjectAccessor::UpdateVisibilityForPlayer((Player*)m_target);
|
|
}
|
|
|
|
void Aura::HandleAuraModRoot(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
uint32 apply_stat = UNIT_STAT_ROOT;
|
|
if (apply)
|
|
{
|
|
// Frost root aura -> freeze/unfreeze target
|
|
if (GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
|
|
m_target->ModifyAuraState(AURA_STATE_FROZEN, apply);
|
|
|
|
m_target->addUnitState(UNIT_STAT_ROOT);
|
|
m_target->SetUInt64Value (UNIT_FIELD_TARGET, 0);
|
|
// probably wrong (this add skinable flag)
|
|
// TODO: find correct flag
|
|
// m_target->SetFlag(UNIT_FIELD_FLAGS,(apply_stat<<16));
|
|
|
|
//Save last orientation
|
|
if( m_target->getVictim() )
|
|
m_target->SetOrientation(m_target->GetAngle(m_target->getVictim()));
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
|
|
data.append(m_target->GetPackGUID());
|
|
data << (uint32)2;
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
//Clear unit movement flags
|
|
m_target->SetUnitMovementFlags(0);
|
|
}
|
|
else
|
|
((Creature *)m_target)->StopMoving();
|
|
}
|
|
else
|
|
{
|
|
// Frost root aura -> freeze/unfreeze target
|
|
if (GetSpellSchoolMask(m_spellProto) & SPELL_SCHOOL_MASK_FROST)
|
|
{
|
|
bool found_another = false;
|
|
for(AuraType const* itr = &frozenAuraTypes[0]; *itr != SPELL_AURA_NONE; ++itr)
|
|
{
|
|
Unit::AuraList const& auras = m_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)
|
|
m_target->ModifyAuraState(AURA_STATE_FROZEN, apply);
|
|
}
|
|
|
|
// Real remove called after current aura remove from lists, check if other similar auras active
|
|
if(m_target->HasAuraType(SPELL_AURA_MOD_ROOT))
|
|
return;
|
|
|
|
m_target->clearUnitState(UNIT_STAT_ROOT);
|
|
// probably wrong (this add skinable flag)
|
|
// TODO: find correct flag
|
|
// m_target->RemoveFlag(UNIT_FIELD_FLAGS,(apply_stat<<16));
|
|
|
|
if(!m_target->hasUnitState(UNIT_STAT_STUNNED)) // prevent allow move if have also stun effect
|
|
{
|
|
if(m_target->getVictim() && m_target->isAlive())
|
|
m_target->SetUInt64Value (UNIT_FIELD_TARGET,m_target->getVictim()->GetGUID() );
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
WorldPacket data(SMSG_FORCE_MOVE_UNROOT, 10);
|
|
data.append(m_target->GetPackGUID());
|
|
data << (uint32)2;
|
|
m_target->SendMessageToSet(&data,true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModSilence(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
if(apply)
|
|
{
|
|
m_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++)
|
|
{
|
|
Spell* currentSpell = m_target->m_currentSpells[i];
|
|
if (currentSpell && currentSpell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
|
|
{
|
|
uint32 state = currentSpell->getState();
|
|
// Stop spells on prepare or casting state
|
|
if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING )
|
|
{
|
|
currentSpell->cancel();
|
|
currentSpell->SetReferencedFromCurrent(false);
|
|
m_target->m_currentSpells[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (GetId())
|
|
{
|
|
// Arcane Torrent (Energy)
|
|
case 25046:
|
|
{
|
|
Unit * caster = GetCaster();
|
|
if (!caster)
|
|
return;
|
|
|
|
// Search Mana Tap auras on caster
|
|
Aura * dummy = caster->GetDummyAura(28734);
|
|
if (dummy)
|
|
{
|
|
int32 bp = dummy->GetStackAmount() * 10;
|
|
caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true);
|
|
caster->RemoveAurasDueToSpell(28734);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Real remove called after current aura remove from lists, check if other similar auras active
|
|
if(m_target->HasAuraType(SPELL_AURA_MOD_SILENCE))
|
|
return;
|
|
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModThreat(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
if(!m_target->isAlive())
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
|
|
if(!caster || !caster->isAlive())
|
|
return;
|
|
|
|
int level_diff = 0;
|
|
int multiplier = 0;
|
|
switch (GetId())
|
|
{
|
|
// Arcane Shroud
|
|
case 26400:
|
|
level_diff = m_target->getLevel() - 60;
|
|
multiplier = 2;
|
|
break;
|
|
// The Eye of Diminution
|
|
case 28862:
|
|
level_diff = m_target->getLevel() - 60;
|
|
multiplier = 1;
|
|
break;
|
|
}
|
|
if (level_diff > 0)
|
|
m_modifier.m_amount += multiplier * level_diff;
|
|
|
|
for(int8 x=0;x < MAX_SPELL_SCHOOL;x++)
|
|
{
|
|
if(m_modifier.m_miscvalue & int32(1<<x))
|
|
{
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_positive ? m_modifier.m_amount : -m_modifier.m_amount, apply);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
if(!m_target->isAlive() || m_target->GetTypeId()!= TYPEID_PLAYER)
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
|
|
if(!caster || !caster->isAlive())
|
|
return;
|
|
|
|
float threatMod = 0.0f;
|
|
if(apply)
|
|
threatMod = float(m_modifier.m_amount);
|
|
else
|
|
threatMod = float(-m_modifier.m_amount);
|
|
|
|
m_target->getHostilRefManager().threatAssist(caster, threatMod);
|
|
}
|
|
|
|
void Aura::HandleModTaunt(bool apply, bool Real)
|
|
{
|
|
// only at real add/remove aura
|
|
if(!Real)
|
|
return;
|
|
|
|
if(!m_target->isAlive() || !m_target->CanHaveThreatList())
|
|
return;
|
|
|
|
Unit* caster = GetCaster();
|
|
|
|
if(!caster || !caster->isAlive() || caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
m_target->TauntApply(caster);
|
|
else
|
|
{
|
|
// When taunt aura fades out, mob will switch to previous target if current has less than 1.1 * secondthreat
|
|
m_target->TauntFadeOut(caster);
|
|
}
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** MODIFY SPEED ***/
|
|
/*********************************************************/
|
|
void Aura::HandleAuraModIncreaseSpeed(bool /*apply*/, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->UpdateSpeed(MOVE_RUN, true);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseMountedSpeed(bool /*apply*/, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->UpdateSpeed(MOVE_RUN, true);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseFlightSpeed(bool apply, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
// Enable Fly mode for flying mounts
|
|
if (m_modifier.m_auraname == SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED)
|
|
{
|
|
WorldPacket data;
|
|
if(apply)
|
|
data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12);
|
|
else
|
|
data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12);
|
|
data.append(m_target->GetPackGUID());
|
|
data << uint32(0); // unknown
|
|
m_target->SendMessageToSet(&data, true);
|
|
|
|
//Players on flying mounts must be immune to polymorph
|
|
if (m_target->GetTypeId()==TYPEID_PLAYER)
|
|
m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,MECHANIC_POLYMORPH,apply);
|
|
|
|
// Dragonmaw Illusion (overwrite mount model, mounted aura already applied)
|
|
if( apply && m_target->HasAura(42016,0) && m_target->GetMountID())
|
|
m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
|
|
}
|
|
|
|
m_target->UpdateSpeed(MOVE_FLIGHT, true);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseSwimSpeed(bool /*apply*/, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->UpdateSpeed(MOVE_SWIM, true);
|
|
}
|
|
|
|
void Aura::HandleAuraModDecreaseSpeed(bool /*apply*/, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->UpdateSpeed(MOVE_RUN, true);
|
|
m_target->UpdateSpeed(MOVE_SWIM, true);
|
|
m_target->UpdateSpeed(MOVE_FLIGHT, true);
|
|
}
|
|
|
|
void Aura::HandleAuraModUseNormalSpeed(bool /*apply*/, bool Real)
|
|
{
|
|
// all applied/removed only at real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_target->UpdateSpeed(MOVE_RUN, true);
|
|
m_target->UpdateSpeed(MOVE_SWIM, true);
|
|
m_target->UpdateSpeed(MOVE_FLIGHT, true);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** IMMUNITY ***/
|
|
/*********************************************************/
|
|
|
|
void Aura::HandleModMechanicImmunity(bool apply, bool Real)
|
|
{
|
|
uint32 mechanic = 1 << m_modifier.m_miscvalue;
|
|
|
|
//immune movement impairment and loss of control
|
|
if(GetId()==42292 || GetId()==59752)
|
|
mechanic=IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK;
|
|
|
|
if(apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
|
|
{
|
|
Unit::AuraMap& Auras = m_target->GetAuras();
|
|
for(Unit::AuraMap::iterator iter = Auras.begin(), next; iter != Auras.end(); iter = next)
|
|
{
|
|
next = iter;
|
|
++next;
|
|
SpellEntry const *spell = iter->second->GetSpellProto();
|
|
if (!( spell->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) && // spells unaffected by invulnerability
|
|
spell->Id != GetId())
|
|
{
|
|
//check for mechanic mask
|
|
if(GetSpellMechanicMask(spell, iter->second->GetEffIndex()) & mechanic)
|
|
{
|
|
m_target->RemoveAurasDueToSpell(spell->Id);
|
|
if(Auras.empty())
|
|
break;
|
|
else
|
|
next = Auras.begin();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_target->ApplySpellImmune(GetId(),IMMUNITY_MECHANIC,m_modifier.m_miscvalue,apply);
|
|
|
|
// Bestial Wrath
|
|
if ( GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellIconID == 1680)
|
|
{
|
|
// The Beast Within cast on owner if talent present
|
|
if ( Unit* owner = m_target->GetOwner() )
|
|
{
|
|
// Search talent
|
|
Unit::AuraList const& m_dummyAuras = owner->GetAurasByType(SPELL_AURA_DUMMY);
|
|
for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
|
|
{
|
|
if ( (*i)->GetSpellProto()->SpellIconID == 2229 )
|
|
{
|
|
if (apply)
|
|
owner->CastSpell(owner, 34471, true, 0, this);
|
|
else
|
|
owner->RemoveAurasDueToSpell(34471);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// The Beast Within and Bestial Wrath - immunity
|
|
if(GetId() == 19574 || GetId() == 34471)
|
|
{
|
|
if(apply)
|
|
{
|
|
m_target->CastSpell(m_target,24395,true);
|
|
m_target->CastSpell(m_target,24396,true);
|
|
m_target->CastSpell(m_target,24397,true);
|
|
m_target->CastSpell(m_target,26592,true);
|
|
}
|
|
else
|
|
{
|
|
m_target->RemoveAurasDueToSpell(24395);
|
|
m_target->RemoveAurasDueToSpell(24396);
|
|
m_target->RemoveAurasDueToSpell(24397);
|
|
m_target->RemoveAurasDueToSpell(26592);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModEffectImmunity(bool apply, bool Real)
|
|
{
|
|
if(!apply)
|
|
{
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if(((Player*)m_target)->InBattleGround())
|
|
{
|
|
BattleGround *bg = ((Player*)m_target)->GetBattleGround();
|
|
if(bg)
|
|
{
|
|
switch(bg->GetTypeID())
|
|
{
|
|
case BATTLEGROUND_AV:
|
|
{
|
|
break;
|
|
}
|
|
case BATTLEGROUND_WS:
|
|
{
|
|
// Warsong Flag, horde // Silverwing Flag, alliance
|
|
if(GetId() == 23333 || GetId() == 23335)
|
|
bg->EventPlayerDroppedFlag(((Player*)m_target));
|
|
break;
|
|
}
|
|
case BATTLEGROUND_AB:
|
|
{
|
|
break;
|
|
}
|
|
case BATTLEGROUND_EY:
|
|
{
|
|
if(GetId() == 34976)
|
|
bg->EventPlayerDroppedFlag(((Player*)m_target));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_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 = m_target->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)
|
|
{
|
|
m_target->RemoveAurasDueToSpell(auraList.front()->GetId());
|
|
itr = auraList.begin();
|
|
}
|
|
else
|
|
++itr;
|
|
}
|
|
}
|
|
|
|
m_target->ApplySpellImmune(GetId(),IMMUNITY_STATE,m_modifier.m_miscvalue,apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModSchoolImmunity(bool apply, bool Real)
|
|
{
|
|
m_target->ApplySpellImmune(GetId(),IMMUNITY_SCHOOL,m_modifier.m_miscvalue,apply);
|
|
|
|
if(Real && apply && GetSpellProto()->AttributesEx & SPELL_ATTR_EX_DISPEL_AURAS_ON_IMMUNITY)
|
|
{
|
|
if(IsPositiveSpell(GetId())) //Only positive immunity removes auras
|
|
{
|
|
uint32 school_mask = m_modifier.m_miscvalue;
|
|
Unit::AuraMap& Auras = m_target->GetAuras();
|
|
for(Unit::AuraMap::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
|
|
{
|
|
m_target->RemoveAurasDueToSpell(spell->Id);
|
|
if(Auras.empty())
|
|
break;
|
|
else
|
|
next = Auras.begin();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( Real && GetSpellProto()->Mechanic == MECHANIC_BANISH )
|
|
{
|
|
if( apply )
|
|
m_target->addUnitState(UNIT_STAT_ISOLATED);
|
|
else
|
|
m_target->clearUnitState(UNIT_STAT_ISOLATED);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModDmgImmunity(bool apply, bool Real)
|
|
{
|
|
m_target->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;
|
|
|
|
m_target->ApplySpellDispelImmunity(m_spellProto, DispelType(m_modifier.m_miscvalue), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraProcTriggerSpell(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(apply)
|
|
{
|
|
// some spell have charges by functionality not have its in spell data
|
|
switch (GetId())
|
|
{
|
|
case 28200: // Ascendance (Talisman of Ascendance trinket)
|
|
SetAuraCharges(6);
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModStalked(bool apply, bool Real)
|
|
{
|
|
// used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND
|
|
if(apply)
|
|
m_target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
|
|
else
|
|
m_target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** PERIODIC ***/
|
|
/*********************************************************/
|
|
|
|
void Aura::HandlePeriodicTriggerSpell(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
if (m_spellProto->Id == 66 && !apply)
|
|
{
|
|
if (m_removeMode == AURA_REMOVE_BY_DEFAULT && m_duration<=0)
|
|
m_target->CastSpell(m_target, 32612, true, NULL, this);
|
|
}
|
|
}
|
|
|
|
void Aura::HandlePeriodicTriggerSpellWithValue(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicEnergize(bool apply, bool Real)
|
|
{
|
|
if (!Real)
|
|
return;
|
|
|
|
m_isPeriodic = apply;
|
|
|
|
// Replenishment (0.25% from max)
|
|
// Infinite Replenishment
|
|
if (GetId() == 57669 ||
|
|
GetId() == 61782)
|
|
m_modifier.m_amount = m_target->GetMaxPower(POWER_MANA) * 25 / 10000;
|
|
}
|
|
|
|
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;
|
|
|
|
// For prevent double apply bonuses
|
|
bool loading = (m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading());
|
|
|
|
Unit* caster = GetCaster();
|
|
|
|
SpellEntry const*spell = GetSpellProto();
|
|
switch( spell->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_ROGUE:
|
|
{
|
|
// Master of Subtlety
|
|
if (spell->Id==31666 && !apply)
|
|
{
|
|
m_target->RemoveAurasDueToSpell(31665);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
// Explosive Shot
|
|
if (apply && !loading && caster)
|
|
m_modifier.m_amount +=caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 8 / 100;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicHeal(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicDamage(bool apply, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
m_isPeriodic = apply;
|
|
|
|
// For prevent double apply bonuses
|
|
bool loading = (m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading());
|
|
|
|
// Custom damage calculation after
|
|
if (!apply || loading)
|
|
return;
|
|
|
|
Unit *caster = GetCaster();
|
|
if (!caster)
|
|
return;
|
|
|
|
switch (m_spellProto->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
{
|
|
// Pounce Bleed
|
|
if ( m_spellProto->SpellIconID == 147 && m_spellProto->SpellVisual[0] == 0 )
|
|
{
|
|
// $AP*0.18/6 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 3 / 100);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARRIOR:
|
|
{
|
|
// Rend
|
|
if (m_spellProto->SpellFamilyFlags & 0x0000000000000020LL)
|
|
{
|
|
// $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);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DRUID:
|
|
{
|
|
// Rake
|
|
if (m_spellProto->SpellFamilyFlags & 0x0000000000001000LL)
|
|
{
|
|
// $AP*0.06 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 6 / 100);
|
|
return;
|
|
}
|
|
// Lacerate
|
|
if (m_spellProto->SpellFamilyFlags & 0x000000010000000000LL)
|
|
{
|
|
// $AP*0.05/5 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
|
|
return;
|
|
}
|
|
// Rip
|
|
if (m_spellProto->SpellFamilyFlags & 0x000000000000800000LL)
|
|
{
|
|
// 0.01*$AP*cp
|
|
if (caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
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);
|
|
return;
|
|
}
|
|
// Lock Jaw
|
|
if (m_spellProto->SpellFamilyFlags & 0x1000000000000000LL)
|
|
{
|
|
// 0.15*$AP
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 15 / 100);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_ROGUE:
|
|
{
|
|
// Rupture
|
|
if (m_spellProto->SpellFamilyFlags & 0x000000000000100000LL)
|
|
{
|
|
if (caster->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
//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[] = {0, 0.015f, 0.024, 0.03, 0.03428571, 0.0375};
|
|
uint8 cp = ((Player*)caster)->GetComboPoints();
|
|
if (cp > 5) cp = 5;
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]);
|
|
return;
|
|
}
|
|
// Garrote
|
|
if (m_spellProto->SpellFamilyFlags & 0x000000000000000100LL)
|
|
{
|
|
// $AP*0.07 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 7 / 100);
|
|
return;
|
|
}
|
|
// Deadly Poison
|
|
if (m_spellProto->SpellFamilyFlags & 0x0000000000010000)
|
|
{
|
|
// 0.08*$AP / 4 * amount of stack
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * 2 * GetStackAmount() / 100);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
// Serpent Sting
|
|
if (m_spellProto->SpellFamilyFlags & 0x0000000000004000LL)
|
|
{
|
|
// $RAP*0.1/5 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
|
|
return;
|
|
}
|
|
// Immolation Trap
|
|
if (m_spellProto->SpellFamilyFlags & 0x0000000000000004LL && m_spellProto->SpellIconID == 678)
|
|
{
|
|
// $RAP*0.1/5 bonus per tick
|
|
m_modifier.m_amount += int32(caster->GetTotalAttackPowerValue(RANGED_ATTACK) * 10 / 500);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Aura::HandlePeriodicDamagePCT(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicLeech(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicManaLeech(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandlePeriodicHealthFunnel(bool apply, bool Real)
|
|
{
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** 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))
|
|
{
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(m_modifier.m_amount), apply);
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,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))
|
|
{
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
|
|
m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,m_modifier.m_amount, apply);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModBaseResistancePCT(bool apply, bool Real)
|
|
{
|
|
// only players have base stats
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
//pets only have base armor
|
|
if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
|
|
m_target->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))
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModResistancePercent(bool apply, bool Real)
|
|
{
|
|
for(int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
|
|
{
|
|
if(m_modifier.m_miscvalue & int32(1<<i))
|
|
{
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
|
|
{
|
|
m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true,m_modifier.m_amount, apply);
|
|
m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false,m_modifier.m_amount, apply);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModBaseResistance(bool apply, bool Real)
|
|
{
|
|
// only players have base stats
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
//only pets have base stats
|
|
if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
|
|
m_target->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))
|
|
m_target->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);
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
|
|
m_target->ApplyStatBuffMod(Stats(i),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 (m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
|
|
{
|
|
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModSpellDamagePercentFromStat(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Magic damage modifiers implemented in Unit::SpellDamageBonus
|
|
// This information for client side use only
|
|
// Recalculate bonus
|
|
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
void Aura::HandleModSpellHealingPercentFromStat(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Recalculate bonus
|
|
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
void Aura::HandleAuraModDispelResist(bool apply, bool Real)
|
|
{
|
|
if(!Real || !apply)
|
|
return;
|
|
|
|
if(GetId()==33206)
|
|
m_target->CastSpell(m_target,44416,true,NULL,this,GetCasterGUID());
|
|
}
|
|
|
|
void Aura::HandleModSpellDamagePercentFromAttackPower(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Magic damage modifiers implemented in Unit::SpellDamageBonus
|
|
// This information for client side use only
|
|
// Recalculate bonus
|
|
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
void Aura::HandleModSpellHealingPercentFromAttackPower(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Recalculate bonus
|
|
((Player*)m_target)->UpdateSpellDamageAndHealingBonus();
|
|
}
|
|
|
|
void Aura::HandleModHealingDone(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
// implemented in Unit::SpellHealingBonus
|
|
// this information is for client side only
|
|
((Player*)m_target)->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;
|
|
}
|
|
|
|
//save current and max HP before applying aura
|
|
uint32 curHPValue = m_target->GetHealth();
|
|
uint32 maxHPValue = m_target->GetMaxHealth();
|
|
|
|
for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++)
|
|
{
|
|
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
|
|
{
|
|
m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
|
|
m_target->ApplyStatPercentBuffMod(Stats(i), 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) && (m_spellProto->Attributes & 0x10))
|
|
{
|
|
// newHP = (curHP / maxHP) * newMaxHP = (newMaxHP * curHP) / maxHP -> which is better because no int -> double -> int conversion is needed
|
|
uint32 newHPValue = (m_target->GetMaxHealth() * curHPValue) / maxHPValue;
|
|
m_target->SetHealth(newHPValue);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModResistenceOfStatPercent(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->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
|
|
m_target->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 = m_target->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 (m_target->GetTypeId() == TYPEID_PLAYER && m_modifier.m_miscvalue == POWER_MANA)
|
|
((Player*)m_target)->UpdateManaRegen();
|
|
|
|
m_isPeriodic = apply;
|
|
}
|
|
|
|
void Aura::HandleModPowerRegenPCT(bool /*apply*/, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
if (m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
// Update manaregen value
|
|
if (m_modifier.m_miscvalue == POWER_MANA)
|
|
((Player*)m_target)->UpdateManaRegen();
|
|
}
|
|
|
|
void Aura::HandleModManaRegen(bool /*apply*/, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
if (m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
//Note: an increase in regen does NOT cause threat.
|
|
((Player*)m_target)->UpdateManaRegen();
|
|
}
|
|
|
|
void Aura::HandleComprehendLanguage(bool apply, bool Real)
|
|
{
|
|
if(apply)
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
|
|
else
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
|
|
{
|
|
// Special case with temporary increase max/current health
|
|
switch(GetId())
|
|
{
|
|
case 12976: // Warrior Last Stand triggered spell
|
|
case 28726: // Nightmare Seed ( Nightmare Seed )
|
|
case 34511: // Valor (Bulwark of Kings, Bulwark of the Ancient Kings)
|
|
case 44055: // Tremendous Fortitude (Battlemaster's Alacrity)
|
|
{
|
|
if(Real)
|
|
{
|
|
if(apply)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
m_target->ModifyHealth(m_modifier.m_amount);
|
|
}
|
|
else
|
|
{
|
|
if (int32(m_target->GetHealth()) > m_modifier.m_amount)
|
|
m_target->ModifyHealth(-m_modifier.m_amount);
|
|
else
|
|
m_target->SetHealth(1);
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// generic case
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseMaxHealth(bool apply, bool Real)
|
|
{
|
|
uint32 oldhealth = m_target->GetHealth();
|
|
double healthPercentage = (double)oldhealth / (double)m_target->GetMaxHealth();
|
|
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
|
|
// refresh percentage
|
|
if(oldhealth > 0)
|
|
{
|
|
uint32 newhealth = uint32(ceil((double)m_target->GetMaxHealth() * healthPercentage));
|
|
if(newhealth==0)
|
|
newhealth = 1;
|
|
|
|
m_target->SetHealth(newhealth);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseEnergy(bool apply, bool Real)
|
|
{
|
|
Powers powerType = m_target->getPowerType();
|
|
if(int32(powerType) != m_modifier.m_miscvalue)
|
|
return;
|
|
|
|
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
|
|
|
|
m_target->HandleStatModifier(unitMod, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseEnergyPercent(bool apply, bool /*Real*/)
|
|
{
|
|
Powers powerType = m_target->getPowerType();
|
|
if(int32(powerType) != m_modifier.m_miscvalue)
|
|
return;
|
|
|
|
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType);
|
|
|
|
m_target->HandleStatModifier(unitMod, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModIncreaseHealthPercent(bool apply, bool /*Real*/)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraIncreaseBaseHealthPercent(bool apply, bool /*Real*/)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
/********************************/
|
|
/*** FIGHT ***/
|
|
/********************************/
|
|
|
|
void Aura::HandleAuraModParryPercent(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)m_target)->UpdateParryPercentage();
|
|
}
|
|
|
|
void Aura::HandleAuraModDodgePercent(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)m_target)->UpdateDodgePercentage();
|
|
//sLog.outError("BONUS DODGE CHANCE: + %f", float(m_modifier.m_amount));
|
|
}
|
|
|
|
void Aura::HandleAuraModBlockPercent(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)m_target)->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(m_target->GetTypeId()!=TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)m_target)->UpdateManaRegen();
|
|
}
|
|
|
|
void Aura::HandleAuraModCritPercent(bool apply, bool Real)
|
|
{
|
|
if(m_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*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
|
|
((Player*)m_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*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
|
|
((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
|
|
((Player*)m_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)
|
|
{
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
((Player*)m_target)->UpdateMeleeHitChances();
|
|
((Player*)m_target)->UpdateRangedHitChances();
|
|
}
|
|
else
|
|
{
|
|
m_target->m_modMeleeHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
|
|
m_target->m_modRangedHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModSpellHitChance(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
((Player*)m_target)->UpdateSpellHitChances();
|
|
}
|
|
else
|
|
{
|
|
m_target->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(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
((Player*)m_target)->UpdateAllSpellCritChances();
|
|
}
|
|
else
|
|
{
|
|
m_target->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(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
for(int school = SPELL_SCHOOL_NORMAL; school < MAX_SPELL_SCHOOL; ++school)
|
|
if (m_modifier.m_miscvalue & (1<<school))
|
|
((Player*)m_target)->UpdateSpellCritChance(school);
|
|
}
|
|
|
|
/********************************/
|
|
/*** ATTACK SPEED ***/
|
|
/********************************/
|
|
|
|
void Aura::HandleModCastingSpeed(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyCastTimePercentMod(m_modifier.m_amount,apply);
|
|
}
|
|
|
|
void Aura::HandleModMeleeRangedSpeedPct(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
|
|
}
|
|
|
|
void Aura::HandleModCombatSpeedPct(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyCastTimePercentMod(m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
|
|
}
|
|
|
|
void Aura::HandleModAttackSpeed(bool apply, bool Real)
|
|
{
|
|
if(!m_target->isAlive() )
|
|
return;
|
|
|
|
m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
|
|
}
|
|
|
|
void Aura::HandleHaste(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyAttackTimePercentMod(BASE_ATTACK, m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(OFF_ATTACK, m_modifier.m_amount,apply);
|
|
m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_modifier.m_amount,apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModRangedHaste(bool apply, bool Real)
|
|
{
|
|
m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
|
|
}
|
|
|
|
void Aura::HandleRangedAmmoHaste(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_modifier.m_amount, apply);
|
|
}
|
|
|
|
/********************************/
|
|
/*** ATTACK POWER ***/
|
|
/********************************/
|
|
|
|
void Aura::HandleAuraModAttackPower(bool apply, bool Real)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModRangedAttackPower(bool apply, bool Real)
|
|
{
|
|
if((m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
|
|
return;
|
|
|
|
m_target->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
|
|
m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
|
|
void Aura::HandleAuraModRangedAttackPowerPercent(bool apply, bool Real)
|
|
{
|
|
if((m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
|
|
return;
|
|
|
|
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
|
|
m_target->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(m_target->GetTypeId() == TYPEID_PLAYER && !(m_target->getClassMask() & CLASSMASK_WAND_USERS))
|
|
((Player*)m_target)->UpdateAttackPowerAndDamage(true);
|
|
}
|
|
|
|
void Aura::HandleAuraModAttackPowerOfStatPercent(bool apply, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
// Recalculate bonus
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)m_target)->UpdateAttackPowerAndDamage(false);
|
|
}
|
|
|
|
/********************************/
|
|
/*** DAMAGE BONUS ***/
|
|
/********************************/
|
|
void Aura::HandleModDamageDone(bool apply, bool Real)
|
|
{
|
|
// apply item specific bonuses for already equipped weapon
|
|
if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
for(int i = 0; i < MAX_ATTACK; ++i)
|
|
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
|
|
((Player*)m_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 || m_target->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(m_modifier.m_amount), apply);
|
|
}
|
|
else
|
|
{
|
|
// done in Player::_ApplyWeaponDependentAuraMods
|
|
}
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
if(m_positive)
|
|
m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS,m_modifier.m_amount,apply);
|
|
else
|
|
m_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::SpellDamageBonus
|
|
// This information for client side use only
|
|
if(m_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)
|
|
m_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)
|
|
m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i,m_modifier.m_amount,apply);
|
|
}
|
|
}
|
|
Pet* pet = m_target->GetPet();
|
|
if(pet)
|
|
pet->UpdateAttackPowerAndDamage();
|
|
}
|
|
}
|
|
|
|
void Aura::HandleModDamagePercentDone(bool apply, bool Real)
|
|
{
|
|
sLog.outDebug("AURA MOD DAMAGE type:%u negative:%u", m_modifier.m_miscvalue, m_positive ? 0 : 1);
|
|
|
|
// apply item specific bonuses for already equipped weapon
|
|
if(Real && m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
for(int i = 0; i < MAX_ATTACK; ++i)
|
|
if(Item* pItem = ((Player*)m_target)->GetWeaponForAttack(WeaponAttackType(i)))
|
|
((Player*)m_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 || m_target->GetTypeId() != TYPEID_PLAYER)
|
|
{
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(m_modifier.m_amount), apply);
|
|
}
|
|
else
|
|
{
|
|
// done in Player::_ApplyWeaponDependentAuraMods
|
|
}
|
|
// For show in client
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
m_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::SpellDamageBonus
|
|
// Send info to client
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
|
|
m_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;
|
|
|
|
sLog.outDebug("AURA MOD OFFHAND DAMAGE");
|
|
|
|
m_target->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))
|
|
m_target->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))
|
|
m_target->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;
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
uint32 mask[3] = {0, 0, 0};
|
|
Unit::AuraList const& noReagent = m_target->GetAurasByType(SPELL_AURA_NO_REAGENT_USE);
|
|
for(Unit::AuraList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i)
|
|
{
|
|
uint32 const *ptr = (*i)->getAuraSpellClassMask();
|
|
mask[0]|=ptr[0];
|
|
mask[1]|=ptr[1];
|
|
mask[2]|=ptr[2];
|
|
}
|
|
|
|
m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1 , mask[0]);
|
|
m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]);
|
|
m_target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask[2]);
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*** OTHERS ***/
|
|
/*********************************************************/
|
|
|
|
void Aura::HandleShapeshiftBoosts(bool apply)
|
|
{
|
|
uint32 spellId = 0;
|
|
uint32 spellId2 = 0;
|
|
uint32 HotWSpellId = 0;
|
|
|
|
switch(GetModifier()->m_miscvalue)
|
|
{
|
|
case FORM_CAT:
|
|
spellId = 3025;
|
|
HotWSpellId = 24900;
|
|
break;
|
|
case FORM_TREE:
|
|
spellId = 5420;
|
|
spellId2 = 34123;
|
|
break;
|
|
case FORM_TRAVEL:
|
|
spellId = 5419;
|
|
break;
|
|
case FORM_AQUA:
|
|
spellId = 5421;
|
|
break;
|
|
case FORM_BEAR:
|
|
spellId = 1178;
|
|
spellId2 = 21178;
|
|
HotWSpellId = 24899;
|
|
break;
|
|
case FORM_DIREBEAR:
|
|
spellId = 9635;
|
|
spellId2 = 21178;
|
|
HotWSpellId = 24899;
|
|
break;
|
|
case FORM_BATTLESTANCE:
|
|
spellId = 21156;
|
|
break;
|
|
case FORM_DEFENSIVESTANCE:
|
|
spellId = 7376;
|
|
break;
|
|
case FORM_BERSERKERSTANCE:
|
|
spellId = 7381;
|
|
break;
|
|
case FORM_MOONKIN:
|
|
spellId = 24905;
|
|
// aura from effect trigger spell
|
|
spellId2 = 24907;
|
|
break;
|
|
case FORM_FLIGHT:
|
|
spellId = 33948;
|
|
spellId2 = 34764;
|
|
break;
|
|
case FORM_FLIGHT_EPIC:
|
|
spellId = 40122;
|
|
spellId2 = 40121;
|
|
break;
|
|
case FORM_METAMORPHOSIS:
|
|
spellId = 54817;
|
|
spellId2 = 54879;
|
|
break;
|
|
case FORM_SPIRITOFREDEMPTION:
|
|
spellId = 27792;
|
|
spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation.
|
|
break;
|
|
case FORM_GHOSTWOLF:
|
|
case FORM_AMBIENT:
|
|
case FORM_GHOUL:
|
|
case FORM_SHADOW:
|
|
case FORM_STEALTH:
|
|
case FORM_CREATURECAT:
|
|
case FORM_CREATUREBEAR:
|
|
spellId = 0;
|
|
break;
|
|
}
|
|
|
|
uint32 form = GetModifier()->m_miscvalue-1;
|
|
|
|
if(apply)
|
|
{
|
|
if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this );
|
|
if (spellId2) m_target->CastSpell(m_target, spellId2, true, NULL, this);
|
|
|
|
if(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
{
|
|
const PlayerSpellMap& sp_list = ((Player *)m_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==spellId || itr->first==spellId2) continue;
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
|
|
if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR_PASSIVE | (1<<7)))) continue;
|
|
if (spellInfo->Stances & (1<<form))
|
|
m_target->CastSpell(m_target, itr->first, true, NULL, this);
|
|
}
|
|
//LotP
|
|
if (((Player*)m_target)->HasSpell(17007))
|
|
{
|
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932);
|
|
if (spellInfo && spellInfo->Stances & (1<<form))
|
|
m_target->CastSpell(m_target, 24932, true, NULL, this);
|
|
}
|
|
// HotW
|
|
if (HotWSpellId)
|
|
{
|
|
Unit::AuraList const& mModTotalStatPct = m_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;
|
|
|
|
m_target->CastCustomSpell(m_target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_target->RemoveAurasDueToSpell(spellId);
|
|
m_target->RemoveAurasDueToSpell(spellId2);
|
|
|
|
Unit::AuraMap& tAuras = m_target->GetAuras();
|
|
for (Unit::AuraMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
|
|
{
|
|
if (itr->second->IsRemovedOnShapeLost())
|
|
{
|
|
m_target->RemoveAurasDueToSpell(itr->second->GetId());
|
|
itr = tAuras.begin();
|
|
}
|
|
else
|
|
{
|
|
++itr;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*double healthPercentage = (double)m_target->GetHealth() / (double)m_target->GetMaxHealth();
|
|
m_target->SetHealth(uint32(ceil((double)m_target->GetMaxHealth() * healthPercentage)));*/
|
|
}
|
|
|
|
void Aura::HandleAuraEmpathy(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_UNIT)
|
|
return;
|
|
|
|
CreatureInfo const * ci = objmgr.GetCreatureTemplate(m_target->GetEntry());
|
|
if(ci && ci->type == CREATURE_TYPE_BEAST)
|
|
m_target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply);
|
|
}
|
|
|
|
void Aura::HandleAuraUntrackable(bool apply, bool Real)
|
|
{
|
|
if(apply)
|
|
m_target->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
|
|
else
|
|
m_target->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE);
|
|
}
|
|
|
|
void Aura::HandleAuraModPacify(bool apply, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED);
|
|
else
|
|
m_target->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(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(apply)
|
|
{
|
|
m_target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST);
|
|
}
|
|
else
|
|
{
|
|
m_target->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.append(m_target->GetPackGUID());
|
|
data << uint32(0); // unk
|
|
m_target->SendMessageToSet(&data, true);
|
|
}
|
|
|
|
void Aura::HandleModRating(bool apply, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
|
if (m_modifier.m_miscvalue & (1 << rating))
|
|
((Player*)m_target)->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(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
// Just recalculate ratings
|
|
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
|
|
if (m_modifier.m_miscvalue & (1 << rating))
|
|
((Player*)m_target)->ApplyRatingMod(CombatRating(rating), 0, apply);
|
|
}
|
|
|
|
void Aura::HandleForceMoveForward(bool apply, bool Real)
|
|
{
|
|
if(!Real || m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
if(apply)
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
|
|
else
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE);
|
|
}
|
|
|
|
void Aura::HandleAuraModExpertise(bool /*apply*/, bool Real)
|
|
{
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
((Player*)m_target)->UpdateExpertise(BASE_ATTACK);
|
|
((Player*)m_target)->UpdateExpertise(OFF_ATTACK);
|
|
}
|
|
|
|
void Aura::HandleModTargetResistance(bool apply, bool Real)
|
|
{
|
|
// spells required only Real aura add/remove
|
|
if(!Real)
|
|
return;
|
|
// applied to damage as HandleNoImmediateEffect in Unit::CalcAbsorbResist and Unit::CalcArmorReducedDamage
|
|
|
|
// show armor penetration
|
|
if (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
|
|
m_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 (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_SPELL)==SPELL_SCHOOL_MASK_SPELL)
|
|
m_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(m_target->GetTypeId() == TYPEID_PLAYER)
|
|
((Player*)m_target)->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(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *target = (Player*)m_target;
|
|
|
|
// 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_duration==0 && target->GetComboTarget())
|
|
if(Unit* unit = ObjectAccessor::GetUnit(*m_target,target->GetComboTarget()))
|
|
target->AddComboPoints(unit, -m_modifier.m_amount);
|
|
}
|
|
|
|
void Aura::HandleModUnattackable( bool Apply, bool Real )
|
|
{
|
|
if(Real && Apply)
|
|
m_target->CombatStop();
|
|
|
|
m_target->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;
|
|
|
|
// prepare spirit state
|
|
if(apply)
|
|
{
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
// disable breath/etc timers
|
|
((Player*)m_target)->StopMirrorTimers();
|
|
|
|
// set stand state (expected in this form)
|
|
if(!m_target->IsStandState())
|
|
m_target->SetStandState(UNIT_STAND_STATE_STAND);
|
|
}
|
|
|
|
m_target->SetHealth(1);
|
|
}
|
|
// die at aura end
|
|
else
|
|
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, GetSpellProto(), false);
|
|
}
|
|
|
|
void Aura::CleanupTriggeredSpells()
|
|
{
|
|
if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellProto->SpellFamilyFlags & 0x0000001000000020LL)
|
|
{
|
|
// Blood Frenzy remove
|
|
m_target->RemoveAurasDueToSpell(30069);
|
|
m_target->RemoveAurasDueToSpell(30070);
|
|
return;
|
|
}
|
|
|
|
uint32 tSpellId = m_spellProto->EffectTriggerSpell[GetEffIndex()];
|
|
if(!tSpellId)
|
|
return;
|
|
|
|
SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId);
|
|
if(!tProto)
|
|
return;
|
|
|
|
if(GetSpellDuration(tProto) != -1)
|
|
return;
|
|
|
|
// 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[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL &&
|
|
GetSpellDuration(m_spellProto) == m_spellProto->EffectAmplitude[GetEffIndex()])
|
|
return;
|
|
m_target->RemoveAurasDueToSpell(tSpellId);
|
|
}
|
|
|
|
void Aura::HandleSchoolAbsorb(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
// prevent double apply bonuses
|
|
if(apply && (m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading()))
|
|
{
|
|
if(Unit* caster = GetCaster())
|
|
{
|
|
float DoneActualBenefit = 0.0f;
|
|
switch(m_spellProto->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_PRIEST:
|
|
if(m_spellProto->SpellFamilyFlags == 0x1) //PW:S
|
|
{
|
|
//+30% from +healing bonus
|
|
DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.3f;
|
|
break;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_MAGE:
|
|
if(m_spellProto->SpellFamilyFlags == 0x80100 || m_spellProto->SpellFamilyFlags == 0x8 || m_spellProto->SpellFamilyFlags == 0x100000000LL)
|
|
{
|
|
//frost ward, fire ward, ice barrier
|
|
//+10% from +spd bonus
|
|
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
|
|
break;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_WARLOCK:
|
|
if(m_spellProto->SpellFamilyFlags == 0x00)
|
|
{
|
|
//shadow ward
|
|
//+10% from +spd bonus
|
|
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
|
|
|
|
m_modifier.m_amount += (int32)DoneActualBenefit;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::PeriodicTick()
|
|
{
|
|
if(!m_target->isAlive())
|
|
return;
|
|
|
|
switch(m_modifier.m_auraname)
|
|
{
|
|
case SPELL_AURA_PERIODIC_DAMAGE:
|
|
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
|
|
{
|
|
Unit *pCaster = GetCaster();
|
|
if(!pCaster)
|
|
return;
|
|
|
|
if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
|
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
|
|
return;
|
|
|
|
// Check for immune (not use charges)
|
|
if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
|
|
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:
|
|
if(m_target->GetHealth() == m_target->GetMaxHealth() )
|
|
{
|
|
m_target->RemoveAurasDueToSpell(GetId());
|
|
return;
|
|
}
|
|
break;
|
|
case 38772:
|
|
{
|
|
uint32 percent =
|
|
GetEffIndex() < 2 && GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_DUMMY ?
|
|
pCaster->CalculateSpellDamage(GetSpellProto(),GetEffIndex()+1,GetSpellProto()->EffectBasePoints[GetEffIndex()+1],m_target) :
|
|
100;
|
|
if(m_target->GetHealth()*100 >= m_target->GetMaxHealth()*percent )
|
|
{
|
|
m_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;
|
|
|
|
// Calculate armor mitigation if it is a physical spell
|
|
// But not for bleed mechanic spells
|
|
if ( GetSpellSchoolMask(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL &&
|
|
GetEffectMechanic(GetSpellProto(), m_effIndex) != MECHANIC_BLEED)
|
|
{
|
|
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage);
|
|
cleanDamage.damage += pdamage - pdamageReductedArmor;
|
|
pdamage = pdamageReductedArmor;
|
|
}
|
|
|
|
pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
|
|
|
|
// Curse of Agony damage-per-tick calculation
|
|
if (GetSpellProto()->SpellFamilyName==SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 0x0000000000000400LL) && GetSpellProto()->SpellIconID==544)
|
|
{
|
|
// 1..4 ticks, 1/2 from normal tick damage
|
|
if (m_duration>=((m_maxduration-m_modifier.periodictime)*2/3))
|
|
pdamage = pdamage/2;
|
|
// 9..12 ticks, 3/2 from normal tick damage
|
|
else if(m_duration<((m_maxduration-m_modifier.periodictime)/3))
|
|
pdamage += (pdamage+1)/2; // +1 prevent 0.5 damage possible lost at 1..4 ticks
|
|
// 5..8 ticks have normal tick damage
|
|
}
|
|
}
|
|
else
|
|
pdamage = uint32(m_target->GetMaxHealth()*amount/100);
|
|
|
|
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
|
|
// Reduce dot damage from resilience for players
|
|
if (m_target->GetTypeId()==TYPEID_PLAYER)
|
|
pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage);
|
|
|
|
pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist);
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId(),absorb);
|
|
|
|
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
|
data.append(m_target->GetPackGUID());
|
|
data.appendPackGUID(GetCasterGUID());
|
|
data << uint32(GetId());
|
|
data << uint32(1);
|
|
data << uint32(m_modifier.m_auraname);
|
|
data << (uint32)pdamage;
|
|
data << uint32(0); // overkill
|
|
data << (uint32)GetSpellSchoolMask(GetSpellProto()); // will be mask in 2.4.x
|
|
data << (uint32)absorb;
|
|
data << (uint32)resist;
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
Unit* target = m_target; // aura can be deleted in DealDamage
|
|
SpellEntry const* spellProto = GetSpellProto();
|
|
|
|
// 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;
|
|
pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
|
|
if (pdamage)
|
|
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
|
|
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
|
|
|
|
pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, true);
|
|
break;
|
|
}
|
|
case SPELL_AURA_PERIODIC_LEECH:
|
|
case SPELL_AURA_PERIODIC_HEALTH_FUNNEL:
|
|
{
|
|
Unit *pCaster = GetCaster();
|
|
if(!pCaster)
|
|
return;
|
|
|
|
if(!pCaster->isAlive())
|
|
return;
|
|
|
|
if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
|
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
|
|
return;
|
|
|
|
// Check for immune
|
|
if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
|
|
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(GetSpellProto()) & SPELL_SCHOOL_MASK_NORMAL)
|
|
{
|
|
uint32 pdamageReductedArmor = pCaster->CalcArmorReducedDamage(m_target, pdamage);
|
|
cleanDamage.damage += pdamage - pdamageReductedArmor;
|
|
pdamage = pdamageReductedArmor;
|
|
}
|
|
|
|
pdamage = pCaster->SpellDamageBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
|
|
|
|
//As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit
|
|
// Reduce dot damage from resilience for players
|
|
if (m_target->GetTypeId()==TYPEID_PLAYER)
|
|
pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage);
|
|
|
|
pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist);
|
|
|
|
if(m_target->GetHealth() < pdamage)
|
|
pdamage = uint32(m_target->GetHealth());
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) health leech of %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId(),absorb);
|
|
|
|
pCaster->SendSpellNonMeleeDamageLog(m_target, GetId(), pdamage, GetSpellSchoolMask(GetSpellProto()), absorb, resist, false, 0);
|
|
|
|
|
|
Unit* target = m_target; // aura can be deleted in DealDamage
|
|
SpellEntry const* spellProto = GetSpellProto();
|
|
float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1;
|
|
int32 stackAmount = GetStackAmount();
|
|
|
|
// 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;
|
|
pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
|
|
if (pdamage)
|
|
procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
|
|
pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, 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 (pCaster->m_currentSpells[i] && pCaster->m_currentSpells[i]->m_spellInfo->Id == spellProto->Id)
|
|
pCaster->m_currentSpells[i]->cancel();
|
|
}
|
|
}
|
|
|
|
|
|
if(Player *modOwner = pCaster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
|
|
|
|
uint32 heal = pCaster->SpellHealingBonus(pCaster, spellProto, uint32(new_damage * multiplier), DOT, stackAmount);
|
|
|
|
int32 gain = pCaster->ModifyHealth(heal);
|
|
pCaster->getHostilRefManager().threatAssist(pCaster, gain * 0.5f, spellProto);
|
|
|
|
pCaster->SendHealSpellLog(pCaster, spellProto->Id, heal);
|
|
break;
|
|
}
|
|
case SPELL_AURA_PERIODIC_HEAL:
|
|
case SPELL_AURA_OBS_MOD_HEALTH:
|
|
{
|
|
Unit *pCaster = GetCaster();
|
|
if(!pCaster)
|
|
return;
|
|
|
|
// heal for caster damage (must be alive)
|
|
if(m_target != pCaster && GetSpellProto()->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(m_target->GetMaxHealth() * amount/100);
|
|
else
|
|
pdamage = amount;
|
|
|
|
pdamage = pCaster->SpellHealingBonus(m_target, GetSpellProto(), pdamage, DOT, GetStackAmount());
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
|
|
|
|
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
|
data.append(m_target->GetPackGUID());
|
|
data.appendPackGUID(GetCasterGUID());
|
|
data << uint32(GetId());
|
|
data << uint32(1);
|
|
data << uint32(m_modifier.m_auraname);
|
|
data << (uint32)pdamage;
|
|
data << uint32(0); // wotlk
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
int32 gain = m_target->ModifyHealth(pdamage);
|
|
|
|
// 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);
|
|
|
|
//Do check before because m_modifier.auraName can be invalidate by DealDamage.
|
|
bool procSpell = (m_modifier.m_auraname == SPELL_AURA_PERIODIC_HEAL && m_target != pCaster);
|
|
|
|
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
|
|
|
|
Unit* target = m_target; // aura can be deleted in DealDamage
|
|
SpellEntry const* spellProto = GetSpellProto();
|
|
bool haveCastItem = GetCastItemGUID()!=0;
|
|
|
|
// heal for caster damage
|
|
if(m_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
|
|
if(pCaster->m_currentSpells[CURRENT_GENERIC_SPELL])
|
|
{
|
|
pCaster->m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
|
|
}
|
|
if(pCaster->m_currentSpells[CURRENT_CHANNELED_SPELL])
|
|
{
|
|
pCaster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0);
|
|
pCaster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), gain, GetSpellSchoolMask(GetSpellProto()), 0, 0, false, 0, false);
|
|
|
|
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
|
|
pCaster->DealDamage(pCaster, gain, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), 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:
|
|
{
|
|
Unit *pCaster = GetCaster();
|
|
if(!pCaster)
|
|
return;
|
|
|
|
if(!pCaster->isAlive())
|
|
return;
|
|
|
|
if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
|
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
|
|
return;
|
|
|
|
// Check for immune (not use charges)
|
|
if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
|
|
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;
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
|
|
|
|
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
|
|
break;
|
|
|
|
Powers power = Powers(m_modifier.m_miscvalue);
|
|
|
|
// power type might have changed between aura applying and tick (druid's shapeshift)
|
|
if(m_target->getPowerType() != power)
|
|
break;
|
|
|
|
int32 drain_amount = m_target->GetPower(power) > pdamage ? pdamage : m_target->GetPower(power);
|
|
|
|
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
|
|
if (power == POWER_MANA && m_target->GetTypeId() == TYPEID_PLAYER)
|
|
drain_amount -= ((Player*)m_target)->GetSpellCritDamageReduction(drain_amount);
|
|
|
|
m_target->ModifyPower(power, -drain_amount);
|
|
|
|
float gain_multiplier = 0;
|
|
|
|
if(pCaster->GetMaxPower(power) > 0)
|
|
{
|
|
gain_multiplier = GetSpellProto()->EffectMultipleValue[GetEffIndex()];
|
|
|
|
if(Player *modOwner = pCaster->GetSpellModOwner())
|
|
modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, gain_multiplier);
|
|
}
|
|
|
|
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
|
data.append(m_target->GetPackGUID());
|
|
data.appendPackGUID(GetCasterGUID());
|
|
data << uint32(GetId());
|
|
data << uint32(1);
|
|
data << uint32(m_modifier.m_auraname);
|
|
data << (uint32)power; // power type
|
|
data << (uint32)drain_amount;
|
|
data << (float)gain_multiplier;
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
int32 gain_amount = int32(drain_amount*gain_multiplier);
|
|
|
|
if(gain_amount)
|
|
{
|
|
int32 gain = pCaster->ModifyPower(power,gain_amount);
|
|
m_target->AddThreat(pCaster, float(gain) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
|
|
}
|
|
break;
|
|
}
|
|
case SPELL_AURA_PERIODIC_ENERGIZE:
|
|
{
|
|
// ignore non positive values (can be result apply spellmods to aura damage
|
|
uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
|
|
|
|
if(m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue >= MAX_POWERS)
|
|
break;
|
|
|
|
Powers power = Powers(m_modifier.m_miscvalue);
|
|
|
|
if(m_target->GetMaxPower(power) == 0)
|
|
break;
|
|
|
|
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
|
data.append(m_target->GetPackGUID());
|
|
data.appendPackGUID(GetCasterGUID());
|
|
data << uint32(GetId());
|
|
data << uint32(1);
|
|
data << uint32(m_modifier.m_auraname);
|
|
data << (uint32)power; // power type
|
|
data << (uint32)pdamage;
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
int32 gain = m_target->ModifyPower(power,pdamage);
|
|
|
|
if(Unit* pCaster = GetCaster())
|
|
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
|
|
break;
|
|
}
|
|
case SPELL_AURA_OBS_MOD_MANA:
|
|
{
|
|
// 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(m_target->GetMaxPower(POWER_MANA) * amount/100);
|
|
|
|
sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u mana inflicted by %u",
|
|
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
|
|
|
|
if(m_target->GetMaxPower(POWER_MANA) == 0)
|
|
break;
|
|
|
|
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
|
data.append(m_target->GetPackGUID());
|
|
data.appendPackGUID(GetCasterGUID());
|
|
data << uint32(GetId());
|
|
data << uint32(1);
|
|
data << uint32(m_modifier.m_auraname);
|
|
data << (uint32)0; // ?
|
|
data << (uint32)pdamage;
|
|
m_target->SendMessageToSet(&data,true);
|
|
|
|
int32 gain = m_target->ModifyPower(POWER_MANA, pdamage);
|
|
|
|
if(Unit* pCaster = GetCaster())
|
|
m_target->getHostilRefManager().threatAssist(pCaster, float(gain) * 0.5f, GetSpellProto());
|
|
break;
|
|
}
|
|
case SPELL_AURA_POWER_BURN_MANA:
|
|
{
|
|
Unit *pCaster = GetCaster();
|
|
if(!pCaster)
|
|
return;
|
|
|
|
// Check for immune (not use charges)
|
|
if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
|
|
return;
|
|
|
|
int32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
|
|
|
|
Powers powerType = Powers(m_modifier.m_miscvalue);
|
|
|
|
if(!m_target->isAlive() || m_target->getPowerType() != powerType)
|
|
return;
|
|
|
|
// resilience reduce mana draining effect at spell crit damage reduction (added in 2.4)
|
|
if (powerType == POWER_MANA && m_target->GetTypeId() == TYPEID_PLAYER)
|
|
pdamage -= ((Player*)m_target)->GetSpellCritDamageReduction(pdamage);
|
|
|
|
uint32 gain = uint32(-m_target->ModifyPower(powerType, -pdamage));
|
|
|
|
gain = uint32(gain * GetSpellProto()->EffectMultipleValue[GetEffIndex()]);
|
|
|
|
SpellEntry const* spellProto = GetSpellProto();
|
|
//maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
|
|
SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
|
|
pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
|
|
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:
|
|
{
|
|
int32 gain = m_target->ModifyHealth(m_modifier.m_amount);
|
|
if (Unit *caster = GetCaster())
|
|
m_target->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto());
|
|
break;
|
|
}
|
|
case SPELL_AURA_MOD_POWER_REGEN:
|
|
{
|
|
Powers pt = m_target->getPowerType();
|
|
if(int32(pt) != m_modifier.m_miscvalue)
|
|
return;
|
|
|
|
if ( GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED )
|
|
{
|
|
// eating anim
|
|
m_target->HandleEmoteCommand(EMOTE_ONESHOT_EAT);
|
|
}
|
|
else if( GetId() == 20577 )
|
|
{
|
|
// cannibalize anim
|
|
m_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)
|
|
m_target->ModifyPower(pt, m_modifier.m_amount*3/5);
|
|
break;
|
|
}
|
|
// Here tick dummy auras
|
|
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()
|
|
{
|
|
Unit *caster = GetCaster();
|
|
SpellEntry const* spell = GetSpellProto();
|
|
switch (spell->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_GENERIC:
|
|
switch (spell->Id)
|
|
{
|
|
// Drink
|
|
case 430:
|
|
case 431:
|
|
case 432:
|
|
case 1133:
|
|
case 1135:
|
|
case 1137:
|
|
case 10250:
|
|
case 22734:
|
|
case 27089:
|
|
case 34291:
|
|
case 43706:
|
|
case 46755:
|
|
case 49472: // Drink Coffee
|
|
case 61830:
|
|
{
|
|
if (m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
// Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus
|
|
Unit::AuraList const& aura = m_target->GetAurasByType(SPELL_AURA_MOD_POWER_REGEN);
|
|
for(Unit::AuraList::const_iterator i = aura.begin(); i != aura.end(); ++i)
|
|
{
|
|
if ((*i)->GetId() == GetId())
|
|
{
|
|
(*i)->GetModifier()->m_amount = m_modifier.m_amount;
|
|
((Player*)m_target)->UpdateManaRegen();
|
|
// Disable continue
|
|
m_isPeriodic = false;
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
// 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;
|
|
}
|
|
// // 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;
|
|
// // Summon Blood Elves Periodic
|
|
// case 46041: break;
|
|
// // 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: break; // Summon Gauntlet Mobs Periodic
|
|
// 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;
|
|
// Exist more after, need add later
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case SPELLFAMILY_MAGE:
|
|
{
|
|
// Mirror Image
|
|
// if (spell->Id == 55342)
|
|
// return;
|
|
break;
|
|
}
|
|
case SPELLFAMILY_WARRIOR:
|
|
{
|
|
// Armored to the Teeth
|
|
if (spell->SpellIconID == 3516)
|
|
{
|
|
// 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 * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
|
|
m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this);
|
|
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 (m_target->getPowerType()!=POWER_RAGE)
|
|
return;
|
|
uint32 rage = m_target->GetPower(POWER_RAGE);
|
|
// Nothing todo
|
|
if (rage == 0)
|
|
return;
|
|
int32 mod = (rage < 100) ? rage : 100;
|
|
int32 points = m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
|
|
int32 regen = m_target->GetMaxHealth() * (mod * points / 10) / 1000;
|
|
m_target->CastCustomSpell(m_target, 22845, ®en, 0, 0, true, 0, this);
|
|
m_target->SetPower(POWER_RAGE, rage-mod);
|
|
return;
|
|
}
|
|
// Force of Nature
|
|
case 33831:
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_ROGUE:
|
|
{
|
|
// switch (spell->Id)
|
|
// {
|
|
// Master of Subtlety
|
|
// case 31666: break;
|
|
// Killing Spree
|
|
// case 51690: break;
|
|
// Overkill
|
|
// case 58428: break;
|
|
// default:
|
|
// break;
|
|
// }
|
|
break;
|
|
}
|
|
case SPELLFAMILY_HUNTER:
|
|
{
|
|
// Explosive Shot
|
|
if (spell->SpellFamilyFlags & 0x8000000000000000LL)
|
|
{
|
|
if (!caster)
|
|
return;
|
|
int32 damage = m_modifier.m_amount;
|
|
// Full damage to target at 0 tick
|
|
if (m_duration > m_modifier.periodictime)
|
|
{
|
|
caster->CastCustomSpell(m_target, 53352, &damage, 0, 0, true, 0, this);
|
|
return;
|
|
}
|
|
damage/=4;
|
|
caster->CastCustomSpell(m_target, 56298, &damage, 0, 0, true, 0, this);
|
|
return;
|
|
}
|
|
switch (spell->Id)
|
|
{
|
|
// Harpooner's Mark
|
|
// case 40084:
|
|
// return;
|
|
// Feeding Frenzy Rank 1
|
|
case 53511:
|
|
if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 )
|
|
m_target->CastSpell(m_target, 60096, true, 0, this);
|
|
return;
|
|
// Feeding Frenzy Rank 2
|
|
case 53512:
|
|
if ( m_target->GetHealth() * 100 < m_target->GetMaxHealth() * 35 )
|
|
m_target->CastSpell(m_target, 60097, true, 0, 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 (!(m_target->GetUInt32Value(UNIT_FIELD_FLAGS)&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED)))
|
|
m_target->RemoveAurasDueToSpell(52179);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case SPELLFAMILY_DEATHKNIGHT:
|
|
{
|
|
// Death and Decay
|
|
if (spell->SpellFamilyFlags & 0x0000000000000020LL)
|
|
{
|
|
if (caster)
|
|
caster->CastCustomSpell(m_target, 52212, &m_modifier.m_amount, NULL, NULL, true, 0, this);
|
|
return;
|
|
}
|
|
// Raise Dead
|
|
// if (spell->SpellFamilyFlags & 0x0000000000001000LL)
|
|
// return;
|
|
// Chains of Ice
|
|
if (spell->SpellFamilyFlags & 0x0000400000000000LL)
|
|
{
|
|
// Get 0 effect aura
|
|
Aura *slow = m_target->GetAura(GetId(), 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 & 0x0000008000000000LL)
|
|
// return;
|
|
// Death Rune Mastery
|
|
// if (spell->SpellFamilyFlags & 0x0000000000004000LL)
|
|
// 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 * m_target->GetArmor() / m_target->CalculateSpellDamage(spell, 1, spell->EffectBasePoints[1], m_target);
|
|
m_target->CastCustomSpell(m_target, 61217, &apBonus, &apBonus, 0, true, 0, this);
|
|
return;
|
|
}
|
|
// Reaping
|
|
// if (spell->SpellIconID == 22)
|
|
// return;
|
|
// Blood of the North
|
|
// if (spell->SpellIconID == 30412)
|
|
// return;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Aura::HandlePreventFleeing(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
Unit::AuraList const& fearAuras = m_target->GetAurasByType(SPELL_AURA_MOD_FEAR);
|
|
if( !fearAuras.empty() )
|
|
{
|
|
if (apply)
|
|
m_target->SetFeared(false, fearAuras.front()->GetCasterGUID());
|
|
else
|
|
m_target->SetFeared(true);
|
|
}
|
|
}
|
|
|
|
void Aura::HandleManaShield(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
// prevent double apply bonuses
|
|
if(apply && (m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading()))
|
|
{
|
|
if(Unit* caster = GetCaster())
|
|
{
|
|
float DoneActualBenefit = 0.0f;
|
|
switch(m_spellProto->SpellFamilyName)
|
|
{
|
|
case SPELLFAMILY_MAGE:
|
|
if(m_spellProto->SpellFamilyFlags & 0x8000)
|
|
{
|
|
// Mana Shield
|
|
// +50% from +spd bonus
|
|
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 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)
|
|
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
|
|
else
|
|
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION);
|
|
}
|
|
|
|
void Aura::HandleAuraControlVehicle(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
if(Pet *pet = m_target->GetPet())
|
|
pet->Remove(PET_SAVE_AS_CURRENT);
|
|
|
|
WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
|
|
((Player*)m_target)->GetSession()->SendPacket(&data);
|
|
}
|
|
|
|
void Aura::HandleAuraConvertRune(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
if(m_target->GetTypeId() != TYPEID_PLAYER)
|
|
return;
|
|
|
|
Player *plr = (Player*)m_target;
|
|
|
|
if(plr->getClass() != CLASS_DEATH_KNIGHT)
|
|
return;
|
|
|
|
// how to determine what rune need to be converted?
|
|
for(uint32 i = 0; i < MAX_RUNES; ++i)
|
|
{
|
|
if(apply)
|
|
{
|
|
if(!plr->GetRuneCooldown(i))
|
|
{
|
|
plr->ConvertRune(i, GetSpellProto()->EffectMiscValueB[m_effIndex]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(plr->GetCurrentRune(i) == GetSpellProto()->EffectMiscValueB[m_effIndex])
|
|
{
|
|
plr->ConvertRune(i, plr->GetBaseRune(i));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Aura::HandlePhase(bool apply, bool Real)
|
|
{
|
|
if(!Real)
|
|
return;
|
|
|
|
// always non stackable
|
|
if(apply)
|
|
{
|
|
Unit::AuraList const& phases = m_target->GetAurasByType(SPELL_AURA_PHASE);
|
|
if(!phases.empty())
|
|
m_target->RemoveAurasDueToSpell(phases.front()->GetId(),this);
|
|
}
|
|
|
|
// no-phase is also phase state so same code for apply and remove
|
|
|
|
// phase auras normally not expected at BG but anyway better check
|
|
if(m_target->GetTypeId()==TYPEID_PLAYER)
|
|
{
|
|
// drop flag at invisible in bg
|
|
if(((Player*)m_target)->InBattleGround())
|
|
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
|
|
bg->EventPlayerDroppedFlag((Player*)m_target);
|
|
|
|
// GM-mode have mask 0xFFFFFFFF
|
|
if(!((Player*)m_target)->isGameMaster())
|
|
m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);
|
|
|
|
((Player*)m_target)->GetSession()->SendSetPhaseShift(apply ? GetMiscValue() : PHASEMASK_NORMAL);
|
|
}
|
|
else
|
|
m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);
|
|
|
|
// need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases)
|
|
if(m_target->GetVisibility()!=VISIBILITY_OFF)
|
|
m_target->SetVisibility(m_target->GetVisibility());
|
|
}
|
|
|