diff options
author | ariel- <ariel-@users.noreply.github.com> | 2018-01-27 03:45:40 -0300 |
---|---|---|
committer | Ariel Silva <ariel-@users.noreply.github.com> | 2018-03-09 14:41:28 -0300 |
commit | e8d5aa56cc48572d81e1898b7b4ff10cfa6d1957 (patch) | |
tree | b21b5dff1cdb693074e23eb57906f6a2a2182a76 /src | |
parent | 9b38a6352c0fe2499de54fd769aa1c721a410bda (diff) |
Core/Spells: rework part 3: spells only handle at most one UnitAura and one DynObjAura during its lifetime
Closes #15088
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Pet/Pet.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 84 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 14 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraDefines.h | 39 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.h | 15 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 420 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 77 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 68 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 64 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.cpp | 20 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 7 |
15 files changed, 513 insertions, 319 deletions
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 0bcb5862e4f..5ad30f70458 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -1213,7 +1213,12 @@ void Pet::_LoadAuras(uint32 timediff) else remaincharges = 0; - if (Aura* aura = Aura::TryCreate(spellInfo, effmask, this, nullptr, &baseDamage[0], nullptr, caster_guid)) + AuraCreateInfo createInfo(spellInfo, effmask, this); + createInfo + .SetCasterGUID(caster_guid) + .SetBaseAmount(baseDamage); + + if (Aura* aura = Aura::TryCreate(createInfo)) { if (!aura->CanBeSaved()) { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d2e66fac891..52c635ca059 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -17799,7 +17799,12 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) else remaincharges = 0; - if (Aura* aura = Aura::TryCreate(spellInfo, effmask, this, nullptr, &baseDamage[0], nullptr, caster_guid)) + AuraCreateInfo createInfo(spellInfo, effmask, this); + createInfo + .SetCasterGUID(caster_guid) + .SetBaseAmount(baseDamage); + + if (Aura* aura = Aura::TryCreate(createInfo)) { if (!aura->CanBeSaved()) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 1538c5ffac6..96fc1caf649 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3409,29 +3409,29 @@ void Unit::DeMorph() SetDisplayId(GetNativeDisplayId()); } -Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool resetPeriodicTimer /*= true*/) +Aura* Unit::_TryStackingOrRefreshingExistingAura(AuraCreateInfo& createInfo) { - ASSERT(casterGUID || caster); + ASSERT(createInfo.CasterGUID || createInfo.Caster); // Check if these can stack anyway - if (!casterGUID && !newAura->IsStackableOnOneSlotWithDifferentCasters()) - casterGUID = caster->GetGUID(); + if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters()) + createInfo.CasterGUID = createInfo.Caster->GetGUID(); // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times - if (!newAura->IsMultiSlotAura()) + if (!createInfo.GetSpellInfo()->IsMultiSlotAura()) { // check if cast item changed ObjectGuid castItemGUID; - if (castItem) - castItemGUID = castItem->GetGUID(); + if (createInfo.CastItem) + castItemGUID = createInfo.CastItem->GetGUID(); // find current aura from spell and change it's stackamount, or refresh it's duration - if (Aura* foundAura = GetOwnedAura(newAura->Id, casterGUID, newAura->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty, 0)) + if (Aura* foundAura = GetOwnedAura(createInfo.GetSpellInfo()->Id, createInfo.CasterGUID, createInfo.GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_ENCHANT_PROC) ? castItemGUID : ObjectGuid::Empty)) { // effect masks do not match // extremely rare case // let's just recreate aura - if (effMask != foundAura->GetEffectMask()) + if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask()) return nullptr; // update basepoints with new values - effect amount will be recalculated in ModStackAmount @@ -3440,11 +3440,9 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 if (!foundAura->HasEffect(i)) continue; - int bp; - if (baseAmount) - bp = *(baseAmount + i); - else - bp = foundAura->GetSpellInfo()->Effects[i].BasePoints; + int32 bp = foundAura->GetSpellInfo()->Effects[i].BasePoints; + if (createInfo.BaseAmount) + bp = *(createInfo.BaseAmount + i); int32* oldBP = const_cast<int32*>(&(foundAura->GetEffect(i)->m_baseAmount)); *oldBP = bp; @@ -3458,7 +3456,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 } // try to increase stack amount - foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, resetPeriodicTimer); + foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer); return foundAura; } } @@ -3469,7 +3467,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 void Unit::_AddAura(UnitAura* aura, Unit* caster) { ASSERT(!m_cleanupDone); - m_ownedAuras.insert(AuraMap::value_type(aura->GetId(), aura)); + m_ownedAuras.emplace(aura->GetId(), aura); _RemoveNoStackAurasDueToAura(aura); @@ -3506,7 +3504,7 @@ void Unit::_AddAura(UnitAura* aura, Unit* caster) // 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) +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); @@ -3556,7 +3554,7 @@ void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex) // handles effects of aura application // should be done after registering aura in lists -void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) +void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask) { Aura* aura = aurApp->GetBase(); @@ -3599,7 +3597,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint8 effMask) } // removes aura application from lists and unapplies effects -void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode) +void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode) { AuraApplication * aurApp = i->second; ASSERT(aurApp); @@ -3687,7 +3685,7 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMo i = m_appliedAuras.begin(); } -void Unit::_UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode) +void Unit::_UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode) { // aura can be removed from unit only if it's applied on it, shouldn't happen ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp); @@ -3756,8 +3754,8 @@ void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply) m_modAuras[aurEff->GetAuraType()].remove(aurEff); } -// All aura base removes should go threw this function! -void Unit::RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode) +// All aura base removes should go through this function! +void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode) { Aura* aura = i->second; ASSERT(!aura->IsRemoved()); @@ -4087,7 +4085,12 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U if (aura->IsSingleTarget()) aura->UnregisterSingleTarget(); - if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID())) + AuraCreateInfo createInfo(aura->GetSpellInfo(), effMask, stealer); + createInfo + .SetCasterGUID(aura->GetCasterGUID()) + .SetBaseAmount(baseDamage); + + if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo)) { // created aura must not be single target aura,, so stealer won't loose it on recast if (newAura->IsSingleTarget()) @@ -12738,11 +12741,18 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target) { if (!(effMask & (1 << i))) continue; + if (target->IsImmunedToSpellEffect(spellInfo, i, this)) effMask &= ~(1 << i); } - if (Aura* aura = Aura::TryRefreshStackOrCreate(spellInfo, effMask, target, this)) + if (!effMask) + return nullptr; + + AuraCreateInfo createInfo(spellInfo, effMask, target); + createInfo.SetCaster(this); + + if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo)) { aura->ApplyForTargets(); return aura; @@ -13365,17 +13375,24 @@ void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/) { CastSpellExtraArgs args(flags); args.OriginalCaster = origCasterGUID; - args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0+i), seatId+1); + args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1); caster->CastSpell(target, clickPair.second.spellId, args); } else // This can happen during Player::_LoadAuras { - int32 bp0[MAX_SPELL_EFFECTS]; + int32 bp[MAX_SPELL_EFFECTS] = { }; for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j) - bp0[j] = spellEntry->Effects[j].BasePoints; + bp[j] = spellEntry->Effects[j].BasePoints; - bp0[i] = seatId; - Aura::TryRefreshStackOrCreate(spellEntry, MAX_EFFECT_MASK, this, clicker, bp0, nullptr, origCasterGUID); + bp[i] = seatId; + + AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this); + createInfo + .SetCaster(clicker) + .SetBaseAmount(bp) + .SetCasterGUID(origCasterGUID); + + Aura::TryRefreshStackOrCreate(createInfo); } } else @@ -13383,7 +13400,14 @@ void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/) if (IsInMap(caster)) caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID)); else - Aura::TryRefreshStackOrCreate(spellEntry, MAX_EFFECT_MASK, this, clicker, nullptr, nullptr, origCasterGUID); + { + AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this); + createInfo + .SetCaster(clicker) + .SetCasterGUID(origCasterGUID); + + Aura::TryRefreshStackOrCreate(createInfo); + } } spellClickHandled = true; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 642c25f49f9..9e7755521d8 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -756,7 +756,7 @@ class TC_GAME_API Unit : public WorldObject typedef std::list<AuraEffect*> AuraEffectList; typedef std::list<Aura*> AuraList; - typedef std::list<AuraApplication *> AuraApplicationList; + typedef std::list<AuraApplication*> AuraApplicationList; typedef std::vector<std::pair<uint8 /*procEffectMask*/, AuraApplication*>> AuraApplicationProcContainer; @@ -1234,13 +1234,13 @@ class TC_GAME_API Unit : public WorldObject bool InitTamedPet(Pet* pet, uint8 level, uint32 spell_id); // aura apply/remove helpers - you should better not use these - Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool resetPeriodicTimer = true); + Aura* _TryStackingOrRefreshingExistingAura(AuraCreateInfo& createInfo); void _AddAura(UnitAura* aura, Unit* caster); - AuraApplication * _CreateAuraApplication(Aura* aura, uint8 effMask); + 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 _ApplyAura(AuraApplication* aurApp, uint8 effMask); + void _UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode); + void _UnapplyAura(AuraApplication* aurApp, AuraRemoveMode removeMode); void _RemoveNoStackAurasDueToAura(Aura* aura); void _RegisterAuraEffect(AuraEffect* aurEff, bool apply); @@ -1248,7 +1248,7 @@ class TC_GAME_API Unit : public WorldObject AuraMap & GetOwnedAuras() { return m_ownedAuras; } AuraMap const& GetOwnedAuras() const { return m_ownedAuras; } - void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + void RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveOwnedAura(Aura* aura, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 9d4ab4a4d30..c219b7c3529 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -19,6 +19,12 @@ #define TRINITY_SPELLAURADEFINES_H #include "Define.h" +#include "ObjectGuid.h" + +class Item; +class SpellInfo; +class Unit; +class WorldObject; #define MAX_AURAS 255 // Client-side limit #define MAX_AURAS_GROUP_UPDATE 64 // Limit of SMSG_PARY_MEMBER_STATS_FULL and SMSG_PARTY_MEMBER_STATS @@ -434,4 +440,37 @@ enum ShapeshiftForm FORM_SPIRITOFREDEMPTION = 0x20 }; +struct TC_GAME_API AuraCreateInfo +{ + friend class Aura; + friend class UnitAura; + friend class DynObjAura; + + AuraCreateInfo(SpellInfo const* spellInfo, uint8 auraEffMask, WorldObject* owner); + + AuraCreateInfo& SetCasterGUID(ObjectGuid const& guid) { CasterGUID = guid; return *this; } + AuraCreateInfo& SetCaster(Unit* caster) { Caster = caster; return *this; } + AuraCreateInfo& SetBaseAmount(int32 const* bp) { BaseAmount = bp; return *this; } + AuraCreateInfo& SetCastItem(Item* item) { CastItem = item; return *this; } + AuraCreateInfo& SetPeriodicReset(bool reset) { ResetPeriodicTimer = reset; return *this; } + AuraCreateInfo& SetOwnerEffectMask(uint8 effMask) { _targetEffectMask = effMask; return *this; } + + SpellInfo const* GetSpellInfo() const { return _spellInfo; } + uint8 GetAuraEffectMask() const { return _auraEffectMask; } + + ObjectGuid CasterGUID; + Unit* Caster = nullptr; + int32 const* BaseAmount = nullptr; + Item* CastItem = nullptr; + bool* IsRefresh = nullptr; + bool ResetPeriodicTimer = true; + + private: + SpellInfo const* _spellInfo = nullptr; + uint8 _auraEffectMask = 0; + WorldObject* _owner = nullptr; + + uint8 _targetEffectMask = 0; +}; + #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 2eb09d0907d..bf5956ec0bc 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -378,7 +378,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNoImmediateEffect, //316 SPELL_AURA_PERIODIC_HASTE implemented in AuraEffect::CalculatePeriodic }; -AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster): +AuraEffect::AuraEffect(Aura* base, uint8 effIndex, int32 const* baseAmount, Unit* caster): m_base(base), m_spellInfo(base->GetSpellInfo()), m_baseAmount(baseAmount ? *baseAmount : m_spellInfo->Effects[effIndex].BasePoints), _amount(), m_spellmod(nullptr), _periodicTimer(0), _amplitude(0), _ticksDone(0), m_effIndex(effIndex), diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 1818dc359af..b83d15148c5 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -19,22 +19,23 @@ #ifndef TRINITY_SPELLAURAEFFECTS_H #define TRINITY_SPELLAURAEFFECTS_H -class Unit; -class AuraEffect; -class Aura; - #include "SpellAuras.h" +class AuraEffect; +class Unit; + typedef void(AuraEffect::*pAuraEffectHandler)(AuraApplication const* aurApp, uint8 mode, bool apply) const; class TC_GAME_API AuraEffect { - friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32* baseAmount); - friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer); + friend void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 const* baseAmount); friend Aura::~Aura(); + friend class Unit; + private: ~AuraEffect(); - explicit AuraEffect(Aura* base, uint8 effIndex, int32 *baseAmount, Unit* caster); + explicit AuraEffect(Aura* base, uint8 effIndex, int32 const* baseAmount, Unit* caster); + public: Unit* GetCaster() const { return GetBase()->GetCaster(); } ObjectGuid GetCasterGUID() const { return GetBase()->GetCasterGUID(); } diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 4dc92fd9ac7..fbd5b3efcd4 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -39,7 +39,17 @@ #include "World.h" #include "WorldPacket.h" -AuraApplication::AuraApplication(Unit* target, Unit* caster, Aura* aura, uint8 effMask): +AuraCreateInfo::AuraCreateInfo(SpellInfo const* spellInfo, uint8 auraEffMask, WorldObject* owner) : + _spellInfo(spellInfo), _auraEffectMask(auraEffMask), _owner(owner) +{ + ASSERT(spellInfo); + ASSERT(auraEffMask); + ASSERT(owner); + + ASSERT(auraEffMask <= MAX_EFFECT_MASK); +} + +AuraApplication::AuraApplication(Unit* target, Unit* caster, Aura* aura, uint8 effMask) : _target(target), _base(aura), _removeMode(AURA_REMOVE_NONE), _slot(MAX_AURAS), _flags(AFLAG_NONE), _effectsToApply(effMask), _needClientUpdate(false) { @@ -178,6 +188,37 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply) SetNeedClientUpdate(); } +void AuraApplication::UpdateApplyEffectMask(uint8 newEffMask) +{ + if (_effectsToApply == newEffMask) + return; + + uint8 removeEffMask = (_effectsToApply ^ newEffMask) & (~newEffMask); + uint8 addEffMask = (_effectsToApply ^ newEffMask) & (~_effectsToApply); + + // quick check, removes application completely + if (removeEffMask == _effectsToApply && !addEffMask) + { + _target->_UnapplyAura(this, AURA_REMOVE_BY_DEFAULT); + return; + } + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + // update real effects only if they were applied already + if (!(_flags & (1 << i))) + continue; + + if (removeEffMask & (1 << i)) + _HandleEffect(i, false); + + if (addEffMask & (1 << i)) + _HandleEffect(i, true); + } + + _effectsToApply = newEffMask; +} + void AuraApplication::BuildUpdatePacket(ByteBuffer& data, bool remove) const { data << uint8(_slot); @@ -252,98 +293,128 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 available return effMask & availableEffectMask; } -Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= nullptr*/, bool resetPeriodicTimer /*= true*/) +Aura* Aura::TryRefreshStackOrCreate(AuraCreateInfo& createInfo) { - ASSERT(spellproto); - ASSERT(owner); - ASSERT(caster || casterGUID); - ASSERT(tryEffMask <= MAX_EFFECT_MASK); - if (refresh) - *refresh = false; + ASSERT(createInfo.Caster || createInfo.CasterGUID); + + if (createInfo.IsRefresh) + *createInfo.IsRefresh = false; + + createInfo._auraEffectMask = Aura::BuildEffectMaskForOwner(createInfo._spellInfo, createInfo._auraEffectMask, createInfo._owner); + createInfo._targetEffectMask &= createInfo._auraEffectMask; + + uint8 effMask = createInfo._auraEffectMask; + if (createInfo._targetEffectMask) + effMask = createInfo._targetEffectMask; - uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (!effMask) return nullptr; - if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer)) + if (Aura* foundAura = createInfo._owner->ToUnit()->_TryStackingOrRefreshingExistingAura(createInfo)) { // we've here aura, which script triggered removal after modding stack amount // check the state here, so we won't create new Aura object if (foundAura->IsRemoved()) return nullptr; - if (refresh) - *refresh = true; + if (createInfo.IsRefresh) + *createInfo.IsRefresh = true; + // add owner + Unit* unit = createInfo._owner->ToUnit(); + + // check effmask on owner application (if existing) + if (AuraApplication* aurApp = foundAura->GetApplicationOfTarget(unit->GetGUID())) + aurApp->UpdateApplyEffectMask(effMask); return foundAura; } else - return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); + return Create(createInfo); } -Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/) +Aura* Aura::TryCreate(AuraCreateInfo& createInfo) { - ASSERT(spellproto); - ASSERT(owner); - ASSERT(caster || casterGUID); - ASSERT(tryEffMask <= MAX_EFFECT_MASK); - uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); + ASSERT(createInfo.Caster || createInfo.CasterGUID); + + uint8 effMask = createInfo._auraEffectMask; + if (createInfo._targetEffectMask) + effMask = createInfo._targetEffectMask; + + effMask = Aura::BuildEffectMaskForOwner(createInfo._spellInfo, effMask, createInfo._owner); if (!effMask) return nullptr; - return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); + return Create(createInfo); } -Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID) +Aura* Aura::Create(AuraCreateInfo& createInfo) { - ASSERT(effMask); - ASSERT(spellproto); - ASSERT(owner); - ASSERT(caster || casterGUID); - ASSERT(effMask <= MAX_EFFECT_MASK); + ASSERT(createInfo.Caster || createInfo.CasterGUID); + // try to get caster of aura - if (casterGUID) + if (createInfo.CasterGUID) { - if (owner->GetGUID() == casterGUID) - caster = owner->ToUnit(); + if (createInfo._owner->GetGUID() == createInfo.CasterGUID) + createInfo.Caster = createInfo._owner->ToUnit(); else - caster = ObjectAccessor::GetUnit(*owner, casterGUID); + createInfo.Caster = ObjectAccessor::GetUnit(*createInfo._owner, createInfo.CasterGUID); } else - casterGUID = caster->GetGUID(); + createInfo.CasterGUID = createInfo.Caster->GetGUID(); // check if aura can be owned by owner - if (owner->isType(TYPEMASK_UNIT)) - if (!owner->IsInWorld() || ((Unit*)owner)->IsDuringRemoveFromWorld()) + if (createInfo._owner->isType(TYPEMASK_UNIT)) + if (!createInfo._owner->IsInWorld() || createInfo._owner->ToUnit()->IsDuringRemoveFromWorld()) // owner not in world so don't allow to own not self cast single target auras - if (casterGUID != owner->GetGUID() && spellproto->IsSingleTarget()) + if (createInfo.CasterGUID != createInfo._owner->GetGUID() && createInfo._spellInfo->IsSingleTarget()) return nullptr; Aura* aura = nullptr; - switch (owner->GetTypeId()) + switch (createInfo._owner->GetTypeId()) { case TYPEID_UNIT: case TYPEID_PLAYER: - aura = new UnitAura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); + { + aura = new UnitAura(createInfo); + + // aura can be removed in Unit::_AddAura call + if (aura->IsRemoved()) + return nullptr; + + // add owner + uint8 effMask = createInfo._auraEffectMask; + if (createInfo._targetEffectMask) + effMask = createInfo._targetEffectMask; + + effMask = Aura::BuildEffectMaskForOwner(createInfo._spellInfo, effMask, createInfo._owner); + ASSERT(effMask); + + Unit* unit = createInfo._owner->ToUnit(); + aura->ToUnitAura()->AddStaticApplication(unit, effMask); break; + } case TYPEID_DYNAMICOBJECT: - aura = new DynObjAura(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); + createInfo._auraEffectMask = Aura::BuildEffectMaskForOwner(createInfo._spellInfo, createInfo._auraEffectMask, createInfo._owner); + ASSERT(createInfo._auraEffectMask); + + aura = new DynObjAura(createInfo); break; default: ABORT(); return nullptr; } - // aura can be removed in Unit::_AddAura call + // scripts, etc. if (aura->IsRemoved()) return nullptr; + return aura; } -Aura::Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID) : -m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID()), -m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_applyTime(GameTime::GetGameTime()), -m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), +Aura::Aura(AuraCreateInfo const& createInfo) : +m_spellInfo(createInfo._spellInfo), m_casterGuid(createInfo.CasterGUID.IsEmpty() ? createInfo.Caster->GetGUID() : createInfo.CasterGUID), +m_castItemGuid(createInfo.CastItem ? createInfo.CastItem->GetGUID() : ObjectGuid::Empty), m_applyTime(GameTime::GetGameTime()), +m_owner(createInfo._owner), m_timeCla(0), m_updateTargetMapInterval(0), _casterInfo(), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), m_procCooldown(std::chrono::steady_clock::time_point::min()) @@ -351,19 +422,19 @@ m_procCooldown(std::chrono::steady_clock::time_point::min()) if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) m_timeCla = 1 * IN_MILLISECONDS; - m_maxDuration = CalcMaxDuration(caster); + m_maxDuration = CalcMaxDuration(createInfo.Caster); m_duration = m_maxDuration; - m_procCharges = CalcMaxCharges(caster); + m_procCharges = CalcMaxCharges(createInfo.Caster); m_isUsingCharges = m_procCharges != 0; memset(m_effects, 0, sizeof(m_effects)); // m_casterLevel = cast item level/caster level, caster level should be saved to db, confirmed with sniffs _casterInfo.Level = m_spellInfo->SpellLevel; - if (caster) + if (createInfo.Caster) { - _casterInfo.Level = caster->getLevel(); - _casterInfo.ApplyResilience = caster->CanApplyResilience(); - SaveCasterInfo(caster); + _casterInfo.Level = createInfo.Caster->getLevel(); + _casterInfo.ApplyResilience = createInfo.Caster->CanApplyResilience(); + SaveCasterInfo(createInfo.Caster); } } @@ -375,7 +446,7 @@ AuraScript* Aura::GetScriptByName(std::string const& scriptName) const return nullptr; } -void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount) +void Aura::_InitEffects(uint8 effMask, Unit* caster, int32 const* baseAmount) { // shouldn't be in constructor - functions in AuraEffect::AuraEffect use polymorphism for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -478,7 +549,7 @@ 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) +void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication* auraApp) { ASSERT(target); ASSERT(auraApp); @@ -498,7 +569,7 @@ void Aura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp } } -void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraApp) +void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication* auraApp) { ASSERT(target); ASSERT(auraApp->GetRemoveMode()); @@ -518,7 +589,7 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA ASSERT(itr->second == auraApp); m_applications.erase(itr); - m_removedApplications.push_back(auraApp); + _removedApplications.push_back(auraApp); // reset cooldown state for spells if (caster && GetSpellInfo()->IsCooldownStartedOnEvent()) @@ -560,61 +631,45 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) std::unordered_map<Unit*, uint8> targets; FillTargetMap(targets, caster); - std::deque<Unit*> targetsToRemove; + std::vector<Unit*> targetsToRemove; // mark all auras as ready to remove - for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end();++appIter) + for (auto const& applicationPair : m_applications) { - auto itr = targets.find(appIter->second->GetTarget()); + auto itr = targets.find(applicationPair.second->GetTarget()); // not found in current area - remove the aura if (itr == targets.end()) - targetsToRemove.push_back(appIter->second->GetTarget()); + targetsToRemove.push_back(applicationPair.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() != itr->second || !CanBeAppliedOn(itr->first)) - targetsToRemove.push_back(appIter->second->GetTarget()); - // nothing todo - aura already applied + if (!CanBeAppliedOn(itr->first)) + { + targetsToRemove.push_back(applicationPair.second->GetTarget()); + continue; + } + + // needs to add/remove effects from application, don't remove from map so it gets updated + if (applicationPair.second->GetEffectMask() != itr->second) + continue; + + // nothing to do - aura already applied // remove from auras to register list targets.erase(itr); } } // register auras for units - for (auto itr = targets.begin(); itr!= targets.end();) + for (auto itr = targets.begin(); itr != targets.end();) { - // aura mustn't be already applied on target - if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID())) - { - // the core created 2 different units with same guid - // this is a major failue, which i can't fix right now - // let's remove one unit from aura list - // this may cause area aura "bouncing" between 2 units after each update - // but because we know the reason of a crash we can remove the assertion for now - if (aurApp->GetTarget() != itr->first) - { - // remove from auras to register list - itr = targets.erase(itr); - continue; - } - else - { - // ok, we have one unit twice in target map (impossible, but...) - ABORT(); - } - } - bool addUnit = true; // check target immunities for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - { if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex, caster)) itr->second &= ~(1 << effIndex); - } - if (!itr->second - || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) - || !CanBeAppliedOn(itr->first)) + + if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(itr->first)) addUnit = false; if (addUnit && !itr->first->IsHighestExclusiveAura(this, true)) @@ -648,6 +703,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) } } } + if (!addUnit) itr = targets.erase(itr); else @@ -661,6 +717,13 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) itr->first->GetName().c_str(), itr->first->IsInWorld() ? itr->first->GetMap()->GetId() : uint32(-1)); ABORT(); } + + if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID())) + { + // aura is already applied, this means we need to update effects of current application + itr->first->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT); + } + itr->first->_CreateAuraApplication(this, itr->second); ++itr; } @@ -925,20 +988,20 @@ void Aura::SetStackAmount(uint8 stackAmount) m_stackAmount = stackAmount; Unit* caster = GetCaster(); - std::list<AuraApplication*> applications; - GetApplicationList(applications); + std::vector<AuraApplication*> applications; + GetApplicationVector(applications); - for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) - if (!(*apptItr)->GetRemoveMode()) - HandleAuraSpecificMods(*apptItr, caster, false, true); + for (AuraApplication* aurApp : applications) + if (!aurApp->GetRemoveMode()) + HandleAuraSpecificMods(aurApp, caster, false, true); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i)) - m_effects[i]->ChangeAmount(m_effects[i]->CalculateAmount(caster), false, true); + if (AuraEffect* aurEff = GetEffect(i)) + aurEff->ChangeAmount(aurEff->CalculateAmount(caster), false, true); - for (std::list<AuraApplication*>::const_iterator apptItr = applications.begin(); apptItr != applications.end(); ++apptItr) - if (!(*apptItr)->GetRemoveMode()) - HandleAuraSpecificMods(*apptItr, caster, true, true); + for (AuraApplication* aurApp : applications) + if (!aurApp->GetRemoveMode()) + HandleAuraSpecificMods(aurApp, caster, true, true); SetNeedClientUpdateForTargets(); } @@ -1191,12 +1254,14 @@ void Aura::HandleAllEffects(AuraApplication * aurApp, uint8 mode, bool apply) m_effects[i]->HandleEffect(aurApp, mode, apply); } -void Aura::GetApplicationList(Unit::AuraApplicationList& applicationList) const +void Aura::GetApplicationVector(std::vector<AuraApplication*>& applicationList) const { - for (Aura::ApplicationMap::const_iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) + for (auto const& applicationPair : m_applications) { - if (appIter->second->GetEffectMask()) - applicationList.push_back(appIter->second); + if (!applicationPair.second->GetEffectMask()) + continue; + + applicationList.push_back(applicationPair.second); } } @@ -2092,11 +2157,10 @@ void Aura::TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, Pro void Aura::_DeleteRemovedApplications() { - while (!m_removedApplications.empty()) - { - delete m_removedApplications.front(); - m_removedApplications.pop_front(); - } + for (AuraApplication* aurApp : _removedApplications) + delete aurApp; + + _removedApplications.clear(); } void Aura::LoadScripts() @@ -2482,16 +2546,16 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli } } -UnitAura::UnitAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) - : Aura(spellproto, owner, caster, castItem, casterGUID) +UnitAura::UnitAura(AuraCreateInfo const& createInfo) + : Aura(createInfo) { m_AuraDRGroup = DIMINISHING_NONE; LoadScripts(); - _InitEffects(effMask, caster, baseAmount); - GetUnitOwner()->_AddAura(this, caster); + _InitEffects(createInfo._auraEffectMask, createInfo.Caster, createInfo.BaseAmount); + GetUnitOwner()->_AddAura(this, createInfo.Caster); } -void UnitAura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) +void UnitAura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication* aurApp) { Aura::_ApplyForTarget(target, caster, aurApp); @@ -2500,7 +2564,7 @@ void UnitAura::_ApplyForTarget(Unit* target, Unit* caster, AuraApplication * aur target->ApplyDiminishingAura(group, true); } -void UnitAura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) +void UnitAura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication* aurApp) { Aura::_UnapplyForTarget(target, caster, aurApp); @@ -2522,85 +2586,97 @@ void UnitAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* ca if (!ref) ref = GetUnitOwner(); + // add non area aura targets + // static applications go through spell system first, so we assume they meet conditions + for (auto const& targetPair : _staticApplications) + if (Unit* target = ObjectAccessor::GetUnit(*GetUnitOwner(), targetPair.first)) + targets.emplace(target, targetPair.second); + for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { if (!HasEffect(effIndex)) continue; - std::vector<Unit*> units; - ConditionContainer* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; - // non-area aura + // area auras only if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA) - { - if (!condList || sConditionMgr->IsObjectMeetToConditions(GetUnitOwner(), ref, *condList)) - units.push_back(GetUnitOwner()); - } - else - { - // skip area update if owner is not in world! - if (!GetUnitOwner()->IsInWorld()) - continue; + continue; - if (GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED)) - continue; + // skip area update if owner is not in world! + if (!GetUnitOwner()->IsInWorld()) + continue; - float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(ref); - SpellTargetCheckTypes selectionType = TARGET_CHECK_DEFAULT; - switch (GetSpellInfo()->Effects[effIndex].Effect) - { - case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: - selectionType = TARGET_CHECK_PARTY; - break; - case SPELL_EFFECT_APPLY_AREA_AURA_RAID: - selectionType = TARGET_CHECK_RAID; - break; - case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: - selectionType = TARGET_CHECK_ALLY; - break; - case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: - selectionType = TARGET_CHECK_ENEMY; - break; - case SPELL_EFFECT_APPLY_AREA_AURA_PET: - if (!condList || sConditionMgr->IsObjectMeetToConditions(GetUnitOwner(), ref, *condList)) - units.push_back(GetUnitOwner()); - // no break - case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: - { - if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner()) - if (GetUnitOwner()->IsWithinDistInMap(owner, radius)) - if (!condList || sConditionMgr->IsObjectMeetToConditions(owner, ref, *condList)) - units.push_back(owner); - break; - } - } + if (GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED)) + continue; + + std::vector<Unit*> units; + ConditionContainer* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; - if (selectionType != TARGET_CHECK_DEFAULT) + float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(ref); + + SpellTargetCheckTypes selectionType = TARGET_CHECK_DEFAULT; + switch (GetSpellInfo()->Effects[effIndex].Effect) + { + case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: + selectionType = TARGET_CHECK_PARTY; + break; + case SPELL_EFFECT_APPLY_AREA_AURA_RAID: + selectionType = TARGET_CHECK_RAID; + break; + case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: + selectionType = TARGET_CHECK_ALLY; + break; + case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: + selectionType = TARGET_CHECK_ENEMY; + break; + case SPELL_EFFECT_APPLY_AREA_AURA_PET: + if (!condList || sConditionMgr->IsObjectMeetToConditions(GetUnitOwner(), ref, *condList)) + units.push_back(GetUnitOwner()); + // no break + case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: { - Trinity::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList); - Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetUnitOwner(), units, check); - Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); + if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner()) + if (GetUnitOwner()->IsWithinDistInMap(owner, radius)) + if (!condList || sConditionMgr->IsObjectMeetToConditions(owner, ref, *condList)) + units.push_back(owner); + break; } } - for (Unit* unit : units) + if (selectionType != TARGET_CHECK_DEFAULT) { - auto itr = targets.find(unit); - if (itr != targets.end()) - itr->second |= 1 << effIndex; - else - targets[unit] = 1 << effIndex; + Trinity::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList); + Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck> searcher(GetUnitOwner(), units, check); + Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); } + + for (Unit* unit : units) + targets[unit] |= 1 << effIndex; } } -DynObjAura::DynObjAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID) - : Aura(spellproto, owner, caster, castItem, casterGUID) +void UnitAura::AddStaticApplication(Unit* target, uint8 effMask) +{ + // only valid for non-area auras + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + if ((effMask & (1 << i)) && GetSpellInfo()->Effects[i].Effect != SPELL_EFFECT_APPLY_AURA) + effMask &= ~(1 << i); + } + + if (!effMask) + return; + + _staticApplications[target->GetGUID()] |= effMask; +} + +DynObjAura::DynObjAura(AuraCreateInfo const& createInfo) + : Aura(createInfo) { LoadScripts(); ASSERT(GetDynobjOwner()); ASSERT(GetDynobjOwner()->IsInWorld()); - ASSERT(GetDynobjOwner()->GetMap() == caster->GetMap()); - _InitEffects(effMask, caster, baseAmount); + ASSERT(GetDynobjOwner()->GetMap() == createInfo.Caster->GetMap()); + _InitEffects(createInfo._auraEffectMask, createInfo.Caster, createInfo.BaseAmount); GetDynobjOwner()->SetAura(this); } @@ -2634,13 +2710,7 @@ void DynObjAura::FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); for (Unit* unit : units) - { - auto itr = targets.find(unit); - if (itr != targets.end()) - itr->second |= 1 << effIndex; - else - targets[unit] = 1 << effIndex; - } + targets[unit] |= 1 << effIndex; } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 82613cea9ea..31ac19e9d04 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -21,7 +21,6 @@ #include "SpellAuraDefines.h" #include "SpellInfo.h" -#include "Unit.h" class SpellInfo; struct SpellModifier; @@ -29,23 +28,23 @@ struct ProcTriggerSpell; struct SpellProcEntry; // forward decl -class AuraEffect; class Aura; -class DynamicObject; +class AuraEffect; class AuraScript; -class ProcInfo; +class DynObjAura; class ChargeDropEvent; +class DynamicObject; +class ProcInfo; +class Unit; +class UnitAura; // update aura target map every 500 ms instead of every update - reduce amount of grid searcher calls #define UPDATE_TARGET_MAP_INTERVAL 500 class TC_GAME_API AuraApplication { - 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 void Unit::RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode); - friend AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint8 effMask); + friend class Unit; + private: Unit* const _target; Aura* const _base; @@ -57,24 +56,26 @@ class TC_GAME_API AuraApplication explicit AuraApplication(Unit* target, Unit* caster, Aura* base, uint8 effMask); void _Remove(); - private: + void _InitFlags(Unit* caster, uint8 effMask); void _HandleEffect(uint8 effIndex, bool apply); - public: + public: Unit* GetTarget() const { return _target; } Aura* GetBase() const { return _base; } uint8 GetSlot() const { return _slot; } uint8 GetFlags() const { return _flags; } uint8 GetEffectMask() const { return _flags & (AFLAG_EFF_INDEX_0 | AFLAG_EFF_INDEX_1 | AFLAG_EFF_INDEX_2); } - bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return (_flags & (1 << effect)) != 0; } + bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return (_flags & (1 << effect)) != 0; } bool IsPositive() const { return (_flags & AFLAG_POSITIVE) != 0; } bool IsSelfcast() const { return (_flags & AFLAG_CASTER) != 0; } + uint8 GetEffectsToApply() const { return _effectsToApply; } + void UpdateApplyEffectMask(uint8 newEffMask); void SetRemoveMode(AuraRemoveMode mode) { _removeMode = mode; } - AuraRemoveMode GetRemoveMode() const {return _removeMode;} + AuraRemoveMode GetRemoveMode() const { return _removeMode; } void SetNeedClientUpdate() { _needClientUpdate = true;} bool IsNeedClientUpdate() const { return _needClientUpdate;} @@ -93,16 +94,17 @@ struct CasterInfo class TC_GAME_API Aura { - friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer); + friend class Unit; + public: - typedef std::map<ObjectGuid, AuraApplication*> ApplicationMap; + typedef std::unordered_map<ObjectGuid, AuraApplication*> ApplicationMap; static uint8 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 availableEffectMask, WorldObject* owner); - static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = nullptr, bool resetPeriodicTimer = true); - static Aura* TryCreate(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty); - static Aura* Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32* baseAmount, Item* castItem, ObjectGuid casterGUID); - explicit Aura(SpellInfo const* spellproto, WorldObject* owner, Unit* caster, Item* castItem, ObjectGuid casterGUID); - void _InitEffects(uint8 effMask, Unit* caster, int32 *baseAmount); + static Aura* TryRefreshStackOrCreate(AuraCreateInfo& createInfo); + static Aura* TryCreate(AuraCreateInfo& createInfo); + static Aura* Create(AuraCreateInfo& createInfo); + explicit Aura(AuraCreateInfo const& createInfo); + void _InitEffects(uint8 effMask, Unit* caster, int32 const* baseAmount); void SaveCasterInfo(Unit* caster); virtual ~Aura(); @@ -113,8 +115,8 @@ class TC_GAME_API Aura ObjectGuid GetCasterGUID() const { return m_casterGuid; } Unit* GetCaster() const; WorldObject* GetOwner() const { return m_owner; } - Unit* GetUnitOwner() const { ASSERT(GetType() == UNIT_AURA_TYPE); return (Unit*)m_owner; } - DynamicObject* GetDynobjOwner() const { ASSERT(GetType() == DYNOBJ_AURA_TYPE); return (DynamicObject*)m_owner; } + Unit* GetUnitOwner() const { ASSERT(GetType() == UNIT_AURA_TYPE); return m_owner->ToUnit(); } + DynamicObject* GetDynobjOwner() const { ASSERT(GetType() == DYNOBJ_AURA_TYPE); return m_owner->ToDynObject(); } AuraObjectType GetType() const; @@ -126,8 +128,8 @@ class TC_GAME_API Aura virtual void FillTargetMap(std::unordered_map<Unit*, uint8>& targets, Unit* caster) = 0; void UpdateTargetMap(Unit* caster, bool apply = true); - void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);} - void ApplyForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, true);} + 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); @@ -204,7 +206,7 @@ class TC_GAME_API Aura // Helpers for targets ApplicationMap const& GetApplicationMap() { return m_applications; } - void GetApplicationList(Unit::AuraApplicationList& applicationList) const; + void GetApplicationVector(std::vector<AuraApplication*>& applicationVector) const; AuraApplication const* GetApplicationOfTarget(ObjectGuid guid) const { ApplicationMap::const_iterator itr = m_applications.find(guid); if (itr != m_applications.end()) return itr->second; return nullptr; } AuraApplication* GetApplicationOfTarget(ObjectGuid guid) { ApplicationMap::iterator itr = m_applications.find(guid); if (itr != m_applications.end()) return itr->second; return nullptr; } bool IsAppliedOnTarget(ObjectGuid guid) const { return m_applications.find(guid) != m_applications.end(); } @@ -252,6 +254,12 @@ class TC_GAME_API Aura bool CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); void CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); + UnitAura* ToUnitAura() { if (GetType() == UNIT_AURA_TYPE) return reinterpret_cast<UnitAura*>(this); else return nullptr; } + UnitAura const* ToUnitAura() const { if (GetType() == UNIT_AURA_TYPE) return reinterpret_cast<UnitAura const*>(this); else return nullptr; } + + DynObjAura* ToDynObjAura() { if (GetType() == DYNOBJ_AURA_TYPE) return reinterpret_cast<DynObjAura*>(this); else return nullptr; } + DynObjAura const* ToDynObjAura() const { if (GetType() == DYNOBJ_AURA_TYPE) return reinterpret_cast<DynObjAura const*>(this); else return nullptr; } + template <class Script> Script* GetScript(std::string const& scriptName) const { @@ -280,7 +288,7 @@ class TC_GAME_API Aura uint8 m_procCharges; // Aura charges (0 for infinite) uint8 m_stackAmount; // Aura stack amount - AuraEffect* m_effects[3]; + AuraEffect* m_effects[MAX_SPELL_EFFECTS]; ApplicationMap m_applications; bool m_isRemoved:1; @@ -292,17 +300,17 @@ class TC_GAME_API Aura std::chrono::steady_clock::time_point m_procCooldown; private: - Unit::AuraApplicationList m_removedApplications; + std::vector<AuraApplication*> _removedApplications; }; class TC_GAME_API UnitAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Aura::Create(AuraCreateInfo& createInfo); protected: - explicit UnitAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + explicit UnitAura(AuraCreateInfo const& createInfo); public: - void _ApplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; - void _UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * aurApp) override; + void _ApplyForTarget(Unit* target, Unit* caster, AuraApplication* aurApp) override; + void _UnapplyForTarget(Unit* target, Unit* caster, AuraApplication* aurApp) override; void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; @@ -312,15 +320,18 @@ class TC_GAME_API UnitAura : public Aura void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; } DiminishingGroup GetDiminishGroup() const { return m_AuraDRGroup; } + void AddStaticApplication(Unit* target, uint8 effMask); + private: DiminishingGroup m_AuraDRGroup; // Diminishing + std::unordered_map<ObjectGuid, uint8> _staticApplications; // non-area auras }; class TC_GAME_API DynObjAura : public Aura { - friend Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Aura::Create(AuraCreateInfo& createInfo); protected: - explicit DynObjAura(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + explicit DynObjAura(AuraCreateInfo const& createInfo); public: void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a92024361c8..799818fd81f 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -609,7 +609,8 @@ m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerO m_glyphIndex = 0; m_preCastSpell = 0; m_triggeredByAuraSpell = nullptr; - m_spellAura = nullptr; + _spellAura = nullptr; + _dynObjAura = nullptr; //Auto Shot & Shoot (wand) m_autoRepeat = m_spellInfo->IsAutoRepeatRangedSpell(); @@ -2315,9 +2316,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) uint32 procVictim = m_procVictim; uint32 hitMask = PROC_HIT_NONE; - m_spellAura = nullptr; // Set aura to null for every target-make sure that pointer is not used for unit without aura applied - - // Spells with this flag cannot trigger if effect is cast on self + // Spells with this flag cannot trigger if effect is cast on self bool const canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE || missInfo == SPELL_MISS_IMMUNE2); Unit* spellHitTarget = nullptr; @@ -2604,14 +2603,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } } - uint8 aura_effmask = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (effectMask & (1 << i) && m_spellInfo->Effects[i].IsUnitOwnedAuraEffect()) - aura_effmask |= 1 << i; + uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, effectMask, unit); // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add - bool const triggered = m_triggeredByAuraSpell != nullptr; - DiminishingGroup const diminishGroup = m_spellInfo->GetDiminishingReturnsGroupForSpell(triggered); + bool triggered = (m_triggeredByAuraSpell != nullptr); + DiminishingGroup diminishGroup = m_spellInfo->GetDiminishingReturnsGroupForSpell(triggered); DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1; if (diminishGroup && aura_effmask) @@ -2628,7 +2624,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA // Select rank for aura with level requirements only in specific cases // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target SpellInfo const* aurSpellInfo = m_spellInfo; - int32 basePoints[MAX_SPELL_EFFECTS]; + int32 basePoints[MAX_SPELL_EFFECTS] = { }; if (scaleAura) { aurSpellInfo = m_spellInfo->GetAuraRankForLevel(unitTarget->getLevel()); @@ -2647,18 +2643,39 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA if (m_originalCaster) { bool refresh = false; - bool const resetPeriodicTimer = !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER); - m_spellAura = Aura::TryRefreshStackOrCreate(aurSpellInfo, effectMask, unit, - m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, resetPeriodicTimer); - if (m_spellAura) + + if (!_spellAura) + { + bool const resetPeriodicTimer = !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER); + uint8 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(aurSpellInfo, MAX_EFFECT_MASK, unit); + int32 const* bp = basePoints; + if (aurSpellInfo == m_spellInfo) + bp = m_spellValue->EffectBasePoints; + + AuraCreateInfo createInfo(aurSpellInfo, allAuraEffectMask, unit); + createInfo + .SetCaster(m_originalCaster) + .SetBaseAmount(bp) + .SetCastItem(m_CastItem) + .SetPeriodicReset(resetPeriodicTimer) + .SetOwnerEffectMask(aura_effmask) + .IsRefresh = &refresh; + + if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo)) + _spellAura = aura->ToUnitAura(); + } + else + _spellAura->AddStaticApplication(unit, aura_effmask); + + if (_spellAura) { // Set aura stack amount to desired value if (m_spellValue->AuraStackAmount > 1) { if (!refresh) - m_spellAura->SetStackAmount(m_spellValue->AuraStackAmount); + _spellAura->SetStackAmount(m_spellValue->AuraStackAmount); else - m_spellAura->ModStackAmount(m_spellValue->AuraStackAmount); + _spellAura->ModStackAmount(m_spellValue->AuraStackAmount); } // Now Reduce spell duration using data received at spell hit @@ -2677,12 +2694,14 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } } - int32 duration = m_spellAura->GetMaxDuration(); + int32 duration = _spellAura->GetMaxDuration(); // unit is immune to aura if it was diminished to 0 duration if (!positive && !unit->ApplyDiminishingToDuration(aurSpellInfo, triggered, duration, m_originalCaster, diminishLevel)) { - m_spellAura->Remove(); + _spellAura->Remove(); + _spellAura = nullptr; + bool found = false; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (effectMask & (1 << i) && m_spellInfo->Effects[i].Effect != SPELL_EFFECT_APPLY_AURA) @@ -2692,7 +2711,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA } else { - static_cast<UnitAura*>(m_spellAura)->SetDiminishGroup(diminishGroup); + _spellAura->SetDiminishGroup(diminishGroup); duration = m_originalCaster->ModSpellDuration(aurSpellInfo, unit, duration, positive, effectMask); @@ -2703,12 +2722,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA else if (m_originalCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, aurSpellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION)) duration = int32(duration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED)); - if (duration != m_spellAura->GetMaxDuration()) + if (duration != _spellAura->GetMaxDuration()) { - m_spellAura->SetMaxDuration(duration); - m_spellAura->SetDuration(duration); + _spellAura->SetMaxDuration(duration); + _spellAura->SetDuration(duration); } - m_spellAura->_RegisterForTargets(); } } } @@ -3536,8 +3554,6 @@ uint64 Spell::handle_delayed(uint64 t_offset) void Spell::_handle_immediate_phase() { - m_spellAura = nullptr; - // handle some immediate features of the spell here HandleThreatSpells(); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 77a74e9593e..ecf0e289d88 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -30,6 +30,7 @@ class Aura; class AuraEffect; class Corpse; class DynamicObject; +class DynObjAura; class GameObject; class Item; class Object; @@ -40,6 +41,7 @@ class SpellImplicitTargetInfo; class SpellInfo; class SpellScript; class Unit; +class UnitAura; class WorldObject; class WorldPacket; struct SummonPropertiesEntry; @@ -331,7 +333,6 @@ class TC_GAME_API Spell void EffectMilling(SpellEffIndex effIndex); void EffectRenamePet(SpellEffIndex effIndex); void EffectSendTaxi(SpellEffIndex effIndex); - void EffectSummonCritter(SpellEffIndex effIndex); void EffectKnockBack(SpellEffIndex effIndex); void EffectPullTowards(SpellEffIndex effIndex); void EffectDispelMechanic(SpellEffIndex effIndex); @@ -609,7 +610,8 @@ class TC_GAME_API Spell SpellMissInfo targetMissInfo; SpellEffectHandleMode effectHandleMode; // used in effects handlers - Aura* m_spellAura; + UnitAura* _spellAura; + DynObjAura* _dynObjAura; // ------------------------------------------- GameObject* focusObject; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 286e6b8c1fe..2695c741874 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1150,10 +1150,10 @@ void Spell::EffectApplyAura(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (!m_spellAura || !unitTarget) + if (!_spellAura || !unitTarget) return; - ASSERT(unitTarget == m_spellAura->GetOwner()); - m_spellAura->_ApplyEffectForTargets(effIndex); + + _spellAura->_ApplyEffectForTargets(effIndex); } void Spell::EffectApplyAreaAura(SpellEffIndex effIndex) @@ -1161,10 +1161,10 @@ void Spell::EffectApplyAreaAura(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (!m_spellAura || !unitTarget) + if (!_spellAura || !unitTarget) return; - ASSERT (unitTarget == m_spellAura->GetOwner()); - m_spellAura->_ApplyEffectForTargets(effIndex); + + _spellAura->_ApplyEffectForTargets(effIndex); } void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex) @@ -1671,32 +1671,42 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - if (!m_spellAura) + // only handle at last effect + for (uint8 i = effIndex + 1; i < MAX_SPELL_EFFECTS; ++i) + if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) + return; + + ASSERT(!_dynObjAura); + + Unit* caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster; + float radius = m_spellInfo->Effects[effIndex].CalcRadius(caster); + + // Caster not in world, might be spell triggered from aura removal + if (!caster->IsInWorld()) + return; + + DynamicObject* dynObj = new DynamicObject(false); + if (!dynObj->CreateDynamicObject(caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL)) { - Unit* caster = m_caster->GetEntry() == WORLD_TRIGGER ? m_originalCaster : m_caster; - float radius = m_spellInfo->Effects[effIndex].CalcRadius(caster); + delete dynObj; + return; + } - // Caster not in world, might be spell triggered from aura removal - if (!caster->IsInWorld()) - return; - DynamicObject* dynObj = new DynamicObject(false); - if (!dynObj->CreateDynamicObject(caster->GetMap()->GenerateLowGuid<HighGuid::DynamicObject>(), caster, m_spellInfo->Id, *destTarget, radius, DYNAMIC_OBJECT_AREA_SPELL)) - { - delete dynObj; - return; - } + AuraCreateInfo createInfo(m_spellInfo, MAX_EFFECT_MASK, dynObj); + createInfo + .SetCaster(caster) + .SetBaseAmount(m_spellValue->EffectBasePoints); - if (Aura* aura = Aura::TryCreate(m_spellInfo, MAX_EFFECT_MASK, dynObj, caster, &m_spellValue->EffectBasePoints[0])) - { - m_spellAura = aura; - m_spellAura->_RegisterForTargets(); - } - else - return; + if (Aura* aura = Aura::TryCreate(createInfo)) + { + _dynObjAura = aura->ToDynObjAura(); + _dynObjAura->_RegisterForTargets(); } + else + return; - ASSERT(m_spellAura->GetDynobjOwner()); - m_spellAura->_ApplyEffectForTargets(effIndex); + ASSERT(_dynObjAura->GetDynobjOwner()); + _dynObjAura->_ApplyEffectForTargets(effIndex); } void Spell::EffectEnergize(SpellEffIndex effIndex) diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 909ae8c9131..a7f852eb884 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -576,18 +576,22 @@ void SpellScript::SetHitHeal(int32 heal) m_spell->m_healing = heal; } -Aura* SpellScript::GetHitAura() const +Aura* SpellScript::GetHitAura(bool dynObjAura /*= false*/) const { if (!IsInTargetHook()) { TC_LOG_ERROR("scripts", "Script: `%s` Spell: `%u`: function SpellScript::GetHitAura was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); return nullptr; } - if (!m_spell->m_spellAura) - return nullptr; - if (m_spell->m_spellAura->IsRemoved()) + + Aura* aura = m_spell->_spellAura; + if (dynObjAura) + aura = m_spell->_dynObjAura; + + if (!aura || aura->IsRemoved()) return nullptr; - return m_spell->m_spellAura; + + return aura; } void SpellScript::PreventHitAura() @@ -597,8 +601,10 @@ void SpellScript::PreventHitAura() TC_LOG_ERROR("scripts", "Script: `%s` Spell: `%u`: function SpellScript::PreventHitAura was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); return; } - if (m_spell->m_spellAura) - m_spell->m_spellAura->Remove(); + if (UnitAura* aura = m_spell->_spellAura) + aura->Remove(); + if (DynObjAura* aura = m_spell->_dynObjAura) + aura->Remove(); } void SpellScript::PreventHitEffect(SpellEffIndex effIndex) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 1f76a3a5b59..3b5385eefa9 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -434,7 +434,7 @@ class TC_GAME_API SpellScript : public _SpellScript void PreventHitHeal() { SetHitHeal(0); } Spell* GetSpell() const { return m_spell; } // returns current spell hit target aura - Aura* GetHitAura() const; + Aura* GetHitAura(bool dynObjAura = false) const; // prevents applying aura on current spell hit target void PreventHitAura(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 9429643b657..a0d4d886717 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -315,7 +315,12 @@ public: uint32 spellId = handler->extractSpellIdFromLink((char*)args); if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) - Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, target, target); + { + AuraCreateInfo createInfo(spellInfo, MAX_EFFECT_MASK, target); + createInfo.SetCaster(target); + + Aura::TryRefreshStackOrCreate(createInfo); + } return true; } |