diff options
11 files changed, 117 insertions, 53 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e39c596c60a..30e04dbd629 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13367,11 +13367,11 @@ uint32 Unit::GetRemainingPeriodicAmount(ObjectGuid caster, uint32 spellId, AuraT { uint32 amount = 0; AuraEffectList const& periodicAuras = GetAuraEffectsByType(auraType); - for (AuraEffectList::const_iterator i = periodicAuras.begin(); i != periodicAuras.end(); ++i) + for (AuraEffect const* aurEff : periodicAuras) { - if ((*i)->GetCasterGUID() != caster || (*i)->GetId() != spellId || (*i)->GetEffIndex() != effectIndex || !(*i)->GetTotalTicks()) + if (aurEff->GetCasterGUID() != caster || aurEff->GetId() != spellId || aurEff->GetEffIndex() != effectIndex || !aurEff->GetTotalTicks()) continue; - amount += uint32(((*i)->GetAmount() * std::max<int32>((*i)->GetTotalTicks() - int32((*i)->GetTickNumber()), 0)) / (*i)->GetTotalTicks()); + amount += uint32((aurEff->GetAmount() * static_cast<int32>(aurEff->GetRemainingTicks())) / aurEff->GetTotalTicks()); break; } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 89aaa7db4c6..eef239d13b5 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -578,7 +578,7 @@ AuraEffect::AuraEffect(Aura* base, SpellEffectInfo const* spellEfffectInfo, int3 m_base(base), m_spellInfo(base->GetSpellInfo()), m_effectInfo(spellEfffectInfo), m_spellmod(nullptr), m_baseAmount(baseAmount ? *baseAmount : spellEfffectInfo->CalcBaseValue(caster, base->GetType() == UNIT_AURA_TYPE ? base->GetOwner()->ToUnit() : nullptr, base->GetCastItemId(), base->GetCastItemLevel())), m_damage(0), m_critChance(0.0f), m_donePct(1.0f), -m_periodicTimer(0), m_tickNumber(0), +_periodicTimer(0), _period(0), _ticksDone(0), m_canBeRecalculated(true), m_isPeriodic(false) { CalculatePeriodic(caster, true, false); @@ -673,18 +673,26 @@ int32 AuraEffect::CalculateAmount(Unit* caster) return amount; } +void AuraEffect::ResetPeriodic(bool resetPeriodicTimer /*= false*/) +{ + _ticksDone = 0; + if (resetPeriodicTimer) + { + _periodicTimer = _period; + // Start periodic on next tick or at aura apply + if (!m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) + _periodicTimer = 0; + } +} + void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= true*/, bool load /*= false*/) { - m_period = GetSpellEffectInfo()->ApplyAuraPeriod; + _period = GetSpellEffectInfo()->ApplyAuraPeriod; // prepare periodics switch (GetAuraType()) { case SPELL_AURA_OBS_MOD_POWER: - // 3 spells have no amplitude set - if (!m_period) - m_period = 1 * IN_MILLISECONDS; - /* fallthrough */ case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_HEAL: case SPELL_AURA_OBS_MOD_HEALTH: @@ -703,49 +711,48 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru break; } - GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, m_period); + GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, _period); if (!m_isPeriodic) return; Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr; // Apply casting time mods - if (m_period) + if (_period) { // Apply periodic time mod if (modOwner) - modOwner->ApplySpellMod(GetSpellInfo(), SPELLMOD_ACTIVATION_TIME, m_period); + modOwner->ApplySpellMod(GetSpellInfo(), SPELLMOD_ACTIVATION_TIME, _period); if (caster) { // Haste modifies periodic time of channeled spells if (m_spellInfo->IsChanneled()) - caster->ModSpellDurationTime(m_spellInfo, m_period); + caster->ModSpellDurationTime(m_spellInfo, _period); else if (m_spellInfo->HasAttribute(SPELL_ATTR5_HASTE_AFFECT_DURATION)) - m_period = int32(m_period * caster->m_unitData->ModCastingSpeed); + _period = int32(_period * caster->m_unitData->ModCastingSpeed); } } + else // prevent infinite loop on Update + m_isPeriodic = false; if (load) // aura loaded from db { - m_tickNumber = m_period ? GetBase()->GetDuration() / m_period : 0; - m_periodicTimer = m_period ? GetBase()->GetDuration() % m_period : 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_period && !m_spellInfo->HasAttribute(SPELL_ATTR5_START_PERIODIC_AT_APPLY)) - m_periodicTimer += m_period; - } + ResetPeriodic(resetPeriodicTimer); } } @@ -908,12 +915,12 @@ void AuraEffect::ApplySpellMod(Unit* target, bool apply) } else if (GetMiscValue() == SPELLMOD_EFFECT1) { - if (AuraEffect* aurEff = aura->GetEffect(0)) + if (AuraEffect* aurEff = aura->GetEffect(0)) aurEff->RecalculateAmount(); } else if (GetMiscValue() == SPELLMOD_EFFECT2) { - if (AuraEffect* aurEff = aura->GetEffect(1)) + if (AuraEffect* aurEff = aura->GetEffect(1)) aurEff->RecalculateAmount(); } else if (GetMiscValue() == SPELLMOD_EFFECT3) @@ -941,16 +948,18 @@ void AuraEffect::ApplySpellMod(Unit* target, bool apply) void AuraEffect::Update(uint32 diff, Unit* caster) { - if (m_isPeriodic && (GetBase()->GetDuration() >=0 || GetBase()->IsPassive() || GetBase()->IsPermanent())) + 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 + _periodicTimer += diff; + while (_periodicTimer >= _period) { - ++m_tickNumber; + _periodicTimer -= _period; + + if (!GetBase()->IsPermanent() && (_ticksDone + 1) > GetTotalTicks()) + break; + + ++_ticksDone; - // update before tick (aura can be removed in TriggerSpell or PeriodicTick calls) - m_periodicTimer += m_period - diff; UpdatePeriodic(caster); std::vector<AuraApplication*> effectApplications; @@ -1029,7 +1038,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); @@ -1067,7 +1076,7 @@ void AuraEffect::UpdatePeriodic(Unit* caster) if (GetSpellInfo()->SpellFamilyFlags[1] & 0x00004000) { // Get 0 effect aura - if (AuraEffect* slow = GetBase()->GetEffect(0)) + if (AuraEffect* slow = GetBase()->GetEffect(EFFECT_0)) { int32 newAmount = slow->GetAmount() + GetAmount(); if (newAmount > 0) @@ -1104,7 +1113,7 @@ void AuraEffect::SendTickImmune(Unit* target, Unit* caster) const caster->SendSpellDamageImmune(target, m_spellInfo->Id, true); } -void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const +void AuraEffect::PeriodicTick(AuraApplication* aurApp, Unit* caster) const { bool prevented = GetBase()->CallScriptEffectPeriodicHandlers(this, aurApp); if (prevented) @@ -5525,11 +5534,11 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) return; // Negative Energy Periodic case 46284: - target->CastCustomSpell(triggerSpellId, SPELLVALUE_MAX_TARGETS, m_tickNumber / 10 + 1, nullptr, true, nullptr, this); + target->CastCustomSpell(triggerSpellId, SPELLVALUE_MAX_TARGETS, _ticksDone / 10 + 1, nullptr, true, nullptr, this); return; // Slime Pool (Dreadscale & Acidmaw) case 66882: - target->CastCustomSpell(triggerSpellId, SPELLVALUE_RADIUS_MOD, (int32)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3), nullptr, true, nullptr, this); + target->CastCustomSpell(triggerSpellId, SPELLVALUE_RADIUS_MOD, static_cast<int32>(((_ticksDone / 60.f) * 0.9f + 0.1f) * 10000.f * 2.f / 3.f), nullptr, true, nullptr, this); return; // Slime Spray - temporary here until preventing default effect works again // added on 9.10.2010 @@ -5681,7 +5690,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; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index e2a9c1608de..b2aba79de95 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -49,7 +49,7 @@ class TC_GAME_API AuraEffect uint32 GetId() const { return m_spellInfo->Id; } uint32 GetEffIndex() const { return m_effectInfo->EffectIndex; } int32 GetBaseAmount() const { return m_baseAmount; } - int32 GetPeriod() const { return m_period; } + int32 GetPeriod() const { return _period; } int32 GetMiscValueB() const { return GetSpellEffectInfo()->MiscValueB; } int32 GetMiscValue() const { return GetSpellEffectInfo()->MiscValue; } @@ -57,8 +57,8 @@ class TC_GAME_API AuraEffect int32 GetAmount() const { return m_amount; } void SetAmount(int32 amount) { m_amount = amount; m_canBeRecalculated = false;} - 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); @@ -82,9 +82,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_period ? (GetBase()->GetMaxDuration() / m_period) : 1;} - void ResetPeriodic(bool resetPeriodicTimer = false) { if (resetPeriodicTimer) m_periodicTimer = m_period; m_tickNumber = 0;} + void ResetTicks() { _ticksDone = 0; } + uint32 GetTickNumber() const { return _ticksDone; } + uint32 GetRemainingTicks() const { return GetTotalTicks() - _ticksDone; } + uint32 GetTotalTicks() const { return (_period && !GetBase()->IsPermanent()) ? uint32(GetBase()->GetMaxDuration() / _period) : uint32(0); } + void ResetPeriodic(bool resetPeriodicTimer = false); bool IsPeriodic() const { return m_isPeriodic; } void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; } @@ -120,9 +122,10 @@ class TC_GAME_API AuraEffect float m_critChance; float m_donePct; - int32 m_periodicTimer; - int32 m_period; - uint32 m_tickNumber; + // periodic stuff + int32 _periodicTimer; + int32 _period; // time between consecutive ticks + uint32 _ticksDone; // ticks counter bool m_canBeRecalculated; bool m_isPeriodic; diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 1d55107b1b1..bbabf96b85e 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -799,6 +799,11 @@ void Aura::RefreshDuration(bool withMods) if (!m_periodicCosts.empty()) m_timeCla = 1 * IN_MILLISECONDS; + + // also reset periodic counters + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (AuraEffect* aurEff = GetEffect(i)) + aurEff->ResetTicks(); } void Aura::RefreshTimers(bool resetPeriodicTimer) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8e4de205301..8c2c1f69853 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3207,6 +3207,43 @@ void SpellMgr::LoadSpellInfoCorrections() { uint32 oldMSTime = getMSTime(); + // Some spells have no amplitude set + { + ApplySpellFix({ + 6727, // Poison Mushroom + 7331, // Healing Aura (TEST) (Rank 1) + /* + 30400, // Nether Beam - Perseverance + Blizzlike to have it disabled? DBC says: + "This is currently turned off to increase performance. Enable this to make it fire more frequently." + */ + 34589, // Dangerous Water + 52562, // Arthas Zombie Catcher + 57550, // Tirion Aggro + 65755 + }, [](SpellInfo* spellInfo) + { + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraPeriod = 1 * IN_MILLISECONDS; + }); + + ApplySpellFix({ + 24707, // Food + 26263, // Dim Sum + 29055, // Refreshing Red Apple + 37504 // Karazhan - Chess NPC AI, action timer + }, [](SpellInfo* spellInfo) + { + // first effect has correct amplitude + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->ApplyAuraPeriod = const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->ApplyAuraPeriod; + }); + + // Vomit + ApplySpellFix({ 43327 }, [](SpellInfo* spellInfo) + { + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_1))->ApplyAuraPeriod = 1 * IN_MILLISECONDS; + }); + } + ApplySpellFix({ 63026, // Summon Aspirant Test NPC (HACK: Target shouldn't be changed) 63137 // Summon Valiant Test (HACK: Target shouldn't be changed; summon position should be untied from spell destination) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index 8528aba9fb7..511c0e17893 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -149,7 +149,7 @@ class spell_marwyn_shared_suffering : public SpellScriptLoader if (Unit* caster = GetCaster()) { - int32 remainingDamage = aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber()); + int32 remainingDamage = aurEff->GetAmount() * aurEff->GetRemainingTicks(); if (remainingDamage > 0) caster->CastCustomSpell(SPELL_SHARED_SUFFERING_DISPEL, SPELLVALUE_BASE_POINT1, remainingDamage, GetTarget(), TRIGGERED_FULL_MASK); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index cb7beeafb42..73dcd478546 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -200,6 +200,8 @@ class spell_grobbulus_poison_cloud : public SpellScriptLoader void PeriodicTick(AuraEffect const* aurEff) { PreventDefaultAction(); + if (!aurEff->GetTotalTicks()) + return; uint32 triggerSpell = aurEff->GetSpellEffectInfo()->TriggerSpell; int32 mod = int32(((float(aurEff->GetTickNumber()) / aurEff->GetTotalTicks()) * 0.9f + 0.1f) * 10000 * 2 / 3); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index df299a03c50..41c5b3c68d6 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -976,7 +976,7 @@ struct npc_thorim_trashAI : public ScriptedAI uint32 heal = 0; Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(SPELL_AURA_PERIODIC_HEAL); for (AuraEffect const* aurEff : auras) - heal += aurEff->GetAmount() * (aurEff->GetTotalTicks() - aurEff->GetTickNumber()); + heal += aurEff->GetAmount() * aurEff->GetRemainingTicks(); return heal; } diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp index a1737fc4e11..f8ae540f12e 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp @@ -178,6 +178,8 @@ class spell_broggok_poison_cloud : public SpellScriptLoader void PeriodicTick(AuraEffect const* aurEff) { PreventDefaultAction(); + if (!aurEff->GetTotalTicks()) + return; uint32 triggerSpell = aurEff->GetSpellEffectInfo()->TriggerSpell; int32 mod = int32(((float(aurEff->GetTickNumber()) / aurEff->GetTotalTicks()) * 0.9f + 0.1f) * 10000 * 2 / 3); diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 80cee09da89..5719b684ccd 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -555,6 +555,12 @@ public: void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { + if (!aurEff->GetTotalTicks()) + { + amount = 0; + return; + } + if (Unit* caster = GetCaster()) amount = int32(CalculatePct(caster->GetCreatePowers(POWER_MANA), amount) / aurEff->GetTotalTicks()); else diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 0d39c1181ad..496c7da3676 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1319,7 +1319,7 @@ class spell_gen_gift_of_naaru : public AuraScript void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { - if (!GetCaster()) + if (!GetCaster() || !aurEff->GetTotalTicks()) return; float heal = 0.0f; |
