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.

1343 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: UNDONE: Rename this to prop_vehicle.cpp !!!
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "vcollide_parse.h"
  9. #include "vehicle_base.h"
  10. #include "ndebugoverlay.h"
  11. #include "igamemovement.h"
  12. #include "soundenvelope.h"
  13. #include "in_buttons.h"
  14. #include "npc_vehicledriver.h"
  15. #include "physics_saverestore.h"
  16. #include "saverestore_utlvector.h"
  17. #include "func_break.h"
  18. #include "physics_impact_damage.h"
  19. #include "entityblocker.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. #define SF_PROP_VEHICLE_ALWAYSTHINK 0x00000001
  23. ConVar g_debug_vehiclebase( "g_debug_vehiclebase", "0", FCVAR_CHEAT );
  24. extern ConVar g_debug_vehicledriver;
  25. // CFourWheelServerVehicle
  26. BEGIN_SIMPLE_DATADESC_( CFourWheelServerVehicle, CBaseServerVehicle )
  27. DEFINE_EMBEDDED( m_ViewSmoothing ),
  28. END_DATADESC()
  29. // CPropVehicle
  30. BEGIN_DATADESC( CPropVehicle )
  31. DEFINE_EMBEDDED( m_VehiclePhysics ),
  32. // These are necessary to save here because the 'owner' of these fields must be the prop_vehicle
  33. DEFINE_PHYSPTR( m_VehiclePhysics.m_pVehicle ),
  34. DEFINE_PHYSPTR_ARRAY( m_VehiclePhysics.m_pWheels ),
  35. DEFINE_FIELD( m_nVehicleType, FIELD_INTEGER ),
  36. // Physics Influence
  37. DEFINE_FIELD( m_hPhysicsAttacker, FIELD_EHANDLE ),
  38. DEFINE_FIELD( m_flLastPhysicsInfluenceTime, FIELD_TIME ),
  39. #ifdef HL2_EPISODIC
  40. DEFINE_UTLVECTOR( m_hPhysicsChildren, FIELD_EHANDLE ),
  41. #endif // HL2_EPISODIC
  42. // Keys
  43. DEFINE_KEYFIELD( m_vehicleScript, FIELD_STRING, "VehicleScript" ),
  44. DEFINE_FIELD( m_vecSmoothedVelocity, FIELD_VECTOR ),
  45. // Inputs
  46. DEFINE_INPUTFUNC( FIELD_FLOAT, "Throttle", InputThrottle ),
  47. DEFINE_INPUTFUNC( FIELD_FLOAT, "Steer", InputSteering ),
  48. DEFINE_INPUTFUNC( FIELD_FLOAT, "Action", InputAction ),
  49. DEFINE_INPUTFUNC( FIELD_VOID, "HandBrakeOn", InputHandBrakeOn ),
  50. DEFINE_INPUTFUNC( FIELD_VOID, "HandBrakeOff", InputHandBrakeOff ),
  51. END_DATADESC()
  52. LINK_ENTITY_TO_CLASS( prop_vehicle, CPropVehicle );
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. #pragma warning (disable:4355)
  57. CPropVehicle::CPropVehicle() : m_VehiclePhysics( this )
  58. {
  59. SetVehicleType( VEHICLE_TYPE_CAR_WHEELS );
  60. }
  61. #pragma warning (default:4355)
  62. //-----------------------------------------------------------------------------
  63. // Purpose:
  64. //-----------------------------------------------------------------------------
  65. CPropVehicle::~CPropVehicle ()
  66. {
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CPropVehicle::Spawn( )
  72. {
  73. CFourWheelServerVehicle *pServerVehicle = dynamic_cast<CFourWheelServerVehicle*>(GetServerVehicle());
  74. m_VehiclePhysics.SetOuter( this, pServerVehicle );
  75. // NOTE: The model has to be set before we can spawn vehicle physics
  76. BaseClass::Spawn();
  77. SetCollisionGroup( COLLISION_GROUP_VEHICLE );
  78. m_VehiclePhysics.Spawn();
  79. if (!m_VehiclePhysics.Initialize( STRING(m_vehicleScript), m_nVehicleType ))
  80. return;
  81. SetNextThink( gpGlobals->curtime );
  82. m_vecSmoothedVelocity.Init();
  83. }
  84. // this allows reloading the script variables from disk over an existing vehicle state
  85. // This is useful for tuning vehicles or updating old saved game formats
  86. CON_COMMAND(vehicle_flushscript, "Flush and reload all vehicle scripts")
  87. {
  88. PhysFlushVehicleScripts();
  89. for ( CBaseEntity *pEnt = gEntList.FirstEnt(); pEnt != NULL; pEnt = gEntList.NextEnt(pEnt) )
  90. {
  91. IServerVehicle *pServerVehicle = pEnt->GetServerVehicle();
  92. if ( pServerVehicle )
  93. {
  94. pServerVehicle->ReloadScript();
  95. }
  96. }
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose: Restore
  100. //-----------------------------------------------------------------------------
  101. int CPropVehicle::Restore( IRestore &restore )
  102. {
  103. CFourWheelServerVehicle *pServerVehicle = dynamic_cast<CFourWheelServerVehicle*>(GetServerVehicle());
  104. m_VehiclePhysics.SetOuter( this, pServerVehicle );
  105. return BaseClass::Restore( restore );
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose: Tell the vehicle physics system whenever we teleport, so it can fixup the wheels.
  109. //-----------------------------------------------------------------------------
  110. void CPropVehicle::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
  111. {
  112. matrix3x4_t startMatrixInv;
  113. MatrixInvert( EntityToWorldTransform(), startMatrixInv );
  114. BaseClass::Teleport( newPosition, newAngles, newVelocity );
  115. // Calculate the relative transform of the teleport
  116. matrix3x4_t xform;
  117. ConcatTransforms( EntityToWorldTransform(), startMatrixInv, xform );
  118. m_VehiclePhysics.Teleport( xform );
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. //-----------------------------------------------------------------------------
  123. void CPropVehicle::DrawDebugGeometryOverlays()
  124. {
  125. if (m_debugOverlays & OVERLAY_BBOX_BIT)
  126. {
  127. m_VehiclePhysics.DrawDebugGeometryOverlays();
  128. }
  129. BaseClass::DrawDebugGeometryOverlays();
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. //-----------------------------------------------------------------------------
  134. int CPropVehicle::DrawDebugTextOverlays()
  135. {
  136. int nOffset = BaseClass::DrawDebugTextOverlays();
  137. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  138. {
  139. nOffset = m_VehiclePhysics.DrawDebugTextOverlays( nOffset );
  140. }
  141. return nOffset;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. //-----------------------------------------------------------------------------
  146. CBasePlayer *CPropVehicle::HasPhysicsAttacker( float dt )
  147. {
  148. if (gpGlobals->curtime - dt <= m_flLastPhysicsInfluenceTime)
  149. {
  150. return m_hPhysicsAttacker;
  151. }
  152. return NULL;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: Keep track of physgun influence
  156. //-----------------------------------------------------------------------------
  157. void CPropVehicle::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
  158. {
  159. m_hPhysicsAttacker = pPhysGunUser;
  160. m_flLastPhysicsInfluenceTime = gpGlobals->curtime;
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. //-----------------------------------------------------------------------------
  165. void CPropVehicle::InputThrottle( inputdata_t &inputdata )
  166. {
  167. m_VehiclePhysics.SetThrottle( inputdata.value.Float() );
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. //-----------------------------------------------------------------------------
  172. void CPropVehicle::InputSteering( inputdata_t &inputdata )
  173. {
  174. m_VehiclePhysics.SetSteering( inputdata.value.Float(), 2*gpGlobals->frametime );
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. void CPropVehicle::InputAction( inputdata_t &inputdata )
  180. {
  181. m_VehiclePhysics.SetAction( inputdata.value.Float() );
  182. }
  183. void CPropVehicle::InputHandBrakeOn( inputdata_t &inputdata )
  184. {
  185. m_VehiclePhysics.SetHandbrake( true );
  186. }
  187. void CPropVehicle::InputHandBrakeOff( inputdata_t &inputdata )
  188. {
  189. m_VehiclePhysics.ReleaseHandbrake();
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. //-----------------------------------------------------------------------------
  194. void CPropVehicle::Think()
  195. {
  196. m_VehiclePhysics.Think();
  197. // Derived classes of CPropVehicle have their own code to determine how frequently to think.
  198. // But the prop_vehicle entity native to this class will only think one time, so this flag
  199. // was added to allow prop_vehicle to always think without affecting the derived classes.
  200. if( HasSpawnFlags(SF_PROP_VEHICLE_ALWAYSTHINK) )
  201. {
  202. SetNextThink(gpGlobals->curtime);
  203. }
  204. }
  205. #define SMOOTHING_FACTOR 0.9
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. void CPropVehicle::VPhysicsUpdate( IPhysicsObject *pPhysics )
  210. {
  211. if ( IsMarkedForDeletion() )
  212. return;
  213. Vector velocity;
  214. VPhysicsGetObject()->GetVelocity( &velocity, NULL );
  215. //Update our smoothed velocity
  216. m_vecSmoothedVelocity = m_vecSmoothedVelocity * SMOOTHING_FACTOR + velocity * ( 1 - SMOOTHING_FACTOR );
  217. // must be a wheel
  218. if (!m_VehiclePhysics.VPhysicsUpdate( pPhysics ))
  219. return;
  220. BaseClass::VPhysicsUpdate( pPhysics );
  221. }
  222. //-----------------------------------------------------------------------------
  223. // Purpose:
  224. // Output : const Vector
  225. //-----------------------------------------------------------------------------
  226. Vector CPropVehicle::GetSmoothedVelocity( void )
  227. {
  228. return m_vecSmoothedVelocity;
  229. }
  230. //=============================================================================
  231. #ifdef HL2_EPISODIC
  232. //-----------------------------------------------------------------------------
  233. // Purpose: Add an entity to a list which receives physics callbacks from the vehicle
  234. //-----------------------------------------------------------------------------
  235. void CPropVehicle::AddPhysicsChild( CBaseEntity *pChild )
  236. {
  237. // Don't add something we already have
  238. if ( m_hPhysicsChildren.Find( pChild ) != m_hPhysicsChildren.InvalidIndex() )
  239. return ;
  240. m_hPhysicsChildren.AddToTail( pChild );
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose: Removes entity from physics callback list
  244. //-----------------------------------------------------------------------------
  245. void CPropVehicle::RemovePhysicsChild( CBaseEntity *pChild )
  246. {
  247. int elemID = m_hPhysicsChildren.Find( pChild );
  248. if ( m_hPhysicsChildren.IsValidIndex( elemID ) )
  249. {
  250. m_hPhysicsChildren.Remove( elemID );
  251. }
  252. }
  253. #endif //HL2_EPISODIC
  254. //=============================================================================
  255. //-----------------------------------------------------------------------------
  256. // Purpose: Player driveable vehicle class
  257. //-----------------------------------------------------------------------------
  258. IMPLEMENT_SERVERCLASS_ST(CPropVehicleDriveable, DT_PropVehicleDriveable)
  259. SendPropEHandle(SENDINFO(m_hPlayer)),
  260. // SendPropFloat(SENDINFO_DT_NAME(m_controls.throttle, m_throttle), 8, SPROP_ROUNDUP, 0.0f, 1.0f),
  261. SendPropInt(SENDINFO(m_nSpeed), 8),
  262. SendPropInt(SENDINFO(m_nRPM), 13),
  263. SendPropFloat(SENDINFO(m_flThrottle), 0, SPROP_NOSCALE ),
  264. SendPropInt(SENDINFO(m_nBoostTimeLeft), 8),
  265. SendPropInt(SENDINFO(m_nHasBoost), 1, SPROP_UNSIGNED),
  266. SendPropInt(SENDINFO(m_nScannerDisabledWeapons), 1, SPROP_UNSIGNED),
  267. SendPropInt(SENDINFO(m_nScannerDisabledVehicle), 1, SPROP_UNSIGNED),
  268. SendPropInt(SENDINFO(m_bEnterAnimOn), 1, SPROP_UNSIGNED ),
  269. SendPropInt(SENDINFO(m_bExitAnimOn), 1, SPROP_UNSIGNED ),
  270. SendPropInt(SENDINFO(m_bUnableToFire), 1, SPROP_UNSIGNED ),
  271. SendPropVector(SENDINFO(m_vecEyeExitEndpoint), -1, SPROP_COORD),
  272. SendPropBool(SENDINFO(m_bHasGun)),
  273. SendPropVector(SENDINFO(m_vecGunCrosshair), -1, SPROP_COORD),
  274. END_SEND_TABLE();
  275. BEGIN_DATADESC( CPropVehicleDriveable )
  276. // Inputs
  277. DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
  278. DEFINE_INPUTFUNC( FIELD_VOID, "Unlock", InputUnlock ),
  279. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
  280. DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
  281. DEFINE_INPUT( m_bHasGun, FIELD_BOOLEAN, "EnableGun" ),
  282. // Outputs
  283. DEFINE_OUTPUT( m_playerOn, "PlayerOn" ),
  284. DEFINE_OUTPUT( m_playerOff, "PlayerOff" ),
  285. DEFINE_OUTPUT( m_pressedAttack, "PressedAttack" ),
  286. DEFINE_OUTPUT( m_pressedAttack2, "PressedAttack2" ),
  287. DEFINE_OUTPUT( m_attackaxis, "AttackAxis" ),
  288. DEFINE_OUTPUT( m_attack2axis, "Attack2Axis" ),
  289. DEFINE_FIELD( m_hPlayer, FIELD_EHANDLE ),
  290. DEFINE_EMBEDDEDBYREF( m_pServerVehicle ),
  291. DEFINE_FIELD( m_nSpeed, FIELD_INTEGER ),
  292. DEFINE_FIELD( m_nRPM, FIELD_INTEGER ),
  293. DEFINE_FIELD( m_flThrottle, FIELD_FLOAT ),
  294. DEFINE_FIELD( m_nBoostTimeLeft, FIELD_INTEGER ),
  295. DEFINE_FIELD( m_nHasBoost, FIELD_INTEGER ),
  296. DEFINE_FIELD( m_nScannerDisabledWeapons, FIELD_BOOLEAN ),
  297. DEFINE_FIELD( m_nScannerDisabledVehicle, FIELD_BOOLEAN ),
  298. DEFINE_FIELD( m_bUnableToFire, FIELD_BOOLEAN ),
  299. DEFINE_FIELD( m_vecEyeExitEndpoint, FIELD_POSITION_VECTOR ),
  300. DEFINE_FIELD( m_vecGunCrosshair, FIELD_VECTOR ),
  301. DEFINE_FIELD( m_bEngineLocked, FIELD_BOOLEAN ),
  302. DEFINE_KEYFIELD( m_bLocked, FIELD_BOOLEAN, "VehicleLocked" ),
  303. DEFINE_FIELD( m_flMinimumSpeedToEnterExit, FIELD_FLOAT ),
  304. DEFINE_FIELD( m_bEnterAnimOn, FIELD_BOOLEAN ),
  305. DEFINE_FIELD( m_bExitAnimOn, FIELD_BOOLEAN ),
  306. DEFINE_FIELD( m_flTurnOffKeepUpright, FIELD_TIME ),
  307. //DEFINE_FIELD( m_flNoImpactDamageTime, FIELD_TIME ),
  308. DEFINE_FIELD( m_hNPCDriver, FIELD_EHANDLE ),
  309. DEFINE_FIELD( m_hKeepUpright, FIELD_EHANDLE ),
  310. END_DATADESC()
  311. LINK_ENTITY_TO_CLASS( prop_vehicle_driveable, CPropVehicleDriveable );
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. //-----------------------------------------------------------------------------
  315. CPropVehicleDriveable::CPropVehicleDriveable( void ) :
  316. m_pServerVehicle( NULL ),
  317. m_hKeepUpright( NULL ),
  318. m_flTurnOffKeepUpright( 0 ),
  319. m_flNoImpactDamageTime( 0 )
  320. {
  321. m_vecEyeExitEndpoint.Init();
  322. m_vecGunCrosshair.Init();
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. CPropVehicleDriveable::~CPropVehicleDriveable( void )
  328. {
  329. DestroyServerVehicle();
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose:
  333. //-----------------------------------------------------------------------------
  334. void CPropVehicleDriveable::CreateServerVehicle( void )
  335. {
  336. // Create our server vehicle
  337. m_pServerVehicle = new CFourWheelServerVehicle();
  338. m_pServerVehicle->SetVehicle( this );
  339. }
  340. //-----------------------------------------------------------------------------
  341. // Purpose:
  342. //-----------------------------------------------------------------------------
  343. void CPropVehicleDriveable::DestroyServerVehicle()
  344. {
  345. if ( m_pServerVehicle )
  346. {
  347. delete m_pServerVehicle;
  348. m_pServerVehicle = NULL;
  349. }
  350. }
  351. //------------------------------------------------
  352. // Precache
  353. //------------------------------------------------
  354. void CPropVehicleDriveable::Precache( void )
  355. {
  356. BaseClass::Precache();
  357. // This step is needed because if we're precaching from a templated instance, we'll miss our vehicle
  358. // script sounds unless we do the parse below. This instance of the vehicle will be nuked when we're actually created.
  359. if ( m_pServerVehicle == NULL )
  360. {
  361. CreateServerVehicle();
  362. }
  363. // Load the script file and precache our assets
  364. if ( m_pServerVehicle )
  365. {
  366. m_pServerVehicle->Initialize( STRING( m_vehicleScript ) );
  367. }
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose:
  371. //-----------------------------------------------------------------------------
  372. void CPropVehicleDriveable::Spawn( void )
  373. {
  374. // Has to be created before Spawn is called (since that causes Precache to be called)
  375. DestroyServerVehicle();
  376. CreateServerVehicle();
  377. // Initialize our vehicle via script
  378. if ( m_pServerVehicle->Initialize( STRING(m_vehicleScript) ) == false )
  379. {
  380. Warning( "Vehicle (%s) unable to properly initialize due to script error in (%s)!\n", GetEntityName().ToCStr(), STRING( m_vehicleScript ) );
  381. SetThink( &CBaseEntity::SUB_Remove );
  382. SetNextThink( gpGlobals->curtime + 0.1f );
  383. return;
  384. }
  385. BaseClass::Spawn();
  386. m_flMinimumSpeedToEnterExit = 0;
  387. m_takedamage = DAMAGE_EVENTS_ONLY;
  388. m_bEngineLocked = false;
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose:
  392. //-----------------------------------------------------------------------------
  393. int CPropVehicleDriveable::Restore( IRestore &restore )
  394. {
  395. // Has to be created before we can restore
  396. // and we can't create it in the constructor because it could be
  397. // overridden by a derived class.
  398. DestroyServerVehicle();
  399. CreateServerVehicle();
  400. int nRetVal = BaseClass::Restore( restore );
  401. return nRetVal;
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Purpose: Do extra fix-up after restore
  405. //-----------------------------------------------------------------------------
  406. void CPropVehicleDriveable::OnRestore( void )
  407. {
  408. BaseClass::OnRestore();
  409. // NOTE: This is necessary to prevent overflow of datatables on level transition
  410. // since the last exit eyepoint in the last level will have been fixed up
  411. // based on the level landmarks, resulting in a position that lies outside
  412. // typical map coordinates. If we're not in the middle of an exit anim, the
  413. // eye exit endpoint field isn't being used at all.
  414. if ( !m_bExitAnimOn )
  415. {
  416. m_vecEyeExitEndpoint = GetAbsOrigin();
  417. }
  418. m_flNoImpactDamageTime = gpGlobals->curtime + 5.0f;
  419. IServerVehicle *pServerVehicle = GetServerVehicle();
  420. if ( pServerVehicle != NULL )
  421. {
  422. // Restore the passenger information we're holding on to
  423. pServerVehicle->RestorePassengerInfo();
  424. }
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Purpose: Vehicles are permanently oriented off angle for vphysics.
  428. //-----------------------------------------------------------------------------
  429. void CPropVehicleDriveable::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const
  430. {
  431. // This call is necessary to cause m_rgflCoordinateFrame to be recomputed
  432. const matrix3x4_t &entityToWorld = EntityToWorldTransform();
  433. if (pForward != NULL)
  434. {
  435. MatrixGetColumn( entityToWorld, 1, *pForward );
  436. }
  437. if (pRight != NULL)
  438. {
  439. MatrixGetColumn( entityToWorld, 0, *pRight );
  440. }
  441. if (pUp != NULL)
  442. {
  443. MatrixGetColumn( entityToWorld, 2, *pUp );
  444. }
  445. }
  446. //-----------------------------------------------------------------------------
  447. // Purpose: AngleVectors equivalent that accounts for the hacked 90 degree rotation of vehicles
  448. // BUGBUG: VPhysics is hardcoded so that vehicles must face down Y instead of X like everything else
  449. //-----------------------------------------------------------------------------
  450. void CPropVehicleDriveable::VehicleAngleVectors( const QAngle &angles, Vector *pForward, Vector *pRight, Vector *pUp )
  451. {
  452. AngleVectors( angles, pRight, pForward, pUp );
  453. if ( pForward )
  454. {
  455. *pForward *= -1;
  456. }
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose:
  460. //-----------------------------------------------------------------------------
  461. void CPropVehicleDriveable::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  462. {
  463. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  464. if ( !pPlayer )
  465. return;
  466. ResetUseKey( pPlayer );
  467. m_pServerVehicle->HandlePassengerEntry( pPlayer, (value>0) );
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose:
  471. //-----------------------------------------------------------------------------
  472. CBaseEntity *CPropVehicleDriveable::GetDriver( void )
  473. {
  474. if ( m_hNPCDriver )
  475. return m_hNPCDriver;
  476. return m_hPlayer;
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose:
  480. //-----------------------------------------------------------------------------
  481. void CPropVehicleDriveable::EnterVehicle( CBaseCombatCharacter *pPassenger )
  482. {
  483. if ( pPassenger == NULL )
  484. return;
  485. CBasePlayer *pPlayer = ToBasePlayer( pPassenger );
  486. if ( pPlayer != NULL )
  487. {
  488. // Remove any player who may be in the vehicle at the moment
  489. if ( m_hPlayer )
  490. {
  491. ExitVehicle( VEHICLE_ROLE_DRIVER );
  492. }
  493. m_hPlayer = pPlayer;
  494. m_playerOn.FireOutput( pPlayer, this, 0 );
  495. // Don't start the engine if the player's using an entry animation,
  496. // because we want to start the engine once the animation is done.
  497. if ( !m_bEnterAnimOn )
  498. {
  499. StartEngine();
  500. }
  501. // Start Thinking
  502. SetNextThink( gpGlobals->curtime );
  503. Vector vecViewOffset = m_pServerVehicle->GetSavedViewOffset();
  504. // Clear our state
  505. m_pServerVehicle->InitViewSmoothing( pPlayer->GetAbsOrigin() + vecViewOffset, pPlayer->EyeAngles() );
  506. m_VehiclePhysics.GetVehicle()->OnVehicleEnter();
  507. }
  508. else
  509. {
  510. // NPCs are not yet supported - jdw
  511. Assert( 0 );
  512. }
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. //-----------------------------------------------------------------------------
  517. void CPropVehicleDriveable::ExitVehicle( int nRole )
  518. {
  519. CBasePlayer *pPlayer = m_hPlayer;
  520. if ( !pPlayer )
  521. return;
  522. m_hPlayer = NULL;
  523. ResetUseKey( pPlayer );
  524. m_playerOff.FireOutput( pPlayer, this, 0 );
  525. // clear out the fire buttons
  526. m_attackaxis.Set( 0, pPlayer, this );
  527. m_attack2axis.Set( 0, pPlayer, this );
  528. m_nSpeed = 0;
  529. m_flThrottle = 0.0f;
  530. StopEngine();
  531. m_VehiclePhysics.GetVehicle()->OnVehicleExit();
  532. // Clear our state
  533. m_pServerVehicle->InitViewSmoothing( vec3_origin, vec3_angle );
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose:
  537. //-----------------------------------------------------------------------------
  538. void CPropVehicleDriveable::ResetUseKey( CBasePlayer *pPlayer )
  539. {
  540. pPlayer->m_afButtonPressed &= ~IN_USE;
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose:
  544. //-----------------------------------------------------------------------------
  545. void CPropVehicleDriveable::DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd )
  546. {
  547. //Lose control when the player dies
  548. if ( pPlayer->IsAlive() == false )
  549. return;
  550. DriveVehicle( TICK_INTERVAL, ucmd, pPlayer->m_afButtonPressed, pPlayer->m_afButtonReleased );
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose:
  554. //-----------------------------------------------------------------------------
  555. void CPropVehicleDriveable::DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased )
  556. {
  557. int iButtons = ucmd->buttons;
  558. m_VehiclePhysics.UpdateDriverControls( ucmd, flFrameTime );
  559. m_nSpeed = m_VehiclePhysics.GetSpeed(); //send speed to client
  560. m_nRPM = clamp( m_VehiclePhysics.GetRPM(), 0, 4095 );
  561. m_nBoostTimeLeft = m_VehiclePhysics.BoostTimeLeft();
  562. m_nHasBoost = m_VehiclePhysics.HasBoost();
  563. m_flThrottle = m_VehiclePhysics.GetThrottle();
  564. m_nScannerDisabledWeapons = false; // off for now, change once we have scanners
  565. m_nScannerDisabledVehicle = false; // off for now, change once we have scanners
  566. //
  567. // Fire the appropriate outputs based on button pressed events.
  568. //
  569. // BUGBUG: m_afButtonPressed is broken - check the player.cpp code!!!
  570. float attack = 0, attack2 = 0;
  571. if ( iButtonsDown & IN_ATTACK )
  572. {
  573. m_pressedAttack.FireOutput( this, this, 0 );
  574. }
  575. if ( iButtonsDown & IN_ATTACK2 )
  576. {
  577. m_pressedAttack2.FireOutput( this, this, 0 );
  578. }
  579. if ( iButtons & IN_ATTACK )
  580. {
  581. attack = 1;
  582. }
  583. if ( iButtons & IN_ATTACK2 )
  584. {
  585. attack2 = 1;
  586. }
  587. m_attackaxis.Set( attack, this, this );
  588. m_attack2axis.Set( attack2, this, this );
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose: Tells whether or not the car has been overturned
  592. // Output : Returns true on success, false on failure.
  593. //-----------------------------------------------------------------------------
  594. bool CPropVehicleDriveable::IsOverturned( void )
  595. {
  596. Vector vUp;
  597. VehicleAngleVectors( GetAbsAngles(), NULL, NULL, &vUp );
  598. float upDot = DotProduct( Vector(0,0,1), vUp );
  599. // Tweak this number to adjust what's considered "overturned"
  600. if ( upDot < 0.0f )
  601. return true;
  602. return false;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose:
  606. //-----------------------------------------------------------------------------
  607. void CPropVehicleDriveable::Think()
  608. {
  609. BaseClass::Think();
  610. if ( ShouldThink() )
  611. {
  612. SetNextThink( gpGlobals->curtime );
  613. }
  614. // If we have an NPC Driver, tell him to drive
  615. if ( m_hNPCDriver )
  616. {
  617. GetServerVehicle()->NPC_DriveVehicle();
  618. }
  619. // Keep thinking while we're waiting to turn off the keep upright
  620. if ( m_flTurnOffKeepUpright )
  621. {
  622. SetNextThink( gpGlobals->curtime );
  623. // Time up?
  624. if ( m_hKeepUpright != NULL && m_flTurnOffKeepUpright < gpGlobals->curtime )
  625. {
  626. variant_t emptyVariant;
  627. m_hKeepUpright->AcceptInput( "TurnOff", this, this, emptyVariant, USE_TOGGLE );
  628. m_flTurnOffKeepUpright = 0;
  629. UTIL_Remove( m_hKeepUpright );
  630. }
  631. }
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose:
  635. //-----------------------------------------------------------------------------
  636. void CPropVehicleDriveable::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
  637. {
  638. // If the engine's not active, prevent driving
  639. if ( !IsEngineOn() || m_bEngineLocked )
  640. return;
  641. // If the player's entering/exiting the vehicle, prevent movement
  642. if ( m_bEnterAnimOn || m_bExitAnimOn )
  643. return;
  644. DriveVehicle( player, ucmd );
  645. }
  646. //-----------------------------------------------------------------------------
  647. // Purpose: Prevent the player from entering / exiting the vehicle
  648. //-----------------------------------------------------------------------------
  649. void CPropVehicleDriveable::InputLock( inputdata_t &inputdata )
  650. {
  651. m_bLocked = true;
  652. }
  653. //-----------------------------------------------------------------------------
  654. // Purpose: Allow the player to enter / exit the vehicle
  655. //-----------------------------------------------------------------------------
  656. void CPropVehicleDriveable::InputUnlock( inputdata_t &inputdata )
  657. {
  658. m_bLocked = false;
  659. }
  660. //-----------------------------------------------------------------------------
  661. // Purpose: Return true of the player's allowed to enter the vehicle
  662. //-----------------------------------------------------------------------------
  663. bool CPropVehicleDriveable::CanEnterVehicle( CBaseEntity *pEntity )
  664. {
  665. // Only drivers are supported
  666. Assert( pEntity && pEntity->IsPlayer() );
  667. // Prevent entering if the vehicle's being driven by an NPC
  668. if ( GetDriver() && GetDriver() != pEntity )
  669. return false;
  670. // Can't enter if we're upside-down
  671. if ( IsOverturned() )
  672. return false;
  673. // Prevent entering if the vehicle's locked, or if it's moving too fast.
  674. return ( !m_bLocked && (m_nSpeed <= m_flMinimumSpeedToEnterExit) );
  675. }
  676. //-----------------------------------------------------------------------------
  677. // Purpose: Return true of the player's allowed to exit the vehicle
  678. //-----------------------------------------------------------------------------
  679. bool CPropVehicleDriveable::CanExitVehicle( CBaseEntity *pEntity )
  680. {
  681. // Prevent exiting if the vehicle's locked, or if it's moving too fast.
  682. return ( !m_bEnterAnimOn && !m_bExitAnimOn && !m_bLocked && (m_nSpeed <= m_flMinimumSpeedToEnterExit) );
  683. }
  684. //-----------------------------------------------------------------------------
  685. // Purpose:
  686. //-----------------------------------------------------------------------------
  687. void CPropVehicleDriveable::InputTurnOn( inputdata_t &inputdata )
  688. {
  689. m_bEngineLocked = false;
  690. StartEngine();
  691. m_VehiclePhysics.SetDisableEngine( false );
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Purpose:
  695. //-----------------------------------------------------------------------------
  696. void CPropVehicleDriveable::InputTurnOff( inputdata_t &inputdata )
  697. {
  698. m_bEngineLocked = true;
  699. StopEngine();
  700. m_VehiclePhysics.SetDisableEngine( true );
  701. }
  702. //-----------------------------------------------------------------------------
  703. // Purpose: Check to see if the engine is on.
  704. //-----------------------------------------------------------------------------
  705. bool CPropVehicleDriveable::IsEngineOn( void )
  706. {
  707. return m_VehiclePhysics.IsOn();
  708. }
  709. //-----------------------------------------------------------------------------
  710. // Purpose: Turn on the engine, but only if we're allowed to
  711. //-----------------------------------------------------------------------------
  712. void CPropVehicleDriveable::StartEngine( void )
  713. {
  714. if ( m_bEngineLocked )
  715. {
  716. m_VehiclePhysics.SetHandbrake( true );
  717. return;
  718. }
  719. m_VehiclePhysics.TurnOn();
  720. }
  721. //-----------------------------------------------------------------------------
  722. // Purpose:
  723. //-----------------------------------------------------------------------------
  724. void CPropVehicleDriveable::StopEngine( void )
  725. {
  726. m_VehiclePhysics.TurnOff();
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Purpose: // The player takes damage if he hits something going fast enough
  730. //-----------------------------------------------------------------------------
  731. void CPropVehicleDriveable::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
  732. {
  733. //=============================================================================
  734. #ifdef HL2_EPISODIC
  735. // Notify all children
  736. for ( int i = 0; i < m_hPhysicsChildren.Count(); i++ )
  737. {
  738. if ( m_hPhysicsChildren[i] == NULL )
  739. continue;
  740. m_hPhysicsChildren[i]->VPhysicsCollision( index, pEvent );
  741. }
  742. #endif // HL2_EPISODIC
  743. //=============================================================================
  744. // Don't care if we don't have a driver
  745. CBaseCombatCharacter *pDriver = GetDriver() ? GetDriver()->MyCombatCharacterPointer() : NULL;
  746. if ( !pDriver )
  747. return;
  748. // Make sure we don't keep hitting the same entity
  749. int otherIndex = !index;
  750. CBaseEntity *pHitEntity = pEvent->pEntities[otherIndex];
  751. if ( pEvent->deltaCollisionTime < 0.5 && (pHitEntity == this) )
  752. return;
  753. BaseClass::VPhysicsCollision( index, pEvent );
  754. // if this is a bone follower, promote to the owner entity
  755. if ( pHitEntity->GetOwnerEntity() && (pHitEntity->GetEffects() & EF_NODRAW) )
  756. {
  757. CBaseEntity *pOwner = pHitEntity->GetOwnerEntity();
  758. // no friendly bone follower damage
  759. // this allows strider legs to damage the player on impact but not d0g for example
  760. if ( pDriver->IRelationType( pOwner ) == D_LI )
  761. return;
  762. }
  763. // If we hit hard enough, damage the player
  764. // Don't take damage from ramming bad guys
  765. if ( pHitEntity->MyNPCPointer() )
  766. {
  767. return;
  768. }
  769. // Don't take damage from ramming ragdolls
  770. if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL )
  771. return;
  772. // Ignore func_breakables
  773. CBreakable *pBreakable = dynamic_cast<CBreakable *>(pHitEntity);
  774. if ( pBreakable )
  775. {
  776. // ROBIN: Do we want to only do this on func_breakables that are about to die?
  777. //if ( pBreakable->HasSpawnFlags( SF_PHYSICS_BREAK_IMMEDIATELY ) )
  778. return;
  779. }
  780. // Over our skill's minimum crash level?
  781. int damageType = 0;
  782. float flDamage = CalculatePhysicsImpactDamage( index, pEvent, gDefaultPlayerVehicleImpactDamageTable, 1.0, true, damageType );
  783. if ( flDamage > 0 && m_flNoImpactDamageTime < gpGlobals->curtime )
  784. {
  785. Vector damagePos;
  786. pEvent->pInternalData->GetContactPoint( damagePos );
  787. Vector damageForce = pEvent->postVelocity[index] * pEvent->pObjects[index]->GetMass();
  788. CTakeDamageInfo info( this, GetDriver(), damageForce, damagePos, flDamage, (damageType|DMG_VEHICLE) );
  789. GetDriver()->TakeDamage( info );
  790. }
  791. }
  792. int CPropVehicleDriveable::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  793. {
  794. return GetPhysics()->VPhysicsGetObjectList( pList, listMax );
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose: Handle trace attacks from the physcannon
  798. //-----------------------------------------------------------------------------
  799. void CPropVehicleDriveable::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
  800. {
  801. // If we've just been zapped by the physcannon, try and right ourselves
  802. if ( info.GetDamageType() & DMG_PHYSGUN )
  803. {
  804. float flUprightStrength = GetUprightStrength();
  805. if ( flUprightStrength )
  806. {
  807. // Update our strength value if we already have an upright controller
  808. if ( m_hKeepUpright )
  809. {
  810. variant_t limitVariant;
  811. limitVariant.SetFloat( flUprightStrength );
  812. m_hKeepUpright->AcceptInput( "SetAngularLimit", this, this, limitVariant, USE_TOGGLE );
  813. }
  814. else
  815. {
  816. // If we don't have one, create an upright controller for us
  817. m_hKeepUpright = CreateKeepUpright( GetAbsOrigin(), vec3_angle, this, GetUprightStrength(), false );
  818. }
  819. Assert( m_hKeepUpright );
  820. variant_t emptyVariant;
  821. m_hKeepUpright->AcceptInput( "TurnOn", this, this, emptyVariant, USE_TOGGLE );
  822. // Turn off the keepupright after a short time
  823. m_flTurnOffKeepUpright = gpGlobals->curtime + GetUprightTime();
  824. SetNextThink( gpGlobals->curtime );
  825. }
  826. #ifdef HL2_EPISODIC
  827. // Notify all children
  828. for ( int i = 0; i < m_hPhysicsChildren.Count(); i++ )
  829. {
  830. if ( m_hPhysicsChildren[i] == NULL )
  831. continue;
  832. variant_t emptyVariant;
  833. m_hPhysicsChildren[i]->AcceptInput( "VehiclePunted", info.GetAttacker(), this, emptyVariant, USE_TOGGLE );
  834. }
  835. #endif // HL2_EPISODIC
  836. }
  837. BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
  838. }
  839. //=============================================================================
  840. // Passenger carrier
  841. //-----------------------------------------------------------------------------
  842. // Purpose:
  843. // Input : *pPassenger -
  844. // bCompanion -
  845. // Output : Returns true on success, false on failure.
  846. //-----------------------------------------------------------------------------
  847. bool CPropVehicleDriveable::NPC_CanEnterVehicle( CAI_BaseNPC *pPassenger, bool bCompanion )
  848. {
  849. // Always allowed unless a leaf class says otherwise
  850. return true;
  851. }
  852. //-----------------------------------------------------------------------------
  853. // Purpose:
  854. // Input : *pPassenger -
  855. // bCompanion -
  856. // Output : Returns true on success, false on failure.
  857. //-----------------------------------------------------------------------------
  858. bool CPropVehicleDriveable::NPC_CanExitVehicle( CAI_BaseNPC *pPassenger, bool bCompanion )
  859. {
  860. // Always allowed unless a leaf class says otherwise
  861. return true;
  862. }
  863. //-----------------------------------------------------------------------------
  864. // Purpose:
  865. // Input : *pPassenger -
  866. // bCompanion -
  867. // Output : Returns true on success, false on failure.
  868. //-----------------------------------------------------------------------------
  869. bool CPropVehicleDriveable::NPC_AddPassenger( CAI_BaseNPC *pPassenger, string_t strRoleName, int nSeatID )
  870. {
  871. // Must be allowed to enter
  872. if ( NPC_CanEnterVehicle( pPassenger, true /*FIXME*/ ) == false )
  873. return false;
  874. IServerVehicle *pVehicleServer = GetServerVehicle();
  875. if ( pVehicleServer != NULL )
  876. return pVehicleServer->NPC_AddPassenger( pPassenger, strRoleName, nSeatID );
  877. return true;
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Purpose:
  881. // Input : *pPassenger -
  882. // bCompanion -
  883. //-----------------------------------------------------------------------------
  884. bool CPropVehicleDriveable::NPC_RemovePassenger( CAI_BaseNPC *pPassenger )
  885. {
  886. // Must be allowed to exit
  887. if ( NPC_CanExitVehicle( pPassenger, true /*FIXME*/ ) == false )
  888. return false;
  889. IServerVehicle *pVehicleServer = GetServerVehicle();
  890. if ( pVehicleServer != NULL )
  891. return pVehicleServer->NPC_RemovePassenger( pPassenger );
  892. return true;
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Purpose:
  896. // Input : *pVictim -
  897. // &info -
  898. //-----------------------------------------------------------------------------
  899. void CPropVehicleDriveable::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info )
  900. {
  901. CBaseEntity *pDriver = GetDriver();
  902. if ( pDriver != NULL )
  903. {
  904. pDriver->Event_KilledOther( pVictim, info );
  905. }
  906. BaseClass::Event_KilledOther( pVictim, info );
  907. }
  908. //========================================================================================================================================
  909. // FOUR WHEEL PHYSICS VEHICLE SERVER VEHICLE
  910. //========================================================================================================================================
  911. CFourWheelServerVehicle::CFourWheelServerVehicle( void )
  912. {
  913. // Setup our smoothing data
  914. memset( &m_ViewSmoothing, 0, sizeof( m_ViewSmoothing ) );
  915. m_ViewSmoothing.bClampEyeAngles = true;
  916. m_ViewSmoothing.bDampenEyePosition = true;
  917. m_ViewSmoothing.flPitchCurveZero = PITCH_CURVE_ZERO;
  918. m_ViewSmoothing.flPitchCurveLinear = PITCH_CURVE_LINEAR;
  919. m_ViewSmoothing.flRollCurveZero = ROLL_CURVE_ZERO;
  920. m_ViewSmoothing.flRollCurveLinear = ROLL_CURVE_LINEAR;
  921. }
  922. #ifdef HL2_EPISODIC
  923. ConVar r_JeepFOV( "r_JeepFOV", "82", FCVAR_CHEAT | FCVAR_REPLICATED );
  924. #else
  925. ConVar r_JeepFOV( "r_JeepFOV", "90", FCVAR_CHEAT | FCVAR_REPLICATED );
  926. #endif // HL2_EPISODIC
  927. //-----------------------------------------------------------------------------
  928. // Purpose: Setup our view smoothing information
  929. //-----------------------------------------------------------------------------
  930. void CFourWheelServerVehicle::InitViewSmoothing( const Vector &vecOrigin, const QAngle &vecAngles )
  931. {
  932. m_ViewSmoothing.bWasRunningAnim = false;
  933. m_ViewSmoothing.vecOriginSaved = vecOrigin;
  934. m_ViewSmoothing.vecAnglesSaved = vecAngles;
  935. m_ViewSmoothing.flFOV = r_JeepFOV.GetFloat();
  936. }
  937. //-----------------------------------------------------------------------------
  938. // Purpose:
  939. //-----------------------------------------------------------------------------
  940. void CFourWheelServerVehicle::SetVehicle( CBaseEntity *pVehicle )
  941. {
  942. ASSERT( dynamic_cast<CPropVehicleDriveable*>(pVehicle) );
  943. BaseClass::SetVehicle( pVehicle );
  944. // Save this for view smoothing
  945. if ( pVehicle != NULL )
  946. {
  947. m_ViewSmoothing.pVehicle = pVehicle->GetBaseAnimating();
  948. }
  949. }
  950. //-----------------------------------------------------------------------------
  951. // Purpose: Modify the player view/camera while in a vehicle
  952. //-----------------------------------------------------------------------------
  953. void CFourWheelServerVehicle::GetVehicleViewPosition( int nRole, Vector *pAbsOrigin, QAngle *pAbsAngles, float *pFOV /*= NULL*/ )
  954. {
  955. CBaseEntity *pDriver = GetPassenger( nRole );
  956. if ( pDriver && pDriver->IsPlayer())
  957. {
  958. CBasePlayer *pPlayerDriver = ToBasePlayer( pDriver );
  959. CPropVehicleDriveable *pVehicle = GetFourWheelVehicle();
  960. SharedVehicleViewSmoothing( pPlayerDriver,
  961. pAbsOrigin, pAbsAngles,
  962. pVehicle->IsEnterAnimOn(), pVehicle->IsExitAnimOn(),
  963. pVehicle->GetEyeExitEndpoint(),
  964. &m_ViewSmoothing,
  965. pFOV );
  966. }
  967. else
  968. {
  969. // NPCs are not supported
  970. Assert( 0 );
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose:
  975. //-----------------------------------------------------------------------------
  976. const vehicleparams_t *CFourWheelServerVehicle::GetVehicleParams( void )
  977. {
  978. return &GetFourWheelVehiclePhysics()->GetVehicleParams();
  979. }
  980. //-----------------------------------------------------------------------------
  981. // Purpose:
  982. //-----------------------------------------------------------------------------
  983. const vehicle_operatingparams_t *CFourWheelServerVehicle::GetVehicleOperatingParams( void )
  984. {
  985. return &GetFourWheelVehiclePhysics()->GetVehicleOperatingParams();
  986. }
  987. //-----------------------------------------------------------------------------
  988. // Purpose:
  989. //-----------------------------------------------------------------------------
  990. const vehicle_controlparams_t *CFourWheelServerVehicle::GetVehicleControlParams( void )
  991. {
  992. return &GetFourWheelVehiclePhysics()->GetVehicleControls();
  993. }
  994. IPhysicsVehicleController *CFourWheelServerVehicle::GetVehicleController()
  995. {
  996. return GetFourWheelVehiclePhysics()->GetVehicleController();
  997. }
  998. //-----------------------------------------------------------------------------
  999. // Purpose:
  1000. //-----------------------------------------------------------------------------
  1001. CPropVehicleDriveable *CFourWheelServerVehicle::GetFourWheelVehicle( void )
  1002. {
  1003. return (CPropVehicleDriveable *)m_pVehicle;
  1004. }
  1005. //-----------------------------------------------------------------------------
  1006. // Purpose:
  1007. //-----------------------------------------------------------------------------
  1008. CFourWheelVehiclePhysics *CFourWheelServerVehicle::GetFourWheelVehiclePhysics( void )
  1009. {
  1010. CPropVehicleDriveable *pVehicle = GetFourWheelVehicle();
  1011. return pVehicle->GetPhysics();
  1012. }
  1013. //-----------------------------------------------------------------------------
  1014. // Purpose:
  1015. //-----------------------------------------------------------------------------
  1016. bool CFourWheelServerVehicle::IsVehicleUpright( void )
  1017. {
  1018. return (GetFourWheelVehicle()->IsOverturned() == false);
  1019. }
  1020. bool CFourWheelServerVehicle::IsVehicleBodyInWater()
  1021. {
  1022. return GetFourWheelVehicle()->IsVehicleBodyInWater();
  1023. }
  1024. //-----------------------------------------------------------------------------
  1025. // Purpose:
  1026. //-----------------------------------------------------------------------------
  1027. bool CFourWheelServerVehicle::IsPassengerEntering( void )
  1028. {
  1029. return GetFourWheelVehicle()->IsEnterAnimOn();
  1030. }
  1031. //-----------------------------------------------------------------------------
  1032. // Purpose:
  1033. //-----------------------------------------------------------------------------
  1034. bool CFourWheelServerVehicle::IsPassengerExiting( void )
  1035. {
  1036. return GetFourWheelVehicle()->IsExitAnimOn();
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // Purpose:
  1040. //-----------------------------------------------------------------------------
  1041. void CFourWheelServerVehicle::NPC_SetDriver( CNPC_VehicleDriver *pDriver )
  1042. {
  1043. if ( pDriver )
  1044. {
  1045. m_nNPCButtons = 0;
  1046. GetFourWheelVehicle()->m_hNPCDriver = pDriver;
  1047. GetFourWheelVehicle()->StartEngine();
  1048. SetVehicleVolume( 1.0 ); // Vehicles driven by NPCs are louder
  1049. // Set our owner entity to be the NPC, so it can path check without hitting us
  1050. GetFourWheelVehicle()->SetOwnerEntity( pDriver );
  1051. // Start Thinking
  1052. GetFourWheelVehicle()->SetNextThink( gpGlobals->curtime );
  1053. }
  1054. else
  1055. {
  1056. GetFourWheelVehicle()->m_hNPCDriver = NULL;
  1057. GetFourWheelVehicle()->StopEngine();
  1058. GetFourWheelVehicle()->SetOwnerEntity( NULL );
  1059. SetVehicleVolume( 0.5 );
  1060. }
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. // Purpose:
  1064. //-----------------------------------------------------------------------------
  1065. void CFourWheelServerVehicle::NPC_DriveVehicle( void )
  1066. {
  1067. #ifdef HL2_DLL
  1068. if ( g_debug_vehicledriver.GetInt() )
  1069. {
  1070. if ( m_nNPCButtons )
  1071. {
  1072. Vector vecForward, vecRight;
  1073. GetFourWheelVehicle()->GetVectors( &vecForward, &vecRight, NULL );
  1074. if ( m_nNPCButtons & IN_FORWARD )
  1075. {
  1076. NDebugOverlay::Line( GetFourWheelVehicle()->GetAbsOrigin(), GetFourWheelVehicle()->GetAbsOrigin() + vecForward * 200, 0,255,0, true, 0.1 );
  1077. }
  1078. if ( m_nNPCButtons & IN_BACK )
  1079. {
  1080. NDebugOverlay::Line( GetFourWheelVehicle()->GetAbsOrigin(), GetFourWheelVehicle()->GetAbsOrigin() - vecForward * 200, 0,255,0, true, 0.1 );
  1081. }
  1082. if ( m_nNPCButtons & IN_MOVELEFT )
  1083. {
  1084. NDebugOverlay::Line( GetFourWheelVehicle()->GetAbsOrigin(), GetFourWheelVehicle()->GetAbsOrigin() - vecRight * 200 * -m_flTurnDegrees, 0,255,0, true, 0.1 );
  1085. }
  1086. if ( m_nNPCButtons & IN_MOVERIGHT )
  1087. {
  1088. NDebugOverlay::Line( GetFourWheelVehicle()->GetAbsOrigin(), GetFourWheelVehicle()->GetAbsOrigin() + vecRight * 200 * m_flTurnDegrees, 0,255,0, true, 0.1 );
  1089. }
  1090. if ( m_nNPCButtons & IN_JUMP )
  1091. {
  1092. NDebugOverlay::Box( GetFourWheelVehicle()->GetAbsOrigin(), -Vector(20,20,20), Vector(20,20,20), 0,255,0, true, 0.1 );
  1093. }
  1094. }
  1095. }
  1096. #endif
  1097. int buttonsChanged = m_nPrevNPCButtons ^ m_nNPCButtons;
  1098. int afButtonPressed = buttonsChanged & m_nNPCButtons; // The changed ones still down are "pressed"
  1099. int afButtonReleased = buttonsChanged & (~m_nNPCButtons); // The ones not down are "released"
  1100. CUserCmd fakeCmd;
  1101. fakeCmd.Reset();
  1102. fakeCmd.buttons = m_nNPCButtons;
  1103. fakeCmd.forwardmove += 200.0f * ( m_nNPCButtons & IN_FORWARD );
  1104. fakeCmd.forwardmove -= 200.0f * ( m_nNPCButtons & IN_BACK );
  1105. fakeCmd.sidemove -= 200.0f * ( m_nNPCButtons & IN_MOVELEFT );
  1106. fakeCmd.sidemove += 200.0f * ( m_nNPCButtons & IN_MOVERIGHT );
  1107. GetFourWheelVehicle()->DriveVehicle( gpGlobals->frametime, &fakeCmd, afButtonPressed, afButtonReleased );
  1108. m_nPrevNPCButtons = m_nNPCButtons;
  1109. // NPC's cheat by using analog steering.
  1110. GetFourWheelVehiclePhysics()->SetSteering( m_flTurnDegrees, 0 );
  1111. // Clear out attack buttons each frame
  1112. m_nNPCButtons &= ~IN_ATTACK;
  1113. m_nNPCButtons &= ~IN_ATTACK2;
  1114. }
  1115. //-----------------------------------------------------------------------------
  1116. // Purpose:
  1117. // Input : nWheelIndex -
  1118. // &vecPos -
  1119. //-----------------------------------------------------------------------------
  1120. bool CFourWheelServerVehicle::GetWheelContactPoint( int nWheelIndex, Vector &vecPos )
  1121. {
  1122. // Dig through a couple layers to get to our data
  1123. CFourWheelVehiclePhysics *pVehiclePhysics = GetFourWheelVehiclePhysics();
  1124. if ( pVehiclePhysics )
  1125. {
  1126. IPhysicsVehicleController *pVehicleController = pVehiclePhysics->GetVehicle();
  1127. if ( pVehicleController )
  1128. {
  1129. return pVehicleController->GetWheelContactPoint( nWheelIndex, &vecPos, NULL );
  1130. }
  1131. }
  1132. return false;
  1133. }