From e3e4b2cf16ff22d0d213742371d9c79b3e2251fd Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Sun, 11 Sep 2022 19:56:59 +0200 Subject: [PATCH] Core/Spells: dropped old dot clipping implementation and restored TC period and duration calculations in preparation of re-implementing it --- src/server/game/Entities/Object/Object.cpp | 18 +++ src/server/game/Entities/Object/Object.h | 1 + src/server/game/Entities/Unit/Unit.cpp | 42 +++---- src/server/game/Entities/Unit/Unit.h | 6 +- .../game/Spells/Auras/SpellAuraDefines.h | 2 + .../game/Spells/Auras/SpellAuraEffects.cpp | 106 ++++++++++++------ .../game/Spells/Auras/SpellAuraEffects.h | 21 ++-- src/server/game/Spells/Auras/SpellAuras.cpp | 57 +++++++--- src/server/game/Spells/Auras/SpellAuras.h | 6 +- src/server/game/Spells/Spell.cpp | 100 ++++++++--------- src/server/game/Spells/Spell.h | 4 +- src/server/game/Spells/SpellDefines.h | 2 +- src/server/game/Spells/SpellInfo.cpp | 96 +--------------- src/server/game/Spells/SpellInfo.h | 6 +- .../boss_icecrown_gunship_battle.cpp | 2 +- 15 files changed, 227 insertions(+), 242 deletions(-) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 5ae790b0d8..57a54d73c8 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -2446,6 +2446,24 @@ float WorldObject::ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effec return value; } +int32 WorldObject::CalcSpellDuration(SpellInfo const* spellInfo) const +{ + uint8 comboPoints = 0; + if (Unit const* unit = ToUnit()) + comboPoints = unit->GetComboPoints(); + + int32 minduration = spellInfo->GetDuration(); + int32 maxduration = spellInfo->GetMaxDuration(); + + int32 duration = 0; + if (spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DURATION) && comboPoints && minduration != -1 && minduration != maxduration) + duration = minduration + int32((maxduration - minduration) * comboPoints / 5); + else + duration = minduration; + + return duration; +} + int32 WorldObject::ModSpellDuration(SpellInfo const* spellInfo, WorldObject const* target, int32 duration, bool positive, uint32 effectMask) { // don't mod permanent auras duration diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index bcbe55ac14..b335669e26 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -443,6 +443,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation float GetSpellMinRangeForTarget(Unit const* target, SpellInfo const* spellInfo) const; float ApplyEffectModifiers(SpellInfo const* spellProto, uint8 effect_index, float value) const; + int32 WorldObject::CalcSpellDuration(SpellInfo const* spellInfo) const; int32 ModSpellDuration(SpellInfo const* spellProto, WorldObject const* target, int32 duration, bool positive, uint32 effectMask); void ModSpellCastTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr); void ModSpellDurationTime(SpellInfo const* spellProto, int32& castTime, Spell* spell = nullptr); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b96e5230c5..fe6bcfb7b5 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -2750,17 +2750,17 @@ void Unit::_UpdateAutoRepeatSpell() } } -void Unit::SetCurrentCastSpell(Spell* pSpell) +void Unit::SetCurrentCastSpell(Spell* spell) { - ASSERT(pSpell); // nullptr may be never passed here, use InterruptSpell or InterruptNonMeleeSpells + ASSERT(spell); // nullptr may be never passed here, use InterruptSpell or InterruptNonMeleeSpells - CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer(); + CurrentSpellTypes CSpellType = spell->GetCurrentContainer(); - if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self + if (spell == m_currentSpells[CSpellType]) // avoid breaking self return; // break same type spell if it is not delayed - InterruptSpell(CSpellType, false, true, pSpell); + InterruptSpell(CSpellType, false, true); // special breakage effects: switch (CSpellType) @@ -2778,7 +2778,7 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) InterruptSpell(CURRENT_AUTOREPEAT_SPELL); m_AutoRepeatFirstCast = true; } - if (pSpell->GetCastTime() > 0) + if (spell->GetCastTime() > 0) AddUnitState(UNIT_STATE_CASTING); break; @@ -2800,7 +2800,7 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) case CURRENT_AUTOREPEAT_SPELL: { // only Auto Shoot does not break anything - if (pSpell->GetSpellInfo()->Id != 75) + if (spell->GetSpellInfo()->Id != 75) { // generic autorepeats break generic non-delayed and channeled non-delayed spells InterruptSpell(CURRENT_GENERIC_SPELL, false); @@ -2820,13 +2820,13 @@ void Unit::SetCurrentCastSpell(Spell* pSpell) m_currentSpells[CSpellType]->SetReferencedFromCurrent(false); // set new current spell - m_currentSpells[CSpellType] = pSpell; - pSpell->SetReferencedFromCurrent(true); + m_currentSpells[CSpellType] = spell; + spell->SetReferencedFromCurrent(true); - pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]); + spell->m_selfContainer = &(m_currentSpells[spell->GetCurrentContainer()]); } -void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant, Spell* interruptingSpell /* = nullptr */) +void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant) { Spell* spell = m_currentSpells[spellType]; if (!spell) @@ -2844,7 +2844,7 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi ToPlayer()->SendAutoRepeatCancel(this); if (spell->getState() != SPELL_STATE_FINISHED) - spell->cancel(interruptingSpell); + spell->cancel(); else { m_currentSpells[spellType] = nullptr; @@ -2898,19 +2898,19 @@ bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAu return false; } -void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant /* = true */, Spell* interruptingSpell /* = nullptr */) +void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant /* = true */) { // generic spells are interrupted if they are not finished or delayed if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant, interruptingSpell); + InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant); // autorepeat spells are interrupted if they are not finished or delayed if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant, interruptingSpell); + InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant); // channeled spells are interrupted if they are not finished, even if they are delayed if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id)) - InterruptSpell(CURRENT_CHANNELED_SPELL, true, true, interruptingSpell); + InterruptSpell(CURRENT_CHANNELED_SPELL, true, true); } Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const @@ -3068,7 +3068,7 @@ Aura* Unit::_TryStackingOrRefreshingExistingAura(AuraCreateInfo& createInfo) } // try to increase stack amount - foundAura->ModStackAmount(1, AuraRemoveFlags::ByDefault); + foundAura->ModStackAmount(1, AuraRemoveFlags::ByDefault, createInfo.ResetPeriodicTimer); return foundAura; } } @@ -3841,7 +3841,7 @@ bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* un } template -void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except, Spell* interruptingSpell /* = nullptr */) +void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except) { if (!HasInterruptFlag(flag)) return; @@ -3868,13 +3868,13 @@ void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except, Spe && spell->GetSpellInfo()->HasChannelInterruptFlag(flag) && spell->GetSpellInfo()->Id != except && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo())) - InterruptNonMeleeSpells(false, 0, true, interruptingSpell); + InterruptNonMeleeSpells(false, 0, true); UpdateInterruptMask(); } -template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint32 except, Spell* interruptingSpell); -template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint32 except, Spell* interruptingSpell); +template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint32 except); +template TC_GAME_API void Unit::RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2 flag, uint32 except); void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID) { diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index f620732cc2..2802fc0412 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1349,7 +1349,7 @@ class TC_GAME_API Unit : public WorldObject void RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID = ObjectGuid::Empty, Aura* except = nullptr, bool negative = true, bool positive = true); void RemoveNotOwnLimitedTargetAuras(bool onPhaseChange = false); template - void RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except = 0, Spell* interruptingSpell = nullptr); + void RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except = 0); void RemoveAurasWithAttribute(uint32 flags); void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID); void RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveFlags removemode = AuraRemoveFlags::ByDefault, uint32 except = 0); @@ -1448,7 +1448,7 @@ class TC_GAME_API Unit : public WorldObject void SetChannelObjectGuid(ObjectGuid guid) { SetGuidValue(UNIT_FIELD_CHANNEL_OBJECT, guid); } void SetCurrentCastSpell(Spell* pSpell); - void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true, Spell* interruptingSpell = nullptr); + void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed = true, bool withInstant = true); void FinishSpell(CurrentSpellTypes spellType, bool ok = true); // set withDelayed to true to account delayed spells as cast @@ -1458,7 +1458,7 @@ class TC_GAME_API Unit : public WorldObject // set withDelayed to true to interrupt delayed spells too // delayed+channeled spells are always interrupted - void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true, Spell* interruptingSpell = nullptr); + void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid = 0, bool withInstant = true); Spell* GetCurrentSpell(CurrentSpellTypes spellType) const { return m_currentSpells[spellType]; } Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; } diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 80aabce89d..906dd513cd 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -509,6 +509,7 @@ struct TC_GAME_API AuraCreateInfo AuraCreateInfo& SetCaster(Unit* caster) { Caster = caster; return *this; } AuraCreateInfo& SetBaseAmount(int32 const* bp) { BaseAmount = bp; return *this; } AuraCreateInfo& SetCastItemGUID(ObjectGuid const& guid) { CastItemGUID = guid; return *this; } + AuraCreateInfo& SetPeriodicReset(bool reset) { ResetPeriodicTimer = reset; return *this; } AuraCreateInfo& SetOwnerEffectMask(uint8 effMask) { _targetEffectMask = effMask; return *this; } SpellInfo const* GetSpellInfo() const { return _spellInfo; } @@ -519,6 +520,7 @@ struct TC_GAME_API AuraCreateInfo int32 const* BaseAmount = nullptr; ObjectGuid CastItemGUID; bool* IsRefresh = nullptr; + bool ResetPeriodicTimer = true; private: SpellInfo const* _spellInfo = nullptr; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 8e875e4dc4..46811a7de8 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -443,7 +443,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= 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), -m_spellmod(nullptr), m_periodicTimer(0), m_tickNumber(0), +m_spellmod(nullptr), _periodicTimer(0), _period(0), _ticksDone(0), m_effIndex(effIndex), m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); @@ -633,8 +633,35 @@ int32 AuraEffect::CalculateAmount(Unit* caster) return amount; } +uint32 AuraEffect::GetTotalTicks() const +{ + uint32 totalTicks = 0; + if (_period && !GetBase()->IsPermanent()) + { + totalTicks = static_cast(GetBase()->GetMaxDuration() / _period); + if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) + ++totalTicks; + } + + return totalTicks; +} + +void AuraEffect::ResetPeriodic(bool resetPeriodicTimer /*= false*/) +{ + _ticksDone = 0; + if (resetPeriodicTimer) + { + _periodicTimer = 0; + // Start periodic on next tick or at aura apply + if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) + _periodicTimer = _period; + } +} + void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer, bool load) { + _period = GetSpellInfo()->Effects[GetEffIndex()].AuraPeriod; + // prepare periodics switch (GetAuraType()) { @@ -657,41 +684,48 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer, bool l break; } - int32_t newPeriod = m_spellInfo->Effects[m_effIndex].CalcPeriod(caster, nullptr); + GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, _period); - GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, newPeriod); - - m_effectPeriodicTimer = 0; if (!m_isPeriodic) return; - m_effectPeriodicTimer = newPeriod; + Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr; + // Apply casting time mods + if (_period) + { + // Apply periodic time mod + if (modOwner) + modOwner->ApplySpellMod(GetSpellInfo()->Id, SPELLMOD_ACTIVATION_TIME, _period); + + if (caster) + { + // Haste modifies periodic time of channeled spells + if (m_spellInfo->IsChanneled()) + caster->ModSpellDurationTime(m_spellInfo, _period); + else if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)) + _period = int32(_period * caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + } + } + else // prevent infinite loop on Update + m_isPeriodic = false; if (load) // aura loaded from db { - m_tickNumber = m_effectPeriodicTimer ? GetBase()->GetDuration() / m_effectPeriodicTimer : 0; - m_periodicTimer = m_effectPeriodicTimer ? GetBase()->GetDuration() % m_effectPeriodicTimer : 0; + if (_period && !GetBase()->IsPermanent()) + { + uint32 elapsedTime = GetBase()->GetMaxDuration() - GetBase()->GetDuration(); + _ticksDone = elapsedTime / uint32(_period); + _periodicTimer = elapsedTime % uint32(_period); + } + if (m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) - ++m_tickNumber; + ++_ticksDone; } else // aura just created or reapplied { - m_tickNumber = 0; - // 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; - // Start periodic on next tick or at aura apply - if (m_effectPeriodicTimer && !m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) - m_periodicTimer += m_effectPeriodicTimer; - - // If the aura was rolled over, use that timer as the first one to ensure ticks connect properly - // in case of a haste proc between this cast and the previous one. - //if (GetBase()->GetRolledOverDuration()) - // m_periodicTimer = GetBase()->GetRolledOverDuration(); - } + ResetPeriodic(resetPeriodicTimer); } } @@ -876,14 +910,18 @@ void AuraEffect::Update(uint32 diff, Unit* caster) { if (m_isPeriodic && (GetBase()->GetDuration() >=0 || GetBase()->IsPassive() || GetBase()->IsPermanent())) { - if (m_periodicTimer > int32(diff)) - m_periodicTimer -= diff; - else // tick also at m_periodicTimer == 0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N + uint32 totalTicks = GetTotalTicks(); + _periodicTimer += diff; + while (_periodicTimer >= _period) { - ++m_tickNumber; + _periodicTimer -= _period; + + if (!GetBase()->IsPermanent() && (_ticksDone + 1) > totalTicks) + break; + + ++_ticksDone; // update before tick (aura can be removed in TriggerSpell or PeriodicTick calls) - m_periodicTimer += m_effectPeriodicTimer - diff; UpdatePeriodic(caster); std::vector effectApplications; @@ -962,7 +1000,7 @@ void AuraEffect::UpdatePeriodic(Unit* caster) // on 2 tick - 133% (handled in 6 second) // Apply bonus for 1 - 4 tick - switch (m_tickNumber) + switch (_ticksDone) { case 1: // 0% aurEff->ChangeAmount(0); @@ -5603,7 +5641,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) case 46284: { CastSpellExtraArgs args(this); - args.AddSpellMod(SPELLVALUE_MAX_TARGETS, int32(m_tickNumber / 10 + 1)); + args.AddSpellMod(SPELLVALUE_MAX_TARGETS, int32(_ticksDone / 10 + 1)); args.SetTriggeringAura(this); target->CastSpell(nullptr, triggerSpellId, args); return; @@ -5612,7 +5650,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) case 66882: { CastSpellExtraArgs args(this); - args.AddSpellMod(SPELLVALUE_RADIUS_MOD, int32((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3)); + args.AddSpellMod(SPELLVALUE_RADIUS_MOD, int32((((float)_ticksDone / 60) * 0.9f + 0.1f) * 10000 * 2 / 3)); args.SetTriggeringAura(this); target->CastSpell(nullptr, triggerSpellId, args); return; @@ -5749,7 +5787,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const case 72854: // Unbound Plague case 72855: // Unbound Plague case 72856: // Unbound Plague - damage *= uint32(pow(1.25f, int32(m_tickNumber))); + damage *= uint32(pow(1.25f, int32(_ticksDone))); break; default: break; @@ -5761,10 +5799,10 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const { uint32 totalTick = GetTotalTicks(); // 1..4 ticks, 1/2 from normal tick damage - if (m_tickNumber <= totalTick / 3) + if (_ticksDone <= totalTick / 3) damage = damage / 2; // 9..12 ticks, 3/2 from normal tick damage - else if (m_tickNumber > totalTick * 2 / 3) + else if (_ticksDone > totalTick * 2 / 3) damage += (damage + 1) / 2; // +1 prevent 0.5 damage possible lost at 1..4 ticks // 5..8 ticks have normal tick damage } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 839874cfaa..bc97674934 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -52,7 +52,7 @@ class TC_GAME_API AuraEffect uint32 GetId() const { return m_spellInfo->Id; } uint32 GetEffIndex() const { return m_effIndex; } int32 GetBaseAmount() const { return m_baseAmount; } - int32 GetPeriodic() const { return m_effectPeriodicTimer; } + int32 GetPeriod() const { return _period; } int32 GetMiscValueB() const { return m_spellInfo->Effects[m_effIndex].MiscValueB; } int32 GetMiscValue() const { return m_spellInfo->Effects[m_effIndex].MiscValue; } @@ -60,8 +60,8 @@ class TC_GAME_API AuraEffect int32 GetAmount() const { return _amount; } void SetAmount(int32 amount); - int32 GetPeriodicTimer() const { return m_periodicTimer; } - void SetPeriodicTimer(int32 periodicTimer) { m_periodicTimer = periodicTimer; } + int32 GetPeriodicTimer() const { return _periodicTimer; } + void SetPeriodicTimer(int32 periodicTimer) { _periodicTimer = periodicTimer; } int32 CalculateAmount(Unit* caster); void CalculatePeriodic(Unit* caster, bool resetPeriodicTimer = true, bool load = false); @@ -78,9 +78,11 @@ class TC_GAME_API AuraEffect void Update(uint32 diff, Unit* caster); void UpdatePeriodic(Unit* caster); - uint32 GetTickNumber() const { return m_tickNumber; } - int32 GetTotalTicks() const { return m_effectPeriodicTimer ? (GetBase()->GetMaxDuration() / m_effectPeriodicTimer) : 1;} - void ResetPeriodic(bool resetPeriodicTimer = false) { if (resetPeriodicTimer) m_periodicTimer = m_effectPeriodicTimer; m_tickNumber = 0;} + uint32 GetTickNumber() const { return _ticksDone; } + uint32 GetRemainingTicks() const { return GetTotalTicks() - _ticksDone; } + uint32 GetTotalTicks() const; + void ResetPeriodic(bool resetPeriodicTimer = false); + void ResetTicks() { _ticksDone = 0; } bool IsPeriodic() const { return m_isPeriodic; } void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; } @@ -107,9 +109,10 @@ class TC_GAME_API AuraEffect SpellModifier* m_spellmod; - int32 m_periodicTimer; - int32 m_effectPeriodicTimer; - uint32 m_tickNumber; + // periodic stuff + int32 _periodicTimer; + int32 _period; // time between consecutive ticks + uint32 _ticksDone; // ticks counter uint8 const m_effIndex; bool m_canBeRecalculated; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 0ea5c6e732..de7b2ba069 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -444,7 +444,6 @@ m_procCooldown(std::chrono::steady_clock::time_point::min()) m_maxDuration = CalcMaxDuration(createInfo.Caster); m_duration = m_maxDuration; - m_rolledOverDuration = 0; m_procCharges = CalcMaxCharges(createInfo.Caster); m_isUsingCharges = m_procCharges != 0; @@ -866,7 +865,25 @@ int32 Aura::CalcMaxDuration(Unit* caster) const /*static*/ int32 Aura::CalcMaxDuration(SpellInfo const* spellInfo, WorldObject* caster) { - return spellInfo->CalcDuration(caster); + Player* modOwner = nullptr; + int32 maxDuration = 0; + + if (caster) + { + modOwner = caster->GetSpellModOwner(); + maxDuration = caster->CalcSpellDuration(spellInfo); + } + else + maxDuration = spellInfo->GetDuration(); + + if (spellInfo->IsPassive() && !spellInfo->DurationEntry) + maxDuration = -1; + + // IsPermanent() checks max duration (which we are supposed to calculate here) + if (maxDuration != -1 && modOwner) + modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, maxDuration); + + return maxDuration; } void Aura::SetDuration(int32 duration, bool withMods) @@ -885,7 +902,11 @@ void Aura::RefreshDuration(bool withMods) Unit* caster = GetCaster(); if (withMods && caster) { - int32 duration = m_spellInfo->CalcDuration(caster); + int32 duration = m_spellInfo->GetMaxDuration(); + // Calculate duration of periodics affected by haste. + if (caster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, m_spellInfo) || m_spellInfo->HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION)) + duration = int32(duration * caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + SetMaxDuration(duration); SetDuration(duration); } @@ -894,24 +915,30 @@ void Aura::RefreshDuration(bool withMods) if (m_spellInfo->ManaPerSecond) m_timeCla = 1 * IN_MILLISECONDS; + + // also reset periodic counters + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect* aurEff = m_effects[i]) + aurEff->ResetTicks(); } -void Aura::RefreshTimers() +void Aura::RefreshTimers(bool resetPeriodicTimer) { m_maxDuration = CalcMaxDuration(); - bool resetPeriodicTimer = !m_spellInfo->IsRollingDurationOver(); - if (!resetPeriodicTimer) { - int32 minAmplitude = m_maxDuration; + int32 minPeriod = m_maxDuration; for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (AuraEffect const* eff = GetEffect(i)) - if (int32 ampl = eff->GetPeriodic()) - minAmplitude = std::min(ampl, minAmplitude); + if (AuraEffect const* aurEff = GetEffect(i)) + if (int32 period = aurEff->GetPeriod()) + minPeriod = std::min(period, minPeriod); - // Roll over the time to next tick into the new duration - m_rolledOverDuration = GetDuration() % minAmplitude; - m_maxDuration += m_rolledOverDuration; + // If only one tick remaining, roll it over into new duration + if (GetDuration() <= minPeriod) + { + m_maxDuration += GetDuration(); + resetPeriodicTimer = false; + } } RefreshDuration(); @@ -1011,7 +1038,7 @@ void Aura::SetStackAmount(uint8 stackAmount) SetNeedClientUpdateForTargets(); } -bool Aura::ModStackAmount(int32 num, AuraRemoveFlags removeMode /*= AuraRemoveFlags::ByDefault*/) +bool Aura::ModStackAmount(int32 num, AuraRemoveFlags removeMode /*= AuraRemoveFlags::ByDefault*/, bool resetPeriodicTimer /*= true*/) { int32 stackAmount = m_stackAmount + num; @@ -1040,7 +1067,7 @@ bool Aura::ModStackAmount(int32 num, AuraRemoveFlags removeMode /*= AuraRemoveFl if (refresh && !removeFlags.HasFlag(AuraRemoveFlags::DontResetPeriodicTimer)) { - RefreshTimers(); + RefreshTimers(resetPeriodicTimer); // reset charges SetCharges(CalcMaxCharges()); diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 0ca6d1a5b1..8739e88d48 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -153,9 +153,8 @@ class TC_GAME_API Aura static int32 CalcMaxDuration(SpellInfo const* spellInfo, WorldObject* caster); int32 GetDuration() const { return m_duration; } void SetDuration(int32 duration, bool withMods = false); - int32_t GetRolledOverDuration() const { return m_rolledOverDuration; } void RefreshDuration(bool withMods = false); - void RefreshTimers(); + void RefreshTimers(bool resetPeriodicTimer); bool IsExpired() const { return !GetDuration() && !m_dropEvent; } bool IsPermanent() const { return GetMaxDuration() == -1; } @@ -170,7 +169,7 @@ class TC_GAME_API Aura uint8 GetStackAmount() const { return m_stackAmount; } void SetStackAmount(uint8 num); - bool ModStackAmount(int32 num, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault); + bool ModStackAmount(int32 num, AuraRemoveFlags removeMode = AuraRemoveFlags::ByDefault, bool resetPeriodicTimer = true); bool CanApplyResilience() const { return _casterInfo.ApplyResilience; } void SetCanApplyResilience(bool val) { _casterInfo.ApplyResilience = val; } @@ -289,7 +288,6 @@ class TC_GAME_API Aura int32 m_maxDuration; // Max aura duration int32 m_duration; // Current time - int32 m_rolledOverDuration; // Duration remainder, rolled over on refresh, if the spell does not reset its periodic timer. // This is normally the time remaining until the next tick of the dot when refreshed. int32 m_timeCla; // Timer for power per sec calcultion int32 m_updateTargetMapInterval; // Timer for UpdateTargetMapOfEffect diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e690c98bdb..8caefd757c 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2967,6 +2967,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo) if (!hitInfo.HitAura) { + bool const resetPeriodicTimer = (m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER); uint8 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(hitInfo.AuraSpellInfo, MAX_EFFECT_MASK, unit); int32 const* bp = hitInfo.AuraBasePoints; if (hitInfo.AuraSpellInfo == m_spellInfo) @@ -2977,6 +2978,7 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo) .SetCasterGUID(caster->GetGUID()) .SetBaseAmount(bp) .SetCastItemGUID(m_CastItem ? m_CastItem->GetGUID() : ObjectGuid::Empty) + .SetPeriodicReset(resetPeriodicTimer) .SetOwnerEffectMask(aura_effmask) .IsRefresh = &refresh; @@ -2995,7 +2997,31 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo) hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup); - hitInfo.AuraDuration = caster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask()); + //if (!m_spellValue->Duration) + { + hitInfo.AuraDuration = caster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask()); + + if (hitInfo.AuraDuration > 0) + { + // Haste modifies duration of channeled spells + if (m_spellInfo->IsChanneled()) + caster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this); + else if (m_spellInfo->HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION)) + { + int32 origDuration = hitInfo.AuraDuration; + hitInfo.AuraDuration = 0; + + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect const* aurEff = hitInfo.HitAura->GetEffect(effIndex)) + if (int32 period = aurEff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED + hitInfo.AuraDuration = std::max(std::max(origDuration / period, 1) * period, hitInfo.AuraDuration); + + // if there is no periodic effect + if (!hitInfo.AuraDuration) + hitInfo.AuraDuration = int32(origDuration * m_originalCaster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + } + } + } if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration()) { @@ -3003,20 +3029,6 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo) hitInfo.HitAura->SetDuration(hitInfo.AuraDuration); } - if (DynamicObject* dynObj = m_originalCaster->GetDynObject(m_spellInfo->Id)) - dynObj->SetDuration(hitInfo.AuraDuration); - - if (m_spellInfo->IsChanneled() && refresh && m_spellInfo->IsRollingDurationOver()) - { - SendChannelStart(hitInfo.HitAura->GetMaxDuration() - hitInfo.HitAura->GetRolledOverDuration()); - SendChannelUpdate(hitInfo.HitAura->GetMaxDuration()); - - // A side-effect of SendChannelStart() is to set the spell's timer to the value passed as parameter. - // However for channeled dot clipping to work properly, we need to roll over the duration. - // So we need to re-update timer with a proper value. - m_timer = hitInfo.HitAura->GetMaxDuration(); - } - if (refresh) hitInfo.HitAura->AddStaticApplication(unit, aura_effmask); } @@ -3331,7 +3343,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const return SPELL_CAST_OK; } -void Spell::cancel(Spell* interruptingSpell /* = nullptr */) +void Spell::cancel() { if (m_spellState == SPELL_STATE_FINISHED) return; @@ -3339,8 +3351,6 @@ void Spell::cancel(Spell* interruptingSpell /* = nullptr */) uint32 oldState = m_spellState; m_spellState = SPELL_STATE_FINISHED; - bool sendChannelUpdate = m_spellInfo->IsChanneled(); - m_autoRepeat = false; switch (oldState) { @@ -3351,40 +3361,17 @@ void Spell::cancel(Spell* interruptingSpell /* = nullptr */) SendInterrupted(0); SendCastResult(SPELL_FAILED_INTERRUPTED); break; - case SPELL_STATE_CASTING: for (TargetInfo const& targetInfo : m_UniqueTargetInfo) - { - // Remove if no miss. - bool removeOwnedAura = targetInfo.MissCondition == SPELL_MISS_NONE; - if (interruptingSpell != nullptr) - { - // However if we are refreshing a channeled spell, only removed owned aura - // if the new target isn't the old one. - if (m_spellInfo->Id == interruptingSpell->m_spellInfo->Id && m_spellInfo->IsChanneled()) - { - // Different target, ease up on the core and already remove auras - // if same target, do nothing. If we miss with the new spell, auras will get removed anyways - removeOwnedAura = targetInfo.TargetGUID != interruptingSpell->m_targets.GetUnitTargetGUID(); - } - } - - if (removeOwnedAura) + if (targetInfo.MissCondition == SPELL_MISS_NONE) if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID)) unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AuraRemoveFlags::ByCancel); - } - - // Only send channel updates if we are interrupt with a spell that is not the one currently channeled. - sendChannelUpdate &= interruptingSpell == nullptr || m_spellInfo->Id != interruptingSpell->m_spellInfo->Id; - if (sendChannelUpdate) - { - SendInterrupted(0); - SendCastResult(SPELL_FAILED_INTERRUPTED); - } + SendChannelUpdate(0); + SendInterrupted(0); + SendCastResult(SPELL_FAILED_INTERRUPTED); m_appliedMods.clear(); break; - default: break; } @@ -3404,7 +3391,7 @@ void Spell::cancel(Spell* interruptingSpell /* = nullptr */) //set state back so finish will be processed m_spellState = oldState; - finish(false, sendChannelUpdate); + finish(false); } void Spell::cast(bool skipCheck) @@ -3717,18 +3704,22 @@ void Spell::handle_immediate() // start channeling if applicable if (m_spellInfo->IsChanneled()) { - int32 duration = m_spellInfo->CalcDuration(m_caster); + int32 duration = m_spellInfo->GetDuration(); if (duration > 0) { + // First mod_duration then haste - see Missile Barrage + // Apply duration mod + if (Player* modOwner = m_caster->GetSpellModOwner()) + modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration); + + // Apply haste mods + m_caster->ModSpellDurationTime(m_spellInfo, duration, this); + m_channeledDuration = duration; SendChannelStart(duration); } else if (duration == -1) - { SendChannelStart(duration); - } - - m_spellState = SPELL_STATE_CASTING; if (duration != 0) { @@ -4057,7 +4048,7 @@ void Spell::update(uint32 difftime) } } -void Spell::finish(bool ok, bool sendChannelUpdate /* = false */) +void Spell::finish(bool ok) { if (m_spellState == SPELL_STATE_FINISHED) return; @@ -4073,9 +4064,6 @@ void Spell::finish(bool ok, bool sendChannelUpdate /* = false */) if (m_spellInfo->IsChanneled()) unitCaster->UpdateInterruptMask(); - if (sendChannelUpdate) - SendChannelUpdate(0); - if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true)) unitCaster->ClearUnitState(UNIT_STATE_CASTING); @@ -7527,7 +7515,7 @@ void Spell::DelayedChannel() unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime); // partially interrupt persistent area auras - if (DynamicObject* dynObj = playerCaster->GetDynObject(m_spellInfo->Id)) + if (DynamicObject* dynObj = unitCaster->GetDynObject(m_spellInfo->Id)) dynObj->Delay(delaytime); SendChannelUpdate(m_timer); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index cf423e5c1f..09bed678ac 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -441,10 +441,10 @@ class TC_GAME_API Spell GameObject* SearchSpellFocus(); SpellCastResult prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura = nullptr); - void cancel(Spell* interruptingSpell = nullptr); + void cancel(); void update(uint32 difftime); void cast(bool skipCheck = false); - void finish(bool ok = true, bool sendChannelUpdate = false); + void finish(bool ok = true); void TakePower(); void TakeAmmo(); diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index 76b73d45f7..1fad5bb3cc 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -175,7 +175,7 @@ enum TriggerCastFlags : uint32 TRIGGERED_IGNORE_BLOCKED_SPELL_FAMILY = 0x00004000, //! Will ignore blocked casts of SPELL_AURA_BLOCK_SPELL_FAMILY // reuse = 0x00008000, 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_FULL_MASK = 0x0007FFFF, //! Used when doing CastSpell with triggered == true diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 18d4d9a351..c117d2053e 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -3323,20 +3323,6 @@ float SpellInfo::CalculateScaledCoefficient(Unit const* caster, float coefficien return coefficient *= GetSpellScalingMultiplier(caster, GetSpellScaling()); } -// As of patch 4.0.1 all DoT and HoT effects roll their ticks over. Since this behavior has also been observed for boss DoTs -// (Reverberating Hymn at Temple Guardian Anhuur and Burning Wound at Ragnaros etc), we can assume that this is a generic feature of Cataclysm. -bool SpellInfo::IsRollingDurationOver() const -{ - if (HasAttribute(SPELL_ATTR0_CU_RESET_PERIODIC_TIMER)) - return false; - - if (HasAttribute(SPELL_ATTR0_CU_DONT_RESET_PERIODIC_TIMER)) - return true; - - // @todo: determine further aura types that behave like this - return (HasAura(SPELL_AURA_PERIODIC_DAMAGE)|| HasAura(SPELL_AURA_PERIODIC_HEAL)); -} - float SpellInfo::GetMinRange(bool positive) const { if (!RangeEntry) @@ -3375,85 +3361,13 @@ int32 SpellInfo::GetMaxDuration() const return (DurationEntry->MaxDuration == -1) ? -1 : abs(DurationEntry->MaxDuration); } -int32 SpellInfo::CalcDuration(WorldObject const* caster, Spell* spell) const +int32 SpellInfo::CalcDuration(WorldObject const* caster /*= nullptr*/) const { - if (IsPassive() && !DurationEntry) - return -1; + int32 duration = GetDuration(); - if (!DurationEntry) - return 0; - - int32 duration = GetMaxDuration(); - if (duration == -1) - return -1; - - Unit const* unitCaster = caster ? caster->ToUnit() : nullptr; - if (!unitCaster) - return std::min(GetMaxDuration(), DurationEntry->Duration); - - uint32 level = unitCaster->getLevel(); - if (MaxLevel > 0 && level > MaxLevel) - level = MaxLevel; - if (BaseLevel > 0) - level -= BaseLevel; - - duration = DurationEntry->Duration + DurationEntry->DurationPerLevel * level; - duration = std::min(GetMaxDuration(), duration); - - if (duration == -1) - return -1; - - // Increase duration based on combo points - if (HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DURATION)) - { - if (uint8 comboPoints = unitCaster->IsMovedByClient() ? unitCaster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints() : 0) - { - if (GetDuration() != GetMaxDuration() && GetDuration() != -1) - duration += int32((GetMaxDuration() - GetDuration()) * comboPoints / 5); - } - } - - if (Player* modOwner = unitCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(Id, SPELLMOD_DURATION, duration, spell); - - bool hasteAffectsDuration = HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION); - bool spellHasteAffectsPeriodic = HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC); - // That aura is not used as of 4.3.4, but just include it, as it still is technically supported by the client, and so should we. - bool hasPeriodicHasteAuras = unitCaster->HasAuraTypeWithAffectMask(SPELL_AURA_PERIODIC_HASTE, this); - - if (spellHasteAffectsPeriodic || hasteAffectsDuration) - { - // This is just a stupid way to find the first periodic effect. - int32 periodicEffectIndex = 0; - while ((Effects[periodicEffectIndex].Effect == 0 || Effects[periodicEffectIndex].AuraPeriod == 0)) - { - ++periodicEffectIndex; - if (periodicEffectIndex >= MAX_SPELL_EFFECTS) - return duration; - } - - if ((spellHasteAffectsPeriodic || hasPeriodicHasteAuras) && !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS)) - { - float hasteValue = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE); - if (hasteValue > 0.0f) - { - if (hasteAffectsDuration) - return int32(duration * hasteValue); - - int32 effectPeriod = Effects[periodicEffectIndex].CalcPeriod(unitCaster, spell); - - if (effectPeriod > 0) - { - // additional ticks are being added by rounding up, resulting in increased duration. - float preciseTicks = (float)duration / float(effectPeriod); - int32 ticks = duration / effectPeriod; - if (preciseTicks - ticks >= 0.5f) - ticks = int32(std::ceil(preciseTicks)); - duration = std::max(ticks * effectPeriod, duration); - } - } - } - } + if (caster) + if (Player* modOwner = caster->GetSpellModOwner()) + modOwner->ApplySpellMod(Id, SPELLMOD_DURATION, duration); return duration; } diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index c586e8b192..98bce44496 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -203,8 +203,6 @@ enum SpellCustomAttributes SPELL_ATTR0_CU_BINARY_SPELL = 0x00100000, SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC = 0x00200000, SPELL_ATTR0_CU_LIQUID_AURA = 0x00400000, - SPELL_ATTR0_CU_DONT_RESET_PERIODIC_TIMER = 0x00800000, - SPELL_ATTR0_CU_RESET_PERIODIC_TIMER = 0x01000000, SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2 }; @@ -584,7 +582,7 @@ class TC_GAME_API SpellInfo int32 GetDuration() const; int32 GetMaxDuration() const; - int32 CalcDuration(WorldObject const* caster, Spell* spell = nullptr) const; + int32 CalcDuration(WorldObject const* caster = nullptr) const; uint32 GetMaxTicks() const; @@ -622,8 +620,6 @@ class TC_GAME_API SpellInfo float CalculateScaledCoefficient(Unit const* caster, float coefficient) const; - bool IsRollingDurationOver() const; - private: // loading helpers void _InitializeExplicitTargetMask(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index c1a9467f6c..e774802a2b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -1830,7 +1830,7 @@ class spell_igb_rocket_pack : public SpellScriptLoader void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { SpellInfo const* damageInfo = sSpellMgr->AssertSpellInfo(SPELL_ROCKET_PACK_DAMAGE); - int32 bp = 2 * (damageInfo->Effects[EFFECT_0].CalcValue() + aurEff->GetTickNumber() * aurEff->GetPeriodic()); + int32 bp = 2 * (damageInfo->Effects[EFFECT_0].CalcValue() + aurEff->GetTickNumber() * aurEff->GetPeriod()); GetTarget()->CastSpell(nullptr, SPELL_ROCKET_PACK_DAMAGE, CastSpellExtraArgs(true).AddSpellBP0(bp)); GetTarget()->CastSpell(nullptr, SPELL_ROCKET_BURST, TRIGGERED_FULL_MASK); }