diff options
author | QAston <none@none> | 2010-01-24 13:08:25 +0100 |
---|---|---|
committer | QAston <none@none> | 2010-01-24 13:08:25 +0100 |
commit | d1a40eb6888c325b3f01ac8a90f1dbac7ed56ea0 (patch) | |
tree | d73e698cb5ce789e70382a150aa57298c8c06b02 /src | |
parent | 79accd730ecbf396b856ee42e25f2c23e51dceed (diff) |
*Do not keep area aura targets in combat with aura owner
*Add some safety checks to area aura target map update.
--HG--
branch : trunk
Diffstat (limited to 'src')
-rw-r--r-- | src/game/Spell.cpp | 1 | ||||
-rw-r--r-- | src/game/SpellAuraEffects.cpp | 2 | ||||
-rw-r--r-- | src/game/SpellAuras.cpp | 374 | ||||
-rw-r--r-- | src/game/SpellAuras.h | 27 | ||||
-rw-r--r-- | src/game/SpellEffects.cpp | 10 | ||||
-rw-r--r-- | src/game/Unit.cpp | 98 | ||||
-rw-r--r-- | src/game/Unit.h | 7 |
7 files changed, 276 insertions, 243 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index b213aa71a88..f48a808225d 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -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(); } } } diff --git a/src/game/SpellAuraEffects.cpp b/src/game/SpellAuraEffects.cpp index c78c9815913..754b6bca17f 100644 --- a/src/game/SpellAuraEffects.cpp +++ b/src/game/SpellAuraEffects.cpp @@ -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()); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 95a70a545e7..7c7ff437801 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -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); - - // fill up to date target list - UnitList targets; + modOwner = caster->GetSpellModOwner(); - 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: + { + 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: { - addUnit = false; + 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) { - float radius = GetDynobjOwner()->GetRadius(); - - // fill up to date target list - UnitList targets; - Unit * dynObjOwnerCaster = GetDynobjOwner()->GetCaster(); + float radius = GetDynobjOwner()->GetRadius(); - 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<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++) + for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { - // 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); } - - if (itr == m_applications.end() || !itr->second->HasEffect(effIndex)) + else { - 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); + Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); + Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check); + GetDynobjOwner()->VisitNearbyObject(radius, searcher); } - 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); + for (UnitList::iterator itr = targetList.begin(); itr!= targetList.end();++itr) + { + std::map<Unit *, uint8>::iterator existing = targets.find(*itr); + if (existing != targets.end()) + existing->second |= 1<<effIndex; + else + targets[*itr] = 1<<effIndex; + } } } + diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index dfa5fca6432..7289b5c4d36 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -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 diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 81ff8116c00..796d007ba64 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -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) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 65038562091..316088d51bb 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -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); + return aurApp; +} + +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(aState) + if(AuraState aState = GetSpellAuraState(aura->GetSpellProto())) ModifyAuraState(aState, true); + if (aurApp->GetRemoveMode()) + return; + // Sitdown on apply aura req seated - if (aurSpellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState()) + if (aura->GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_SEATED && !IsSitState()) SetStandState(UNIT_STAND_STATE_SIT); - aura->HandleAuraSpecificMods(aurApp, caster, true); + Unit * caster = aura->GetCaster(); if (aurApp->GetRemoveMode()) - return NULL; + return; - return aurApp; + 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); + } } -void Unit::__UnapplyAura(AuraApplicationMap::iterator &i) +// 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 diff --git a/src/game/Unit.h b/src/game/Unit.h index 5ff61195cc4..07281fd90e8 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -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); |