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();
|
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(Position pos, float dist) { ShortenPathUntilDist(new Vector3(pos.posX, pos.posY, pos.posZ), dist); }
|
||||||
|
|
||||||
public void ShortenPathUntilDist(Vector3 target, float dist)
|
public void ShortenPathUntilDist(Vector3 target, float dist)
|
||||||
|
|||||||
@@ -192,7 +192,9 @@ namespace Game.Movement
|
|||||||
|
|
||||||
public void MovementInform(Unit owner)
|
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()
|
public override void UnitSpeedChanged()
|
||||||
|
|||||||
@@ -702,6 +702,8 @@ namespace Game.Movement
|
|||||||
|
|
||||||
MoveCharge(dest.X, dest.Y, dest.Z, SPEED_CHARGE, EventId.ChargePrepath);
|
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
|
// Charge movement is not started when using EVENT_CHARGE_PREPATH
|
||||||
MoveSplineInit init = new(_owner);
|
MoveSplineInit init = new(_owner);
|
||||||
init.MovebyPath(path.GetPath());
|
init.MovebyPath(path.GetPath());
|
||||||
|
|||||||
+43
-21
@@ -337,8 +337,36 @@ namespace Game.Spells
|
|||||||
|
|
||||||
public void RecalculateDelayMomentForDst()
|
public void RecalculateDelayMomentForDst()
|
||||||
{
|
{
|
||||||
m_delayMoment = CalculateDelayMomentForDst(0.0f);
|
UpdateDelayMomentForDst(CalculateDelayMomentForDst(0.0f));
|
||||||
m_caster.m_Events.ModifyEventTime(_spellEvent, TimeSpan.FromMilliseconds(GetDelayStart() + m_delayMoment));
|
}
|
||||||
|
|
||||||
|
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)
|
void SelectEffectImplicitTargets(SpellEffectInfo spellEffectInfo, SpellImplicitTargetInfo targetType, ref uint processedEffectMask)
|
||||||
@@ -3054,7 +3082,9 @@ namespace Game.Spells
|
|||||||
return 0;
|
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 single_missile = m_targets.HasDst();
|
||||||
|
bool ignoreTargetInfoTimeDelay = single_missile;
|
||||||
ulong next_time = 0;
|
ulong next_time = 0;
|
||||||
|
|
||||||
if (!m_launchHandled)
|
if (!m_launchHandled)
|
||||||
@@ -3065,21 +3095,13 @@ namespace Game.Spells
|
|||||||
|
|
||||||
HandleLaunchPhase();
|
HandleLaunchPhase();
|
||||||
m_launchHandled = true;
|
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)
|
if (m_delayMoment > offset)
|
||||||
return m_delayMoment;
|
{
|
||||||
|
ignoreTargetInfoTimeDelay = false;
|
||||||
|
next_time = m_delayMoment;
|
||||||
|
}
|
||||||
|
|
||||||
Player modOwner = m_caster.GetSpellModOwner();
|
Player modOwner = m_caster.GetSpellModOwner();
|
||||||
if (modOwner != null)
|
if (modOwner != null)
|
||||||
@@ -3087,7 +3109,7 @@ namespace Game.Spells
|
|||||||
|
|
||||||
PrepareTargetProcessing();
|
PrepareTargetProcessing();
|
||||||
|
|
||||||
if (!m_immediateHandled && offset != 0)
|
if (!m_immediateHandled && m_delayMoment <= offset)
|
||||||
{
|
{
|
||||||
_handle_immediate_phase();
|
_handle_immediate_phase();
|
||||||
m_immediateHandled = true;
|
m_immediateHandled = true;
|
||||||
@@ -3098,13 +3120,13 @@ namespace Game.Spells
|
|||||||
List<TargetInfo> delayedTargets = new();
|
List<TargetInfo> delayedTargets = new();
|
||||||
m_UniqueTargetInfo.RemoveAll(target =>
|
m_UniqueTargetInfo.RemoveAll(target =>
|
||||||
{
|
{
|
||||||
if (single_missile || target.TimeDelay <= offset)
|
if (ignoreTargetInfoTimeDelay || target.TimeDelay <= offset)
|
||||||
{
|
{
|
||||||
target.TimeDelay = offset;
|
target.TimeDelay = offset;
|
||||||
delayedTargets.Add(target);
|
delayedTargets.Add(target);
|
||||||
return true;
|
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;
|
next_time = target.TimeDelay;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@@ -3117,13 +3139,13 @@ namespace Game.Spells
|
|||||||
List<GOTargetInfo> delayedGOTargets = new();
|
List<GOTargetInfo> delayedGOTargets = new();
|
||||||
m_UniqueGOTargetInfo.RemoveAll(goTarget =>
|
m_UniqueGOTargetInfo.RemoveAll(goTarget =>
|
||||||
{
|
{
|
||||||
if (single_missile || goTarget.TimeDelay <= offset)
|
if (ignoreTargetInfoTimeDelay || goTarget.TimeDelay <= offset)
|
||||||
{
|
{
|
||||||
goTarget.TimeDelay = offset;
|
goTarget.TimeDelay = offset;
|
||||||
delayedGOTargets.Add(goTarget);
|
delayedGOTargets.Add(goTarget);
|
||||||
return true;
|
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;
|
next_time = goTarget.TimeDelay;
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@@ -9070,7 +9092,7 @@ namespace Game.Spells
|
|||||||
if (m_Spell.m_spellInfo.LaunchDelay != 0)
|
if (m_Spell.m_spellInfo.LaunchDelay != 0)
|
||||||
Cypher.Assert(n_offset == (ulong)Math.Floor(m_Spell.m_spellInfo.LaunchDelay * 1000.0f));
|
Cypher.Assert(n_offset == (ulong)Math.Floor(m_Spell.m_spellInfo.LaunchDelay * 1000.0f));
|
||||||
else
|
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
|
// re-plan the event for the delay moment
|
||||||
m_Spell.GetCaster().m_Events.AddEvent(this, TimeSpan.FromMilliseconds(e_time + n_offset), false);
|
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)
|
if (m_preGeneratedPath == null)
|
||||||
{
|
{
|
||||||
Position pos = unitTarget.GetFirstCollisionPosition(unitTarget.GetCombatReach(), unitTarget.GetRelativeAngle(m_caster.GetPosition()));
|
Position pos = unitTarget.GetFirstCollisionPosition(unitTarget.GetCombatReach(), unitTarget.GetRelativeAngle(m_caster.GetPosition()));
|
||||||
if (MathFunctions.fuzzyGt(m_spellInfo.Speed, 0.0f) && m_spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
|
m_preGeneratedPath = new PathGenerator(unitCaster);
|
||||||
speed = pos.GetExactDist(m_caster) / speed;
|
m_preGeneratedPath.CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
|
||||||
|
|
||||||
unitCaster.GetMotionMaster().MoveCharge(pos.posX, pos.posY, pos.posZ, speed, EventId.Charge, false, unitTarget, spellEffectExtraData);
|
|
||||||
}
|
}
|
||||||
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)
|
if (effectHandleMode == SpellEffectHandleMode.HitTarget)
|
||||||
@@ -3578,7 +3574,18 @@ namespace Game.Spells
|
|||||||
pos = unitCaster.GetFirstCollisionPosition(dist, angle);
|
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)
|
else if (effectHandleMode == SpellEffectHandleMode.Hit)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user