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.

569 lines
18 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "ai_utils.h"
  8. #include "ai_memory.h"
  9. #include "ai_basenpc.h"
  10. #include "ai_senses.h"
  11. #include "ai_moveprobe.h"
  12. #include "vphysics/object_hash.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. BEGIN_SIMPLE_DATADESC( CAI_MoveMonitor )
  17. DEFINE_FIELD( m_vMark, FIELD_POSITION_VECTOR ),
  18. DEFINE_FIELD( m_flMarkTolerance, FIELD_FLOAT )
  19. END_DATADESC()
  20. //-----------------------------------------------------------------------------
  21. BEGIN_SIMPLE_DATADESC( CAI_ShotRegulator )
  22. DEFINE_FIELD( m_flNextShotTime, FIELD_TIME ),
  23. DEFINE_FIELD( m_bInRestInterval, FIELD_BOOLEAN ),
  24. DEFINE_FIELD( m_nBurstShotsRemaining, FIELD_SHORT ),
  25. DEFINE_FIELD( m_nMinBurstShots, FIELD_SHORT ),
  26. DEFINE_FIELD( m_nMaxBurstShots, FIELD_SHORT ),
  27. DEFINE_FIELD( m_flMinRestInterval, FIELD_FLOAT ),
  28. DEFINE_FIELD( m_flMaxRestInterval, FIELD_FLOAT ),
  29. DEFINE_FIELD( m_flMinBurstInterval, FIELD_FLOAT ),
  30. DEFINE_FIELD( m_flMaxBurstInterval, FIELD_FLOAT ),
  31. DEFINE_FIELD( m_bDisabled, FIELD_BOOLEAN ),
  32. END_DATADESC()
  33. //-----------------------------------------------------------------------------
  34. //-----------------------------------------------------------------------------
  35. // Constructor
  36. //-----------------------------------------------------------------------------
  37. CAI_ShotRegulator::CAI_ShotRegulator() : m_nMinBurstShots(1), m_nMaxBurstShots(1)
  38. {
  39. m_flMinRestInterval = 0.0f;
  40. m_flMinRestInterval = 0.0f;
  41. m_flMinBurstInterval = 0.0f;
  42. m_flMaxBurstInterval = 0.0f;
  43. m_flNextShotTime = -1;
  44. m_nBurstShotsRemaining = 1;
  45. m_bInRestInterval = false;
  46. m_bDisabled = false;
  47. }
  48. //-----------------------------------------------------------------------------
  49. // For backward compatibility
  50. //-----------------------------------------------------------------------------
  51. void CAI_ShotRegulator::SetParameters( int minShotsPerBurst, int maxShotsPerBurst, float minRestTime, float maxRestTime )
  52. {
  53. SetBurstShotCountRange( minShotsPerBurst, maxShotsPerBurst );
  54. SetRestInterval( minRestTime, maxRestTime );
  55. Reset( false );
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Sets the number of shots to shoot in a single burst
  59. //-----------------------------------------------------------------------------
  60. void CAI_ShotRegulator::SetBurstShotCountRange( int minShotsPerBurst, int maxShotsPerBurst )
  61. {
  62. m_nMinBurstShots = minShotsPerBurst;
  63. m_nMaxBurstShots = maxShotsPerBurst;
  64. }
  65. //-----------------------------------------------------------------------------
  66. // How much time should I rest between bursts?
  67. //-----------------------------------------------------------------------------
  68. void CAI_ShotRegulator::SetRestInterval( float flMinRestInterval, float flMaxRestInterval )
  69. {
  70. m_flMinRestInterval = flMinRestInterval;
  71. m_flMaxRestInterval = flMaxRestInterval;
  72. }
  73. //-----------------------------------------------------------------------------
  74. // How much time should I wait in between shots in a single burst?
  75. //-----------------------------------------------------------------------------
  76. void CAI_ShotRegulator::SetBurstInterval( float flMinBurstInterval, float flMaxBurstInterval )
  77. {
  78. m_flMinBurstInterval = flMinBurstInterval;
  79. m_flMaxBurstInterval = flMaxBurstInterval;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Poll the current parameters
  83. //-----------------------------------------------------------------------------
  84. void CAI_ShotRegulator::GetBurstShotCountRange( int *pMinShotsPerBurst, int *pMaxShotsPerBurst ) const
  85. {
  86. *pMinShotsPerBurst = m_nMinBurstShots;
  87. *pMaxShotsPerBurst = m_nMaxBurstShots;
  88. }
  89. void CAI_ShotRegulator::GetRestInterval( float *pMinRestInterval, float *pMaxRestInterval ) const
  90. {
  91. *pMinRestInterval = m_flMinRestInterval;
  92. *pMaxRestInterval = m_flMaxRestInterval;
  93. }
  94. void CAI_ShotRegulator::GetBurstInterval( float *pMinBurstInterval, float *pMaxBurstInterval ) const
  95. {
  96. *pMinBurstInterval = m_flMinBurstInterval;
  97. *pMaxBurstInterval = m_flMaxBurstInterval;
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Resets the shot regulator to start a new burst
  101. //-----------------------------------------------------------------------------
  102. void CAI_ShotRegulator::Reset( bool bStartShooting )
  103. {
  104. m_bDisabled = false;
  105. m_nBurstShotsRemaining = random->RandomInt( m_nMinBurstShots, m_nMaxBurstShots );
  106. if ( bStartShooting )
  107. {
  108. m_flNextShotTime = gpGlobals->curtime;
  109. m_bInRestInterval = false;
  110. }
  111. else
  112. {
  113. m_flNextShotTime = gpGlobals->curtime + random->RandomFloat( m_flMinRestInterval, m_flMaxRestInterval );
  114. m_bInRestInterval = true;
  115. }
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Should we shoot?
  119. //-----------------------------------------------------------------------------
  120. bool CAI_ShotRegulator::ShouldShoot() const
  121. {
  122. return ( !m_bDisabled && (m_flNextShotTime <= gpGlobals->curtime) );
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Am I in the middle of a burst?
  126. //-----------------------------------------------------------------------------
  127. bool CAI_ShotRegulator::IsInRestInterval() const
  128. {
  129. return (m_bInRestInterval && !ShouldShoot());
  130. }
  131. //-----------------------------------------------------------------------------
  132. // When will I shoot next?
  133. //-----------------------------------------------------------------------------
  134. float CAI_ShotRegulator::NextShotTime() const
  135. {
  136. return m_flNextShotTime;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Causes us to potentially delay our shooting time
  140. //-----------------------------------------------------------------------------
  141. void CAI_ShotRegulator::FireNoEarlierThan( float flTime )
  142. {
  143. if ( flTime > m_flNextShotTime )
  144. {
  145. m_flNextShotTime = flTime;
  146. }
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Burst shot count accessors
  150. //-----------------------------------------------------------------------------
  151. int CAI_ShotRegulator::GetBurstShotsRemaining() const
  152. {
  153. return m_nBurstShotsRemaining;
  154. }
  155. void CAI_ShotRegulator::SetBurstShotsRemaining( int shots )
  156. {
  157. m_nBurstShotsRemaining = shots;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // We fired the weapon! Update the next shot time
  161. //-----------------------------------------------------------------------------
  162. void CAI_ShotRegulator::OnFiredWeapon()
  163. {
  164. --m_nBurstShotsRemaining;
  165. if ( m_nBurstShotsRemaining <= 0 )
  166. {
  167. Reset( false );
  168. }
  169. else
  170. {
  171. m_bInRestInterval = false;
  172. m_flNextShotTime += random->RandomFloat( m_flMinBurstInterval, m_flMaxBurstInterval );
  173. if ( m_flNextShotTime < gpGlobals->curtime )
  174. {
  175. m_flNextShotTime = gpGlobals->curtime;
  176. }
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose:
  181. //-----------------------------------------------------------------------------
  182. void CAI_ShotRegulator::EnableShooting( void )
  183. {
  184. m_bDisabled = false;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose:
  188. //-----------------------------------------------------------------------------
  189. void CAI_ShotRegulator::DisableShooting( void )
  190. {
  191. m_bDisabled = true;
  192. }
  193. //-----------------------------------------------------------------------------
  194. //
  195. //-----------------------------------------------------------------------------
  196. BEGIN_SIMPLE_DATADESC( CAI_AccelDecay )
  197. DEFINE_FIELD( m_velocity, FIELD_FLOAT ),
  198. DEFINE_FIELD( m_maxVelocity, FIELD_FLOAT ),
  199. DEFINE_FIELD( m_minVelocity, FIELD_FLOAT ),
  200. DEFINE_FIELD( m_invDecay, FIELD_FLOAT ),
  201. DEFINE_FIELD( m_decayTime, FIELD_FLOAT ),
  202. DEFINE_FIELD( m_accel, FIELD_FLOAT ),
  203. END_DATADESC()
  204. void CAI_AccelDecay::SetParameters( float minVelocity, float maxVelocity, float accelPercentPerTick, float decelPercentPerTick )
  205. {
  206. m_minVelocity = minVelocity;
  207. m_maxVelocity = maxVelocity;
  208. m_accel = accelPercentPerTick;
  209. m_invDecay = 1.0 - decelPercentPerTick;
  210. m_decayTime = 0.0;
  211. float d = 1.0;
  212. int i = 0;
  213. while (d * m_maxVelocity > m_minVelocity && i < 10)
  214. {
  215. d = d * m_invDecay;
  216. m_decayTime = m_decayTime + 0.1 * d; // appox interval call
  217. i++;
  218. }
  219. }
  220. //-----------------------------------------------------------------------------
  221. //
  222. //-----------------------------------------------------------------------------
  223. float CAI_AccelDecay::Update( float flCurrent, float flTarget, float flInterval )
  224. {
  225. float delta = flTarget - flCurrent;
  226. float deltaSign = ( delta < 0 ) ? -1 : 1;
  227. delta = fabsf( delta );
  228. float curVelocity = m_velocity;
  229. if ( delta > 0.01 )
  230. {
  231. if (fabsf( m_velocity ) < m_minVelocity)
  232. m_velocity = m_minVelocity * deltaSign;
  233. if (delta < m_velocity * deltaSign * m_decayTime )
  234. {
  235. m_velocity = m_velocity * m_invDecay;
  236. if (delta < m_velocity * deltaSign * flInterval)
  237. {
  238. m_velocity = delta * deltaSign / flInterval;
  239. }
  240. }
  241. else
  242. {
  243. m_velocity = m_velocity * (1.0f - m_accel) + m_maxVelocity * m_accel * deltaSign;
  244. if (delta < m_velocity * deltaSign * m_decayTime)
  245. {
  246. m_velocity = delta * deltaSign / m_decayTime;
  247. }
  248. }
  249. float newValue = flCurrent + (curVelocity + m_velocity) * 0.5 * flInterval;
  250. return newValue;
  251. }
  252. return flTarget;
  253. }
  254. void CAI_AccelDecay::ResetVelocity( float flVelocity )
  255. {
  256. m_velocity = flVelocity;
  257. }
  258. void CAI_AccelDecay::SetMaxVelocity( float maxVelocity )
  259. {
  260. if (maxVelocity != m_maxVelocity)
  261. {
  262. SetParameters( m_minVelocity, maxVelocity, m_accel, 1.0 - m_invDecay );
  263. }
  264. }
  265. //-----------------------------------------------------------------------------
  266. //-----------------------------------------------------------------------------
  267. ConVar free_pass_peek_debug( "free_pass_peek_debug", "0" );
  268. BEGIN_SIMPLE_DATADESC( AI_FreePassParams_t )
  269. DEFINE_KEYFIELD( timeToTrigger, FIELD_FLOAT, "freepass_timetotrigger"),
  270. DEFINE_KEYFIELD( duration, FIELD_FLOAT, "freepass_duration"),
  271. DEFINE_KEYFIELD( moveTolerance, FIELD_FLOAT, "freepass_movetolerance"),
  272. DEFINE_KEYFIELD( refillRate, FIELD_FLOAT, "freepass_refillrate"),
  273. DEFINE_FIELD( coverDist, FIELD_FLOAT),
  274. DEFINE_KEYFIELD( peekTime, FIELD_FLOAT, "freepass_peektime"),
  275. DEFINE_FIELD( peekTimeAfterDamage, FIELD_FLOAT),
  276. DEFINE_FIELD( peekEyeDist, FIELD_FLOAT),
  277. DEFINE_FIELD( peekEyeDistZ, FIELD_FLOAT),
  278. END_DATADESC()
  279. BEGIN_SIMPLE_DATADESC( CAI_FreePass )
  280. DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
  281. DEFINE_FIELD( m_FreePassTimeRemaining, FIELD_FLOAT ),
  282. DEFINE_EMBEDDED( m_FreePassMoveMonitor ),
  283. DEFINE_EMBEDDED( m_Params ),
  284. END_DATADESC()
  285. //---------------------------------------------------------
  286. //---------------------------------------------------------
  287. void CAI_FreePass::Reset( float passTime, float moveTolerance )
  288. {
  289. CBaseEntity *pTarget = GetPassTarget();
  290. if ( !pTarget || m_Params.duration < 0.1 )
  291. return;
  292. if ( passTime == -1 )
  293. {
  294. m_FreePassTimeRemaining = m_Params.duration;
  295. }
  296. else
  297. {
  298. m_FreePassTimeRemaining = passTime;
  299. }
  300. if ( moveTolerance == -1 )
  301. {
  302. m_FreePassMoveMonitor.SetMark( pTarget, m_Params.moveTolerance );
  303. }
  304. else
  305. {
  306. m_FreePassMoveMonitor.SetMark( pTarget, moveTolerance );
  307. }
  308. }
  309. //---------------------------------------------------------
  310. //---------------------------------------------------------
  311. void CAI_FreePass::Update( )
  312. {
  313. CBaseEntity *pTarget = GetPassTarget();
  314. if ( !pTarget || m_Params.duration < 0.1 )
  315. return;
  316. //---------------------------------
  317. //
  318. // Free pass logic
  319. //
  320. AI_EnemyInfo_t *pTargetInfo = GetOuter()->GetEnemies()->Find( pTarget );
  321. // This works with old data because need to do before base class so as to not choose as enemy
  322. if ( !HasPass() )
  323. {
  324. float timePlayerLastSeen = (pTargetInfo) ? pTargetInfo->timeLastSeen : AI_INVALID_TIME;
  325. float lastTimeDamagedBy = (pTargetInfo) ? pTargetInfo->timeLastReceivedDamageFrom : AI_INVALID_TIME;
  326. if ( timePlayerLastSeen == AI_INVALID_TIME || gpGlobals->curtime - timePlayerLastSeen > .15 ) // If didn't see the player last think
  327. {
  328. trace_t tr;
  329. UTIL_TraceLine( pTarget->EyePosition(), GetOuter()->EyePosition(), MASK_BLOCKLOS, GetOuter(), COLLISION_GROUP_NONE, &tr );
  330. if ( tr.fraction != 1.0 && tr.m_pEnt != pTarget )
  331. {
  332. float dist = (tr.endpos - tr.startpos).Length() * tr.fraction;
  333. if ( dist < m_Params.coverDist )
  334. {
  335. if ( ( timePlayerLastSeen == AI_INVALID_TIME || gpGlobals->curtime - timePlayerLastSeen > m_Params.timeToTrigger ) &&
  336. ( lastTimeDamagedBy == AI_INVALID_TIME || gpGlobals->curtime - lastTimeDamagedBy > m_Params.timeToTrigger ) )
  337. {
  338. m_FreePassTimeRemaining = m_Params.duration;
  339. m_FreePassMoveMonitor.SetMark( pTarget, m_Params.moveTolerance );
  340. }
  341. }
  342. }
  343. }
  344. }
  345. else
  346. {
  347. float temp = m_FreePassTimeRemaining;
  348. m_FreePassTimeRemaining = 0;
  349. CAI_Senses *pSenses = GetOuter()->GetSenses();
  350. bool bCanSee = ( pSenses && pSenses->ShouldSeeEntity( pTarget ) && pSenses->CanSeeEntity( pTarget ) );
  351. m_FreePassTimeRemaining = temp;
  352. if ( bCanSee )
  353. {
  354. if ( !m_FreePassMoveMonitor.TargetMoved( pTarget ) )
  355. m_FreePassTimeRemaining -= 0.1;
  356. else
  357. Revoke( true );
  358. }
  359. else
  360. {
  361. m_FreePassTimeRemaining += 0.1 * m_Params.refillRate;
  362. if ( m_FreePassTimeRemaining > m_Params.duration )
  363. m_FreePassTimeRemaining = m_Params.duration;
  364. m_FreePassMoveMonitor.SetMark( pTarget, m_Params.moveTolerance );
  365. }
  366. }
  367. }
  368. //---------------------------------------------------------
  369. //---------------------------------------------------------
  370. bool CAI_FreePass::HasPass()
  371. {
  372. return ( m_FreePassTimeRemaining > 0 );
  373. }
  374. //---------------------------------------------------------
  375. //---------------------------------------------------------
  376. void CAI_FreePass::Revoke( bool bUpdateMemory )
  377. {
  378. m_FreePassTimeRemaining = 0;
  379. if ( bUpdateMemory && GetPassTarget() )
  380. {
  381. GetOuter()->UpdateEnemyMemory( GetPassTarget(), GetPassTarget()->GetAbsOrigin() );
  382. }
  383. }
  384. //---------------------------------------------------------
  385. //---------------------------------------------------------
  386. bool CAI_FreePass::ShouldAllowFVisible(bool bBaseResult )
  387. {
  388. CBaseEntity * pTarget = GetPassTarget();
  389. AI_EnemyInfo_t *pTargetInfo = GetOuter()->GetEnemies()->Find( pTarget );
  390. if ( !bBaseResult || HasPass() )
  391. return false;
  392. bool bIsVisible = true;
  393. // Peek logic
  394. if ( m_Params.peekTime > 0.1 )
  395. {
  396. float lastTimeSeen = (pTargetInfo) ? pTargetInfo->timeLastSeen : AI_INVALID_TIME;
  397. float lastTimeDamagedBy = (pTargetInfo) ? pTargetInfo->timeLastReceivedDamageFrom : AI_INVALID_TIME;
  398. if ( ( lastTimeSeen == AI_INVALID_TIME || gpGlobals->curtime - lastTimeSeen > m_Params.peekTime ) &&
  399. ( lastTimeDamagedBy == AI_INVALID_TIME || gpGlobals->curtime - lastTimeDamagedBy > m_Params.peekTimeAfterDamage ) )
  400. {
  401. Vector vToTarget;
  402. VectorSubtract( pTarget->EyePosition(), GetOuter()->EyePosition(), vToTarget );
  403. vToTarget.z = 0.0f;
  404. VectorNormalize( vToTarget );
  405. Vector vecRight( -vToTarget.y, vToTarget.x, 0.0f );
  406. trace_t tr;
  407. UTIL_TraceLine( GetOuter()->EyePosition(), pTarget->EyePosition() + (vecRight * m_Params.peekEyeDist - Vector( 0, 0, m_Params.peekEyeDistZ )), MASK_BLOCKLOS, GetOuter(), COLLISION_GROUP_NONE, &tr );
  408. if ( tr.fraction != 1.0 && tr.m_pEnt != pTarget )
  409. {
  410. if ( free_pass_peek_debug.GetBool() )
  411. NDebugOverlay::Line( tr.startpos, tr.endpos - Vector( 0, 0, 2), 0, 255, 0, false, 0.1 );
  412. bIsVisible = false;
  413. }
  414. if ( bIsVisible )
  415. {
  416. UTIL_TraceLine( GetOuter()->EyePosition(), pTarget->EyePosition() + (-vecRight * m_Params.peekEyeDist - Vector( 0, 0, m_Params.peekEyeDistZ )), MASK_BLOCKLOS, GetOuter(), COLLISION_GROUP_NONE, &tr );
  417. if ( tr.fraction != 1.0 && tr.m_pEnt != pTarget )
  418. {
  419. if ( free_pass_peek_debug.GetBool() )
  420. NDebugOverlay::Line( tr.startpos, tr.endpos - Vector( 0, 0, 2), 0, 255, 0, false, 0.1 );
  421. bIsVisible = false;
  422. }
  423. }
  424. }
  425. if ( bIsVisible && free_pass_peek_debug.GetBool() )
  426. NDebugOverlay::Line( GetOuter()->EyePosition(), pTarget->EyePosition() - Vector( 0, 0, 2), 255, 0, 0, false, 0.1 );
  427. }
  428. return bIsVisible;
  429. }
  430. //-----------------------------------------------------------------------------
  431. //-----------------------------------------------------------------------------
  432. CTraceFilterNav::CTraceFilterNav( CAI_BaseNPC *pProber, bool bIgnoreTransientEntities, const IServerEntity *passedict, int collisionGroup, bool bAllowPlayerAvoid ) :
  433. CTraceFilterSimple( passedict, collisionGroup ),
  434. m_pProber(pProber),
  435. m_bIgnoreTransientEntities(bIgnoreTransientEntities),
  436. m_bAllowPlayerAvoid(bAllowPlayerAvoid)
  437. {
  438. m_bCheckCollisionTable = g_EntityCollisionHash->IsObjectInHash( pProber );
  439. }
  440. //-----------------------------------------------------------------------------
  441. bool CTraceFilterNav::ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  442. {
  443. IServerEntity *pServerEntity = (IServerEntity*)pHandleEntity;
  444. CBaseEntity *pEntity = (CBaseEntity *)pServerEntity;
  445. if ( m_pProber == pEntity )
  446. return false;
  447. if ( m_pProber->GetMoveProbe()->ShouldBrushBeIgnored( pEntity ) == true )
  448. return false;
  449. if ( m_bIgnoreTransientEntities && (pEntity->IsPlayer() || pEntity->IsNPC() ) )
  450. return false;
  451. //Adrian - If I'm flagged as using the new collision method, then ignore the player when trying
  452. //to check if I can get somewhere.
  453. if ( m_bAllowPlayerAvoid && m_pProber->ShouldPlayerAvoid() && pEntity->IsPlayer() )
  454. return false;
  455. if ( pEntity->IsNavIgnored() )
  456. return false;
  457. if ( m_bCheckCollisionTable )
  458. {
  459. if ( g_EntityCollisionHash->IsObjectPairInHash( m_pProber, pEntity ) )
  460. return false;
  461. }
  462. if ( m_pProber->ShouldProbeCollideAgainstEntity( pEntity ) == false )
  463. return false;
  464. return CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
  465. }