diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 0155871786d..a8287893f54 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3161,7 +3161,7 @@ void Unit::DeMorph() SetDisplayId(GetNativeDisplayId()); } -Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= 0*/) +Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool resetPeriodicTimer /*= true*/) { ASSERT(casterGUID || caster); @@ -3184,7 +3184,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 // extremely rare case // let's just recreate aura if (effMask != foundAura->GetEffectMask()) - return NULL; + return nullptr; // update basepoints with new values - effect amount will be recalculated in ModStackAmount for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -3210,12 +3210,12 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 } // try to increase stack amount - foundAura->ModStackAmount(1); + foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, resetPeriodicTimer); return foundAura; } } - return NULL; + return nullptr; } void Unit::_AddAura(UnitAura* aura, Unit* caster) @@ -3823,7 +3823,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, U if (aura->IsSingleTarget()) aura->UnregisterSingleTarget(); - if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID())) + if (Aura* newAura = Aura::TryRefreshStackOrCreate(aura->GetSpellInfo(), effMask, stealer, nullptr, &baseDamage[0], nullptr, aura->GetCasterGUID())) { // created aura must not be single target aura,, so stealer won't loose it on recast if (newAura->IsSingleTarget()) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7d741c43bac..d6ca5a0dc7c 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -452,7 +452,7 @@ enum TriggerCastFlags TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE = 0x00002000, //! Will ignore mounted/on vehicle restrictions TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements - // reuse 0x00020000 + TRIGGERED_DONT_RESET_PERIODIC_TIMER = 0x00020000, //! Will allow periodic aura timers to keep ticking (instead of resetting) TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements TRIGGERED_IGNORE_TARGET_CHECK = 0x00100000, //! Will ignore most target checks (mostly DBC target checks) @@ -1734,16 +1734,14 @@ 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 = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); + Aura* _TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount = nullptr, Item* castItem = nullptr, ObjectGuid casterGUID = ObjectGuid::Empty, bool resetPeriodicTimer = true); void _AddAura(UnitAura* aura, Unit* caster); AuraApplication * _CreateAuraApplication(Aura* aura, uint8 effMask); void _ApplyAuraEffect(Aura* aura, uint8 effIndex); void _ApplyAura(AuraApplication * aurApp, uint8 effMask); void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode); void _UnapplyAura(AuraApplication * aurApp, AuraRemoveMode removeMode); - void _RemoveNoStackAuraApplicationsDueToAura(Aura* aura); void _RemoveNoStackAurasDueToAura(Aura* aura); - bool _IsNoStackAuraDueToAura(Aura* appliedAura, Aura* existingAura) const; void _RegisterAuraEffect(AuraEffect* aurEff, bool apply); // m_ownedAuras container management diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 44f1bbd93de..d6c74255ac1 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -629,8 +629,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru if (!m_isPeriodic) return; - Player* modOwner = caster ? caster->GetSpellModOwner() : NULL; - + Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr; // Apply casting time mods if (m_amplitude) { @@ -658,9 +657,9 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru else // aura just created or reapplied { m_tickNumber = 0; - // reset periodic timer on aura create or on reapply when aura isn't dot - // possibly we should not reset periodic timers only when aura is triggered by proc - // or maybe there's a spell attribute somewhere + + // reset periodic timer on aura create or reapply + // we don't reset periodic timers when aura is triggered by proc if (resetPeriodicTimer) { m_periodicTimer = 0; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 4d4e1213076..7cba9937f40 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -29,8 +29,8 @@ typedef void(AuraEffect::*pAuraEffectHandler)(AuraApplication const* aurApp, uin 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); + 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 Aura::~Aura(); private: ~AuraEffect(); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 97ab83a4103..b937a5faea4 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -230,7 +230,7 @@ void AuraApplication::ClientUpdate(bool remove) _target->SendMessageToSet(&data, true); } -uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner) +uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 availableEffectMask, WorldObject* owner) { ASSERT(spellProto); ASSERT(owner); @@ -239,26 +239,28 @@ uint8 Aura::BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleE { case TYPEID_UNIT: case TYPEID_PLAYER: - for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (spellProto->Effects[i].IsUnitOwnedAuraEffect()) effMask |= 1 << i; } break; case TYPEID_DYNAMICOBJECT: - for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) { if (spellProto->Effects[i].Effect == SPELL_EFFECT_PERSISTENT_AREA_AURA) effMask |= 1 << i; } break; default: + ABORT(); break; } - return effMask & avalibleEffectMask; + + return effMask & availableEffectMask; } -Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/, bool* refresh /*= NULL*/) +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*/) { ASSERT(spellproto); ASSERT(owner); @@ -266,25 +268,28 @@ Aura* Aura::TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMas ASSERT(tryEffMask <= MAX_EFFECT_MASK); if (refresh) *refresh = false; + uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (!effMask) - return NULL; - if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID)) + return nullptr; + + if (Aura* foundAura = owner->ToUnit()->_TryStackingOrRefreshingExistingAura(spellproto, effMask, caster, baseAmount, castItem, casterGUID, resetPeriodicTimer)) { // 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 NULL; + return nullptr; if (refresh) *refresh = true; + return foundAura; } else return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); } -Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/) +Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount /*= nullptr*/, Item* castItem /*= nullptr*/, ObjectGuid casterGUID /*= ObjectGuid::Empty*/) { ASSERT(spellproto); ASSERT(owner); @@ -292,7 +297,8 @@ Aura* Aura::TryCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject ASSERT(tryEffMask <= MAX_EFFECT_MASK); uint8 effMask = Aura::BuildEffectMaskForOwner(spellproto, tryEffMask, owner); if (!effMask) - return NULL; + return nullptr; + return Create(spellproto, effMask, owner, caster, baseAmount, castItem, casterGUID); } @@ -319,9 +325,9 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne if (!owner->IsInWorld() || ((Unit*)owner)->IsDuringRemoveFromWorld()) // owner not in world so don't allow to own not self cast single target auras if (casterGUID != owner->GetGUID() && spellproto->IsSingleTarget()) - return NULL; + return nullptr; - Aura* aura = NULL; + Aura* aura = nullptr; switch (owner->GetTypeId()) { case TYPEID_UNIT: @@ -333,11 +339,12 @@ Aura* Aura::Create(SpellInfo const* spellproto, uint8 effMask, WorldObject* owne break; default: ABORT(); - return NULL; + return nullptr; } + // aura can be removed in Unit::_AddAura call if (aura->IsRemoved()) - return NULL; + return nullptr; return aura; } @@ -774,10 +781,9 @@ void Aura::RefreshDuration(bool withMods) m_timeCla = 1 * IN_MILLISECONDS; } -void Aura::RefreshTimers() +void Aura::RefreshTimers(bool resetPeriodicTimer) { m_maxDuration = CalcMaxDuration(); - bool resetPeriodic = true; if (m_spellInfo->HasAttribute(SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER)) { int32 minAmplitude = m_maxDuration; @@ -790,15 +796,16 @@ void Aura::RefreshTimers() if (GetDuration() <= minAmplitude) { m_maxDuration += GetDuration(); - resetPeriodic = false; + resetPeriodicTimer = false; } } RefreshDuration(); + Unit* caster = GetCaster(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (HasEffect(i)) - GetEffect(i)->CalculatePeriodic(caster, resetPeriodic, false); + if (AuraEffect* aurEff = m_effects[i]) + aurEff->CalculatePeriodic(caster, resetPeriodicTimer, false); } void Aura::SetCharges(uint8 charges) @@ -895,7 +902,7 @@ void Aura::SetStackAmount(uint8 stackAmount) SetNeedClientUpdateForTargets(); } -bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode) +bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool resetPeriodicTimer /*= true*/) { int32 stackAmount = m_stackAmount + num; @@ -923,7 +930,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveMode removeMode) if (refresh) { RefreshSpellMods(); - RefreshTimers(); + RefreshTimers(resetPeriodicTimer); // reset charges SetCharges(CalcMaxCharges()); @@ -1085,14 +1092,16 @@ void Aura::SetLoadedState(int32 maxduration, int32 duration, int32 charges, uint m_stackAmount = stackamount; Unit* caster = GetCaster(); for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (m_effects[i]) + { + if (AuraEffect* aurEff = m_effects[i]) { - m_effects[i]->SetAmount(amount[i]); - m_effects[i]->SetCanBeRecalculated((recalculateMask & (1 << i)) != 0); - m_effects[i]->CalculatePeriodic(caster, false, true); - m_effects[i]->CalculateSpellMod(); - m_effects[i]->RecalculateAmount(caster); + aurEff->SetAmount(amount[i]); + aurEff->SetCanBeRecalculated((recalculateMask & (1 << i)) != 0); + aurEff->CalculatePeriodic(caster, false, true); + aurEff->CalculateSpellMod(); + aurEff->RecalculateAmount(caster); } + } } bool Aura::HasEffectType(AuraType type) const diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 4ebe087d840..5bb7dfc7c1f 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -84,13 +84,13 @@ class TC_GAME_API AuraApplication class TC_GAME_API Aura { - friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID); + friend Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32 *baseAmount, Item* castItem, ObjectGuid casterGUID, bool resetPeriodicTimer); public: typedef std::map ApplicationMap; - static uint8 BuildEffectMaskForOwner(SpellInfo const* spellProto, uint8 avalibleEffectMask, WorldObject* owner); - static Aura* TryRefreshStackOrCreate(SpellInfo const* spellproto, uint8 tryEffMask, WorldObject* owner, Unit* caster, int32* baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty, bool* refresh = NULL); - static Aura* TryCreate(SpellInfo const* spellproto, uint8 effMask, WorldObject* owner, Unit* caster, int32 *baseAmount = NULL, Item* castItem = NULL, ObjectGuid casterGUID = ObjectGuid::Empty); + 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); @@ -131,7 +131,7 @@ class TC_GAME_API Aura int32 GetDuration() const { return m_duration; } void SetDuration(int32 duration, bool withMods = false); void RefreshDuration(bool withMods = false); - void RefreshTimers(); + void RefreshTimers(bool resetPeriodicTimer); bool IsExpired() const { return !GetDuration() && !m_dropEvent; } bool IsPermanent() const { return GetMaxDuration() == -1; } @@ -146,7 +146,7 @@ class TC_GAME_API Aura uint8 GetStackAmount() const { return m_stackAmount; } void SetStackAmount(uint8 num); - bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + bool ModStackAmount(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer = true); void RefreshSpellMods(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 322fcce3ba1..d30dd29a27e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2653,8 +2653,9 @@ 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); + m_originalCaster, (aurSpellInfo == m_spellInfo) ? &m_spellValue->EffectBasePoints[0] : &basePoints[0], m_CastItem, ObjectGuid::Empty, &refresh, resetPeriodicTimer); if (m_spellAura) { // Set aura stack amount to desired value diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp index 62593769258..f3764c68434 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp @@ -231,11 +231,7 @@ class boss_kelidan_the_breaker : public CreatureScript Talk(SAY_NOVA); - if (SpellInfo const* nova = sSpellMgr->GetSpellInfo(SPELL_BURNING_NOVA)) - { - if (Aura* aura = Aura::TryRefreshStackOrCreate(nova, MAX_EFFECT_MASK, me, me)) - aura->ApplyForTargets(); - } + me->AddAura(SPELL_BURNING_NOVA, me); if (IsHeroic()) DoTeleportAll(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index f17cbbcded0..9d9955591e3 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -748,12 +748,14 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader Unit* caster = GetCaster(); // Refresh Shadow Word: Pain on target if (Unit* target = GetHitUnit()) + { if (AuraEffect* aur = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x8000, 0, 0, caster->GetGUID())) { aur->SetBonusAmount(caster->SpellDamageBonusDone(target, aur->GetSpellInfo(), 0, DOT)); aur->CalculatePeriodic(caster, false, false); aur->GetBase()->RefreshDuration(); } + } } void Register() override diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 53675688b47..6de09b0a63e 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -544,6 +544,7 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader { Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) + { // Refresh corruption on target if (AuraEffect* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, caster->GetGUID())) { @@ -551,6 +552,7 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader aurEff->CalculatePeriodic(caster, false, false); aurEff->GetBase()->RefreshDuration(true); } + } } void Register() override