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.

1584 lines
48 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 "soundenvelope.h"
  15. #include "decals.h"
  16. #include "soundent.h"
  17. #include "te_effect_dispatch.h"
  18. #include "ndebugoverlay.h"
  19. #include "movevars_shared.h"
  20. #include "bone_setup.h"
  21. #include "ai_basenpc.h"
  22. #include "ai_hint.h"
  23. #include "globalstate.h"
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. #define VEHICLE_HITBOX_DRIVER 1
  27. #define LOCK_SPEED 10
  28. #define JEEP_GUN_YAW "vehicle_weapon_yaw"
  29. #define JEEP_GUN_PITCH "vehicle_weapon_pitch"
  30. #define JEEP_GUN_SPIN "gun_spin"
  31. #define JEEP_GUN_SPIN_RATE 20
  32. #define CANNON_MAX_UP_PITCH 20
  33. #define CANNON_MAX_DOWN_PITCH 20
  34. #define CANNON_MAX_LEFT_YAW 90
  35. #define CANNON_MAX_RIGHT_YAW 90
  36. #define OVERTURNED_EXIT_WAITTIME 2.0f
  37. #define JEEP_AMMOCRATE_HITGROUP 5
  38. #define JEEP_WHEEL_COUNT 4
  39. #define JEEP_STEERING_SLOW_ANGLE 50.0f
  40. #define JEEP_STEERING_FAST_ANGLE 15.0f
  41. #define JEEP_AMMO_CRATE_CLOSE_DELAY 2.0f
  42. #define JEEP_DELTA_LENGTH_MAX 12.0f // 1 foot
  43. #define JEEP_FRAMETIME_MIN 1e-6
  44. ConVar hud_jeephint_numentries( "hud_jeephint_numentries", "10", FCVAR_NONE );
  45. ConVar g_jeepexitspeed( "g_jeepexitspeed", "100", FCVAR_CHEAT );
  46. //=============================================================================
  47. //
  48. // Jeep water data.
  49. //
  50. struct JeepWaterData_t
  51. {
  52. bool m_bWheelInWater[JEEP_WHEEL_COUNT];
  53. bool m_bWheelWasInWater[JEEP_WHEEL_COUNT];
  54. Vector m_vecWheelContactPoints[JEEP_WHEEL_COUNT];
  55. float m_flNextRippleTime[JEEP_WHEEL_COUNT];
  56. bool m_bBodyInWater;
  57. bool m_bBodyWasInWater;
  58. DECLARE_SIMPLE_DATADESC();
  59. };
  60. BEGIN_SIMPLE_DATADESC( JeepWaterData_t )
  61. DEFINE_ARRAY( m_bWheelInWater, FIELD_BOOLEAN, JEEP_WHEEL_COUNT ),
  62. DEFINE_ARRAY( m_bWheelWasInWater, FIELD_BOOLEAN, JEEP_WHEEL_COUNT ),
  63. DEFINE_ARRAY( m_vecWheelContactPoints, FIELD_VECTOR, JEEP_WHEEL_COUNT ),
  64. DEFINE_ARRAY( m_flNextRippleTime, FIELD_TIME, JEEP_WHEEL_COUNT ),
  65. DEFINE_FIELD( m_bBodyInWater, FIELD_BOOLEAN ),
  66. DEFINE_FIELD( m_bBodyWasInWater, FIELD_BOOLEAN ),
  67. END_DATADESC()
  68. //-----------------------------------------------------------------------------
  69. // Purpose: Four wheel physics vehicle server vehicle with weaponry
  70. //-----------------------------------------------------------------------------
  71. class CJeepFourWheelServerVehicle : public CFourWheelServerVehicle
  72. {
  73. typedef CFourWheelServerVehicle BaseClass;
  74. // IServerVehicle
  75. public:
  76. bool NPC_HasPrimaryWeapon( void ) { return true; }
  77. void NPC_AimPrimaryWeapon( Vector vecTarget );
  78. int GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked );
  79. };
  80. //-----------------------------------------------------------------------------
  81. // Purpose:
  82. //-----------------------------------------------------------------------------
  83. class CPropJeep : public CPropVehicleDriveable
  84. {
  85. DECLARE_CLASS( CPropJeep, CPropVehicleDriveable );
  86. public:
  87. DECLARE_SERVERCLASS();
  88. DECLARE_DATADESC();
  89. CPropJeep( void );
  90. // CPropVehicle
  91. virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData );
  92. virtual void DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased );
  93. virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
  94. virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  95. virtual void DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles );
  96. virtual bool AllowBlockedExit( CBasePlayer *pPlayer, int nRole ) { return false; }
  97. virtual bool CanExitVehicle( CBaseEntity *pEntity );
  98. virtual bool IsVehicleBodyInWater() { return m_WaterData.m_bBodyInWater; }
  99. // CBaseEntity
  100. void Think(void);
  101. void Precache( void );
  102. void Spawn( void );
  103. void OnRestore( void );
  104. virtual void CreateServerVehicle( void );
  105. virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy = true );
  106. virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
  107. virtual int OnTakeDamage( const CTakeDamageInfo &info );
  108. virtual void EnterVehicle( CBasePlayer *pPlayer );
  109. virtual void ExitVehicle( int nRole );
  110. void AimGunAt( Vector *endPos, float flInterval );
  111. bool TauCannonHasBeenCutOff( void ) { return m_bGunHasBeenCutOff; }
  112. // NPC Driving
  113. bool NPC_HasPrimaryWeapon( void ) { return true; }
  114. void NPC_AimPrimaryWeapon( Vector vecTarget );
  115. const char *GetTracerType( void ) { return "AR2Tracer"; }
  116. void DoImpactEffect( trace_t &tr, int nDamageType );
  117. bool HeadlightIsOn( void ) { return m_bHeadlightIsOn; }
  118. void HeadlightTurnOn( void ) { m_bHeadlightIsOn = true; }
  119. void HeadlightTurnOff( void ) { m_bHeadlightIsOn = false; }
  120. private:
  121. void FireCannon( void );
  122. void ChargeCannon( void );
  123. void FireChargedCannon( void );
  124. void DrawBeam( const Vector &startPos, const Vector &endPos, float width );
  125. void StopChargeSound( void );
  126. void GetCannonAim( Vector *resultDir );
  127. void InitWaterData( void );
  128. void HandleWater( void );
  129. bool CheckWater( void );
  130. void CheckWaterLevel( void );
  131. void CreateSplash( const Vector &vecPosition );
  132. void CreateRipple( const Vector &vecPosition );
  133. void UpdateSteeringAngle( void );
  134. void CreateDangerSounds( void );
  135. void ComputePDControllerCoefficients( float *pCoefficientsOut, float flFrequency, float flDampening, float flDeltaTime );
  136. void DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
  137. void DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime );
  138. void InputStartRemoveTauCannon( inputdata_t &inputdata );
  139. void InputFinishRemoveTauCannon( inputdata_t &inputdata );
  140. private:
  141. bool m_bGunHasBeenCutOff;
  142. float m_flDangerSoundTime;
  143. int m_nBulletType;
  144. bool m_bCannonCharging;
  145. float m_flCannonTime;
  146. float m_flCannonChargeStartTime;
  147. Vector m_vecGunOrigin;
  148. CSoundPatch *m_sndCannonCharge;
  149. int m_nSpinPos;
  150. float m_aimYaw;
  151. float m_aimPitch;
  152. float m_throttleDisableTime;
  153. float m_flAmmoCrateCloseTime;
  154. // handbrake after the fact to keep vehicles from rolling
  155. float m_flHandbrakeTime;
  156. bool m_bInitialHandbrake;
  157. float m_flOverturnedTime;
  158. Vector m_vecLastEyePos;
  159. Vector m_vecLastEyeTarget;
  160. Vector m_vecEyeSpeed;
  161. Vector m_vecTargetSpeed;
  162. JeepWaterData_t m_WaterData;
  163. int m_iNumberOfEntries;
  164. int m_nAmmoType;
  165. // Seagull perching
  166. float m_flPlayerExitedTime; // Time at which the player last left this vehicle
  167. float m_flLastSawPlayerAt; // Time at which we last saw the player
  168. EHANDLE m_hLastPlayerInVehicle;
  169. bool m_bHasPoop;
  170. CNetworkVar( bool, m_bHeadlightIsOn );
  171. };
  172. BEGIN_DATADESC( CPropJeep )
  173. DEFINE_FIELD( m_bGunHasBeenCutOff, FIELD_BOOLEAN ),
  174. DEFINE_FIELD( m_flDangerSoundTime, FIELD_TIME ),
  175. DEFINE_FIELD( m_nBulletType, FIELD_INTEGER ),
  176. DEFINE_FIELD( m_bCannonCharging, FIELD_BOOLEAN ),
  177. DEFINE_FIELD( m_flCannonTime, FIELD_TIME ),
  178. DEFINE_FIELD( m_flCannonChargeStartTime, FIELD_TIME ),
  179. DEFINE_FIELD( m_vecGunOrigin, FIELD_POSITION_VECTOR ),
  180. DEFINE_SOUNDPATCH( m_sndCannonCharge ),
  181. DEFINE_FIELD( m_nSpinPos, FIELD_INTEGER ),
  182. DEFINE_FIELD( m_aimYaw, FIELD_FLOAT ),
  183. DEFINE_FIELD( m_aimPitch, FIELD_FLOAT ),
  184. DEFINE_FIELD( m_throttleDisableTime, FIELD_TIME ),
  185. DEFINE_FIELD( m_flHandbrakeTime, FIELD_TIME ),
  186. DEFINE_FIELD( m_bInitialHandbrake, FIELD_BOOLEAN ),
  187. DEFINE_FIELD( m_flOverturnedTime, FIELD_TIME ),
  188. DEFINE_FIELD( m_flAmmoCrateCloseTime, FIELD_FLOAT ),
  189. DEFINE_FIELD( m_vecLastEyePos, FIELD_POSITION_VECTOR ),
  190. DEFINE_FIELD( m_vecLastEyeTarget, FIELD_POSITION_VECTOR ),
  191. DEFINE_FIELD( m_vecEyeSpeed, FIELD_POSITION_VECTOR ),
  192. DEFINE_FIELD( m_vecTargetSpeed, FIELD_POSITION_VECTOR ),
  193. DEFINE_FIELD( m_bHeadlightIsOn, FIELD_BOOLEAN ),
  194. DEFINE_EMBEDDED( m_WaterData ),
  195. DEFINE_FIELD( m_iNumberOfEntries, FIELD_INTEGER ),
  196. DEFINE_FIELD( m_nAmmoType, FIELD_INTEGER ),
  197. DEFINE_FIELD( m_flPlayerExitedTime, FIELD_TIME ),
  198. DEFINE_FIELD( m_flLastSawPlayerAt, FIELD_TIME ),
  199. DEFINE_FIELD( m_hLastPlayerInVehicle, FIELD_EHANDLE ),
  200. DEFINE_FIELD( m_bHasPoop, FIELD_BOOLEAN ),
  201. DEFINE_INPUTFUNC( FIELD_VOID, "StartRemoveTauCannon", InputStartRemoveTauCannon ),
  202. DEFINE_INPUTFUNC( FIELD_VOID, "FinishRemoveTauCannon", InputFinishRemoveTauCannon ),
  203. END_DATADESC()
  204. IMPLEMENT_SERVERCLASS_ST( CPropJeep, DT_PropJeep )
  205. SendPropBool( SENDINFO( m_bHeadlightIsOn ) ),
  206. END_SEND_TABLE();
  207. LINK_ENTITY_TO_CLASS( prop_vehicle_jeep, CPropJeep );
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. //-----------------------------------------------------------------------------
  211. CPropJeep::CPropJeep( void )
  212. {
  213. m_bHasGun = true;
  214. m_bGunHasBeenCutOff = false;
  215. m_bCannonCharging = false;
  216. m_flCannonChargeStartTime = 0;
  217. m_flCannonTime = 0;
  218. m_nBulletType = -1;
  219. m_flOverturnedTime = 0.0f;
  220. m_iNumberOfEntries = 0;
  221. m_vecEyeSpeed.Init();
  222. InitWaterData();
  223. m_bUnableToFire = true;
  224. m_flAmmoCrateCloseTime = 0;
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. //-----------------------------------------------------------------------------
  229. void CPropJeep::CreateServerVehicle( void )
  230. {
  231. // Create our armed server vehicle
  232. m_pServerVehicle = new CJeepFourWheelServerVehicle();
  233. m_pServerVehicle->SetVehicle( this );
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose:
  237. //-----------------------------------------------------------------------------
  238. void CPropJeep::Precache( void )
  239. {
  240. UTIL_PrecacheOther( "npc_seagull" );
  241. PrecacheScriptSound( "PropJeep.AmmoClose" );
  242. PrecacheScriptSound( "PropJeep.FireCannon" );
  243. PrecacheScriptSound( "PropJeep.FireChargedCannon" );
  244. PrecacheScriptSound( "PropJeep.AmmoOpen" );
  245. PrecacheScriptSound( "Jeep.GaussCharge" );
  246. // PrecacheModel( GAUSS_BEAM_SPRITE );
  247. BaseClass::Precache();
  248. }
  249. //------------------------------------------------
  250. // Spawn
  251. //------------------------------------------------
  252. void CPropJeep::Spawn( void )
  253. {
  254. // Setup vehicle as a real-wheels car.
  255. SetVehicleType( VEHICLE_TYPE_CAR_WHEELS );
  256. BaseClass::Spawn();
  257. m_flHandbrakeTime = gpGlobals->curtime + 0.1;
  258. m_bInitialHandbrake = false;
  259. m_VehiclePhysics.SetHasBrakePedal( false );
  260. m_flMinimumSpeedToEnterExit = LOCK_SPEED;
  261. m_nBulletType = GetAmmoDef()->Index("GaussEnergy");
  262. if ( m_bHasGun )
  263. {
  264. SetBodygroup( 1, true );
  265. }
  266. else
  267. {
  268. SetBodygroup( 1, false );
  269. }
  270. // Initialize pose parameters
  271. SetPoseParameter( JEEP_GUN_YAW, 0 );
  272. SetPoseParameter( JEEP_GUN_PITCH, 0 );
  273. m_nSpinPos = 0;
  274. SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos );
  275. m_aimYaw = 0;
  276. m_aimPitch = 0;
  277. AddSolidFlags( FSOLID_NOT_STANDABLE );
  278. CAmmoDef *pAmmoDef = GetAmmoDef();
  279. m_nAmmoType = pAmmoDef->Index("GaussEnergy");
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Purpose:
  283. // Input : &tr -
  284. // nDamageType -
  285. //-----------------------------------------------------------------------------
  286. void CPropJeep::DoImpactEffect( trace_t &tr, int nDamageType )
  287. {
  288. //Draw our beam
  289. DrawBeam( tr.startpos, tr.endpos, 2.4 );
  290. if ( (tr.surface.flags & SURF_SKY) == false )
  291. {
  292. CPVSFilter filter( tr.endpos );
  293. te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
  294. UTIL_ImpactTrace( &tr, m_nBulletType );
  295. }
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. //-----------------------------------------------------------------------------
  300. void CPropJeep::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr )
  301. {
  302. CTakeDamageInfo info = inputInfo;
  303. if ( ptr->hitbox != VEHICLE_HITBOX_DRIVER )
  304. {
  305. if ( inputInfo.GetDamageType() & DMG_BULLET )
  306. {
  307. info.ScaleDamage( 0.0001 );
  308. }
  309. }
  310. BaseClass::TraceAttack( info, vecDir, ptr );
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. //-----------------------------------------------------------------------------
  315. int CPropJeep::OnTakeDamage( const CTakeDamageInfo &inputInfo )
  316. {
  317. //Do scaled up physics damage to the car
  318. CTakeDamageInfo info = inputInfo;
  319. info.ScaleDamage( 25 );
  320. // HACKHACK: Scale up grenades until we get a better explosion/pressure damage system
  321. if ( inputInfo.GetDamageType() & DMG_BLAST )
  322. {
  323. info.SetDamageForce( inputInfo.GetDamageForce() * 10 );
  324. }
  325. VPhysicsTakeDamage( info );
  326. // reset the damage
  327. info.SetDamage( inputInfo.GetDamage() );
  328. // small amounts of shock damage disrupt the car, but aren't transferred to the player
  329. if ( info.GetDamageType() == DMG_SHOCK )
  330. {
  331. if ( info.GetDamage() <= 10 )
  332. {
  333. // take 10% damage and make the engine stall
  334. info.ScaleDamage( 0.1 );
  335. m_throttleDisableTime = gpGlobals->curtime + 2;
  336. }
  337. }
  338. //Check to do damage to driver
  339. if ( GetDriver() )
  340. {
  341. //Take no damage from physics damages
  342. if ( info.GetDamageType() & DMG_CRUSH )
  343. return 0;
  344. // Take the damage (strip out the DMG_BLAST)
  345. info.SetDamageType( info.GetDamageType() & (~DMG_BLAST) );
  346. GetDriver()->TakeDamage( info );
  347. }
  348. return 0;
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose:
  352. //-----------------------------------------------------------------------------
  353. Vector CPropJeep::BodyTarget( const Vector &posSrc, bool bNoisy )
  354. {
  355. Vector shotPos;
  356. matrix3x4_t matrix;
  357. int eyeAttachmentIndex = LookupAttachment("vehicle_driver_eyes");
  358. GetAttachment( eyeAttachmentIndex, matrix );
  359. MatrixGetColumn( matrix, 3, shotPos );
  360. if ( bNoisy )
  361. {
  362. shotPos[0] += random->RandomFloat( -8.0f, 8.0f );
  363. shotPos[1] += random->RandomFloat( -8.0f, 8.0f );
  364. shotPos[2] += random->RandomFloat( -8.0f, 8.0f );
  365. }
  366. return shotPos;
  367. }
  368. //-----------------------------------------------------------------------------
  369. // Purpose: Aim Gun at a target
  370. //-----------------------------------------------------------------------------
  371. void CPropJeep::AimGunAt( Vector *endPos, float flInterval )
  372. {
  373. Vector aimPos = *endPos;
  374. // See if the gun should be allowed to aim
  375. if ( IsOverturned() || m_bEngineLocked )
  376. {
  377. SetPoseParameter( JEEP_GUN_YAW, 0 );
  378. SetPoseParameter( JEEP_GUN_PITCH, 0 );
  379. SetPoseParameter( JEEP_GUN_SPIN, 0 );
  380. return;
  381. // Make the gun go limp and look "down"
  382. Vector v_forward, v_up;
  383. AngleVectors( GetLocalAngles(), NULL, &v_forward, &v_up );
  384. aimPos = WorldSpaceCenter() + ( v_forward * -32.0f ) - Vector( 0, 0, 128.0f );
  385. }
  386. matrix3x4_t gunMatrix;
  387. GetAttachment( LookupAttachment("gun_ref"), gunMatrix );
  388. // transform the enemy into gun space
  389. Vector localEnemyPosition;
  390. VectorITransform( aimPos, gunMatrix, localEnemyPosition );
  391. // do a look at in gun space (essentially a delta-lookat)
  392. QAngle localEnemyAngles;
  393. VectorAngles( localEnemyPosition, localEnemyAngles );
  394. // convert to +/- 180 degrees
  395. localEnemyAngles.x = UTIL_AngleDiff( localEnemyAngles.x, 0 );
  396. localEnemyAngles.y = UTIL_AngleDiff( localEnemyAngles.y, 0 );
  397. float targetYaw = m_aimYaw + localEnemyAngles.y;
  398. float targetPitch = m_aimPitch + localEnemyAngles.x;
  399. // Constrain our angles
  400. float newTargetYaw = clamp( targetYaw, -CANNON_MAX_LEFT_YAW, CANNON_MAX_RIGHT_YAW );
  401. float newTargetPitch = clamp( targetPitch, -CANNON_MAX_DOWN_PITCH, CANNON_MAX_UP_PITCH );
  402. // If the angles have been clamped, we're looking outside of our valid range
  403. if ( fabs(newTargetYaw-targetYaw) > 1e-4 || fabs(newTargetPitch-targetPitch) > 1e-4 )
  404. {
  405. m_bUnableToFire = true;
  406. }
  407. targetYaw = newTargetYaw;
  408. targetPitch = newTargetPitch;
  409. // Exponentially approach the target
  410. float yawSpeed = 8;
  411. float pitchSpeed = 8;
  412. m_aimYaw = UTIL_Approach( targetYaw, m_aimYaw, yawSpeed );
  413. m_aimPitch = UTIL_Approach( targetPitch, m_aimPitch, pitchSpeed );
  414. SetPoseParameter( JEEP_GUN_YAW, -m_aimYaw);
  415. SetPoseParameter( JEEP_GUN_PITCH, -m_aimPitch );
  416. InvalidateBoneCache();
  417. // read back to avoid drift when hitting limits
  418. // as long as the velocity is less than the delta between the limit and 180, this is fine.
  419. m_aimPitch = -GetPoseParameter( JEEP_GUN_PITCH );
  420. m_aimYaw = -GetPoseParameter( JEEP_GUN_YAW );
  421. // Now draw crosshair for actual aiming point
  422. Vector vecMuzzle, vecMuzzleDir;
  423. QAngle vecMuzzleAng;
  424. GetAttachment( "Muzzle", vecMuzzle, vecMuzzleAng );
  425. AngleVectors( vecMuzzleAng, &vecMuzzleDir );
  426. trace_t tr;
  427. UTIL_TraceLine( vecMuzzle, vecMuzzle + (vecMuzzleDir * MAX_TRACE_LENGTH), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  428. // see if we hit something, if so, adjust endPos to hit location
  429. if ( tr.fraction < 1.0 )
  430. {
  431. m_vecGunCrosshair = vecMuzzle + ( vecMuzzleDir * MAX_TRACE_LENGTH * tr.fraction );
  432. }
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Purpose:
  436. //-----------------------------------------------------------------------------
  437. void CPropJeep::InitWaterData( void )
  438. {
  439. m_WaterData.m_bBodyInWater = false;
  440. m_WaterData.m_bBodyWasInWater = false;
  441. for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
  442. {
  443. m_WaterData.m_bWheelInWater[iWheel] = false;
  444. m_WaterData.m_bWheelWasInWater[iWheel] = false;
  445. m_WaterData.m_vecWheelContactPoints[iWheel].Init();
  446. m_WaterData.m_flNextRippleTime[iWheel] = 0;
  447. }
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Purpose:
  451. //-----------------------------------------------------------------------------
  452. void CPropJeep::HandleWater( void )
  453. {
  454. // Only check the wheels and engine in water if we have a driver (player).
  455. if ( !GetDriver() )
  456. return;
  457. // Check to see if we are in water.
  458. if ( CheckWater() )
  459. {
  460. for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
  461. {
  462. // Create an entry/exit splash!
  463. if ( m_WaterData.m_bWheelInWater[iWheel] != m_WaterData.m_bWheelWasInWater[iWheel] )
  464. {
  465. CreateSplash( m_WaterData.m_vecWheelContactPoints[iWheel] );
  466. CreateRipple( m_WaterData.m_vecWheelContactPoints[iWheel] );
  467. }
  468. // Create ripples.
  469. if ( m_WaterData.m_bWheelInWater[iWheel] && m_WaterData.m_bWheelWasInWater[iWheel] )
  470. {
  471. if ( m_WaterData.m_flNextRippleTime[iWheel] < gpGlobals->curtime )
  472. {
  473. // Stagger ripple times
  474. m_WaterData.m_flNextRippleTime[iWheel] = gpGlobals->curtime + RandomFloat( 0.1, 0.3 );
  475. CreateRipple( m_WaterData.m_vecWheelContactPoints[iWheel] );
  476. }
  477. }
  478. }
  479. }
  480. // Save of data from last think.
  481. for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
  482. {
  483. m_WaterData.m_bWheelWasInWater[iWheel] = m_WaterData.m_bWheelInWater[iWheel];
  484. }
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose:
  488. //-----------------------------------------------------------------------------
  489. bool CPropJeep::CheckWater( void )
  490. {
  491. bool bInWater = false;
  492. // Check all four wheels.
  493. for ( int iWheel = 0; iWheel < JEEP_WHEEL_COUNT; ++iWheel )
  494. {
  495. // Get the current wheel and get its contact point.
  496. IPhysicsObject *pWheel = m_VehiclePhysics.GetWheel( iWheel );
  497. if ( !pWheel )
  498. continue;
  499. // Check to see if we hit water.
  500. if ( pWheel->GetContactPoint( &m_WaterData.m_vecWheelContactPoints[iWheel], NULL ) )
  501. {
  502. m_WaterData.m_bWheelInWater[iWheel] = ( UTIL_PointContents( m_WaterData.m_vecWheelContactPoints[iWheel] ) & MASK_WATER ) ? true : false;
  503. if ( m_WaterData.m_bWheelInWater[iWheel] )
  504. {
  505. bInWater = true;
  506. }
  507. }
  508. }
  509. // Check the body and the BONNET.
  510. int iEngine = LookupAttachment( "vehicle_engine" );
  511. Vector vecEnginePoint;
  512. QAngle vecEngineAngles;
  513. GetAttachment( iEngine, vecEnginePoint, vecEngineAngles );
  514. m_WaterData.m_bBodyInWater = ( UTIL_PointContents( vecEnginePoint ) & MASK_WATER ) ? true : false;
  515. if ( m_WaterData.m_bBodyInWater )
  516. {
  517. if ( m_bHasPoop )
  518. {
  519. RemoveAllDecals();
  520. m_bHasPoop = false;
  521. }
  522. if ( !m_VehiclePhysics.IsEngineDisabled() )
  523. {
  524. m_VehiclePhysics.SetDisableEngine( true );
  525. }
  526. }
  527. else
  528. {
  529. if ( m_VehiclePhysics.IsEngineDisabled() )
  530. {
  531. m_VehiclePhysics.SetDisableEngine( false );
  532. }
  533. }
  534. if ( bInWater )
  535. {
  536. // Check the player's water level.
  537. CheckWaterLevel();
  538. }
  539. return bInWater;
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Purpose:
  543. //-----------------------------------------------------------------------------
  544. void CPropJeep::CheckWaterLevel( void )
  545. {
  546. CBaseEntity *pEntity = GetDriver();
  547. if ( pEntity && pEntity->IsPlayer() )
  548. {
  549. CBasePlayer *pPlayer = static_cast<CBasePlayer*>( pEntity );
  550. Vector vecAttachPoint;
  551. QAngle vecAttachAngles;
  552. // Check eyes. (vehicle_driver_eyes point)
  553. int iAttachment = LookupAttachment( "vehicle_driver_eyes" );
  554. GetAttachment( iAttachment, vecAttachPoint, vecAttachAngles );
  555. // Add the jeep's Z view offset
  556. Vector vecUp;
  557. AngleVectors( vecAttachAngles, NULL, NULL, &vecUp );
  558. vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z );
  559. vecAttachPoint.z += r_JeepViewZHeight.GetFloat() * vecUp.z;
  560. bool bEyes = ( UTIL_PointContents( vecAttachPoint ) & MASK_WATER ) ? true : false;
  561. if ( bEyes )
  562. {
  563. pPlayer->SetWaterLevel( WL_Eyes );
  564. return;
  565. }
  566. // Check waist. (vehicle_engine point -- see parent function).
  567. if ( m_WaterData.m_bBodyInWater )
  568. {
  569. pPlayer->SetWaterLevel( WL_Waist );
  570. return;
  571. }
  572. // Check feet. (vehicle_feet_passenger0 point)
  573. iAttachment = LookupAttachment( "vehicle_feet_passenger0" );
  574. GetAttachment( iAttachment, vecAttachPoint, vecAttachAngles );
  575. bool bFeet = ( UTIL_PointContents( vecAttachPoint ) & MASK_WATER ) ? true : false;
  576. if ( bFeet )
  577. {
  578. pPlayer->SetWaterLevel( WL_Feet );
  579. return;
  580. }
  581. // Not in water.
  582. pPlayer->SetWaterLevel( WL_NotInWater );
  583. }
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Purpose:
  587. //-----------------------------------------------------------------------------
  588. void CPropJeep::CreateSplash( const Vector &vecPosition )
  589. {
  590. // Splash data.
  591. CEffectData data;
  592. data.m_fFlags = 0;
  593. data.m_vOrigin = vecPosition;
  594. data.m_vNormal.Init( 0.0f, 0.0f, 1.0f );
  595. VectorAngles( data.m_vNormal, data.m_vAngles );
  596. data.m_flScale = 10.0f + random->RandomFloat( 0, 2 );
  597. // Create the splash..
  598. DispatchEffect( "watersplash", data );
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose:
  602. //-----------------------------------------------------------------------------
  603. void CPropJeep::CreateRipple( const Vector &vecPosition )
  604. {
  605. // Ripple data.
  606. CEffectData data;
  607. data.m_fFlags = 0;
  608. data.m_vOrigin = vecPosition;
  609. data.m_vNormal.Init( 0.0f, 0.0f, 1.0f );
  610. VectorAngles( data.m_vNormal, data.m_vAngles );
  611. data.m_flScale = 10.0f + random->RandomFloat( 0, 2 );
  612. if ( GetWaterType() & CONTENTS_SLIME )
  613. {
  614. data.m_fFlags |= FX_WATER_IN_SLIME;
  615. }
  616. // Create the ripple.
  617. DispatchEffect( "waterripple", data );
  618. }
  619. //-----------------------------------------------------------------------------
  620. // Purpose:
  621. //-----------------------------------------------------------------------------
  622. void CPropJeep::Think(void)
  623. {
  624. BaseClass::Think();
  625. /*
  626. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  627. if ( m_bEngineLocked )
  628. {
  629. m_bUnableToFire = true;
  630. if ( pPlayer != NULL )
  631. {
  632. pPlayer->m_Local.m_iHideHUD |= HIDEHUD_VEHICLE_CROSSHAIR;
  633. }
  634. }
  635. else
  636. {
  637. // Start this as false and update it again each frame
  638. m_bUnableToFire = false;
  639. if ( pPlayer != NULL )
  640. {
  641. pPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_VEHICLE_CROSSHAIR;
  642. }
  643. }
  644. */
  645. // Water!?
  646. HandleWater();
  647. SetSimulationTime( gpGlobals->curtime );
  648. SetNextThink( gpGlobals->curtime );
  649. SetAnimatedEveryTick( true );
  650. if ( !m_bInitialHandbrake ) // after initial timer expires, set the handbrake
  651. {
  652. m_bInitialHandbrake = true;
  653. m_VehiclePhysics.SetHandbrake( true );
  654. m_VehiclePhysics.Think();
  655. }
  656. // Check overturned status.
  657. if ( !IsOverturned() )
  658. {
  659. m_flOverturnedTime = 0.0f;
  660. }
  661. else
  662. {
  663. m_flOverturnedTime += gpGlobals->frametime;
  664. }
  665. // spin gun if charging cannon
  666. //FIXME: Don't bother for E3
  667. if ( m_bCannonCharging )
  668. {
  669. m_nSpinPos += JEEP_GUN_SPIN_RATE;
  670. SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos );
  671. }
  672. // Aim gun based on the player view direction.
  673. if ( m_hPlayer && !m_bExitAnimOn && !m_bEnterAnimOn )
  674. {
  675. Vector vecEyeDir, vecEyePos;
  676. m_hPlayer->EyePositionAndVectors( &vecEyePos, &vecEyeDir, NULL, NULL );
  677. // Trace out from the player's eye point.
  678. Vector vecEndPos = vecEyePos + ( vecEyeDir * MAX_TRACE_LENGTH );
  679. trace_t trace;
  680. UTIL_TraceLine( vecEyePos, vecEndPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &trace );
  681. // See if we hit something, if so, adjust end position to hit location.
  682. if ( trace.fraction < 1.0 )
  683. {
  684. vecEndPos = vecEyePos + ( vecEyeDir * MAX_TRACE_LENGTH * trace.fraction );
  685. }
  686. //m_vecLookCrosshair = vecEndPos;
  687. AimGunAt( &vecEndPos, 0.1f );
  688. }
  689. StudioFrameAdvance();
  690. // If the enter or exit animation has finished, tell the server vehicle
  691. if ( IsSequenceFinished() && (m_bExitAnimOn || m_bEnterAnimOn) )
  692. {
  693. if ( m_bEnterAnimOn )
  694. {
  695. m_VehiclePhysics.ReleaseHandbrake();
  696. StartEngine();
  697. // HACKHACK: This forces the jeep to play a sound when it gets entered underwater
  698. if ( m_VehiclePhysics.IsEngineDisabled() )
  699. {
  700. CBaseServerVehicle *pServerVehicle = dynamic_cast<CBaseServerVehicle *>(GetServerVehicle());
  701. if ( pServerVehicle )
  702. {
  703. pServerVehicle->SoundStartDisabled();
  704. }
  705. }
  706. // The first few time we get into the jeep, print the jeep help
  707. if ( m_iNumberOfEntries < hud_jeephint_numentries.GetInt() )
  708. {
  709. UTIL_HudHintText( m_hPlayer, "#Valve_Hint_JeepKeys" );
  710. m_iNumberOfEntries++;
  711. }
  712. }
  713. // If we're exiting and have had the tau cannon removed, we don't want to reset the animation
  714. GetServerVehicle()->HandleEntryExitFinish( m_bExitAnimOn, true );
  715. }
  716. // See if the ammo crate needs to close
  717. if ( ( m_flAmmoCrateCloseTime < gpGlobals->curtime ) && ( GetSequence() == LookupSequence( "ammo_open" ) ) )
  718. {
  719. m_flAnimTime = gpGlobals->curtime;
  720. m_flPlaybackRate = 0.0;
  721. SetCycle( 0 );
  722. ResetSequence( LookupSequence( "ammo_close" ) );
  723. }
  724. else if ( ( GetSequence() == LookupSequence( "ammo_close" ) ) && IsSequenceFinished() )
  725. {
  726. m_flAnimTime = gpGlobals->curtime;
  727. m_flPlaybackRate = 0.0;
  728. SetCycle( 0 );
  729. ResetSequence( LookupSequence( "idle" ) );
  730. CPASAttenuationFilter sndFilter( this, "PropJeep.AmmoClose" );
  731. EmitSound( sndFilter, entindex(), "PropJeep.AmmoClose" );
  732. }
  733. }
  734. //-----------------------------------------------------------------------------
  735. // Purpose:
  736. // Input : &startPos -
  737. // &endPos -
  738. // width -
  739. // useMuzzle -
  740. //-----------------------------------------------------------------------------
  741. void CPropJeep::DrawBeam( const Vector &startPos, const Vector &endPos, float width )
  742. {
  743. /*
  744. //Tracer down the middle
  745. UTIL_Tracer( startPos, endPos, 0, TRACER_DONT_USE_ATTACHMENT, 6500, false, "GaussTracer" );
  746. //Draw the main beam shaft
  747. CBeam *pBeam = CBeam::BeamCreate( GAUSS_BEAM_SPRITE, 0.5 );
  748. pBeam->SetStartPos( startPos );
  749. pBeam->PointEntInit( endPos, this );
  750. pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
  751. pBeam->SetWidth( width );
  752. pBeam->SetEndWidth( 0.05f );
  753. pBeam->SetBrightness( 255 );
  754. pBeam->SetColor( 255, 185+random->RandomInt( -16, 16 ), 40 );
  755. pBeam->RelinkBeam();
  756. pBeam->LiveForTime( 0.1f );
  757. //Draw electric bolts along shaft
  758. pBeam = CBeam::BeamCreate( GAUSS_BEAM_SPRITE, 3.0f );
  759. pBeam->SetStartPos( startPos );
  760. pBeam->PointEntInit( endPos, this );
  761. pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
  762. pBeam->SetBrightness( random->RandomInt( 64, 255 ) );
  763. pBeam->SetColor( 255, 255, 150+random->RandomInt( 0, 64 ) );
  764. pBeam->RelinkBeam();
  765. pBeam->LiveForTime( 0.1f );
  766. pBeam->SetNoise( 1.6f );
  767. pBeam->SetEndWidth( 0.1f ); */
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Purpose:
  771. //-----------------------------------------------------------------------------
  772. void CPropJeep::FireCannon( void )
  773. {
  774. //Don't fire again if it's been too soon
  775. if ( m_flCannonTime > gpGlobals->curtime )
  776. return;
  777. if ( m_bUnableToFire )
  778. return;
  779. m_flCannonTime = gpGlobals->curtime + 0.2f;
  780. m_bCannonCharging = false;
  781. //Find the direction the gun is pointing in
  782. Vector aimDir;
  783. GetCannonAim( &aimDir );
  784. FireBulletsInfo_t info( 1, m_vecGunOrigin, aimDir, VECTOR_CONE_1DEGREES, MAX_TRACE_LENGTH, m_nAmmoType );
  785. info.m_nFlags = FIRE_BULLETS_ALLOW_WATER_SURFACE_IMPACTS;
  786. info.m_pAttacker = m_hPlayer;
  787. FireBullets( info );
  788. // Register a muzzleflash for the AI
  789. if ( m_hPlayer )
  790. {
  791. m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );
  792. }
  793. CPASAttenuationFilter sndFilter( this, "PropJeep.FireCannon" );
  794. EmitSound( sndFilter, entindex(), "PropJeep.FireCannon" );
  795. // make cylinders of gun spin a bit
  796. m_nSpinPos += JEEP_GUN_SPIN_RATE;
  797. //SetPoseParameter( JEEP_GUN_SPIN, m_nSpinPos ); //FIXME: Don't bother with this for E3, won't look right
  798. }
  799. //-----------------------------------------------------------------------------
  800. // Purpose:
  801. //-----------------------------------------------------------------------------
  802. void CPropJeep::FireChargedCannon( void )
  803. {
  804. /* bool penetrated = false;
  805. m_bCannonCharging = false;
  806. m_flCannonTime = gpGlobals->curtime + 0.5f;
  807. StopChargeSound();
  808. CPASAttenuationFilter sndFilter( this, "PropJeep.FireChargedCannon" );
  809. EmitSound( sndFilter, entindex(), "PropJeep.FireChargedCannon" );
  810. //Find the direction the gun is pointing in
  811. Vector aimDir;
  812. GetCannonAim( &aimDir );
  813. Vector endPos = m_vecGunOrigin + ( aimDir * MAX_TRACE_LENGTH );
  814. //Shoot a shot straight out
  815. trace_t tr;
  816. UTIL_TraceLine( m_vecGunOrigin, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  817. ClearMultiDamage();
  818. //Find how much damage to do
  819. float flChargeAmount = ( gpGlobals->curtime - m_flCannonChargeStartTime ) / MAX_GAUSS_CHARGE_TIME;
  820. //Clamp this
  821. if ( flChargeAmount > 1.0f )
  822. {
  823. flChargeAmount = 1.0f;
  824. }
  825. //Determine the damage amount
  826. //FIXME: Use ConVars!
  827. float flDamage = 15 + ( ( 250 - 15 ) * flChargeAmount );
  828. CBaseEntity *pHit = tr.m_pEnt;
  829. //Look for wall penetration
  830. if ( tr.DidHitWorld() && !(tr.surface.flags & SURF_SKY) )
  831. {
  832. //Try wall penetration
  833. UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" );
  834. UTIL_DecalTrace( &tr, "RedGlowFade" );
  835. CPVSFilter filter( tr.endpos );
  836. te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
  837. Vector testPos = tr.endpos + ( aimDir * 48.0f );
  838. UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, GetDriver(), COLLISION_GROUP_NONE, &tr );
  839. if ( tr.allsolid == false )
  840. {
  841. UTIL_DecalTrace( &tr, "RedGlowFade" );
  842. penetrated = true;
  843. }
  844. }
  845. else if ( pHit != NULL )
  846. {
  847. CTakeDamageInfo dmgInfo( this, GetDriver(), flDamage, DMG_SHOCK );
  848. CalculateBulletDamageForce( &dmgInfo, GetAmmoDef()->Index("GaussEnergy"), aimDir, tr.endpos, 1.0f + flChargeAmount * 4.0f );
  849. //Do direct damage to anything in our path
  850. pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr );
  851. }
  852. ApplyMultiDamage();
  853. //Kick up an effect
  854. if ( !(tr.surface.flags & SURF_SKY) )
  855. {
  856. UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" );
  857. //Do a gauss explosion
  858. CPVSFilter filter( tr.endpos );
  859. te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
  860. }
  861. //Show the effect
  862. DrawBeam( m_vecGunOrigin, tr.endpos, 9.6 );
  863. // Register a muzzleflash for the AI
  864. if ( m_hPlayer )
  865. {
  866. m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5f );
  867. }
  868. //Rock the car
  869. IPhysicsObject *pObj = VPhysicsGetObject();
  870. if ( pObj != NULL )
  871. {
  872. Vector shoveDir = aimDir * -( flDamage * 500.0f );
  873. pObj->ApplyForceOffset( shoveDir, m_vecGunOrigin );
  874. }
  875. //Do radius damage if we didn't penetrate the wall
  876. if ( penetrated == true )
  877. {
  878. RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL );
  879. } */
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Purpose:
  883. //-----------------------------------------------------------------------------
  884. void CPropJeep::ChargeCannon( void )
  885. {
  886. //Don't fire again if it's been too soon
  887. if ( m_flCannonTime > gpGlobals->curtime )
  888. return;
  889. //See if we're starting a charge
  890. if ( m_bCannonCharging == false )
  891. {
  892. m_flCannonChargeStartTime = gpGlobals->curtime;
  893. m_bCannonCharging = true;
  894. //Start charging sound
  895. CPASAttenuationFilter filter( this );
  896. m_sndCannonCharge = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "Jeep.GaussCharge", ATTN_NORM );
  897. assert(m_sndCannonCharge!=NULL);
  898. if ( m_sndCannonCharge != NULL )
  899. {
  900. (CSoundEnvelopeController::GetController()).Play( m_sndCannonCharge, 1.0f, 50 );
  901. (CSoundEnvelopeController::GetController()).SoundChangePitch( m_sndCannonCharge, 250, 3.0f );
  902. }
  903. return;
  904. }
  905. //TODO: Add muzzle effect?
  906. //TODO: Check for overcharge and have the weapon simply fire or instead "decharge"?
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose:
  910. //-----------------------------------------------------------------------------
  911. void CPropJeep::StopChargeSound( void )
  912. {
  913. if ( m_sndCannonCharge != NULL )
  914. {
  915. (CSoundEnvelopeController::GetController()).SoundFadeOut( m_sndCannonCharge, 0.1f );
  916. }
  917. }
  918. //-----------------------------------------------------------------------------
  919. // Purpose: Finds the true aiming position of the gun (looks at what player
  920. // is looking at and adjusts)
  921. // Input : &resultDir - direction to be calculated
  922. //-----------------------------------------------------------------------------
  923. void CPropJeep::GetCannonAim( Vector *resultDir )
  924. {
  925. Vector muzzleOrigin;
  926. QAngle muzzleAngles;
  927. GetAttachment( LookupAttachment("gun_ref"), muzzleOrigin, muzzleAngles );
  928. AngleVectors( muzzleAngles, resultDir );
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Purpose: If the player uses the jeep while at the back, he gets ammo from the crate instead
  932. //-----------------------------------------------------------------------------
  933. void CPropJeep::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  934. {
  935. CBasePlayer *pPlayer = ToBasePlayer( pActivator );
  936. if ( pPlayer == NULL)
  937. return;
  938. // Find out if the player's looking at our ammocrate hitbox
  939. Vector vecForward;
  940. pPlayer->EyeVectors( &vecForward, NULL, NULL );
  941. trace_t tr;
  942. Vector vecStart = pPlayer->EyePosition();
  943. UTIL_TraceLine( vecStart, vecStart + vecForward * 1024, MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX, pPlayer, COLLISION_GROUP_NONE, &tr );
  944. if ( tr.m_pEnt == this && tr.hitgroup == JEEP_AMMOCRATE_HITGROUP )
  945. {
  946. // Player's using the crate.
  947. // Fill up his SMG ammo.
  948. pPlayer->GiveAmmo( 300, "SMG1");
  949. if ( ( GetSequence() != LookupSequence( "ammo_open" ) ) && ( GetSequence() != LookupSequence( "ammo_close" ) ) )
  950. {
  951. // Open the crate
  952. m_flAnimTime = gpGlobals->curtime;
  953. m_flPlaybackRate = 0.0;
  954. SetCycle( 0 );
  955. ResetSequence( LookupSequence( "ammo_open" ) );
  956. CPASAttenuationFilter sndFilter( this, "PropJeep.AmmoOpen" );
  957. EmitSound( sndFilter, entindex(), "PropJeep.AmmoOpen" );
  958. }
  959. m_flAmmoCrateCloseTime = gpGlobals->curtime + JEEP_AMMO_CRATE_CLOSE_DELAY;
  960. return;
  961. }
  962. // Fall back and get in the vehicle instead
  963. BaseClass::Use( pActivator, pCaller, useType, value );
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Purpose:
  967. //-----------------------------------------------------------------------------
  968. bool CPropJeep::CanExitVehicle( CBaseEntity *pEntity )
  969. {
  970. return ( !m_bEnterAnimOn && !m_bExitAnimOn && !m_bLocked && (m_nSpeed <= g_jeepexitspeed.GetFloat() ) );
  971. }
  972. //-----------------------------------------------------------------------------
  973. // Purpose:
  974. //-----------------------------------------------------------------------------
  975. void CPropJeep::DampenEyePosition( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles )
  976. {
  977. // Get the frametime. (Check to see if enough time has passed to warrent dampening).
  978. float flFrameTime = gpGlobals->frametime;
  979. if ( flFrameTime < JEEP_FRAMETIME_MIN )
  980. {
  981. vecVehicleEyePos = m_vecLastEyePos;
  982. DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, 0.0f );
  983. return;
  984. }
  985. // Keep static the sideways motion.
  986. // Dampen forward/backward motion.
  987. DampenForwardMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
  988. // Blend up/down motion.
  989. DampenUpMotion( vecVehicleEyePos, vecVehicleEyeAngles, flFrameTime );
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Use the controller as follows:
  993. // speed += ( pCoefficientsOut[0] * ( targetPos - currentPos ) + pCoefficientsOut[1] * ( targetSpeed - currentSpeed ) ) * flDeltaTime;
  994. //-----------------------------------------------------------------------------
  995. void CPropJeep::ComputePDControllerCoefficients( float *pCoefficientsOut,
  996. float flFrequency, float flDampening,
  997. float flDeltaTime )
  998. {
  999. float flKs = 9.0f * flFrequency * flFrequency;
  1000. float flKd = 4.5f * flFrequency * flDampening;
  1001. float flScale = 1.0f / ( 1.0f + flKd * flDeltaTime + flKs * flDeltaTime * flDeltaTime );
  1002. pCoefficientsOut[0] = flKs * flScale;
  1003. pCoefficientsOut[1] = ( flKd + flKs * flDeltaTime ) * flScale;
  1004. }
  1005. //-----------------------------------------------------------------------------
  1006. // Purpose:
  1007. //-----------------------------------------------------------------------------
  1008. void CPropJeep::DampenForwardMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
  1009. {
  1010. // Get forward vector.
  1011. Vector vecForward;
  1012. AngleVectors( vecVehicleEyeAngles, &vecForward);
  1013. // Simulate the eye position forward based on the data from last frame
  1014. // (assumes no acceleration - it will get that from the "spring").
  1015. Vector vecCurrentEyePos = m_vecLastEyePos + m_vecEyeSpeed * flFrameTime;
  1016. // Calculate target speed based on the current vehicle eye position and the last vehicle eye position and frametime.
  1017. Vector vecVehicleEyeSpeed = ( vecVehicleEyePos - m_vecLastEyeTarget ) / flFrameTime;
  1018. m_vecLastEyeTarget = vecVehicleEyePos;
  1019. // Calculate the speed and position deltas.
  1020. Vector vecDeltaSpeed = vecVehicleEyeSpeed - m_vecEyeSpeed;
  1021. Vector vecDeltaPos = vecVehicleEyePos - vecCurrentEyePos;
  1022. // Clamp.
  1023. if ( vecDeltaPos.Length() > JEEP_DELTA_LENGTH_MAX )
  1024. {
  1025. float flSign = vecForward.Dot( vecVehicleEyeSpeed ) >= 0.0f ? -1.0f : 1.0f;
  1026. vecVehicleEyePos += flSign * ( vecForward * JEEP_DELTA_LENGTH_MAX );
  1027. m_vecLastEyePos = vecVehicleEyePos;
  1028. m_vecEyeSpeed = vecVehicleEyeSpeed;
  1029. return;
  1030. }
  1031. // Generate an updated (dampening) speed for use in next frames position extrapolation.
  1032. float flCoefficients[2];
  1033. ComputePDControllerCoefficients( flCoefficients, r_JeepViewDampenFreq.GetFloat(), r_JeepViewDampenDamp.GetFloat(), flFrameTime );
  1034. m_vecEyeSpeed += ( ( flCoefficients[0] * vecDeltaPos + flCoefficients[1] * vecDeltaSpeed ) * flFrameTime );
  1035. // Save off data for next frame.
  1036. m_vecLastEyePos = vecCurrentEyePos;
  1037. // Move eye forward/backward.
  1038. Vector vecForwardOffset = vecForward * ( vecForward.Dot( vecDeltaPos ) );
  1039. vecVehicleEyePos -= vecForwardOffset;
  1040. }
  1041. //-----------------------------------------------------------------------------
  1042. // Purpose:
  1043. //-----------------------------------------------------------------------------
  1044. void CPropJeep::DampenUpMotion( Vector &vecVehicleEyePos, QAngle &vecVehicleEyeAngles, float flFrameTime )
  1045. {
  1046. // Get up vector.
  1047. Vector vecUp;
  1048. AngleVectors( vecVehicleEyeAngles, NULL, NULL, &vecUp );
  1049. vecUp.z = clamp( vecUp.z, 0.0f, vecUp.z );
  1050. vecVehicleEyePos.z += r_JeepViewZHeight.GetFloat() * vecUp.z;
  1051. // NOTE: Should probably use some damped equation here.
  1052. }
  1053. //-----------------------------------------------------------------------------
  1054. // Purpose:
  1055. //-----------------------------------------------------------------------------
  1056. void CPropJeep::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
  1057. {
  1058. // If we are overturned and hit any key - leave the vehicle (IN_USE is already handled!).
  1059. if ( m_flOverturnedTime > OVERTURNED_EXIT_WAITTIME )
  1060. {
  1061. if ( (ucmd->buttons & (IN_FORWARD|IN_BACK|IN_MOVELEFT|IN_MOVERIGHT|IN_SPEED|IN_JUMP|IN_ATTACK|IN_ATTACK2) ) && !m_bExitAnimOn )
  1062. {
  1063. // Can't exit yet? We're probably still moving. Swallow the keys.
  1064. if ( !CanExitVehicle(player) )
  1065. return;
  1066. if ( !GetServerVehicle()->HandlePassengerExit( m_hPlayer ) && ( m_hPlayer != NULL ) )
  1067. {
  1068. m_hPlayer->PlayUseDenySound();
  1069. }
  1070. return;
  1071. }
  1072. }
  1073. // If the throttle is disabled or we're upside-down, don't allow throttling (including turbo)
  1074. CUserCmd tmp;
  1075. if ( ( m_throttleDisableTime > gpGlobals->curtime ) || ( IsOverturned() ) )
  1076. {
  1077. m_bUnableToFire = true;
  1078. tmp = (*ucmd);
  1079. tmp.buttons &= ~(IN_FORWARD|IN_BACK|IN_SPEED);
  1080. ucmd = &tmp;
  1081. }
  1082. BaseClass::SetupMove( player, ucmd, pHelper, move );
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. // Purpose:
  1086. //-----------------------------------------------------------------------------
  1087. void CPropJeep::DriveVehicle( float flFrameTime, CUserCmd *ucmd, int iButtonsDown, int iButtonsReleased )
  1088. {
  1089. int iButtons = ucmd->buttons;
  1090. //Adrian: No headlights on Superfly.
  1091. /* if ( ucmd->impulse == 100 )
  1092. {
  1093. if (HeadlightIsOn())
  1094. {
  1095. HeadlightTurnOff();
  1096. }
  1097. else
  1098. {
  1099. HeadlightTurnOn();
  1100. }
  1101. }*/
  1102. // If we're holding down an attack button, update our state
  1103. if ( IsOverturned() == false )
  1104. {
  1105. if ( iButtons & IN_ATTACK )
  1106. {
  1107. if ( m_bCannonCharging )
  1108. {
  1109. FireChargedCannon();
  1110. }
  1111. else
  1112. {
  1113. FireCannon();
  1114. }
  1115. }
  1116. else if ( iButtons & IN_ATTACK2 )
  1117. {
  1118. ChargeCannon();
  1119. }
  1120. }
  1121. // If we've released our secondary button, fire off our cannon
  1122. if ( ( iButtonsReleased & IN_ATTACK2 ) && ( m_bCannonCharging ) )
  1123. {
  1124. FireChargedCannon();
  1125. }
  1126. BaseClass::DriveVehicle( flFrameTime, ucmd, iButtonsDown, iButtonsReleased );
  1127. }
  1128. //-----------------------------------------------------------------------------
  1129. // Purpose:
  1130. // Input : *pPlayer -
  1131. // *pMoveData -
  1132. //-----------------------------------------------------------------------------
  1133. void CPropJeep::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData )
  1134. {
  1135. BaseClass::ProcessMovement( pPlayer, pMoveData );
  1136. // Update the steering angles based on speed.
  1137. UpdateSteeringAngle();
  1138. // Create dangers sounds in front of the vehicle.
  1139. CreateDangerSounds();
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Purpose:
  1143. //-----------------------------------------------------------------------------
  1144. void CPropJeep::UpdateSteeringAngle( void )
  1145. {
  1146. float flMaxSpeed = m_VehiclePhysics.GetMaxSpeed();
  1147. float flSpeed = m_VehiclePhysics.GetSpeed();
  1148. float flRatio = 1.0f - ( flSpeed / flMaxSpeed );
  1149. float flSteeringDegrees = JEEP_STEERING_FAST_ANGLE + ( ( JEEP_STEERING_SLOW_ANGLE - JEEP_STEERING_FAST_ANGLE ) * flRatio );
  1150. flSteeringDegrees = clamp( flSteeringDegrees, JEEP_STEERING_FAST_ANGLE, JEEP_STEERING_SLOW_ANGLE );
  1151. m_VehiclePhysics.SetSteeringDegrees( flSteeringDegrees );
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Purpose: Create danger sounds in front of the vehicle.
  1155. //-----------------------------------------------------------------------------
  1156. void CPropJeep::CreateDangerSounds( void )
  1157. {
  1158. QAngle dummy;
  1159. GetAttachment( "Muzzle", m_vecGunOrigin, dummy );
  1160. if ( m_flDangerSoundTime > gpGlobals->curtime )
  1161. return;
  1162. QAngle vehicleAngles = GetLocalAngles();
  1163. Vector vecStart = GetAbsOrigin();
  1164. Vector vecDir, vecRight;
  1165. GetVectors( &vecDir, &vecRight, NULL );
  1166. const float soundDuration = 0.25;
  1167. float speed = m_VehiclePhysics.GetHLSpeed();
  1168. // Make danger sounds ahead of the jeep
  1169. if ( fabs(speed) > 120 )
  1170. {
  1171. Vector vecSpot;
  1172. float steering = m_VehiclePhysics.GetSteering();
  1173. if ( steering != 0 )
  1174. {
  1175. if ( speed > 0 )
  1176. {
  1177. vecDir += vecRight * steering * 0.5;
  1178. }
  1179. else
  1180. {
  1181. vecDir -= vecRight * steering * 0.5;
  1182. }
  1183. VectorNormalize(vecDir);
  1184. }
  1185. const float radius = speed * 0.4;
  1186. // 0.3 seconds ahead of the jeep
  1187. vecSpot = vecStart + vecDir * (speed * 0.3f);
  1188. CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, radius, soundDuration, this, 0 );
  1189. CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, vecSpot, radius, soundDuration, this, 1 );
  1190. //NDebugOverlay::Box(vecSpot, Vector(-radius,-radius,-radius),Vector(radius,radius,radius), 255, 0, 255, 0, soundDuration);
  1191. #if 0
  1192. trace_t tr;
  1193. // put sounds a bit to left and right but slightly closer to Jeep to make a "cone" of sound
  1194. // in front of it
  1195. vecSpot = vecStart + vecDir * (speed * 0.5f) - vecRight * speed * 0.5;
  1196. UTIL_TraceLine( vecStart, vecSpot, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  1197. CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, soundDuration, this, 1 );
  1198. vecSpot = vecStart + vecDir * (speed * 0.5f) + vecRight * speed * 0.5;
  1199. UTIL_TraceLine( vecStart, vecSpot, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  1200. CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, soundDuration, this, 2);
  1201. #endif
  1202. }
  1203. m_flDangerSoundTime = gpGlobals->curtime + 0.1;
  1204. }
  1205. //-----------------------------------------------------------------------------
  1206. // Purpose:
  1207. //-----------------------------------------------------------------------------
  1208. void CPropJeep::EnterVehicle( CBasePlayer *pPlayer )
  1209. {
  1210. if ( !pPlayer )
  1211. return;
  1212. CheckWater();
  1213. BaseClass::EnterVehicle( pPlayer );
  1214. // Start looking for seagulls to land
  1215. m_hLastPlayerInVehicle = m_hPlayer;
  1216. }
  1217. //-----------------------------------------------------------------------------
  1218. // Purpose:
  1219. //-----------------------------------------------------------------------------
  1220. void CPropJeep::ExitVehicle( int nRole )
  1221. {
  1222. HeadlightTurnOff();
  1223. BaseClass::ExitVehicle( nRole );
  1224. //If the player has exited, stop charging
  1225. StopChargeSound();
  1226. m_bCannonCharging = false;
  1227. // Remember when we last saw the player
  1228. m_flPlayerExitedTime = gpGlobals->curtime;
  1229. m_flLastSawPlayerAt = gpGlobals->curtime;
  1230. }
  1231. //-----------------------------------------------------------------------------
  1232. // Purpose:
  1233. //-----------------------------------------------------------------------------
  1234. void CPropJeep::InputStartRemoveTauCannon( inputdata_t &inputdata )
  1235. {
  1236. // Start the gun removal animation
  1237. m_flAnimTime = gpGlobals->curtime;
  1238. m_flPlaybackRate = 0.0;
  1239. SetCycle( 0 );
  1240. ResetSequence( LookupSequence( "tau_levitate" ) );
  1241. m_bGunHasBeenCutOff = true;
  1242. }
  1243. //-----------------------------------------------------------------------------
  1244. // Purpose:
  1245. //-----------------------------------------------------------------------------
  1246. void CPropJeep::InputFinishRemoveTauCannon( inputdata_t &inputdata )
  1247. {
  1248. // Remove & hide the gun
  1249. SetBodygroup( 1, false );
  1250. m_bHasGun = false;
  1251. }
  1252. //-----------------------------------------------------------------------------
  1253. // Purpose:
  1254. //-----------------------------------------------------------------------------
  1255. void CPropJeep::OnRestore( void )
  1256. {
  1257. IServerVehicle *pServerVehicle = GetServerVehicle();
  1258. if ( pServerVehicle != NULL )
  1259. {
  1260. // Restore the passenger information we're holding on to
  1261. pServerVehicle->RestorePassengerInfo();
  1262. }
  1263. }
  1264. //========================================================================================================================================
  1265. // JEEP FOUR WHEEL PHYSICS VEHICLE SERVER VEHICLE
  1266. //========================================================================================================================================
  1267. //-----------------------------------------------------------------------------
  1268. // Purpose:
  1269. //-----------------------------------------------------------------------------
  1270. void CJeepFourWheelServerVehicle::NPC_AimPrimaryWeapon( Vector vecTarget )
  1271. {
  1272. ((CPropJeep*)m_pVehicle)->AimGunAt( &vecTarget, 0.1f );
  1273. }
  1274. //-----------------------------------------------------------------------------
  1275. // Purpose:
  1276. // Input : &vecEyeExitEndpoint -
  1277. // Output : int
  1278. //-----------------------------------------------------------------------------
  1279. int CJeepFourWheelServerVehicle::GetExitAnimToUse( Vector &vecEyeExitEndpoint, bool &bAllPointsBlocked )
  1280. {
  1281. bAllPointsBlocked = false;
  1282. if ( !m_bParsedAnimations )
  1283. {
  1284. // Load the entry/exit animations from the vehicle
  1285. ParseEntryExitAnims();
  1286. m_bParsedAnimations = true;
  1287. }
  1288. CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating *>(m_pVehicle);
  1289. // If we don't have the gun anymore, we want to get out using the "gun-less" animation
  1290. if ( pAnimating )
  1291. {
  1292. // HACK: We know the tau-cannon removed exit anim uses the first upright anim's exit details
  1293. trace_t tr;
  1294. Vector vehicleExitOrigin;
  1295. QAngle vehicleExitAngles;
  1296. // Ensure the endpoint is clear by dropping a point down from above
  1297. pAnimating->GetAttachment( m_ExitAnimations[0].iAttachment, vehicleExitOrigin, vehicleExitAngles );
  1298. vehicleExitOrigin -= VEC_VIEW;
  1299. Vector vecMove = Vector(0,0,64);
  1300. Vector vecStart = vehicleExitOrigin + vecMove;
  1301. Vector vecEnd = vehicleExitOrigin - vecMove;
  1302. UTIL_TraceHull( vecStart, vecEnd, VEC_HULL_MIN, VEC_HULL_MAX, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
  1303. Assert( !tr.startsolid && tr.fraction < 1.0 );
  1304. m_vecCurrentExitEndPoint = vecStart + ((vecEnd - vecStart) * tr.fraction);
  1305. vecEyeExitEndpoint = m_vecCurrentExitEndPoint + VEC_VIEW;
  1306. m_iCurrentExitAnim = 0;
  1307. return pAnimating->LookupSequence( "exit_tauremoved" );
  1308. }
  1309. return BaseClass::GetExitAnimToUse( vecEyeExitEndpoint, bAllPointsBlocked );
  1310. }