/*
* Copyright (C) 2005-2009 MaNGOS
*
* Copyright (C) 2008-2009 Trinity
*
* 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 "WorldPacket.h"
#include "Opcodes.h"
#include "Log.h"
#include "ObjectMgr.h"
#include "SpellMgr.h"
#include "Player.h"
#include "Unit.h"
#include "Spell.h"
#include "SpellAuraEffects.h"
#include "SpellId.h"
#include "DynamicObject.h"
#include "ObjectAccessor.h"
#include "Util.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
AuraApplication::AuraApplication(Unit * target, Unit * caster, Aura * aura)
: m_target(target), m_base(aura), m_slot(MAX_AURAS), m_flags(AFLAG_NONE), m_needClientUpdate(false), m_removeMode(AURA_REMOVE_NONE), m_canBeRemoved(false)
{
assert(GetTarget() && GetBase());
if(GetBase()->IsVisible())
{
// Try find slot for aura
uint8 slot = MAX_AURAS;
// Lookup for auras already applied from spell
if (AuraApplication * foundAura = m_target->GetAuraApplication(m_base->GetId(), m_base->GetCasterGUID()))
{
// allow use single slot only by auras from same caster
slot = foundAura->GetSlot();
}
else
{
Unit::VisibleAuraMap const * visibleAuras = m_target->GetVisibleAuras();
// lookup for free slots in units visibleAuras
Unit::VisibleAuraMap::const_iterator itr = visibleAuras->find(0);
for (uint32 freeSlot = 0; freeSlot < MAX_AURAS; ++itr , ++freeSlot)
{
if(itr == visibleAuras->end() || itr->first != freeSlot)
{
slot = freeSlot;
break;
}
}
}
// Register Visible Aura
if(slot < MAX_AURAS)
{
m_slot = slot;
m_target->SetVisibleAura(slot, this);
SetNeedClientUpdate();
sLog.outDebug("Aura: %u Effect: %d put to unit visible auras slot: %u", GetBase()->GetId(), GetEffectMask(), slot);
}
else
sLog.outDebug("Aura: %u Effect: %d could not find empty unit visible slot", GetBase()->GetId(), GetEffectMask());
}
m_flags |= (_CheckPositive(caster) ? AFLAG_POSITIVE : AFLAG_NEGATIVE) |
(GetBase()->GetCasterGUID() == GetTarget()->GetGUID() ? AFLAG_CASTER : AFLAG_NONE);
m_isNeedManyNegativeEffects = false;
if (GetBase()->GetCasterGUID() == GetTarget()->GetGUID()) // caster == target - 1 negative effect is enough for aura to be negative
m_isNeedManyNegativeEffects = false;
else if (caster)
m_isNeedManyNegativeEffects = caster->IsFriendlyTo(m_target);
}
void AuraApplication::_Remove()
{
uint8 slot = GetSlot();
if (slot >= MAX_AURAS)
return;
if (AuraApplication * foundAura = m_target->GetAuraApplication(GetBase()->GetId(), GetBase()->GetCasterGUID()))
{
// Reuse visible aura slot by aura which is still applied - prevent storing dead pointers
if (slot == foundAura->GetSlot())
{
if (GetTarget()->GetVisibleAura(slot) == this)
{
GetTarget()->SetVisibleAura(slot, foundAura);
foundAura->SetNeedClientUpdate();
}
// set not valid slot for aura - prevent removing other visible aura
slot = MAX_AURAS;
}
}
// update for out of range group members
if (slot < MAX_AURAS)
{
GetTarget()->RemoveVisibleAura(slot);
ClientUpdate(true);
}
}
bool AuraApplication::_CheckPositive(Unit * caster) const
{
// Aura is positive when it is casted by friend and at least one aura is positive
// or when it is casted by enemy and at least one aura is negative
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if((1<GetId(), i))
return m_isNeedManyNegativeEffects;
}
}
return !m_isNeedManyNegativeEffects;
}
void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
{
AuraEffect * aurEff = GetBase()->GetEffect(effIndex);
assert(aurEff);
assert(HasEffect(effIndex) == (!apply));
sLog.outDebug("AuraApplication::_HandleEffect: %u, apply: %u: amount: %u", aurEff->GetAuraType(), apply, aurEff->GetAmount());
Unit * caster = GetBase()->GetCaster();
m_flags &= ~(AFLAG_POSITIVE | AFLAG_NEGATIVE);
if (apply)
{
m_flags |= 1<_HandleAuraEffect(aurEff, true);
aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, true);
}
else
{
m_flags &= ~(1<_HandleAuraEffect(aurEff, false);
aurEff->HandleEffect(this, AURA_EFFECT_HANDLE_REAL, false);
// Remove all triggered by aura spells vs unlimited duration
aurEff->CleanupTriggeredSpells(GetTarget());
}
SetNeedClientUpdate();
}
void AuraApplication::ClientUpdate(bool remove)
{
m_needClientUpdate = false;
WorldPacket data(SMSG_AURA_UPDATE);
data.append(GetTarget()->GetPackGUID());
data << uint8(m_slot);
if(remove)
{
assert(!m_target->GetVisibleAura(m_slot));
data << uint32(0);
sLog.outDebug("Aura %u removed slot %u",GetBase()->GetId(), m_slot);
m_target->SendMessageToSet(&data, true);
return;
}
assert(m_target->GetVisibleAura(m_slot));
Aura const * aura = GetBase();
data << uint32(aura->GetId());
uint32 flags = m_flags;
if (aura->GetMaxDuration() > 0)
flags |= AFLAG_DURATION;
data << uint8(flags);
data << uint8(aura->GetCasterLevel());
data << uint8(aura->GetStackAmount() > 1 ? aura->GetStackAmount() : (aura->GetCharges()) ? aura->GetCharges() : 1);
if(!(flags & AFLAG_CASTER))
data.appendPackGUID(aura->GetCasterGUID());
if(flags & AFLAG_DURATION)
{
data << uint32(aura->GetMaxDuration());
data << uint32(aura->GetDuration());
}
m_target->SendMessageToSet(&data, true);
}
void AuraApplication::ConstructAuraInfo(ByteBuffer &data)
{
m_needClientUpdate = false;
data << uint8(m_slot);
if(!m_target->GetVisibleAura(m_slot))
{
data << uint32(0);
sLog.outDebug("Aura %u removed slot %u",GetBase()->GetId(), m_slot);
return;
}
Aura const * aura = GetBase();
data << uint32(aura->GetId());
uint32 flags = m_flags;
if (aura->GetMaxDuration() > 0)
flags |= AFLAG_DURATION;
data << uint8(flags);
data << uint8(aura->GetCasterLevel());
data << uint8(aura->GetStackAmount() > 1 ? aura->GetStackAmount() : (aura->GetCharges()) ? aura->GetCharges() : 1);
if(!(flags & AFLAG_CASTER))
data.appendPackGUID(aura->GetCasterGUID());
if(flags & AFLAG_DURATION)
{
data << uint32(aura->GetMaxDuration());
data << uint32(aura->GetDuration());
}
}
Aura * Aura::TryCreate(SpellEntry const* spellproto, uint8 tryEffMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
assert(spellproto);
assert(owner);
assert(caster || casterGUID);
assert(tryEffMask <= MAX_EFFECT_MASK);
uint8 effMask = 0;
switch(owner->GetTypeId())
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
for(uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
{
if (IsUnitOwnedAuraEffect(spellproto->Effect[i]))
effMask |= 1 << i;
}
break;
case TYPEID_DYNAMICOBJECT:
for(uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
{
if (spellproto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
effMask |= 1 << i;
}
break;
}
if (uint8 realMask = effMask & tryEffMask)
return Create(spellproto,realMask,owner,caster,baseAmount,castItem,casterGUID);
return NULL;
}
Aura * Aura::TryCreate(SpellEntry const* spellproto, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
assert(spellproto);
assert(owner);
assert(caster || casterGUID);
uint8 effMask = 0;
switch(owner->GetTypeId())
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
for(uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
{
if (IsUnitOwnedAuraEffect(spellproto->Effect[i]))
effMask |= 1 << i;
}
break;
case TYPEID_DYNAMICOBJECT:
for(uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i)
{
if (spellproto->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
effMask |= 1 << i;
}
break;
}
if (effMask)
return Create(spellproto,effMask,owner,caster,baseAmount,castItem,casterGUID);
return NULL;
}
Aura * Aura::Create(SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
{
assert(effMask);
assert(spellproto);
assert(owner);
assert(caster || casterGUID);
assert(effMask <= MAX_EFFECT_MASK);
// try to get caster of aura
if (casterGUID)
{
if (owner->GetGUID() == casterGUID)
caster = (Unit *)owner;
else
caster = ObjectAccessor::GetUnit(*owner, casterGUID);
}
Aura * aura = NULL;
switch(owner->GetTypeId())
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
aura = new UnitAura(spellproto,effMask,owner,caster,baseAmount,castItem, casterGUID);
break;
case TYPEID_DYNAMICOBJECT:
aura = new DynObjAura(spellproto,effMask,owner,caster,baseAmount,castItem, casterGUID);
break;
default:
assert(false);
return NULL;
}
// aura can be removed in Unit::_AddAura call
if (aura->IsRemoved())
return NULL;
return aura;
}
Aura::Aura(SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID) :
m_spellProto(spellproto), m_owner(owner), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()), m_castItemGuid(castItem ? castItem->GetGUID() : 0),
m_applyTime(time(NULL)), m_timeCla(0), m_isSingleTarget(false),
m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_casterLevel(caster ? caster->getLevel() : m_spellProto->spellLevel)
{
if(m_spellProto->manaPerSecond || m_spellProto->manaPerSecondPerLevel)
m_timeCla = 1 * IN_MILISECONDS;
Player* modOwner = NULL;
if (caster)
{
modOwner = caster->GetSpellModOwner();
m_maxDuration = caster->CalcSpellDuration(m_spellProto);
}
else
m_maxDuration = GetSpellDuration(m_spellProto);
if(IsPassive() && m_spellProto->DurationIndex == 0)
m_maxDuration = -1;
if(!IsPermanent() && modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxDuration);
m_duration = m_maxDuration;
m_procCharges = m_spellProto->procCharges;
if(modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
for (uint8 i=0 ; iGetGUID() == GetCasterGUID())
return GetUnitOwner();
if(AuraApplication const * aurApp = GetApplicationOfTarget(GetCasterGUID()))
return aurApp->GetTarget();
return ObjectAccessor::GetUnit(*GetOwner(), GetCasterGUID());
}
AuraObjectType Aura::GetType() const
{
return (m_owner->GetTypeId() == TYPEID_DYNAMICOBJECT) ? DYNOBJ_AURA_TYPE : UNIT_AURA_TYPE;
}
void Aura::_ApplyForTarget(Unit * target, Unit * caster, AuraApplication * auraApp)
{
assert(target);
assert(auraApp);
// aura mustn't be already applied
assert (m_applications.find(target->GetGUID()) == m_applications.end());
m_applications[target->GetGUID()] = auraApp;
// 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);
}
}
}
void Aura::_UnapplyForTarget(Unit * target, Unit * caster, AuraApplication * auraApp)
{
assert(target);
assert(auraApp->GetRemoveMode());
assert(auraApp);
ApplicationMap::iterator itr = m_applications.find(target->GetGUID());
// aura has to be already applied
assert(itr->second == auraApp);
m_applications.erase(itr);
m_removedApplications.push_back(auraApp);
// 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());
}
}
// removes aura from all targets
// and marks aura as removed
void Aura::_Remove(AuraRemoveMode removeMode)
{
assert (!m_isRemoved);
m_isRemoved = true;
for (ApplicationMap::iterator appItr = m_applications.begin() ; appItr != m_applications.end() ;)
{
AuraApplication * aurApp = appItr->second;
Unit * target = aurApp->GetTarget();
++appItr;
target->_UnapplyAura(aurApp, removeMode);
}
}
void Aura::UpdateTargetMap(Unit * caster)
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i] && !IsRemoved())
UpdateTargetMapForEffect(caster, i);
}
void Aura::UpdateOwner(uint32 diff, WorldObject * owner)
{
assert(owner == m_owner);
Unit * caster = GetCaster();
// Apply spellmods for channeled auras
// used for example when triggered spell of spell:10 is modded
Spell * modSpell = NULL;
Player * modOwner = NULL;
if(caster)
if ((modOwner = caster->GetSpellModOwner())
&& (modSpell = modOwner->FindCurrentSpellBySpellId(GetId())))
modOwner->SetSpellModTakingSpell(modSpell, true);
Update(diff, caster);
UpdateTargetMap(caster);
// update aura effects
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (m_effects[i])
m_effects[i]->Update(diff, caster);
// remove spellmods after effects update
if (modSpell)
modOwner->SetSpellModTakingSpell(modSpell, false);
_DeleteRemovedApplications();
}
void Aura::Update(uint32 diff, Unit * caster)
{
if (m_duration > 0)
{
m_duration -= diff;
if (m_duration < 0)
m_duration = 0;
// handle manaPerSecond/manaPerSecondPerLevel
if(m_timeCla)
{
if(m_timeCla > diff)
m_timeCla -= diff;
else if(caster)
{
if(int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel())
{
m_timeCla += 1000 - diff;
Powers powertype = Powers(m_spellProto->powerType);
if(powertype == POWER_HEALTH)
{
if (caster->GetHealth() > manaPerSecond)
caster->ModifyHealth(-manaPerSecond);
else
{
Remove();
return;
}
}
else
{
if (caster->GetPower(powertype) >= manaPerSecond)
caster->ModifyPower(powertype, -manaPerSecond);
else
{
Remove();
return;
}
}
}
}
}
}
}
void Aura::SetDuration(int32 duration, bool withMods)
{
if (withMods)
{
if (Unit * caster = GetCaster())
if (Player * modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, duration);
}
m_duration = duration;
SetNeedClientUpdateForTargets();
}
void Aura::RefreshDuration()
{
SetDuration(GetMaxDuration());
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i])
m_effects[i]->ResetPeriodic();
if(m_spellProto->manaPerSecond || m_spellProto->manaPerSecondPerLevel)
m_timeCla = 1 * IN_MILISECONDS;
}
void Aura::SetCharges(uint8 charges)
{
if (m_procCharges == charges)
return;
m_procCharges = charges;
SetNeedClientUpdateForTargets();
}
bool Aura::DropCharge()
{
if(m_procCharges) //auras without charges always have charge = 0
{
if(--m_procCharges) // Send charge change
SetNeedClientUpdateForTargets();
else // Last charge dropped
{
Remove(AURA_REMOVE_BY_EXPIRE);
return true;
}
}
return false;
}
void Aura::SetStackAmount(uint8 stackAmount, bool applied)
{
if (stackAmount != m_stackAmount)
{
m_stackAmount = stackAmount;
RecalculateAmountOfEffects();
}
SetNeedClientUpdateForTargets();
}
bool Aura::ModStackAmount(int32 num)
{
// Can`t mod
if (!m_spellProto->StackAmount || !GetStackAmount())
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
}
bool refresh = stackAmount >= GetStackAmount();
// Update stack amount
SetStackAmount(stackAmount);
if (refresh)
RefreshDuration();
SetNeedClientUpdateForTargets();
return false;
}
bool Aura::IsPassive() const
{
return IsPassiveSpell(GetSpellProto());
}
bool Aura::IsDeathPersistent() const
{
return IsDeathPersistentSpell(GetSpellProto());
}
bool Aura::CanBeSaved() const
{
if (IsPassive())
return false;
if (GetCasterGUID() != GetOwner()->GetGUID())
if (IsSingleTargetSpell(GetSpellProto()))
return false;
// Can't be saved - aura handler relies on calculated amount and changes it
if (HasEffectType(SPELL_AURA_CONVERT_RUNE))
return false;
return true;
}
bool Aura::HasEffectType(AuraType type) const
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if(m_effects[i] && m_effects[i]->GetAuraType() == type)
return true;
}
return false;
}
void Aura::RecalculateAmountOfEffects()
{
assert (!IsRemoved());
Unit * caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i])
m_effects[i]->RecalculateAmount(caster);
}
void Aura::HandleAllEffects(AuraApplication const * aurApp, uint8 mode, bool apply)
{
assert (!IsRemoved());
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i] && !IsRemoved())
m_effects[i]->HandleEffect(aurApp, mode, apply);
}
bool Aura::IsVisible() const
{
// Is this blizzlike? show totem passive auras
if (GetOwner()->GetTypeId() == TYPEID_UNIT && ((Creature*)m_owner)->isTotem() && IsPassive())
return true;
return !IsPassive() || HasEffectType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
}
void Aura::UnregisterSingleTarget()
{
assert(m_isSingleTarget);
Unit * caster = GetCaster();
caster->GetSingleCastAuras().remove(this);
SetIsSingleTarget(false);
}
void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint8 stackamount, uint8 recalculateMask, int32 * amount)
{
m_maxDuration = maxduration;
m_duration = duration;
m_procCharges = charges;
m_stackAmount = stackamount;
Unit * caster = GetCaster();
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i])
{
m_effects[i]->SetAmount(amount[i]);
m_effects[i]->SetCanBeRecalculated(recalculateMask & (1<CalculatePeriodic(caster);
m_effects[i]->CalculateSpellMod();
m_effects[i]->RecalculateAmount(caster);
}
}
// trigger effects on real aura apply/remove
void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply)
{
Unit * target = aurApp->GetTarget();
AuraRemoveMode removeMode = aurApp->GetRemoveMode();
// spell_area table
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone, area;
target->GetZoneAndAreaId(zone,area);
for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
// some auras remove at aura remove
if(!itr->second->IsFitToRequirements((Player*)target,zone,area))
target->RemoveAurasDueToSpell(itr->second->spellId);
// some auras applied at aura apply
else if(itr->second->autocast)
{
if( !target->HasAura(itr->second->spellId) )
target->CastSpell(target,itr->second->spellId,true);
}
}
}
// mods at aura apply
if (apply)
{
// Apply linked auras (On first aura apply)
if(spellmgr.GetSpellCustomAttr(GetId()) & SPELL_ATTR_CU_LINK_AURA)
{
if(const std::vector *spell_triggered = spellmgr.GetSpellLinked(GetId() + SPELL_LINK_AURA))
for (std::vector::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
{
if(*itr < 0)
target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), true);
else if(caster)
caster->AddAura(*itr, target);
}
}
switch (GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
switch(GetId())
{
case 32474: // Buffeting Winds of Susurrus
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->ActivateTaxiPathTo(506, GetId());
break;
case 33572: // Gronn Lord's Grasp, becomes stoned
if(GetStackAmount() >= 5 && !target->HasAura(33652))
target->CastSpell(target, 33652, true);
break;
case 60970: // Heroic Fury (remove Intercept cooldown)
if(target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->RemoveSpellCooldown(20252, true);
break;
}
break;
case SPELLFAMILY_MAGE:
if (!caster)
break;
if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000001 && GetSpellProto()->SpellFamilyFlags[2] & 0x00000008)
{
// Glyph of Fireball
if (caster->HasAura(56368))
SetDuration(0);
}
else if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000020 && GetSpellProto()->SpellVisual[0] == 13)
{
// Glyph of Frostbolt
if (caster->HasAura(56370))
SetDuration(0);
}
// Todo: This should be moved to similar function in spell::hit
else if (GetSpellProto()->SpellFamilyFlags[0] & 0x01000000)
{
// Polymorph Sound - Sheep && Penguin
if (GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978)
{
// Glyph of the Penguin
if (caster->HasAura(52648))
caster->CastSpell(target,61635,true);
else
caster->CastSpell(target,61634,true);
}
}
switch(GetId())
{
case 12536: // Clearcasting
case 12043: // Presence of Mind
// Arcane Potency
if (AuraEffect const * aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_MAGE, 2120, 0))
{
if (roll_chance_i(aurEff->GetAmount()))
{
uint32 spellId = 0;
switch (aurEff->GetId())
{
case 31571: spellId = 57529; break;
case 31572: spellId = 57531; break;
default:
sLog.outError("Aura::HandleAuraSpecificMods: Unknown rank of Arcane Potency (%d) found", aurEff->GetId());
}
if(spellId)
caster->CastSpell(caster, spellId, true);
}
}
break;
}
break;
case SPELLFAMILY_WARLOCK:
switch(GetId())
{
case 48020: // Demonic Circle
if(target->GetTypeId() == TYPEID_PLAYER)
if(GameObject* obj = target->GetGameObject(48018))
((Player*)target)->TeleportTo(obj->GetMapId(),obj->GetPositionX(),obj->GetPositionY(),obj->GetPositionZ(),obj->GetOrientation());
break;
}
break;
case SPELLFAMILY_PRIEST:
if (!caster)
break;
// Devouring Plague
if (GetSpellProto()->SpellFamilyFlags[0] & 0x02000000 && GetEffect(0))
{
// Improved Devouring Plague
if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3790, 1))
{
int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * GetEffect(0)->GetAmount() / 100;
caster->CastCustomSpell(target, 63675, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
}
}
// Renew
else if (GetSpellProto()->SpellFamilyFlags[0] & 0x00000040 && GetEffect(0))
{
// Empowered Renew
if (AuraEffect const * aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 3021, 1))
{
int32 basepoints0 = aurEff->GetAmount() * GetEffect(0)->GetTotalTicks() * caster->SpellHealingBonus(target, GetSpellProto(), GetEffect(0)->GetAmount(), HEAL) / 100;
caster->CastCustomSpell(target, 63544, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
}
}
// Power Word: Shield
else if (m_spellProto->SpellFamilyFlags[0] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x400 && GetEffect(0))
{
// Glyph of Power Word: Shield
if (AuraEffect* glyph = caster->GetAuraEffect(55672,0))
{
// instantly heal m_amount% of the absorb-value
int32 heal = glyph->GetAmount() * GetEffect(0)->GetAmount()/100;
caster->CastCustomSpell(GetUnitOwner(), 56160, &heal, NULL, NULL, true, 0, GetEffect(0));
}
}
break;
case SPELLFAMILY_ROGUE:
// Sprint (skip non player casted spells by category)
if(GetSpellProto()->SpellFamilyFlags[0] & 0x40 && GetSpellProto()->Category == 44)
// in official maybe there is only one icon?
if(target->HasAura(58039)) // Glyph of Blurred Speed
target->CastSpell(target, 61922, true); // Sprint (waterwalk)
break;
case SPELLFAMILY_DEATHKNIGHT:
if (!caster)
break;
// Frost Fever and Blood Plague
if(GetSpellProto()->SpellFamilyFlags[2] & 0x2)
{
// Can't proc on self
if (GetCasterGUID() == target->GetGUID())
break;
AuraEffect * aurEff = NULL;
// Ebon Plaguebringer / Crypt Fever
Unit::AuraEffectList const& TalentAuras = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for (Unit::AuraEffectList::const_iterator itr = TalentAuras.begin(); itr != TalentAuras.end(); ++itr)
{
if ((*itr)->GetMiscValue() == 7282)
{
aurEff = *itr;
// Ebon Plaguebringer - end search if found
if ((*itr)->GetSpellProto()->SpellIconID == 1766)
break;
}
}
if (aurEff)
{
uint32 spellId = 0;
switch (aurEff->GetId())
{
// Ebon Plague
case 51161: spellId = 51735; break;
case 51160: spellId = 51734; break;
case 51099: spellId = 51726; break;
// Crypt Fever
case 49632: spellId = 50510; break;
case 49631: spellId = 50509; break;
case 49032: spellId = 50508; break;
default:
sLog.outError("Aura::HandleAuraSpecificMods: Unknown rank of Crypt Fever/Ebon Plague (%d) found", aurEff->GetId());
}
caster->CastSpell(target, spellId, true, 0, GetEffect(0));
}
}
break;
}
}
// mods at aura remove
else
{
// Remove Linked Auras
if(removeMode != AURA_REMOVE_BY_STACK && removeMode != AURA_REMOVE_BY_DEATH)
{
if(uint32 customAttr = spellmgr.GetSpellCustomAttr(GetId()))
{
if(customAttr & SPELL_ATTR_CU_LINK_REMOVE)
{
if(const std::vector *spell_triggered = spellmgr.GetSpellLinked(-(int32)GetId()))
for (std::vector::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
{
if(*itr < 0)
target->RemoveAurasDueToSpell(-(*itr));
else if (removeMode != AURA_REMOVE_BY_DEFAULT)
target->CastSpell(target, *itr, true, 0, 0, GetCasterGUID());
}
}
if(customAttr & SPELL_ATTR_CU_LINK_AURA)
{
if(const std::vector *spell_triggered = spellmgr.GetSpellLinked(GetId() + SPELL_LINK_AURA))
for (std::vector::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
{
if(*itr < 0)
target->ApplySpellImmune(GetId(), IMMUNITY_ID, -(*itr), false);
else
target->RemoveAurasDueToSpell(*itr);
}
}
}
}
switch(GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_MAGE:
switch(GetId())
{
case 66: // Invisibility
if (removeMode != AURA_REMOVE_BY_EXPIRE)
break;
target->CastSpell(target, 32612, true, NULL, GetEffect(1));
break;
}
if (!caster)
break;
// Ice barrier - dispel/absorb remove
if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellProto()->SpellFamilyFlags[1] & 0x1)
{
// Shattered Barrier
if (caster->GetDummyAuraEffect(SPELLFAMILY_MAGE, 2945, 0))
caster->CastSpell(target, 55080, true, NULL, GetEffect(0));
}
break;
case SPELLFAMILY_WARRIOR:
if (!caster)
break;
// Spell Reflection
if (GetSpellProto()->SpellFamilyFlags[1] & 0x2)
{
if (removeMode != AURA_REMOVE_BY_DEFAULT)
{
// Improved Spell Reflection
if (caster->GetDummyAuraEffect(SPELLFAMILY_WARRIOR,1935, 1))
{
// aura remove - remove auras from all party members
std::list PartyMembers;
target->GetPartyMembers(PartyMembers);
for (std::list::iterator itr = PartyMembers.begin(); itr!=PartyMembers.end(); ++itr)
{
if ((*itr)!= target)
(*itr)->RemoveAurasWithFamily(SPELLFAMILY_WARRIOR, 0, 0x2, 0, GetCasterGUID());
}
}
}
}
break;
case SPELLFAMILY_WARLOCK:
if (!caster)
break;
// Curse of Doom
if (GetSpellProto()->SpellFamilyFlags[1] & 0x02)
{
if (removeMode == AURA_REMOVE_BY_DEATH)
{
if (caster->GetTypeId() == TYPEID_PLAYER && ((Player*)caster)->isHonorOrXPTarget(target))
caster->CastSpell(target, 18662, true, NULL, GetEffect(0));
}
}
// Improved Fear
else if (GetSpellProto()->SpellFamilyFlags[1] & 0x00000400)
{
if (caster->GetTypeId() == TYPEID_UNIT)
{
if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_WARLOCK, 98, 0))
{
uint32 spellId = 0;
switch (aurEff->GetId())
{
case 53759: spellId = 60947; break;
case 53754: spellId = 60946; break;
default:
sLog.outError("Aura::HandleAuraSpecificMods: Unknown rank of Improved Fear (%d) found", aurEff->GetId());
}
if (spellId)
caster->CastSpell(caster, spellId, true);
}
}
}
switch(GetId())
{
case 48018: // Demonic Circle
// Do not remove GO when aura is removed by stack
// to prevent remove GO added by new spell
// old one is already removed
if (removeMode!=AURA_REMOVE_BY_STACK)
target->RemoveGameObject(GetId(), true);
target->RemoveAura(62388);
break;
}
break;
case SPELLFAMILY_PRIEST:
if (!caster)
break;
// Shadow word: Pain // Vampiric Touch
if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && (GetSpellProto()->SpellFamilyFlags[0] & 0x00008000 || GetSpellProto()->SpellFamilyFlags[1] & 0x00000400))
{
// Shadow Affinity
if (AuraEffect const * aurEff = target->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 178, 1))
{
int32 basepoints0 = aurEff->GetAmount() * target->GetCreateMana() / 100;
caster->CastCustomSpell(caster, 64103, &basepoints0, NULL, NULL, true, NULL, GetEffect(0));
}
}
// Power word: shield
else if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellProto()->SpellFamilyFlags[0] & 0x00000001)
{
// Rapture
if (Aura const * aura = caster->GetAuraOfRankedSpell(47535))
{
// check cooldown
if (caster->GetTypeId() == TYPEID_PLAYER)
{
if (((Player*)caster)->HasSpellCooldown(aura->GetId()))
break;
// and add if needed
((Player*)caster)->AddSpellCooldown(aura->GetId(), 0, uint32(time(NULL) + 12));
}
// effect on caster
if (AuraEffect const * aurEff = aura->GetEffect(0))
{
float multiplier = aurEff->GetAmount();
if (aurEff->GetId() == 47535)
multiplier -= 0.5f;
else if (aurEff->GetId() == 47537)
multiplier += 0.5f;
int32 basepoints0 = (multiplier * caster->GetMaxPower(POWER_MANA) / 100);
caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true);
}
// effect on aura target
if (AuraEffect const * aurEff = aura->GetEffect(1))
{
if (!roll_chance_i(aurEff->GetAmount()))
break;
int32 triggeredSpellId = 0;
switch(target->getPowerType())
{
case POWER_MANA:
{
int32 basepoints0 = 2 * (target->GetMaxPower(POWER_MANA) / 100);
caster->CastCustomSpell(target, 63654, &basepoints0, NULL, NULL, true);
break;
}
case POWER_RAGE: triggeredSpellId = 63653; break;
case POWER_ENERGY: triggeredSpellId = 63655; break;
case POWER_RUNIC_POWER: triggeredSpellId = 63652; break;
}
if (triggeredSpellId)
caster->CastSpell(target, triggeredSpellId, true);
}
}
}
switch(GetId())
{
case 47788: // Guardian Spirit
if (removeMode != AURA_REMOVE_BY_EXPIRE)
break;
if(caster->GetTypeId() != TYPEID_PLAYER)
break;
Player *player = ((Player*)caster);
// Glyph of Guardian Spirit
if(AuraEffect * aurEff = player->GetAuraEffect(63231, 0))
{
if (!player->HasSpellCooldown(47788))
break;
player->RemoveSpellCooldown(GetSpellProto()->Id, true);
player->AddSpellCooldown(GetSpellProto()->Id, 0, uint32(time(NULL) + aurEff->GetAmount()));
WorldPacket data(SMSG_SPELL_COOLDOWN, 8+1+4+4);
data << uint64(player->GetGUID());
data << uint8(0x0); // flags (0x1, 0x2)
data << uint32(GetSpellProto()->Id);
data << uint32(aurEff->GetAmount()*IN_MILISECONDS);
player->SendDirectMessage(&data);
}
break;
}
break;
case SPELLFAMILY_DEATHKNIGHT:
switch(GetId())
{
case 50514: // Summon Gargoyle
if (removeMode != AURA_REMOVE_BY_EXPIRE)
break;
target->CastSpell(target, GetEffect(0)->GetAmount(), true, NULL, GetEffect(0));
break;
}
break;
}
}
// mods at aura apply or remove
switch (GetSpellProto()->SpellFamilyName)
{
case SPELLFAMILY_ROGUE:
// Stealth
if (GetSpellProto()->SpellFamilyFlags[0] & 0x00400000)
{
// Master of subtlety
if (AuraEffect const * aurEff = target->GetAuraEffectOfRankedSpell(31221, 0))
{
if (!apply)
target->CastSpell(target,31666,true);
else
{
int32 basepoints0 = aurEff->GetAmount();
target->CastCustomSpell(target,31665, &basepoints0, NULL, NULL ,true);
}
}
// Overkill
if (target->HasAura(58426))
{
if (!apply)
target->CastSpell(target,58428,true);
else
target->CastSpell(target,58427,true);
}
break;
}
break;
case SPELLFAMILY_HUNTER:
switch(GetId())
{
case 19574: // Bestial Wrath
// The Beast Within cast on owner if talent present
if ( Unit* owner = target->GetOwner() )
{
// Search talent
if (owner->HasAura(34692))
{
if (apply)
owner->CastSpell(owner, 34471, true, 0, GetEffect(0));
else
owner->RemoveAurasDueToSpell(34471);
}
}
break;
}
break;
case SPELLFAMILY_PALADIN:
switch(GetId())
{
case 19746:
case 31821:
// Aura Mastery Triggered Spell Handler
// If apply Concentration Aura -> trigger -> apply Aura Mastery Immunity
// If remove Concentration Aura -> trigger -> remove Aura Mastery Immunity
// If remove Aura Mastery -> trigger -> remove Aura Mastery Immunity
// Do effects only on aura owner
if (GetCasterGUID() != target->GetGUID())
break;
if (apply)
{
if ((GetSpellProto()->Id == 31821 && target->HasAura(19746, GetCasterGUID())) || (GetSpellProto()->Id == 19746 && target->HasAura(31821)))
target->CastSpell(target,64364,true);
}
else
target->RemoveAurasDueToSpell(64364, GetCasterGUID());
break;
}
break;
case SPELLFAMILY_DEATHKNIGHT:
if (GetSpellSpecific(GetId()) == SPELL_SPECIFIC_PRESENCE)
{
AuraEffect *bloodPresenceAura=0; // healing by damage done
AuraEffect *frostPresenceAura=0; // increased health
AuraEffect *unholyPresenceAura=0; // increased movement speed, faster rune recovery
// Improved Presences
Unit::AuraEffectList const& vDummyAuras = target->GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (Unit::AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
{
switch((*itr)->GetId())
{
// Improved Blood Presence
case 50365:
case 50371:
{
bloodPresenceAura = (*itr);
break;
}
// Improved Frost Presence
case 50384:
case 50385:
{
frostPresenceAura = (*itr);
break;
}
// Improved Unholy Presence
case 50391:
case 50392:
{
unholyPresenceAura = (*itr);
break;
}
}
}
uint32 presence=GetId();
if (apply)
{
// Blood Presence bonus
if (presence == SPELL_BLOOD_PRESENCE_48266)
target->CastSpell(target,63611,true);
else if (bloodPresenceAura)
{
int32 basePoints1=bloodPresenceAura->GetAmount();
target->CastCustomSpell(target,63611,NULL,&basePoints1,NULL,true,0,bloodPresenceAura);
}
// Frost Presence bonus
if (presence == SPELL_FROST_PRESENCE_48263)
target->CastSpell(target,61261,true);
else if (frostPresenceAura)
{
int32 basePoints0=frostPresenceAura->GetAmount();
target->CastCustomSpell(target,61261,&basePoints0,NULL,NULL,true,0,frostPresenceAura);
}
// Unholy Presence bonus
if (presence == SPELL_UNHOLY_PRESENCE_48265)
{
if(unholyPresenceAura)
{
// Not listed as any effect, only base points set
int32 basePoints0 = unholyPresenceAura->GetSpellProto()->EffectBasePoints[1];
//target->CastCustomSpell(target,63622,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura);
target->CastCustomSpell(target,65095,&basePoints0 ,NULL,NULL,true,0,unholyPresenceAura);
}
target->CastSpell(target,49772, true);
}
else if (unholyPresenceAura)
{
int32 basePoints0=unholyPresenceAura->GetAmount();
target->CastCustomSpell(target,49772,&basePoints0,NULL,NULL,true,0,unholyPresenceAura);
}
}
else
{
// Remove passive auras
if (presence == SPELL_BLOOD_PRESENCE_48266 || bloodPresenceAura)
target->RemoveAurasDueToSpell(63611);
if (presence == SPELL_FROST_PRESENCE_48263 || frostPresenceAura)
target->RemoveAurasDueToSpell(61261);
if (presence == SPELL_UNHOLY_PRESENCE_48265 || unholyPresenceAura)
{
if(presence == SPELL_UNHOLY_PRESENCE_48265 && unholyPresenceAura)
{
//target->RemoveAurasDueToSpell(63622);
target->RemoveAurasDueToSpell(65095);
}
target->RemoveAurasDueToSpell(49772);
}
}
}
break;
}
}
void Aura::SetNeedClientUpdateForTargets() const
{
for (ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
appIter->second->SetNeedClientUpdate();
}
void Aura::_DeleteRemovedApplications()
{
while(!m_removedApplications.empty())
{
delete m_removedApplications.front();
m_removedApplications.pop_front();
}
}
UnitAura::UnitAura(SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
: Aura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID)
{
m_AuraDRGroup = DIMINISHING_NONE;
GetUnitOwner()->_AddAura(this, caster);
};
void UnitAura::_ApplyForTarget(Unit * target, Unit * caster, AuraApplication * aurApp)
{
Aura::_ApplyForTarget(target, caster, aurApp);
// register aura diminishing on apply
if (DiminishingGroup group = GetDiminishGroup())
target->ApplyDiminishingAura(group,true);
}
void UnitAura::_UnapplyForTarget(Unit * target, Unit * caster, AuraApplication * aurApp)
{
Aura::_UnapplyForTarget(target, caster, aurApp);
// unregister aura diminishing (and store last time)
if (DiminishingGroup group = GetDiminishGroup())
target->ApplyDiminishingAura(group,false);
}
void UnitAura::Remove(AuraRemoveMode removeMode)
{
if (IsRemoved())
return;
GetUnitOwner()->RemoveOwnedAura(this, removeMode);
}
void UnitAura::UpdateTargetMapForEffect(Unit * caster, uint8 effIndex)
{
if (GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AURA)
{
AuraApplication * aurApp = GetApplicationOfTarget(GetOwner()->GetGUID());
if (!aurApp || !aurApp->HasEffect(effIndex))
GetUnitOwner()->_ApplyAuraEffect(this, effIndex);
return;
}
float radius;
if (GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY)
radius = GetSpellRadiusForHostile(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[effIndex]));
else
radius = GetSpellRadiusForFriend(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[effIndex]));
if (caster)
if(Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius);
// fill up to date target list
UnitList targets;
if (!GetUnitOwner()->hasUnitState(UNIT_STAT_ISOLATED))
{
switch(GetSpellProto()->Effect[effIndex])
{
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
targets.push_back(GetUnitOwner());
GetUnitOwner()->GetPartyMemberInDist(targets, radius);
break;
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
targets.push_back(GetUnitOwner());
GetUnitOwner()->GetRaidMember(targets, radius);
break;
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
{
targets.push_back(GetUnitOwner());
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
Trinity::UnitListSearcher searcher(GetUnitOwner(), targets, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
{
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); // No GetCharmer in searcher
Trinity::UnitListSearcher searcher(GetUnitOwner(), targets, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
targets.push_back(GetUnitOwner());
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
{
if(Unit *owner = GetUnitOwner()->GetCharmerOrOwner())
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
targets.push_back(owner);
break;
}
}
}
// mark all auras as ready to remove
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); appIter++)
if (appIter->second->HasEffect(effIndex))
appIter->second->_SetCanBeRemoved(true);
for (UnitList::iterator appIter = targets.begin(); appIter != targets.end(); appIter++)
{
// add an aura to units new in list
ApplicationMap::iterator itr = m_applications.find((*appIter)->GetGUID());
if (itr == m_applications.end())
{
// check target immunities
if ((*appIter)->IsImmunedToSpell(GetSpellProto())
|| (*appIter)->hasUnitState(UNIT_STAT_ISOLATED))
continue;
// Allow to remove by stack when aura is going to be applied on owner
if (*appIter != GetOwner())
{
bool addUnit = true;
// check if not stacking aura already on target
// this one prevents unwanted usefull buff loss because of stacking and prevents overriding auras periodicaly by 2 near area aura owners
for (Unit::AuraApplicationMap::iterator iter = (*appIter)->GetAppliedAuras().begin(); iter != (*appIter)->GetAppliedAuras().end(); ++iter)
{
Aura const * aura = iter->second->GetBase();
if(!spellmgr.CanAurasStack(GetSpellProto(), aura->GetSpellProto(), aura->GetCasterGUID() == GetCasterGUID()))
{
addUnit = false;
break;
}
}
if (!addUnit)
continue;
}
}
if (itr == m_applications.end() || !itr->second->HasEffect(effIndex))
{
if((*appIter)->IsImmunedToSpellEffect(GetSpellProto(), effIndex))
continue;
// add new unit to persistent area aura
(*appIter)->_ApplyAuraEffect(this, effIndex);
// start combat with targeted enemy
if(GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AREA_AURA_ENEMY)
GetUnitOwner()->CombatStart(*appIter);
}
itr = m_applications.find((*appIter)->GetGUID());
if (itr != m_applications.end())
// mark aura of unit already in list to be not removed
itr->second->_SetCanBeRemoved(false);
}
// remove auras which are not in current area
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();)
{
AuraApplication * aurApp = appIter->second;
++appIter;
if (aurApp->_CanBeRemoved())
aurApp->GetTarget()->_UnapplyAuraEffect(aurApp, effIndex, AURA_REMOVE_BY_DEFAULT);
}
}
DynObjAura::DynObjAura(SpellEntry const* spellproto, uint8 effMask, WorldObject * owner, Unit * caster, int32 *baseAmount, Item * castItem, uint64 casterGUID)
: Aura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID)
{
GetDynobjOwner()->SetAura(this);
}
void DynObjAura::Remove(AuraRemoveMode removeMode)
{
if (IsRemoved())
return;
_Remove(removeMode);
}
void DynObjAura::UpdateTargetMapForEffect(Unit * caster, uint8 effIndex)
{
float radius = GetDynobjOwner()->GetRadius();
// fill up to date target list
UnitList targets;
Unit * dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
if(GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_DEST_DYNOBJ_ALLY
|| GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_UNIT_AREA_ALLY_DST)
{
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher searcher(GetDynobjOwner(), targets, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
else
{
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher searcher(GetDynobjOwner(), targets, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
// mark all auras as ready to remove
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); appIter++)
if (appIter->second->HasEffect(effIndex))
appIter->second->_SetCanBeRemoved(true);
for (UnitList::iterator appIter = targets.begin(); appIter != targets.end(); appIter++)
{
// add an aura to units new in list
ApplicationMap::iterator itr = m_applications.find((*appIter)->GetGUID());
if (itr == m_applications.end())
{
// persistent area aura does not hit flying targets
if ((*appIter)->isInFlight()
// check target immunities
|| (*appIter)->IsImmunedToSpell(GetSpellProto())
|| (*appIter)->hasUnitState(UNIT_STAT_ISOLATED))
continue;
}
if (itr == m_applications.end() || !itr->second->HasEffect(effIndex))
{
if((*appIter)->IsImmunedToSpellEffect(GetSpellProto(), effIndex))
continue;
// add new unit to persistent area aura
(*appIter)->_ApplyAuraEffect(this, effIndex);
// start combat with targeted enemy
if(GetSpellProto()->EffectImplicitTargetB[effIndex] != TARGET_DEST_DYNOBJ_ALLY
&& GetSpellProto()->EffectImplicitTargetB[effIndex] != TARGET_UNIT_AREA_ALLY_DST)
dynObjOwnerCaster->CombatStart(*appIter);
}
itr = m_applications.find((*appIter)->GetGUID());
if (itr != m_applications.end())
// mark aura of unit already in list to be not removed
itr->second->_SetCanBeRemoved(false);
}
// remove auras which are not in current area
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();)
{
AuraApplication * aurApp = appIter->second;
++appIter;
if (aurApp->_CanBeRemoved())
aurApp->GetTarget()->_UnapplyAuraEffect(aurApp, effIndex, AURA_REMOVE_BY_DEFAULT);
}
}