Core/Spells: Fixed effects targeting the caster not hitting him immediately on spell launch if the spell targets a dest

Port From (https://github.com/TrinityCore/TrinityCore/commit/295c8f63269d966812f37a8bd8e988a9f2dc1235)
This commit is contained in:
hondacrx
2023-05-02 15:40:21 -04:00
parent 9decc17cd0
commit 5e5e17e23c
5 changed files with 78 additions and 36 deletions
@@ -920,6 +920,15 @@ namespace Game.Movement
return (p1 - p2).LengthSquared();
}
public float GetPathLength()
{
float length = 0.0f;
for (var i = 0; i < _pathPoints.Length - 1; ++i)
length += (_pathPoints[i + 1] - _pathPoints[i]).Length();
return length;
}
public void ShortenPathUntilDist(Position pos, float dist) { ShortenPathUntilDist(new Vector3(pos.posX, pos.posY, pos.posZ), dist); }
public void ShortenPathUntilDist(Vector3 target, float dist)
@@ -192,7 +192,9 @@ namespace Game.Movement
public void MovementInform(Unit owner)
{
owner.ToCreature()?.GetAI()?.MovementInform(MovementGeneratorType.Point, _movementId);
// deliver EVENT_CHARGE to scripts, EVENT_CHARGE_PREPATH is just internal implementation detail of this movement generator
uint movementId = _movementId == EventId.ChargePrepath ? EventId.Charge : _movementId;
owner.ToCreature()?.GetAI()?.MovementInform(MovementGeneratorType.Point, movementId);
}
public override void UnitSpeedChanged()
+2
View File
@@ -702,6 +702,8 @@ namespace Game.Movement
MoveCharge(dest.X, dest.Y, dest.Z, SPEED_CHARGE, EventId.ChargePrepath);
// If this is ever changed to not happen immediately then all spell effect handlers that use this must be updated
// Charge movement is not started when using EVENT_CHARGE_PREPATH
MoveSplineInit init = new(_owner);
init.MovebyPath(path.GetPath());
+43 -21
View File
@@ -337,8 +337,36 @@ namespace Game.Spells
public void RecalculateDelayMomentForDst()
{
m_delayMoment = CalculateDelayMomentForDst(0.0f);
m_caster.m_Events.ModifyEventTime(_spellEvent, TimeSpan.FromMilliseconds(GetDelayStart() + m_delayMoment));
UpdateDelayMomentForDst(CalculateDelayMomentForDst(0.0f));
}
void UpdateDelayMomentForDst(ulong hitDelay)
{
m_delayMoment = hitDelay;
if (GetDelayStart() != 0)
m_caster.m_Events.ModifyEventTime(_spellEvent, TimeSpan.FromMilliseconds(GetDelayStart() + m_delayMoment));
}
void UpdateDelayMomentForUnitTarget(Unit unit, ulong hitDelay)
{
var itr = m_UniqueTargetInfo.Find(targetInfo => targetInfo.TargetGUID == unit.GetGUID());
ulong oldDelay = itr.TimeDelay;
itr.TimeDelay = hitDelay;
if (hitDelay != 0 && (m_delayMoment == 0 || m_delayMoment > hitDelay))
m_delayMoment = hitDelay;
else if (m_delayMoment != 0 && oldDelay < hitDelay)
{
// if new hit delay is greater than old delay for this target we must check all other spell targets to see if m_delayMoment can be increased
var minDelay = m_UniqueTargetInfo.Min(targetInfo => targetInfo.TimeDelay);
m_delayMoment = minDelay;
}
if (GetDelayStart() != 0)
m_caster.m_Events.ModifyEventTime(_spellEvent, TimeSpan.FromMilliseconds(GetDelayStart() + m_delayMoment));
}
void SelectEffectImplicitTargets(SpellEffectInfo spellEffectInfo, SpellImplicitTargetInfo targetType, ref uint processedEffectMask)
@@ -3054,7 +3082,9 @@ namespace Game.Spells
return 0;
}
// when spell has a single missile we hit all targets (except caster) at the same time
bool single_missile = m_targets.HasDst();
bool ignoreTargetInfoTimeDelay = single_missile;
ulong next_time = 0;
if (!m_launchHandled)
@@ -3065,21 +3095,13 @@ namespace Game.Spells
HandleLaunchPhase();
m_launchHandled = true;
if (m_delayMoment > offset)
{
if (single_missile)
return m_delayMoment;
next_time = m_delayMoment;
if ((m_UniqueTargetInfo.Count > 2 || (m_UniqueTargetInfo.Count == 1 && m_UniqueTargetInfo[0].TargetGUID == m_caster.GetGUID())) || !m_UniqueGOTargetInfo.Empty())
{
offset = 0; // if LaunchDelay was present then the only target that has timeDelay = 0 is m_caster - and that is the only target we want to process now
}
}
}
if (single_missile && offset == 0)
return m_delayMoment;
if (m_delayMoment > offset)
{
ignoreTargetInfoTimeDelay = false;
next_time = m_delayMoment;
}
Player modOwner = m_caster.GetSpellModOwner();
if (modOwner != null)
@@ -3087,7 +3109,7 @@ namespace Game.Spells
PrepareTargetProcessing();
if (!m_immediateHandled && offset != 0)
if (!m_immediateHandled && m_delayMoment <= offset)
{
_handle_immediate_phase();
m_immediateHandled = true;
@@ -3098,13 +3120,13 @@ namespace Game.Spells
List<TargetInfo> delayedTargets = new();
m_UniqueTargetInfo.RemoveAll(target =>
{
if (single_missile || target.TimeDelay <= offset)
if (ignoreTargetInfoTimeDelay || target.TimeDelay <= offset)
{
target.TimeDelay = offset;
delayedTargets.Add(target);
return true;
}
else if (next_time == 0 || target.TimeDelay < next_time)
else if (!single_missile && (next_time == 0 || target.TimeDelay < next_time))
next_time = target.TimeDelay;
return false;
});
@@ -3117,13 +3139,13 @@ namespace Game.Spells
List<GOTargetInfo> delayedGOTargets = new();
m_UniqueGOTargetInfo.RemoveAll(goTarget =>
{
if (single_missile || goTarget.TimeDelay <= offset)
if (ignoreTargetInfoTimeDelay || goTarget.TimeDelay <= offset)
{
goTarget.TimeDelay = offset;
delayedGOTargets.Add(goTarget);
return true;
}
else if (next_time == 0 || goTarget.TimeDelay < next_time)
else if (!single_missile && (next_time == 0 || goTarget.TimeDelay < next_time))
next_time = goTarget.TimeDelay;
return false;
});
@@ -9070,7 +9092,7 @@ namespace Game.Spells
if (m_Spell.m_spellInfo.LaunchDelay != 0)
Cypher.Assert(n_offset == (ulong)Math.Floor(m_Spell.m_spellInfo.LaunchDelay * 1000.0f));
else
Cypher.Assert(n_offset == m_Spell.GetDelayMoment());
Cypher.Assert(n_offset == m_Spell.GetDelayMoment(), $"{n_offset} == {m_Spell.GetDelayMoment()}");
// re-plan the event for the delay moment
m_Spell.GetCaster().m_Events.AddEvent(this, TimeSpan.FromMilliseconds(e_time + n_offset), false);
+21 -14
View File
@@ -3528,21 +3528,17 @@ namespace Game.Spells
if (m_preGeneratedPath == null)
{
Position pos = unitTarget.GetFirstCollisionPosition(unitTarget.GetCombatReach(), unitTarget.GetRelativeAngle(m_caster.GetPosition()));
if (MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) && m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
speed = pos.GetExactDist(m_caster) / speed;
unitCaster.GetMotionMaster().MoveCharge(pos.posX, pos.posY, pos.posZ, speed, EventId.Charge, false, unitTarget, spellEffectExtraData);
m_preGeneratedPath = new PathGenerator(unitCaster);
m_preGeneratedPath.CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
}
else
{
if (MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) && m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
{
Vector3 pos = m_preGeneratedPath.GetActualEndPosition();
speed = new Position(pos.X, pos.Y, pos.Z).GetExactDist(m_caster) / speed;
}
unitCaster.GetMotionMaster().MoveCharge(m_preGeneratedPath, speed, unitTarget, spellEffectExtraData);
}
if (MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) && m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
speed = m_preGeneratedPath.GetPathLength() / speed;
unitCaster.GetMotionMaster().MoveCharge(m_preGeneratedPath, speed, unitTarget, spellEffectExtraData);
// abuse implementation detail of MoveCharge accepting PathGenerator argument (instantly started spline)
UpdateDelayMomentForUnitTarget(unitTarget, (uint)unitCaster.MoveSpline.Duration());
}
if (effectHandleMode == SpellEffectHandleMode.HitTarget)
@@ -3578,7 +3574,18 @@ namespace Game.Spells
pos = unitCaster.GetFirstCollisionPosition(dist, angle);
}
unitCaster.GetMotionMaster().MoveCharge(pos.posX, pos.posY, pos.posZ);
PathGenerator path = new(unitCaster);
path.CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
float speed = MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) ? m_spellInfo.Speed : MotionMaster.SPEED_CHARGE;
if (MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) && m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
speed = path.GetPathLength() / speed;
unitCaster.GetMotionMaster().MoveCharge(path, speed);
// abuse implementation detail of MoveCharge accepting PathGenerator argument (instantly started spline)
UpdateDelayMomentForDst((uint)unitCaster.MoveSpline.Duration());
}
else if (effectHandleMode == SpellEffectHandleMode.Hit)
{