23#include "G3DPosition.hpp"
33#include <boost/container/static_vector.hpp>
138 std::vector<MovementGeneratorInformation> list;
154 list.emplace_back(type, target->GetGUID(), target->GetName());
210 return (*
_generators.begin())->GetMovementGeneratorType();
246 auto itr = std::ranges::find_if(
_generators, std::ref(filter));
270 value = std::ranges::any_of(
_generators, std::ref(filter));
291 enum class InitState :
uint8
296 } initializationState = InitState::AlreadyInitialized;
302 initializationState = top->
Initialize(
_owner) ? InitState::Success : InitState::Failed;
305 initializationState = top->
Initialize(
_owner) ? InitState::Success : InitState::Failed;
307 initializationState = top->
Reset(
_owner) ? InitState::Success : InitState::Failed;
311 if (initializationState == InitState::Failed || !top->
Update(
_owner, initializationState == InitState::AlreadyInitialized ? diff : 0))
553 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTargetedHome: '{}', attempted to move towards target home.",
_owner->
GetGUID());
576 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})",
_owner->
GetGUID(), wanderDistance);
587 if (!target || target ==
_owner)
601 if (!target || target ==
_owner)
612 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveConfused: '{}', started confused movement.",
_owner->
GetGUID());
617 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveConfused: '{}', started confused movement.",
_owner->
GetGUID());
645 fadeObject, std::move(scriptResult));
653 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})",
_owner->
GetGUID(),
id, x, y, z);
654 Add(
new PointMovementGenerator(
id, x, y, z, generatePath, speed, finalOrient,
nullptr,
nullptr, speedSelectionMode, closeEnoughDistance,
655 fadeObject, std::move(scriptResult)));
661 if (distanceToTravel > 0.0f)
675 init.SetFacing(refreshedTarget);
699 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveTierTransition: '{}', anim tier transition to {} Id: {} (X: {}, Y: {}, Z: {})",
703 if (!tierTransitionId)
708 tierTransitionId = 208;
711 tierTransitionId = 149;
714 tierTransitionId = 25;
717 tierTransitionId = 17;
726 init.MoveTo(PositionToVector3(pos),
false);
727 init.SetAnimation(newAnimTier, tierTransitionId);
728 if (flyingTransition)
731 switch (speedSelectionMode)
744 init.SetVelocity(*velocity);
757 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})",
_owner->
GetGUID(),
id, x, y, z);
779 if (spellEffectExtraData)
786 if (std::abs(speedXY) < 0.01f && std::abs(speedZ) < 0.01f)
801 float dist = 2 * moveTimeHalf * speedXY;
804 boost::container::static_vector<G3D::Vector3, 3> path;
805 path.push_back(PositionToVector3(dest));
811 path.push_back(PositionToVector3(dest));
818 path.push_back(PositionToVector3(dest));
823 init.
MovebyPath({ path.data(), path.size() });
843 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveJump: '{}', jumps to point Id: {} ({})",
_owner->
GetGUID(),
id, pos);
847 float speedXY = std::visit([owner =
_owner, speedMultiplier = speedMultiplier.value_or(1.0f), dist]<
typename T>(T speedOrTime) noexcept ->
float
849 if constexpr (std::is_same_v<T, std::monostate>)
851 float baseSpeed = owner->IsControlledByPlayer() ? playerBaseMoveSpeed[MOVE_RUN] : baseMoveSpeed[MOVE_RUN];
852 if (Creature* creature = owner->ToCreature())
853 baseSpeed *= creature->GetCreatureTemplate()->speed_run;
855 return baseSpeed * 3.0f * speedMultiplier;
857 else if constexpr (std::is_same_v<T, float>)
861 else if constexpr (std::is_same_v<T, Milliseconds>)
863 return dist / duration_cast<FloatSeconds>(speedOrTime).count();
867 static_assert(Trinity::dependant_false_v<T>,
"Unhandled type");
872 speedXY = std::min(speedXY, 50.0f);
881 float duration = dist / speedXY;
882 float durationSqr = duration * duration;
883 float height = std::clamp(
Movement::gravity * durationSqr / 8, minHeight.value_or(0.5f), maxHeight.value_or(1000.0f));
887 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(),
false);
888 init.SetParabolic(height, 0);
889 init.SetVelocity(speedXY);
891 init.SetJumpOrientationFixed(orientationFixed);
893 init.SetUnlimitedSpeed();
895 init.SetSpellEffectExtraData(*effect);
898 uint32 arrivalSpellId = 0;
902 arrivalSpellId = arrivalCast->SpellId;
903 arrivalSpellTargetGuid = arrivalCast->Target;
907 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid, .ScriptResult = std::move(scriptResult) });
920 float step = 2 * float(
M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
921 Position const& pos = { x, y, z, 0.0f };
924 init.Path().reserve(stepCount + 1);
929 for (
uint8 i = 0; i < stepCount; angle += step, ++i)
931 G3D::Vector3& point = init.Path().emplace_back();
932 point.x = x + radius * cosf(angle);
933 point.y = y + radius * sinf(angle);
950 switch (speedSelectionMode)
963 init.SetVelocity(*speed);
974 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring.",
_owner->
GetGUID());
977 std::vector<SplineChainLink>
const* chain =
sScriptSystemMgr->GetSplineChain(owner, dbChainId);
980 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}.",
_owner->
GetGUID(), dbChainId);
995 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info.",
_owner->
GetGUID());
1014 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})",
1051 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})", creature->GetGUID(), x, y, z);
1052 creature->AttackStop();
1053 creature->CastStop();
1054 creature->DoNotReacquireSpellFocusTarget();
1059 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance.",
_owner->
GetGUID());
1066 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})",
_owner->
GetGUID(), time);
1070 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.",
_owner->
GetGUID());
1080 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})",
_owner->
GetGUID(), path, pathnode);
1084 ASSERT(!hasExisting,
"Duplicate flight path movement generator");
1091 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})",
_owner->
GetGUID(), path, pathnode);
1094 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})",
_owner->
GetGUID(), path, pathnode);
1103 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})",
_owner->
GetGUID(), timer, orientation);
1109 Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd ,
1121 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1126 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, fadeObject, std::move(scriptResult)),
MOTION_SLOT_DEFAULT);
1129 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, {}, std::move(scriptResult)));
1134 Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd ,
1139 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1144 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, fadeObject, std::move(scriptResult)),
MOTION_SLOT_DEFAULT);
1147 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, {}, std::move(scriptResult)));
1154 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveRotate: '{}', starts rotate (time: {}ms, turnSpeed: {}, totalTurnAngle: {}, direction: {})",
1155 _owner->
GetGUID(), time.value_or(0ms).count(), turnSpeed, totalTurnAngle, direction);
1164 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}",
_owner->
GetGUID(), leader->
GetGUID());
1175 init.MoveTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(),
false);
1176 if (owner->GetTransport())
1177 init.DisableTransportPathTransformations();
1178 init.SetFacing(orientation);
1193 init.MoveTo(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(),
false);
1194 init.SetFacing(owner->GetAbsoluteAngle(
object));
1204 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})",
_owner->
GetGUID(), type,
id, priority);
1208 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})",
_owner->
GetGUID(),
id, type, priority);
1230 Delete(pointer, active, movementInform);
1237 Remove(itr, active, movementInform);
1275 Remove(itr, *itr == top,
false);
1301 if (replacesExisting)
1302 Remove(where, where == top,
false);
1303 else if (where == top)
1304 (*top)->Deactivate(
_owner);
1328 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1338 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1369 unitState |= itr->first;
TaxiPathNodesByPath sTaxiPathNodesByPath
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
#define MAX_FALL_DISTANCE
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
void MovementGeneratorPointerDeleter(MovementGenerator *a)
MovementGenerator * GetIdleMovementGenerator()
bool IsStatic(MovementGenerator *movement)
@ MOTIONMASTER_DELAYED_ADD
@ MOTIONMASTER_DELAYED_REMOVE
@ MOTIONMASTER_DELAYED_REMOVE_TYPE
@ MOTIONMASTER_DELAYED_INITIALIZE
@ MOTIONMASTER_DELAYED_CLEAR_PRIORITY
@ MOTIONMASTER_DELAYED_CLEAR
@ MOTIONMASTER_DELAYED_CLEAR_SLOT
@ MOTIONMASTER_FLAG_DELAYED
@ MOTIONMASTER_FLAG_INITIALIZING
@ MOTIONMASTER_FLAG_UPDATE
@ MOTIONMASTER_FLAG_INITIALIZATION_PENDING
@ MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING
bool IsInvalidMovementSlot(uint8 const slot)
MovementGeneratorPriority
@ MOTION_PRIORITY_HIGHEST
MovementWalkRunSpeedSelectionMode
std::variant< std::monostate, Position, Unit const *, float > MovementFacingTarget
bool IsInvalidMovementGeneratorType(uint8 const type)
@ MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING
@ MOVEMENTGENERATOR_FLAG_DEACTIVATED
@ MOVEMENTGENERATOR_FLAG_FINALIZED
@ MOVEMENTGENERATOR_FLAG_IMMEDIATE
@ MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH
#define sMovementGeneratorRegistry
std::optional< T > Optional
Optional helper class to wrap optional values within.
ObjectGuid const & GetGUID() const
void LoadPath(Player *owner, uint32 startNode=0)
void MoveTierTransition(uint32 id, Position const &pos, AnimTier newAnimTier, Optional< int32 > tierTransitionId={}, Optional< float > velocity={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
bool HasMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
void ClearBaseUnitStates()
void DeleteDefault(bool active, bool movementInform)
bool HasFlag(uint8 const flag) const
void ClearBaseUnitState(MovementGenerator const *movement)
void LaunchMoveSpline(std::function< void(Movement::MoveSplineInit &init)> &&initializer, uint32 id=0, MovementGeneratorPriority priority=MOTION_PRIORITY_NORMAL, MovementGeneratorType type=EFFECT_MOTION_TYPE, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void ResolveDelayedActions()
void MoveTakeoff(uint32 id, Position const &pos, Optional< int32 > tierTransitionId={}, Optional< float > velocity={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveFall(uint32 id=0, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
MovementGeneratorType GetCurrentMovementGeneratorType() const
std::vector< MovementGeneratorInformation > GetMovementGeneratorsInformation() const
void Pop(bool active, bool movementInform)
void PropagateSpeedChange()
void Delete(MovementGenerator *movement, bool active, bool movementInform)
void MoveFollow(Unit *target, float dist, Optional< ChaseAngle > angle={}, Optional< Milliseconds > duration={}, bool ignoreTargetWalk=false, MovementSlot slot=MOTION_SLOT_ACTIVE, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
void MoveFormation(Unit *leader, float range, float angle, uint32 point1, uint32 point2)
void MoveJump(uint32 id, Position const &pos, std::variant< std::monostate, float, Milliseconds > speedOrTime={}, Optional< float > minHeight={}, Optional< float > maxHeight={}, MovementFacingTarget const &facing={}, bool orientationFixed=false, bool unlimitedSpeed=false, Optional< float > speedMultiplier={}, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void InterruptOnTeleport()
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void MoveRotate(uint32 id, RotateDirection direction, Optional< Milliseconds > time={}, Optional< float > turnSpeed={}, Optional< float > totalTurnAngle={}, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
Makes the Unit turn in place.
void DirectAdd(MovementGenerator *movement, MovementSlot slot)
void MoveTaxiFlight(uint32 path, uint32 pathnode, Optional< float > speed={}, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
std::unique_ptr< MovementGenerator, MovementGeneratorDeleter > MovementGeneratorPointer
void AddFlag(uint8 const flag)
void MoveSeekAssistance(float x, float y, float z)
void MoveRandom(float wanderDistance=0.0f, Optional< Milliseconds > duration={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::ForceWalk, MovementSlot slot=MOTION_SLOT_DEFAULT, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveSeekAssistanceDistract(uint32 timer)
void MoveFleeing(Unit *enemy, Milliseconds time=0ms, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void DirectClearDefault()
MotionMasterUnitStatesContainer _baseUnitStatesMap
void ResumeSplineChain(SplineChainResumeInfo const &info)
void RemoveFlag(uint8 const flag)
void Add(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
bool GetDestination(float &x, float &y, float &z)
std::function< void()> DelayedActionDefine
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={}, Optional< MovementFadeObject > fadeObject={}, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
MovementGenerator * GetCurrentMovementGenerator() const
std::deque< DelayedAction > _delayedActions
void MoveCharge(float x, float y, float z, float speed=SPEED_CHARGE, uint32 id=EVENT_CHARGE, bool generatePath=false, Unit const *target=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
MovementSlot GetCurrentSlot() const
MovementGeneratorPointer _defaultGenerator
void MoveCloserAndStop(uint32 id, Unit *target, float distance)
void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount, Optional< Milliseconds > duration={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
void MoveDistract(uint32 time, float orientation)
void MovePath(uint32 pathId, bool repeatable, Optional< Milliseconds > duration={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< std::pair< Milliseconds, Milliseconds > > waitTimeRangeAtPathEnd={}, Optional< float > wanderDistanceAtPathEnds={}, Optional< bool > followPathBackwardsFromEndToStart={}, Optional< bool > exactSplinePath={}, bool generatePath=true, Optional< MovementFadeObject > fadeObject={}, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
MovementGenerator * GetMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void MoveKnockbackFrom(Position const &origin, float speedXY, float speedZ, float angle=M_PI, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveFace(float orientation, uint32 id=EVENT_FACE)
MotionMasterContainer _generators
void AddBaseUnitState(MovementGenerator const *movement)
void MoveLand(uint32 id, Position const &pos, Optional< int32 > tierTransitionId={}, Optional< float > velocity={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
virtual bool Update(Unit *owner, uint32 diff)=0
virtual bool Initialize(Unit *owner)=0
void AddFlag(uint16 const flag)
virtual void Finalize(Unit *owner, bool active, bool movementInform)=0
bool HasFlag(uint16 const flag) const
virtual void UnitSpeedChanged()
virtual MovementGeneratorType GetMovementGeneratorType() const =0
virtual bool Reset(Unit *owner)=0
void MovebyPath(std::span< Vector3 const > path, int32 pointId=0)
void SetVelocity(float velocity)
void SetFacing(float angle)
void SetSpellEffectExtraData(SpellEffectExtraData const &spellEffectExtraData)
void SetParabolic(float amplitude, int32 start_point)
void SetOrientationFixed(bool enable)
static ObjectGuid const Empty
std::string ToString() const
Movement::PointsArray const & GetPath() const
G3D::Vector3 const & GetActualEndPosition() const
void SetFallInformation(uint32 time, float z)
void ClearUnitState(uint32 f)
bool SetFall(bool enable)
void StopMoving(bool force=false)
AnimTier GetAnimTier() const
void AddUnitState(uint32 f)
Unit * GetCharmerOrOwner() const
float GetHoverOffset() const
bool HasUnitState(const uint32 f) const
std::unique_ptr< Movement::MoveSpline > movespline
ObjectGuid GetTarget() const
constexpr uint32 GetMapId() const
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
void MovePositionToFirstCollision(Position &pos, float dist, float angle) const
MovementGenerator * SelectMovementGenerator(Unit *unit)
float computeFallElevation(float t_passed, bool isSafeFall, float start_velocity=0.0f)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
void MultimapErasePair(M &multimap, typename M::key_type const &key, typename M::mapped_type const &value)
std::unique_ptr< T, Impl::stateful_unique_ptr_deleter< Ptr, Del > > make_unique_ptr_with_deleter(Ptr ptr, Del deleter)
bool operator()(MovementGenerator const *a, MovementGenerator const *b) const
void operator()(MovementGenerator *a)
constexpr float GetPositionX() const
constexpr float GetPositionY() const
float GetExactDist2d(const float x, const float y) const
float GetRelativeAngle(float x, float y) const
float GetExactDist(float x, float y, float z) const
Position GetPositionWithOffset(Position const &offset) const
float GetAbsoluteAngle(float x, float y) const
constexpr void GetPosition(float &x, float &y) const
constexpr float GetOrientation() const
constexpr float GetPositionZ() const