diff --git a/Source/Framework/Constants/Movement/MovementConst.cs b/Source/Framework/Constants/Movement/MovementConst.cs index c03d06349..c8c7a3da8 100644 --- a/Source/Framework/Constants/Movement/MovementConst.cs +++ b/Source/Framework/Constants/Movement/MovementConst.cs @@ -59,6 +59,11 @@ namespace Framework.Constants /// and had a path already generated - using it in PointMovementGenerator will not /// create a new spline and launch it public const uint ChargePrepath = 1005; + + public const uint Face = 1006; + public const uint VehicleBoard = 1007; + public const uint VehicleExit = 1008; + public const uint SmartRandomPoint = 0xFFFFFE; public const uint SmartEscortLastOCCPoint = 0xFFFFFF; } diff --git a/Source/Game/Entities/Object/Position.cs b/Source/Game/Entities/Object/Position.cs index bfb9a4673..8153de9b3 100644 --- a/Source/Game/Entities/Object/Position.cs +++ b/Source/Game/Entities/Object/Position.cs @@ -353,6 +353,10 @@ namespace Game.Entities { return new(position.posX, position.posY); } + public static implicit operator Vector3(Position position) + { + return new(position.posX, position.posY, position.posZ); + } } public class WorldLocation : Position diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 6a13c8f4e..5ddf576b6 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -205,7 +205,7 @@ namespace Game.Entities MoveSplineInit init = new(this); init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false); init.SetFacing(ori); - init.Launch(); + GetMotionMaster().LaunchMoveSpline(init, EventId.Face, MovementSlot.Controlled); } public void SetFacingToObject(WorldObject obj, bool force = true) @@ -223,7 +223,7 @@ namespace Game.Entities MoveSplineInit init = new(this); init.MoveTo(x, y, z, generatePath, forceDestination); init.SetVelocity(speed); - init.Launch(); + GetMotionMaster().LaunchMoveSpline(init, 0, MovementSlot.Active, MovementGeneratorType.Point); } public void KnockbackFrom(float x, float y, float speedXY, float speedZ, SpellEffectExtraData spellEffectExtraData = null) diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 17ed9e212..a992de8e8 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -999,7 +999,7 @@ namespace Game.Entities init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false); init.SetFacing(GetOrientation()); init.SetTransportExit(); - init.Launch(); + GetMotionMaster().LaunchMoveSpline(init, EventId.VehicleExit, MovementSlot.Controlled); if (player != null) player.ResummonPetTemporaryUnSummonedIfAny(); diff --git a/Source/Game/Entities/Vehicle.cs b/Source/Game/Entities/Vehicle.cs index e2e82f03e..5a2086a8e 100644 --- a/Source/Game/Entities/Vehicle.cs +++ b/Source/Game/Entities/Vehicle.cs @@ -641,7 +641,7 @@ namespace Game.Entities init.MoveTo(veSeat.AttachmentOffset.X, veSeat.AttachmentOffset.Y, veSeat.AttachmentOffset.Z, false, true); init.SetFacing(0.0f); init.SetTransportEnter(); - init.Launch(); + Passenger.GetMotionMaster().LaunchMoveSpline(init, EventId.VehicleBoard, MovementSlot.Controlled); Creature creature = Target.GetBase().ToCreature(); if (creature != null) diff --git a/Source/Game/Movement/Generators/GenericMovementGenerator.cs b/Source/Game/Movement/Generators/GenericMovementGenerator.cs new file mode 100644 index 000000000..c0274ed97 --- /dev/null +++ b/Source/Game/Movement/Generators/GenericMovementGenerator.cs @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012-2020 CypherCore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Framework.Constants; +using Game.Entities; +using System; + +namespace Game.Movement +{ + class GenericMovementGenerator : IMovementGenerator + { + MoveSplineInit _splineInit; + MovementGeneratorType _type; + uint _pointId; + TimeTrackerSmall _duration; + + uint _arrivalSpellId; + ObjectGuid _arrivalSpellTargetGuid; + + public GenericMovementGenerator(MoveSplineInit splineInit, MovementGeneratorType type, uint id, uint arrivalSpellId = 0, ObjectGuid arrivalSpellTargetGuid = default) + { + _splineInit = splineInit; + _type = type; + _pointId = id; + _duration = new(); + _arrivalSpellId = arrivalSpellId; + _arrivalSpellTargetGuid = arrivalSpellTargetGuid; + } + + public void Initialize(Unit owner) + { + _duration.Reset(_splineInit.Launch()); + } + + public bool Update(Unit owner, uint diff) + { + _duration.Update((int)diff); + if (_duration.Passed()) + return false; + + return !owner.MoveSpline.Finalized(); + } + + public void Finalize(Unit owner) + { + MovementInform(owner); + } + + void MovementInform(Unit owner) + { + if (_arrivalSpellId != 0) + owner.CastSpell(Global.ObjAccessor.GetUnit(owner, _arrivalSpellTargetGuid), _arrivalSpellId, true); + + Creature creature = owner.ToCreature(); + if (creature != null) + if (creature.GetAI() != null) + creature.GetAI().MovementInform(_type, _pointId); + } + + public void Reset(Unit owner) { } + + public MovementGeneratorType GetMovementGeneratorType() { return _type; } + } +} diff --git a/Source/Game/Movement/Generators/PointMovement.cs b/Source/Game/Movement/Generators/PointMovement.cs index fa8f34b7f..195b37a79 100644 --- a/Source/Game/Movement/Generators/PointMovement.cs +++ b/Source/Game/Movement/Generators/PointMovement.cs @@ -173,43 +173,4 @@ namespace Game.Movement owner.GetMotionMaster().MoveSeekAssistanceDistract(WorldConfig.GetUIntValue(WorldCfg.CreatureFamilyAssistanceDelay)); } } - - public class EffectMovementGenerator : IMovementGenerator - { - public EffectMovementGenerator(uint Id, uint arrivalSpellId = 0, ObjectGuid arrivalSpellTargetGuid = default) - { - _pointId = Id; - _arrivalSpellId = arrivalSpellId; - _arrivalSpellTargetGuid = arrivalSpellTargetGuid; - } - - public void Initialize(Unit owner) { } - - public void Reset(Unit owner) { } - - public bool Update(Unit owner, uint diff) - { - return !owner.MoveSpline.Finalized(); - } - - public void Finalize(Unit owner) - { - MovementInform(owner); - } - - public void MovementInform(Unit owner) - { - if (_arrivalSpellId != 0) - owner.CastSpell(Global.ObjAccessor.GetUnit(owner, _arrivalSpellTargetGuid), _arrivalSpellId, true); - - if (owner.ToCreature() && owner.ToCreature().GetAI() != null) - owner.ToCreature().GetAI().MovementInform(MovementGeneratorType.Effect, _pointId); - } - - public MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Effect; } - - uint _pointId; - uint _arrivalSpellId; - ObjectGuid _arrivalSpellTargetGuid; - } } diff --git a/Source/Game/Movement/MotionMaster.cs b/Source/Game/Movement/MotionMaster.cs index 7aa675501..e83bb1b87 100644 --- a/Source/Game/Movement/MotionMaster.cs +++ b/Source/Game/Movement/MotionMaster.cs @@ -202,18 +202,20 @@ namespace Game.Movement public void MoveTargetedHome() { + Creature owner = _owner.ToCreature(); + if (owner == null) + { + Log.outError(LogFilter.Movement, $"MotionMaster::MoveTargetedHome: '{_owner.GetGUID()}', attempted to move towards target home."); + return; + } + Clear(false); - if (_owner.IsTypeId(TypeId.Unit) && _owner.ToCreature().GetCharmerOrOwnerGUID().IsEmpty()) - { + Unit target = owner.GetCharmerOrOwner(); + if (target == null) StartMovement(new HomeMovementGenerator(), MovementSlot.Active); - } - else if (_owner.IsTypeId(TypeId.Unit) && !_owner.ToCreature().GetCharmerOrOwnerGUID().IsEmpty()) - { - Unit target = _owner.ToCreature().GetCharmerOrOwner(); - if (target) - StartMovement(new FollowMovementGenerator(target, SharedConst.PetFollowDist, new ChaseAngle(SharedConst.PetFollowAngle)), MovementSlot.Active); - } + else + StartMovement(new FollowMovementGenerator(target, SharedConst.PetFollowDist, new ChaseAngle(SharedConst.PetFollowAngle)), MovementSlot.Active); } public void MoveRandom(float spawndist = 0.0f) @@ -230,8 +232,6 @@ namespace Game.Movement if (!target || target == _owner) return; - Log.outDebug(LogFilter.Misc, $"{(_owner.IsPlayer() ? "Player" : "Creature")} (Entry: {_owner.GetEntry()}, {_owner.GetGUID()}) follows {(target.IsPlayer() ? "player" : "creature")} (Entry {target.GetEntry()}, {target.GetGUID()})."); - StartMovement(new FollowMovementGenerator(target, dist, angle), slot); } @@ -242,8 +242,6 @@ namespace Game.Movement if (!target || target == _owner) return; - Log.outDebug(LogFilter.Misc, $"{(_owner.IsPlayer() ? "Player" : "Creature")} (Entry: {_owner.GetEntry()}, {_owner.GetGUID()}) chase to {(target.IsPlayer() ? "player" : "creature")} (Entry: {target.GetEntry()}, {target.GetGUID()})"); - StartMovement(new ChaseMovementGenerator(target, dist, angle), MovementSlot.Active); } @@ -260,15 +258,15 @@ namespace Game.Movement if (!enemy) return; - if (_owner.IsTypeId(TypeId.Player)) - StartMovement(new FleeingGenerator(enemy.GetGUID()), MovementSlot.Controlled); - else + if (_owner.IsCreature()) { if (time != 0) StartMovement(new TimedFleeingGenerator(enemy.GetGUID(), time), MovementSlot.Controlled); else StartMovement(new FleeingGenerator(enemy.GetGUID()), MovementSlot.Controlled); } + else + StartMovement(new FleeingGenerator(enemy.GetGUID()), MovementSlot.Controlled); } public void MovePoint(uint id, Position pos, bool generatePath = true, float? finalOrient = null) @@ -300,33 +298,25 @@ namespace Game.Movement MoveSplineInit init = new(_owner); init.MoveTo(_owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ()); init.SetFacing(target); - init.Launch(); - StartMovement(new EffectMovementGenerator(id), MovementSlot.Active); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, id), MovementSlot.Active); } } public void MoveLand(uint id, Position pos) { - float x, y, z; - pos.GetPosition(out x, out y, out z); - MoveSplineInit init = new(_owner); - init.MoveTo(x, y, z); + init.MoveTo(pos); init.SetAnimation(AnimType.ToGround); - init.Launch(); - StartMovement(new EffectMovementGenerator(id), MovementSlot.Active); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, id), MovementSlot.Active); } public void MoveTakeoff(uint id, Position pos) { - float x, y, z; - pos.GetPosition(out x, out y, out z); - MoveSplineInit init = new(_owner); - init.MoveTo(x, y, z); + init.MoveTo(pos); init.SetAnimation(AnimType.ToFly); - init.Launch(); - StartMovement(new EffectMovementGenerator(id), MovementSlot.Active); + + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, id), MovementSlot.Active); } public void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint id = EventId.Charge, bool generatePath = false, Unit target = null, SpellEffectExtraData spellEffectExtraData = null) @@ -381,8 +371,7 @@ namespace Game.Movement if (spellEffectExtraData != null) init.SetSpellEffectExtraData(spellEffectExtraData); - init.Launch(); - StartMovement(new EffectMovementGenerator(0), MovementSlot.Controlled); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, 0), MovementSlot.Controlled); } public void MoveJumpTo(float angle, float speedXY, float speedZ) @@ -422,7 +411,6 @@ namespace Game.Movement init.SetFacing(o); if (spellEffectExtraData != null) init.SetSpellEffectExtraData(spellEffectExtraData); - init.Launch(); uint arrivalSpellId = 0; ObjectGuid arrivalSpellTargetGuid = ObjectGuid.Empty; @@ -432,7 +420,7 @@ namespace Game.Movement arrivalSpellTargetGuid = arrivalCast.Target; } - StartMovement(new EffectMovementGenerator(id, arrivalSpellId, arrivalSpellTargetGuid), MovementSlot.Controlled); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, id, arrivalSpellId, arrivalSpellTargetGuid), MovementSlot.Controlled); } public void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, byte stepCount) @@ -469,7 +457,7 @@ namespace Game.Movement init.SetCyclic(); } - init.Launch(); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, 0), MovementSlot.Active); } void MoveSmoothPath(uint pointId, Vector3[] pathPoints, int pathSize, bool walk = false, bool fly = false) @@ -484,14 +472,11 @@ namespace Game.Movement init.MovebyPath(pathPoints); init.SetWalk(walk); - init.Launch(); // This code is not correct - // EffectMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE + // GenericMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE // need to call PointMovementGenerator with various pointIds - StartMovement(new EffectMovementGenerator(pointId), MovementSlot.Active); - //Position pos(pathPoints[pathSize - 1].x, pathPoints[pathSize - 1].y, pathPoints[pathSize - 1].z); - //MovePoint(EVENT_CHARGE_PREPATH, pos, false); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, pointId), MovementSlot.Active); } public void MoveAlongSplineChain(uint pointId, uint dbChainId, bool walk) @@ -550,29 +535,28 @@ namespace Game.Movement MoveSplineInit init = new(_owner); init.MoveTo(_owner.GetPositionX(), _owner.GetPositionY(), tz + _owner.GetHoverOffset(), false); init.SetFall(); - init.Launch(); - StartMovement(new EffectMovementGenerator(id), MovementSlot.Controlled); + StartMovement(new GenericMovementGenerator(init, MovementGeneratorType.Effect, id), MovementSlot.Controlled); } public void MoveSeekAssistance(float x, float y, float z) { - if (_owner.IsTypeId(TypeId.Player)) - Log.outError(LogFilter.Server, "Player {0} attempt to seek assistance", _owner.GetGUID().ToString()); - else + if (_owner.IsCreature()) { _owner.AttackStop(); _owner.CastStop(); _owner.ToCreature().SetReactState(ReactStates.Passive); StartMovement(new AssistanceMovementGenerator(x, y, z), MovementSlot.Active); } + else + Log.outError(LogFilter.Server, $"MotionMaster::MoveSeekAssistance: {_owner.GetGUID()}, attempted to seek assistance"); } public void MoveSeekAssistanceDistract(uint time) { - if (_owner.IsTypeId(TypeId.Player)) - Log.outError(LogFilter.Server, "Player {0} attempt to call distract after assistance", _owner.GetGUID().ToString()); - else + if (_owner.IsCreature()) StartMovement(new AssistanceDistractMovementGenerator(time), MovementSlot.Active); + else + Log.outError(LogFilter.Server, $"MotionMaster::MoveSeekAssistanceDistract: {_owner.GetGUID()} attempted to call distract after assistance"); } public void MoveTaxiFlight(uint path, uint pathnode) @@ -581,22 +565,17 @@ namespace Game.Movement { if (path < CliDB.TaxiPathNodesByPath.Count) { - Log.outDebug(LogFilter.Server, "{0} taxi to (Path {1} node {2})", _owner.GetName(), path, pathnode); - FlightPathMovementGenerator mgen = new(); - mgen.LoadPath(_owner.ToPlayer()); - StartMovement(mgen, MovementSlot.Controlled); + Log.outDebug(LogFilter.Server, $"MotionMaster::MoveTaxiFlight: {_owner.GetGUID()} taxi to Path Id: {path} (node {pathnode})"); + FlightPathMovementGenerator movement = new(); + movement.LoadPath(_owner.ToPlayer()); + StartMovement(movement, MovementSlot.Controlled); } else - { - Log.outDebug(LogFilter.Server, "{0} attempt taxi to (not existed Path {1} node {2})", - _owner.GetName(), path, pathnode); - } + Log.outError(LogFilter.Movement, $"MotionMaster::MoveTaxiFlight: '{_owner.GetGUID()}', attempted taxi to non-existing path Id: {path} (node: {pathnode})"); + } else - { - Log.outDebug(LogFilter.Server, "Creature (Entry: {0} GUID: {1}) attempt taxi to (Path {2} node {3})", - _owner.GetEntry(), _owner.GetGUID().ToString(), path, pathnode); - } + Log.outError(LogFilter.Movement, $"MotionMaster::MoveTaxiFlight: '{_owner.GetGUID()}', attempted taxi to path Id: {path} (node: {pathnode})"); } public void MoveDistract(uint timer) @@ -634,6 +613,17 @@ namespace Game.Movement StartMovement(new FormationMovementGenerator(id, destination, moveType, forceRun, forceOrientation), MovementSlot.Active); } + public void LaunchMoveSpline(MoveSplineInit init, uint id = 0, MovementSlot slot = MovementSlot.Active, MovementGeneratorType type = MovementGeneratorType.Effect) + { + if (IsInvalidMovementGeneratorType(type)) + { + Log.outDebug(LogFilter.Movement, $"MotionMaster::LaunchMoveSpline: '{_owner.GetGUID()}', tried to launch a spline with an invalid MovementGeneratorType: {type} (Id: {id}, Slot: {slot})"); + return; + } + + StartMovement(new GenericMovementGenerator(init, type, id), slot); + } + void Pop() { if (Empty()) @@ -824,6 +814,8 @@ namespace Game.Movement return (movement == staticIdleMovement); } + bool IsInvalidMovementGeneratorType(MovementGeneratorType type) { return type == MovementGeneratorType.MaxDB || type == MovementGeneratorType.Max; } + static uint splineId; Unit _owner { get; } diff --git a/Source/Scripts/World/NpcSpecial.cs b/Source/Scripts/World/NpcSpecial.cs index e4cf719e9..1c8c7758d 100644 --- a/Source/Scripts/World/NpcSpecial.cs +++ b/Source/Scripts/World/NpcSpecial.cs @@ -2323,7 +2323,7 @@ namespace Scripts.World.NpcSpecial init.DisableTransportPathTransformations(); init.MoveTo(x, y, z, false); init.SetFacing(o); - init.Launch(); + who.GetMotionMaster().LaunchMoveSpline(init, EventId.VehicleBoard, MovementSlot.Controlled); who.m_Events.AddEvent(new CastFoodSpell(who, SpellIds.ChairSpells[who.GetEntry()]), who.m_Events.CalculateTime(1000)); Creature creature = who.ToCreature(); if (creature)