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.

552 lines
15 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ai_motor.h"
  8. #include "ai_behavior_fear.h"
  9. #include "ai_hint.h"
  10. #include "ai_navigator.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. BEGIN_DATADESC( CAI_FearBehavior )
  14. DEFINE_FIELD( m_flTimeToSafety, FIELD_TIME ),
  15. DEFINE_FIELD( m_flTimePlayerLastVisible, FIELD_TIME ),
  16. DEFINE_FIELD( m_hSafePlaceHint, FIELD_EHANDLE ),
  17. DEFINE_FIELD( m_hMovingToHint, FIELD_EHANDLE ),
  18. DEFINE_EMBEDDED( m_SafePlaceMoveMonitor ),
  19. DEFINE_FIELD( m_flDeferUntil, FIELD_TIME ),
  20. END_DATADESC();
  21. #define BEHAVIOR_FEAR_SAFETY_TIME 5
  22. #define FEAR_SAFE_PLACE_TOLERANCE 36.0f
  23. #define FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR Square(300.0f) // (25 feet)
  24. #define FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR Square( 60.0f ) // (5 Feet)
  25. ConVar ai_enable_fear_behavior( "ai_enable_fear_behavior", "1" );
  26. ConVar ai_fear_player_dist("ai_fear_player_dist", "720" );
  27. //-----------------------------------------------------------------------------
  28. // Purpose:
  29. //-----------------------------------------------------------------------------
  30. CAI_FearBehavior::CAI_FearBehavior()
  31. {
  32. ReleaseAllHints();
  33. m_SafePlaceMoveMonitor.ClearMark();
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. void CAI_FearBehavior::Precache( void )
  39. {
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Purpose:
  43. // Input : *pTask -
  44. //-----------------------------------------------------------------------------
  45. void CAI_FearBehavior::StartTask( const Task_t *pTask )
  46. {
  47. switch( pTask->iTask )
  48. {
  49. case TASK_FEAR_IN_SAFE_PLACE:
  50. // We've arrived! Lock the hint and set the marker. we're safe for now.
  51. m_hSafePlaceHint = m_hMovingToHint;
  52. m_hSafePlaceHint->Lock( GetOuter() );
  53. m_SafePlaceMoveMonitor.SetMark( GetOuter(), FEAR_SAFE_PLACE_TOLERANCE );
  54. TaskComplete();
  55. break;
  56. case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
  57. // Using TaskInterrupt() optimizations. See RunTask().
  58. break;
  59. case TASK_FEAR_WAIT_FOR_SAFETY:
  60. m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
  61. break;
  62. default:
  63. BaseClass::StartTask( pTask );
  64. break;
  65. }
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. // Input : *pTask -
  70. //-----------------------------------------------------------------------------
  71. void CAI_FearBehavior::RunTask( const Task_t *pTask )
  72. {
  73. switch( pTask->iTask )
  74. {
  75. case TASK_FEAR_WAIT_FOR_SAFETY:
  76. if( HasCondition(COND_SEE_ENEMY) )
  77. {
  78. m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
  79. }
  80. else
  81. {
  82. if( gpGlobals->curtime > m_flTimeToSafety )
  83. {
  84. TaskComplete();
  85. }
  86. }
  87. break;
  88. case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
  89. {
  90. switch( GetOuter()->GetTaskInterrupt() )
  91. {
  92. case 0:// Find the hint node
  93. {
  94. ReleaseAllHints();
  95. CAI_Hint *pHint = FindFearWithdrawalDest();
  96. if( pHint == NULL )
  97. {
  98. TaskFail("Fear: Couldn't find hint node\n");
  99. m_flDeferUntil = gpGlobals->curtime + 3.0f;// Don't bang the hell out of this behavior. If we don't find a node, take a short break and run regular AI.
  100. }
  101. else
  102. {
  103. m_hMovingToHint.Set( pHint );
  104. GetOuter()->TaskInterrupt();
  105. }
  106. }
  107. break;
  108. case 1:// Do the pathfinding.
  109. {
  110. Assert( m_hMovingToHint != NULL );
  111. AI_NavGoal_t goal(m_hMovingToHint->GetAbsOrigin());
  112. goal.pTarget = NULL;
  113. if( GetNavigator()->SetGoal( goal ) == false )
  114. {
  115. m_hMovingToHint.Set( NULL );
  116. // Do whatever we'd want to do if we can't find a path
  117. /*
  118. Msg("Can't path to the Fear Hint!\n");
  119. AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hRallyPoint->GetAbsOrigin(), AIN_DEF_ACTIVITY, 256 );
  120. if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) )
  121. {
  122. //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it!
  123. ClearCondition( COND_TASK_FAILED );
  124. GetNavigator()->SetArrivalDirection( m_hRallyPoint->GetAbsAngles() );
  125. TaskComplete();
  126. return;
  127. }
  128. */
  129. }
  130. else
  131. {
  132. GetNavigator()->SetArrivalDirection( m_hMovingToHint->GetAbsAngles() );
  133. }
  134. }
  135. break;
  136. }
  137. }
  138. break;
  139. default:
  140. BaseClass::RunTask( pTask );
  141. break;
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. // Output : TRUE if I have an enemy and that enemy would attack me if it could
  147. // Notes : Returns FALSE if the enemy is neutral or likes me.
  148. //-----------------------------------------------------------------------------
  149. bool CAI_FearBehavior::EnemyDislikesMe()
  150. {
  151. CBaseEntity *pEnemy = GetEnemy();
  152. if( pEnemy == NULL )
  153. return false;
  154. if( pEnemy->MyNPCPointer() == NULL )
  155. return false;
  156. Disposition_t disposition = pEnemy->MyNPCPointer()->IRelationType(GetOuter());
  157. Assert(disposition != D_ER);
  158. if( disposition >= D_LI )
  159. return false;
  160. return true;
  161. }
  162. //-----------------------------------------------------------------------------
  163. // This place is definitely no longer safe. Stop picking it for a while.
  164. //-----------------------------------------------------------------------------
  165. void CAI_FearBehavior::MarkAsUnsafe()
  166. {
  167. Assert( m_hSafePlaceHint );
  168. // Disable the node to stop anyone from picking it for a while.
  169. m_hSafePlaceHint->DisableForSeconds( 5.0f );
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Am I in safe place from my enemy?
  173. //-----------------------------------------------------------------------------
  174. bool CAI_FearBehavior::IsInASafePlace()
  175. {
  176. // No safe place in mind.
  177. if( !m_SafePlaceMoveMonitor.IsMarkSet() )
  178. return false;
  179. // I have a safe place, but I'm not there.
  180. if( m_SafePlaceMoveMonitor.TargetMoved(GetOuter()) )
  181. return false;
  182. return true;
  183. }
  184. //-----------------------------------------------------------------------------
  185. //-----------------------------------------------------------------------------
  186. void CAI_FearBehavior::SpoilSafePlace()
  187. {
  188. m_SafePlaceMoveMonitor.ClearMark();
  189. }
  190. //-----------------------------------------------------------------------------
  191. //-----------------------------------------------------------------------------
  192. void CAI_FearBehavior::ReleaseAllHints()
  193. {
  194. if( m_hSafePlaceHint )
  195. {
  196. // If I have a safe place, unlock it for others.
  197. m_hSafePlaceHint->Unlock();
  198. // Don't make it available right away. I probably left for a good reason.
  199. // We also don't want to oscillate
  200. m_hSafePlaceHint->DisableForSeconds( 4.0f );
  201. m_hSafePlaceHint = NULL;
  202. }
  203. if( m_hMovingToHint )
  204. {
  205. m_hMovingToHint->Unlock();
  206. m_hMovingToHint = NULL;
  207. }
  208. m_SafePlaceMoveMonitor.ClearMark();
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose:
  212. // Output : Returns true on success, false on failure.
  213. // Notes : This behavior runs when I have an enemy that I fear, but who
  214. // does NOT hate or fear me (meaning they aren't going to fight me)
  215. //-----------------------------------------------------------------------------
  216. bool CAI_FearBehavior::CanSelectSchedule()
  217. {
  218. if( !GetOuter()->IsInterruptable() )
  219. return false;
  220. if( m_flDeferUntil > gpGlobals->curtime )
  221. return false;
  222. CBaseEntity *pEnemy = GetEnemy();
  223. if( pEnemy == NULL )
  224. return false;
  225. //if( !HasCondition(COND_SEE_PLAYER) )
  226. // return false;
  227. if( !ai_enable_fear_behavior.GetBool() )
  228. return false;
  229. if( GetOuter()->IRelationType(pEnemy) != D_FR )
  230. return false;
  231. if( !pEnemy->ClassMatches("npc_hunter") )
  232. return false;
  233. return true;
  234. }
  235. //-----------------------------------------------------------------------------
  236. //-----------------------------------------------------------------------------
  237. void CAI_FearBehavior::GatherConditions()
  238. {
  239. BaseClass::GatherConditions();
  240. ClearCondition( COND_FEAR_ENEMY_CLOSE );
  241. ClearCondition( COND_FEAR_ENEMY_TOO_CLOSE );
  242. if( GetEnemy() )
  243. {
  244. float flEnemyDistSqr = GetAbsOrigin().DistToSqr(GetEnemy()->GetAbsOrigin());
  245. if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR )
  246. {
  247. SetCondition( COND_FEAR_ENEMY_TOO_CLOSE );
  248. if( IsInASafePlace() )
  249. {
  250. SpoilSafePlace();
  251. }
  252. }
  253. else if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR && GetEnemy()->GetEnemy() == GetOuter() )
  254. {
  255. // Only become scared of an enemy at this range if they're my enemy, too
  256. SetCondition( COND_FEAR_ENEMY_CLOSE );
  257. if( IsInASafePlace() )
  258. {
  259. SpoilSafePlace();
  260. }
  261. }
  262. }
  263. ClearCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
  264. // Check for separation from the player
  265. // -The player is farther away than 60 feet
  266. // -I haven't seen the player in 2 seconds
  267. //
  268. // Here's the distance check:
  269. CBasePlayer *pPlayer = AI_GetSinglePlayer();
  270. if( pPlayer != NULL && GetAbsOrigin().DistToSqr(pPlayer->GetAbsOrigin()) >= Square( ai_fear_player_dist.GetFloat() * 1.5f ) )
  271. {
  272. SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
  273. }
  274. // Here's the visibility check. We can't skip this because it's time-sensitive
  275. if( GetOuter()->FVisible(pPlayer) )
  276. {
  277. m_flTimePlayerLastVisible = gpGlobals->curtime;
  278. }
  279. else
  280. {
  281. if( gpGlobals->curtime - m_flTimePlayerLastVisible >= 2.0f )
  282. {
  283. SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
  284. }
  285. }
  286. if( HasCondition(COND_FEAR_SEPARATED_FROM_PLAYER) )
  287. {
  288. //Msg("I am separated from player\n");
  289. if( IsInASafePlace() )
  290. {
  291. SpoilSafePlace();
  292. }
  293. }
  294. }
  295. //-----------------------------------------------------------------------------
  296. //-----------------------------------------------------------------------------
  297. void CAI_FearBehavior::BeginScheduleSelection()
  298. {
  299. if( m_hSafePlaceHint )
  300. {
  301. // We think we're safe. Is it true?
  302. if( !IsInASafePlace() )
  303. {
  304. // no! So mark it so.
  305. ReleaseAllHints();
  306. }
  307. }
  308. m_flTimePlayerLastVisible = gpGlobals->curtime;
  309. }
  310. //-----------------------------------------------------------------------------
  311. //-----------------------------------------------------------------------------
  312. void CAI_FearBehavior::EndScheduleSelection()
  313. {
  314. // We don't have to release our hints or markers or anything here.
  315. // Just because we ran other AI for a while doesn't mean we aren't still in a safe place.
  316. //ReleaseAllHints();
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. // Output : int
  321. // Notes : If fear behavior is running at all, we know we're afraid of our enemy
  322. //-----------------------------------------------------------------------------
  323. int CAI_FearBehavior::SelectSchedule()
  324. {
  325. bool bInSafePlace = IsInASafePlace();
  326. if( !HasCondition(COND_HEAR_DANGER) )
  327. {
  328. if( !bInSafePlace )
  329. {
  330. // Always move to a safe place if we're not running from a danger sound
  331. return SCHED_FEAR_MOVE_TO_SAFE_PLACE;
  332. }
  333. else
  334. {
  335. // We ARE in a safe place
  336. if( HasCondition(COND_CAN_RANGE_ATTACK1) )
  337. return SCHED_RANGE_ATTACK1;
  338. return SCHED_FEAR_STAY_IN_SAFE_PLACE;
  339. }
  340. }
  341. return BaseClass::SelectSchedule();
  342. }
  343. //-----------------------------------------------------------------------------
  344. //-----------------------------------------------------------------------------
  345. void CAI_FearBehavior::BuildScheduleTestBits()
  346. {
  347. BaseClass::BuildScheduleTestBits();
  348. if( GetOuter()->GetState() != NPC_STATE_SCRIPT )
  349. {
  350. // Stop doing ANYTHING if we get scared.
  351. //GetOuter()->SetCustomInterruptCondition( COND_HEAR_DANGER );
  352. if( !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY, false) && !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE, false) )
  353. {
  354. GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal(COND_FEAR_SEPARATED_FROM_PLAYER) );
  355. }
  356. }
  357. }
  358. //-----------------------------------------------------------------------------
  359. //-----------------------------------------------------------------------------
  360. int CAI_FearBehavior::TranslateSchedule( int scheduleType )
  361. {
  362. switch( scheduleType )
  363. {
  364. case SCHED_FEAR_MOVE_TO_SAFE_PLACE:
  365. if( HasCondition(COND_FEAR_ENEMY_TOO_CLOSE) )
  366. {
  367. // If I'm moving to a safe place AND have an enemy too close to me,
  368. // make the move to safety while ignoring the condition.
  369. // this stops an oscillation
  370. // IS THIS CODE EVER EVEN BEING CALLED? (sjb)
  371. return SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY;
  372. }
  373. break;
  374. }
  375. return BaseClass::TranslateSchedule( scheduleType );
  376. }
  377. //-----------------------------------------------------------------------------
  378. //-----------------------------------------------------------------------------
  379. CAI_Hint *CAI_FearBehavior::FindFearWithdrawalDest()
  380. {
  381. CAI_Hint *pHint;
  382. CHintCriteria hintCriteria;
  383. CAI_BaseNPC *pOuter = GetOuter();
  384. Assert(pOuter != NULL);
  385. hintCriteria.AddHintType( HINT_PLAYER_ALLY_FEAR_DEST );
  386. hintCriteria.SetFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER | bits_HINT_NOT_CLOSE_TO_ENEMY /*| bits_HINT_NODE_IN_VIEWCONE | bits_HINT_NPC_IN_NODE_FOV*/ );
  387. hintCriteria.AddIncludePosition( AI_GetSinglePlayer()->GetAbsOrigin(), ( ai_fear_player_dist.GetFloat() ) );
  388. pHint = CAI_HintManager::FindHint( pOuter, hintCriteria );
  389. if( pHint )
  390. {
  391. // Reserve this node while I try to get to it. When I get there I will lock it.
  392. // Otherwise, if I fail to get there, the node will come available again soon.
  393. pHint->DisableForSeconds( 4.0f );
  394. }
  395. #if 0
  396. else
  397. {
  398. Msg("DID NOT FIND HINT\n");
  399. NDebugOverlay::Cross3D( GetOuter()->WorldSpaceCenter(), 32, 255, 255, 0, false, 10.0f );
  400. }
  401. #endif
  402. return pHint;
  403. }
  404. AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_FearBehavior )
  405. DECLARE_TASK( TASK_FEAR_GET_PATH_TO_SAFETY_HINT )
  406. DECLARE_TASK( TASK_FEAR_WAIT_FOR_SAFETY )
  407. DECLARE_TASK( TASK_FEAR_IN_SAFE_PLACE )
  408. DECLARE_CONDITION( COND_FEAR_ENEMY_CLOSE )
  409. DECLARE_CONDITION( COND_FEAR_ENEMY_TOO_CLOSE )
  410. DECLARE_CONDITION( COND_FEAR_SEPARATED_FROM_PLAYER )
  411. //===============================================
  412. //===============================================
  413. DEFINE_SCHEDULE
  414. (
  415. SCHED_FEAR_MOVE_TO_SAFE_PLACE,
  416. " Tasks"
  417. " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
  418. " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
  419. " TASK_RUN_PATH 0"
  420. " TASK_WAIT_FOR_MOVEMENT 0"
  421. " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
  422. " TASK_FEAR_IN_SAFE_PLACE 0"
  423. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
  424. ""
  425. " Interrupts"
  426. ""
  427. " COND_HEAR_DANGER"
  428. " COND_NEW_ENEMY"
  429. " COND_FEAR_ENEMY_TOO_CLOSE"
  430. );
  431. DEFINE_SCHEDULE
  432. (
  433. SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY,
  434. " Tasks"
  435. " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
  436. " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
  437. " TASK_RUN_PATH 0"
  438. " TASK_WAIT_FOR_MOVEMENT 0"
  439. " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
  440. " TASK_FEAR_IN_SAFE_PLACE 0"
  441. " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
  442. ""
  443. " Interrupts"
  444. ""
  445. " COND_HEAR_DANGER"
  446. " COND_NEW_ENEMY"
  447. );
  448. //===============================================
  449. //===============================================
  450. DEFINE_SCHEDULE
  451. (
  452. SCHED_FEAR_STAY_IN_SAFE_PLACE,
  453. " Tasks"
  454. " TASK_FEAR_WAIT_FOR_SAFETY 0"
  455. ""
  456. " Interrupts"
  457. ""
  458. " COND_NEW_ENEMY"
  459. " COND_HEAR_DANGER"
  460. " COND_FEAR_ENEMY_CLOSE"
  461. " COND_FEAR_ENEMY_TOO_CLOSE"
  462. " COND_CAN_RANGE_ATTACK1"
  463. " COND_FEAR_SEPARATED_FROM_PLAYER"
  464. );
  465. AI_END_CUSTOM_SCHEDULE_PROVIDER()