2010-10-07 15:35:36 +02:00
/*
2019-01-01 10:13:49 +01:00
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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"
#include "CreatureAISelector.h"
#include "Creature.h"
2016-09-14 23:53:37 +02:00
#include "ScriptSystem.h"
2017-05-12 18:49:51 +02:00
#include "Log.h"
2017-06-04 01:00:45 +02:00
#include "Map.h"
2008-10-11 14:16:25 -05:00
#include "ConfusedMovementGenerator.h"
#include "FleeingMovementGenerator.h"
#include "HomeMovementGenerator.h"
#include "IdleMovementGenerator.h"
#include "PointMovementGenerator.h"
#include "TargetedMovementGenerator.h"
#include "WaypointMovementGenerator.h"
2008-12-19 00:37:40 +02:00
#include "RandomMovementGenerator.h"
2016-09-14 23:53:37 +02:00
#include "SplineChainMovementGenerator.h"
2012-01-14 15:34:41 +01:00
#include "MoveSpline.h"
#include "MoveSplineInit.h"
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
inline bool IsStatic ( MovementGenerator * movement )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
return ( movement == & si_idleMovement );
}
MotionMaster ::~ MotionMaster ()
{
// clear ALL movement generators (including default)
while ( ! empty ())
{
MovementGenerator * curr = top ();
pop ();
if ( curr && ! IsStatic ( curr ))
delete curr ; // Skip finalizing on delete, it might launch new movement
}
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 :: Initialize ()
2008-10-11 14:16:25 -05:00
{
// clear ALL movement generators (including default)
2010-04-07 19:13:19 +02:00
while ( ! empty ())
2008-10-11 14:16:25 -05:00
{
MovementGenerator * curr = top ();
pop ();
2012-10-24 13:29:34 +02:00
if ( curr )
DirectDelete ( curr );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-03-21 10:11:29 -06:00
InitDefault ();
}
2009-10-17 15:51:44 -07:00
2009-03-21 10:11:29 -06:00
// set new default movement generator
void MotionMaster :: InitDefault ()
{
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_UNIT )
2008-10-11 14:16:25 -05:00
{
2012-02-14 12:46:26 -05:00
MovementGenerator * movement = FactorySelector :: selectMovementGenerator ( _owner -> ToCreature ());
2009-03-21 10:11:29 -06:00
Mutate ( movement == NULL ? & si_idleMovement : movement , MOTION_SLOT_IDLE );
2008-10-11 14:16:25 -05:00
}
else
2009-03-04 10:16:15 -06:00
{
2009-03-21 10:11:29 -06:00
Mutate ( & si_idleMovement , MOTION_SLOT_IDLE );
2009-03-04 10:16:15 -06:00
}
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 :: UpdateMotion ( 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 ;
2012-02-14 12:46:26 -05:00
if ( _owner -> HasUnitState ( UNIT_STATE_ROOT | UNIT_STATE_STUNNED )) // what about UNIT_STATE_DISTRACTED? Why is this not included?
2008-10-11 14:16:25 -05:00
return ;
2011-08-01 13:44:54 +02:00
2010-07-30 20:04:28 +02:00
ASSERT ( ! empty ());
2011-08-01 13:44:54 +02:00
2012-02-14 12:46:26 -05:00
_cleanFlag |= MMCF_UPDATE ;
2016-12-01 23:45:32 +01:00
bool isMoveGenUpdateSuccess = top () -> Update ( _owner , diff );
_cleanFlag &= ~ MMCF_UPDATE ;
if ( ! isMoveGenUpdateSuccess )
2008-10-11 14:16:25 -05:00
MovementExpired ();
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
if ( _expireList )
2016-12-01 23:45:32 +01:00
ClearExpireList ();
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 :: Clear ( bool reset /*= true*/ )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( _cleanFlag & MMCF_UPDATE )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( reset )
_cleanFlag |= MMCF_RESET ;
else
_cleanFlag &= ~ MMCF_RESET ;
DelayedClean ();
2008-10-11 14:16:25 -05:00
}
2016-11-23 02:28:40 +01:00
else
DirectClean ( reset );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2016-12-01 23:45:32 +01:00
void MotionMaster :: ClearExpireList ()
{
for ( size_t i = 0 ; i < _expireList -> size (); ++ i )
{
MovementGenerator * mg = ( * _expireList )[ i ];
DirectDelete ( mg );
}
delete _expireList ;
_expireList = nullptr ;
if ( empty ())
Initialize ();
else if ( NeedInitTop ())
InitTop ();
else if ( _cleanFlag & MMCF_RESET )
top () -> Reset ( _owner );
_cleanFlag &= ~ MMCF_RESET ;
}
2016-11-23 02:28:40 +01:00
void MotionMaster :: MovementExpired ( bool reset /*= true*/ )
2008-12-19 00:37:40 +02:00
{
2016-11-23 02:28:40 +01:00
if ( _cleanFlag & MMCF_UPDATE )
2008-12-19 00:37:40 +02:00
{
2016-11-23 02:28:40 +01:00
if ( reset )
_cleanFlag |= MMCF_RESET ;
else
_cleanFlag &= ~ MMCF_RESET ;
DelayedExpire ();
2008-12-19 00:37:40 +02:00
}
2016-11-23 02:28:40 +01:00
else
DirectExpire ( reset );
2008-12-19 00:37:40 +02:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
MovementGeneratorType MotionMaster :: GetCurrentMovementGeneratorType () const
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( empty ())
return IDLE_MOTION_TYPE ;
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
return top () -> GetMovementGeneratorType ();
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
MovementGeneratorType MotionMaster :: GetMotionSlotType ( int slot ) const
{
if ( ! _slot [ slot ])
return NULL_MOTION_TYPE ;
else
return _slot [ slot ] -> GetMovementGeneratorType ();
2009-02-08 22:56:57 -06:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
MovementGenerator * MotionMaster :: GetMotionSlot ( int slot ) const
2009-02-08 22:56:57 -06:00
{
2016-11-23 02:28:40 +01:00
ASSERT ( slot >= 0 );
return _slot [ slot ];
}
void MotionMaster :: propagateSpeedChange ()
{
for ( int i = 0 ; i <= _top ; ++ i )
2009-03-04 10:16:15 -06:00
{
2016-11-23 02:28:40 +01:00
if ( _slot [ i ])
_slot [ i ] -> unitSpeedChanged ();
2009-03-04 10:16:15 -06:00
}
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
2012-01-13 16:43:49 +01:00
void MotionMaster :: MoveIdle ()
2008-10-11 14:16:25 -05:00
{
2012-01-13 16:43:49 +01:00
//! Should be preceded by MovementExpired or Clear if there's an overlying movementgenerator active
2016-11-23 02:28:40 +01:00
if ( empty () || ! IsStatic ( top ()))
2012-01-13 16:43:49 +01:00
Mutate ( & si_idleMovement , MOTION_SLOT_IDLE );
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
{
Clear ( false );
2009-10-17 15:51:44 -07:00
2012-08-25 22:57:55 -05:00
if ( _owner -> GetTypeId () == TYPEID_UNIT && ! _owner -> ToCreature () -> GetCharmerOrOwnerGUID ())
2008-10-11 14:16:25 -05:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) targeted home." , _owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str ());
2009-03-21 10:11:29 -06:00
Mutate ( new HomeMovementGenerator < Creature > (), MOTION_SLOT_ACTIVE );
2008-10-11 14:16:25 -05:00
}
2014-10-21 19:23:32 +02:00
else if ( _owner -> GetTypeId () == TYPEID_UNIT && ! _owner -> ToCreature () -> GetCharmerOrOwnerGUID (). IsEmpty ())
2012-01-14 15:34:41 +01:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Pet or controlled creature (Entry: %u %s) is targeting home" , _owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str ());
2012-08-25 22:57:55 -05:00
Unit * target = _owner -> ToCreature () -> GetCharmerOrOwner ();
2012-01-14 15:34:41 +01:00
if ( target )
{
2014-10-22 23:31:10 +02:00
TC_LOG_DEBUG ( "misc" , "Following %s" , target -> GetGUID (). ToString (). c_str ());
2012-08-25 22:57:55 -05:00
Mutate ( new FollowMovementGenerator < Creature > ( target , PET_FOLLOW_DIST , PET_FOLLOW_ANGLE ), MOTION_SLOT_ACTIVE );
2012-01-14 15:34:41 +01:00
}
}
2008-10-11 14:16:25 -05:00
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_ERROR ( "misc" , "Player (%s) attempted to move towards target home." , _owner -> GetGUID (). ToString (). c_str ());
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 :: MoveRandom ( float spawndist )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( _owner -> GetTypeId () == TYPEID_UNIT )
{
TC_LOG_DEBUG ( "misc" , "Creature (%s) started random movement." , _owner -> GetGUID (). ToString (). c_str ());
Mutate ( new RandomMovementGenerator < Creature > ( spawndist ), MOTION_SLOT_IDLE );
}
}
void MotionMaster :: MoveFollow ( Unit * target , float dist , float angle , MovementSlot slot )
{
// ignore movement request if target not exist
if ( ! target || target == _owner )
return ;
//_owner->AddUnitState(UNIT_STATE_FOLLOW);
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
TC_LOG_DEBUG ( "misc" , "Player (%s) follows (%s)" , _owner -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str ());
Mutate ( new FollowMovementGenerator < Player > ( target , dist , angle ), slot );
2008-10-11 14:16:25 -05:00
}
else
{
2016-11-23 02:28:40 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) follows (%s)" , _owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), target -> GetGUID (). ToString (). c_str ());
Mutate ( new FollowMovementGenerator < Creature > ( target , dist , angle ), slot );
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 :: MoveChase ( Unit * target , float dist , float angle )
2008-10-11 14:16:25 -05: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
2012-02-14 12:46:26 -05:00
//_owner->ClearUnitState(UNIT_STATE_FOLLOW);
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2014-10-22 23:31:10 +02:00
TC_LOG_DEBUG ( "misc" , "Player (%s) chase (%s)" ,
_owner -> GetGUID (). ToString (). c_str (),
target -> GetGUID (). ToString (). c_str ());
2012-08-25 22:57:55 -05:00
Mutate ( new ChaseMovementGenerator < Player > ( target , dist , angle ), MOTION_SLOT_ACTIVE );
2008-10-11 14:16:25 -05:00
}
else
{
2014-10-22 23:31:10 +02:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) chase %s" ,
2014-11-14 01:55:29 +00:00
_owner -> GetEntry (),
2014-10-22 23:31:10 +02:00
_owner -> GetGUID (). ToString (). c_str (),
target -> GetGUID (). ToString (). c_str ());
2012-08-25 22:57:55 -05:00
Mutate ( new ChaseMovementGenerator < Creature > ( target , dist , angle ), MOTION_SLOT_ACTIVE );
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 )
{
TC_LOG_DEBUG ( "misc" , "Player (%s) move confused" , _owner -> GetGUID (). ToString (). c_str ());
Mutate ( new ConfusedMovementGenerator < Player > (), MOTION_SLOT_CONTROLLED );
}
else
{
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) move confused" ,
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str ());
Mutate ( new ConfusedMovementGenerator < Creature > (), MOTION_SLOT_CONTROLLED );
}
}
void MotionMaster :: MoveFleeing ( Unit * enemy , uint32 time )
{
if ( ! enemy )
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07:00
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
TC_LOG_DEBUG ( "misc" , "Player (%s) flees from (%s)." , _owner -> GetGUID (). ToString (). c_str (),
enemy -> GetGUID (). ToString (). c_str ());
Mutate ( new FleeingMovementGenerator < Player > ( enemy -> GetGUID ()), MOTION_SLOT_CONTROLLED );
2008-10-11 14:16:25 -05:00
}
else
{
2016-11-23 02:28:40 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) flees from (%s)%s." ,
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (),
enemy -> GetGUID (). ToString (). c_str (),
time ? " for a limited time" : "" );
if ( time )
Mutate ( new TimedFleeingMovementGenerator ( enemy -> GetGUID (), time ), MOTION_SLOT_CONTROLLED );
else
Mutate ( new FleeingMovementGenerator < Creature > ( enemy -> GetGUID ()), MOTION_SLOT_CONTROLLED );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2012-04-09 18:36:45 +02:00
void MotionMaster :: MovePoint ( uint32 id , float x , float y , float z , bool generatePath )
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
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Player (%s) targeted point (Id: %u X: %f Y: %f Z: %f)." , _owner -> GetGUID (). ToString (). c_str (), id , x , y , z );
2012-04-09 18:36:45 +02:00
Mutate ( new PointMovementGenerator < Player > ( id , x , y , z , generatePath ), MOTION_SLOT_ACTIVE );
2008-10-11 14:16:25 -05:00
}
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) targeted point (ID: %u X: %f Y: %f Z: %f)." ,
2014-10-22 23:31:10 +02:00
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), id , x , y , z );
2012-04-09 18:36:45 +02:00
Mutate ( new PointMovementGenerator < Creature > ( id , x , y , z , generatePath ), MOTION_SLOT_ACTIVE );
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 )
{
float angle = _owner -> GetAngle ( target );
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
{
// we are already close enough. We just need to turn toward the target without changing position.
Movement :: MoveSplineInit init ( _owner );
init . MoveTo ( _owner -> GetPositionX (), _owner -> GetPositionY (), _owner -> GetPositionZMinusOffset ());
init . SetFacing ( target );
init . Launch ();
Mutate ( new EffectMovementGenerator ( id ), MOTION_SLOT_ACTIVE );
}
}
2012-05-31 19:45:11 +02:00
void MotionMaster :: MoveLand ( uint32 id , Position const & pos )
2011-07-27 12:40:14 +02:00
{
float x , y , z ;
pos . GetPosition ( x , y , z );
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)." , _owner -> GetEntry (), id , x , y , z );
2011-07-27 12:40:14 +02:00
2012-08-25 22:57:55 -05:00
Movement :: MoveSplineInit init ( _owner );
2013-01-14 09:50:59 +01:00
init . MoveTo ( x , y , z );
2012-01-14 15:34:41 +01:00
init . SetAnimation ( Movement :: ToGround );
init . Launch ();
2012-01-18 16:26:45 +03:00
Mutate ( new EffectMovementGenerator ( id ), MOTION_SLOT_ACTIVE );
2011-07-27 12:40:14 +02:00
}
2012-05-31 19:45:11 +02:00
void MotionMaster :: MoveTakeoff ( uint32 id , Position const & pos )
2011-07-27 12:40:14 +02:00
{
float x , y , z ;
pos . GetPosition ( x , y , z );
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)." , _owner -> GetEntry (), id , x , y , z );
2011-07-27 12:40:14 +02:00
2012-08-25 22:57:55 -05:00
Movement :: MoveSplineInit init ( _owner );
2013-01-14 09:50:59 +01:00
init . MoveTo ( x , y , z );
2012-01-14 15:34:41 +01:00
init . SetAnimation ( Movement :: ToFly );
init . Launch ();
2012-01-18 16:26:45 +03:00
Mutate ( new EffectMovementGenerator ( id ), MOTION_SLOT_ACTIVE );
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*/ )
{
if ( _slot [ MOTION_SLOT_CONTROLLED ] && _slot [ MOTION_SLOT_CONTROLLED ] -> GetMovementGeneratorType () != DISTRACT_MOTION_TYPE )
return ;
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
{
TC_LOG_DEBUG ( "misc" , "Player (%s) charged point (X: %f Y: %f Z: %f)." , _owner -> GetGUID (). ToString (). c_str (), x , y , z );
Mutate ( new PointMovementGenerator < Player > ( id , x , y , z , generatePath , speed , target , spellEffectExtraData ), MOTION_SLOT_CONTROLLED );
}
else
{
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) charged point (X: %f Y: %f Z: %f)." ,
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), x , y , z );
Mutate ( new PointMovementGenerator < Creature > ( id , x , y , z , generatePath , speed , target , spellEffectExtraData ), MOTION_SLOT_CONTROLLED );
}
}
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 );
// 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 ();
}
2017-02-18 21:55:28 +01:00
void MotionMaster :: MoveKnockbackFrom ( float srcX , float srcY , float speedXY , float speedZ , Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ )
2009-03-23 15:26:13 -06: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
2014-01-28 22:40:13 +01:00
if ( speedXY <= 0.1f )
return ;
2009-03-23 15:26:13 -06:00
float x , y , z ;
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
2014-08-21 16:56:11 +02:00
_owner -> GetNearPoint ( _owner , x , y , z , _owner -> GetObjectSize (), dist , _owner -> GetAngle ( srcX , srcY ) + float ( M_PI ));
2012-07-28 17:07:05 +02:00
2012-08-25 22:57:55 -05:00
Movement :: MoveSplineInit init ( _owner );
2012-09-03 20:30:30 +02:00
init . MoveTo ( x , y , z );
2013-01-14 09:50:59 +01:00
init . SetParabolic ( max_height , 0 );
2012-07-28 17:07:05 +02:00
init . SetOrientationFixed ( true );
init . SetVelocity ( speedXY );
2017-02-18 21:55:28 +01:00
if ( spellEffectExtraData )
init . SetSpellEffectExtraData ( * spellEffectExtraData );
2012-07-28 17:07:05 +02:00
init . Launch ();
Mutate ( new EffectMovementGenerator ( 0 ), MOTION_SLOT_CONTROLLED );
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 )
{
//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
2009-04-11 22:41:15 -05:00
float x , y , z ;
2012-01-14 15:34:41 +01:00
float moveTimeHalf = speedZ / Movement :: gravity ;
float dist = 2 * moveTimeHalf * speedXY ;
2012-02-14 12:46:26 -05:00
_owner -> GetClosePoint ( x , y , z , _owner -> GetObjectSize (), dist , angle );
2016-02-10 17:41:19 +01:00
MoveJump ( x , y , z , 0.0f , speedXY , speedZ );
2009-04-11 22:41:15 -05:00
}
2009-10-17 15:51:44 -07:00
2017-02-18 21:55:28 +01:00
void MotionMaster :: MoveJump ( float x , float y , float z , float o , float speedXY , float speedZ , uint32 id /*= EVENT_JUMP*/ , bool hasOrientation /* = false*/ ,
JumpArrivalCastArgs const * arrivalCast /*= nullptr*/ , Movement :: SpellEffectExtraData const * spellEffectExtraData /*= nullptr*/ )
2009-03-23 15:26:13 -06:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Unit (%s) jumps to point (X: %f Y: %f Z: %f)." , _owner -> GetGUID (). ToString (). c_str (), x , y , z );
2014-01-28 22:40:13 +01:00
if ( speedXY <= 0.1f )
return ;
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
2012-08-25 22:57:55 -05:00
Movement :: MoveSplineInit init ( _owner );
2012-08-25 14:32:52 -05:00
init . MoveTo ( x , y , z , false );
2013-01-14 09:50:59 +01:00
init . SetParabolic ( max_height , 0 );
2012-01-14 15:34:41 +01:00
init . SetVelocity ( speedXY );
2016-02-10 17:41:19 +01:00
if ( hasOrientation )
init . SetFacing ( o );
2017-02-18 21:55:28 +01:00
if ( spellEffectExtraData )
init . SetSpellEffectExtraData ( * spellEffectExtraData );
2012-01-14 15:34:41 +01:00
init . Launch ();
2017-02-18 21:55:28 +01:00
uint32 arrivalSpellId = 0 ;
ObjectGuid arrivalSpellTargetGuid ;
if ( arrivalCast )
{
arrivalSpellId = arrivalCast -> SpellId ;
arrivalSpellTargetGuid = arrivalCast -> Target ;
}
2016-01-25 19:35:41 +01:00
Mutate ( new EffectMovementGenerator ( id , arrivalSpellId , arrivalSpellTargetGuid ), MOTION_SLOT_CONTROLLED );
2012-01-14 15:34:41 +01:00
}
2015-03-15 21:32:35 +01:00
void MotionMaster :: MoveCirclePath ( float x , float y , float z , float radius , bool clockwise , uint8 stepCount )
{
float step = 2 * float ( M_PI ) / stepCount * ( clockwise ? - 1.0f : 1.0f );
Position const & pos = { x , y , z , 0.0f };
float angle = pos . GetAngle ( _owner -> GetPositionX (), _owner -> GetPositionY ());
Movement :: MoveSplineInit init ( _owner );
for ( uint8 i = 0 ; i < stepCount ; angle += step , ++ i )
{
G3D :: Vector3 point ;
point . x = x + radius * cosf ( angle );
point . y = y + radius * sinf ( angle );
if ( _owner -> IsFlying ())
point . z = z ;
else
2018-01-28 11:37:20 +01:00
point . z = _owner -> GetMap () -> GetHeight ( _owner -> GetPhaseShift (), point . x , point . y , z );
2015-03-15 21:32:35 +01:00
init . Path (). push_back ( point );
}
if ( _owner -> IsFlying ())
{
init . SetFly ();
init . SetCyclic ();
init . SetAnimation ( Movement :: ToFly );
}
else
{
init . SetWalk ( true );
init . SetCyclic ();
}
init . Launch ();
}
2017-06-04 01:00:45 +02:00
void MotionMaster :: MoveSmoothPath ( uint32 pointId , Position const * pathPoints , size_t pathSize , bool walk , bool fly )
2016-08-31 21:41:23 +02:00
{
2015-08-23 14:43:11 +02:00
Movement :: MoveSplineInit init ( _owner );
2017-04-16 15:10:48 +02:00
if ( fly )
{
init . SetFly ();
2017-01-14 15:03:47 +01:00
init . SetUncompressed ();
2017-07-13 17:50:13 +02:00
init . SetSmooth ();
2017-04-16 15:10:48 +02:00
}
2017-06-04 01:00:45 +02:00
Movement :: PointsArray path ;
path . reserve ( pathSize );
std :: transform ( pathPoints , pathPoints + pathSize , std :: back_inserter ( path ), []( Position const & point )
{
return G3D :: Vector3 ( point . GetPositionX (), point . GetPositionY (), point . GetPositionZ ());
});
2015-08-23 14:43:11 +02:00
init . MovebyPath ( path );
init . SetWalk ( walk );
init . Launch ();
// This code is not correct
// EffectMovementGenerator does not affect UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE
// need to call PointMovementGenerator with various pointIds
Mutate ( new EffectMovementGenerator ( pointId ), MOTION_SLOT_ACTIVE );
//Position pos(pathPoints[pathSize - 1].x, pathPoints[pathSize - 1].y, pathPoints[pathSize - 1].z);
//MovePoint(EVENT_CHARGE_PREPATH, pos, false);
}
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 )
{
TC_LOG_ERROR ( "misc" , "MotionMaster::MoveAlongSplineChain: non-creature %s tried to walk along DB spline chain. Ignoring." , _owner -> GetGUID (). ToString (). c_str ());
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 )
{
TC_LOG_ERROR ( "misc" , "MotionMaster::MoveAlongSplineChain: creature with entry %u tried to walk along non-existing spline chain with DB id %u." , owner -> GetEntry (), dbChainId );
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
{
Mutate ( new SplineChainMovementGenerator ( pointId , chain , walk ), MOTION_SLOT_ACTIVE );
}
void MotionMaster :: ResumeSplineChain ( SplineChainResumeInfo const & info )
{
2016-09-21 16:22:12 +02:00
if ( info . Empty ())
{
TC_LOG_ERROR ( "misc" , "MotionMaster::ResumeSplineChain: unit with entry %u tried to resume a spline chain from empty info." , _owner -> GetEntry ());
return ;
}
2016-09-14 23:53:37 +02:00
Mutate ( new SplineChainMovementGenerator ( info ), MOTION_SLOT_ACTIVE );
}
2012-12-18 14:46:06 +01:00
void MotionMaster :: MoveFall ( uint32 id /*=0*/ )
2012-01-14 15:34:41 +01:00
{
// use larger distance for vmap height search than in most other cases
2018-01-28 11:37:20 +01:00
float tz = _owner -> GetMap () -> GetHeight ( _owner -> GetPhaseShift (), _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
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "MotionMaster::MoveFall: unable to retrieve a proper height at map %u (x: %f, y: %f, z: %f)." ,
2012-12-18 14:46:06 +01:00
_owner -> GetMap () -> GetId (), _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 ;
2016-04-13 20:47:57 +02:00
_owner -> SetFall ( true );
// don't run spline movement for players
2012-04-08 12:17:43 +02:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2016-04-13 20:47:57 +02:00
return ;
2012-04-08 12:17:43 +02:00
2012-08-25 22:57:55 -05:00
Movement :: MoveSplineInit init ( _owner );
2012-09-03 20:34:07 +02:00
init . MoveTo ( _owner -> GetPositionX (), _owner -> GetPositionY (), tz , false );
2012-01-14 15:34:41 +01:00
init . SetFall ();
init . Launch ();
2012-01-15 15:26:00 +01:00
Mutate ( new EffectMovementGenerator ( id ), MOTION_SLOT_CONTROLLED );
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
{
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2009-05-21 10:48:00 -05:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_ERROR ( "misc" , "Player (GUID: %s) attempted to seek assistance." , _owner -> GetGUID (). ToString (). c_str ());
2009-05-21 10:48:00 -05:00
}
else
{
2014-10-22 23:31:10 +02:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) seek assistance (X: %f Y: %f Z: %f)" ,
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), x , y , z );
2012-02-14 12:46:26 -05:00
_owner -> AttackStop ();
2016-06-10 21:03:30 +02:00
_owner -> CastStop ();
2012-02-14 12:46:26 -05:00
_owner -> ToCreature () -> SetReactState ( REACT_PASSIVE );
2011-04-29 20:47:02 +02:00
Mutate ( new AssistanceMovementGenerator ( x , y , z ), MOTION_SLOT_ACTIVE );
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
{
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2009-05-21 10:48:00 -05:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_ERROR ( "misc" , "Player (%s) attempedt to call distract after assistance." , _owner -> GetGUID (). ToString (). c_str ());
2009-05-21 10:48:00 -05:00
}
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) is distracted after assistance call (Time: %u)." ,
2014-10-22 23:31:10 +02:00
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), time );
2009-05-21 10:48:00 -05:00
Mutate ( new AssistanceDistractMovementGenerator ( time ), MOTION_SLOT_ACTIVE );
}
}
2009-10-17 15:51:44 -07:00
2011-07-27 12:40:14 +02:00
void MotionMaster :: MoveTaxiFlight ( uint32 path , uint32 pathnode )
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 ())
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "%s taxi to (Path %u node %u)." , _owner -> GetName (). c_str (), path , pathnode );
2015-09-21 00:01:44 +02:00
FlightPathMovementGenerator * mgen = new FlightPathMovementGenerator ();
2015-09-13 17:23:37 +02:00
mgen -> LoadPath ( _owner -> ToPlayer ());
2010-06-23 00:57:16 +02:00
Mutate ( mgen , MOTION_SLOT_CONTROLLED );
}
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_ERROR ( "misc" , "%s attempted taxi to (non-existing Path %u node %u)." ,
2012-10-24 13:29:34 +02:00
_owner -> GetName (). c_str (), path , pathnode );
2010-06-23 00:57:16 +02:00
}
2008-10-11 14:16:25 -05:00
}
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_ERROR ( "misc" , "Creature (Entry: %u %s) attempted taxi to (Path %u node %u)." ,
2014-10-22 23:31:10 +02:00
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), path , pathnode );
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 :: MoveDistract ( uint32 timer )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( _slot [ MOTION_SLOT_CONTROLLED ])
2009-01-17 00:00:48 -06:00
return ;
2009-10-17 15:51:44 -07:00
2012-02-14 12:46:26 -05:00
if ( _owner -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Player (%s) distracted (timer: %u)." , _owner -> GetGUID (). ToString (). c_str (), timer );
2008-10-11 14:16:25 -05:00
}
else
{
2016-02-20 13:23:35 +01:00
TC_LOG_DEBUG ( "misc" , "Creature (Entry: %u %s) distracted (timer: %u)" ,
2014-10-22 23:31:10 +02:00
_owner -> GetEntry (), _owner -> GetGUID (). ToString (). c_str (), timer );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
DistractMovementGenerator * mgen = new DistractMovementGenerator ( timer );
2009-01-16 22:57:03 -06:00
Mutate ( mgen , MOTION_SLOT_CONTROLLED );
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 :: MovePath ( uint32 path_id , bool repeatable )
{
if ( ! path_id )
return ;
Mutate ( new WaypointMovementGenerator < Creature > ( path_id , repeatable ), MOTION_SLOT_IDLE );
TC_LOG_DEBUG ( "misc" , "%s starts moving over path (Id:%u, repeatable: %s)." ,
_owner -> GetGUID (). ToString (). c_str (), path_id , repeatable ? "YES" : "NO" );
}
2016-11-25 00:31:10 +01:00
void MotionMaster :: MovePath ( WaypointPath & path , bool repeatable )
{
Mutate ( new WaypointMovementGenerator < Creature > ( path , repeatable ), MOTION_SLOT_IDLE );
TC_LOG_DEBUG ( "misc" , "%s starts moving over path (repeatable: %s)." ,
_owner -> GetGUID (). ToString (). c_str (), repeatable ? "YES" : "NO" );
}
2016-11-23 02:28:40 +01:00
void MotionMaster :: MoveRotate ( uint32 time , RotateDirection direction )
{
if ( ! time )
return ;
Mutate ( new RotateMovementGenerator ( time , direction ), MOTION_SLOT_ACTIVE );
}
/******************** Private methods ********************/
void MotionMaster :: pop ()
{
if ( empty ())
return ;
_slot [ _top ] = nullptr ;
while ( ! empty () && ! top ())
-- _top ;
}
bool MotionMaster :: NeedInitTop () const
{
if ( empty ())
return false ;
return _initialize [ _top ];
}
void MotionMaster :: InitTop ()
{
top () -> Initialize ( _owner );
_initialize [ _top ] = false ;
}
2009-01-16 22:57:03 -06:00
void MotionMaster :: Mutate ( MovementGenerator * m , MovementSlot slot )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01: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
2012-02-14 12:46:26 -05:00
if ( _top == slot && ( _cleanFlag & MMCF_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
}
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 :: DirectClean ( bool reset )
2008-12-09 23:06:16 -06:00
{
2016-11-23 02:28:40 +01:00
while ( size () > 1 )
2008-12-09 23:06:16 -06:00
{
MovementGenerator * curr = top ();
pop ();
2016-11-23 02:28:40 +01:00
if ( curr )
DirectDelete ( curr );
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
if ( empty ())
2009-08-30 11:50:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
if ( NeedInitTop ())
InitTop ();
else if ( reset )
top () -> Reset ( _owner );
2009-08-29 17:14:47 -05:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
void MotionMaster :: DelayedClean ()
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
while ( size () > 1 )
2009-01-17 13:29:26 -06:00
{
2016-11-23 02:28:40 +01:00
MovementGenerator * curr = top ();
pop ();
if ( curr )
DelayedDelete ( curr );
2009-01-17 13:29:26 -06:00
}
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 :: DirectExpire ( bool reset )
2008-10-11 14:16:25 -05:00
{
2016-11-23 02:28:40 +01:00
if ( size () > 1 )
{
MovementGenerator * curr = top ();
pop ();
DirectDelete ( curr );
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
while ( ! empty () && ! top ())
-- _top ;
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
if ( empty ())
Initialize ();
else if ( NeedInitTop ())
InitTop ();
else if ( reset )
top () -> Reset ( _owner );
2009-03-15 10:50:10 -06:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
void MotionMaster :: DelayedExpire ()
2009-03-04 10:16:15 -06:00
{
2016-11-23 02:28:40 +01:00
if ( size () > 1 )
{
MovementGenerator * curr = top ();
pop ();
DelayedDelete ( curr );
}
while ( ! empty () && ! top ())
-- _top ;
2009-03-04 10:16:15 -06:00
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
void MotionMaster :: DirectDelete ( MovementGenerator * curr )
2009-02-08 22:56:57 -06:00
{
2016-11-23 02:28:40 +01:00
if ( IsStatic ( curr ))
2009-02-08 22:56:57 -06:00
return ;
2012-08-25 22:57:55 -05:00
curr -> Finalize ( _owner );
2009-02-08 22:56:57 -06:00
delete curr ;
}
2009-10-17 15:51:44 -07:00
2016-11-23 02:28:40 +01:00
void MotionMaster :: DelayedDelete ( MovementGenerator * curr )
2009-02-08 22:56:57 -06:00
{
2015-02-20 14:31:50 +01:00
TC_LOG_FATAL ( "misc" , "Unit (Entry %u) is trying to delete its updating Movement Generator (Type %u)!" , _owner -> GetEntry (), curr -> GetMovementGeneratorType ());
2016-11-23 02:28:40 +01:00
if ( IsStatic ( curr ))
2009-02-08 22:56:57 -06:00
return ;
2016-11-23 02:28:40 +01:00
if ( ! _expireList )
_expireList = new ExpireList ();
_expireList -> push_back ( curr );
2008-10-11 14:16:25 -05:00
}