Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1190 lines
35 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "ai_network.h"
  9. #include "ai_default.h"
  10. #include "ai_schedule.h"
  11. #include "ai_hull.h"
  12. #include "ai_node.h"
  13. #include "ai_task.h"
  14. #include "ai_senses.h"
  15. #include "ai_navigator.h"
  16. #include "ai_route.h"
  17. #include "entitylist.h"
  18. #include "soundenvelope.h"
  19. #include "gamerules.h"
  20. #include "ndebugoverlay.h"
  21. #include "soundflags.h"
  22. #include "trains.h"
  23. #include "globalstate.h"
  24. #include "vehicle_base.h"
  25. #include "npc_vehicledriver.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. #define DRIVER_DEBUG_PATH 1
  29. #define DRIVER_DEBUG_PATH_SPLINE 2
  30. //------------------------------------
  31. //
  32. //------------------------------------
  33. ConVar g_debug_vehicledriver( "g_debug_vehicledriver", "0", FCVAR_CHEAT );
  34. BEGIN_DATADESC( CNPC_VehicleDriver )
  35. DEFINE_KEYFIELD( m_iszVehicleName, FIELD_STRING, "vehicle" ),
  36. // DEFINE_FIELD( m_hVehicle, FIELD_EHANDLE ),
  37. // DEFINE_FIELD( m_pVehicleInterface, FIELD_POINTER ),
  38. DEFINE_FIELD( m_hVehicleEntity, FIELD_EHANDLE ),
  39. // DEFINE_FIELD( m_Waypoints, FIELD_???? ),
  40. // DEFINE_FIELD( m_pCurrentWaypoint, FIELD_POINTER ),
  41. // DEFINE_FIELD( m_pNextWaypoint, FIELD_POINTER ),
  42. DEFINE_FIELD( m_vecDesiredVelocity, FIELD_VECTOR ),
  43. DEFINE_FIELD( m_vecDesiredPosition, FIELD_POSITION_VECTOR ),
  44. DEFINE_FIELD( m_vecPrevPoint, FIELD_POSITION_VECTOR ),
  45. DEFINE_FIELD( m_vecPrevPrevPoint, FIELD_POSITION_VECTOR ),
  46. DEFINE_FIELD( m_vecPostPoint, FIELD_POSITION_VECTOR ),
  47. DEFINE_FIELD( m_vecPostPostPoint, FIELD_POSITION_VECTOR ),
  48. DEFINE_FIELD( m_flDistanceAlongSpline, FIELD_FLOAT ),
  49. DEFINE_KEYFIELD( m_flDriversMaxSpeed, FIELD_FLOAT, "drivermaxspeed" ),
  50. DEFINE_KEYFIELD( m_flDriversMinSpeed, FIELD_FLOAT, "driverminspeed" ),
  51. DEFINE_FIELD( m_flMaxSpeed, FIELD_FLOAT ),
  52. DEFINE_FIELD( m_flGoalSpeed, FIELD_FLOAT ),
  53. //DEFINE_KEYFIELD( m_flInitialSpeed, FIELD_FLOAT ),
  54. DEFINE_FIELD( m_flSteering, FIELD_FLOAT ),
  55. // Inputs
  56. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDriversMaxSpeed", InputSetDriversMaxSpeed ),
  57. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetDriversMinSpeed", InputSetDriversMinSpeed ),
  58. DEFINE_INPUTFUNC( FIELD_VOID, "StartForward", InputStartForward ),
  59. DEFINE_INPUTFUNC( FIELD_VOID, "Stop", InputStop ),
  60. DEFINE_INPUTFUNC( FIELD_VOID, "StartFiring", InputStartFiring ),
  61. DEFINE_INPUTFUNC( FIELD_VOID, "StopFiring", InputStopFiring ),
  62. DEFINE_INPUTFUNC( FIELD_STRING, "GotoPathCorner", InputGotoPathCorner ),
  63. END_DATADESC()
  64. LINK_ENTITY_TO_CLASS( npc_vehicledriver, CNPC_VehicleDriver );
  65. //-----------------------------------------------------------------------------
  66. // Purpose:
  67. //-----------------------------------------------------------------------------
  68. CNPC_VehicleDriver::CNPC_VehicleDriver( void )
  69. {
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Purpose:
  73. //-----------------------------------------------------------------------------
  74. CNPC_VehicleDriver::~CNPC_VehicleDriver( void )
  75. {
  76. ClearWaypoints();
  77. }
  78. //------------------------------------------------------------------------------
  79. // Purpose :
  80. //------------------------------------------------------------------------------
  81. void CNPC_VehicleDriver::Spawn( void )
  82. {
  83. Precache( );
  84. BaseClass::Spawn();
  85. CapabilitiesClear();
  86. CapabilitiesAdd( bits_CAP_MOVE_GROUND );
  87. CapabilitiesAdd( bits_CAP_MOVE_SHOOT );
  88. SetModel( "models/roller_vehicledriver.mdl" );
  89. SetHullType(HULL_LARGE);
  90. SetHullSizeNormal();
  91. m_iMaxHealth = m_iHealth = 1;
  92. m_flFieldOfView = VIEW_FIELD_FULL;
  93. SetSolid( SOLID_BBOX );
  94. AddSolidFlags( FSOLID_NOT_SOLID );
  95. SetMoveType( MOVETYPE_NONE );
  96. AddEffects( EF_NODRAW );
  97. m_lifeState = LIFE_ALIVE;
  98. SetCycle( 0 );
  99. ResetSequenceInfo();
  100. AddFlag( FL_NPC );
  101. m_flMaxSpeed = 0;
  102. m_flGoalSpeed = m_flInitialSpeed;
  103. m_vecDesiredVelocity = vec3_origin;
  104. m_vecPrevPoint = vec3_origin;
  105. m_vecPrevPrevPoint = vec3_origin;
  106. m_vecPostPoint = vec3_origin;
  107. m_vecPostPostPoint = vec3_origin;
  108. m_vecDesiredPosition = vec3_origin;
  109. m_flSteering = 45;
  110. m_flDistanceAlongSpline = 0.2;
  111. m_pCurrentWaypoint = m_pNextWaypoint = NULL;
  112. GetNavigator()->SetPathcornerPathfinding( false );
  113. NPCInit();
  114. m_takedamage = DAMAGE_NO;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void CNPC_VehicleDriver::Precache( void )
  120. {
  121. PrecacheModel( "models/roller_vehicledriver.mdl" );
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. //-----------------------------------------------------------------------------
  126. void CNPC_VehicleDriver::Activate( void )
  127. {
  128. BaseClass::Activate();
  129. // Restore doesn't need to do this
  130. if ( m_hVehicleEntity )
  131. return;
  132. // Make sure we've got a vehicle
  133. if ( m_iszVehicleName == NULL_STRING )
  134. {
  135. Warning( "npc_vehicledriver %s has no vehicle to drive.\n", STRING(GetEntityName()) );
  136. UTIL_Remove( this );
  137. return;
  138. }
  139. m_hVehicleEntity = (gEntList.FindEntityByName( NULL, STRING(m_iszVehicleName) ));
  140. if ( !m_hVehicleEntity )
  141. {
  142. Warning( "npc_vehicledriver %s couldn't find his vehicle named %s.\n", STRING(GetEntityName()), STRING(m_iszVehicleName) );
  143. UTIL_Remove( this );
  144. return;
  145. }
  146. m_pVehicleInterface = m_hVehicleEntity->GetServerVehicle();
  147. Assert( m_pVehicleInterface );
  148. if ( !m_pVehicleInterface->NPC_CanDrive() )
  149. {
  150. Warning( "npc_vehicledriver %s doesn't know how to drive vehicle %s.\n", STRING(GetEntityName()), STRING(m_hVehicleEntity->GetEntityName()) );
  151. UTIL_Remove( this );
  152. return;
  153. }
  154. // We've found our vehicle. Move to it and start following it.
  155. SetAbsOrigin( m_hVehicleEntity->WorldSpaceCenter() );
  156. m_pVehicleInterface->NPC_SetDriver( this );
  157. RecalculateSpeeds();
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. //-----------------------------------------------------------------------------
  162. void CNPC_VehicleDriver::OnRestore( void )
  163. {
  164. BaseClass::OnRestore();
  165. if ( m_hVehicleEntity )
  166. {
  167. m_pVehicleInterface = m_hVehicleEntity->GetServerVehicle();
  168. Assert( m_pVehicleInterface );
  169. }
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. //-----------------------------------------------------------------------------
  174. void CNPC_VehicleDriver::UpdateOnRemove( void )
  175. {
  176. // Leave our vehicle
  177. if ( m_pVehicleInterface )
  178. {
  179. m_pVehicleInterface->NPC_SetDriver( NULL );
  180. }
  181. BaseClass::UpdateOnRemove();
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose:
  185. //-----------------------------------------------------------------------------
  186. void CNPC_VehicleDriver::PrescheduleThink( void )
  187. {
  188. if ( !m_hVehicleEntity )
  189. {
  190. m_pVehicleInterface = NULL;
  191. UTIL_Remove( this );
  192. return;
  193. }
  194. // Keep up with my vehicle
  195. SetAbsOrigin( m_hVehicleEntity->WorldSpaceCenter() );
  196. SetAbsAngles( m_hVehicleEntity->GetAbsAngles() );
  197. BaseClass::PrescheduleThink();
  198. if ( m_NPCState == NPC_STATE_IDLE )
  199. {
  200. m_pVehicleInterface->NPC_Brake();
  201. return;
  202. }
  203. // If we've been picked up by something (dropship probably), abort.
  204. if ( m_hVehicleEntity->GetParent() )
  205. {
  206. SetState( NPC_STATE_IDLE );
  207. ClearWaypoints();
  208. SetGoalEnt( NULL );
  209. return;
  210. }
  211. DriveVehicle();
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. int CNPC_VehicleDriver::SelectSchedule( void )
  217. {
  218. // Vehicle driver hangs in the air inside the vehicle, so we never need to fall to ground
  219. ClearCondition( COND_FLOATING_OFF_GROUND );
  220. if ( HasSpawnFlags(SF_VEHICLEDRIVER_INACTIVE) )
  221. {
  222. SetState( NPC_STATE_IDLE );
  223. return SCHED_VEHICLEDRIVER_INACTIVE;
  224. }
  225. if ( GetGoalEnt() )
  226. return SCHED_VEHICLEDRIVER_DRIVE_PATH;
  227. switch ( m_NPCState )
  228. {
  229. case NPC_STATE_IDLE:
  230. break;
  231. case NPC_STATE_ALERT:
  232. break;
  233. case NPC_STATE_COMBAT:
  234. {
  235. if ( HasCondition(COND_NEW_ENEMY) || HasCondition( COND_ENEMY_DEAD ) )
  236. return BaseClass::SelectSchedule();
  237. if ( HasCondition(COND_SEE_ENEMY) )
  238. {
  239. // we can see the enemy
  240. if ( HasCondition(COND_CAN_RANGE_ATTACK2) )
  241. return SCHED_RANGE_ATTACK2;
  242. if ( HasCondition(COND_CAN_RANGE_ATTACK1) )
  243. return SCHED_RANGE_ATTACK1;
  244. // What to do here? Not necessarily easy to face enemy.
  245. //if ( HasCondition(COND_NOT_FACING_ATTACK) )
  246. //return SCHED_COMBAT_FACE;
  247. }
  248. // We can see him, but can't shoot him. Just wait and hope he comes closer.
  249. return SCHED_VEHICLEDRIVER_COMBAT_WAIT;
  250. }
  251. break;
  252. }
  253. return BaseClass::SelectSchedule();
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose:
  257. //-----------------------------------------------------------------------------
  258. int CNPC_VehicleDriver::RangeAttack1Conditions( float flDot, float flDist )
  259. {
  260. // Vehicle not ready to fire again yet?
  261. if ( m_pVehicleInterface->Weapon_PrimaryCanFireAt() > gpGlobals->curtime )
  262. return 0;
  263. // Check weapon range
  264. float flMinRange, flMaxRange;
  265. m_pVehicleInterface->Weapon_PrimaryRanges( &flMinRange, &flMaxRange );
  266. if ( flDist < flMinRange )
  267. return COND_TOO_CLOSE_TO_ATTACK;
  268. if ( flDist > flMaxRange )
  269. return COND_TOO_FAR_TO_ATTACK;
  270. // Don't shoot backwards
  271. Vector vecForward;
  272. Vector vecToTarget = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin());
  273. VectorNormalize(vecToTarget);
  274. m_hVehicleEntity->GetVectors( &vecForward, NULL, NULL );
  275. float flForwardDot = DotProduct( vecForward, vecToTarget );
  276. if ( flForwardDot < 0 && fabs(flDot) < 0.5 )
  277. return COND_NOT_FACING_ATTACK;
  278. return COND_CAN_RANGE_ATTACK1;
  279. }
  280. //=========================================================
  281. // RangeAttack2Conditions
  282. //=========================================================
  283. int CNPC_VehicleDriver::RangeAttack2Conditions( float flDot, float flDist )
  284. {
  285. // Vehicle not ready to fire again yet?
  286. if ( m_pVehicleInterface->Weapon_SecondaryCanFireAt() > gpGlobals->curtime )
  287. return 0;
  288. // Check weapon range
  289. float flMinRange, flMaxRange;
  290. m_pVehicleInterface->Weapon_SecondaryRanges( &flMinRange, &flMaxRange );
  291. if ( flDist < flMinRange )
  292. return COND_TOO_CLOSE_TO_ATTACK;
  293. if ( flDist > flMaxRange )
  294. return COND_TOO_FAR_TO_ATTACK;
  295. return COND_CAN_RANGE_ATTACK2;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. //-----------------------------------------------------------------------------
  300. int CNPC_VehicleDriver::TranslateSchedule( int scheduleType )
  301. {
  302. switch ( scheduleType )
  303. {
  304. case SCHED_COMBAT_FACE:
  305. {
  306. // Vehicles can't rotate, so don't try and face
  307. return TranslateSchedule( SCHED_CHASE_ENEMY );
  308. }
  309. break;
  310. case SCHED_ALERT_FACE:
  311. {
  312. // Vehicles can't rotate, so don't try and face
  313. return SCHED_ALERT_STAND;
  314. }
  315. break;
  316. case SCHED_CHASE_ENEMY_FAILED:
  317. case SCHED_FAIL:
  318. {
  319. return SCHED_FAIL;
  320. }
  321. break;
  322. }
  323. return BaseClass::TranslateSchedule(scheduleType);
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose:
  327. // Input : *pTask -
  328. //-----------------------------------------------------------------------------
  329. void CNPC_VehicleDriver::StartTask( const Task_t *pTask )
  330. {
  331. switch( pTask->iTask )
  332. {
  333. case TASK_RUN_PATH:
  334. case TASK_WALK_PATH:
  335. TaskComplete();
  336. break;
  337. case TASK_FACE_IDEAL:
  338. case TASK_FACE_ENEMY:
  339. {
  340. // Vehicle ignores face commands, since it can't rotate on the spot.
  341. TaskComplete();
  342. }
  343. break;
  344. case TASK_VEHICLEDRIVER_GET_PATH:
  345. {
  346. if ( !GetGoalEnt() )
  347. {
  348. TaskFail( FAIL_NO_TARGET );
  349. return;
  350. }
  351. CheckForTeleport();
  352. if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH )
  353. {
  354. NDebugOverlay::Box( GetGoalEnt()->GetAbsOrigin(), -Vector(50,50,50), Vector(50,50,50), 255,255,255, true, 5);
  355. }
  356. AI_NavGoal_t goal( GOALTYPE_PATHCORNER, GetGoalEnt()->GetLocalOrigin(), ACT_WALK, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
  357. if ( !GetNavigator()->SetGoal( goal ) )
  358. {
  359. TaskFail( FAIL_NO_ROUTE );
  360. return;
  361. }
  362. TaskComplete();
  363. }
  364. break;
  365. case TASK_WAIT_FOR_MOVEMENT:
  366. {
  367. if (GetNavigator()->GetGoalType() == GOALTYPE_NONE)
  368. {
  369. TaskComplete();
  370. GetNavigator()->StopMoving(); // Stop moving
  371. }
  372. else if (!GetNavigator()->IsGoalActive())
  373. {
  374. SetIdealActivity( GetStoppedActivity() );
  375. }
  376. else
  377. {
  378. // Check validity of goal type
  379. ValidateNavGoal();
  380. }
  381. }
  382. break;
  383. default:
  384. BaseClass::StartTask( pTask );
  385. break;
  386. }
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose:
  390. //-----------------------------------------------------------------------------
  391. void CNPC_VehicleDriver::RunTask( const Task_t *pTask )
  392. {
  393. switch( pTask->iTask )
  394. {
  395. case TASK_RANGE_ATTACK1:
  396. {
  397. // Vehicle driver has no animations, so fire a burst at the target
  398. CBaseEntity *pEnemy = GetEnemy();
  399. if ( pEnemy )
  400. {
  401. // TODO: Get a bodytarget from the firing point of the gun in the vehicle
  402. Vector vecTarget = GetEnemy()->BodyTarget( GetAbsOrigin(), false );
  403. m_pVehicleInterface->NPC_AimPrimaryWeapon( vecTarget );
  404. m_pVehicleInterface->NPC_PrimaryFire();
  405. TaskComplete();
  406. }
  407. else
  408. {
  409. TaskFail(FAIL_NO_ENEMY);
  410. return;
  411. }
  412. }
  413. break;
  414. case TASK_RANGE_ATTACK2:
  415. {
  416. // Vehicle driver has no animations, so fire a burst at the target
  417. CBaseEntity *pEnemy = GetEnemy();
  418. if ( pEnemy )
  419. {
  420. // TODO: Get a bodytarget from the firing point of the gun in the vehicle
  421. Vector vecTarget = GetEnemy()->BodyTarget( GetAbsOrigin(), false );
  422. m_pVehicleInterface->NPC_AimSecondaryWeapon( vecTarget );
  423. m_pVehicleInterface->NPC_SecondaryFire();
  424. TaskComplete();
  425. }
  426. else
  427. {
  428. TaskFail(FAIL_NO_ENEMY);
  429. return;
  430. }
  431. }
  432. break;
  433. case TASK_WAIT_FOR_MOVEMENT:
  434. {
  435. BaseClass::RunTask( pTask );
  436. if ( HasCondition(COND_SEE_ENEMY) )
  437. {
  438. // we can see the enemy
  439. if ( HasCondition(COND_CAN_RANGE_ATTACK2) )
  440. {
  441. ChainRunTask( TASK_RANGE_ATTACK2, pTask->flTaskData );
  442. }
  443. if ( HasCondition(COND_CAN_RANGE_ATTACK1) )
  444. {
  445. ChainRunTask( TASK_RANGE_ATTACK1, pTask->flTaskData );
  446. }
  447. }
  448. }
  449. break;
  450. default:
  451. BaseClass::RunTask( pTask );
  452. break;
  453. }
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose:
  457. //-----------------------------------------------------------------------------
  458. void CNPC_VehicleDriver::GatherEnemyConditions( CBaseEntity *pEnemy )
  459. {
  460. BaseClass::GatherEnemyConditions(pEnemy);
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose: Overridden because if the player is a criminal, we hate them.
  464. //-----------------------------------------------------------------------------
  465. Disposition_t CNPC_VehicleDriver::IRelationType(CBaseEntity *pTarget)
  466. {
  467. // If it's the player and they are a criminal, we hate them.
  468. if ( pTarget && pTarget->Classify() == CLASS_PLAYER)
  469. {
  470. if (GlobalEntity_GetState("gordon_precriminal") == GLOBAL_ON)
  471. {
  472. return(D_NU);
  473. }
  474. }
  475. return(BaseClass::IRelationType(pTarget));
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. //-----------------------------------------------------------------------------
  480. bool CNPC_VehicleDriver::OverrideMove( float flInterval )
  481. {
  482. if ( !m_hVehicleEntity )
  483. return true;
  484. // If we don't have a maxspeed, we've been stopped, so abort early
  485. // Or we've been picked up by something (dropship probably).
  486. if ( !m_flMaxSpeed || m_hVehicleEntity->GetParent() )
  487. {
  488. m_pVehicleInterface->NPC_Brake();
  489. return true;
  490. }
  491. // -----------------------------------------------------------------
  492. // If I have a route, keep it updated and move toward target
  493. // ------------------------------------------------------------------
  494. if (GetNavigator()->IsGoalActive())
  495. {
  496. if ( OverridePathMove( flInterval ) )
  497. return true;
  498. }
  499. return true;
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose:
  503. //-----------------------------------------------------------------------------
  504. void CNPC_VehicleDriver::CalculatePostPoints( void )
  505. {
  506. m_vecPostPoint = m_vecDesiredPosition;
  507. m_vecPostPostPoint = m_vecDesiredPosition;
  508. // If we have a waypoint beyond our current, use it instead.
  509. if ( !GetNavigator()->CurWaypointIsGoal() )
  510. {
  511. AI_Waypoint_t *pCurWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();
  512. m_vecPostPoint = pCurWaypoint->GetNext()->GetPos();
  513. if ( pCurWaypoint->GetNext()->GetNext() )
  514. {
  515. m_vecPostPostPoint = pCurWaypoint->GetNext()->GetNext()->GetPos();
  516. }
  517. else
  518. {
  519. m_vecPostPostPoint = m_vecPostPoint;
  520. }
  521. }
  522. }
  523. //-----------------------------------------------------------------------------
  524. // Purpose: Destroy our current waypoints
  525. //-----------------------------------------------------------------------------
  526. void CNPC_VehicleDriver::ClearWaypoints( void )
  527. {
  528. m_vecDesiredPosition = vec3_origin;
  529. if ( m_pCurrentWaypoint )
  530. {
  531. delete m_pCurrentWaypoint;
  532. m_pCurrentWaypoint = NULL;
  533. }
  534. if ( m_pNextWaypoint )
  535. {
  536. delete m_pNextWaypoint;
  537. m_pNextWaypoint = NULL;
  538. }
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose: We've hit a waypoint. Handle it, and return true if this is the
  542. // end of the path.
  543. //-----------------------------------------------------------------------------
  544. bool CNPC_VehicleDriver::WaypointReached( void )
  545. {
  546. // We reached our current waypoint.
  547. m_vecPrevPrevPoint = m_vecPrevPoint;
  548. m_vecPrevPoint = GetAbsOrigin();
  549. // If we've got to our goal, we're done here.
  550. if ( GetNavigator()->CurWaypointIsGoal() )
  551. {
  552. // Necessary for InPass outputs to be fired, is a no-op otherwise
  553. GetNavigator()->AdvancePath();
  554. // Stop pathing
  555. ClearWaypoints();
  556. TaskComplete();
  557. SetGoalEnt( NULL );
  558. return true;
  559. }
  560. AI_Waypoint_t *pCurWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();
  561. if ( !pCurWaypoint )
  562. return false;
  563. // Check to see if the waypoint wants us to change speed
  564. if ( pCurWaypoint->Flags() & bits_WP_TO_PATHCORNER )
  565. {
  566. CBaseEntity *pEntity = pCurWaypoint->hPathCorner;
  567. if ( pEntity )
  568. {
  569. if ( pEntity->m_flSpeed > 0 )
  570. {
  571. if ( pEntity->m_flSpeed <= 1.0 )
  572. {
  573. m_flDriversMaxSpeed = pEntity->m_flSpeed;
  574. RecalculateSpeeds();
  575. }
  576. else
  577. {
  578. Warning("path_track %s tried to tell the npc_vehicledriver to set speed to %.3f. npc_vehicledriver only accepts values between 0 and 1.\n", STRING(pEntity->GetEntityName()), pEntity->m_flSpeed );
  579. }
  580. }
  581. }
  582. }
  583. // Get the waypoints for the next part of the path
  584. GetNavigator()->AdvancePath();
  585. if ( !GetNavigator()->GetPath()->GetCurWaypoint() )
  586. {
  587. ClearWaypoints();
  588. TaskComplete();
  589. SetGoalEnt( NULL );
  590. return true;
  591. }
  592. m_vecDesiredPosition = GetNavigator()->GetCurWaypointPos();
  593. CalculatePostPoints();
  594. // Move to the next waypoint
  595. delete m_pCurrentWaypoint;
  596. m_pCurrentWaypoint = m_pNextWaypoint;
  597. m_Waypoints[1] = new CVehicleWaypoint( m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint, m_vecPostPostPoint );
  598. m_pNextWaypoint = m_Waypoints[1];
  599. // Drop the spline marker back
  600. m_flDistanceAlongSpline = MAX( 0, m_flDistanceAlongSpline - 1.0 );
  601. CheckForTeleport();
  602. return false;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose:
  606. //-----------------------------------------------------------------------------
  607. bool CNPC_VehicleDriver::OverridePathMove( float flInterval )
  608. {
  609. // Setup our initial path data if we've just started running a path
  610. if ( !m_pCurrentWaypoint )
  611. {
  612. m_vecPrevPoint = GetAbsOrigin();
  613. m_vecPrevPrevPoint = GetAbsOrigin();
  614. m_vecDesiredPosition = GetNavigator()->GetCurWaypointPos();
  615. CalculatePostPoints();
  616. // Init our two waypoints
  617. m_Waypoints[0] = new CVehicleWaypoint( m_vecPrevPrevPoint, m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint );
  618. m_Waypoints[1] = new CVehicleWaypoint( m_vecPrevPoint, m_vecDesiredPosition, m_vecPostPoint, m_vecPostPostPoint );
  619. m_pCurrentWaypoint = m_Waypoints[0];
  620. m_pNextWaypoint = m_Waypoints[1];
  621. m_flDistanceAlongSpline = 0.2;
  622. }
  623. // Have we reached our target? See if we've passed the current waypoint's plane.
  624. Vector vecAbsMins, vecAbsMaxs;
  625. CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
  626. if ( BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pCurrentWaypoint->planeWaypoint ) == 3 )
  627. {
  628. if ( WaypointReached() )
  629. return true;
  630. }
  631. // Did we bypass it and reach the next one already?
  632. if ( m_pNextWaypoint && BoxOnPlaneSide( vecAbsMins, vecAbsMaxs, &m_pNextWaypoint->planeWaypoint ) == 3 )
  633. {
  634. if ( WaypointReached() )
  635. return true;
  636. }
  637. // We may have just teleported, so check to make sure we have a waypoint
  638. if ( !m_pCurrentWaypoint || !m_pNextWaypoint )
  639. return false;
  640. // Figure out which spline we're trucking along
  641. CVehicleWaypoint *pCurrentSplineBeingTraversed = m_pCurrentWaypoint;
  642. if ( m_flDistanceAlongSpline > 1 )
  643. {
  644. pCurrentSplineBeingTraversed = m_pNextWaypoint;
  645. }
  646. // Get our current speed, and check it against the length of the spline to know how far to advance our marker
  647. AngularImpulse angVel;
  648. Vector vecVelocity;
  649. IPhysicsObject *pVehiclePhysics = m_hVehicleEntity->VPhysicsGetObject();
  650. if( !pVehiclePhysics )
  651. {
  652. // I think my vehicle has been destroyed.
  653. return false;
  654. }
  655. pVehiclePhysics->GetVelocity( &vecVelocity, &angVel );
  656. float flSpeed = vecVelocity.Length();
  657. float flIncTime = gpGlobals->curtime - GetLastThink();
  658. float flIncrement = flIncTime * (flSpeed / pCurrentSplineBeingTraversed->GetLength());
  659. // Now advance our point along the spline
  660. m_flDistanceAlongSpline = clamp( m_flDistanceAlongSpline + flIncrement, 0, 2);
  661. if ( m_flDistanceAlongSpline > 1 )
  662. {
  663. // We crossed the spline boundary
  664. pCurrentSplineBeingTraversed = m_pNextWaypoint;
  665. }
  666. Vector vSplinePoint = pCurrentSplineBeingTraversed->GetPointAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline );
  667. Vector vSplineTangent = pCurrentSplineBeingTraversed->GetTangentAt( m_flDistanceAlongSpline > 1 ? m_flDistanceAlongSpline-1 : m_flDistanceAlongSpline );
  668. // Now that we've got the target spline point & tangent, use it to decide what our desired velocity is.
  669. // If we're close to the tangent, just use the tangent. Otherwise, Lerp towards it.
  670. Vector vecToDesired = (vSplinePoint - GetAbsOrigin());
  671. float flDistToDesired = VectorNormalize( vecToDesired );
  672. float flTangentLength = VectorNormalize( vSplineTangent );
  673. if ( flDistToDesired > (flTangentLength * 0.75) )
  674. {
  675. m_vecDesiredVelocity = vecToDesired * flTangentLength;
  676. }
  677. else
  678. {
  679. VectorLerp( vSplineTangent, vecToDesired * flTangentLength, (flDistToDesired / (flTangentLength * 0.5)), m_vecDesiredVelocity );
  680. }
  681. // Decrease speed according to the turn we're trying to make
  682. Vector vecRight;
  683. m_hVehicleEntity->GetVectors( NULL, &vecRight, NULL );
  684. Vector vecNormVel = m_vecDesiredVelocity;
  685. VectorNormalize( vecNormVel );
  686. float flDotRight = DotProduct( vecRight, vecNormVel );
  687. flSpeed = (1.0 - fabs(flDotRight));
  688. // Don't go slower than we've been told to go
  689. if ( flSpeed < m_flDriversMinSpeed )
  690. {
  691. flSpeed = m_flDriversMinSpeed;
  692. }
  693. m_vecDesiredVelocity = vecNormVel * (flSpeed * m_flMaxSpeed);
  694. // Bunch o'debug
  695. if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH )
  696. {
  697. NDebugOverlay::Box( m_vecPrevPrevPoint, -Vector(15,15,15), Vector(15,15,15), 192,0,0, true, 0.1);
  698. NDebugOverlay::Box( m_vecPrevPoint, -Vector(20,20,20), Vector(20,20,20), 255,0,0, true, 0.1);
  699. NDebugOverlay::Box( m_vecPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,192,0, true, 0.1);
  700. NDebugOverlay::Box( m_vecPostPostPoint, -Vector(20,20,20), Vector(20,20,20), 0,128,0, true, 0.1);
  701. NDebugOverlay::Box( vSplinePoint, -Vector(10,10,10), Vector(10,10,10), 0,0,255, true, 0.1);
  702. NDebugOverlay::Line( vSplinePoint, vSplinePoint + (vSplineTangent * 40), 0,0,255, true, 0.1);
  703. //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[0], pCurrentSplineBeingTraversed->splinePoints[1], 30, 255,255,255,0, false, 0.1f );
  704. //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[1], pCurrentSplineBeingTraversed->splinePoints[2], 20, 255,255,255,0, false, 0.1f );
  705. //NDebugOverlay::HorzArrow( pCurrentSplineBeingTraversed->splinePoints[2], pCurrentSplineBeingTraversed->splinePoints[3], 10, 255,255,255,0, false, 0.1f );
  706. // Draw the plane we're checking against for waypoint passing
  707. Vector vecPlaneRight;
  708. CrossProduct( m_pCurrentWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight );
  709. Vector vecPlane = m_pCurrentWaypoint->splinePoints[2];
  710. NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 255,0,0, true, 0.1);
  711. // Draw the next plane too
  712. CrossProduct( m_pNextWaypoint->planeWaypoint.normal, Vector(0,0,1), vecPlaneRight );
  713. vecPlane = m_pNextWaypoint->splinePoints[2];
  714. NDebugOverlay::Line( vecPlane + (vecPlaneRight * -100), vecPlane + (vecPlaneRight * 100), 192,0,0, true, 0.1);
  715. }
  716. if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH_SPLINE )
  717. {
  718. for ( int i = 0; i < 10; i++ )
  719. {
  720. Vector vecTarget = m_pCurrentWaypoint->GetPointAt( 0.1 * i );
  721. Vector vecTangent = m_pCurrentWaypoint->GetTangentAt( 0.1 * i );
  722. VectorNormalize(vecTangent);
  723. NDebugOverlay::Box( vecTarget, -Vector(10,10,10), Vector(10,10,10), 255,0,0, true, 0.1 );
  724. NDebugOverlay::Line( vecTarget, vecTarget + (vecTangent * 10), 255,255,0, true, 0.1);
  725. }
  726. }
  727. return true;
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose: This takes the current place the NPC's trying to get to, figures out
  731. // what keys to press to get the vehicle to go there, and then sends
  732. // them to the vehicle.
  733. //-----------------------------------------------------------------------------
  734. void CNPC_VehicleDriver::DriveVehicle( void )
  735. {
  736. AngularImpulse angVel;
  737. Vector vecVelocity;
  738. IPhysicsObject *pVehiclePhysics = m_hVehicleEntity->VPhysicsGetObject();
  739. if ( !pVehiclePhysics )
  740. return;
  741. pVehiclePhysics->GetVelocity( &vecVelocity, &angVel );
  742. float flSpeed = VectorNormalize( vecVelocity );
  743. // If we have no target position to drive to, brake to a halt
  744. if ( !m_flMaxSpeed || m_vecDesiredPosition == vec3_origin )
  745. {
  746. if ( flSpeed > 1 )
  747. {
  748. m_pVehicleInterface->NPC_Brake();
  749. }
  750. return;
  751. }
  752. if ( g_debug_vehicledriver.GetInt() & DRIVER_DEBUG_PATH )
  753. {
  754. NDebugOverlay::Box(m_vecDesiredPosition, -Vector(20,20,20), Vector(20,20,20), 0,255,0, true, 0.1);
  755. NDebugOverlay::Line(GetAbsOrigin(), GetAbsOrigin() + m_vecDesiredVelocity, 0,255,0, true, 0.1);
  756. }
  757. m_flGoalSpeed = VectorNormalize(m_vecDesiredVelocity);
  758. // Is our target in front or behind us?
  759. Vector vecForward, vecRight;
  760. m_hVehicleEntity->GetVectors( &vecForward, &vecRight, NULL );
  761. float flDot = DotProduct( vecForward, m_vecDesiredVelocity );
  762. bool bBehind = ( flDot < 0 );
  763. float flVelDot = DotProduct( vecVelocity, m_vecDesiredVelocity );
  764. bool bGoingWrongWay = ( flVelDot < 0 );
  765. // Figure out whether we should accelerate / decelerate
  766. if ( bGoingWrongWay || (flSpeed < m_flGoalSpeed) )
  767. {
  768. // If it's behind us, go backwards not forwards
  769. if ( bBehind )
  770. {
  771. m_pVehicleInterface->NPC_ThrottleReverse();
  772. }
  773. else
  774. {
  775. m_pVehicleInterface->NPC_ThrottleForward();
  776. }
  777. }
  778. else
  779. {
  780. // Brake if we're go significantly too fast
  781. if ( (flSpeed - 200) > m_flGoalSpeed )
  782. {
  783. m_pVehicleInterface->NPC_Brake();
  784. }
  785. else
  786. {
  787. m_pVehicleInterface->NPC_ThrottleCenter();
  788. }
  789. }
  790. // Do we need to turn?
  791. float flDotRight = DotProduct( vecRight, m_vecDesiredVelocity );
  792. if ( bBehind )
  793. {
  794. // If we're driving backwards, flip our turning
  795. flDotRight *= -1;
  796. }
  797. // Map it to the vehicle's steering
  798. flDotRight *= (m_flSteering / 90);
  799. if ( flDotRight < 0 )
  800. {
  801. // Turn left
  802. m_pVehicleInterface->NPC_TurnLeft( -flDotRight );
  803. }
  804. else if ( flDotRight > 0 )
  805. {
  806. // Turn right
  807. m_pVehicleInterface->NPC_TurnRight( flDotRight );
  808. }
  809. else
  810. {
  811. m_pVehicleInterface->NPC_TurnCenter();
  812. }
  813. }
  814. //-----------------------------------------------------------------------------
  815. // Purpose: Check to see if we should teleport to the current path corner
  816. //-----------------------------------------------------------------------------
  817. void CNPC_VehicleDriver::CheckForTeleport( void )
  818. {
  819. if ( !GetGoalEnt() )
  820. return;
  821. CPathTrack *pTrack = dynamic_cast<CPathTrack *>( GetGoalEnt() );
  822. if ( !pTrack )
  823. return;
  824. // Does it have the teleport flag set?
  825. if ( pTrack->HasSpawnFlags( SF_PATH_TELEPORT ) )
  826. {
  827. AddEffects( EF_NOINTERP );
  828. // Teleport the vehicle to the pathcorner
  829. Vector vecMins, vecMaxs;
  830. vecMins = m_hVehicleEntity->CollisionProp()->OBBMins();
  831. vecMaxs = m_hVehicleEntity->CollisionProp()->OBBMaxs();
  832. Vector vecTarget = pTrack->GetAbsOrigin() - (vecMins + vecMaxs) * 0.5;
  833. vecTarget.z += ((vecMaxs.z - vecMins.z) * 0.5) + 8; // Safety buffer
  834. // Orient it to face the next point
  835. QAngle vecAngles = pTrack->GetAbsAngles();
  836. Vector vecToTarget = vec3_origin;
  837. if ( pTrack->GetNext() )
  838. {
  839. vecToTarget = (pTrack->GetNext()->GetAbsOrigin() - pTrack->GetAbsOrigin());
  840. VectorNormalize( vecToTarget );
  841. // Vehicles are rotated 90 degrees
  842. VectorAngles( vecToTarget, vecAngles );
  843. vecAngles[YAW] -= 90;
  844. }
  845. m_hVehicleEntity->Teleport( &vecTarget, &vecAngles, &vec3_origin );
  846. // Teleport the driver
  847. SetAbsOrigin( m_hVehicleEntity->WorldSpaceCenter() );
  848. SetAbsAngles( m_hVehicleEntity->GetAbsAngles() );
  849. m_vecPrevPoint = pTrack->GetAbsOrigin();
  850. // Move to the next waypoint, we've reached this one
  851. if ( GetNavigator()->GetPath() )
  852. {
  853. WaypointReached();
  854. }
  855. // Clear our waypoints, because the next waypoint is certainly invalid now.
  856. ClearWaypoints();
  857. }
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose:
  861. //-----------------------------------------------------------------------------
  862. float CNPC_VehicleDriver::GetDefaultNavGoalTolerance()
  863. {
  864. return 48;
  865. }
  866. //-----------------------------------------------------------------------------
  867. // Purpose:
  868. //-----------------------------------------------------------------------------
  869. void CNPC_VehicleDriver::RecalculateSpeeds( void )
  870. {
  871. // Get data from the vehicle
  872. const vehicleparams_t *pParams = m_pVehicleInterface->GetVehicleParams();
  873. if ( pParams )
  874. {
  875. m_flMaxSpeed = pParams->engine.maxSpeed * m_flDriversMaxSpeed;
  876. m_flSteering = pParams->steering.degreesSlow;
  877. }
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Purpose:
  881. //-----------------------------------------------------------------------------
  882. void CNPC_VehicleDriver::InputSetDriversMaxSpeed( inputdata_t &inputdata )
  883. {
  884. m_flDriversMaxSpeed = inputdata.value.Float();
  885. RecalculateSpeeds();
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Purpose:
  889. //-----------------------------------------------------------------------------
  890. void CNPC_VehicleDriver::InputSetDriversMinSpeed( inputdata_t &inputdata )
  891. {
  892. m_flDriversMinSpeed = inputdata.value.Float();
  893. RecalculateSpeeds();
  894. }
  895. //-----------------------------------------------------------------------------
  896. // Purpose:
  897. //-----------------------------------------------------------------------------
  898. void CNPC_VehicleDriver::InputStartForward( inputdata_t &inputdata )
  899. {
  900. CLEARBITS( m_spawnflags, SF_VEHICLEDRIVER_INACTIVE );
  901. if ( m_NPCState == NPC_STATE_IDLE )
  902. {
  903. SetState( NPC_STATE_ALERT );
  904. }
  905. SetCondition( COND_PROVOKED );
  906. RecalculateSpeeds();
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose: Tell the driver to stop moving
  910. //-----------------------------------------------------------------------------
  911. void CNPC_VehicleDriver::InputStop( inputdata_t &inputdata )
  912. {
  913. m_flMaxSpeed = 0;
  914. }
  915. //-----------------------------------------------------------------------------
  916. // Purpose: Tell the driver to start firing at targets
  917. //-----------------------------------------------------------------------------
  918. void CNPC_VehicleDriver::InputStartFiring( inputdata_t &inputdata )
  919. {
  920. CLEARBITS( m_spawnflags, SF_VEHICLEDRIVER_INACTIVE );
  921. SetCondition( COND_PROVOKED );
  922. float flMinRange, flMaxRange;
  923. // If the vehicle has a weapon, set our capability
  924. if ( m_pVehicleInterface->NPC_HasPrimaryWeapon() )
  925. {
  926. CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 );
  927. m_pVehicleInterface->Weapon_PrimaryRanges( &flMinRange, &flMaxRange );
  928. // Ensure the look distances is long enough
  929. if ( m_flDistTooFar < flMaxRange || GetSenses()->GetDistLook() < flMaxRange )
  930. {
  931. m_flDistTooFar = flMaxRange;
  932. SetDistLook( flMaxRange );
  933. }
  934. }
  935. if ( m_pVehicleInterface->NPC_HasSecondaryWeapon() )
  936. {
  937. CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK2 );
  938. m_pVehicleInterface->Weapon_SecondaryRanges( &flMinRange, &flMaxRange );
  939. // Ensure the look distances is long enough
  940. if ( m_flDistTooFar < flMaxRange || GetSenses()->GetDistLook() < flMaxRange )
  941. {
  942. m_flDistTooFar = flMaxRange;
  943. SetDistLook( flMaxRange );
  944. }
  945. }
  946. }
  947. //-----------------------------------------------------------------------------
  948. // Purpose: Tell the driver to stop firing at targets
  949. //-----------------------------------------------------------------------------
  950. void CNPC_VehicleDriver::InputStopFiring( inputdata_t &inputdata )
  951. {
  952. // If the vehicle has a weapon, set our capability
  953. CapabilitiesRemove( bits_CAP_INNATE_RANGE_ATTACK1 );
  954. CapabilitiesRemove( bits_CAP_INNATE_RANGE_ATTACK2 );
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Purpose:
  958. //-----------------------------------------------------------------------------
  959. void CNPC_VehicleDriver::InputGotoPathCorner( inputdata_t &inputdata )
  960. {
  961. string_t iszPathName = inputdata.value.StringID();
  962. if ( iszPathName != NULL_STRING )
  963. {
  964. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, iszPathName );
  965. if ( !pEntity )
  966. {
  967. Warning("npc_vehicledriver %s couldn't find entity named %s\n", STRING(GetEntityName()), STRING(iszPathName) );
  968. return;
  969. }
  970. ClearWaypoints();
  971. // Drive to the point
  972. SetGoalEnt( pEntity );
  973. if ( m_NPCState == NPC_STATE_IDLE )
  974. {
  975. SetState( NPC_STATE_ALERT );
  976. }
  977. SetCondition( COND_PROVOKED );
  978. // Force him to start forward
  979. InputStartForward( inputdata );
  980. }
  981. }
  982. //-----------------------------------------------------------------------------
  983. //
  984. // Schedules
  985. //
  986. //-----------------------------------------------------------------------------
  987. AI_BEGIN_CUSTOM_NPC( npc_vehicledriver, CNPC_VehicleDriver )
  988. //Tasks
  989. DECLARE_TASK( TASK_VEHICLEDRIVER_GET_PATH )
  990. // Schedules
  991. DEFINE_SCHEDULE
  992. (
  993. SCHED_VEHICLEDRIVER_INACTIVE,
  994. " Tasks"
  995. " TASK_WAIT_INDEFINITE 0"
  996. ""
  997. " Interrupts"
  998. " COND_PROVOKED"
  999. )
  1000. DEFINE_SCHEDULE
  1001. (
  1002. SCHED_VEHICLEDRIVER_COMBAT_WAIT,
  1003. " Tasks"
  1004. " TASK_WAIT 5"
  1005. ""
  1006. " Interrupts"
  1007. " COND_NEW_ENEMY"
  1008. " COND_LIGHT_DAMAGE"
  1009. " COND_HEAVY_DAMAGE"
  1010. " COND_PROVOKED"
  1011. " COND_CAN_RANGE_ATTACK1"
  1012. " COND_CAN_RANGE_ATTACK2"
  1013. )
  1014. DEFINE_SCHEDULE
  1015. (
  1016. SCHED_VEHICLEDRIVER_DRIVE_PATH,
  1017. " Tasks"
  1018. " TASK_VEHICLEDRIVER_GET_PATH 0"
  1019. " TASK_WALK_PATH 9999"
  1020. " TASK_WAIT_FOR_MOVEMENT 0"
  1021. " TASK_WAIT_PVS 0"
  1022. ""
  1023. " Interrupts"
  1024. " COND_NEW_ENEMY"
  1025. " COND_PROVOKED"
  1026. )
  1027. AI_END_CUSTOM_NPC()