*Do not keep area aura targets in combat with aura owner

*Add some safety checks to area aura target map update.

--HG--
branch : trunk
This commit is contained in:
QAston
2010-01-24 13:08:25 +01:00
parent 79accd730e
commit d1a40eb688
7 changed files with 287 additions and 254 deletions
+1
View File
@@ -1404,6 +1404,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool
if(aurSpellInfo->SpellFamilyFlags[1] & 0x000020)
m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);
}
m_spellAura->_RegisterForTargets();
}
}
}
+1 -1
View File
@@ -386,7 +386,7 @@ void AuraEffect::GetTargetList(std::list<Unit *> & targetList) const
{
Aura::ApplicationMap const & targetMap = GetBase()->GetApplicationMap();
// remove all targets which were not added to new list - they no longer deserve area aura
for (Aura::ApplicationMap::const_iterator appIter = targetMap.begin(); appIter != targetMap.end(); appIter++)
for (Aura::ApplicationMap::const_iterator appIter = targetMap.begin(); appIter != targetMap.end(); ++appIter)
{
if(appIter->second->HasEffect(GetEffIndex()))
targetList.push_back(appIter->second->GetTarget());
+203 -171
View File
@@ -36,8 +36,9 @@
#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)
AuraApplication::AuraApplication(Unit * target, Unit * caster, Aura * aura, uint8 effMask)
: m_target(target), m_base(aura), m_slot(MAX_AURAS), m_flags(AFLAG_NONE), m_needClientUpdate(false)
, m_removeMode(AURA_REMOVE_NONE), m_effectsToApply(effMask)
{
assert(GetTarget() && GetBase());
@@ -138,6 +139,7 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
AuraEffect * aurEff = GetBase()->GetEffect(effIndex);
assert(aurEff);
assert(HasEffect(effIndex) == (!apply));
assert((1<<effIndex) & m_effectsToApply);
sLog.outDebug("AuraApplication::_HandleEffect: %u, apply: %u: amount: %u", aurEff->GetAuraType(), apply, aurEff->GetAmount());
Unit * caster = GetBase()->GetCaster();
@@ -451,14 +453,129 @@ void Aura::_Remove(AuraRemoveMode removeMode)
}
}
void Aura::UpdateTargetMap(Unit * caster)
void Aura::UpdateTargetMap(Unit * caster, bool apply)
{
m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if(m_effects[i] && !IsRemoved())
UpdateTargetMapForEffect(caster, i);
// fill up to date target list
// target, effMask
std::map<Unit *, uint8> targets;
FillTargetMap(targets, caster);
UnitList targetsToRemove;
// mark all auras as ready to remove
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();++appIter)
{
std::map<Unit *, uint8>::iterator existing = targets.find(appIter->second->GetTarget());
// not found in current area - remove the aura
if (existing == targets.end())
targetsToRemove.push_back(appIter->second->GetTarget());
else
{
// needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
if (appIter->second->GetEffectMask() != existing->second)
targetsToRemove.push_back(appIter->second->GetTarget());
// nothing todo - aura already applied
// remove from auras to register list
targets.erase(existing);
}
}
// register auras for units
for (std::map<Unit *, uint8>::iterator itr = targets.begin(); itr!= targets.end();)
{
bool addUnit = true;
// check target immunities
if (itr->first->IsImmunedToSpell(GetSpellProto()))
addUnit = false;
if (addUnit)
{
// persistent area aura does not hit flying targets
if (GetType() == DYNOBJ_AURA_TYPE)
{
if (itr->first->isInFlight())
addUnit = false;
}
// unit auras can not stack with each other
else // (GetType() == UNIT_AURA_TYPE)
{
// Allow to remove by stack when aura is going to be applied on owner
if (itr->first != GetOwner())
{
// 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 = itr->first->GetAppliedAuras().begin(); iter != itr->first->GetAppliedAuras().end(); ++iter)
{
Aura const * aura = iter->second->GetBase();
if(!spellmgr.CanAurasStack(GetSpellProto(), aura->GetSpellProto(), aura->GetCasterGUID() == GetCasterGUID()))
{
addUnit = false;
break;
}
}
}
}
}
if (!addUnit)
targets.erase(itr++);
else
{
// owner has to be in world, or effect has to be applied to self
assert((!GetOwner()->IsInWorld() && GetOwner() == itr->first) || GetOwner()->IsInMap(itr->first));
itr->first->_CreateAuraApplication(this, itr->second);
++itr;
}
}
// remove auras from units no longer needing them
for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end();++itr)
{
if (AuraApplication * aurApp = GetApplicationOfTarget((*itr)->GetGUID()))
(*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
}
if (!apply)
return;
// apply aura effects for units
for (std::map<Unit *, uint8>::iterator itr = targets.begin(); itr!= targets.end();++itr)
{
if (AuraApplication * aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
{
// owner has to be in world, or effect has to be applied to self
assert((!GetOwner()->IsInWorld() && GetOwner() == itr->first) || GetOwner()->IsInMap(itr->first));
itr->first->_ApplyAura(aurApp, itr->second);
}
}
}
// targets have to be registered and not have effect applied yet to use this function
void Aura::_ApplyEffectForTargets(uint8 effIndex)
{
Unit * caster = GetCaster();
// prepare list of aura targets
UnitList targetList;
for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter)
{
if ((appIter->second->GetEffectsToApply() & (1<<effIndex)) && !appIter->second->HasEffect(effIndex))
targetList.push_back(appIter->second->GetTarget());
}
// apply effect to targets
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
{
if (GetApplicationOfTarget((*itr)->GetGUID()))
{
// owner has to be in world, or effect has to be applied to self
assert((!GetOwner()->IsInWorld() && GetOwner() == *itr) || GetOwner()->IsInMap(*itr));
(*itr)->_ApplyAuraEffect(this, effIndex);
}
}
}
void Aura::UpdateOwner(uint32 diff, WorldObject * owner)
{
assert(owner == m_owner);
@@ -1370,130 +1487,81 @@ void UnitAura::Remove(AuraRemoveMode removeMode)
GetUnitOwner()->RemoveOwnedAura(this, removeMode);
}
void UnitAura::UpdateTargetMapForEffect(Unit * caster, uint8 effIndex)
void UnitAura::FillTargetMap(std::map<Unit *, uint8> & targets, Unit * caster)
{
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]));
Player * modOwner = NULL;
if (caster)
if(Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius);
modOwner = caster->GetSpellModOwner();
// fill up to date target list
UnitList targets;
if (!GetUnitOwner()->hasUnitState(UNIT_STAT_ISOLATED))
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS ; ++effIndex)
{
switch(GetSpellProto()->Effect[effIndex])
if (!HasEffect(effIndex))
continue;
UnitList targetList;
// non-area aura
if (GetSpellProto()->Effect[effIndex] == SPELL_EFFECT_APPLY_AURA)
{
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<Trinity::AnyFriendlyUnitInObjectRangeCheck> 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<Trinity::AnyAoETargetUnitInObjectRangeCheck> 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;
}
targetList.push_back(GetUnitOwner());
}
}
// 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())
else
{
// check target immunities
if ((*appIter)->IsImmunedToSpell(GetSpellProto())
|| (*appIter)->hasUnitState(UNIT_STAT_ISOLATED))
continue;
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]));
// Allow to remove by stack when aura is going to be applied on owner
if (*appIter != GetOwner())
if (modOwner)
modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, radius);
if (!GetUnitOwner()->hasUnitState(UNIT_STAT_ISOLATED))
{
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)
switch(GetSpellProto()->Effect[effIndex])
{
Aura const * aura = iter->second->GetBase();
if(!spellmgr.CanAurasStack(GetSpellProto(), aura->GetSpellProto(), aura->GetCasterGUID() == GetCasterGUID()))
case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
targetList.push_back(GetUnitOwner());
GetUnitOwner()->GetPartyMemberInDist(targetList, radius);
break;
case SPELL_EFFECT_APPLY_AREA_AURA_RAID:
targetList.push_back(GetUnitOwner());
GetUnitOwner()->GetRaidMember(targetList, radius);
break;
case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
{
addUnit = false;
targetList.push_back(GetUnitOwner());
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius);
Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, 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<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetUnitOwner(), targetList, u_check);
GetUnitOwner()->VisitNearbyObject(radius, searcher);
break;
}
case SPELL_EFFECT_APPLY_AREA_AURA_PET:
targetList.push_back(GetUnitOwner());
case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
{
if(Unit *owner = GetUnitOwner()->GetCharmerOrOwner())
if (GetUnitOwner()->IsWithinDistInMap(owner, radius))
targetList.push_back(owner);
break;
}
}
if (!addUnit)
continue;
}
}
if (itr == m_applications.end() || !itr->second->HasEffect(effIndex))
for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr)
{
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);
std::map<Unit *, uint8>::iterator existing = targets.find(*itr);
if (existing != targets.end())
existing->second |= 1<<effIndex;
else
targets[*itr] = 1<<effIndex;
}
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);
}
}
@@ -1510,74 +1578,38 @@ void DynObjAura::Remove(AuraRemoveMode removeMode)
_Remove(removeMode);
}
void DynObjAura::UpdateTargetMapForEffect(Unit * caster, uint8 effIndex)
void DynObjAura::FillTargetMap(std::map<Unit *, uint8> & targets, Unit * caster)
{
Unit * dynObjOwnerCaster = GetDynobjOwner()->GetCaster();
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)
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targets, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
else
{
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> 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())
if (!HasEffect(effIndex))
continue;
UnitList targetList;
if(GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_DEST_DYNOBJ_ALLY
|| GetSpellProto()->EffectImplicitTargetB[effIndex] == TARGET_UNIT_AREA_ALLY_DST)
{
// persistent area aura does not hit flying targets
if ((*appIter)->isInFlight()
// check target immunities
|| (*appIter)->IsImmunedToSpell(GetSpellProto())
|| (*appIter)->hasUnitState(UNIT_STAT_ISOLATED))
continue;
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
else
{
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
GetDynobjOwner()->VisitNearbyObject(radius, searcher);
}
if (itr == m_applications.end() || !itr->second->HasEffect(effIndex))
for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr)
{
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);
std::map<Unit *, uint8>::iterator existing = targets.find(*itr);
if (existing != targets.end())
existing->second |= 1<<effIndex;
else
targets[*itr] = 1<<effIndex;
}
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);
}
}
+14 -13
View File
@@ -38,27 +38,26 @@ class DynamicObject;
class AuraApplication
{
friend AuraApplication * Unit::__ApplyAura(Aura * aura);
friend void Unit::__UnapplyAura(AuraApplicationMap::iterator &i);
friend bool Unit::_ApplyAuraEffect(Aura * aura, uint8 effIndex);
friend void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask);
friend void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode);
friend void Unit::_ApplyAuraEffect(Aura * aura, uint8 effIndex);
friend AuraApplication * Unit::_CreateAuraApplication(Aura * aura, uint8 effMask);
private:
Unit * const m_target;
Aura * const m_base;
uint8 m_slot; // Aura slot on unit
uint8 m_flags; // Aura info flag
uint8 m_effectsToApply; // Used only at spell hit to determine which effect should be applied
AuraRemoveMode m_removeMode:8; // Store info for know remove aura reason
bool m_needClientUpdate:1;
bool m_isNeedManyNegativeEffects:1;
bool m_canBeRemoved:1; // used only in aura list update of Aura
explicit AuraApplication(Unit * target, Unit * caster, Aura * base);
explicit AuraApplication(Unit * target, Unit * caster, Aura * base, uint8 effMask);
void _Remove();
private:
bool _CheckPositive(Unit * caster) const;
void _HandleEffect(uint8 effIndex, bool apply);
public:
bool _CanBeRemoved() const {return m_canBeRemoved;}
void _SetCanBeRemoved(bool val) {m_canBeRemoved = val;}
Unit * GetTarget() const { return m_target; }
Aura * GetBase() const { return m_base; }
@@ -68,6 +67,7 @@ class AuraApplication
uint8 GetEffectMask() const { return m_flags & (AFLAG_EFF_INDEX_0 | AFLAG_EFF_INDEX_1 | AFLAG_EFF_INDEX_2); }
bool HasEffect(uint8 effect) const { assert(effect < MAX_SPELL_EFFECTS); return m_flags & (1<<effect); }
bool IsPositive() const { return m_flags & AFLAG_POSITIVE; }
uint8 GetEffectsToApply() const { return m_effectsToApply; }
void SetRemoveMode(AuraRemoveMode mode) { m_removeMode = mode; }
AuraRemoveMode GetRemoveMode() const {return m_removeMode;}
@@ -106,11 +106,12 @@ class TRINITY_DLL_SPEC Aura
void _Remove(AuraRemoveMode removeMode);
virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0;
virtual void UpdateTargetMapForEffect(Unit * caster, uint8 effIndex) = 0;
void UpdateTargetMap(Unit * caster);
virtual void FillTargetMap(std::map<Unit *, uint8> & targets, Unit * caster) = 0;
void UpdateTargetMap(Unit * caster, bool apply = true);
void ApplyForTargets() {Unit * caster = GetCaster(); UpdateTargetMap(caster);}
void ApplyEffectForTargets(uint8 effIndex) {Unit * caster = GetCaster(); UpdateTargetMapForEffect(caster, effIndex);}
void _RegisterForTargets() {Unit * caster = GetCaster(); UpdateTargetMap(caster, false);}
void ApplyForTargets() {Unit * caster = GetCaster(); UpdateTargetMap(caster, true);}
void _ApplyEffectForTargets(uint8 effIndex);
void UpdateOwner(uint32 diff, WorldObject * owner);
void Update(uint32 diff, Unit * caster);
@@ -202,7 +203,7 @@ class TRINITY_DLL_SPEC UnitAura : public Aura
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void UpdateTargetMapForEffect(Unit * caster, uint8 effIndex);
void FillTargetMap(std::map<Unit *, uint8> & targets, Unit * caster);
// Allow Apply Aura Handler to modify and access m_AuraDRGroup
void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; }
@@ -220,6 +221,6 @@ class TRINITY_DLL_SPEC DynObjAura : public Aura
public:
void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void UpdateTargetMapForEffect(Unit * caster, uint8 effIndex);
void FillTargetMap(std::map<Unit *, uint8> & targets, Unit * caster);
};
#endif
+4 -6
View File
@@ -2601,8 +2601,7 @@ void Spell::EffectApplyAura(uint32 i)
if (!m_spellAura)
return;
assert (unitTarget == m_spellAura->GetOwner());
if (!m_spellAura->IsRemoved())
m_spellAura->ApplyEffectForTargets(i);
m_spellAura->_ApplyEffectForTargets(i);
}
void Spell::EffectApplyAreaAura(uint32 i)
@@ -2610,8 +2609,7 @@ void Spell::EffectApplyAreaAura(uint32 i)
if (!m_spellAura)
return;
assert (unitTarget == m_spellAura->GetOwner());
if (!m_spellAura->IsRemoved())
m_spellAura->ApplyEffectForTargets(i);
m_spellAura->_ApplyEffectForTargets(i);
}
void Spell::EffectUnlearnSpecialization( uint32 i )
@@ -3140,10 +3138,10 @@ void Spell::EffectPersistentAA(uint32 i)
assert(false);
return;
}
m_spellAura->_RegisterForTargets();
}
assert(m_spellAura->GetDynobjOwner());
if (!m_spellAura->IsRemoved())
m_spellAura->ApplyEffectForTargets(i);
m_spellAura->_ApplyEffectForTargets(i);
}
void Spell::EffectEnergize(uint32 i)
+61 -59
View File
@@ -3578,8 +3578,11 @@ void Unit::_AddAura(UnitAura * aura, Unit * caster)
}
}
AuraApplication * Unit::__ApplyAura(Aura * aura)
// creates aura application instance and registers it in lists
// aura application effects are handled separately to prevent aura list corruption
AuraApplication * Unit::_CreateAuraApplication(Aura * aura, uint8 effMask)
{
// can't apply aura on unit which is going to be deleted - to not create a memory leak
assert(!m_cleanupDone);
// aura musn't be removed
assert(!aura->IsRemoved());
@@ -3594,9 +3597,7 @@ AuraApplication * Unit::__ApplyAura(Aura * aura)
Unit * caster = aura->GetCaster();
// Add all pointers to lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
AuraApplication * aurApp = new AuraApplication(this, caster, aura);
AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
if(aurSpellInfo->AuraInterruptFlags)
@@ -3605,35 +3606,72 @@ AuraApplication * Unit::__ApplyAura(Aura * aura)
AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
}
AuraState aState = GetSpellAuraState(aura->GetSpellProto());
if(aState)
if(AuraState aState = GetSpellAuraState(aura->GetSpellProto()))
m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
aura->_ApplyForTarget(this, caster, aurApp);
_RemoveNoStackAurasDueToAura(aura);
// Update target aura state flag
if(aState)
ModifyAuraState(aState, true);
// Sitdown on apply aura req seated
if (aurSpellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState())
SetStandState(UNIT_STAND_STATE_SIT);
aura->HandleAuraSpecificMods(aurApp, caster, true);
if (aurApp->GetRemoveMode())
return NULL;
return aurApp;
}
void Unit::__UnapplyAura(AuraApplicationMap::iterator &i)
void Unit::_ApplyAuraEffect(Aura * aura, uint8 effIndex)
{
assert(aura);
assert(aura->HasEffect(effIndex));
AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
assert(aurApp);
if (!aurApp->GetEffectMask())
_ApplyAura(aurApp, 1<<effIndex);
else
aurApp->_HandleEffect(effIndex, true);
}
// handles effects of aura application
// should be done after registering aura in lists
void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask)
{
Aura * aura = aurApp->GetBase();
_RemoveNoStackAurasDueToAura(aura);
if (aurApp->GetRemoveMode())
return;
// Update target aura state flag
if(AuraState aState = GetSpellAuraState(aura->GetSpellProto()))
ModifyAuraState(aState, true);
if (aurApp->GetRemoveMode())
return;
// Sitdown on apply aura req seated
if (aura->GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState())
SetStandState(UNIT_STAND_STATE_SIT);
Unit * caster = aura->GetCaster();
if (aurApp->GetRemoveMode())
return;
aura->HandleAuraSpecificMods(aurApp, caster, true);
// apply effects of the aura
for (uint8 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
{
if (effMask & 1<<i && (!aurApp->GetRemoveMode()))
aurApp->_HandleEffect(i, true);
}
}
// removes aura application from lists and unapplies effects
void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
{
AuraApplication * aurApp = i->second;
assert(aurApp);
assert(!aurApp->GetRemoveMode());
assert(aurApp->GetTarget() == this);
aurApp->SetRemoveMode(removeMode);
Aura * aura = aurApp->GetBase();
sLog.outDebug("Aura %u now is remove mode %d", aura->GetId(), removeMode);
// dead loop is killing the server probably
assert(m_removedAurasCount < 0xFFFFFFFF);
@@ -3702,42 +3740,6 @@ void Unit::__UnapplyAura(AuraApplicationMap::iterator &i)
i = m_appliedAuras.begin();
}
bool Unit::_ApplyAuraEffect(Aura * aura, uint8 effIndex)
{
// check if aura has requested effect - should always do
assert(aura);
assert(aura->HasEffect(effIndex));
AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
if (!aurApp)
{
// real aura apply
aurApp = __ApplyAura(aura);
if (!aurApp)
return false;
}
// add effect to unit
aurApp->_HandleEffect(effIndex, true);
return true;
}
// Not implemented - afaik there should be no way to remove effects separately
void Unit::_UnapplyAuraEffect(AuraApplication * aurApp, uint8 effIndex, AuraRemoveMode removeMode)
{
assert(aurApp);
assert(aurApp->HasEffect(effIndex));
_UnapplyAura(aurApp, removeMode);
}
void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
{
AuraApplication * aurApp = i->second;
assert(aurApp);
assert(!aurApp->GetRemoveMode());
aurApp->SetRemoveMode(removeMode);
sLog.outDebug("Aura %u now is remove mode %d", aurApp->GetBase()->GetId(), removeMode);
__UnapplyAura(i);
}
void Unit::_UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode)
{
// aura can be removed from unit only if it's applied on it, shouldn't happen
+3 -4
View File
@@ -1536,10 +1536,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
// aura apply/remove helpers - you should better not use these
void _AddAura(UnitAura * aura, Unit * caster);
AuraApplication * __ApplyAura(Aura * aura);
void __UnapplyAura(AuraApplicationMap::iterator &i);
bool _ApplyAuraEffect(Aura * aura, uint8 effIndex);
void _UnapplyAuraEffect(AuraApplication * aurApp, uint8 effIndex, AuraRemoveMode removeMode);
AuraApplication * _CreateAuraApplication(Aura * aura, uint8 effMask);
void _ApplyAuraEffect(Aura * aura, uint8 effIndex);
void _ApplyAura(AuraApplication * aurApp, uint8 effMask);
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode);
void _UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode);
void _RemoveNoStackAuraApplicationsDueToAura(Aura * aura);