Core/Auras: periodics refactor part 1:
Port From (https://github.com/TrinityCore/TrinityCore/commit/5f9e0d92d563c983c229db1569414916b3dce51e)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user