Core/Spells: refactored duration and period calculations
* fixed sending hit targets in spell_go packet
This commit is contained in:
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in new issue
Block a user