Team Fortress 2 Source Code as on 22/4/2020
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.

783 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ai_behavior_police.h"
  8. #include "ai_navigator.h"
  9. #include "ai_memory.h"
  10. #include "collisionutils.h"
  11. #include "npc_metropolice.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. BEGIN_DATADESC( CAI_PolicingBehavior )
  15. DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
  16. DEFINE_FIELD( m_bStartPolicing, FIELD_BOOLEAN ),
  17. DEFINE_FIELD( m_hPoliceGoal, FIELD_EHANDLE ),
  18. DEFINE_FIELD( m_flNextHarassTime, FIELD_TIME ),
  19. DEFINE_FIELD( m_flAggressiveTime, FIELD_TIME ),
  20. DEFINE_FIELD( m_nNumWarnings, FIELD_INTEGER ),
  21. DEFINE_FIELD( m_bTargetIsHostile, FIELD_BOOLEAN ),
  22. DEFINE_FIELD( m_flTargetHostileTime,FIELD_TIME ),
  23. END_DATADESC();
  24. CAI_PolicingBehavior::CAI_PolicingBehavior( void )
  25. {
  26. m_bEnabled = false;
  27. m_nNumWarnings = 0;
  28. m_bTargetIsHostile = false;
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Purpose:
  32. // Output : Returns true on success, false on failure.
  33. //-----------------------------------------------------------------------------
  34. bool CAI_PolicingBehavior::TargetIsHostile( void )
  35. {
  36. if ( ( m_flTargetHostileTime < gpGlobals->curtime ) && ( !m_bTargetIsHostile ) )
  37. return false;
  38. return true;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. // Input : *pGoal -
  43. //-----------------------------------------------------------------------------
  44. void CAI_PolicingBehavior::Enable( CAI_PoliceGoal *pGoal )
  45. {
  46. m_hPoliceGoal = pGoal;
  47. m_bEnabled = true;
  48. m_bStartPolicing = true;
  49. // Update ourselves immediately
  50. GetOuter()->ClearSchedule( "Enable police behavior" );
  51. //NotifyChangeBehaviorStatus( GetOuter()->IsInAScript() );
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. void CAI_PolicingBehavior::Disable( void )
  57. {
  58. m_hPoliceGoal = NULL;
  59. m_bEnabled = false;
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose:
  63. // Output : Returns true on success, false on failure.
  64. //-----------------------------------------------------------------------------
  65. bool CAI_PolicingBehavior::CanSelectSchedule( void )
  66. {
  67. // Must be activated and valid
  68. if ( IsEnabled() == false || !m_hPoliceGoal || !m_hPoliceGoal->GetTarget() )
  69. return false;
  70. return true;
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose:
  74. // Input : false -
  75. //-----------------------------------------------------------------------------
  76. void CAI_PolicingBehavior::HostSetBatonState( bool state )
  77. {
  78. // If we're a cop, turn the baton on
  79. CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(GetOuter());
  80. if ( pCop != NULL )
  81. {
  82. pCop->SetBatonState( state );
  83. pCop->SetTarget( m_hPoliceGoal->GetTarget() );
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. // Input : false -
  89. //-----------------------------------------------------------------------------
  90. bool CAI_PolicingBehavior::HostBatonIsOn( void )
  91. {
  92. // If we're a cop, turn the baton on
  93. CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(GetOuter());
  94. if ( pCop )
  95. return pCop->BatonActive();
  96. return false;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. //-----------------------------------------------------------------------------
  101. void CAI_PolicingBehavior::HostSpeakSentence( const char *pSentence, SentencePriority_t nSoundPriority, SentenceCriteria_t nCriteria )
  102. {
  103. // If we're a cop, turn the baton on
  104. CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(GetOuter());
  105. if ( pCop != NULL )
  106. {
  107. CAI_Sentence< CNPC_MetroPolice > *pSentences = pCop->GetSentences();
  108. pSentences->Speak( pSentence, nSoundPriority, nCriteria );
  109. }
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. void CAI_PolicingBehavior::BuildScheduleTestBits( void )
  115. {
  116. if ( IsCurSchedule( SCHED_IDLE_STAND ) || IsCurSchedule( SCHED_ALERT_STAND ) )
  117. {
  118. if ( m_flNextHarassTime < gpGlobals->curtime )
  119. {
  120. GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_POLICE_TARGET_TOO_CLOSE_HARASS ) );
  121. }
  122. GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS ) );
  123. }
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. //-----------------------------------------------------------------------------
  128. void CAI_PolicingBehavior::GatherConditions( void )
  129. {
  130. BaseClass::GatherConditions();
  131. // Mapmaker may have removed our goal while we're running our schedule
  132. if ( !m_hPoliceGoal )
  133. {
  134. Disable();
  135. return;
  136. }
  137. ClearCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS );
  138. ClearCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
  139. CBaseEntity *pTarget = m_hPoliceGoal->GetTarget();
  140. if ( pTarget == NULL )
  141. {
  142. DevMsg( "ai_goal_police with NULL target entity!\n" );
  143. return;
  144. }
  145. // See if we need to knock out our target immediately
  146. if ( ShouldKnockOutTarget( pTarget ) )
  147. {
  148. SetCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
  149. }
  150. float flDistSqr = ( m_hPoliceGoal->WorldSpaceCenter() - pTarget->WorldSpaceCenter() ).Length2DSqr();
  151. float radius = ( m_hPoliceGoal->GetRadius() * PATROL_RADIUS_RATIO );
  152. float zDiff = fabs( m_hPoliceGoal->WorldSpaceCenter().z - pTarget->WorldSpaceCenter().z );
  153. // If we're too far away, don't bother
  154. if ( flDistSqr < (radius*radius) && zDiff < 32.0f )
  155. {
  156. SetCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS );
  157. if ( flDistSqr < (m_hPoliceGoal->GetRadius()*m_hPoliceGoal->GetRadius()) )
  158. {
  159. SetCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
  160. }
  161. }
  162. // If we're supposed to stop chasing (aggression over), return
  163. if ( m_bTargetIsHostile && m_flAggressiveTime < gpGlobals->curtime && IsCurSchedule(SCHED_CHASE_ENEMY) )
  164. {
  165. // Force me to re-evaluate my schedule
  166. GetOuter()->ClearSchedule( "Stopped chasing, aggression over" );
  167. }
  168. }
  169. //-----------------------------------------------------------------------------
  170. // We're taking cover from danger
  171. //-----------------------------------------------------------------------------
  172. void CAI_PolicingBehavior::AnnouncePolicing( void )
  173. {
  174. // We're policing
  175. static const char *pWarnings[3] =
  176. {
  177. "METROPOLICE_MOVE_ALONG_A",
  178. "METROPOLICE_MOVE_ALONG_B",
  179. "METROPOLICE_MOVE_ALONG_C",
  180. };
  181. if ( m_nNumWarnings <= 3 )
  182. {
  183. HostSpeakSentence( pWarnings[ m_nNumWarnings - 1 ], SENTENCE_PRIORITY_MEDIUM, SENTENCE_CRITERIA_NORMAL );
  184. }
  185. else
  186. {
  187. // We loop at m_nNumWarnings == 4 for players who aren't moving
  188. // but still pissing us off, and we're not allowed to do anything about it. (i.e. can't leave post)
  189. // First two sentences sound pretty good, so randomly pick one of them.
  190. int iSentence = RandomInt( 0, 1 );
  191. HostSpeakSentence( pWarnings[ iSentence ], SENTENCE_PRIORITY_MEDIUM, SENTENCE_CRITERIA_NORMAL );
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. // Input : scheduleType -
  197. // Output : int
  198. //-----------------------------------------------------------------------------
  199. int CAI_PolicingBehavior::TranslateSchedule( int scheduleType )
  200. {
  201. if ( scheduleType == SCHED_CHASE_ENEMY )
  202. {
  203. if ( m_hPoliceGoal->ShouldRemainAtPost() && !MaintainGoalPosition() )
  204. return BaseClass::TranslateSchedule( SCHED_COMBAT_FACE );
  205. }
  206. return BaseClass::TranslateSchedule( scheduleType );
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. // Input : newActivity -
  211. // Output : Activity
  212. //-----------------------------------------------------------------------------
  213. Activity CAI_PolicingBehavior::NPC_TranslateActivity( Activity newActivity )
  214. {
  215. // See which harassment to play
  216. if ( newActivity == ACT_POLICE_HARASS1 )
  217. {
  218. switch( m_nNumWarnings )
  219. {
  220. case 1:
  221. return (Activity) ACT_POLICE_HARASS1;
  222. break;
  223. default:
  224. case 2:
  225. return (Activity) ACT_POLICE_HARASS2;
  226. break;
  227. }
  228. }
  229. return BaseClass::NPC_TranslateActivity( newActivity );
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose:
  233. // Output : CBaseEntity
  234. //-----------------------------------------------------------------------------
  235. CBaseEntity *CAI_PolicingBehavior::GetGoalTarget( void )
  236. {
  237. if ( m_hPoliceGoal == NULL )
  238. {
  239. //NOTENOTE: This has been called before the behavior is actually active, or the goal has gone invalid
  240. Assert(0);
  241. return NULL;
  242. }
  243. return m_hPoliceGoal->GetTarget();
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose:
  247. // Input : time -
  248. //-----------------------------------------------------------------------------
  249. void CAI_PolicingBehavior::SetTargetHostileDuration( float time )
  250. {
  251. m_flTargetHostileTime = gpGlobals->curtime + time;
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose:
  255. // Input : *pTask -
  256. //-----------------------------------------------------------------------------
  257. void CAI_PolicingBehavior::StartTask( const Task_t *pTask )
  258. {
  259. switch (pTask->iTask)
  260. {
  261. case TASK_POLICE_GET_PATH_TO_HARASS_GOAL:
  262. {
  263. Vector harassDir = ( m_hPoliceGoal->GetTarget()->WorldSpaceCenter() - WorldSpaceCenter() );
  264. float flDist = VectorNormalize( harassDir );
  265. // See if we're already close enough
  266. if ( flDist < pTask->flTaskData )
  267. {
  268. TaskComplete();
  269. break;
  270. }
  271. float flInter1, flInter2;
  272. Vector harassPos = GetAbsOrigin() + ( harassDir * ( flDist - pTask->flTaskData ) );
  273. // Find a point on our policing radius to stand on
  274. if ( IntersectInfiniteRayWithSphere( GetAbsOrigin(), harassDir, m_hPoliceGoal->GetAbsOrigin(), m_hPoliceGoal->GetRadius(), &flInter1, &flInter2 ) )
  275. {
  276. Vector vPos = m_hPoliceGoal->GetAbsOrigin() + harassDir * ( MAX( flInter1, flInter2 ) );
  277. // See how far away the default one is
  278. float testDist = UTIL_DistApprox2D( m_hPoliceGoal->GetAbsOrigin(), harassPos );
  279. // If our other goal is closer, choose it
  280. if ( testDist > UTIL_DistApprox2D( m_hPoliceGoal->GetAbsOrigin(), vPos ) )
  281. {
  282. harassPos = vPos;
  283. }
  284. }
  285. if ( GetNavigator()->SetGoal( harassPos, pTask->flTaskData ) )
  286. {
  287. GetNavigator()->SetMovementActivity( (Activity) ACT_WALK_ANGRY );
  288. GetNavigator()->SetArrivalDirection( m_hPoliceGoal->GetTarget() );
  289. TaskComplete();
  290. }
  291. else
  292. {
  293. TaskFail( FAIL_NO_ROUTE );
  294. }
  295. }
  296. break;
  297. case TASK_POLICE_GET_PATH_TO_POLICE_GOAL:
  298. {
  299. if ( GetNavigator()->SetGoal( m_hPoliceGoal->GetAbsOrigin(), pTask->flTaskData ) )
  300. {
  301. GetNavigator()->SetArrivalDirection( m_hPoliceGoal->GetAbsAngles() );
  302. TaskComplete();
  303. }
  304. else
  305. {
  306. TaskFail( FAIL_NO_ROUTE );
  307. }
  308. }
  309. break;
  310. case TASK_POLICE_ANNOUNCE_HARASS:
  311. {
  312. AnnouncePolicing();
  313. // Randomly say this again in the future
  314. m_flNextHarassTime = gpGlobals->curtime + random->RandomInt( 4, 6 );
  315. // Scatter rubber-neckers
  316. CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), 256.0f, 2.0f, GetOuter() );
  317. }
  318. TaskComplete();
  319. break;
  320. case TASK_POLICE_FACE_ALONG_GOAL:
  321. {
  322. // We may have lost our police goal in the 2 seconds we wait before this task
  323. if ( m_hPoliceGoal )
  324. {
  325. GetMotor()->SetIdealYaw( m_hPoliceGoal->GetAbsAngles().y );
  326. GetOuter()->SetTurnActivity();
  327. }
  328. }
  329. break;
  330. default:
  331. BaseClass::StartTask( pTask );
  332. break;
  333. }
  334. }
  335. //-----------------------------------------------------------------------------
  336. // Purpose:
  337. //-----------------------------------------------------------------------------
  338. void CAI_PolicingBehavior::RunTask( const Task_t *pTask )
  339. {
  340. switch ( pTask->iTask )
  341. {
  342. case TASK_POLICE_FACE_ALONG_GOAL:
  343. {
  344. GetMotor()->UpdateYaw();
  345. if ( GetOuter()->FacingIdeal() )
  346. {
  347. TaskComplete();
  348. }
  349. break;
  350. }
  351. default:
  352. BaseClass::RunTask( pTask);
  353. }
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Purpose:
  357. // Output : Returns true on success, false on failure.
  358. //-----------------------------------------------------------------------------
  359. bool CAI_PolicingBehavior::MaintainGoalPosition( void )
  360. {
  361. Vector vecOrg = GetAbsOrigin();
  362. Vector vecTarget = m_hPoliceGoal->GetAbsOrigin();
  363. // Allow some slop on Z
  364. if ( fabs(vecOrg.z - vecTarget.z) > 64 )
  365. return true;
  366. // Need to be very close on X/Y
  367. if ( (vecOrg - vecTarget).Length2D() > 16 )
  368. return true;
  369. return false;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose:
  373. // Output : Returns true on success, false on failure.
  374. //-----------------------------------------------------------------------------
  375. bool CAI_PolicingBehavior::ShouldKnockOutTarget( CBaseEntity *pTarget )
  376. {
  377. if ( m_hPoliceGoal == NULL )
  378. {
  379. //NOTENOTE: This has been called before the behavior is actually active, or the goal has gone invalid
  380. Assert(0);
  381. return false;
  382. }
  383. bool bVisible = GetOuter()->FVisible( pTarget );
  384. return m_hPoliceGoal->ShouldKnockOutTarget( pTarget->WorldSpaceCenter(), bVisible );
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. // Input : *pTarget -
  389. //-----------------------------------------------------------------------------
  390. void CAI_PolicingBehavior::KnockOutTarget( CBaseEntity *pTarget )
  391. {
  392. if ( m_hPoliceGoal == NULL )
  393. {
  394. //NOTENOTE: This has been called before the behavior is actually active, or the goal has gone invalid
  395. Assert(0);
  396. return;
  397. }
  398. m_hPoliceGoal->KnockOutTarget( pTarget );
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose:
  402. // Output : int
  403. //-----------------------------------------------------------------------------
  404. int CAI_PolicingBehavior::SelectSuppressSchedule( void )
  405. {
  406. CBaseEntity *pTarget = m_hPoliceGoal->GetTarget();
  407. m_flAggressiveTime = gpGlobals->curtime + 4.0f;
  408. if ( m_bTargetIsHostile == false )
  409. {
  410. // Mark this as a valid target
  411. m_bTargetIsHostile = true;
  412. // Attack the target
  413. GetOuter()->SetEnemy( pTarget );
  414. GetOuter()->SetState( NPC_STATE_COMBAT );
  415. GetOuter()->UpdateEnemyMemory( pTarget, pTarget->GetAbsOrigin() );
  416. HostSetBatonState( true );
  417. // Remember that we're angry with the target
  418. m_nNumWarnings = POLICE_MAX_WARNINGS;
  419. // We need to let the system pickup the new enemy and deal with it on the next frame
  420. return SCHED_COMBAT_FACE;
  421. }
  422. // If we're supposed to stand still, then we need to show aggression
  423. if ( m_hPoliceGoal->ShouldRemainAtPost() )
  424. {
  425. // If we're off our mark, fight to it
  426. if ( MaintainGoalPosition() )
  427. {
  428. return SCHED_CHASE_ENEMY;
  429. }
  430. //FIXME: This needs to be a more aggressive warning to the player
  431. if ( m_flNextHarassTime < gpGlobals->curtime )
  432. {
  433. return SCHED_POLICE_WARN_TARGET;
  434. }
  435. else
  436. {
  437. return SCHED_COMBAT_FACE;
  438. }
  439. }
  440. return SCHED_CHASE_ENEMY;
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. // Output : int
  445. //-----------------------------------------------------------------------------
  446. int CAI_PolicingBehavior::SelectHarassSchedule( void )
  447. {
  448. CBaseEntity *pTarget = m_hPoliceGoal->GetTarget();
  449. m_flAggressiveTime = gpGlobals->curtime + 4.0f;
  450. // If we just started to police, make sure we're on our mark
  451. if ( MaintainGoalPosition() )
  452. return SCHED_POLICE_RETURN_FROM_HARASS;
  453. // Look at the target if they're too close
  454. GetOuter()->AddLookTarget( pTarget, 0.5f, 5.0f );
  455. // Say something if it's been long enough
  456. if ( m_flNextHarassTime < gpGlobals->curtime )
  457. {
  458. // Gesture the player away
  459. GetOuter()->SetTarget( pTarget );
  460. // Send outputs for each level of warning
  461. if ( m_nNumWarnings == 0 )
  462. {
  463. m_hPoliceGoal->FireWarningLevelOutput( 1 );
  464. }
  465. else if ( m_nNumWarnings == 1 )
  466. {
  467. m_hPoliceGoal->FireWarningLevelOutput( 2 );
  468. }
  469. if ( m_nNumWarnings < POLICE_MAX_WARNINGS )
  470. {
  471. m_nNumWarnings++;
  472. }
  473. // If we're over our limit, just suppress the offender
  474. if ( m_nNumWarnings >= POLICE_MAX_WARNINGS )
  475. {
  476. if ( m_bTargetIsHostile == false )
  477. {
  478. // Mark the target as a valid target
  479. m_bTargetIsHostile = true;
  480. GetOuter()->SetEnemy( pTarget );
  481. GetOuter()->SetState( NPC_STATE_COMBAT );
  482. GetOuter()->UpdateEnemyMemory( pTarget, pTarget->GetAbsOrigin() );
  483. HostSetBatonState( true );
  484. m_hPoliceGoal->FireWarningLevelOutput( 4 );
  485. return SCHED_COMBAT_FACE;
  486. }
  487. if ( m_hPoliceGoal->ShouldRemainAtPost() == false )
  488. return SCHED_CHASE_ENEMY;
  489. }
  490. // On our last warning, approach the target
  491. if ( m_nNumWarnings == (POLICE_MAX_WARNINGS-1) )
  492. {
  493. m_hPoliceGoal->FireWarningLevelOutput( 3 );
  494. GetOuter()->SetTarget( pTarget );
  495. HostSetBatonState( true );
  496. if ( m_hPoliceGoal->ShouldRemainAtPost() == false )
  497. return SCHED_POLICE_HARASS_TARGET;
  498. }
  499. // Otherwise just verbally warn him
  500. return SCHED_POLICE_WARN_TARGET;
  501. }
  502. return SCHED_NONE;
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Purpose:
  506. // Output : int
  507. //-----------------------------------------------------------------------------
  508. int CAI_PolicingBehavior::SelectSchedule( void )
  509. {
  510. CBaseEntity *pTarget = m_hPoliceGoal->GetTarget();
  511. // Validate our target
  512. if ( pTarget == NULL )
  513. {
  514. DevMsg( "ai_goal_police with NULL target entity!\n" );
  515. // Turn us off
  516. Disable();
  517. return SCHED_NONE;
  518. }
  519. // Attack if we're supposed to
  520. if ( ( m_flAggressiveTime >= gpGlobals->curtime ) && HasCondition( COND_CAN_MELEE_ATTACK1 ) )
  521. {
  522. return SCHED_MELEE_ATTACK1;
  523. }
  524. // See if we should immediately begin to attack our target
  525. if ( HasCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS ) )
  526. {
  527. return SelectSuppressSchedule();
  528. }
  529. int newSchedule = SCHED_NONE;
  530. // See if we're harassing
  531. if ( HasCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS ) )
  532. {
  533. newSchedule = SelectHarassSchedule();
  534. }
  535. // Return that schedule if it was found
  536. if ( newSchedule != SCHED_NONE )
  537. return newSchedule;
  538. // If our enemy is set, fogeda'bout it!
  539. if ( m_flAggressiveTime < gpGlobals->curtime )
  540. {
  541. // Return to your initial spot
  542. if ( GetEnemy() )
  543. {
  544. GetOuter()->SetEnemy( NULL );
  545. GetOuter()->SetState( NPC_STATE_ALERT );
  546. GetOuter()->GetEnemies()->RefreshMemories();
  547. }
  548. HostSetBatonState( false );
  549. m_bTargetIsHostile = false;
  550. }
  551. // If we just started to police, make sure we're on our mark
  552. if ( MaintainGoalPosition() )
  553. return SCHED_POLICE_RETURN_FROM_HARASS;
  554. // If I've got my baton on, keep looking at the target
  555. if ( HostBatonIsOn() )
  556. return SCHED_POLICE_TRACK_TARGET;
  557. // Re-align myself to the goal angles if I've strayed
  558. if ( fabs(UTIL_AngleDiff( GetAbsAngles().y, m_hPoliceGoal->GetAbsAngles().y )) > 15 )
  559. return SCHED_POLICE_FACE_ALONG_GOAL;
  560. return SCHED_IDLE_STAND;
  561. }
  562. //-----------------------------------------------------------------------------
  563. // Purpose:
  564. //-----------------------------------------------------------------------------
  565. int CAI_PolicingBehavior::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode )
  566. {
  567. if ( failedSchedule == SCHED_CHASE_ENEMY )
  568. {
  569. // We've failed to chase our enemy, return to where we were came from
  570. if ( MaintainGoalPosition() )
  571. return SCHED_POLICE_RETURN_FROM_HARASS;
  572. return SCHED_POLICE_WARN_TARGET;
  573. }
  574. return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode );
  575. }
  576. //-------------------------------------
  577. AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_PolicingBehavior )
  578. DECLARE_CONDITION( COND_POLICE_TARGET_TOO_CLOSE_HARASS );
  579. DECLARE_CONDITION( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
  580. DECLARE_TASK( TASK_POLICE_GET_PATH_TO_HARASS_GOAL );
  581. DECLARE_TASK( TASK_POLICE_GET_PATH_TO_POLICE_GOAL );
  582. DECLARE_TASK( TASK_POLICE_ANNOUNCE_HARASS );
  583. DECLARE_TASK( TASK_POLICE_FACE_ALONG_GOAL );
  584. DEFINE_SCHEDULE
  585. (
  586. SCHED_POLICE_WARN_TARGET,
  587. " Tasks"
  588. " TASK_STOP_MOVING 0"
  589. " TASK_FACE_TARGET 0"
  590. " TASK_POLICE_ANNOUNCE_HARASS 0"
  591. " TASK_PLAY_SEQUENCE ACTIVITY:ACT_POLICE_HARASS1"
  592. ""
  593. " Interrupts"
  594. " COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS"
  595. );
  596. DEFINE_SCHEDULE
  597. (
  598. SCHED_POLICE_HARASS_TARGET,
  599. " Tasks"
  600. " TASK_STOP_MOVING 0"
  601. " TASK_FACE_TARGET 0"
  602. " TASK_POLICE_GET_PATH_TO_HARASS_GOAL 64"
  603. " TASK_WAIT_FOR_MOVEMENT 0"
  604. " TASK_POLICE_ANNOUNCE_HARASS 0"
  605. " TASK_PLAY_SEQUENCE ACTIVITY:ACT_POLICE_HARASS1"
  606. ""
  607. " Interrupts"
  608. " COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS"
  609. );
  610. DEFINE_SCHEDULE
  611. (
  612. SCHED_POLICE_SUPPRESS_TARGET,
  613. " Tasks"
  614. " TASK_STOP_MOVING 0"
  615. " TASK_FACE_TARGET 0"
  616. " TASK_POLICE_ANNOUNCE_HARASS 0"
  617. " TASK_PLAY_SEQUENCE ACTIVITY:ACT_POLICE_HARASS1"
  618. ""
  619. " Interrupts"
  620. );
  621. DEFINE_SCHEDULE
  622. (
  623. SCHED_POLICE_RETURN_FROM_HARASS,
  624. " Tasks"
  625. " TASK_STOP_MOVING 0"
  626. " TASK_POLICE_GET_PATH_TO_POLICE_GOAL 16"
  627. " TASK_WALK_PATH 0"
  628. " TASK_WAIT_FOR_MOVEMENT 0"
  629. " TASK_STOP_MOVING 0"
  630. ""
  631. " Interrupts"
  632. " COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS"
  633. );
  634. DEFINE_SCHEDULE
  635. (
  636. SCHED_POLICE_TRACK_TARGET,
  637. " Tasks"
  638. " TASK_FACE_TARGET 0"
  639. ""
  640. " Interrupts"
  641. " COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS"
  642. );
  643. DEFINE_SCHEDULE
  644. (
  645. SCHED_POLICE_FACE_ALONG_GOAL,
  646. " Tasks"
  647. " TASK_WAIT_RANDOM 2"
  648. " TASK_POLICE_FACE_ALONG_GOAL 0"
  649. ""
  650. " Interrupts"
  651. " COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS"
  652. );
  653. AI_END_CUSTOM_SCHEDULE_PROVIDER()