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.

551 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "vehicle_base.h"
  9. #include "engine/IEngineSound.h"
  10. #include "in_buttons.h"
  11. #include "ammodef.h"
  12. #include "IEffects.h"
  13. #include "beam_shared.h"
  14. #include "weapon_gauss.h"
  15. #include "soundenvelope.h"
  16. #include "decals.h"
  17. #include "soundent.h"
  18. #include "te_effect_dispatch.h"
  19. #define VEHICLE_HITBOX_DRIVER 1
  20. #define JETSKI_SHOCK_LENGTH_LONG2 0.35f //
  21. #define JETSKI_SHOCK_LENGTH_LONG 0.25f // meters (about 12 inches)
  22. #define JETSKI_SHOCK_LENGTH_REST 0.15f // meters (about 8 inches)
  23. #define JETSKI_SHOCK_LENGTH_SHORT 0.1f // meters (about 4 inches)
  24. #define JETSKI_PITCH_AND_ROLL_RATE 0.02f
  25. #define JETSKI_FRICTION_MIN 0.3f
  26. #define JETSKI_FRICTION_MAX 0.8f
  27. #define JETSKI_SPLASH_DISTANCE 40.0f
  28. #define JETSKI_SPLASH_SPRAY 1
  29. #define JETSKI_SPLASH_SPRAY_SIZE 2.0f
  30. #define JETSKI_SPLASH_GURGLE 2
  31. #define JETSKI_SPLASH_GURGLE_SIZE 8.0f
  32. #define JETSKI_SPLASH_RIPPLE 3
  33. #define JETSKI_SPLASH_RIPPLE_SIZE 10.0f
  34. #define JETSKI_DRAG_NO_THRUST_IN_WATER 10.0f
  35. #define JETSKI_DRAG_NO_THRUST_ON_WATER 30.0f
  36. #define JETSKI_DRAG_LEAN_ADD 10.0f
  37. #define JETSKI_DRAG_IN_REVERSE 10.0f
  38. #define JETSKI_DRAG_IN_THRUST 5.0f
  39. #define JETSKI_STEERING_EPS 0.01f
  40. #define JETSKI_STEERING_IN_PLACE 90.0f
  41. #define JETSKI_STEERING_NORMAL 45.0f
  42. #define JETSKI_STEERING_LEAN 60.0f
  43. #define JETSKI_ROTATE_IN_PLACE_RATIO 0.35f
  44. class CPropJetski : public CPropVehicleDriveable
  45. {
  46. DECLARE_CLASS( CPropJetski, CPropVehicleDriveable );
  47. DECLARE_DATADESC();
  48. public:
  49. // CPropVehicle
  50. virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData );
  51. virtual void DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd );
  52. virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
  53. // CBaseEntity
  54. void Think(void);
  55. void Precache( void );
  56. void Spawn( void );
  57. virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
  58. virtual int OnTakeDamage( const CTakeDamageInfo &info );
  59. private:
  60. void OnTurn( CUserCmd *ucmd );
  61. void OnSpeed( CUserCmd *ucmd );
  62. void UpdateTurnAndSpeed( void );
  63. void CreateSplash( int nSplashType );
  64. bool UpdateLean( CUserCmd *ucmd );
  65. float CalculateFriction( CUserCmd *ucmd );
  66. float CalculateDrag( CUserCmd *ucmd );
  67. private:
  68. float m_flSpringLengthApproach[4]; //
  69. float m_flFrictionWheels[4];
  70. float m_flHandbrakeTime; // handbrake after the fact to keep vehicles from rolling
  71. bool m_bInitialHandbrake;
  72. float m_springLen[4];
  73. IPhysicsVehicleController *m_pVehicle;
  74. };
  75. LINK_ENTITY_TO_CLASS( prop_vehicle_jetski, CPropJetski );
  76. //---------------------------------------------------------
  77. // Save/Restore
  78. //---------------------------------------------------------
  79. BEGIN_DATADESC( CPropJetski )
  80. DEFINE_AUTO_ARRAY( m_flSpringLengthApproach, FIELD_FLOAT ),
  81. DEFINE_AUTO_ARRAY( m_flFrictionWheels, FIELD_FLOAT ),
  82. DEFINE_FIELD( m_flHandbrakeTime, FIELD_TIME ),
  83. DEFINE_FIELD( m_bInitialHandbrake, FIELD_BOOLEAN ),
  84. DEFINE_AUTO_ARRAY( m_springLen, FIELD_FLOAT ),
  85. DEFINE_PHYSPTR( m_pVehicle ),
  86. END_DATADESC()
  87. //-----------------------------------------------------------------------------
  88. // Purpose:
  89. //-----------------------------------------------------------------------------
  90. void CPropJetski::Precache( void )
  91. {
  92. BaseClass::Precache();
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //-----------------------------------------------------------------------------
  97. void CPropJetski::Spawn( void )
  98. {
  99. // Setup vehicle as a ray-cast jetski.
  100. SetVehicleType( VEHICLE_TYPE_JETSKI_RAYCAST );
  101. BaseClass::Spawn();
  102. // Handbrake data.
  103. m_flHandbrakeTime = gpGlobals->curtime + 0.1;
  104. m_bInitialHandbrake = false;
  105. m_VehiclePhysics.SetHasBrakePedal( false );
  106. // Slow reverse.
  107. m_VehiclePhysics.SetMaxReverseThrottle( -0.3f );
  108. // Setup vehicle variables.
  109. m_pVehicle = m_VehiclePhysics.GetVehicle();
  110. for ( int i = 0; i < 4; i++ )
  111. {
  112. m_springLen[i] = JETSKI_SHOCK_LENGTH_REST;
  113. }
  114. m_takedamage = DAMAGE_EVENTS_ONLY;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void CPropJetski::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
  120. {
  121. if ( ptr->hitbox == VEHICLE_HITBOX_DRIVER )
  122. {
  123. if ( m_hPlayer != NULL )
  124. {
  125. m_hPlayer->TakeDamage( info );
  126. }
  127. }
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose:
  131. //-----------------------------------------------------------------------------
  132. int CPropJetski::OnTakeDamage( const CTakeDamageInfo &info )
  133. {
  134. //Do scaled up physic damage to the car
  135. CTakeDamageInfo physDmg = info;
  136. physDmg.ScaleDamage( 25 );
  137. VPhysicsTakeDamage( physDmg );
  138. //Check to do damage to driver
  139. if ( m_hPlayer != NULL )
  140. {
  141. //Take no damage from physics damages
  142. if ( info.GetDamageType() & DMG_CRUSH )
  143. return 0;
  144. //Take the damage
  145. m_hPlayer->TakeDamage( info );
  146. }
  147. return 0;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // Purpose:
  151. //-----------------------------------------------------------------------------
  152. void CPropJetski::Think(void)
  153. {
  154. BaseClass::Think();
  155. // set handbrake after physics sim settles down
  156. if ( gpGlobals->curtime < m_flHandbrakeTime )
  157. {
  158. SetNextThink( gpGlobals->curtime );
  159. }
  160. else if ( !m_bInitialHandbrake ) // after initial timer expires, set the handbrake
  161. {
  162. m_bInitialHandbrake = true;
  163. m_VehiclePhysics.SetHandbrake( true );
  164. m_VehiclePhysics.Think();
  165. }
  166. // play enter animation
  167. if ( (m_bEnterAnimOn || m_bExitAnimOn) && !IsSequenceFinished() )
  168. {
  169. StudioFrameAdvance();
  170. }
  171. else if ( IsSequenceFinished() )
  172. {
  173. if ( m_bExitAnimOn )
  174. {
  175. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  176. if ( pPlayer )
  177. {
  178. pPlayer->LeaveVehicle(); // now that sequence is finished, leave car
  179. Vector vecEyes;
  180. QAngle vecEyeAng;
  181. GetAttachment( "vehicle_driver_eyes", vecEyes, vecEyeAng );
  182. vecEyeAng.x = 0;
  183. vecEyeAng.z = 0;
  184. pPlayer->SnapEyeAngles( vecEyeAng );
  185. }
  186. m_bExitAnimOn = false;
  187. }
  188. int iSequence = SelectWeightedSequence( ACT_IDLE );
  189. if ( iSequence > ACTIVITY_NOT_AVAILABLE )
  190. {
  191. m_flCycle = 0;
  192. m_flAnimTime = gpGlobals->curtime;
  193. ResetSequence( iSequence );
  194. ResetClientsideFrame();
  195. }
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose:
  200. //-----------------------------------------------------------------------------
  201. void CPropJetski::OnTurn( CUserCmd *ucmd )
  202. {
  203. #if 0
  204. // Check for lean and adjust the turning radius accordingly.
  205. if ( ucmd->buttons & IN_JUMP )
  206. {
  207. m_VehiclePhysics.SetSteeringDegrees( JETSKI_STEERING_LEAN );
  208. }
  209. else
  210. {
  211. m_VehiclePhysics.SetSteeringDegrees( JETSKI_STEERING_NORMAL );
  212. }
  213. #endif
  214. float flSteering = m_VehiclePhysics.GetSteering();
  215. bool bLeft = ( flSteering < -JETSKI_STEERING_EPS );
  216. bool bRight = ( flSteering > JETSKI_STEERING_EPS );
  217. float flAbsSteering = fabsf( flSteering );
  218. float flInvAbsSteering = 1.0f - flAbsSteering;
  219. // Get the speed and ratio to max speed.
  220. float flSpeed = m_VehiclePhysics.GetSpeed();
  221. float flMaxSpeed = m_VehiclePhysics.GetMaxSpeed();
  222. float flRatio = flSpeed / flMaxSpeed;
  223. float flScale = 1.0f - flRatio;
  224. flScale *= 0.95f;
  225. flScale += 0.05f;
  226. flAbsSteering *= flScale;
  227. flInvAbsSteering *= flScale;
  228. m_flSpringLengthApproach[0] = JETSKI_SHOCK_LENGTH_SHORT; // Front-Left
  229. m_flSpringLengthApproach[1] = JETSKI_SHOCK_LENGTH_SHORT; // Front-Right
  230. m_flSpringLengthApproach[2] = JETSKI_SHOCK_LENGTH_SHORT; // Back-Left
  231. m_flSpringLengthApproach[3] = JETSKI_SHOCK_LENGTH_SHORT; // Back-Right
  232. return;
  233. // Roll right.
  234. if( bRight )
  235. {
  236. float flLengthRight = JETSKI_SHOCK_LENGTH_SHORT + ( JETSKI_SHOCK_LENGTH_REST - JETSKI_SHOCK_LENGTH_SHORT ) * flInvAbsSteering;
  237. float flLengthLeft = JETSKI_SHOCK_LENGTH_REST + ( JETSKI_SHOCK_LENGTH_LONG - JETSKI_SHOCK_LENGTH_REST ) * flAbsSteering;
  238. m_flSpringLengthApproach[0] = flLengthLeft; // Front-Left
  239. m_flSpringLengthApproach[1] = flLengthRight; // Front-Right
  240. m_flSpringLengthApproach[2] = flLengthLeft; // Back-Left
  241. m_flSpringLengthApproach[3] = flLengthRight; // Back-Right
  242. }
  243. // Roll left.
  244. else if ( bLeft )
  245. {
  246. float flLengthRight = JETSKI_SHOCK_LENGTH_REST + ( JETSKI_SHOCK_LENGTH_LONG - JETSKI_SHOCK_LENGTH_REST ) * flAbsSteering;
  247. float flLengthLeft = JETSKI_SHOCK_LENGTH_SHORT + ( JETSKI_SHOCK_LENGTH_REST - JETSKI_SHOCK_LENGTH_SHORT ) * flInvAbsSteering;
  248. m_flSpringLengthApproach[0] = flLengthLeft; // Front-Left
  249. m_flSpringLengthApproach[1] = flLengthRight; // Front-Right
  250. m_flSpringLengthApproach[2] = flLengthLeft; // Back-Left
  251. m_flSpringLengthApproach[3] = flLengthRight; // Back-Right
  252. }
  253. // Return springs to their normal height
  254. else
  255. {
  256. m_flSpringLengthApproach[0] = JETSKI_SHOCK_LENGTH_REST; // Front-Left
  257. m_flSpringLengthApproach[1] = JETSKI_SHOCK_LENGTH_REST; // Front-Right
  258. m_flSpringLengthApproach[2] = JETSKI_SHOCK_LENGTH_REST; // Back-Left
  259. m_flSpringLengthApproach[3] = JETSKI_SHOCK_LENGTH_REST; // Back-Right
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. //-----------------------------------------------------------------------------
  265. bool CPropJetski::UpdateLean( CUserCmd *ucmd )
  266. {
  267. // Are we leaning back?
  268. if ( ucmd->buttons & IN_JUMP )
  269. {
  270. m_pVehicle->SetLeanBack( true );
  271. return true;
  272. }
  273. m_pVehicle->SetLeanBack( false );
  274. return false;
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose:
  278. //-----------------------------------------------------------------------------
  279. float CPropJetski::CalculateFriction( CUserCmd *ucmd )
  280. {
  281. // Get the speed and ratio to max speed.
  282. float flSpeed = m_VehiclePhysics.GetSpeed();
  283. float flMaxSpeed = m_VehiclePhysics.GetMaxSpeed();
  284. float flRatio = flSpeed / flMaxSpeed;
  285. float flFriction = JETSKI_FRICTION_MAX;
  286. flRatio = 1.0f - ( float )pow( flRatio, 4 );
  287. flFriction = JETSKI_FRICTION_MIN + ( JETSKI_FRICTION_MAX - JETSKI_FRICTION_MIN ) * flRatio;
  288. flFriction = clamp( flFriction, JETSKI_FRICTION_MIN, JETSKI_FRICTION_MAX );
  289. // Debug!
  290. Msg( "Speed = %f, Friction = %f", flSpeed, flFriction );
  291. return flFriction;
  292. }
  293. //-----------------------------------------------------------------------------
  294. // Purpose:
  295. //-----------------------------------------------------------------------------
  296. float CPropJetski::CalculateDrag( CUserCmd *ucmd )
  297. {
  298. // Get the speed and ratio to max speed.
  299. float flSpeed = m_VehiclePhysics.GetSpeed();
  300. float flMaxSpeed = m_VehiclePhysics.GetMaxSpeed();
  301. float flRatio = flSpeed / flMaxSpeed;
  302. float flDrag = 0.0f;
  303. bool bLean = UpdateLean( ucmd );
  304. #if 0
  305. if ( bLean )
  306. {
  307. flDrag += JETSKI_DRAG_LEAN_ADD;
  308. }
  309. float flNormalizedRatio = ( flRatio - 0.4f ) * 1.667f;
  310. float flSplineRatio = SimpleSpline( flNormalizedRatio );
  311. flFriction = JETSKI_FRICTION_MAX + ( JETSKI_FRICTION_MIN - JETSKI_FRICTION_MAX ) * flSplineRatio;
  312. flDrag = JETSKI_DRAG_IN_WATER + ( JETSKI_DRAG_ON_WATER - JETSKI_DRAG_IN_WATER ) * flNormalizedRatio;
  313. // Leaning backwards.
  314. if ( bLean )
  315. {
  316. flDrag += JETSKI_DRAG_LEAN_ADD;
  317. }
  318. }
  319. #define JETSKI_DRAG_NO_THRUST_IN_WATER 10.0f
  320. #define JETSKI_DRAG_NO_THRUST_ON_WATER 30.0f
  321. #define JETSKI_DRAG_LEAN_ADD 10.0f
  322. #define JETSKI_DRAG_IN_REVERSE 10.0f
  323. #define JETSKI_DRAG_IN_THRUST 5.0f
  324. #endif
  325. // Debug
  326. Msg( "Drag = %f\n", flDrag );
  327. return flDrag;
  328. }
  329. //-----------------------------------------------------------------------------
  330. // Purpose:
  331. //-----------------------------------------------------------------------------
  332. void CPropJetski::OnSpeed( CUserCmd *ucmd )
  333. {
  334. // Get the physics object so we can adjust the drag.
  335. IPhysicsObject *pPhysJetski = VPhysicsGetObject();
  336. if ( !pPhysJetski )
  337. return;
  338. float flFriction = CalculateFriction( ucmd );
  339. float flDrag = CalculateDrag( ucmd );
  340. // Update the friction of the jetski "fake wheels."
  341. for ( int iWheel = 0; iWheel < 4; ++iWheel )
  342. {
  343. m_flFrictionWheels[iWheel] = flFriction;
  344. }
  345. // Update the Damp coefficient on the jetski.
  346. float flZero = 0.0f;
  347. pPhysJetski->SetDragCoefficient( &flDrag, &flZero );
  348. #if 0
  349. // Splash effects.
  350. if ( flRatio > 0.1f )
  351. {
  352. CreateSplash( JETSKI_SPLASH_RIPPLE );
  353. }
  354. float flRandom = random->RandomFloat( 0.0f, 1.0f );
  355. if ( flRatio > 0.8f && flRandom < 0.15f )
  356. {
  357. CreateSplash( JETSKI_SPLASH_SPRAY );
  358. }
  359. #endif
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose:
  363. //-----------------------------------------------------------------------------
  364. void CPropJetski::UpdateTurnAndSpeed( void )
  365. {
  366. #if 1
  367. // Update springs.
  368. m_springLen[0] = UTIL_Approach( m_flSpringLengthApproach[0], m_springLen[0], JETSKI_PITCH_AND_ROLL_RATE );
  369. m_pVehicle->SetSpringLength( 0, m_springLen[0] );
  370. m_springLen[1] = UTIL_Approach( m_flSpringLengthApproach[1], m_springLen[1], JETSKI_PITCH_AND_ROLL_RATE );
  371. m_pVehicle->SetSpringLength( 1, m_springLen[1] );
  372. m_springLen[2] = UTIL_Approach( m_flSpringLengthApproach[2], m_springLen[2], JETSKI_PITCH_AND_ROLL_RATE );
  373. m_pVehicle->SetSpringLength( 2, m_springLen[2] );
  374. m_springLen[3] = UTIL_Approach( m_flSpringLengthApproach[3], m_springLen[3], JETSKI_PITCH_AND_ROLL_RATE );
  375. m_pVehicle->SetSpringLength( 3, m_springLen[3] );
  376. #endif
  377. // Update wheel frictions.
  378. for ( int iWheel = 0; iWheel < 4; ++iWheel )
  379. {
  380. m_pVehicle->SetWheelFriction( iWheel, m_flFrictionWheels[iWheel] );
  381. }
  382. }
  383. //-----------------------------------------------------------------------------
  384. // Purpose:
  385. //-----------------------------------------------------------------------------
  386. void CPropJetski::DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd )
  387. {
  388. //Lose control when the player dies
  389. if ( pPlayer->IsAlive() == false )
  390. return;
  391. OnTurn( ucmd );
  392. OnSpeed( ucmd );
  393. UpdateTurnAndSpeed();
  394. m_VehiclePhysics.UpdateDriverControls( ucmd, ucmd->frametime );
  395. // Save this data.
  396. m_nSpeed = m_VehiclePhysics.GetSpeed();
  397. m_nRPM = m_VehiclePhysics.GetRPM();
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. // Input : *pPlayer -
  402. // *pMoveData -
  403. //-----------------------------------------------------------------------------
  404. void CPropJetski::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData )
  405. {
  406. BaseClass::ProcessMovement( pPlayer, pMoveData );
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose:
  410. //-----------------------------------------------------------------------------
  411. void CPropJetski::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
  412. {
  413. DriveVehicle( player, ucmd );
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose:
  417. //-----------------------------------------------------------------------------
  418. void CPropJetski::CreateSplash( int nSplashType )
  419. {
  420. Vector vecSplashPoint;
  421. QAngle vecSplashAngles;
  422. GetAttachment( "splash_pt", vecSplashPoint, vecSplashAngles );
  423. Vector vecForward, vecUp;
  424. AngleVectors( vecSplashAngles, &vecForward, &vecUp, NULL );
  425. CEffectData data;
  426. data.m_vOrigin = vecSplashPoint;
  427. switch ( nSplashType )
  428. {
  429. case JETSKI_SPLASH_SPRAY:
  430. {
  431. Vector vecSplashDir;
  432. vecSplashDir = ( vecForward + vecUp ) * 0.5f;
  433. VectorNormalize( vecSplashDir );
  434. data.m_vNormal = vecSplashDir;
  435. data.m_flScale = JETSKI_SPLASH_SPRAY_SIZE + random->RandomFloat( 0, JETSKI_SPLASH_SPRAY_SIZE * 0.25 );
  436. DispatchEffect( "waterripple", data );
  437. DispatchEffect( "watersplash", data );
  438. }
  439. case JETSKI_SPLASH_GURGLE:
  440. {
  441. Vector vecSplashDir;
  442. vecSplashDir = vecUp;
  443. data.m_vNormal = vecSplashDir;
  444. data.m_flScale = JETSKI_SPLASH_GURGLE_SIZE + random->RandomFloat( 0, JETSKI_SPLASH_GURGLE_SIZE * 0.25 );
  445. DispatchEffect( "waterripple", data );
  446. DispatchEffect( "watersplash", data );
  447. }
  448. case JETSKI_SPLASH_RIPPLE:
  449. {
  450. Vector vecSplashDir;
  451. vecSplashDir = vecUp;
  452. data.m_vNormal = vecSplashDir;
  453. data.m_flScale = JETSKI_SPLASH_RIPPLE_SIZE + random->RandomFloat( 0, JETSKI_SPLASH_RIPPLE_SIZE * 0.25 );
  454. DispatchEffect( "waterripple", data );
  455. }
  456. default:
  457. {
  458. return;
  459. }
  460. }
  461. }