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:
@@ -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()
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user