2009-02-17 18:08:26 +01:00
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
2008-10-21 13:19:26 -05:00
* This program is free software licensed under GPL version 2
* Please see the included DOCS/LICENSE.TXT for more information */
/* ScriptData
SDName: Npc_EscortAI
SD%Complete: 100
SDComment:
SDCategory: Npc
EndScriptData */
#include "precompiled.h"
2009-08-16 00:53:16 +02:00
#include "escortAI.h"
2008-10-21 13:19:26 -05:00
2009-08-13 05:47:23 +02:00
enum
{
POINT_LAST_POINT = 0xFFFFFF ,
POINT_HOME = 0xFFFFFE
};
2009-04-04 13:11:03 -06:00
extern std :: list < PointMovement > PointMovementList ;
2008-10-21 13:19:26 -05:00
2009-08-14 05:32:39 +02:00
void npc_escortAI :: AttackStart ( Unit * pWho )
2008-10-21 13:19:26 -05:00
{
2009-08-14 05:32:39 +02:00
if ( ! pWho )
2008-10-21 13:19:26 -05:00
return ;
2009-08-14 05:32:39 +02:00
if ( m_creature -> Attack ( pWho , true ))
2009-04-27 21:23:42 -05:00
{
2009-08-11 00:43:06 +02:00
if ( m_creature -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == POINT_MOTION_TYPE )
2009-05-19 23:48:48 +02:00
m_creature -> GetMotionMaster () -> MovementExpired ();
2009-08-11 00:43:06 +02:00
2009-08-13 02:48:34 +02:00
if ( IsCombatMovement ())
2009-08-14 05:32:39 +02:00
m_creature -> GetMotionMaster () -> MoveChase ( pWho );
2009-04-27 21:23:42 -05:00
}
}
2009-02-04 10:33:18 -06:00
2009-08-14 05:32:39 +02:00
void npc_escortAI :: MoveInLineOfSight ( Unit * pWho )
2008-10-21 13:19:26 -05:00
{
2009-08-11 00:43:06 +02:00
if ( IsBeingEscorted && ! m_bIsActiveAttacker )
2008-10-21 13:19:26 -05:00
return ;
2009-08-14 05:32:39 +02:00
ScriptedAI :: MoveInLineOfSight ( pWho );
}
void npc_escortAI :: JustDied ( Unit * pKiller )
{
if ( ! IsBeingEscorted || ! PlayerGUID || ! m_pQuestForEscort )
return ;
if ( Player * pPlayer = Unit :: GetPlayer ( PlayerGUID ))
{
if ( Group * pGroup = pPlayer -> GetGroup ())
{
for ( GroupReference * pRef = pGroup -> GetFirstMember (); pRef != NULL ; pRef = pRef -> next ())
{
if ( Player * pMember = pRef -> getSource ())
{
if ( pPlayer -> GetQuestStatus ( m_pQuestForEscort -> GetQuestId ()) == QUEST_STATUS_INCOMPLETE )
pPlayer -> FailQuest ( m_pQuestForEscort -> GetQuestId ());
}
}
}
else
{
if ( pPlayer -> GetQuestStatus ( m_pQuestForEscort -> GetQuestId ()) == QUEST_STATUS_INCOMPLETE )
pPlayer -> FailQuest ( m_pQuestForEscort -> GetQuestId ());
}
}
2008-10-21 13:19:26 -05:00
}
void npc_escortAI :: JustRespawned ()
{
IsBeingEscorted = false ;
IsOnHold = false ;
2009-08-13 02:48:34 +02:00
if ( ! IsCombatMovement ())
SetCombatMovement ( true );
2008-10-21 13:19:26 -05:00
2009-08-14 05:32:39 +02:00
//add a small delay before going to first waypoint, normal in near all cases
m_uiWPWaitTimer = 2500 ;
if ( m_creature -> getFaction () != m_creature -> GetCreatureInfo () -> faction_A )
me -> RestoreFaction ();
2008-10-21 13:19:26 -05:00
Reset ();
}
2009-08-10 15:27:42 +02:00
void npc_escortAI :: ReturnToLastPoint ()
{
float x , y , z , o ;
m_creature -> GetHomePosition ( x , y , z , o );
2009-08-13 05:47:23 +02:00
m_creature -> GetMotionMaster () -> MovePoint ( POINT_LAST_POINT , x , y , z );
2009-08-10 15:27:42 +02:00
}
2008-10-21 13:19:26 -05:00
void npc_escortAI :: EnterEvadeMode ()
{
m_creature -> RemoveAllAuras ();
m_creature -> DeleteThreatList ();
2009-05-24 18:16:43 -05:00
m_creature -> CombatStop ( true );
2008-10-21 13:19:26 -05:00
m_creature -> SetLootRecipient ( NULL );
if ( IsBeingEscorted )
{
2009-08-11 00:43:06 +02:00
m_bIsReturning = true ;
2009-08-10 15:27:42 +02:00
ReturnToLastPoint ();
debug_log ( "TSCR: EscortAI has left combat and is now returning to last point" );
2009-04-19 21:16:11 +02:00
}
else
2008-10-21 13:19:26 -05:00
m_creature -> GetMotionMaster () -> MoveTargetedHome ();
Reset ();
}
2009-08-14 05:32:39 +02:00
void npc_escortAI :: UpdateAI ( const uint32 uiDiff )
2008-10-21 13:19:26 -05:00
{
//Waypoint Updating
2009-08-11 00:43:06 +02:00
if ( IsBeingEscorted && ! m_creature -> getVictim () && m_uiWPWaitTimer && ! m_bIsReturning )
2008-10-21 13:19:26 -05:00
{
2009-08-14 05:32:39 +02:00
if ( m_uiWPWaitTimer <= uiDiff )
2008-10-21 13:19:26 -05:00
{
2009-08-13 05:47:23 +02:00
//End of the line
2009-08-11 00:43:06 +02:00
if ( CurrentWP == WaypointList . end ())
2008-10-21 13:19:26 -05:00
{
2009-08-14 00:02:13 +02:00
if ( DespawnAtEnd )
2009-08-11 00:43:06 +02:00
{
debug_log ( "TSCR: EscortAI reached end of waypoints" );
2008-10-21 13:19:26 -05:00
2009-08-13 05:47:23 +02:00
if ( m_bCanReturnToStart )
{
float fRetX , fRetY , fRetZ ;
m_creature -> GetRespawnCoord ( fRetX , fRetY , fRetZ );
2008-10-21 13:19:26 -05:00
2009-08-13 05:47:23 +02:00
m_creature -> GetMotionMaster () -> MovePoint ( POINT_HOME , fRetX , fRetY , fRetZ );
m_uiWPWaitTimer = 0 ;
debug_log ( "TSCR: EscortAI are returning home to spawn location: %u, %f, %f, %f" , POINT_HOME , fRetX , fRetY , fRetZ );
return ;
}
if ( m_bCanInstantRespawn )
{
m_creature -> setDeathState ( JUST_DIED );
m_creature -> Respawn ();
}
else
m_creature -> ForcedDespawn ();
2008-10-21 13:19:26 -05:00
2009-08-11 00:43:06 +02:00
return ;
}
else
{
debug_log ( "TSCR: EscortAI reached end of waypoints with Despawn off" );
2008-10-21 13:19:26 -05:00
2009-08-11 00:43:06 +02:00
return ;
}
2009-04-19 21:16:11 +02:00
}
2009-08-11 00:43:06 +02:00
2009-08-14 00:02:13 +02:00
if ( ! IsOnHold )
2009-04-19 21:16:11 +02:00
{
2009-08-14 00:02:13 +02:00
m_creature -> GetMotionMaster () -> MovePoint ( CurrentWP -> id , CurrentWP -> x , CurrentWP -> y , CurrentWP -> z );
2009-08-11 00:43:06 +02:00
debug_log ( "TSCR: EscortAI Next WP is: %u, %f, %f, %f" , CurrentWP -> id , CurrentWP -> x , CurrentWP -> y , CurrentWP -> z );
m_uiWPWaitTimer = 0 ;
2009-04-03 17:57:57 +02:00
}
2009-08-14 05:32:39 +02:00
}
else
m_uiWPWaitTimer -= uiDiff ;
2009-02-09 08:16:34 -05:00
}
2008-10-21 13:19:26 -05:00
2009-08-10 23:24:40 +02:00
//Check if player or any member of his group is within range
2009-08-11 00:43:06 +02:00
if ( IsBeingEscorted && PlayerGUID && ! m_creature -> getVictim () && ! m_bIsReturning )
2009-02-09 08:16:34 -05:00
{
2009-08-14 05:32:39 +02:00
if ( m_uiPlayerCheckTimer < uiDiff )
2008-10-21 13:19:26 -05:00
{
2009-08-10 23:24:40 +02:00
bool bIsMaxRangeExceeded = true ;
if ( Player * pPlayer = Unit :: GetPlayer ( PlayerGUID ))
{
if ( Group * pGroup = pPlayer -> GetGroup ())
{
for ( GroupReference * pRef = pGroup -> GetFirstMember (); pRef != NULL ; pRef = pRef -> next ())
{
Player * pMember = pRef -> getSource ();
if ( pMember && m_creature -> IsWithinDistInMap ( pMember , GetMaxPlayerDistance ()))
{
bIsMaxRangeExceeded = false ;
break ;
}
}
}
else
{
if ( m_creature -> IsWithinDistInMap ( pPlayer , GetMaxPlayerDistance ()))
bIsMaxRangeExceeded = false ;
}
}
2008-10-21 13:19:26 -05:00
2009-08-10 23:24:40 +02:00
if ( DespawnAtFar && bIsMaxRangeExceeded )
{
2009-08-14 05:32:39 +02:00
debug_log ( "TSCR: EscortAI failed because player/group was to far away or not found" );
2009-04-19 21:16:11 +02:00
2009-08-13 05:47:23 +02:00
if ( m_bCanInstantRespawn )
{
m_creature -> setDeathState ( JUST_DIED );
m_creature -> Respawn ();
}
else
m_creature -> ForcedDespawn ();
2009-08-10 23:24:40 +02:00
2009-08-11 00:43:06 +02:00
return ;
2009-08-10 23:24:40 +02:00
}
2008-10-21 13:19:26 -05:00
2009-08-11 00:43:06 +02:00
m_uiPlayerCheckTimer = 1000 ;
2009-08-14 05:32:39 +02:00
}
else
m_uiPlayerCheckTimer -= uiDiff ;
2009-02-09 08:16:34 -05:00
}
2008-10-21 13:19:26 -05:00
2009-08-14 00:02:13 +02:00
if ( CanMelee && UpdateVictim ())
2009-05-24 18:16:43 -05:00
DoMeleeAttackIfReady ();
2008-10-21 13:19:26 -05:00
}
2009-08-14 05:32:39 +02:00
void npc_escortAI :: MovementInform ( uint32 uiMoveType , uint32 uiPointId )
2008-10-21 13:19:26 -05:00
{
2009-08-14 05:32:39 +02:00
if ( uiMoveType != POINT_MOTION_TYPE || ! IsBeingEscorted )
2008-10-21 13:19:26 -05:00
return ;
2009-08-11 00:43:06 +02:00
//Combat start position reached, continue waypoint movement
2009-08-14 05:32:39 +02:00
if ( uiPointId == POINT_LAST_POINT )
2008-10-21 13:19:26 -05:00
{
2009-04-24 00:51:09 -04:00
debug_log ( "TSCR: EscortAI has returned to original position before combat" );
2008-10-21 13:19:26 -05:00
2009-08-11 00:43:06 +02:00
if ( m_bIsRunning && m_creature -> HasUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE ))
m_creature -> RemoveUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
else if ( ! m_bIsRunning && ! m_creature -> HasUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE ))
m_creature -> AddUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
m_bIsReturning = false ;
if ( ! m_uiWPWaitTimer )
m_uiWPWaitTimer = 1 ;
2009-04-19 21:16:11 +02:00
}
2009-08-14 05:32:39 +02:00
else if ( uiPointId == POINT_HOME )
2009-08-13 05:47:23 +02:00
{
debug_log ( "TSCR: EscortAI has returned to original home location and will continue from beginning of waypoint list." );
CurrentWP = WaypointList . begin ();
m_uiWPWaitTimer = 1 ;
}
2009-04-19 21:16:11 +02:00
else
2008-10-21 13:19:26 -05:00
{
//Make sure that we are still on the right waypoint
2009-08-14 05:32:39 +02:00
if ( CurrentWP -> id != uiPointId )
2008-10-21 13:19:26 -05:00
{
2009-08-14 05:32:39 +02:00
debug_log ( "TSCR ERROR: EscortAI reached waypoint out of order %d, expected %d" , uiPointId , CurrentWP -> id );
2008-10-21 13:19:26 -05:00
return ;
}
2009-04-24 00:51:09 -04:00
debug_log ( "TSCR: EscortAI Waypoint %d reached" , CurrentWP -> id );
2008-10-21 13:19:26 -05:00
//Call WP function
WaypointReached ( CurrentWP -> id );
2009-08-11 00:43:06 +02:00
m_uiWPWaitTimer = CurrentWP -> WaitTimeMs + 1 ;
2008-10-21 13:19:26 -05:00
++ CurrentWP ;
}
}
2009-05-24 18:16:43 -05:00
/*
2008-11-05 20:51:05 -06:00
void npc_escortAI::OnPossess(bool apply)
{
2009-02-04 10:33:18 -06:00
// We got possessed in the middle of being escorted, store the point
2008-11-05 20:51:05 -06:00
// where we left off to come back to when possess is removed
if (IsBeingEscorted)
{
if (apply)
m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);
else
{
Returning = true;
m_creature->GetMotionMaster()->MovementExpired();
m_creature->GetMotionMaster()->MovePoint(WP_LAST_POINT, LastPos.x, LastPos.y, LastPos.z);
}
}
}
2009-05-24 18:16:43 -05:00
*/
2008-11-05 20:51:05 -06:00
2008-10-21 13:19:26 -05:00
void npc_escortAI :: AddWaypoint ( uint32 id , float x , float y , float z , uint32 WaitTimeMs )
{
Escort_Waypoint t ( id , x , y , z , WaitTimeMs );
WaypointList . push_back ( t );
}
2009-03-22 23:11:55 +01:00
void npc_escortAI :: FillPointMovementListForCreature ()
{
2009-04-09 23:07:32 +02:00
UNORDERED_MAP < uint32 , std :: vector < PointMovement > >:: iterator pPointsEntries = PointMovementMap . find ( m_creature -> GetEntry ());
2009-03-22 23:11:55 +01:00
2009-04-09 23:07:32 +02:00
if ( pPointsEntries != PointMovementMap . end ())
2009-03-22 23:11:55 +01:00
{
2009-04-09 23:07:32 +02:00
std :: vector < PointMovement >:: iterator itr ;
for ( itr = pPointsEntries -> second . begin (); itr != pPointsEntries -> second . end (); ++ itr )
2009-03-22 23:11:55 +01:00
{
Escort_Waypoint pPoint ( itr -> m_uiPointId , itr -> m_fX , itr -> m_fY , itr -> m_fZ , itr -> m_uiWaitTime );
WaypointList . push_back ( pPoint );
}
}
}
2009-04-19 21:16:11 +02:00
void npc_escortAI :: SetRun ( bool bRun )
{
if ( bRun )
{
2009-08-11 00:43:06 +02:00
if ( ! m_bIsRunning )
2009-04-19 21:16:11 +02:00
m_creature -> RemoveUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
else
2009-04-24 00:51:09 -04:00
debug_log ( "TSCR: EscortAI attempt to set run mode, but is already running." );
2009-04-19 21:16:11 +02:00
}
else
{
2009-08-11 00:43:06 +02:00
if ( m_bIsRunning )
2009-04-19 21:16:11 +02:00
m_creature -> AddUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
else
2009-04-24 00:51:09 -04:00
debug_log ( "TSCR: EscortAI attempt to set walk mode, but is already walking." );
2009-04-19 21:16:11 +02:00
}
2009-08-11 00:43:06 +02:00
m_bIsRunning = bRun ;
2009-04-19 21:16:11 +02:00
}
2009-08-13 05:47:23 +02:00
//TODO: get rid of this many variables passed in function.
void npc_escortAI :: Start ( bool bIsActiveAttacker , bool bRun , uint64 uiPlayerGUID , const Quest * pQuest , bool bInstantRespawn , bool bCanLoopPath )
2008-10-21 13:19:26 -05:00
{
2009-08-11 00:43:06 +02:00
if ( m_creature -> getVictim ())
2008-10-21 13:19:26 -05:00
{
2009-05-19 23:48:48 +02:00
debug_log ( "TSCR ERROR: EscortAI attempt to Start while in combat" );
2008-10-21 13:19:26 -05:00
return ;
}
2009-04-19 21:16:11 +02:00
if ( IsBeingEscorted )
{
2009-04-24 00:51:09 -04:00
error_log ( "TSCR: EscortAI attempt to Start while already escorting" );
2009-04-19 21:16:11 +02:00
return ;
}
2008-10-21 13:19:26 -05:00
if ( WaypointList . empty ())
{
2009-04-24 00:51:09 -04:00
error_db_log ( "TSCR: EscortAI Start with 0 waypoints (possible missing entry in script_waypoint)" );
2008-10-21 13:19:26 -05:00
return ;
}
2009-08-13 05:47:23 +02:00
//set variables
m_bIsActiveAttacker = bIsActiveAttacker ;
m_bIsRunning = bRun ;
PlayerGUID = uiPlayerGUID ;
m_pQuestForEscort = pQuest ;
m_bCanInstantRespawn = bInstantRespawn ;
m_bCanReturnToStart = bCanLoopPath ;
if ( m_bCanReturnToStart && m_bCanInstantRespawn )
debug_log ( "TSCR: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn." );
2009-08-14 00:02:13 +02:00
if ( m_creature -> GetMotionMaster () -> GetCurrentMovementGeneratorType () == WAYPOINT_MOTION_TYPE )
2009-05-19 23:48:48 +02:00
{
m_creature -> GetMotionMaster () -> MovementExpired ();
m_creature -> GetMotionMaster () -> MoveIdle ();
debug_log ( "TSCR: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle." );
}
2009-08-11 00:43:06 +02:00
//disable npcflags
m_creature -> SetUInt32Value ( UNIT_NPC_FLAGS , UNIT_NPC_FLAG_NONE );
2009-04-19 21:16:11 +02:00
2009-08-13 05:47:23 +02:00
debug_log ( "TSCR: EscortAI started with %d waypoints. ActiveAttacker = %d, Run = %d, PlayerGUID = %d" , WaypointList . size (), m_bIsActiveAttacker , m_bIsRunning , PlayerGUID );
2008-10-21 13:19:26 -05:00
CurrentWP = WaypointList . begin ();
//Set initial speed
2009-08-11 00:43:06 +02:00
if ( m_bIsRunning )
2008-10-21 13:19:26 -05:00
m_creature -> RemoveUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
2009-04-19 21:16:11 +02:00
else
m_creature -> AddUnitMovementFlag ( MOVEMENTFLAG_WALK_MODE );
2008-10-21 13:19:26 -05:00
IsBeingEscorted = true ;
}