Core/Spells: refactored duration and period calculations

* fixed sending hit targets in spell_go packet
This commit is contained in:
Ovahlord committed 2022-10-01 19:13:01 +02:00
1 parent b6f8a68d61
commit 3d529f2d7d
5 files changed
+109 -69

No files matched your search

@@ -680,30 +680,15 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer, bool l
GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, _period);
if (!m_isPeriodic)
{
_period = 0;
return;
if (_period == 0)
_period = 5200; // fallback value found in client
Player* modOwner = caster ? caster->GetSpellModOwner() : nullptr;
}
if (_period)
{
// Apply periodic time mod
if (modOwner)
modOwner->ApplySpellMod(GetSpellInfo()->Id, SpellModOp::Period, _period);
_period = m_spellInfo->CalcPeriod(caster, SpellEffIndex(GetEffIndex()), _period);
if (caster)
{
// Apply haste modifiers
if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
_period = int32(_period * caster->GetFloatValue(UNIT_MOD_CAST_HASTE));
if (m_spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC) && caster->IsPlayer())
_period = int32(_period * caster->GetFloatValue(PLAYER_FIELD_MOD_HASTE));
}
}
else // prevent infinite loop on Update
if (!_period) // prevent infinite loop on Update
m_isPeriodic = false;
if (load) // aura loaded from db
+1 -23
View File
@@ -885,29 +885,7 @@ int32 Aura::CalcMaxDuration(Unit* caster) const
/*static*/ int32 Aura::CalcMaxDuration(SpellInfo const* spellInfo, WorldObject* 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, SpellModOp::Duration, maxDuration);
// Calculate duration of periodics affected by haste.
if (caster && caster->IsUnit() && spellInfo->HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION))
maxDuration = int32(maxDuration * caster->GetFloatValue(UNIT_MOD_CAST_HASTE));
return maxDuration;
return spellInfo->CalcDuration(caster);
}
void Aura::SetDuration(int32 duration, bool withMods)
+9 -22
View File
@@ -3037,8 +3037,8 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
|| m_spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_HEAL))
return false;
if ((m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER))
return true;
if (m_spellInfo->StackAmount < 2)
return !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
return true;
}();
@@ -3074,39 +3074,26 @@ void Spell::DoSpellEffectHit(Unit* unit, uint8 effIndex, TargetInfo& hitInfo)
//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 and periodic of spells so we have to clamp the duration accordingly
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION)
|| m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)
|| m_spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) || m_spellInfo->HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION))
{
// Haste based auras need their duration adapted.
int32 origDuration = hitInfo.AuraDuration;
hitInfo.AuraDuration = 0;
int32 period = 0;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (AuraEffect const* aurEff = hitInfo.HitAura->GetEffect(effIndex))
{
if (int32 period = aurEff->GetPeriod())
{
hitInfo.AuraDuration = std::clamp(origDuration / period * period, 1, origDuration);
if (int32 effectPeriod = aurEff->GetPeriod())
period = effectPeriod;
// If the duration of the aura could fit in half of a tick, round up
if (origDuration % period >= (period / 2))
hitInfo.AuraDuration += period;
break;
}
}
}
if (period != 0)
hitInfo.AuraDuration = std::clamp(origDuration / period * period, 1, origDuration);
// if there is no periodic effect
if (!hitInfo.AuraDuration)
hitInfo.AuraDuration = origDuration;
}
// Apply rolled over duration if there is any
hitInfo.AuraDuration += hitInfo.HitAura->GetRolledOverDuration();
}
@@ -4679,7 +4666,7 @@ void Spell::UpdateSpellCastDataTargets(WorldPackets::Spells::SpellHitInfo& data)
// possibly SPELL_MISS_IMMUNE2 for this??
targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
if (targetInfo.MissCondition == SPELL_MISS_NONE) // hits
if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // hits
{
data.HitTargets.push_back(targetInfo.TargetGUID);
m_channelTargetEffectMask |= targetInfo.EffectMask;
+93 -4
View File
@@ -3353,15 +3353,104 @@ int32 SpellInfo::GetMaxDuration() const
int32 SpellInfo::CalcDuration(WorldObject const* caster /*= nullptr*/) const
{
int32 duration = GetDuration();
if (!DurationEntry)
return IsPassive() ? -1 : 0;
if (caster)
if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(Id, SpellModOp::Duration, duration);
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 const* modOwner = unitCaster->GetSpellModOwner())
modOwner->ApplySpellMod(Id, SpellModOp::Duration, duration);
if (HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION) || HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
{
SpellEffIndex periodicEffectIndex = EFFECT_0;
bool hasPeriodicEffect = [&]()
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (Effects[i].IsEffect() && Effects[i].AuraPeriod)
{
periodicEffectIndex = SpellEffIndex(i);
return true;
}
return false;
}();
if (hasPeriodicEffect && HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
{
float hasteMod = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE);
if (hasteMod > 0.001f)
{
if (HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION))
return int32(duration * hasteMod);
int32 period = CalcPeriod(caster, periodicEffectIndex);
if (period > 0)
duration = int32(period * (duration / (float)period));
}
}
}
return duration;
}
int32 SpellInfo::CalcPeriod(WorldObject const* caster, SpellEffIndex effIndex, Optional<int32> periodOverride /*= {}*/) const
{
int32 period = 0;
if (periodOverride.has_value() && *periodOverride > 0)
period = *periodOverride;
else
{
if (Effects[effIndex].IsEffect() && Effects[effIndex].AuraPeriod != 0)
period = Effects[effIndex].AuraPeriod;
else
period = 5200;
}
Unit const* unitCaster = caster ? caster->ToUnit() : nullptr;
if (!unitCaster)
return period;
if (Player const* modOwner = unitCaster->GetSpellModOwner())
modOwner->ApplySpellMod(Id, SpellModOp::Period, period);
if (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
{
float hasteMod = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE);
if (hasteMod > 0.001f)
period = ((float)period * hasteMod);
}
return period;
}
uint32 SpellInfo::CalcCastTime(uint8 level, Spell* spell /*= nullptr*/) const
{
int32 castTime = 0;
+1
View File
@@ -578,6 +578,7 @@ class TC_GAME_API SpellInfo
int32 GetMaxDuration() const;
int32 CalcDuration(WorldObject const* caster = nullptr) const;
int32 CalcPeriod(WorldObject const* caster, SpellEffIndex effIndex, Optional<int32> periodOverride = {}) const;
uint32 GetMaxTicks() const;