23#include "G3DPosition.hpp"
33#include <boost/container/static_vector.hpp>
143 std::vector<MovementGeneratorInformation> list;
159 list.emplace_back(type, target->GetGUID(), target->GetName());
215 return (*
_generators.begin())->GetMovementGeneratorType();
379 auto itr = std::find(bounds.first, bounds.second, movement);
418 return a->GetMovementGeneratorType() == type;
494 return a->Mode == mode;
516 return a->Priority == priority;
577 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTargetedHome: '{}', attempted to move towards target home.",
_owner->
GetGUID());
600 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})",
_owner->
GetGUID(), wanderDistance);
611 if (!target || target ==
_owner)
625 if (!target || target ==
_owner)
636 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveConfused: '{}', started confused movement.",
_owner->
GetGUID());
641 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveConfused: '{}', started confused movement.",
_owner->
GetGUID());
669 fadeObject, std::move(scriptResult));
677 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})",
_owner->
GetGUID(),
id, x, y, z);
678 Add(
new PointMovementGenerator(
id, x, y, z, generatePath, speed, finalOrient,
nullptr,
nullptr, speedSelectionMode, closeEnoughDistance,
679 fadeObject, std::move(scriptResult)));
685 if (distanceToTravel > 0.0f)
699 init.SetFacing(refreshedTarget);
723 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveTierTransition: '{}', anim tier transition to {} Id: {} (X: {}, Y: {}, Z: {})",
727 if (!tierTransitionId)
732 tierTransitionId = 208;
735 tierTransitionId = 149;
738 tierTransitionId = 25;
741 tierTransitionId = 17;
750 init.MoveTo(PositionToVector3(pos),
false);
751 init.SetAnimation(newAnimTier, tierTransitionId);
752 if (flyingTransition)
755 switch (speedSelectionMode)
768 init.SetVelocity(*velocity);
781 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})",
_owner->
GetGUID(),
id, x, y, z);
803 if (spellEffectExtraData)
810 if (std::abs(speedXY) < 0.01f && std::abs(speedZ) < 0.01f)
825 float dist = 2 * moveTimeHalf * speedXY;
828 boost::container::static_vector<G3D::Vector3, 3> path;
829 path.push_back(PositionToVector3(dest));
835 path.push_back(PositionToVector3(dest));
842 path.push_back(PositionToVector3(dest));
847 init.
MovebyPath({ path.data(), path.size() });
867 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveJump: '{}', jumps to point Id: {} ({})",
_owner->
GetGUID(),
id, pos);
871 float speedXY = std::visit([owner =
_owner, speedMultiplier = speedMultiplier.value_or(1.0f), dist]<
typename T>(T speedOrTime) noexcept ->
float
873 if constexpr (std::is_same_v<T, std::monostate>)
875 float baseSpeed = owner->IsControlledByPlayer() ? playerBaseMoveSpeed[MOVE_RUN] : baseMoveSpeed[MOVE_RUN];
876 if (Creature* creature = owner->ToCreature())
877 baseSpeed *= creature->GetCreatureTemplate()->speed_run;
879 return baseSpeed * 3.0f * speedMultiplier;
881 else if constexpr (std::is_same_v<T, float>)
885 else if constexpr (std::is_same_v<T, Milliseconds>)
887 return dist / duration_cast<FloatSeconds>(speedOrTime).count();
891 static_assert(Trinity::dependant_false_v<T>,
"Unhandled type");
896 speedXY = std::min(speedXY, 50.0f);
905 float duration = dist / speedXY;
906 float durationSqr = duration * duration;
907 float height = std::clamp(
Movement::gravity * durationSqr / 8, minHeight.value_or(0.5f), maxHeight.value_or(1000.0f));
911 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(),
false);
912 init.SetParabolic(height, 0);
913 init.SetVelocity(speedXY);
915 init.SetJumpOrientationFixed(orientationFixed);
917 init.SetUnlimitedSpeed();
919 init.SetSpellEffectExtraData(*effect);
922 uint32 arrivalSpellId = 0;
926 arrivalSpellId = arrivalCast->SpellId;
927 arrivalSpellTargetGuid = arrivalCast->Target;
931 { .ArrivalSpellId = arrivalSpellId, .ArrivalSpellTarget = arrivalSpellTargetGuid, .ScriptResult = std::move(scriptResult) });
944 float step = 2 * float(
M_PI) / stepCount * (clockwise ? -1.0f : 1.0f);
945 Position const& pos = { x, y, z, 0.0f };
948 init.Path().reserve(stepCount + 1);
953 for (
uint8 i = 0; i < stepCount; angle += step, ++i)
955 G3D::Vector3& point = init.Path().emplace_back();
956 point.x = x + radius * cosf(angle);
957 point.y = y + radius * sinf(angle);
974 switch (speedSelectionMode)
987 init.SetVelocity(*speed);
998 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring.",
_owner->
GetGUID());
1001 std::vector<SplineChainLink>
const* chain =
sScriptSystemMgr->GetSplineChain(owner, dbChainId);
1004 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}.",
_owner->
GetGUID(), dbChainId);
1019 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info.",
_owner->
GetGUID());
1038 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})",
1075 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})", creature->GetGUID(), x, y, z);
1076 creature->AttackStop();
1077 creature->CastStop();
1078 creature->DoNotReacquireSpellFocusTarget();
1083 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance.",
_owner->
GetGUID());
1090 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})",
_owner->
GetGUID(), time);
1094 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance.",
_owner->
GetGUID());
1104 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})",
_owner->
GetGUID(), path, pathnode);
1108 ASSERT(!hasExisting,
"Duplicate flight path movement generator");
1115 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})",
_owner->
GetGUID(), path, pathnode);
1118 TC_LOG_ERROR(
"movement.motionmaster",
"MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})",
_owner->
GetGUID(), path, pathnode);
1127 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})",
_owner->
GetGUID(), timer, orientation);
1133 Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd ,
1145 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1150 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, fadeObject, std::move(scriptResult)),
MOTION_SLOT_DEFAULT);
1153 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, {}, std::move(scriptResult)));
1158 Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd ,
1163 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
1168 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, fadeObject, std::move(scriptResult)),
MOTION_SLOT_DEFAULT);
1171 wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, {}, std::move(scriptResult)));
1178 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveRotate: '{}', starts rotate (time: {}ms, turnSpeed: {}, totalTurnAngle: {}, direction: {})",
1179 _owner->
GetGUID(), time.value_or(0ms).count(), turnSpeed, totalTurnAngle, direction);
1188 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}",
_owner->
GetGUID(), leader->
GetGUID());
1197 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})",
_owner->
GetGUID(), type,
id, priority);
1201 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})",
_owner->
GetGUID(),
id, type, priority);
1223 Delete(pointer, active, movementInform);
1273 Delete(movement, movement == top,
false);
1327 if (movement->
Priority == (*itr)->Priority)
1328 Remove(itr,
true,
false);
1330 (*itr)->Deactivate(
_owner);
1336 return a->Priority == movement->Priority;
1340 Remove(itr,
false,
false);
1356 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1366 TC_LOG_DEBUG(
"movement.motionmaster",
"MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'",
1397 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_DELAYED_CLEAR_MODE
@ 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_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 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)
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 void Initialize(Unit *owner)=0
virtual bool Update(Unit *owner, uint32 diff)=0
void AddFlag(uint16 const flag)
virtual void Finalize(Unit *owner, bool active, bool movementInform)=0
bool HasFlag(uint16 const flag) const
virtual void Reset(Unit *owner)=0
virtual void UnitSpeedChanged()
virtual MovementGeneratorType GetMovementGeneratorType() const =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)
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