Core/Spells: dropped old dot clipping implementation and restored TC period and duration calculations in preparation of re-implementing it

This commit is contained in:
Ovahlord committed 2022-09-12 09:15:35 +02:00
1 parent 6d89d242a7
commit e3e4b2cf16
15 files changed
+227 -242

No files matched your search

@@ -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
+1
View File
@@ -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);
+21 -21
View File
@@ -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 <typename InterruptFlags>
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)
{
+3 -3
View File
@@ -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 <typename InterruptFlags>
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]; }
@@ -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;
@@ -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<uint32>(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<AuraApplication*> 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
}
@@ -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;
+42 -15
View File
@@ -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());
+2 -4
View File
@@ -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
+44 -56
View File
@@ -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);
+2 -2
View File
@@ -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();
+1 -1
View File
@@ -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
+5 -91
View File
@@ -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;
}
+1 -5
View File
@@ -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();
@@ -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);
}