From f6c56c3293deba3f02db14bc3a8c88bc815a801e Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Wed, 13 Aug 2025 21:35:10 -0400 Subject: [PATCH] Core/Spells: Implemented new SpellMisc field, MinDuration that controls minimum spell missile travel time Port From (https://github.com/TrinityCore/TrinityCore/commit/a63d404e7bf2dce3b15ce5f66ac98fe71a41f51c) --- Source/Game/Entities/Object/WorldObject.cs | 4 ++-- Source/Game/Spells/Spell.cs | 18 +++++++++--------- Source/Game/Spells/SpellInfo.cs | 2 ++ Source/Game/Spells/SpellManager.cs | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index dc84c0331..a6e9e3fc4 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -2943,9 +2943,9 @@ namespace Game.Entities // Set up missile speed based delay float hitDelay = spellInfo.LaunchDelay; if (spellInfo.HasAttribute(SpellAttr9.MissileSpeedIsDelayInSec)) - hitDelay += spellInfo.Speed; + hitDelay += Math.Max(spellInfo.Speed, spellInfo.MinDuration); else if (spellInfo.Speed > 0.0f) - hitDelay += Math.Max(victim.GetDistance(this), 5.0f) / spellInfo.Speed; + hitDelay += Math.Max(Math.Max(victim.GetDistance(this), 5.0f) / spellInfo.Speed, spellInfo.MinDuration); uint delay = (uint)Math.Floor(hitDelay * 1000.0f); // Schedule charge drop diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 247bd601f..759bd2d92 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -338,15 +338,15 @@ namespace Game.Spells { float speed = m_targets.GetSpeedXY(); if (speed > 0.0f) - return (ulong)(Math.Floor((m_targets.GetDist2d() / speed + launchDelay) * 1000.0f)); + return (ulong)(Math.Floor((Math.Max(m_targets.GetDist2d() / speed, m_spellInfo.MinDuration) + launchDelay) * 1000.0f)); } else if (m_spellInfo.HasAttribute(SpellAttr9.MissileSpeedIsDelayInSec)) - return (ulong)(Math.Floor((m_spellInfo.Speed + launchDelay) * 1000.0f)); + return (ulong)(Math.Floor((Math.Max(m_spellInfo.Speed, m_spellInfo.MinDuration) + launchDelay) * 1000.0f)); else if (m_spellInfo.Speed > 0.0f) { // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP) float dist = m_caster.GetExactDist(m_targets.GetDstPos()); - return (ulong)(Math.Floor((dist / m_spellInfo.Speed + launchDelay) * 1000.0f)); + return (ulong)(Math.Floor((Math.Max(dist / m_spellInfo.Speed, m_spellInfo.MinDuration) + launchDelay) * 1000.0f)); } return (ulong)Math.Floor(launchDelay * 1000.0f); @@ -2001,13 +2001,13 @@ namespace Game.Spells } if (m_spellInfo.HasAttribute(SpellAttr9.MissileSpeedIsDelayInSec)) - hitDelay += m_spellInfo.Speed; + hitDelay += Math.Max(m_spellInfo.Speed, m_spellInfo.MinDuration); else if (m_spellInfo.Speed > 0.0f) { // calculate spell incoming interval /// @todo this is a hack float dist = Math.Max(missileSource.GetDistance(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()), 5.0f); - hitDelay += dist / m_spellInfo.Speed; + hitDelay += Math.Max(dist / m_spellInfo.Speed, m_spellInfo.MinDuration); } targetInfo.TimeDelay += (ulong)Math.Floor(hitDelay * 1000.0f); @@ -2070,12 +2070,12 @@ namespace Game.Spells { float hitDelay = m_spellInfo.LaunchDelay; if (m_spellInfo.HasAttribute(SpellAttr9.MissileSpeedIsDelayInSec)) - hitDelay += m_spellInfo.Speed; + hitDelay += Math.Max(m_spellInfo.Speed, m_spellInfo.MinDuration); else if (m_spellInfo.Speed > 0.0f) { // calculate spell incoming interval float dist = Math.Max(m_caster.GetDistance(go.GetPositionX(), go.GetPositionY(), go.GetPositionZ()), 5.0f); - hitDelay += dist / m_spellInfo.Speed; + hitDelay += Math.Max(dist / m_spellInfo.Speed, m_spellInfo.MinDuration); } target.TimeDelay = (ulong)Math.Floor(hitDelay * 1000.0f); @@ -2150,12 +2150,12 @@ namespace Game.Spells { float hitDelay = m_spellInfo.LaunchDelay; if (m_spellInfo.HasAttribute(SpellAttr9.MissileSpeedIsDelayInSec)) - hitDelay += m_spellInfo.Speed; + hitDelay += Math.Max(m_spellInfo.Speed, m_spellInfo.MinDuration); else if (m_spellInfo.Speed > 0.0f) { // calculate spell incoming interval float dist = Math.Max(m_caster.GetDistance(corpse.GetPositionX(), corpse.GetPositionY(), corpse.GetPositionZ()), 5.0f); - hitDelay += dist / m_spellInfo.Speed; + hitDelay += Math.Max(dist / m_spellInfo.Speed, m_spellInfo.MinDuration); } target.TimeDelay = (ulong)Math.Floor(hitDelay * 1000.0f); diff --git a/Source/Game/Spells/SpellInfo.cs b/Source/Game/Spells/SpellInfo.cs index 98adcf1de..405676158 100644 --- a/Source/Game/Spells/SpellInfo.cs +++ b/Source/Game/Spells/SpellInfo.cs @@ -63,6 +63,7 @@ namespace Game.Spells RangeEntry = CliDB.SpellRangeStorage.LookupByKey(_misc.RangeIndex); Speed = _misc.Speed; LaunchDelay = _misc.LaunchDelay; + MinDuration = _misc.MinDuration; SchoolMask = (SpellSchoolMask)_misc.SchoolMask; IconFileDataId = _misc.SpellIconFileDataID; ActiveIconFileDataId = _misc.ActiveIconFileDataID; @@ -3937,6 +3938,7 @@ namespace Game.Spells public SpellRangeRecord RangeEntry { get; set; } public float Speed { get; set; } public float LaunchDelay { get; set; } + public float MinDuration { get; set; } public uint StackAmount { get; set; } public uint[] Totem = new uint[SpellConst.MaxTotems]; public uint[] TotemCategory = new uint[SpellConst.MaxTotems]; diff --git a/Source/Game/Spells/SpellManager.cs b/Source/Game/Spells/SpellManager.cs index 4612aa6d2..13dbd9643 100644 --- a/Source/Game/Spells/SpellManager.cs +++ b/Source/Game/Spells/SpellManager.cs @@ -2493,7 +2493,7 @@ namespace Game.Entities var existingSpellBounds = _GetSpellInfo(spellId); if (existingSpellBounds == null) { - Log.outError(LogFilter.Sql, $"Serverside spell {spellId} difficulty {difficulty} effext index {effect.EffectIndex} references a regular spell loaded from file. Adding serverside effects to existing spells is not allowed."); + Log.outError(LogFilter.Sql, $"Serverside spell {spellId} difficulty {difficulty} effect index {effect.EffectIndex} references a regular spell loaded from file. Adding serverside effects to existing spells is not allowed."); continue; }