aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorariel- <ariel-@users.noreply.github.com>2018-01-27 03:45:40 -0300
committerAriel Silva <ariel-@users.noreply.github.com>2018-03-09 14:41:28 -0300
commite8d5aa56cc48572d81e1898b7b4ff10cfa6d1957 (patch)
treeb21b5dff1cdb693074e23eb57906f6a2a2182a76
parent9b38a6352c0fe2499de54fd769aa1c721a410bda (diff)
Core/Spells: rework part 3: spells only handle at most one UnitAura and one DynObjAura during its lifetime
Closes #15088
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp7
-rw-r--r--src/server/game/Entities/Player/Player.cpp7
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp84
-rw-r--r--src/server/game/Entities/Unit/Unit.h14
-rw-r--r--src/server/game/Spells/Auras/SpellAuraDefines.h39
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.h15
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp420
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h77
-rw-r--r--src/server/game/Spells/Spell.cpp68
-rw-r--r--src/server/game/Spells/Spell.h6
-rw-r--r--src/server/game/Spells/SpellEffects.cpp64
-rw-r--r--src/server/game/Spells/SpellScript.cpp20
-rw-r--r--src/server/game/Spells/SpellScript.h2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp7
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;
}