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.

1731 lines
53 KiB

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