2010-10-07 15:35:36 +02:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2010-10-07 15:35:36 +02:00
*
* 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 2 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 <http://www.gnu.org/licenses/>.
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
#include "MotionMaster.h"
2017-08-12 01:40:25 +02:00
#include "Creature.h"
#include "CreatureAISelector.h"
#include "DB2Stores.h"
2018-06-03 10:06:57 -07:00
#include "Errors.h"
2018-04-23 20:33:14 +02:00
#include "G3DPosition.hpp"
2017-08-12 01:40:25 +02:00
#include "Log.h"
2024-12-31 18:12:36 +01:00
#include "MapUtils.h"
#include "Memory.h"
2012-01-14 15:34:41 +01:00
#include "MoveSpline.h"
2022-04-03 22:36:49 +02:00
#include "ObjectAccessor.h"
2017-04-07 21:35:23 +02:00
#include "PathGenerator.h"
2017-08-12 01:40:25 +02:00
#include "Player.h"
2018-04-19 13:31:39 +02:00
#include "ScriptSystem.h"
2025-11-17 16:18:04 +01:00
#include <boost/container/static_vector.hpp>
2018-06-03 10:06:57 -07:00
#include <algorithm>
#include <iterator>
2018-04-19 13:31:39 +02:00
#include "ChaseMovementGenerator.h"
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
#include "FlightPathMovementGenerator.h"
#include "FollowMovementGenerator.h"
#include "FormationMovementGenerator.h"
2018-04-23 20:33:14 +02:00
#include "GenericMovementGenerator.h"
2018-04-19 13:31:39 +02:00
#include "HomeMovementGenerator.h"
#include "IdleMovementGenerator.h"
2017-08-12 01:40:25 +02:00
#include "PointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "SplineChainMovementGenerator.h"
#include "WaypointMovementGenerator.h"
2009-10-17 15:51:44 -07:00
2017-06-01 02:29:20 -03:00
inline MovementGenerator * GetIdleMovementGenerator ()
{
return sMovementGeneratorRegistry -> GetRegistryItem ( IDLE_MOTION_TYPE ) -> Create ();
}
2016-11-23 02:28:40 +01:00
inline bool IsStatic ( MovementGenerator * movement )
2008-10-11 14:16:25 -05:00
{
2017-06-01 02:29:20 -03:00
return ( movement == GetIdleMovementGenerator ());
2016-11-23 02:28:40 +01:00
}
2018-06-03 10:06:57 -07:00
inline void MovementGeneratorPointerDeleter ( MovementGenerator * a )
{
if ( a != nullptr && ! IsStatic ( a ))
delete a ;
}
2019-01-10 22:51:47 +01:00
void MovementGeneratorDeleter :: operator ()( MovementGenerator * a )
2018-06-03 10:06:57 -07:00
{
MovementGeneratorPointerDeleter ( a );
}
bool MovementGeneratorComparator :: operator ()( MovementGenerator const * a , MovementGenerator const * b ) const
{
if ( a -> Mode > b -> Mode )
return true ;
else if ( a -> Mode == b -> Mode )
return a -> Priority > b -> Priority ;
return false ;
}
MovementGeneratorInformation :: MovementGeneratorInformation ( MovementGeneratorType type , ObjectGuid targetGUID , std :: string const & targetName ) : Type ( type ), TargetGUID ( targetGUID ), TargetName ( targetName ) { }
2019-10-21 16:49:25 +02:00
MotionMaster :: MotionMaster ( Unit * unit ) : _owner ( unit ), _defaultGenerator ( nullptr ), _flags ( MOTIONMASTER_FLAG_INITIALIZATION_PENDING ) { }
2018-06-03 10:06:57 -07:00
2016-11-23 02:28:40 +01:00
MotionMaster ::~ MotionMaster ()
{
2018-06-03 10:06:57 -07:00
_delayedActions . clear ();
for ( auto itr = _generators . begin (); itr != _generators . end (); itr = _generators . erase ( itr ))
MovementGeneratorPointerDeleter ( * itr );
}
void MotionMaster :: Initialize ()
{
2019-10-23 03:28:57 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_INITIALIZATION_PENDING ))
return ;
if ( HasFlag ( MOTIONMASTER_FLAG_UPDATE ))
2016-11-23 02:28:40 +01:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this ]()
2018-06-03 10:06:57 -07:00
{
Initialize ();
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_INITIALIZE );
return ;
2017-03-25 13:17:29 +01:00
}
2018-06-03 10:06:57 -07:00
DirectInitialize ();
}
void MotionMaster :: InitializeDefault ()
{
Add ( FactorySelector :: SelectMovementGenerator ( _owner ), MOTION_SLOT_DEFAULT );
}
2019-10-21 13:55:23 +02:00
void MotionMaster :: AddToWorld ()
{
if ( ! HasFlag ( MOTIONMASTER_FLAG_INITIALIZATION_PENDING ))
return ;
2019-10-22 15:48:00 +02:00
AddFlag ( MOTIONMASTER_FLAG_INITIALIZING );
RemoveFlag ( MOTIONMASTER_FLAG_INITIALIZATION_PENDING );
2019-10-23 03:28:57 +02:00
DirectInitialize ();
2019-10-21 13:55:23 +02:00
ResolveDelayedActions ();
2019-10-22 15:48:00 +02:00
RemoveFlag ( MOTIONMASTER_FLAG_INITIALIZING );
2019-10-21 13:55:23 +02:00
}
2018-06-03 10:06:57 -07:00
bool MotionMaster :: Empty () const
{
return ! _defaultGenerator && _generators . empty ();
}
uint32 MotionMaster :: Size () const
{
2019-07-09 15:25:25 +02:00
return ( _defaultGenerator ? 1 : 0 ) + uint32 ( _generators . size ());
2018-06-03 10:06:57 -07:00
}
2019-01-10 23:02:43 +01:00
std :: vector < MovementGeneratorInformation > MotionMaster :: GetMovementGeneratorsInformation () const
2018-06-03 10:06:57 -07:00
{
std :: vector < MovementGeneratorInformation > list ;
if ( _defaultGenerator )
list . emplace_back ( _defaultGenerator -> GetMovementGeneratorType (), ObjectGuid :: Empty , std :: string ());
for ( auto itr = _generators . begin (); itr != _generators . end (); ++ itr )
2017-03-25 13:17:29 +01:00
{
2018-06-03 10:06:57 -07:00
MovementGenerator * movement = * itr ;
MovementGeneratorType const type = movement -> GetMovementGeneratorType ();
switch ( type )
{
case CHASE_MOTION_TYPE :
case FOLLOW_MOTION_TYPE :
if ( AbstractFollower * followInformation = dynamic_cast < AbstractFollower *> ( movement ))
{
if ( Unit * target = followInformation -> GetTarget ())
list . emplace_back ( type , target -> GetGUID (), target -> GetName ());
else
list . emplace_back ( type , ObjectGuid :: Empty , std :: string ());
}
else
list . emplace_back ( type , ObjectGuid :: Empty , std :: string ());
break ;
default :
list . emplace_back ( type , ObjectGuid :: Empty , std :: string ());
break ;
}
2016-11-23 02:28:40 +01:00
}
2018-06-03 10:06:57 -07:00
return list ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
MovementSlot MotionMaster :: GetCurrentSlot () const
2018-04-19 13:31:39 +02:00
{
2018-06-03 10:06:57 -07:00
if ( ! _generators . empty ())
return MOTION_SLOT_ACTIVE ;
2018-04-19 13:31:39 +02:00
2018-06-03 10:06:57 -07:00
if ( _defaultGenerator )
return MOTION_SLOT_DEFAULT ;
return MAX_MOTION_SLOT ;
2018-04-19 13:31:39 +02:00
}
2018-06-03 10:06:57 -07:00
MovementGenerator * MotionMaster :: GetCurrentMovementGenerator () const
{
if ( ! _generators . empty ())
return * _generators . begin ();
if ( _defaultGenerator )
return _defaultGenerator . get ();
return nullptr ;
}
MovementGeneratorType MotionMaster :: GetCurrentMovementGeneratorType () const
{
if ( Empty ())
return MAX_MOTION_TYPE ;
MovementGenerator const * movement = GetCurrentMovementGenerator ();
if ( ! movement )
return MAX_MOTION_TYPE ;
return movement -> GetMovementGeneratorType ();
}
MovementGeneratorType MotionMaster :: GetCurrentMovementGeneratorType ( MovementSlot slot ) const
{
if ( Empty () || IsInvalidMovementSlot ( slot ))
return MAX_MOTION_TYPE ;
if ( slot == MOTION_SLOT_ACTIVE && ! _generators . empty ())
return ( * _generators . begin ()) -> GetMovementGeneratorType ();
if ( slot == MOTION_SLOT_DEFAULT && _defaultGenerator )
return _defaultGenerator -> GetMovementGeneratorType ();
return MAX_MOTION_TYPE ;
}
MovementGenerator * MotionMaster :: GetCurrentMovementGenerator ( MovementSlot slot ) const
{
if ( Empty () || IsInvalidMovementSlot ( slot ))
return nullptr ;
if ( slot == MOTION_SLOT_ACTIVE && ! _generators . empty ())
return * _generators . begin ();
if ( slot == MOTION_SLOT_DEFAULT && _defaultGenerator )
return _defaultGenerator . get ();
return nullptr ;
}
MovementGenerator * MotionMaster :: GetMovementGenerator ( std :: function < bool ( MovementGenerator const * ) > const & filter , MovementSlot slot ) const
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
if ( Empty () || IsInvalidMovementSlot ( slot ))
return nullptr ;
MovementGenerator * movement = nullptr ;
switch ( slot )
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
case MOTION_SLOT_DEFAULT :
if ( _defaultGenerator && filter ( _defaultGenerator . get ()))
movement = _defaultGenerator . get ();
break ;
case MOTION_SLOT_ACTIVE :
if ( ! _generators . empty ())
{
auto itr = std :: find_if ( _generators . begin (), _generators . end (), std :: ref ( filter ));
if ( itr != _generators . end ())
movement = * itr ;
}
break ;
default :
break ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
return movement ;
2009-03-21 10:11:29 -06:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
bool MotionMaster :: HasMovementGenerator ( std :: function < bool ( MovementGenerator const * ) > const & filter , MovementSlot slot ) const
2009-03-21 10:11:29 -06:00
{
2018-06-03 10:06:57 -07:00
if ( Empty () || IsInvalidMovementSlot ( slot ))
return false ;
bool value = false ;
switch ( slot )
{
case MOTION_SLOT_DEFAULT :
if ( _defaultGenerator && filter ( _defaultGenerator . get ()))
value = true ;
break ;
case MOTION_SLOT_ACTIVE :
if ( ! _generators . empty ())
{
auto itr = std :: find_if ( _generators . begin (), _generators . end (), std :: ref ( filter ));
value = itr != _generators . end ();
}
break ;
default :
break ;
}
return value ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Update ( uint32 diff )
2008-10-11 14:16:25 -05:00
{
2012-02-14 12:46:26 -05:00
if ( ! _owner )
2011-08-01 13:44:54 +02:00
return ;
2019-10-22 15:48:00 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_INITIALIZATION_PENDING | MOTIONMASTER_FLAG_INITIALIZING ))
2019-10-21 13:55:23 +02:00
return ;
2018-06-03 10:06:57 -07:00
ASSERT ( ! Empty (), "MotionMaster:Update: update called without Initializing! (%s)" , _owner -> GetGUID (). ToString (). c_str ());
2011-08-01 13:44:54 +02:00
2018-06-03 10:06:57 -07:00
AddFlag ( MOTIONMASTER_FLAG_UPDATE );
MovementGenerator * top = GetCurrentMovementGenerator ();
if ( HasFlag ( MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING ) && IsStatic ( top ))
2017-03-25 12:33:39 +01:00
{
2018-06-03 10:06:57 -07:00
RemoveFlag ( MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING );
top -> Initialize ( _owner );
2017-03-25 12:33:39 +01:00
}
2018-06-03 10:06:57 -07:00
if ( top -> HasFlag ( MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING ))
top -> Initialize ( _owner );
if ( top -> HasFlag ( MOVEMENTGENERATOR_FLAG_DEACTIVATED ))
top -> Reset ( _owner );
ASSERT ( ! top -> HasFlag ( MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_DEACTIVATED ), "MotionMaster:Update: update called on an uninitialized top! (%s) (type: %u, flags: %u)" , _owner -> GetGUID (). ToString (). c_str (), top -> GetMovementGeneratorType (), top -> Flags );
if ( ! top -> Update ( _owner , diff ))
{
ASSERT ( top == GetCurrentMovementGenerator (), "MotionMaster::Update: top was modified while updating! (%s)" , _owner -> GetGUID (). ToString (). c_str ());
// Since all the actions that modify any slot are delayed, this movement is guaranteed to be top
Pop ( true , true ); // Natural, and only, call to MovementInform
}
RemoveFlag ( MOTIONMASTER_FLAG_UPDATE );
2009-10-17 15:51:44 -07:00
2019-10-21 13:55:23 +02:00
ResolveDelayedActions ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Add ( MovementGenerator * movement , MovementSlot slot /* = MOTION_SLOT_ACTIVE*/ )
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
if ( ! movement )
return ;
if ( IsInvalidMovementSlot ( slot ))
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
delete movement ;
return ;
}
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , movement , slot ]()
2018-06-03 10:06:57 -07:00
{
Add ( movement , slot );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_ADD );
2008-10-11 14:16:25 -05:00
}
2016-11-23 02:28:40 +01:00
else
2018-06-03 10:06:57 -07:00
DirectAdd ( movement , slot );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Remove ( MovementGenerator * movement , MovementSlot slot /* = MOTION_SLOT_ACTIVE*/ )
2017-08-08 20:29:30 +02:00
{
2018-06-03 10:06:57 -07:00
if ( ! movement || IsInvalidMovementSlot ( slot ))
2017-08-08 20:29:30 +02:00
return ;
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , movement , slot ]()
2018-06-03 10:06:57 -07:00
{
Remove ( movement , slot );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_REMOVE );
return ;
}
if ( Empty ())
return ;
switch ( slot )
{
case MOTION_SLOT_DEFAULT :
if ( _defaultGenerator && _defaultGenerator . get () == movement )
DirectClearDefault ();
break ;
case MOTION_SLOT_ACTIVE :
if ( ! _generators . empty ())
{
2019-04-17 00:06:06 +02:00
auto bounds = _generators . equal_range ( movement );
auto itr = std :: find ( bounds . first , bounds . second , movement );
2018-06-03 10:06:57 -07:00
if ( itr != _generators . end ())
2019-04-16 23:29:04 +02:00
Remove ( itr , GetCurrentMovementGenerator () == * itr , false );
2018-06-03 10:06:57 -07:00
}
break ;
default :
break ;
}
2017-08-08 20:29:30 +02:00
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: Remove ( MovementGeneratorType type , MovementSlot slot /* = MOTION_SLOT_ACTIVE*/ )
2008-12-19 00:37:40 +02:00
{
2018-06-03 10:06:57 -07:00
if ( IsInvalidMovementGeneratorType ( type ) || IsInvalidMovementSlot ( slot ))
return ;
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2008-12-19 00:37:40 +02:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , type , slot ]()
2018-06-03 10:06:57 -07:00
{
Remove ( type , slot );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_REMOVE_TYPE );
return ;
}
if ( Empty ())
return ;
switch ( slot )
{
case MOTION_SLOT_DEFAULT :
if ( _defaultGenerator && _defaultGenerator -> GetMovementGeneratorType () == type )
DirectClearDefault ();
break ;
case MOTION_SLOT_ACTIVE :
if ( ! _generators . empty ())
{
auto itr = std :: find_if ( _generators . begin (), _generators . end (), [ type ]( MovementGenerator const * a ) -> bool
{
return a -> GetMovementGeneratorType () == type ;
});
if ( itr != _generators . end ())
2019-04-16 23:29:04 +02:00
Remove ( itr , GetCurrentMovementGenerator () == * itr , false );
2018-06-03 10:06:57 -07:00
}
break ;
default :
break ;
2008-12-19 00:37:40 +02:00
}
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Clear ()
2008-10-11 14:16:25 -05:00
{
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this ]()
2018-06-03 10:06:57 -07:00
{
Clear ();
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_CLEAR );
return ;
}
2018-04-20 12:46:24 +02:00
2018-06-03 10:06:57 -07:00
if ( ! Empty ())
DirectClear ();
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Clear ( MovementSlot slot )
{
if ( IsInvalidMovementSlot ( slot ))
return ;
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , slot ]()
2018-06-03 10:06:57 -07:00
{
Clear ( slot );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_CLEAR_SLOT );
return ;
}
if ( Empty ())
return ;
switch ( slot )
{
case MOTION_SLOT_DEFAULT :
DirectClearDefault ();
break ;
case MOTION_SLOT_ACTIVE :
DirectClear ();
break ;
default :
break ;
}
2016-11-23 02:28:40 +01:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Clear ( MovementGeneratorMode mode )
2016-11-23 02:28:40 +01:00
{
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , mode ]()
2018-06-03 10:06:57 -07:00
{
Clear ( mode );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_CLEAR_MODE );
return ;
}
if ( Empty ())
return ;
2017-11-06 22:19:23 +01:00
2018-06-03 10:06:57 -07:00
std :: function < bool ( MovementGenerator * ) > criteria = [ mode ]( MovementGenerator * a ) -> bool
{
return a -> Mode == mode ;
};
DirectClear ( criteria );
2009-02-08 22:56:57 -06:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: Clear ( MovementGeneratorPriority priority )
2009-02-08 22:56:57 -06:00
{
2019-10-21 13:55:23 +02:00
if ( HasFlag ( MOTIONMASTER_FLAG_DELAYED ))
2018-06-03 10:06:57 -07:00
{
2019-05-19 11:38:10 +02:00
DelayedActionDefine action = [ this , priority ]()
2018-06-03 10:06:57 -07:00
{
Clear ( priority );
};
_delayedActions . emplace_back ( std :: move ( action ), MOTIONMASTER_DELAYED_CLEAR_PRIORITY );
return ;
}
2017-11-06 22:19:23 +01:00
2018-06-03 10:06:57 -07:00
if ( Empty ())
return ;
std :: function < bool ( MovementGenerator * ) > criteria = [ priority ]( MovementGenerator * a ) -> bool
{
return a -> Priority == priority ;
};
DirectClear ( criteria );
2016-11-23 02:28:40 +01:00
}
2017-04-07 21:35:23 +02:00
void MotionMaster :: PropagateSpeedChange ()
2016-11-23 02:28:40 +01:00
{
2018-06-03 10:06:57 -07:00
if ( Empty ())
2017-08-08 19:49:12 +02:00
return ;
2018-06-03 10:06:57 -07:00
MovementGenerator * movement = GetCurrentMovementGenerator ();
2017-08-08 19:49:12 +02:00
if ( ! movement )
return ;
movement -> UnitSpeedChanged ();
2016-11-23 02:28:40 +01:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
bool MotionMaster :: GetDestination ( float & x , float & y , float & z )
{
if ( _owner -> movespline -> Finalized ())
return false ;
G3D :: Vector3 const & dest = _owner -> movespline -> FinalDestination ();
x = dest . x ;
y = dest . y ;
z = dest . z ;
return true ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2021-06-06 17:51:00 +02:00
bool MotionMaster :: StopOnDeath ()
{
if ( MovementGenerator * movementGenerator = GetCurrentMovementGenerator ())
if ( movementGenerator -> HasFlag ( MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH ))
return false ;
if ( _owner -> IsInWorld ())
{
// Only clear MotionMaster for entities that exists in world
// Avoids crashes in the following conditions :
// * Using 'call pet' on dead pets
// * Using 'call stabled pet'
// * Logging in with dead pets
Clear ();
MoveIdle ();
}
_owner -> StopMoving ();
return true ;
}
2012-01-13 16:43:49 +01:00
void MotionMaster :: MoveIdle ()
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
Add ( GetIdleMovementGenerator (), MOTION_SLOT_DEFAULT );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-27 12:40:14 +02:00
void MotionMaster :: MoveTargetedHome ()
2008-10-11 14:16:25 -05:00
{
2018-04-23 20:33:14 +02:00
Creature * owner = _owner -> ToCreature ();
if ( ! owner )
{
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveTargetedHome: '{}', attempted to move towards target home." , _owner -> GetGUID ());
2018-04-23 20:33:14 +02:00
return ;
}
2018-06-03 10:06:57 -07:00
Clear ();
2009-10-17 15:51:44 -07:00
2018-04-23 20:33:14 +02:00
Unit * target = owner -> GetCharmerOrOwner ();
if ( ! target )
2008-10-11 14:16:25 -05:00
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveTargetedHome: '{}', targeted home." , _owner -> GetGUID ());
2018-06-03 10:06:57 -07:00
Add ( new HomeMovementGenerator < Creature > ());
2008-10-11 14:16:25 -05:00
}
else
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveTargetedHome: '{}', starts following '{}'" , _owner -> GetGUID (), target -> GetGUID ());
2023-03-04 14:57:17 +01:00
Add ( new FollowMovementGenerator ( target , PET_FOLLOW_DIST , PET_FOLLOW_ANGLE , {}));
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2024-04-06 20:50:59 +02:00
void MotionMaster :: MoveRandom ( float wanderDistance /*= 0.0f*/ , Optional < Milliseconds > duration /*= {}*/ , MovementSlot slot /*= MOTION_SLOT_DEFAULT*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( _owner -> GetTypeId () == TYPEID_UNIT )
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})" , _owner -> GetGUID (), wanderDistance );
2024-04-06 20:50:59 +02:00
Add ( new RandomMovementGenerator < Creature > ( wanderDistance , duration , std :: move ( scriptResult )), slot );
2016-11-23 02:28:40 +01:00
}
2024-04-06 20:50:59 +02:00
else if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2016-11-23 02:28:40 +01:00
}
2024-08-02 22:46:29 +02:00
void MotionMaster :: MoveFollow ( Unit * target , float dist , Optional < ChaseAngle > angle /*= {}*/ , Optional < Milliseconds > duration /*= {}*/ , bool ignoreTargetWalk /*= false*/ , MovementSlot slot /* = MOTION_SLOT_ACTIVE*/ ,
2024-04-06 20:50:59 +02:00
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2016-11-23 02:28:40 +01:00
{
2018-06-03 10:06:57 -07:00
// Ignore movement request if target not exist
2016-11-23 02:28:40 +01:00
if ( ! target || target == _owner )
2024-04-06 20:50:59 +02:00
{
if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2016-11-23 02:28:40 +01:00
return ;
2024-04-06 20:50:59 +02:00
}
2016-11-23 02:28:40 +01:00
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveFollow: '{}', starts following '{}'" , _owner -> GetGUID (), target -> GetGUID ());
2024-08-02 22:46:29 +02:00
Add ( new FollowMovementGenerator ( target , dist , angle , duration , ignoreTargetWalk , std :: move ( scriptResult )), slot );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2019-03-02 14:04:01 +00:00
void MotionMaster :: MoveChase ( Unit * target , Optional < ChaseRange > dist , Optional < ChaseAngle > angle )
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
// Ignore movement request if target not exist
2016-05-27 14:45:06 +02:00
if ( ! target || target == _owner )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveChase: '{}', starts chasing '{}'" , _owner -> GetGUID (), target -> GetGUID ());
2019-03-02 14:04:01 +00:00
Add ( new ChaseMovementGenerator ( target , dist , angle ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
void MotionMaster :: MoveConfused ()
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveConfused: '{}', started confused movement." , _owner -> GetGUID ());
2018-06-03 10:06:57 -07:00
Add ( new ConfusedMovementGenerator < Player > ());
2016-11-23 02:28:40 +01:00
}
else
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveConfused: '{}', started confused movement." , _owner -> GetGUID ());
2018-06-03 10:06:57 -07:00
Add ( new ConfusedMovementGenerator < Creature > ());
2016-11-23 02:28:40 +01:00
}
}
2024-04-06 20:50:59 +02:00
void MotionMaster :: MoveFleeing ( Unit * enemy , Milliseconds time /*= 0ms*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2016-11-23 02:28:40 +01:00
{
if ( ! enemy )
2024-04-06 20:50:59 +02:00
{
if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2008-10-11 14:16:25 -05:00
return ;
2024-04-06 20:50:59 +02:00
}
2009-10-17 15:51:44 -07:00
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveFleeing: '{}', flees from '{}' (time: {}ms)" , _owner -> GetGUID (), enemy -> GetGUID (), time . count ());
2024-02-22 18:21:52 +01:00
if ( _owner -> GetTypeId () == TYPEID_UNIT && time > 0 ms )
2024-04-06 20:50:59 +02:00
Add ( new TimedFleeingMovementGenerator ( enemy -> GetGUID (), time , std :: move ( scriptResult )));
2018-04-23 20:33:14 +02:00
else
2024-04-06 20:50:59 +02:00
Add ( new FleeingMovementGenerator ( enemy -> GetGUID (), std :: move ( scriptResult )));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2023-03-02 23:24:42 +01:00
void MotionMaster :: MovePoint ( uint32 id , Position const & pos , bool generatePath /* = true*/ , Optional < float > finalOrient /* = {}*/ , Optional < float > speed /*= {}*/ ,
2024-04-06 20:50:59 +02:00
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ , Optional < float > closeEnoughDistance /*= {}*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2018-04-19 13:31:39 +02:00
{
2024-04-06 20:50:59 +02:00
MovePoint ( id , pos . m_positionX , pos . m_positionY , pos . m_positionZ , generatePath , finalOrient , speed , speedSelectionMode , closeEnoughDistance , std :: move ( scriptResult ));
2018-04-19 13:31:39 +02:00
}
2023-03-02 23:24:42 +01:00
void MotionMaster :: MovePoint ( uint32 id , float x , float y , float z , bool generatePath /*= true*/ , Optional < float > finalOrient /*= {}*/ , Optional < float > speed /*= {}*/ ,
2024-04-06 20:50:59 +02:00
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ , Optional < float > closeEnoughDistance /*= {}*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2008-10-11 14:16:25 -05:00
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MovePoint: '{}', targeted point Id: {} (X: {}, Y: {}, Z: {})" , _owner -> GetGUID (), id , x , y , z );
2024-04-06 20:50:59 +02:00
Add ( new PointMovementGenerator ( id , x , y , z , generatePath , speed , finalOrient , nullptr , nullptr , speedSelectionMode , closeEnoughDistance , std :: move ( scriptResult )));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2016-04-11 16:52:23 +02:00
void MotionMaster :: MoveCloserAndStop ( uint32 id , Unit * target , float distance )
{
float distanceToTravel = _owner -> GetExactDist2d ( target ) - distance ;
if ( distanceToTravel > 0.0f )
{
2018-04-01 13:52:36 +02:00
float angle = _owner -> GetAbsoluteAngle ( target );
2016-04-11 16:52:23 +02:00
float destx = _owner -> GetPositionX () + distanceToTravel * std :: cos ( angle );
float desty = _owner -> GetPositionY () + distanceToTravel * std :: sin ( angle );
MovePoint ( id , destx , desty , target -> GetPositionZ ());
}
2016-04-16 12:19:23 +02:00
else
2016-04-11 16:52:23 +02:00
{
2018-06-03 10:06:57 -07:00
// We are already close enough. We just need to turn toward the target without changing position.
2023-01-01 00:26:53 +01:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , this , target = target -> GetGUID ()]( Movement :: MoveSplineInit & init )
2022-04-03 22:36:49 +02:00
{
init . MoveTo ( _owner -> GetPositionX (), _owner -> GetPositionY (), _owner -> GetPositionZ ());
if ( Unit const * refreshedTarget = ObjectAccessor :: GetUnit ( * _owner , target ))
init . SetFacing ( refreshedTarget );
};
Add ( new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , id ));
2016-04-11 16:52:23 +02:00
}
}
2023-03-26 12:22:41 +02:00
void MotionMaster :: MoveLand ( uint32 id , Position const & pos , Optional < int32 > tierTransitionId /*= {}*/ , Optional < float > velocity /*= {}*/ ,
2024-04-06 20:50:59 +02:00
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2011-07-27 12:40:14 +02:00
{
2025-11-11 23:45:06 +01:00
MoveTierTransition ( id , pos , AnimTier :: Ground , tierTransitionId , velocity , speedSelectionMode , std :: move ( scriptResult ));
}
2011-07-27 12:40:14 +02:00
2025-11-11 23:45:06 +01:00
void MotionMaster :: MoveTakeoff ( uint32 id , Position const & pos , Optional < int32 > tierTransitionId /*= {}*/ , Optional < float > velocity /*= {}*/ ,
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
{
MoveTierTransition ( id , pos , AnimTier :: Fly , tierTransitionId , velocity , speedSelectionMode , std :: move ( scriptResult ));
}
void MotionMaster :: MoveTierTransition ( uint32 id , Position const & pos , AnimTier newAnimTier , Optional < int32 > tierTransitionId /*= {}*/ , Optional < float > velocity /*= {}*/ ,
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
{
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveTierTransition: '{}', anim tier transition to {} Id: {} (X: {}, Y: {}, Z: {})" ,
_owner -> GetGUID (), newAnimTier , id , pos . GetPositionX (), pos . GetPositionY (), pos . GetPositionZ ());
bool flyingTransition = newAnimTier == AnimTier :: Fly || _owner -> GetAnimTier () == AnimTier :: Fly ;
if ( ! tierTransitionId )
2022-04-03 22:36:49 +02:00
{
2025-11-11 23:45:06 +01:00
switch ( newAnimTier )
2023-03-26 12:22:41 +02:00
{
2025-11-11 23:45:06 +01:00
case AnimTier :: Ground :
tierTransitionId = 208 ;
2023-03-26 12:22:41 +02:00
break ;
2025-11-11 23:45:06 +01:00
case AnimTier :: Swim :
tierTransitionId = 149 ;
break ;
case AnimTier :: Hover :
tierTransitionId = 25 ;
break ;
case AnimTier :: Fly :
tierTransitionId = 17 ;
2023-03-26 12:22:41 +02:00
break ;
default :
break ;
}
2025-11-11 23:45:06 +01:00
}
2011-07-27 12:40:14 +02:00
2025-11-11 23:45:06 +01:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , tierTransitionId = tierTransitionId . value_or ( 0 )]( Movement :: MoveSplineInit & init )
2022-04-03 22:36:49 +02:00
{
init . MoveTo ( PositionToVector3 ( pos ), false );
2025-11-11 23:45:06 +01:00
init . SetAnimation ( newAnimTier , tierTransitionId );
if ( flyingTransition )
init . SetFly (); // ensure smooth animation even if gravity is disabled after/enabled before calling this function
init . SetSmooth ();
2023-03-26 12:22:41 +02:00
switch ( speedSelectionMode )
{
case MovementWalkRunSpeedSelectionMode :: ForceRun :
init . SetWalk ( false );
break ;
case MovementWalkRunSpeedSelectionMode :: ForceWalk :
init . SetWalk ( true );
break ;
case MovementWalkRunSpeedSelectionMode :: Default :
default :
break ;
}
2022-04-03 22:36:49 +02:00
if ( velocity )
init . SetVelocity ( * velocity );
};
2025-11-11 23:45:06 +01:00
2024-04-06 20:50:59 +02:00
Add ( new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , id , { . ScriptResult = std :: move ( scriptResult ) }));
2011-07-27 12:40:14 +02:00
}
2016-11-23 02:28:40 +01:00
void MotionMaster :: 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*/ )
{
2018-06-03 10:06:57 -07:00
/*
2016-11-23 02:28:40 +01:00
if (_slot[MOTION_SLOT_CONTROLLED] && _slot[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
2018-06-03 10:06:57 -07:00
*/
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveCharge: '{}', charging point Id: {} (X: {}, Y: {}, Z: {})" , _owner -> GetGUID (), id , x , y , z );
2023-03-02 23:24:42 +01:00
PointMovementGenerator * movement = new PointMovementGenerator ( id , x , y , z , generatePath , speed , {}, target , spellEffectExtraData );
movement -> Priority = MOTION_PRIORITY_HIGHEST ;
movement -> BaseUnitState = UNIT_STATE_CHARGING ;
Add ( movement );
2016-11-23 02:28:40 +01:00
}
void MotionMaster :: MoveCharge ( PathGenerator const & path , float speed /*= SPEED_CHARGE*/ , Unit const * target /*= nullptr*/ ,
Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ )
{
G3D :: Vector3 dest = path . GetActualEndPosition ();
MoveCharge ( dest . x , dest . y , dest . z , speed , EVENT_CHARGE_PREPATH );
2023-04-21 19:05:38 +02:00
// If this is ever changed to not happen immediately then all spell effect handlers that use this must be updated
2016-11-23 02:28:40 +01:00
// Charge movement is not started when using EVENT_CHARGE_PREPATH
Movement :: MoveSplineInit init ( _owner );
init . MovebyPath ( path . GetPath ());
init . SetVelocity ( speed );
if ( target )
init . SetFacing ( target );
if ( spellEffectExtraData )
init . SetSpellEffectExtraData ( * spellEffectExtraData );
init . Launch ();
}
2021-11-06 23:17:43 +01:00
void MotionMaster :: MoveKnockbackFrom ( Position const & origin , float speedXY , float speedZ , Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ )
2009-03-23 15:26:13 -06:00
{
2018-06-03 10:06:57 -07:00
// This function may make players fall below map
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2009-03-23 15:26:13 -06:00
return ;
2009-10-17 15:51:44 -07:00
2025-11-17 16:18:04 +01:00
if ( std :: abs ( speedXY ) < 0.01f && std :: abs ( speedZ ) < 0.01f )
2014-01-28 22:40:13 +01:00
return ;
2020-04-17 21:13:18 +02:00
Position dest = _owner -> GetPosition ();
2025-11-16 20:25:56 +01:00
float o = dest == origin ? 0.0f : _owner -> GetRelativeAngle ( origin ) + float ( M_PI );
if ( speedXY < 0 )
{
speedXY = - speedXY ;
o = o - float ( M_PI );
}
if ( speedZ < 0 )
speedZ = - speedZ ; // doesn't seem to be supported on official servers - packet sent for knockback with positive and negative speed has the same flags and JumpGravity
2012-01-14 15:34:41 +01:00
float moveTimeHalf = speedZ / Movement :: gravity ;
float dist = 2 * moveTimeHalf * speedXY ;
2013-01-14 09:50:59 +01:00
float max_height = - Movement :: computeFallElevation ( moveTimeHalf , false , - speedZ );
2012-01-14 15:34:41 +01:00
2025-11-17 16:18:04 +01:00
boost :: container :: static_vector < G3D :: Vector3 , 3 > path ;
path . push_back ( PositionToVector3 ( dest ));
if ( dist > 0.01f )
{
// Use a mmap raycast to get a valid destination.
_owner -> MovePositionToFirstCollision ( dest , dist , o );
path . push_back ( PositionToVector3 ( dest ));
}
else
{
// vertical knockbacks get a fake 0.5 higher additional point to avoid clientside spline length checks
// sniffs confirmed that it is always 0.5, no matter what the max height is
path . push_back ( PositionToVector3 ( dest . GetPositionWithOffset ({ 0.0f , 0.0f , 0.5f })));
path . push_back ( PositionToVector3 ( dest ));
}
2012-07-28 17:07:05 +02:00
2022-04-03 22:36:49 +02:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , effect = ( spellEffectExtraData ? Optional < Movement :: SpellEffectExtraData > ( * spellEffectExtraData ) : Optional < Movement :: SpellEffectExtraData > ())]( Movement :: MoveSplineInit & init )
{
2025-11-17 16:37:01 +01:00
init . MovebyPath ({ path . data (), path . size () });
2022-04-03 22:36:49 +02:00
init . SetParabolic ( max_height , 0 );
init . SetOrientationFixed ( true );
2025-11-17 16:18:04 +01:00
init . SetVelocity ( speedXY );
2022-04-03 22:36:49 +02:00
if ( effect )
init . SetSpellEffectExtraData ( * effect );
};
2017-02-18 21:55:28 +01:00
2022-04-03 22:36:49 +02:00
GenericMovementGenerator * movement = new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , 0 );
2018-06-03 10:06:57 -07:00
movement -> Priority = MOTION_PRIORITY_HIGHEST ;
2021-06-06 17:51:00 +02:00
movement -> AddFlag ( MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH );
2018-06-03 10:06:57 -07:00
Add ( movement );
2009-03-23 15:26:13 -06:00
}
2009-10-17 15:51:44 -07:00
2009-04-11 22:41:15 -05:00
void MotionMaster :: MoveJumpTo ( float angle , float speedXY , float speedZ )
{
2018-06-03 10:06:57 -07:00
// This function may make players fall below map
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2009-04-11 22:41:15 -05:00
return ;
2009-10-17 15:51:44 -07:00
2018-04-23 20:33:14 +02:00
float x , y , z = _owner -> GetPositionZ ();
2012-01-14 15:34:41 +01:00
float moveTimeHalf = speedZ / Movement :: gravity ;
float dist = 2 * moveTimeHalf * speedXY ;
2018-04-23 20:33:14 +02:00
2018-04-01 18:27:29 +02:00
_owner -> GetNearPoint2D ( nullptr , x , y , dist , _owner -> GetOrientation () + angle );
2017-12-14 16:56:30 +01:00
_owner -> UpdateAllowedPositionZ ( x , y , z );
2018-04-23 20:33:14 +02:00
2025-11-18 00:32:06 +01:00
MoveJump ({ x , y , z }, speedXY , speedZ );
2009-04-11 22:41:15 -05:00
}
2009-10-17 15:51:44 -07:00
2024-06-29 18:15:43 +02:00
void MotionMaster :: MoveJump ( Position const & pos , float speedXY , float speedZ , uint32 id /*= EVENT_JUMP*/ , MovementFacingTarget const & facing /*= {}*/ ,
bool orientationFixed /*= false*/ , JumpArrivalCastArgs const * arrivalCast /*= nullptr*/ , Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ ,
2024-04-06 20:50:59 +02:00
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2018-04-19 13:31:39 +02:00
{
2025-11-18 00:32:06 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveJump: '{}', jumps to point Id: {} ({})" , _owner -> GetGUID (), id , pos . ToString ());
2017-02-28 15:18:09 -03:00
if ( speedXY < 0.01f )
2024-04-06 20:50:59 +02:00
{
if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2014-01-28 22:40:13 +01:00
return ;
2024-04-06 20:50:59 +02:00
}
2009-10-17 15:51:44 -07:00
2012-01-14 15:34:41 +01:00
float moveTimeHalf = speedZ / Movement :: gravity ;
2013-01-14 09:50:59 +01:00
float max_height = - Movement :: computeFallElevation ( moveTimeHalf , false , - speedZ );
2010-08-25 18:24:40 +03:00
2022-04-03 22:36:49 +02:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , effect = ( spellEffectExtraData ? Optional < Movement :: SpellEffectExtraData > ( * spellEffectExtraData ) : Optional < Movement :: SpellEffectExtraData > ())]( Movement :: MoveSplineInit & init )
{
2025-11-18 00:32:06 +01:00
init . MoveTo ( pos . GetPositionX (), pos . GetPositionY (), pos . GetPositionZ (), false );
2022-04-03 22:36:49 +02:00
init . SetParabolic ( max_height , 0 );
init . SetVelocity ( speedXY );
2024-06-21 15:35:12 +02:00
std :: visit ( Movement :: MoveSplineInitFacingVisitor ( init ), facing );
2024-06-29 18:15:43 +02:00
init . SetJumpOrientationFixed ( orientationFixed );
2022-04-03 22:36:49 +02:00
if ( effect )
init . SetSpellEffectExtraData ( * effect );
};
2017-02-18 21:55:28 +01:00
uint32 arrivalSpellId = 0 ;
ObjectGuid arrivalSpellTargetGuid ;
if ( arrivalCast )
{
arrivalSpellId = arrivalCast -> SpellId ;
arrivalSpellTargetGuid = arrivalCast -> Target ;
}
2024-02-18 15:19:35 +01:00
GenericMovementGenerator * movement = new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , id ,
2024-04-06 20:50:59 +02:00
{ . ArrivalSpellId = arrivalSpellId , . ArrivalSpellTarget = arrivalSpellTargetGuid , . ScriptResult = std :: move ( scriptResult ) });
2018-06-03 10:06:57 -07:00
movement -> Priority = MOTION_PRIORITY_HIGHEST ;
movement -> BaseUnitState = UNIT_STATE_JUMPING ;
Add ( movement );
2012-01-14 15:34:41 +01:00
}
2024-06-21 15:35:12 +02:00
void MotionMaster :: MoveJumpWithGravity ( Position const & pos , float speedXY , float gravity , uint32 id /* = EVENT_JUMP*/ , MovementFacingTarget const & facing /* = {}*/ ,
2024-06-29 18:15:43 +02:00
bool orientationFixed /*= false*/ , JumpArrivalCastArgs const * arrivalCast /*= nullptr*/ , Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ ,
2024-04-06 20:50:59 +02:00
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2021-11-27 21:56:00 +01:00
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveJumpWithGravity: '{}', jumps to point Id: {} ({})" , _owner -> GetGUID (), id , pos . ToString ());
2021-11-27 21:56:00 +01:00
if ( speedXY < 0.01f )
2024-04-06 20:50:59 +02:00
{
if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2021-11-27 21:56:00 +01:00
return ;
2024-04-06 20:50:59 +02:00
}
2021-11-27 21:56:00 +01:00
2022-04-03 22:36:49 +02:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , effect = ( spellEffectExtraData ? Optional < Movement :: SpellEffectExtraData > ( * spellEffectExtraData ) : Optional < Movement :: SpellEffectExtraData > ())]( Movement :: MoveSplineInit & init )
{
init . MoveTo ( pos . GetPositionX (), pos . GetPositionY (), pos . GetPositionZ (), false );
init . SetParabolicVerticalAcceleration ( gravity , 0 );
init . SetUncompressed ();
init . SetVelocity ( speedXY );
2022-07-24 22:20:35 +02:00
init . SetUnlimitedSpeed ();
2024-06-21 15:35:12 +02:00
std :: visit ( Movement :: MoveSplineInitFacingVisitor ( init ), facing );
2024-06-29 18:15:43 +02:00
init . SetJumpOrientationFixed ( orientationFixed );
2022-04-03 22:36:49 +02:00
if ( effect )
init . SetSpellEffectExtraData ( * effect );
};
2021-11-27 21:56:00 +01:00
uint32 arrivalSpellId = 0 ;
ObjectGuid arrivalSpellTargetGuid ;
if ( arrivalCast )
{
arrivalSpellId = arrivalCast -> SpellId ;
arrivalSpellTargetGuid = arrivalCast -> Target ;
}
2024-02-18 15:19:35 +01:00
GenericMovementGenerator * movement = new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , id ,
2024-04-06 20:50:59 +02:00
{ . ArrivalSpellId = arrivalSpellId , . ArrivalSpellTarget = arrivalSpellTargetGuid , . ScriptResult = std :: move ( scriptResult ) });
2021-11-27 21:56:00 +01:00
movement -> Priority = MOTION_PRIORITY_HIGHEST ;
movement -> BaseUnitState = UNIT_STATE_JUMPING ;
2021-06-06 17:51:00 +02:00
movement -> AddFlag ( MOVEMENTGENERATOR_FLAG_PERSIST_ON_DEATH );
2021-11-27 21:56:00 +01:00
Add ( movement );
}
2024-02-18 15:19:35 +01:00
void MotionMaster :: MoveCirclePath ( float x , float y , float z , float radius , bool clockwise , uint8 stepCount ,
Optional < Milliseconds > duration /*= {}*/ , Optional < float > speed /*= {}*/ ,
2024-04-06 20:50:59 +02:00
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2015-03-15 21:32:35 +01:00
{
2023-01-01 00:26:53 +01:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ = , this ]( Movement :: MoveSplineInit & init )
2022-04-03 22:36:49 +02:00
{
float step = 2 * float ( M_PI ) / stepCount * ( clockwise ? - 1.0f : 1.0f );
Position const & pos = { x , y , z , 0.0f };
float angle = pos . GetAbsoluteAngle ( _owner -> GetPositionX (), _owner -> GetPositionY ());
2015-03-15 21:32:35 +01:00
2025-06-17 23:09:08 +02:00
init . Path (). reserve ( stepCount + 1 );
2022-04-03 22:36:49 +02:00
// add the owner's current position as starting point as it gets removed after entering the cycle
2024-02-18 15:19:35 +01:00
init . Path (). emplace_back ( _owner -> GetPositionX (), _owner -> GetPositionY (), _owner -> GetPositionZ ());
2022-04-03 22:36:49 +02:00
for ( uint8 i = 0 ; i < stepCount ; angle += step , ++ i )
{
2024-02-18 15:19:35 +01:00
G3D :: Vector3 & point = init . Path (). emplace_back ();
2022-04-03 22:36:49 +02:00
point . x = x + radius * cosf ( angle );
point . y = y + radius * sinf ( angle );
2015-03-15 21:32:35 +01:00
2022-04-03 22:36:49 +02:00
if ( _owner -> IsFlying ())
point . z = z ;
else
point . z = _owner -> GetMapHeight ( point . x , point . y , z ) + _owner -> GetHoverOffset ();
}
2015-03-15 21:32:35 +01:00
2024-02-18 15:19:35 +01:00
init . SetCyclic ();
2015-03-15 21:32:35 +01:00
if ( _owner -> IsFlying ())
2022-04-03 22:36:49 +02:00
{
init . SetFly ();
init . SetAnimation ( AnimTier :: Hover );
}
2015-03-15 21:32:35 +01:00
else
2022-04-03 22:36:49 +02:00
init . SetWalk ( true );
2024-02-18 15:19:35 +01:00
switch ( speedSelectionMode )
{
case MovementWalkRunSpeedSelectionMode :: ForceRun :
init . SetWalk ( false );
break ;
case MovementWalkRunSpeedSelectionMode :: ForceWalk :
init . SetWalk ( true );
break ;
case MovementWalkRunSpeedSelectionMode :: Default :
default :
break ;
2022-04-03 22:36:49 +02:00
}
2024-02-18 15:19:35 +01:00
if ( speed )
init . SetVelocity ( * speed );
2022-04-03 22:36:49 +02:00
};
2015-03-15 21:32:35 +01:00
2024-04-06 20:50:59 +02:00
Add ( new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , 0 , { . Duration = duration , . ScriptResult = std :: move ( scriptResult ) }));
2015-03-15 21:32:35 +01:00
}
2016-09-20 20:19:15 +02:00
void MotionMaster :: MoveAlongSplineChain ( uint32 pointId , uint16 dbChainId , bool walk )
2016-09-14 23:53:37 +02:00
{
Creature * owner = _owner -> ToCreature ();
if ( ! owner )
{
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along DB spline chain. Ignoring." , _owner -> GetGUID ());
2016-09-14 23:53:37 +02:00
return ;
}
2017-06-04 01:00:45 +02:00
std :: vector < SplineChainLink > const * chain = sScriptSystemMgr -> GetSplineChain ( owner , dbChainId );
2016-09-14 23:53:37 +02:00
if ( ! chain )
{
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveAlongSplineChain: '{}', tried to walk along non-existing spline chain with DB Id: {}." , _owner -> GetGUID (), dbChainId );
2016-09-14 23:53:37 +02:00
return ;
}
MoveAlongSplineChain ( pointId , * chain , walk );
}
2017-05-20 00:09:37 +02:00
void MotionMaster :: MoveAlongSplineChain ( uint32 pointId , std :: vector < SplineChainLink > const & chain , bool walk )
2016-09-14 23:53:37 +02:00
{
2018-06-03 10:06:57 -07:00
Add ( new SplineChainMovementGenerator ( pointId , chain , walk ));
2016-09-14 23:53:37 +02:00
}
void MotionMaster :: ResumeSplineChain ( SplineChainResumeInfo const & info )
{
2016-09-21 16:22:12 +02:00
if ( info . Empty ())
{
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::ResumeSplineChain: '{}', tried to resume a spline chain from empty info." , _owner -> GetGUID ());
2016-09-21 16:22:12 +02:00
return ;
}
2018-06-03 10:06:57 -07:00
Add ( new SplineChainMovementGenerator ( info ));
2016-09-14 23:53:37 +02:00
}
2024-04-06 20:50:59 +02:00
void MotionMaster :: MoveFall ( uint32 id /*= 0*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2012-01-14 15:34:41 +01:00
{
2024-04-06 20:50:59 +02:00
auto setterScopeExit = Trinity :: make_unique_ptr_with_deleter ( & scriptResult , []( Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>* opt )
{
if ( opt -> has_value ())
( * opt ) -> SetResult ( MovementStopReason :: Interrupted );
});
2018-06-03 10:06:57 -07:00
// Use larger distance for vmap height search than in most other cases
2017-12-29 22:32:07 +01:00
float tz = _owner -> GetMapHeight ( _owner -> GetPositionX (), _owner -> GetPositionY (), _owner -> GetPositionZ (), true , MAX_FALL_DISTANCE );
2012-01-14 15:34:41 +01:00
if ( tz <= INVALID_HEIGHT )
2009-03-23 15:26:13 -06:00
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveFall: '{}', unable to retrieve a proper height at map Id: {} (X: {}, Y: {}, Z: {})" ,
2024-12-31 18:12:36 +01:00
_owner -> GetGUID (), _owner -> GetMapId (), _owner -> GetPositionX (), _owner -> GetPositionY (), _owner -> GetPositionZ ());
2012-01-14 15:34:41 +01:00
return ;
2009-03-23 15:26:13 -06:00
}
2009-10-17 15:51:44 -07:00
2012-01-14 15:34:41 +01:00
// Abort too if the ground is very near
2014-08-21 16:56:11 +02:00
if ( std :: fabs ( _owner -> GetPositionZ () - tz ) < 0.1f )
2012-01-14 15:34:41 +01:00
return ;
2019-05-10 23:30:50 +02:00
// rooted units don't move (also setting falling+root flag causes client freezes)
2019-12-27 16:33:16 +01:00
if ( _owner -> HasUnitState ( UNIT_STATE_ROOT | UNIT_STATE_STUNNED ))
2019-05-10 23:30:50 +02:00
return ;
2016-04-13 20:47:57 +02:00
_owner -> SetFall ( true );
2018-06-03 10:06:57 -07:00
// Don't run spline movement for players
2012-04-08 12:17:43 +02:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2017-02-13 21:05:32 +01:00
{
_owner -> ToPlayer () -> SetFallInformation ( 0 , _owner -> GetPositionZ ());
2016-04-13 20:47:57 +02:00
return ;
2017-02-13 21:05:32 +01:00
}
2012-04-08 12:17:43 +02:00
2024-04-06 20:50:59 +02:00
std :: function < void ( Movement :: MoveSplineInit & ) > initializer = [ this , tz ]( Movement :: MoveSplineInit & init )
2022-04-03 22:36:49 +02:00
{
init . MoveTo ( _owner -> GetPositionX (), _owner -> GetPositionY (), tz + _owner -> GetHoverOffset (), false );
init . SetFall ();
};
2018-06-03 10:06:57 -07:00
2024-04-06 20:50:59 +02:00
GenericMovementGenerator * movement = new GenericMovementGenerator ( std :: move ( initializer ), EFFECT_MOTION_TYPE , id , { . ScriptResult = std :: move ( * setterScopeExit . release ()) });
2018-06-03 10:06:57 -07:00
movement -> Priority = MOTION_PRIORITY_HIGHEST ;
Add ( movement );
2009-03-23 15:26:13 -06:00
}
2009-10-17 15:51:44 -07:00
2011-07-27 12:40:14 +02:00
void MotionMaster :: MoveSeekAssistance ( float x , float y , float z )
2009-05-21 10:48:00 -05:00
{
2020-01-01 16:28:33 +01:00
if ( Creature * creature = _owner -> ToCreature ())
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveSeekAssistance: '{}', seeks assistance (X: {}, Y: {}, Z: {})" , creature -> GetGUID (), x , y , z );
2020-01-01 16:28:33 +01:00
creature -> AttackStop ();
creature -> CastStop ();
creature -> DoNotReacquireSpellFocusTarget ();
creature -> SetReactState ( REACT_PASSIVE );
Add ( new AssistanceMovementGenerator ( EVENT_ASSIST_MOVE , x , y , z ));
2009-05-21 10:48:00 -05:00
}
2018-04-23 20:33:14 +02:00
else
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveSeekAssistance: '{}', attempted to seek assistance." , _owner -> GetGUID ());
2009-05-21 10:48:00 -05:00
}
2009-10-17 15:51:44 -07:00
2011-07-27 12:40:14 +02:00
void MotionMaster :: MoveSeekAssistanceDistract ( uint32 time )
2009-05-21 10:48:00 -05:00
{
2018-04-23 20:33:14 +02:00
if ( _owner -> GetTypeId () == TYPEID_UNIT )
2009-05-21 10:48:00 -05:00
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveSeekAssistanceDistract: '{}', is distracted after assistance call (Time: {})" , _owner -> GetGUID (), time );
2018-06-03 10:06:57 -07:00
Add ( new AssistanceDistractMovementGenerator ( time , _owner -> GetOrientation ()));
2009-05-21 10:48:00 -05:00
}
2018-04-23 20:33:14 +02:00
else
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveSeekAssistanceDistract: '{}', attempted to call distract assistance." , _owner -> GetGUID ());
2009-05-21 10:48:00 -05:00
}
2009-10-17 15:51:44 -07:00
2024-04-06 20:50:59 +02:00
void MotionMaster :: MoveTaxiFlight ( uint32 path , uint32 pathnode , Optional < float > speed /*= {}*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2008-10-11 14:16:25 -05:00
{
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2010-06-23 00:57:16 +02:00
if ( path < sTaxiPathNodesByPath . size ())
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveTaxiFlight: '{}', taxi to path Id: {} (node {})" , _owner -> GetGUID (), path , pathnode );
2018-06-03 10:06:57 -07:00
// Only one FLIGHT_MOTION_TYPE is allowed
2018-10-02 19:53:55 +02:00
bool hasExisting = HasMovementGenerator ([]( MovementGenerator const * gen ) { return gen -> GetMovementGeneratorType () == FLIGHT_MOTION_TYPE ; });
ASSERT ( ! hasExisting , "Duplicate flight path movement generator" );
2018-06-03 10:06:57 -07:00
2024-04-06 20:50:59 +02:00
FlightPathMovementGenerator * movement = new FlightPathMovementGenerator ( speed , std :: move ( scriptResult ));
2018-04-23 20:33:14 +02:00
movement -> LoadPath ( _owner -> ToPlayer (), pathnode );
2018-06-03 10:06:57 -07:00
Add ( movement );
2010-06-23 00:57:16 +02:00
}
else
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to non-existing path Id: {} (node: {})", _owner->GetGUID(), path, pathnode) ;
2008-10-11 14:16:25 -05:00
}
else
2024-03-31 19:32:39 +02:00
TC_LOG_ERROR ( "movement.motionmaster" , "MotionMaster::MoveTaxiFlight: '{}', attempted taxi to path Id: {} (node: {})", _owner->GetGUID(), path, pathnode) ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: MoveDistract ( uint32 timer , float orientation )
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
/*
2016-11-23 02:28:40 +01:00
if (_slot[MOTION_SLOT_CONTROLLED])
2009-01-17 00:00:48 -06:00
return;
2018-06-03 10:06:57 -07:00
*/
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveDistract: '{}', distracted (timer: {}, orientation: {})" , _owner -> GetGUID (), timer , orientation );
2018-06-03 10:06:57 -07:00
Add ( new DistractMovementGenerator ( timer , orientation ));
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2024-04-06 20:50:59 +02:00
void MotionMaster :: MovePath ( uint32 pathId , bool repeatable , Optional < Milliseconds > duration /*= {}*/ , Optional < float > speed /*= {}*/ ,
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < std :: pair < Milliseconds , Milliseconds >> waitTimeRangeAtPathEnd /*= {}*/ ,
2024-04-21 00:16:57 +02:00
Optional < float > wanderDistanceAtPathEnds /*= {}*/ , Optional < bool > followPathBackwardsFromEndToStart /*= {}*/ ,
Optional < bool > exactSplinePath /*= {}*/ , bool generatePath /*= true*/ ,
2024-04-06 20:50:59 +02:00
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2016-11-23 02:28:40 +01:00
{
2017-08-12 01:40:25 +02:00
if ( ! pathId )
2024-04-06 20:50:59 +02:00
{
if ( scriptResult )
scriptResult -> SetResult ( MovementStopReason :: Interrupted );
2016-11-23 02:28:40 +01:00
return ;
2024-04-06 20:50:59 +02:00
}
2016-11-23 02:28:40 +01:00
2023-03-07 20:13:28 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})" ,
2024-03-31 19:32:39 +02:00
_owner -> GetGUID (), pathId , repeatable ? "YES" : "NO" );
2023-03-07 20:13:28 +01:00
Add ( new WaypointMovementGenerator < Creature > ( pathId , repeatable , duration , speed , speedSelectionMode , waitTimeRangeAtPathEnd ,
2024-04-21 00:16:57 +02:00
wanderDistanceAtPathEnds , followPathBackwardsFromEndToStart , exactSplinePath , generatePath , std :: move ( scriptResult )), MOTION_SLOT_DEFAULT );
2017-08-12 01:40:25 +02:00
}
2024-04-06 20:50:59 +02:00
void MotionMaster :: MovePath ( WaypointPath const & path , bool repeatable , Optional < Milliseconds > duration /*= {}*/ , Optional < float > speed /*= {}*/ ,
MovementWalkRunSpeedSelectionMode speedSelectionMode /*= MovementWalkRunSpeedSelectionMode::Default*/ ,
Optional < std :: pair < Milliseconds , Milliseconds >> waitTimeRangeAtPathEnd /*= {}*/ ,
2024-04-21 00:16:57 +02:00
Optional < float > wanderDistanceAtPathEnds /*= {}*/ , Optional < bool > followPathBackwardsFromEndToStart /*= {}*/ ,
Optional < bool > exactSplinePath /*= {}*/ , bool generatePath /*= true*/ ,
2024-04-06 20:50:59 +02:00
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2017-08-12 01:40:25 +02:00
{
2023-03-07 20:13:28 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})" ,
2024-03-31 19:32:39 +02:00
_owner -> GetGUID (), path . Id , repeatable ? "YES" : "NO" );
2023-03-07 20:13:28 +01:00
Add ( new WaypointMovementGenerator < Creature > ( path , repeatable , duration , speed , speedSelectionMode , waitTimeRangeAtPathEnd ,
2024-04-21 00:16:57 +02:00
wanderDistanceAtPathEnds , followPathBackwardsFromEndToStart , exactSplinePath , generatePath , std :: move ( scriptResult )), MOTION_SLOT_DEFAULT );
2016-11-23 02:28:40 +01:00
}
2024-02-28 21:10:05 +01:00
void MotionMaster :: MoveRotate ( uint32 id , RotateDirection direction , Optional < Milliseconds > time /*= {}*/ ,
2024-04-06 20:50:59 +02:00
Optional < float > turnSpeed /*= {}*/ , Optional < float > totalTurnAngle /*= {}*/ ,
Optional < Scripting :: v2 :: ActionResultSetter < MovementStopReason >>&& scriptResult /*= {}*/ )
2016-11-23 02:28:40 +01:00
{
2024-02-28 21:10:05 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveRotate: '{}', starts rotate (time: {}ms, turnSpeed: {}, totalTurnAngle: {}, direction: {})" ,
2024-03-31 19:32:39 +02:00
_owner -> GetGUID (), time . value_or ( 0 ms ). count (), turnSpeed , totalTurnAngle , direction );
2016-11-23 02:28:40 +01:00
2024-04-06 20:50:59 +02:00
Add ( new RotateMovementGenerator ( id , direction , time , turnSpeed , totalTurnAngle , std :: move ( scriptResult )));
2016-11-23 02:28:40 +01:00
}
2020-04-04 15:08:42 +02:00
void MotionMaster :: MoveFormation ( Unit * leader , float range , float angle , uint32 point1 , uint32 point2 )
2017-04-09 14:13:29 +02:00
{
2020-04-04 15:08:42 +02:00
if ( _owner -> GetTypeId () == TYPEID_UNIT && leader )
2017-04-09 14:13:29 +02:00
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::MoveFormation: '{}', started to move in a formation with leader {}" , _owner -> GetGUID (), leader -> GetGUID ());
2020-04-04 15:08:42 +02:00
Add ( new FormationMovementGenerator ( leader , range , angle , point1 , point2 ), MOTION_SLOT_DEFAULT );
2017-04-09 14:13:29 +02:00
}
}
2022-04-03 22:36:49 +02:00
void MotionMaster :: LaunchMoveSpline ( std :: function < void ( Movement :: MoveSplineInit & init ) >&& initializer , uint32 id /*= 0*/ , MovementGeneratorPriority priority /* = MOTION_PRIORITY_NORMAL*/ , MovementGeneratorType type /*= EFFECT_MOTION_TYPE*/ )
2018-04-23 20:33:14 +02:00
{
if ( IsInvalidMovementGeneratorType ( type ))
{
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::LaunchMoveSpline: '{}', tried to launch a spline with an invalid MovementGeneratorType: {} (Id: {}, Priority: {})" , _owner -> GetGUID (), type , id , priority );
2018-04-23 20:33:14 +02:00
return ;
}
2024-03-31 19:32:39 +02:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::LaunchMoveSpline: '{}', initiates spline Id: {} (Type: {}, Priority: {})" , _owner -> GetGUID (), id , type , priority );
2018-06-03 10:06:57 -07:00
2022-04-03 22:36:49 +02:00
GenericMovementGenerator * movement = new GenericMovementGenerator ( std :: move ( initializer ), type , id );
2018-06-03 10:06:57 -07:00
movement -> Priority = priority ;
Add ( movement );
2018-04-23 20:33:14 +02:00
}
2023-03-06 00:14:42 +01:00
void MotionMaster :: CalculateJumpSpeeds ( float dist , UnitMoveType moveType , float speedMultiplier , float minHeight , float maxHeight , float & speedXY , float & speedZ ) const
{
float baseSpeed = _owner -> IsControlledByPlayer () ? playerBaseMoveSpeed [ moveType ] : baseMoveSpeed [ moveType ];
if ( Creature * creature = _owner -> ToCreature ())
baseSpeed *= creature -> GetCreatureTemplate () -> speed_run ;
speedXY = std :: min ( baseSpeed * 3.0f * speedMultiplier , std :: max ( 28.0f , _owner -> GetSpeed ( moveType ) * 4.0f ));
float duration = dist / speedXY ;
float durationSqr = duration * duration ;
float height ;
if ( durationSqr < minHeight * 8 / Movement :: gravity )
height = minHeight ;
else if ( durationSqr > maxHeight * 8 / Movement :: gravity )
height = maxHeight ;
else
height = Movement :: gravity * durationSqr / 8 ;
speedZ = std :: sqrt ( 2 * Movement :: gravity * height );
}
2016-11-23 02:28:40 +01:00
/******************** Private methods ********************/
2019-10-21 13:55:23 +02:00
void MotionMaster :: ResolveDelayedActions ()
{
while ( ! _delayedActions . empty ())
{
_delayedActions . front (). Resolve ();
_delayedActions . pop_front ();
}
}
2019-04-16 23:29:04 +02:00
void MotionMaster :: Remove ( MotionMasterContainer :: iterator iterator , bool active , bool movementInform )
2016-11-23 02:28:40 +01:00
{
2019-04-16 23:29:04 +02:00
MovementGenerator * pointer = * iterator ;
_generators . erase ( iterator );
2018-06-03 10:06:57 -07:00
Delete ( pointer , active , movementInform );
}
2019-04-16 23:29:04 +02:00
void MotionMaster :: Pop ( bool active , bool movementInform )
{
2020-04-08 14:15:49 +02:00
if ( ! _generators . empty ())
Remove ( _generators . begin (), active , movementInform );
2019-04-16 23:29:04 +02:00
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: DirectInitialize ()
{
// Clear ALL movement generators (including default)
DirectClearDefault ();
DirectClear ();
2016-11-23 02:28:40 +01:00
2018-06-03 10:06:57 -07:00
InitializeDefault ();
2016-11-23 02:28:40 +01:00
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: DirectClear ()
2016-11-23 02:28:40 +01:00
{
2018-06-03 10:06:57 -07:00
// First delete Top
if ( ! _generators . empty ())
Pop ( true , false );
// Then the rest
while ( ! _generators . empty ())
Pop ( false , false );
// Make sure the storage is empty
ClearBaseUnitStates ();
2016-11-23 02:28:40 +01:00
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: DirectClearDefault ()
2016-11-23 02:28:40 +01:00
{
2018-06-03 10:06:57 -07:00
if ( _defaultGenerator )
DeleteDefault ( _generators . empty (), false );
2016-11-23 02:28:40 +01:00
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: DirectClear ( std :: function < bool ( MovementGenerator * ) > const & filter )
2008-10-11 14:16:25 -05:00
{
2018-06-03 10:06:57 -07:00
if ( _generators . empty ())
return ;
MovementGenerator const * top = GetCurrentMovementGenerator ();
for ( auto itr = _generators . begin (); itr != _generators . end ();)
{
if ( filter ( * itr ))
{
MovementGenerator * movement = * itr ;
itr = _generators . erase ( itr );
Delete ( movement , movement == top , false );
}
else
++ itr ;
}
}
void MotionMaster :: DirectAdd ( MovementGenerator * movement , MovementSlot slot /* = MOTION_SLOT_ACTIVE*/ )
{
/*
2017-08-08 20:29:30 +02:00
if (MovementGenerator* curr = _slot[slot])
2009-01-16 22:57:03 -06:00
{
2016-11-23 02:28:40 +01:00
_slot[slot] = nullptr; // in case a new one is generated in this slot during directdelete
2018-04-19 13:31:39 +02:00
if (_top == slot && (_cleanFlag & MOTIONMMASTER_CLEANFLAG_UPDATE))
2009-02-08 22:56:57 -06:00
DelayedDelete(curr);
else
DirectDelete(curr);
2009-01-16 22:57:03 -06:00
}
2012-02-14 12:46:26 -05:00
else if (_top < slot)
2009-01-16 22:57:03 -06:00
{
2012-02-14 12:46:26 -05:00
_top = slot;
2009-01-16 22:57:03 -06:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
_slot[slot] = m;
2012-02-14 12:46:26 -05:00
if (_top > slot)
2016-11-23 02:28:40 +01:00
_initialize[slot] = true;
2009-03-04 10:16:15 -06:00
else
{
2016-11-23 02:28:40 +01:00
_initialize[slot] = false;
2012-08-25 22:57:55 -05:00
m->Initialize(_owner);
2009-03-04 10:16:15 -06:00
}
2018-06-03 10:06:57 -07:00
*/
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
/*
* NOTE: This mimics old behaviour: only one MOTION_SLOT_IDLE, MOTION_SLOT_ACTIVE, MOTION_SLOT_CONTROLLED
* On future changes support for multiple will be added
*/
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
switch ( slot )
2017-08-08 20:29:30 +02:00
{
2018-06-03 10:06:57 -07:00
case MOTION_SLOT_DEFAULT :
if ( _defaultGenerator )
_defaultGenerator -> Finalize ( _owner , _generators . empty (), false );
_defaultGenerator = MovementGeneratorPointer ( movement );
if ( IsStatic ( movement ))
AddFlag ( MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING );
break ;
case MOTION_SLOT_ACTIVE :
if ( ! _generators . empty ())
{
if ( movement -> Priority >= ( * _generators . begin ()) -> Priority )
{
2019-04-16 23:29:04 +02:00
auto itr = _generators . begin ();
if ( movement -> Priority == ( * itr ) -> Priority )
Remove ( itr , true , false );
2018-06-03 10:06:57 -07:00
else
2019-04-16 23:29:04 +02:00
( * itr ) -> Deactivate ( _owner );
2018-06-03 10:06:57 -07:00
}
else
{
auto itr = std :: find_if ( _generators . begin (), _generators . end (), [ movement ]( MovementGenerator const * a ) -> bool
{
return a -> Priority == movement -> Priority ;
});
if ( itr != _generators . end ())
2019-04-16 23:29:04 +02:00
Remove ( itr , false , false );
2018-06-03 10:06:57 -07:00
}
}
else
_defaultGenerator -> Deactivate ( _owner );
_generators . emplace ( movement );
AddBaseUnitState ( movement );
break ;
default :
break ;
2017-08-08 20:29:30 +02:00
}
}
2018-06-03 10:06:57 -07:00
void MotionMaster :: Delete ( MovementGenerator * movement , bool active , bool movementInform )
2008-10-11 14:16:25 -05:00
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::Delete: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'" ,
2024-03-31 19:32:39 +02:00
movement -> Priority , movement -> Flags , movement -> BaseUnitState , movement -> GetMovementGeneratorType (), _owner -> GetGUID ());
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
movement -> Finalize ( _owner , active , movementInform );
ClearBaseUnitState ( movement );
MovementGeneratorPointerDeleter ( movement );
2009-03-15 10:50:10 -06:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: DeleteDefault ( bool active , bool movementInform )
2009-03-04 10:16:15 -06:00
{
2023-01-08 21:16:53 +01:00
TC_LOG_DEBUG ( "movement.motionmaster" , "MotionMaster::DeleteDefault: deleting generator (Priority: {}, Flags: {}, BaseUnitState: {}, Type: {}), owner: '{}'" ,
2024-03-31 19:32:39 +02:00
_defaultGenerator -> Priority , _defaultGenerator -> Flags , _defaultGenerator -> BaseUnitState , _defaultGenerator -> GetMovementGeneratorType (), _owner -> GetGUID ());
2016-11-23 02:28:40 +01:00
2018-06-03 10:06:57 -07:00
_defaultGenerator -> Finalize ( _owner , active , movementInform );
_defaultGenerator = MovementGeneratorPointer ( GetIdleMovementGenerator ());
AddFlag ( MOTIONMASTER_FLAG_STATIC_INITIALIZATION_PENDING );
2009-03-04 10:16:15 -06:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: AddBaseUnitState ( MovementGenerator const * movement )
2009-02-08 22:56:57 -06:00
{
2018-06-03 10:06:57 -07:00
if ( ! movement || ! movement -> BaseUnitState )
2009-02-08 22:56:57 -06:00
return ;
2018-04-23 20:33:14 +02:00
2018-06-03 10:06:57 -07:00
_baseUnitStatesMap . emplace ( movement -> BaseUnitState , movement );
_owner -> AddUnitState ( movement -> BaseUnitState );
2009-02-08 22:56:57 -06:00
}
2009-10-17 15:51:44 -07:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: ClearBaseUnitState ( MovementGenerator const * movement )
2009-02-08 22:56:57 -06:00
{
2018-06-03 10:06:57 -07:00
if ( ! movement || ! movement -> BaseUnitState )
2009-02-08 22:56:57 -06:00
return ;
2017-03-25 12:33:39 +01:00
2018-06-03 10:06:57 -07:00
Trinity :: Containers :: MultimapErasePair ( _baseUnitStatesMap , movement -> BaseUnitState , movement );
if ( _baseUnitStatesMap . count ( movement -> BaseUnitState ) == 0 )
_owner -> ClearUnitState ( movement -> BaseUnitState );
2008-10-11 14:16:25 -05:00
}
2017-08-08 19:35:13 +02:00
2018-06-03 10:06:57 -07:00
void MotionMaster :: ClearBaseUnitStates ()
2017-08-08 19:35:13 +02:00
{
2018-06-03 10:06:57 -07:00
uint32 unitState = 0 ;
for ( auto itr = _baseUnitStatesMap . begin (); itr != _baseUnitStatesMap . end (); ++ itr )
unitState |= itr -> first ;
2017-08-08 19:35:13 +02:00
2018-06-03 10:06:57 -07:00
_owner -> ClearUnitState ( unitState );
_baseUnitStatesMap . clear ();
2017-08-08 19:35:13 +02:00
}