Core/Auras: periodics refactor part 1:

Port From (https://github.com/TrinityCore/TrinityCore/commit/5f9e0d92d563c983c229db1569414916b3dce51e)
This commit is contained in:
hondacrx
2021-03-17 16:08:17 -04:00
parent f2317c2bdf
commit 1d8bab3b58
6 changed files with 112 additions and 58 deletions
+18 -3
View File
@@ -1127,6 +1127,20 @@ namespace Game.Entities
CastSpell(targets, spellInfo, null, triggered ? TriggerCastFlags.FullMask : TriggerCastFlags.None, castItem, triggeredByAura, originalCaster);
}
public void CastSpell(Item item, uint spellId, bool triggered, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
if (spellInfo == null)
{
Log.outError(LogFilter.Unit, "CastSpell: unknown spell id {0} by caster: {1}", spellId, GetGUID().ToString());
return;
}
SpellCastTargets targets = new SpellCastTargets();
targets.SetItemTarget(item);
CastSpell(targets, spellInfo, null, triggered ? TriggerCastFlags.FullMask : TriggerCastFlags.None, castItem, triggeredByAura, originalCaster);
}
public void CastCustomSpell(Unit target, uint spellId, int bp0, int bp1, int bp2, bool triggered, Item castItem = null, AuraEffect triggeredByAura = null, ObjectGuid originalCaster = default)
{
@@ -2859,11 +2873,12 @@ namespace Game.Entities
{
uint amount = 0;
var periodicAuras = GetAuraEffectsByType(auraType);
foreach (var eff in periodicAuras)
foreach (var aurEff in periodicAuras)
{
if (eff.GetCasterGUID() != caster || eff.GetId() != spellId || eff.GetEffIndex() != effectIndex || eff.GetTotalTicks() == 0)
if (aurEff.GetCasterGUID() != caster || aurEff.GetId() != spellId || aurEff.GetEffIndex() != effectIndex || aurEff.GetTotalTicks() == 0)
continue;
amount += (uint)((eff.GetAmount() * Math.Max(eff.GetTotalTicks() - eff.GetTickNumber(), 0)) / eff.GetTotalTicks());
amount += (uint)((aurEff.GetAmount() * aurEff.GetRemainingTicks()) / aurEff.GetTotalTicks());
break;
}
+8
View File
@@ -742,6 +742,14 @@ namespace Game.Spells
if (!m_periodicCosts.Empty())
m_timeCla = 1 * Time.InMilliseconds;
// also reset periodic counters
for (byte i = 0; i < SpellConst.MaxEffects; ++i)
{
AuraEffect aurEff = GetEffect(i);
if (aurEff != null)
aurEff.ResetTicks();
}
}
void RefreshTimers(bool resetPeriodicTimer)
+52 -49
View File
@@ -125,18 +125,25 @@ namespace Game.Spells
amount *= GetBase().GetStackAmount();
return amount;
}
void ResetPeriodic(bool resetPeriodicTimer = false)
{
_ticksDone = 0;
if (resetPeriodicTimer)
{
_periodicTimer = _period;
// Start periodic on next tick or at aura apply
if (!m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
_periodicTimer = 0;
}
}
public void CalculatePeriodic(Unit caster, bool resetPeriodicTimer = true, bool load = false)
{
m_period = (int)GetSpellEffectInfo().ApplyAuraPeriod;
_period = (int)GetSpellEffectInfo().ApplyAuraPeriod;
// prepare periodics
switch (GetAuraType())
{
case AuraType.ObsModPower:
// 3 spells have no amplitude set
if (m_period == 0)
m_period = 1 * Time.InMilliseconds;
break;
case AuraType.PeriodicDamage:
case AuraType.PeriodicHeal:
case AuraType.ObsModHealth:
@@ -155,7 +162,7 @@ namespace Game.Spells
break;
}
GetBase().CallScriptEffectCalcPeriodicHandlers(this, ref m_isPeriodic, ref m_period);
GetBase().CallScriptEffectCalcPeriodicHandlers(this, ref m_isPeriodic, ref _period);
if (!m_isPeriodic)
return;
@@ -163,42 +170,41 @@ namespace Game.Spells
Player modOwner = caster != null ? caster.GetSpellModOwner() : null;
// Apply casting time mods
if (m_period != 0)
if (_period != 0)
{
// Apply periodic time mod
if (modOwner != null)
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ActivationTime, ref m_period);
modOwner.ApplySpellMod(GetSpellInfo(), SpellModOp.ActivationTime, ref _period);
if (caster != null)
{
// Haste modifies periodic time of channeled spells
if (m_spellInfo.IsChanneled())
caster.ModSpellDurationTime(m_spellInfo, ref m_period);
caster.ModSpellDurationTime(m_spellInfo, ref _period);
else if (m_spellInfo.HasAttribute(SpellAttr5.HasteAffectDuration))
m_period = (int)(m_period * caster.m_unitData.ModCastingSpeed);
_period = (int)(_period * caster.m_unitData.ModCastingSpeed);
}
}
else // prevent infinite loop on Update
m_isPeriodic = false;
if (load) // aura loaded from db
{
m_tickNumber = (uint)(m_period != 0 ? GetBase().GetDuration() / m_period : 0);
m_periodicTimer = m_period != 0 ? GetBase().GetDuration() % m_period : 0;
if (_period != 0 && !GetBase().IsPermanent())
{
uint elapsedTime = (uint)(GetBase().GetMaxDuration() - GetBase().GetDuration());
_ticksDone = elapsedTime / (uint)_period;
_periodicTimer = (int)(elapsedTime % _period);
}
if (m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
++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 != 0 && !m_spellInfo.HasAttribute(SpellAttr5.StartPeriodicAtApply))
m_periodicTimer += m_period;
}
ResetPeriodic(resetPeriodicTimer);
}
}
public void CalculateSpellMod()
@@ -397,13 +403,16 @@ namespace Game.Spells
{
if (m_isPeriodic && (GetBase().GetDuration() >= 0 || GetBase().IsPassive() || GetBase().IsPermanent()))
{
if (m_periodicTimer > diff)
m_periodicTimer -= (int)diff;
else // tick also at m_periodicTimer == 0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
_periodicTimer += (int)diff;
while (_periodicTimer >= _period)
{
++m_tickNumber;
// update before tick (aura can be removed in TriggerSpell or PeriodicTick calls)
m_periodicTimer += m_period - (int)diff;
_periodicTimer -= _period;
if (!GetBase().IsPermanent() && (_ticksDone + 1) > GetTotalTicks())
break;
++_ticksDone;
UpdatePeriodic(caster);
GetApplicationList(out List<AuraApplication> effectApplications);
@@ -481,7 +490,7 @@ namespace Game.Spells
// 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);
@@ -874,7 +883,7 @@ namespace Game.Spells
public uint GetId() { return m_spellInfo.Id; }
public uint GetEffIndex() { return _effectInfo.EffectIndex; }
public int GetBaseAmount() { return m_baseAmount; }
public int GetPeriod() { return m_period; }
public int GetPeriod() { return _period; }
public int GetMiscValueB() { return GetSpellEffectInfo().MiscValueB; }
public int GetMiscValue() { return GetSpellEffectInfo().MiscValue; }
@@ -883,8 +892,8 @@ namespace Game.Spells
public bool HasAmount() { return m_amount != 0; }
public void SetAmount(int _amount) { m_amount = _amount; m_canBeRecalculated = false; }
public int GetPeriodicTimer() { return m_periodicTimer; }
public void SetPeriodicTimer(int periodicTimer) { m_periodicTimer = periodicTimer; }
public int GetPeriodicTimer() { return _periodicTimer; }
public void SetPeriodicTimer(int periodicTimer) { _periodicTimer = periodicTimer; }
void RecalculateAmount()
{
@@ -909,17 +918,10 @@ namespace Game.Spells
public void SetDonePct(float val) { m_donePct = val; }
public float GetDonePct() { return m_donePct; }
public uint GetTickNumber() { return m_tickNumber; }
public int GetTotalTicks()
{
return m_period != 0 ? (GetBase().GetMaxDuration() / m_period) : 1;
}
public void ResetPeriodic(bool resetPeriodicTimer = false)
{
if (resetPeriodicTimer)
m_periodicTimer = m_period;
m_tickNumber = 0;
}
public void ResetTicks() { _ticksDone = 0; }
public uint GetTickNumber() { return _ticksDone; }
public uint GetRemainingTicks() { return GetTotalTicks() - _ticksDone; }
public uint GetTotalTicks() { return (_period != 0 && !GetBase().IsPermanent()) ? (uint)(GetBase().GetMaxDuration() / _period) : 0u; }
public bool IsPeriodic() { return m_isPeriodic; }
void SetPeriodic(bool isPeriodic) { m_isPeriodic = isPeriodic; }
@@ -946,9 +948,10 @@ namespace Game.Spells
float m_critChance;
float m_donePct;
int m_periodicTimer;
int m_period;
uint m_tickNumber;
// periodic stuff
int _periodicTimer;
int _period; // time between consecutive ticks
uint _ticksDone; // ticks counter
bool m_canBeRecalculated;
bool m_isPeriodic;
@@ -5276,14 +5279,14 @@ namespace Game.Spells
return;
// Negative Energy Periodic
case 46284:
target.CastCustomSpell(triggerSpellId, SpellValueMod.MaxTargets, (int)(m_tickNumber / 10 + 1), null, true, null, this);
target.CastCustomSpell(triggerSpellId, SpellValueMod.MaxTargets, (int)(_ticksDone / 10 + 1), null, true, null, this);
return;
// Poison (Grobbulus)
case 28158:
case 54362:
// Slime Pool (Dreadscale & Acidmaw)
case 66882:
target.CastCustomSpell(triggerSpellId, SpellValueMod.RadiusMod, (int)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3), null, true, null, this);
target.CastCustomSpell(triggerSpellId, SpellValueMod.RadiusMod, (int)(((_ticksDone / 60.0f) * 0.9f + 0.1f) * 10000.0f * 2.0f / 3.0f), null, true, null, this);
return;
// Slime Spray - temporary here until preventing default effect works again
// added on 9.10.2010
@@ -5443,7 +5446,7 @@ namespace Game.Spells
case 72854: // Unbound Plague
case 72855: // Unbound Plague
case 72856: // Unbound Plague
damage *= (uint)Math.Pow(1.25f, m_tickNumber);
damage *= (uint)Math.Pow(1.25f, _ticksDone);
break;
default:
break;
+26 -4
View File
@@ -2431,7 +2431,7 @@ namespace Game.Entities
if (effect.EffectIndex >= SpellConst.MaxEffects)
{
Log.outError(LogFilter.Sql, $"Serverside spell {spellId} difficulty {difficulty} has more than 32 effects, effect at index {effect.EffectIndex} skipped");
Log.outError(LogFilter.Sql, $"Serverside spell {spellId} difficulty {difficulty} has more than {SpellConst.MaxEffects} effects, effect at index {effect.EffectIndex} skipped");
continue;
}
@@ -2960,6 +2960,30 @@ namespace Game.Entities
switch (spellInfo.Id)
{
case 6727: // Poison Mushroom
case 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."
*/
case 34589: // Dangerous Water
case 52562: // Arthas Zombie Catcher
case 57550: // Tirion Aggro
case 65755:
spellInfo.GetEffect(0).ApplyAuraPeriod = 1 * Time.InMilliseconds;
break;
case 24707: // Food
case 26263: // Dim Sum
case 29055: // Refreshing Red Apple
case 37504: // Karazhan - Chess NPC AI, action timer
// first effect has correct amplitude
spellInfo.GetEffect(1).ApplyAuraPeriod = spellInfo.GetEffect(0).ApplyAuraPeriod;
break;
// Vomit
case 43327:
spellInfo.GetEffect(1).ApplyAuraPeriod = 1 * Time.InMilliseconds;
break;
case 63026: // Summon Aspirant Test NPC (HACK: Target shouldn't be changed)
case 63137: // Summon Valiant Test (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
spellInfo.GetEffect(0).TargetA = new SpellImplicitTargetInfo(Targets.DestDb);
@@ -3356,7 +3380,7 @@ namespace Game.Entities
break;
case 69846: // Frost Bomb
spellInfo.Speed = 0.0f; // This spell's summon happens instantly
break;
break;
case 70106: // Chilled to the Bone
spellInfo.AttributesEx3 |= SpellAttr3.NoDoneBonus;
spellInfo.AttributesEx6 |= SpellAttr6.NoDonePctDamageMods;
@@ -4001,14 +4025,12 @@ namespace Game.Entities
struct ServersideSpellName
{
public SpellNameRecord Name;
public string NameStorage;
public ServersideSpellName(uint id, string name)
{
Name = new();
Name.Name = new LocalizedString();
NameStorage = name;
Name.Id = id;
for (Locale i = 0; i < Locale.Total; ++i)
Name.Name[i] = name;
+7 -1
View File
@@ -455,9 +455,15 @@ namespace Scripts.Spells.Druid
{
void CalculateAmount(AuraEffect aurEff, ref int amount, ref bool canBeRecalculated)
{
if (aurEff.GetTotalTicks() == 0)
{
amount = 0;
return;
}
Unit caster = GetCaster();
if (caster)
amount = MathFunctions.CalculatePct(caster.GetCreatePowers(PowerType.Mana), amount) / aurEff.GetTotalTicks();
amount = MathFunctions.CalculatePct(caster.GetCreatePowers(PowerType.Mana), amount) / (int)aurEff.GetTotalTicks();
else
amount = 0;
}
+1 -1
View File
@@ -1321,7 +1321,7 @@ namespace Scripts.Spells.Generic
{
void CalculateAmount(AuraEffect aurEff, ref int amount, ref bool canBeRecalculated)
{
if (!GetCaster())
if (!GetCaster() || aurEff.GetTotalTicks() == 0)
return;
float heal = 0.0f;