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.

1354 lines
44 KiB

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