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.

910 lines
27 KiB

  1. // NextBotPlayer.h
  2. // A CBasePlayer bot based on the NextBot technology
  3. // Author: Michael Booth, November 2005
  4. //========= Copyright Valve Corporation, All rights reserved. ============//
  5. #ifndef _NEXT_BOT_PLAYER_H_
  6. #define _NEXT_BOT_PLAYER_H_
  7. #include "cbase.h"
  8. #include "gameinterface.h"
  9. #include "NextBot.h"
  10. #include "Path/NextBotPathFollow.h"
  11. //#include "NextBotPlayerBody.h"
  12. #include "NextBotBehavior.h"
  13. #include "in_buttons.h"
  14. extern ConVar NextBotPlayerStop;
  15. extern ConVar NextBotPlayerWalk;
  16. extern ConVar NextBotPlayerCrouch;
  17. extern ConVar NextBotPlayerMove;
  18. //--------------------------------------------------------------------------------------------------
  19. /**
  20. * Instantiate a NextBot derived from CBasePlayer and spawn it into the environment.
  21. * Assumes class T is derived from CBasePlayer, and has the following method that
  22. * creates a new entity of type T and returns it:
  23. *
  24. * static CBasePlayer *T::AllocatePlayerEntity( edict_t *pEdict, const char *playerName )
  25. *
  26. */
  27. template < typename T >
  28. T * NextBotCreatePlayerBot( const char *name, bool bReportFakeClient = true )
  29. {
  30. /*
  31. if ( UTIL_ClientsInGame() >= gpGlobals->maxClients )
  32. {
  33. Msg( "CreatePlayerBot: Failed - server is full (%d/%d clients).\n", UTIL_ClientsInGame(), gpGlobals->maxClients );
  34. return NULL;
  35. }
  36. */
  37. // This is a "back door" for allocating a custom player bot entity when
  38. // the engine calls ClientPutInServer (from CreateFakeClient)
  39. ClientPutInServerOverride( T::AllocatePlayerEntity );
  40. // create the bot and spawn it into the environment
  41. edict_t *botEdict = engine->CreateFakeClientEx( name, bReportFakeClient );
  42. // close the "back door"
  43. ClientPutInServerOverride( NULL );
  44. if ( botEdict == NULL )
  45. {
  46. Msg( "CreatePlayerBot: Unable to create bot %s - CreateFakeClient() returned NULL.\n", name );
  47. return NULL;
  48. }
  49. // create an instance of the bot's class and bind it to the edict
  50. T *bot = dynamic_cast< T * >( CBaseEntity::Instance( botEdict ) );
  51. if ( bot == NULL )
  52. {
  53. Assert( false );
  54. Error( "CreatePlayerBot: Could not Instance() from the bot edict.\n" );
  55. return NULL;
  56. }
  57. bot->SetPlayerName( name );
  58. // flag this as a fakeclient (bot)
  59. bot->ClearFlags();
  60. bot->AddFlag( FL_CLIENT | FL_FAKECLIENT );
  61. return bot;
  62. }
  63. //--------------------------------------------------------------------------------------------------
  64. /**
  65. * Interface to access player input buttons.
  66. * Unless a duration is given, each button is released at the start of the next frame.
  67. * The release methods allow releasing a button before its duration has elapsed.
  68. */
  69. class INextBotPlayerInput
  70. {
  71. public:
  72. virtual void PressFireButton( float duration = -1.0f ) = 0;
  73. virtual void ReleaseFireButton( void ) = 0;
  74. virtual void PressAltFireButton( float duration = -1.0f ) = 0;
  75. virtual void ReleaseAltFireButton( void ) = 0;
  76. virtual void PressMeleeButton( float duration = -1.0f ) = 0;
  77. virtual void ReleaseMeleeButton( void ) = 0;
  78. virtual void PressSpecialFireButton( float duration = -1.0f ) = 0;
  79. virtual void ReleaseSpecialFireButton( void ) = 0;
  80. virtual void PressUseButton( float duration = -1.0f ) = 0;
  81. virtual void ReleaseUseButton( void ) = 0;
  82. virtual void PressReloadButton( float duration = -1.0f ) = 0;
  83. virtual void ReleaseReloadButton( void ) = 0;
  84. virtual void PressForwardButton( float duration = -1.0f ) = 0;
  85. virtual void ReleaseForwardButton( void ) = 0;
  86. virtual void PressBackwardButton( float duration = -1.0f ) = 0;
  87. virtual void ReleaseBackwardButton( void ) = 0;
  88. virtual void PressLeftButton( float duration = -1.0f ) = 0;
  89. virtual void ReleaseLeftButton( void ) = 0;
  90. virtual void PressRightButton( float duration = -1.0f ) = 0;
  91. virtual void ReleaseRightButton( void ) = 0;
  92. virtual void PressJumpButton( float duration = -1.0f ) = 0;
  93. virtual void ReleaseJumpButton( void ) = 0;
  94. virtual void PressCrouchButton( float duration = -1.0f ) = 0;
  95. virtual void ReleaseCrouchButton( void ) = 0;
  96. virtual void PressWalkButton( float duration = -1.0f ) = 0;
  97. virtual void ReleaseWalkButton( void ) = 0;
  98. virtual void SetButtonScale( float forward, float right ) = 0;
  99. };
  100. //--------------------------------------------------------------------------------------------------
  101. /**
  102. * Drive a CBasePlayer-derived entity via NextBot logic
  103. */
  104. template < typename PlayerType >
  105. class NextBotPlayer : public PlayerType, public INextBot, public INextBotPlayerInput
  106. {
  107. public:
  108. DECLARE_CLASS( NextBotPlayer, PlayerType );
  109. NextBotPlayer( void );
  110. virtual ~NextBotPlayer();
  111. virtual void Spawn( void );
  112. virtual void SetSpawnPoint( CBaseEntity *spawnPoint ); // define place in environment where bot will (re)spawn
  113. virtual CBaseEntity *EntSelectSpawnPoint( void );
  114. virtual void PhysicsSimulate( void );
  115. virtual bool IsNetClient( void ) const { return false; } // Bots should return FALSE for this, they can't receive NET messages
  116. virtual bool IsFakeClient( void ) const { return true; }
  117. virtual bool IsBot( void ) const { return true; }
  118. virtual INextBot *MyNextBotPointer( void ) { return this; }
  119. // this is valid because the templatized PlayerType must be derived from CBasePlayer, which is derived from CBaseCombatCharacter
  120. virtual CBaseCombatCharacter *GetEntity( void ) const { return ( PlayerType * )this; }
  121. virtual bool IsRemovedOnReset( void ) const { return false; } // remove this bot when the NextBot manager calls Reset
  122. virtual bool IsDormantWhenDead( void ) const { return true; } // should this player-bot continue to update itself when dead (respawn logic, etc)
  123. // allocate a bot and bind it to the edict
  124. static CBasePlayer *AllocatePlayerEntity( edict_t *edict, const char *playerName );
  125. //------------------------------------------------------------------------
  126. // utility methods
  127. float GetDistanceBetween( CBaseEntity *other ) const; // return distance between us and the given entity
  128. bool IsDistanceBetweenLessThan( CBaseEntity *other, float range ) const; // return true if distance between is less than the given value
  129. bool IsDistanceBetweenGreaterThan( CBaseEntity *other, float range ) const; // return true if distance between is greater than the given value
  130. float GetDistanceBetween( const Vector &target ) const; // return distance between us and the given entity
  131. bool IsDistanceBetweenLessThan( const Vector &target, float range ) const; // return true if distance between is less than the given value
  132. bool IsDistanceBetweenGreaterThan( const Vector &target, float range ) const; // return true if distance between is greater than the given value
  133. //------------------------------------------------------------------------
  134. // INextBotPlayerInput
  135. virtual void PressFireButton( float duration = -1.0f );
  136. virtual void ReleaseFireButton( void );
  137. virtual void PressAltFireButton( float duration = -1.0f );
  138. virtual void ReleaseAltFireButton( void );
  139. virtual void PressMeleeButton( float duration = -1.0f );
  140. virtual void ReleaseMeleeButton( void );
  141. virtual void PressSpecialFireButton( float duration = -1.0f );
  142. virtual void ReleaseSpecialFireButton( void );
  143. virtual void PressUseButton( float duration = -1.0f );
  144. virtual void ReleaseUseButton( void );
  145. virtual void PressReloadButton( float duration = -1.0f );
  146. virtual void ReleaseReloadButton( void );
  147. virtual void PressForwardButton( float duration = -1.0f );
  148. virtual void ReleaseForwardButton( void );
  149. virtual void PressBackwardButton( float duration = -1.0f );
  150. virtual void ReleaseBackwardButton( void );
  151. virtual void PressLeftButton( float duration = -1.0f );
  152. virtual void ReleaseLeftButton( void );
  153. virtual void PressRightButton( float duration = -1.0f );
  154. virtual void ReleaseRightButton( void );
  155. virtual void PressJumpButton( float duration = -1.0f );
  156. virtual void ReleaseJumpButton( void );
  157. virtual void PressCrouchButton( float duration = -1.0f );
  158. virtual void ReleaseCrouchButton( void );
  159. virtual void PressWalkButton( float duration = -1.0f );
  160. virtual void ReleaseWalkButton( void );
  161. virtual void SetButtonScale( float forward, float right );
  162. //------------------------------------------------------------------------
  163. // Event hooks into NextBot system
  164. virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
  165. virtual int OnTakeDamage_Dying( const CTakeDamageInfo &info );
  166. virtual void Event_Killed( const CTakeDamageInfo &info );
  167. virtual void HandleAnimEvent( animevent_t *event );
  168. virtual void OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea ); // invoked (by UpdateLastKnownArea) when we enter a new nav area (or it is reset to NULL)
  169. virtual void Touch( CBaseEntity *other );
  170. virtual void Weapon_Equip( CBaseCombatWeapon *weapon ); // for OnPickUp
  171. virtual void Weapon_Drop( CBaseCombatWeapon *weapon, const Vector *target, const Vector *velocity ); // for OnDrop
  172. virtual void OnMainActivityComplete( Activity newActivity, Activity oldActivity );
  173. virtual void OnMainActivityInterrupted( Activity newActivity, Activity oldActivity );
  174. //------------------------------------------------------------------------
  175. bool IsAbleToAutoCenterOnLadders( void ) const;
  176. virtual void AvoidPlayers( CUserCmd *pCmd ) { } // some game types allow players to pass through each other, this method pushes them apart
  177. public:
  178. // begin INextBot ------------------------------------------------------------------------------------------------------------------
  179. virtual void Update( void ); // (EXTEND) update internal state
  180. protected:
  181. int m_inputButtons; // this is still needed to guarantee each button press is captured at least once
  182. int m_prevInputButtons;
  183. CountdownTimer m_fireButtonTimer;
  184. CountdownTimer m_meleeButtonTimer;
  185. CountdownTimer m_specialFireButtonTimer;
  186. CountdownTimer m_useButtonTimer;
  187. CountdownTimer m_reloadButtonTimer;
  188. CountdownTimer m_forwardButtonTimer;
  189. CountdownTimer m_backwardButtonTimer;
  190. CountdownTimer m_leftButtonTimer;
  191. CountdownTimer m_rightButtonTimer;
  192. CountdownTimer m_jumpButtonTimer;
  193. CountdownTimer m_crouchButtonTimer;
  194. CountdownTimer m_walkButtonTimer;
  195. CountdownTimer m_buttonScaleTimer;
  196. IntervalTimer m_burningTimer; // how long since we were last burning
  197. float m_forwardScale;
  198. float m_rightScale;
  199. CHandle< CBaseEntity > m_spawnPointEntity;
  200. };
  201. template < typename PlayerType >
  202. inline void NextBotPlayer< PlayerType >::SetSpawnPoint( CBaseEntity *spawnPoint )
  203. {
  204. m_spawnPointEntity = spawnPoint;
  205. }
  206. template < typename PlayerType >
  207. inline CBaseEntity *NextBotPlayer< PlayerType >::EntSelectSpawnPoint( void )
  208. {
  209. if ( m_spawnPointEntity != NULL )
  210. return m_spawnPointEntity;
  211. return BaseClass::EntSelectSpawnPoint();
  212. }
  213. template < typename PlayerType >
  214. inline float NextBotPlayer< PlayerType >::GetDistanceBetween( CBaseEntity *other ) const
  215. {
  216. return (this->GetAbsOrigin() - other->GetAbsOrigin()).Length();
  217. }
  218. template < typename PlayerType >
  219. inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenLessThan( CBaseEntity *other, float range ) const
  220. {
  221. return (this->GetAbsOrigin() - other->GetAbsOrigin()).IsLengthLessThan( range );
  222. }
  223. template < typename PlayerType >
  224. inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenGreaterThan( CBaseEntity *other, float range ) const
  225. {
  226. return (this->GetAbsOrigin() - other->GetAbsOrigin()).IsLengthGreaterThan( range );
  227. }
  228. template < typename PlayerType >
  229. inline float NextBotPlayer< PlayerType >::GetDistanceBetween( const Vector &target ) const
  230. {
  231. return (this->GetAbsOrigin() - target).Length();
  232. }
  233. template < typename PlayerType >
  234. inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenLessThan( const Vector &target, float range ) const
  235. {
  236. return (this->GetAbsOrigin() - target).IsLengthLessThan( range );
  237. }
  238. template < typename PlayerType >
  239. inline bool NextBotPlayer< PlayerType >::IsDistanceBetweenGreaterThan( const Vector &target, float range ) const
  240. {
  241. return (this->GetAbsOrigin() - target).IsLengthGreaterThan( range );
  242. }
  243. template < typename PlayerType >
  244. inline void NextBotPlayer< PlayerType >::PressFireButton( float duration )
  245. {
  246. m_inputButtons |= IN_ATTACK;
  247. m_fireButtonTimer.Start( duration );
  248. }
  249. template < typename PlayerType >
  250. inline void NextBotPlayer< PlayerType >::ReleaseFireButton( void )
  251. {
  252. m_inputButtons &= ~IN_ATTACK;
  253. m_fireButtonTimer.Invalidate();
  254. }
  255. template < typename PlayerType >
  256. inline void NextBotPlayer< PlayerType >::PressAltFireButton( float duration )
  257. {
  258. PressMeleeButton( duration );
  259. }
  260. template < typename PlayerType >
  261. inline void NextBotPlayer< PlayerType >::ReleaseAltFireButton( void )
  262. {
  263. ReleaseMeleeButton();
  264. }
  265. template < typename PlayerType >
  266. inline void NextBotPlayer< PlayerType >::PressMeleeButton( float duration )
  267. {
  268. m_inputButtons |= IN_ATTACK2;
  269. m_meleeButtonTimer.Start( duration );
  270. }
  271. template < typename PlayerType >
  272. inline void NextBotPlayer< PlayerType >::ReleaseMeleeButton( void )
  273. {
  274. m_inputButtons &= ~IN_ATTACK2;
  275. m_meleeButtonTimer.Invalidate();
  276. }
  277. template < typename PlayerType >
  278. inline void NextBotPlayer< PlayerType >::PressSpecialFireButton( float duration )
  279. {
  280. m_inputButtons |= IN_ATTACK3;
  281. m_specialFireButtonTimer.Start( duration );
  282. }
  283. template < typename PlayerType >
  284. inline void NextBotPlayer< PlayerType >::ReleaseSpecialFireButton( void )
  285. {
  286. m_inputButtons &= ~IN_ATTACK3;
  287. m_specialFireButtonTimer.Invalidate();
  288. }
  289. template < typename PlayerType >
  290. inline void NextBotPlayer< PlayerType >::PressUseButton( float duration )
  291. {
  292. m_inputButtons |= IN_USE;
  293. m_useButtonTimer.Start( duration );
  294. }
  295. template < typename PlayerType >
  296. inline void NextBotPlayer< PlayerType >::ReleaseUseButton( void )
  297. {
  298. m_inputButtons &= ~IN_USE;
  299. m_useButtonTimer.Invalidate();
  300. }
  301. template < typename PlayerType >
  302. inline void NextBotPlayer< PlayerType >::PressReloadButton( float duration )
  303. {
  304. m_inputButtons |= IN_RELOAD;
  305. m_reloadButtonTimer.Start( duration );
  306. }
  307. template < typename PlayerType >
  308. inline void NextBotPlayer< PlayerType >::ReleaseReloadButton( void )
  309. {
  310. m_inputButtons &= ~IN_RELOAD;
  311. m_reloadButtonTimer.Invalidate();
  312. }
  313. template < typename PlayerType >
  314. inline void NextBotPlayer< PlayerType >::PressJumpButton( float duration )
  315. {
  316. m_inputButtons |= IN_JUMP;
  317. m_jumpButtonTimer.Start( duration );
  318. }
  319. template < typename PlayerType >
  320. inline void NextBotPlayer< PlayerType >::ReleaseJumpButton( void )
  321. {
  322. m_inputButtons &= ~IN_JUMP;
  323. m_jumpButtonTimer.Invalidate();
  324. }
  325. template < typename PlayerType >
  326. inline void NextBotPlayer< PlayerType >::PressCrouchButton( float duration )
  327. {
  328. m_inputButtons |= IN_DUCK;
  329. m_crouchButtonTimer.Start( duration );
  330. }
  331. template < typename PlayerType >
  332. inline void NextBotPlayer< PlayerType >::ReleaseCrouchButton( void )
  333. {
  334. m_inputButtons &= ~IN_DUCK;
  335. m_crouchButtonTimer.Invalidate();
  336. }
  337. template < typename PlayerType >
  338. inline void NextBotPlayer< PlayerType >::PressWalkButton( float duration )
  339. {
  340. m_inputButtons |= IN_SPEED;
  341. m_walkButtonTimer.Start( duration );
  342. }
  343. template < typename PlayerType >
  344. inline void NextBotPlayer< PlayerType >::ReleaseWalkButton( void )
  345. {
  346. m_inputButtons &= ~IN_SPEED;
  347. m_walkButtonTimer.Invalidate();
  348. }
  349. template < typename PlayerType >
  350. inline void NextBotPlayer< PlayerType >::PressForwardButton( float duration )
  351. {
  352. m_inputButtons |= IN_FORWARD;
  353. m_forwardButtonTimer.Start( duration );
  354. }
  355. template < typename PlayerType >
  356. inline void NextBotPlayer< PlayerType >::ReleaseForwardButton( void )
  357. {
  358. m_inputButtons &= ~IN_FORWARD;
  359. m_forwardButtonTimer.Invalidate();
  360. }
  361. template < typename PlayerType >
  362. inline void NextBotPlayer< PlayerType >::PressBackwardButton( float duration )
  363. {
  364. m_inputButtons |= IN_BACK;
  365. m_backwardButtonTimer.Start( duration );
  366. }
  367. template < typename PlayerType >
  368. inline void NextBotPlayer< PlayerType >::ReleaseBackwardButton( void )
  369. {
  370. m_inputButtons &= ~IN_BACK;
  371. m_backwardButtonTimer.Invalidate();
  372. }
  373. template < typename PlayerType >
  374. inline void NextBotPlayer< PlayerType >::PressLeftButton( float duration )
  375. {
  376. m_inputButtons |= IN_MOVELEFT;
  377. m_leftButtonTimer.Start( duration );
  378. }
  379. template < typename PlayerType >
  380. inline void NextBotPlayer< PlayerType >::ReleaseLeftButton( void )
  381. {
  382. m_inputButtons &= ~IN_MOVELEFT;
  383. m_leftButtonTimer.Invalidate();
  384. }
  385. template < typename PlayerType >
  386. inline void NextBotPlayer< PlayerType >::PressRightButton( float duration )
  387. {
  388. m_inputButtons |= IN_MOVERIGHT;
  389. m_rightButtonTimer.Start( duration );
  390. }
  391. template < typename PlayerType >
  392. inline void NextBotPlayer< PlayerType >::ReleaseRightButton( void )
  393. {
  394. m_inputButtons &= ~IN_MOVERIGHT;
  395. m_rightButtonTimer.Invalidate();
  396. }
  397. template < typename PlayerType >
  398. inline void NextBotPlayer< PlayerType >::SetButtonScale( float forward, float right )
  399. {
  400. m_forwardScale = forward;
  401. m_rightScale = right;
  402. m_buttonScaleTimer.Start( 0.01 );
  403. }
  404. //-----------------------------------------------------------------------------------------------------
  405. template < typename PlayerType >
  406. inline NextBotPlayer< PlayerType >::NextBotPlayer( void )
  407. {
  408. m_prevInputButtons = 0;
  409. m_inputButtons = 0;
  410. m_burningTimer.Invalidate();
  411. m_spawnPointEntity = NULL;
  412. }
  413. //-----------------------------------------------------------------------------------------------------
  414. template < typename PlayerType >
  415. inline NextBotPlayer< PlayerType >::~NextBotPlayer()
  416. {
  417. }
  418. //-----------------------------------------------------------------------------------------------------
  419. template < typename PlayerType >
  420. inline void NextBotPlayer< PlayerType >::Spawn( void )
  421. {
  422. engine->SetFakeClientConVarValue( this->edict(), "cl_autohelp", "0" );
  423. m_prevInputButtons = m_inputButtons = 0;
  424. m_fireButtonTimer.Invalidate();
  425. m_meleeButtonTimer.Invalidate();
  426. m_specialFireButtonTimer.Invalidate();
  427. m_useButtonTimer.Invalidate();
  428. m_reloadButtonTimer.Invalidate();
  429. m_forwardButtonTimer.Invalidate();
  430. m_backwardButtonTimer.Invalidate();
  431. m_leftButtonTimer.Invalidate();
  432. m_rightButtonTimer.Invalidate();
  433. m_jumpButtonTimer.Invalidate();
  434. m_crouchButtonTimer.Invalidate();
  435. m_walkButtonTimer.Invalidate();
  436. m_buttonScaleTimer.Invalidate();
  437. m_forwardScale = m_rightScale = 0.04;
  438. m_burningTimer.Invalidate();
  439. // reset first, because Spawn() may access various interfaces
  440. INextBot::Reset();
  441. BaseClass::Spawn();
  442. }
  443. //-----------------------------------------------------------------------------------------------------
  444. inline void _NextBot_BuildUserCommand( CUserCmd *cmd, const QAngle &viewangles, float forwardmove, float sidemove, float upmove, int buttons, byte impulse )
  445. {
  446. Q_memset( cmd, 0, sizeof( CUserCmd ) );
  447. cmd->command_number = gpGlobals->tickcount;
  448. cmd->forwardmove = forwardmove;
  449. cmd->sidemove = sidemove;
  450. cmd->upmove = upmove;
  451. cmd->buttons = buttons;
  452. cmd->impulse = impulse;
  453. VectorCopy( viewangles, cmd->viewangles );
  454. cmd->random_seed = random->RandomInt( 0, 0x7fffffff );
  455. }
  456. //-----------------------------------------------------------------------------------------------------
  457. template < typename PlayerType >
  458. inline void NextBotPlayer< PlayerType >::PhysicsSimulate( void )
  459. {
  460. VPROF( "NextBotPlayer::PhysicsSimulate" );
  461. // Make sure not to simulate this guy twice per frame
  462. if ( PlayerType::m_nSimulationTick == gpGlobals->tickcount )
  463. {
  464. return;
  465. }
  466. if ( engine->IsPaused() )
  467. {
  468. // We're paused - don't add new commands
  469. PlayerType::PhysicsSimulate();
  470. return;
  471. }
  472. if ( ( IsDormantWhenDead() && PlayerType::m_lifeState == LIFE_DEAD ) || NextBotStop.GetBool() )
  473. {
  474. // death animation complete - nothing left to do except let PhysicsSimulate run PreThink etc
  475. PlayerType::PhysicsSimulate();
  476. return;
  477. }
  478. int inputButtons;
  479. //
  480. // Update bot behavior
  481. //
  482. if ( BeginUpdate() )
  483. {
  484. Update();
  485. // build button bits
  486. if ( !m_fireButtonTimer.IsElapsed() )
  487. m_inputButtons |= IN_ATTACK;
  488. if ( !m_meleeButtonTimer.IsElapsed() )
  489. m_inputButtons |= IN_ATTACK2;
  490. if ( !m_specialFireButtonTimer.IsElapsed() )
  491. m_inputButtons |= IN_ATTACK3;
  492. if ( !m_useButtonTimer.IsElapsed() )
  493. m_inputButtons |= IN_USE;
  494. if ( !m_reloadButtonTimer.IsElapsed() )
  495. m_inputButtons |= IN_RELOAD;
  496. if ( !m_forwardButtonTimer.IsElapsed() )
  497. m_inputButtons |= IN_FORWARD;
  498. if ( !m_backwardButtonTimer.IsElapsed() )
  499. m_inputButtons |= IN_BACK;
  500. if ( !m_leftButtonTimer.IsElapsed() )
  501. m_inputButtons |= IN_MOVELEFT;
  502. if ( !m_rightButtonTimer.IsElapsed() )
  503. m_inputButtons |= IN_MOVERIGHT;
  504. if ( !m_jumpButtonTimer.IsElapsed() )
  505. m_inputButtons |= IN_JUMP;
  506. if ( !m_crouchButtonTimer.IsElapsed() )
  507. m_inputButtons |= IN_DUCK;
  508. if ( !m_walkButtonTimer.IsElapsed() )
  509. m_inputButtons |= IN_SPEED;
  510. m_prevInputButtons = m_inputButtons;
  511. inputButtons = m_inputButtons;
  512. EndUpdate();
  513. }
  514. else
  515. {
  516. // HACK: Smooth out body animations
  517. GetBodyInterface()->Update();
  518. // keep buttons pressed between Update() calls (m_prevInputButtons),
  519. // and include any button presses that occurred this tick (m_inputButtons).
  520. inputButtons = m_prevInputButtons | m_inputButtons;
  521. }
  522. //
  523. // Convert NextBot locomotion and posture into
  524. // player commands
  525. //
  526. IBody *body = GetBodyInterface();
  527. ILocomotion *mover = GetLocomotionInterface();
  528. if ( body->IsActualPosture( IBody::CROUCH ) )
  529. {
  530. inputButtons |= IN_DUCK;
  531. }
  532. float forwardSpeed = 0.0f;
  533. float strafeSpeed = 0.0f;
  534. float verticalSpeed = ( m_inputButtons & IN_JUMP ) ? mover->GetRunSpeed() : 0.0f;
  535. if ( inputButtons & IN_FORWARD )
  536. {
  537. forwardSpeed = mover->GetRunSpeed();
  538. }
  539. else if ( inputButtons & IN_BACK )
  540. {
  541. forwardSpeed = -mover->GetRunSpeed();
  542. }
  543. if ( inputButtons & IN_MOVELEFT )
  544. {
  545. strafeSpeed = -mover->GetRunSpeed();
  546. }
  547. else if ( inputButtons & IN_MOVERIGHT )
  548. {
  549. strafeSpeed = mover->GetRunSpeed();
  550. }
  551. if ( NextBotPlayerWalk.GetBool() )
  552. {
  553. inputButtons |= IN_SPEED;
  554. }
  555. if ( NextBotPlayerCrouch.GetBool() )
  556. {
  557. inputButtons |= IN_DUCK;
  558. }
  559. if ( !m_buttonScaleTimer.IsElapsed() )
  560. {
  561. forwardSpeed = mover->GetRunSpeed() * m_forwardScale;
  562. strafeSpeed = mover->GetRunSpeed() * m_rightScale;
  563. }
  564. if ( !NextBotPlayerMove.GetBool() )
  565. {
  566. inputButtons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP );
  567. forwardSpeed = 0.0f;
  568. strafeSpeed = 0.0f;
  569. verticalSpeed = 0.0f;
  570. }
  571. QAngle angles = this->EyeAngles();
  572. #ifdef TERROR
  573. if ( IsStunned() )
  574. {
  575. inputButtons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP | IN_DUCK );
  576. }
  577. // "Look" in the direction we're climbing/stumbling etc. We can't do anything anyway, and it
  578. // keeps motion extraction working.
  579. if ( IsRenderYawOverridden() && IsMotionControlledXY( GetMainActivity() ) )
  580. {
  581. angles[YAW] = GetOverriddenRenderYaw();
  582. }
  583. #endif
  584. // construct a "command" to move the player
  585. CUserCmd userCmd;
  586. _NextBot_BuildUserCommand( &userCmd, angles, forwardSpeed, strafeSpeed, verticalSpeed, inputButtons, 0 );
  587. AvoidPlayers( &userCmd );
  588. // allocate a new command and add it to the player's list of command to process
  589. this->ProcessUsercmds( &userCmd, 1, 1, 0, false );
  590. m_inputButtons = 0;
  591. // actually execute player commands and do player physics
  592. PlayerType::PhysicsSimulate();
  593. }
  594. //----------------------------------------------------------------------------------------------------------
  595. template < typename PlayerType >
  596. inline void NextBotPlayer< PlayerType >::OnNavAreaChanged( CNavArea *enteredArea, CNavArea *leftArea )
  597. {
  598. // propagate into NextBot responders
  599. INextBotEventResponder::OnNavAreaChanged( enteredArea, leftArea );
  600. BaseClass::OnNavAreaChanged( enteredArea, leftArea );
  601. }
  602. //----------------------------------------------------------------------------------------------------------
  603. template < typename PlayerType >
  604. inline void NextBotPlayer< PlayerType >::Touch( CBaseEntity *other )
  605. {
  606. if ( ShouldTouch( other ) )
  607. {
  608. // propagate touch into NextBot event responders
  609. trace_t result;
  610. result = this->GetTouchTrace();
  611. OnContact( other, &result );
  612. }
  613. BaseClass::Touch( other );
  614. }
  615. //----------------------------------------------------------------------------------------------------------
  616. template < typename PlayerType >
  617. inline void NextBotPlayer< PlayerType >::Weapon_Equip( CBaseCombatWeapon *weapon )
  618. {
  619. #ifdef TERROR
  620. // TODO: Reimplement GetDroppingPlayer() into GetLastOwner()
  621. OnPickUp( weapon, weapon->GetDroppingPlayer() );
  622. #else
  623. OnPickUp( weapon, NULL );
  624. #endif
  625. BaseClass::Weapon_Equip( weapon );
  626. }
  627. //----------------------------------------------------------------------------------------------------------
  628. template < typename PlayerType >
  629. inline void NextBotPlayer< PlayerType >::Weapon_Drop( CBaseCombatWeapon *weapon, const Vector *target, const Vector *velocity )
  630. {
  631. OnDrop( weapon );
  632. BaseClass::Weapon_Drop( weapon, target, velocity );
  633. }
  634. //--------------------------------------------------------------------------------------------------------
  635. template < typename PlayerType >
  636. inline void NextBotPlayer< PlayerType >::OnMainActivityComplete( Activity newActivity, Activity oldActivity )
  637. {
  638. #ifdef TERROR
  639. BaseClass::OnMainActivityComplete( newActivity, oldActivity );
  640. #endif
  641. OnAnimationActivityComplete( oldActivity );
  642. }
  643. //--------------------------------------------------------------------------------------------------------
  644. template < typename PlayerType >
  645. inline void NextBotPlayer< PlayerType >::OnMainActivityInterrupted( Activity newActivity, Activity oldActivity )
  646. {
  647. #ifdef TERROR
  648. BaseClass::OnMainActivityInterrupted( newActivity, oldActivity );
  649. #endif
  650. OnAnimationActivityInterrupted( oldActivity );
  651. }
  652. //----------------------------------------------------------------------------------------------------------
  653. template < typename PlayerType >
  654. inline void NextBotPlayer< PlayerType >::Update( void )
  655. {
  656. // don't spend CPU updating if this Survivor is dead
  657. if ( ( this->IsAlive() || !IsDormantWhenDead() ) && !NextBotPlayerStop.GetBool() )
  658. {
  659. INextBot::Update();
  660. }
  661. }
  662. //----------------------------------------------------------------------------------------------------------
  663. template < typename PlayerType >
  664. inline bool NextBotPlayer< PlayerType >::IsAbleToAutoCenterOnLadders( void ) const
  665. {
  666. const ILocomotion *locomotion = GetLocomotionInterface();
  667. return locomotion && locomotion->IsAbleToAutoCenterOnLadder();
  668. }
  669. //----------------------------------------------------------------------------------------------------------
  670. template < typename PlayerType >
  671. inline int NextBotPlayer< PlayerType >::OnTakeDamage_Alive( const CTakeDamageInfo &info )
  672. {
  673. if ( info.GetDamageType() & DMG_BURN )
  674. {
  675. if ( !m_burningTimer.HasStarted() || m_burningTimer.IsGreaterThen( 1.0f ) )
  676. {
  677. // emit ignite event periodically as long as we are burning
  678. OnIgnite();
  679. m_burningTimer.Start();
  680. }
  681. }
  682. // propagate event to components
  683. OnInjured( info );
  684. return BaseClass::OnTakeDamage_Alive( info );
  685. }
  686. //----------------------------------------------------------------------------------------------------------
  687. template < typename PlayerType >
  688. inline int NextBotPlayer< PlayerType >::OnTakeDamage_Dying( const CTakeDamageInfo &info )
  689. {
  690. if ( info.GetDamageType() & DMG_BURN )
  691. {
  692. if ( !m_burningTimer.HasStarted() || m_burningTimer.IsGreaterThen( 1.0f ) )
  693. {
  694. // emit ignite event periodically as long as we are burning
  695. OnIgnite();
  696. m_burningTimer.Start();
  697. }
  698. }
  699. // propagate event to components
  700. OnInjured( info );
  701. return BaseClass::OnTakeDamage_Dying( info );
  702. }
  703. //----------------------------------------------------------------------------------------------------------
  704. template < typename PlayerType >
  705. inline void NextBotPlayer< PlayerType >::Event_Killed( const CTakeDamageInfo &info )
  706. {
  707. // propagate event to my components
  708. OnKilled( info );
  709. BaseClass::Event_Killed( info );
  710. }
  711. //----------------------------------------------------------------------------------------------------------
  712. template < typename PlayerType >
  713. inline void NextBotPlayer< PlayerType >::HandleAnimEvent( animevent_t *event )
  714. {
  715. // propagate event to components
  716. OnAnimationEvent( event );
  717. BaseClass::HandleAnimEvent( event );
  718. }
  719. #endif // _NEXT_BOT_PLAYER_H_