diff --git a/Source/Framework/Constants/Movement/MovementConst.cs b/Source/Framework/Constants/Movement/MovementConst.cs index 5e0553c07..c8ac9282a 100644 --- a/Source/Framework/Constants/Movement/MovementConst.cs +++ b/Source/Framework/Constants/Movement/MovementConst.cs @@ -107,6 +107,19 @@ namespace Framework.Constants public const uint SmartEscortLastOCCPoint = 0xFFFFFF; } + public enum MovementWalkRunSpeedSelectionMode + { + Default, + ForceRun, + ForceWalk + } + + public enum MovementStopReason + { + Finished, // Movement finished either by arriving at location or successfully continuing it for requested duration + Interrupted + } + public enum RotateDirection { Left, diff --git a/Source/Game/Movement/Generators/PointMovement.cs b/Source/Game/Movement/Generators/PointMovement.cs index 0f8072140..ccf44cf3c 100644 --- a/Source/Game/Movement/Generators/PointMovement.cs +++ b/Source/Game/Movement/Generators/PointMovement.cs @@ -3,12 +3,25 @@ using Framework.Constants; using Game.Entities; +using System; namespace Game.Movement { - public class PointMovementGenerator : MovementGeneratorMedium where T : Unit + public class PointMovementGenerator : MovementGenerator { - public PointMovementGenerator(uint id, float x, float y, float z, bool generatePath, float speed = 0.0f, float? finalOrient = null, Unit faceTarget = null, SpellEffectExtraData spellEffectExtraData = null) + uint _movementId; + Position _destination; + float? _speed; + bool _generatePath; + //! if set then unit will turn to specified _orient in provided _pos + float? _finalOrient; + Unit _faceTarget; + SpellEffectExtraData _spellEffectExtra; + MovementWalkRunSpeedSelectionMode _speedSelectionMode; + float? _closeEnoughDistance; + + public PointMovementGenerator(uint id, float x, float y, float z, bool generatePath, float? speed = null, float? finalOrient = null, Unit faceTarget = null, SpellEffectExtraData spellEffectExtraData = null, + MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null) { _movementId = id; _destination = new Position(x, y, z); @@ -17,6 +30,8 @@ namespace Game.Movement _finalOrient = finalOrient; _faceTarget = faceTarget; _spellEffectExtra = spellEffectExtraData; + _speedSelectionMode = speedSelectionMode; + _closeEnoughDistance = closeEnoughDistance; Mode = MovementGeneratorMode.Default; Priority = MovementGeneratorPriority.Normal; @@ -24,7 +39,7 @@ namespace Game.Movement BaseUnitState = UnitState.Roaming; } - public override void DoInitialize(T owner) + public override void Initialize(Unit owner) { RemoveFlag(MovementGeneratorFlags.InitializationPending | MovementGeneratorFlags.Deactivated); AddFlag(MovementGeneratorFlags.Initialized); @@ -45,9 +60,28 @@ namespace Game.Movement owner.AddUnitState(UnitState.RoamingMove); MoveSplineInit init = new(owner); - init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _generatePath); - if (_speed > 0.0f) - init.SetVelocity(_speed); + if (_generatePath) + { + PathGenerator path = new(owner); + bool result = path.CalculatePath(_destination.posX, _destination.posY, _destination.posZ, false); + if (result && !path.GetPathType().HasFlag(PathType.NoPath)) + { + if (_closeEnoughDistance.HasValue) + path.ShortenPathUntilDist(_destination, _closeEnoughDistance.Value); + + init.MovebyPath(path.GetPath()); + return; + } + } + + Position dest = _destination; + if (_closeEnoughDistance.HasValue) + owner.MovePosition(dest, Math.Min(_closeEnoughDistance.Value, dest.GetExactDist(owner)), MathF.PI + owner.GetRelativeAngle(dest)); + + init.MoveTo(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false); + + if (_speed.HasValue) + init.SetVelocity(_speed.Value); if (_faceTarget) init.SetFacing(_faceTarget); @@ -58,6 +92,20 @@ namespace Game.Movement if (_finalOrient.HasValue) init.SetFacing(_finalOrient.Value); + switch (_speedSelectionMode) + { + case MovementWalkRunSpeedSelectionMode.Default: + break; + case MovementWalkRunSpeedSelectionMode.ForceRun: + init.SetWalk(false); + break; + case MovementWalkRunSpeedSelectionMode.ForceWalk: + init.SetWalk(true); + break; + default: + break; + } + init.Launch(); // Call for creature group update @@ -66,14 +114,14 @@ namespace Game.Movement creature.SignalFormationMovement(); } - public override void DoReset(T owner) + public override void Reset(Unit owner) { RemoveFlag(MovementGeneratorFlags.Transitory | MovementGeneratorFlags.Deactivated); - DoInitialize(owner); + Initialize(owner); } - public override bool DoUpdate(T owner, uint diff) + public override bool Update(Unit owner, uint diff) { if (owner == null) return false; @@ -103,8 +151,8 @@ namespace Game.Movement MoveSplineInit init = new(owner); init.MoveTo(_destination.GetPositionX(), _destination.GetPositionY(), _destination.GetPositionZ(), _generatePath); - if (_speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit - init.SetVelocity(_speed); + if (_speed.HasValue) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit + init.SetVelocity(_speed.Value); init.Launch(); // Call for creature group update @@ -122,13 +170,13 @@ namespace Game.Movement return true; } - public override void DoDeactivate(T owner) + public override void Deactivate(Unit owner) { AddFlag(MovementGeneratorFlags.Deactivated); owner.ClearUnitState(UnitState.RoamingMove); } - public override void DoFinalize(T owner, bool active, bool movementInform) + public override void Finalize(Unit owner, bool active, bool movementInform) { AddFlag(MovementGeneratorFlags.Finalized); if (active) @@ -138,13 +186,9 @@ namespace Game.Movement MovementInform(owner); } - public void MovementInform(T owner) + public void MovementInform(Unit owner) { - if (owner.IsTypeId(TypeId.Unit)) - { - if (owner.ToCreature().GetAI() != null) - owner.ToCreature().GetAI().MovementInform(MovementGeneratorType.Point, _movementId); - } + owner.ToCreature()?.GetAI()?.MovementInform(MovementGeneratorType.Point, _movementId); } public override void UnitSpeedChanged() @@ -158,18 +202,9 @@ namespace Game.Movement { return MovementGeneratorType.Point; } - - uint _movementId; - Position _destination; - float _speed; - bool _generatePath; - //! if set then unit will turn to specified _orient in provided _pos - float? _finalOrient; - Unit _faceTarget; - SpellEffectExtraData _spellEffectExtra; } - public class AssistanceMovementGenerator : PointMovementGenerator + public class AssistanceMovementGenerator : PointMovementGenerator { public AssistanceMovementGenerator(uint id, float x, float y, float z) : base(id, x, y, z, true) { } @@ -179,7 +214,7 @@ namespace Game.Movement if (active) owner.ClearUnitState(UnitState.RoamingMove); - if (movementInform && HasFlag(MovementGeneratorFlags.InformEnabled)) + if (movementInform && HasFlag(MovementGeneratorFlags.InformEnabled) && owner.IsCreature()) { Creature ownerCreature = owner.ToCreature(); ownerCreature.SetNoCallAssistance(false); diff --git a/Source/Game/Movement/MotionMaster.cs b/Source/Game/Movement/MotionMaster.cs index 0a7c3d212..f160d8457 100644 --- a/Source/Game/Movement/MotionMaster.cs +++ b/Source/Game/Movement/MotionMaster.cs @@ -597,17 +597,15 @@ namespace Game.Movement Add(new FleeingMovementGenerator(enemy.GetGUID())); } - public void MovePoint(uint id, Position pos, bool generatePath = true, float? finalOrient = null) + public void MovePoint(uint id, Position pos, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null) { - MovePoint(id, pos.posX, pos.posY, pos.posZ, generatePath, finalOrient); + MovePoint(id, pos.posX, pos.posY, pos.posZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance); } - public void MovePoint(uint id, float x, float y, float z, bool generatePath = true, float? finalOrient = null) + public void MovePoint(uint id, float x, float y, float z, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null) { - if (_owner.IsTypeId(TypeId.Player)) - Add(new PointMovementGenerator(id, x, y, z, generatePath, 0.0f, finalOrient)); - else - Add(new PointMovementGenerator(id, x, y, z, generatePath, 0.0f, finalOrient)); + Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePoint: '{_owner.GetGUID()}', targeted point Id: {id} (X: {x}, Y: {y}, Z: {z})"); + Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, null, null, speedSelectionMode, closeEnoughDistance)); } public void MoveCloserAndStop(uint id, Unit target, float distance) @@ -667,20 +665,11 @@ namespace Game.Movement return; */ - if (_owner.IsTypeId(TypeId.Player)) - { - PointMovementGenerator movement = new(id, x, y, z, generatePath, speed, null, target, spellEffectExtraData); - movement.Priority = MovementGeneratorPriority.Highest; - movement.BaseUnitState = UnitState.Charging; - Add(movement); - } - else - { - PointMovementGenerator movement = new(id, x, y, z, generatePath, speed, null, target, spellEffectExtraData); - movement.Priority = MovementGeneratorPriority.Highest; - movement.BaseUnitState = UnitState.Charging; - Add(movement); - } + Log.outDebug(LogFilter.Movement, $"MotionMaster::MoveCharge: '{_owner.GetGUID()}', charging point Id: {id} (X: {x}, Y: {y}, Z: {z})"); + PointMovementGenerator movement = new PointMovementGenerator(id, x, y, z, generatePath, speed, null, target, spellEffectExtraData); + movement.Priority = MovementGeneratorPriority.Highest; + movement.BaseUnitState = UnitState.Charging; + Add(movement); } public void MoveCharge(PathGenerator path, float speed = SPEED_CHARGE, Unit target = null, SpellEffectExtraData spellEffectExtraData = null)