diff --git a/Source/Game/DataStorage/AreaTriggerDataStorage.cs b/Source/Game/DataStorage/AreaTriggerDataStorage.cs index f5ddb682b..2087fb013 100644 --- a/Source/Game/DataStorage/AreaTriggerDataStorage.cs +++ b/Source/Game/DataStorage/AreaTriggerDataStorage.cs @@ -124,8 +124,8 @@ namespace Game.DataStorage // 0 1 2 3 4 SQLResult areatriggerCreateProperties = DB.World.Query("SELECT Id, IsCustom, AreaTriggerId, IsAreatriggerCustom, Flags, " + - //5 6 7 8 9 10 11 12 13 14 - "MoveCurveId, ScaleCurveId, MorphCurveId, FacingCurveId, AnimId, AnimKitId, DecalPropertiesId, SpellForVisuals, TimeToTarget, TimeToTargetScale, " + + //5 6 7 8 9 10 11 12 13 14 + "MoveCurveId, ScaleCurveId, MorphCurveId, FacingCurveId, AnimId, AnimKitId, DecalPropertiesId, SpellForVisuals, TimeToTargetScale, Speed, " + //15 16 17 18 19 20 21 22 23 24 "Shape, ShapeData0, ShapeData1, ShapeData2, ShapeData3, ShapeData4, ShapeData5, ShapeData6, ShapeData7, ScriptName FROM `areatrigger_create_properties`"); if (!areatriggerCreateProperties.IsEmpty()) @@ -185,8 +185,8 @@ namespace Game.DataStorage } } - createProperties.TimeToTarget = areatriggerCreateProperties.Read(13); - createProperties.TimeToTargetScale = areatriggerCreateProperties.Read(14); + createProperties.TimeToTargetScale = areatriggerCreateProperties.Read(13); + createProperties.Speed = areatriggerCreateProperties.Read(14); createProperties.Shape.TriggerType = shape; unsafe @@ -315,7 +315,7 @@ namespace Game.DataStorage continue; } - if (createProperties.TimeToTarget != 0 || createProperties.TimeToTargetScale != 0 || createProperties.FacingCurveId != 0 || createProperties.MoveCurveId != 0) + if (createProperties.TimeToTargetScale != 0) { Log.outError(LogFilter.Sql, $"Table `areatrigger` has listed AreaTriggerCreatePropertiesId (Id: {createPropertiesId.Id}, IsCustom: {createPropertiesId.IsCustom}) with time to target values"); continue; diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index 06bc52cc7..67030f420 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -32,7 +32,6 @@ namespace Game.Entities m_areaTriggerData = new AreaTriggerFieldData(); - _spline = new(); _stationaryPosition = new(); } @@ -195,8 +194,6 @@ namespace Game.Entities UpdateShape(); - uint timeToTarget = GetCreateProperties().TimeToTarget != 0 ? GetCreateProperties().TimeToTarget : m_areaTriggerData.Duration; - if (GetCreateProperties().OrbitInfo != null) { AreaTriggerOrbitInfo orbit = GetCreateProperties().OrbitInfo; @@ -205,11 +202,11 @@ namespace Game.Entities else orbit.Center = new(pos.posX, pos.posY, pos.posZ); - InitOrbit(orbit, timeToTarget); + InitOrbit(orbit, GetCreateProperties().Speed); } else if (GetCreateProperties().HasSplines()) { - InitSplineOffsets(GetCreateProperties().SplinePoints, timeToTarget); + InitSplineOffsets(GetCreateProperties().SplinePoints); } // movement on transport of areatriggers on unit is handled by themself @@ -1035,7 +1032,7 @@ namespace Game.Entities } } - void InitSplineOffsets(List offsets, uint timeToTarget) + void InitSplineOffsets(List offsets, float? overrideSpeed = null) { float angleSin = (float)Math.Sin(GetOrientation()); float angleCos = (float)Math.Cos(GetOrientation()); @@ -1054,19 +1051,25 @@ namespace Game.Entities rotatedPoints.Add(new Vector3(x, y, z)); } - InitSplines(rotatedPoints.ToArray(), timeToTarget); + InitSplines(rotatedPoints.ToArray(), overrideSpeed); } - public void InitSplines(Vector3[] splinePoints, uint timeToTarget) + public void InitSplines(Vector3[] splinePoints, float? overrideSpeed = null) { if (splinePoints.Length < 2) return; _movementTime = 0; + _spline = new Spline(); _spline.InitSpline(splinePoints, splinePoints.Length, EvaluationMode.Linear); _spline.InitLengths(); + float speed = overrideSpeed.GetValueOrDefault(GetCreateProperties().Speed); + if (speed <= 0.0f) + speed = 1.0f; + + uint timeToTarget = _spline.Length() / speed * (float)Time.InMilliseconds; SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTarget), timeToTarget); if (IsInWorld) @@ -1083,28 +1086,28 @@ namespace Game.Entities reshape.AreaTriggerSpline = new(); reshape.AreaTriggerSpline.ElapsedTimeForMovement = GetElapsedTimeForMovement(); reshape.AreaTriggerSpline.TimeToTarget = timeToTarget; - reshape.AreaTriggerSpline.Points = splinePoints; + reshape.AreaTriggerSpline.Points = _spline.GetPoints(); SendMessageToSet(reshape, true); } _reachedDestination = false; } - void InitOrbit(AreaTriggerOrbitInfo orbit, uint timeToTarget) + void InitOrbit(AreaTriggerOrbitInfo orbit, float? overrideSpeed = null) { // Circular movement requires either a center position or an attached unit Cypher.Assert(orbit.Center.HasValue || orbit.PathTarget.HasValue); - // should be sent in object create packets only - DoWithSuppressingObjectUpdates(() => - { - SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTarget), timeToTarget); - m_areaTriggerData.ClearChanged(m_areaTriggerData.TimeToTarget); - }); + float speed = overrideSpeed.GetValueOrDefault(GetCreateProperties().Speed); + if (speed <= 0.0f) + speed = 1.0f; + uint timeToTarget = (uint)(orbit.Radius * 2.0f * MathF.PI * (float)Time.InMilliseconds / speed); + + SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.TimeToTarget), timeToTarget); SetUpdateFieldValue(m_values.ModifyValue(m_areaTriggerData).ModifyValue(m_areaTriggerData.OrbitPathTarget), orbit.PathTarget.GetValueOrDefault(ObjectGuid.Empty)); - _orbitInfo = orbit; + _orbitInfo = new AreaTriggerOrbitInfo(); _orbitInfo.TimeToTarget = timeToTarget; _orbitInfo.ElapsedTimeForMovement = 0; @@ -1126,7 +1129,7 @@ namespace Game.Entities Position GetOrbitCenterPosition() { - if (_orbitInfo == null) + if (!HasOrbit()) return null; if (_orbitInfo.PathTarget.HasValue) @@ -1149,7 +1152,7 @@ namespace Game.Entities return GetPosition(); AreaTriggerCreateProperties createProperties = GetCreateProperties(); - AreaTriggerOrbitInfo cmi = _orbitInfo; + AreaTriggerOrbitInfo cmi = GetOrbit(); // AreaTrigger make exactly "Duration / TimeToTarget" loops during his life time float pathProgress = (float)cmi.ElapsedTimeForMovement / cmi.TimeToTarget; diff --git a/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs b/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs index e07bf58ef..cb1affd65 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs @@ -266,13 +266,14 @@ namespace Game.Entities public uint? SpellForVisuals; - public uint TimeToTarget; public uint TimeToTargetScale; public AreaTriggerScaleCurveTemplate OverrideScale; public AreaTriggerScaleCurveTemplate ExtraScale; public AreaTriggerShapeInfo Shape = new(); + + public float Speed = 1.0f; public List SplinePoints = new(); public AreaTriggerOrbitInfo OrbitInfo; diff --git a/Source/Scripts/Spells/Priest.cs b/Source/Scripts/Spells/Priest.cs index 48b00fa60..9b34a7062 100644 --- a/Source/Scripts/Spells/Priest.cs +++ b/Source/Scripts/Spells/Priest.cs @@ -960,7 +960,6 @@ namespace Scripts.Spells.Priest TaskScheduler _scheduler = new(); Position _casterCurrentPosition; List _affectedUnits = new(); - float _maxTravelDistance; public areatrigger_pri_divine_star(AreaTrigger areatrigger) : base(areatrigger) { } @@ -980,18 +979,15 @@ namespace Scripts.Spells.Priest _casterCurrentPosition = caster.GetPosition(); // Note: max. distance at which the Divine Star can travel to is 1's BasePoints yards. - _maxTravelDistance = (float)(spellInfo.GetEffect(1).CalcValue(caster)); + float maxTravelDistance = (float)(spellInfo.GetEffect(1).CalcValue(caster)); Position destPos = _casterCurrentPosition; - at.MovePositionToFirstCollision(destPos, _maxTravelDistance, 0.0f); + at.MovePositionToFirstCollision(destPos, maxTravelDistance, 0.0f); PathGenerator firstPath = new(at); firstPath.CalculatePath(destPos.GetPositionX(), destPos.GetPositionY(), destPos.GetPositionZ(), false); - Vector3 endPoint = firstPath.GetPath().Last(); - - // Note: it takes TimeSpan.FromMilliseconds(1000) to reach 1's BasePoints yards, so it takes (1000 / 1's BasePoints)ms to run 1 yard. - at.InitSplines(firstPath.GetPath(), (uint)(at.GetDistance(endPoint.X, endPoint.Y, endPoint.Z) * (float)(1000 / _maxTravelDistance))); + at.InitSplines(firstPath.GetPath()); } public override void OnUpdate(uint diff) @@ -1060,11 +1056,9 @@ namespace Scripts.Spells.Priest Vector3[] returnSplinePoints = new Vector3[4]; returnSplinePoints[0] = at.GetPosition(); - returnSplinePoints[1] = at.GetPosition(); - returnSplinePoints[2] = caster.GetPosition(); - returnSplinePoints[3] = caster.GetPosition(); + returnSplinePoints[1] = caster.GetPosition(); - at.InitSplines(returnSplinePoints, (uint)(at.GetDistance(caster) / _maxTravelDistance * 1000)); + at.InitSplines(returnSplinePoints); task.Repeat(TimeSpan.FromMilliseconds(250)); }); diff --git a/Source/Scripts/World/AreaTrigger.cs b/Source/Scripts/World/AreaTrigger.cs index 9bc418cd8..09ab5fa3a 100644 --- a/Source/Scripts/World/AreaTrigger.cs +++ b/Source/Scripts/World/AreaTrigger.cs @@ -418,8 +418,7 @@ namespace Scripts.World.Areatriggers PathGenerator path = new(at); path.CalculatePath(destPos.GetPositionX(), destPos.GetPositionY(), destPos.GetPositionZ(), false); - float timeToTarget = at.GetDistance(destPos.GetPositionX(), destPos.GetPositionY(), destPos.GetPositionZ()) * 144.5f; - at.InitSplines(path.GetPath(), (uint)timeToTarget); + at.InitSplines(path.GetPath()); } }