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.

1144 lines
31 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "gamemovement.h"
  9. #include "cs_gamerules.h"
  10. #include "in_buttons.h"
  11. #include "movevars_shared.h"
  12. #include "weapon_csbase.h"
  13. #ifdef CLIENT_DLL
  14. #include "c_cs_player.h"
  15. #else
  16. #include "cs_player.h"
  17. #include "KeyValues.h"
  18. #endif
  19. #define STAMINA_MAX 100.0
  20. #define STAMINA_COST_JUMP 25.0
  21. #define STAMINA_COST_FALL 20.0
  22. #define STAMINA_RECOVER_RATE 19.0
  23. extern bool g_bMovementOptimizations;
  24. ConVar sv_timebetweenducks( "sv_timebetweenducks", "0", FCVAR_REPLICATED, "Minimum time before recognizing consecutive duck key", true, 0.0, true, 2.0 );
  25. ConVar sv_enableboost( "sv_enableboost", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Allow boost exploits");
  26. class CCSGameMovement : public CGameMovement
  27. {
  28. public:
  29. DECLARE_CLASS( CCSGameMovement, CGameMovement );
  30. CCSGameMovement();
  31. virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
  32. virtual bool CanAccelerate();
  33. virtual bool CheckJumpButton( void );
  34. virtual void PreventBunnyJumping( void );
  35. virtual void ReduceTimers( void );
  36. virtual void WalkMove( void );
  37. virtual void AirMove( void );
  38. virtual bool LadderMove( void );
  39. virtual void DecayPunchAngle( void );
  40. virtual void CheckParameters( void );
  41. // allow overridden versions to respond to jumping
  42. virtual void OnJump( float fImpulse );
  43. virtual void OnLand( float fVelocity );
  44. // Ducking
  45. virtual void Duck( void );
  46. virtual void FinishUnDuck( void );
  47. virtual void FinishDuck( void );
  48. virtual bool CanUnduck();
  49. virtual void HandleDuckingSpeedCrop();
  50. virtual bool OnLadder( trace_t &trace );
  51. virtual float LadderDistance( void ) const
  52. {
  53. if ( player->GetMoveType() == MOVETYPE_LADDER )
  54. return 10.0f;
  55. return 2.0f;
  56. }
  57. virtual unsigned int LadderMask( void ) const
  58. {
  59. return MASK_PLAYERSOLID & ( ~CONTENTS_PLAYERCLIP );
  60. }
  61. virtual float ClimbSpeed( void ) const;
  62. virtual float LadderLateralMultiplier( void ) const;
  63. virtual void TryTouchGround( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, unsigned int fMask, int collisionGroup, trace_t& pm );
  64. protected:
  65. virtual void PlayerMove();
  66. void CheckForLadders( bool wasOnGround );
  67. virtual unsigned int PlayerSolidMask( bool brushOnly = false ); ///< returns the solid mask for the given player, so bots can have a more-restrictive set
  68. float m_fTimeLastUnducked;
  69. public:
  70. CCSPlayer *m_pCSPlayer;
  71. };
  72. //-----------------------------------------------------------------------------
  73. // Purpose: used by the TryTouchGround function to exclude non-standables from
  74. // consideration
  75. //-----------------------------------------------------------------------------
  76. bool CheckForStandable( IHandleEntity *pHandleEntity, int contentsMask )
  77. {
  78. CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  79. if ( !pEntity )
  80. return false;
  81. return ( pEntity->IsPlayer() && pEntity->GetGroundEntity() != NULL ) || pEntity->IsStandable();
  82. }
  83. // Expose our interface.
  84. static CCSGameMovement g_GameMovement;
  85. IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
  86. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
  87. // ---------------------------------------------------------------------------------------- //
  88. // CCSGameMovement.
  89. // ---------------------------------------------------------------------------------------- //
  90. CCSGameMovement::CCSGameMovement()
  91. {
  92. m_fTimeLastUnducked = 0.0f;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Allow bots etc to use slightly different solid masks
  96. //-----------------------------------------------------------------------------
  97. unsigned int CCSGameMovement::PlayerSolidMask( bool brushOnly )
  98. {
  99. bool isBot = !player || player->IsBot();
  100. if ( brushOnly )
  101. {
  102. if ( isBot )
  103. {
  104. return MASK_PLAYERSOLID_BRUSHONLY | CONTENTS_MONSTERCLIP;
  105. }
  106. else
  107. {
  108. return MASK_PLAYERSOLID_BRUSHONLY;
  109. }
  110. }
  111. else
  112. {
  113. if ( isBot )
  114. {
  115. return MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
  116. }
  117. else
  118. {
  119. return MASK_PLAYERSOLID;
  120. }
  121. }
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. //-----------------------------------------------------------------------------
  126. void CCSGameMovement::CheckParameters( void )
  127. {
  128. QAngle v_angle;
  129. // maintaining auto-duck during jumps
  130. if ( m_pCSPlayer->m_duckUntilOnGround )
  131. {
  132. if ( !player->GetGroundEntity() )
  133. {
  134. if ( mv->m_nButtons & IN_DUCK )
  135. {
  136. m_pCSPlayer->m_duckUntilOnGround = false; // player hit +duck, so cancel our auto duck
  137. }
  138. else
  139. {
  140. mv->m_nButtons |= IN_DUCK;
  141. }
  142. }
  143. }
  144. // it would be nice to put this into the player->GetPlayerMaxSpeed() method, but
  145. // this flag is only stored in the move!
  146. if ( mv->m_nButtons & IN_SPEED )
  147. {
  148. mv->m_flMaxSpeed *= CS_PLAYER_SPEED_WALK_MODIFIER;
  149. }
  150. if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
  151. player->GetMoveType() != MOVETYPE_NOCLIP &&
  152. player->GetMoveType() != MOVETYPE_OBSERVER )
  153. {
  154. float spd;
  155. spd = ( mv->m_flForwardMove * mv->m_flForwardMove ) +
  156. ( mv->m_flSideMove * mv->m_flSideMove ) +
  157. ( mv->m_flUpMove * mv->m_flUpMove );
  158. // Slow down by the speed factor
  159. float flSpeedFactor = 1.0f;
  160. if (player->m_pSurfaceData)
  161. {
  162. flSpeedFactor = player->m_pSurfaceData->game.maxSpeedFactor;
  163. }
  164. // If we have a constraint, slow down because of that too.
  165. float flConstraintSpeedFactor = ComputeConstraintSpeedFactor();
  166. if (flConstraintSpeedFactor < flSpeedFactor)
  167. flSpeedFactor = flConstraintSpeedFactor;
  168. // Take the player's velocity modifier into account
  169. if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
  170. {
  171. flSpeedFactor *= m_pCSPlayer->m_flVelocityModifier;
  172. }
  173. mv->m_flMaxSpeed *= flSpeedFactor;
  174. if ( g_bMovementOptimizations )
  175. {
  176. // Same thing but only do the sqrt if we have to.
  177. if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed*mv->m_flMaxSpeed ) )
  178. {
  179. float fRatio = mv->m_flMaxSpeed / sqrt( spd );
  180. mv->m_flForwardMove *= fRatio;
  181. mv->m_flSideMove *= fRatio;
  182. mv->m_flUpMove *= fRatio;
  183. }
  184. }
  185. else
  186. {
  187. spd = sqrt( spd );
  188. if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed ) )
  189. {
  190. float fRatio = mv->m_flMaxSpeed / spd;
  191. mv->m_flForwardMove *= fRatio;
  192. mv->m_flSideMove *= fRatio;
  193. mv->m_flUpMove *= fRatio;
  194. }
  195. }
  196. }
  197. if ( player->GetFlags() & FL_FROZEN ||
  198. player->GetFlags() & FL_ONTRAIN ||
  199. IsDead() )
  200. {
  201. mv->m_flForwardMove = 0;
  202. mv->m_flSideMove = 0;
  203. mv->m_flUpMove = 0;
  204. }
  205. DecayPunchAngle();
  206. // Take angles from command.
  207. if ( !IsDead() )
  208. {
  209. v_angle = mv->m_vecAngles;
  210. v_angle = v_angle + player->m_Local.m_vecPunchAngle;
  211. // Now adjust roll angle
  212. if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
  213. player->GetMoveType() != MOVETYPE_NOCLIP )
  214. {
  215. mv->m_vecAngles[ROLL] = CalcRoll( v_angle, mv->m_vecVelocity, sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
  216. }
  217. else
  218. {
  219. mv->m_vecAngles[ROLL] = 0.0; // v_angle[ ROLL ];
  220. }
  221. mv->m_vecAngles[PITCH] = v_angle[PITCH];
  222. mv->m_vecAngles[YAW] = v_angle[YAW];
  223. }
  224. else
  225. {
  226. mv->m_vecAngles = mv->m_vecOldAngles;
  227. }
  228. // Set dead player view_offset
  229. if ( IsDead() )
  230. {
  231. player->SetViewOffset( VEC_DEAD_VIEWHEIGHT );
  232. }
  233. // Adjust client view angles to match values used on server.
  234. if ( mv->m_vecAngles[YAW] > 180.0f )
  235. {
  236. mv->m_vecAngles[YAW] -= 360.0f;
  237. }
  238. // If we're standing on a player, then force them off.
  239. if ( !player->IsObserver() && ( player->GetMoveType() != MOVETYPE_LADDER ) )
  240. {
  241. int nLevels = 0;
  242. CBaseEntity *pCurGround = player->GetGroundEntity();
  243. while ( pCurGround && pCurGround->IsPlayer() && nLevels < 1000 )
  244. {
  245. pCurGround = pCurGround->GetGroundEntity();
  246. ++nLevels;
  247. }
  248. if ( nLevels == 1000 )
  249. Warning( "BUG: CCSGameMovement::CheckParameters - too many stacking levels.\n" );
  250. // If they're stacked too many levels deep, slide them off.
  251. if ( nLevels > 1 )
  252. {
  253. mv->m_flForwardMove = mv->m_flMaxSpeed * 3;
  254. mv->m_flSideMove = 0;
  255. mv->m_nButtons = 0;
  256. mv->m_nImpulseCommand = 0;
  257. }
  258. }
  259. }
  260. void CCSGameMovement::ProcessMovement( CBasePlayer *pBasePlayer, CMoveData *pMove )
  261. {
  262. m_pCSPlayer = ToCSPlayer( pBasePlayer );
  263. Assert( m_pCSPlayer );
  264. BaseClass::ProcessMovement( pBasePlayer, pMove );
  265. }
  266. bool CCSGameMovement::CanAccelerate()
  267. {
  268. // Only allow the player to accelerate when in certain states.
  269. CSPlayerState curState = m_pCSPlayer->State_Get();
  270. if ( curState == STATE_ACTIVE )
  271. {
  272. return player->GetWaterJumpTime() == 0;
  273. }
  274. else if ( player->IsObserver() )
  275. {
  276. return true;
  277. }
  278. else
  279. {
  280. return false;
  281. }
  282. }
  283. void CCSGameMovement::PlayerMove()
  284. {
  285. if ( !m_pCSPlayer->CanMove() )
  286. {
  287. mv->m_flForwardMove = 0;
  288. mv->m_flSideMove = 0;
  289. mv->m_flUpMove = 0;
  290. mv->m_nButtons &= ~(IN_JUMP | IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT);
  291. }
  292. BaseClass::PlayerMove();
  293. if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
  294. {
  295. if ( m_pCSPlayer->m_flVelocityModifier < 1.0 )
  296. {
  297. m_pCSPlayer->m_flVelocityModifier += gpGlobals->frametime / 3.0f;
  298. }
  299. if ( m_pCSPlayer->m_flVelocityModifier > 1.0 )
  300. m_pCSPlayer->m_flVelocityModifier = 1.0;
  301. }
  302. #if !defined(CLIENT_DLL)
  303. if ( m_pCSPlayer->IsAlive() )
  304. {
  305. // Check if our eye height is too close to the ceiling and lower it.
  306. // This is needed because we have taller models with the old collision bounds.
  307. const float eyeClearance = 12.0f; // eye pos must be this far below the ceiling
  308. Vector offset = player->GetViewOffset();
  309. Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
  310. vHullMin.z = 0.0f;
  311. Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
  312. Vector start = player->GetAbsOrigin();
  313. start.z += vHullMax.z;
  314. Vector end = start;
  315. end.z += eyeClearance - vHullMax.z;
  316. end.z += player->m_Local.m_bDucked ? VEC_DUCK_VIEW_SCALED( player ).z : VEC_VIEW_SCALED( player ).z;
  317. vHullMax.z = 0.0f;
  318. Vector fudge( 1, 1, 0 );
  319. vHullMin += fudge;
  320. vHullMax -= fudge;
  321. trace_t trace;
  322. Ray_t ray;
  323. ray.Init( start, end, vHullMin, vHullMax );
  324. UTIL_TraceRay( ray, PlayerSolidMask(), mv->m_nPlayerHandle.Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  325. if ( trace.fraction < 1.0f )
  326. {
  327. float est = start.z + trace.fraction * (end.z - start.z) - player->GetAbsOrigin().z - eyeClearance;
  328. if ( ( player->GetFlags() & FL_DUCKING ) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked )
  329. {
  330. offset.z = est;
  331. }
  332. else
  333. {
  334. offset.z = MIN( est, offset.z );
  335. }
  336. player->SetViewOffset( offset );
  337. }
  338. else
  339. {
  340. if ( ( player->GetFlags() & FL_DUCKING ) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked )
  341. {
  342. player->SetViewOffset( VEC_VIEW_SCALED( player ) );
  343. }
  344. else if ( m_pCSPlayer->m_duckUntilOnGround )
  345. {
  346. // Duck Hull, but we're in the air. Calculate where the view would be.
  347. Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  348. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
  349. // We've got the duck hull, pulled up to the top of where the player should be
  350. Vector lowerClearance = hullSizeNormal - hullSizeCrouch;
  351. Vector duckEyeHeight = GetPlayerViewOffset( false ) - lowerClearance;
  352. player->SetViewOffset( duckEyeHeight );
  353. }
  354. else if( player->m_Local.m_bDucked && !player->m_Local.m_bDucking )
  355. {
  356. player->SetViewOffset( VEC_DUCK_VIEW );
  357. }
  358. }
  359. }
  360. #endif
  361. }
  362. void CCSGameMovement::WalkMove( void )
  363. {
  364. if ( m_pCSPlayer->m_flStamina > 0 )
  365. {
  366. float flRatio;
  367. flRatio = ( STAMINA_MAX - ( ( m_pCSPlayer->m_flStamina / 1000.0 ) * STAMINA_RECOVER_RATE ) ) / STAMINA_MAX;
  368. // This Goldsrc code was run with variable timesteps and it had framerate dependencies.
  369. // People looking at Goldsrc for reference are usually
  370. // (these days) measuring the stoppage at 60fps or greater, so we need
  371. // to account for the fact that Goldsrc was applying more stopping power
  372. // since it applied the slowdown across more frames.
  373. float flReferenceFrametime = 1.0f / 70.0f;
  374. float flFrametimeRatio = gpGlobals->frametime / flReferenceFrametime;
  375. flRatio = pow( flRatio, flFrametimeRatio );
  376. mv->m_vecVelocity.x *= flRatio;
  377. mv->m_vecVelocity.y *= flRatio;
  378. }
  379. BaseClass::WalkMove();
  380. CheckForLadders( player->GetGroundEntity() != NULL );
  381. }
  382. //-------------------------------------------------------------------------------------------------------------------------------
  383. void CCSGameMovement::AirMove( void )
  384. {
  385. BaseClass::AirMove();
  386. CheckForLadders( false );
  387. }
  388. //-------------------------------------------------------------------------------------------------------------------------------
  389. bool CCSGameMovement::OnLadder( trace_t &trace )
  390. {
  391. if ( trace.plane.normal.z == 1.0f )
  392. return false;
  393. return BaseClass::OnLadder( trace );
  394. }
  395. //-------------------------------------------------------------------------------------------------------------------------------
  396. bool CCSGameMovement::LadderMove( void )
  397. {
  398. bool isOnLadder = BaseClass::LadderMove();
  399. if ( isOnLadder && m_pCSPlayer )
  400. {
  401. m_pCSPlayer->SurpressLadderChecks( mv->GetAbsOrigin(), m_pCSPlayer->m_vecLadderNormal );
  402. }
  403. return isOnLadder;
  404. }
  405. //-------------------------------------------------------------------------------------------------------------------------------
  406. /**
  407. * In CS, crouching up ladders goes slowly and doesn't make a sound.
  408. */
  409. float CCSGameMovement::ClimbSpeed( void ) const
  410. {
  411. if ( mv->m_nButtons & IN_DUCK )
  412. {
  413. return BaseClass::ClimbSpeed() * CS_PLAYER_SPEED_CLIMB_MODIFIER;
  414. }
  415. else
  416. {
  417. return BaseClass::ClimbSpeed();
  418. }
  419. }
  420. //-------------------------------------------------------------------------------------------------------------------------------
  421. /**
  422. * In CS, strafing on ladders goes slowly.
  423. */
  424. float CCSGameMovement::LadderLateralMultiplier( void ) const
  425. {
  426. if ( mv->m_nButtons & IN_DUCK )
  427. {
  428. return 1.0f;
  429. }
  430. else
  431. {
  432. return 0.5f;
  433. }
  434. }
  435. //-------------------------------------------------------------------------------------------------------------------------------
  436. /**
  437. * Looks behind and beneath the player in the air, in case he skips out over the top of a ladder. If the
  438. * trace hits a ladder, the player is snapped to the ladder.
  439. */
  440. void CCSGameMovement::CheckForLadders( bool wasOnGround )
  441. {
  442. if ( !wasOnGround )
  443. {
  444. // If we're higher than the last place we were on the ground, bail - obviously we're not dropping
  445. // past a ladder we might want to grab.
  446. if ( mv->GetAbsOrigin().z > m_pCSPlayer->m_lastStandingPos.z )
  447. return;
  448. Vector dir = -m_pCSPlayer->m_lastStandingPos + mv->GetAbsOrigin();
  449. if ( !dir.x && !dir.y )
  450. {
  451. // If we're dropping straight down, we don't know which way to look for a ladder. Oh well.
  452. return;
  453. }
  454. dir.z = 0.0f;
  455. float dist = dir.NormalizeInPlace();
  456. if ( dist > 64.0f )
  457. {
  458. // Don't grab ladders too far behind us.
  459. return;
  460. }
  461. trace_t trace;
  462. TracePlayerBBox(
  463. mv->GetAbsOrigin(),
  464. m_pCSPlayer->m_lastStandingPos - dir*(5+dist),
  465. (PlayerSolidMask() & (~CONTENTS_PLAYERCLIP)), COLLISION_GROUP_PLAYER_MOVEMENT, trace );
  466. if ( trace.fraction != 1.0f && OnLadder( trace ) && trace.plane.normal.z != 1.0f )
  467. {
  468. if ( m_pCSPlayer->CanGrabLadder( trace.endpos, trace.plane.normal ) )
  469. {
  470. player->SetMoveType( MOVETYPE_LADDER );
  471. player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
  472. player->SetLadderNormal( trace.plane.normal );
  473. mv->m_vecVelocity.Init();
  474. // The ladder check ignored playerclips, to fix a bug exposed by de_train, where a clipbrush is
  475. // flush with a ladder. This causes the above tracehull to fail unless we ignore playerclips.
  476. // However, we have to check for playerclips before we snap to that pos, so we don't warp a
  477. // player into a clipbrush.
  478. TracePlayerBBox(
  479. mv->GetAbsOrigin(),
  480. m_pCSPlayer->m_lastStandingPos - dir*(5+dist),
  481. PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace );
  482. mv->SetAbsOrigin( trace.endpos );
  483. }
  484. }
  485. }
  486. else
  487. {
  488. m_pCSPlayer->m_lastStandingPos = mv->GetAbsOrigin();
  489. }
  490. }
  491. void CCSGameMovement::ReduceTimers( void )
  492. {
  493. float frame_msec = 1000.0f * gpGlobals->frametime;
  494. if ( m_pCSPlayer->m_flStamina > 0 )
  495. {
  496. m_pCSPlayer->m_flStamina -= frame_msec;
  497. if ( m_pCSPlayer->m_flStamina < 0 )
  498. {
  499. m_pCSPlayer->m_flStamina = 0;
  500. }
  501. }
  502. BaseClass::ReduceTimers();
  503. }
  504. ConVar sv_enablebunnyhopping( "sv_enablebunnyhopping", "0", FCVAR_REPLICATED | FCVAR_NOTIFY );
  505. // Only allow bunny jumping up to 1.1x server / player maxspeed setting
  506. #define BUNNYJUMP_MAX_SPEED_FACTOR 1.1f
  507. // taken from TF2 but changed BUNNYJUMP_MAX_SPEED_FACTOR from 1.1 to 1.0
  508. void CCSGameMovement::PreventBunnyJumping()
  509. {
  510. // Speed at which bunny jumping is limited
  511. float maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * player->m_flMaxspeed;
  512. if ( maxscaledspeed <= 0.0f )
  513. return;
  514. // Current player speed
  515. float spd = mv->m_vecVelocity.Length();
  516. if ( spd <= maxscaledspeed )
  517. return;
  518. // Apply this cropping fraction to velocity
  519. float fraction = ( maxscaledspeed / spd );
  520. mv->m_vecVelocity *= fraction;
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose:
  524. //-----------------------------------------------------------------------------
  525. bool CCSGameMovement::CheckJumpButton( void )
  526. {
  527. if (m_pCSPlayer->pl.deadflag)
  528. {
  529. mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
  530. return false;
  531. }
  532. // See if we are waterjumping. If so, decrement count and return.
  533. if (m_pCSPlayer->m_flWaterJumpTime)
  534. {
  535. m_pCSPlayer->m_flWaterJumpTime -= gpGlobals->frametime;
  536. if (m_pCSPlayer->m_flWaterJumpTime < 0)
  537. m_pCSPlayer->m_flWaterJumpTime = 0;
  538. return false;
  539. }
  540. // If we are in the water most of the way...
  541. if ( m_pCSPlayer->GetWaterLevel() >= 2 )
  542. {
  543. // swimming, not jumping
  544. SetGroundEntity( NULL );
  545. if(m_pCSPlayer->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
  546. mv->m_vecVelocity[2] = 100;
  547. else if (m_pCSPlayer->GetWaterType() == CONTENTS_SLIME)
  548. mv->m_vecVelocity[2] = 80;
  549. // play swiming sound
  550. if ( m_pCSPlayer->m_flSwimSoundTime <= 0 )
  551. {
  552. // Don't play sound again for 1 second
  553. m_pCSPlayer->m_flSwimSoundTime = 1000;
  554. PlaySwimSound();
  555. }
  556. return false;
  557. }
  558. // No more effect
  559. if (m_pCSPlayer->GetGroundEntity() == NULL)
  560. {
  561. mv->m_nOldButtons |= IN_JUMP;
  562. return false; // in air, so no effect
  563. }
  564. if ( mv->m_nOldButtons & IN_JUMP )
  565. return false; // don't pogo stick
  566. if ( !sv_enablebunnyhopping.GetBool() )
  567. {
  568. PreventBunnyJumping();
  569. }
  570. // In the air now.
  571. SetGroundEntity( NULL );
  572. m_pCSPlayer->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->m_pSurfaceData, 1.0, true );
  573. //MoveHelper()->PlayerSetAnimation( PLAYER_JUMP );
  574. m_pCSPlayer->DoAnimationEvent( PLAYERANIMEVENT_JUMP );
  575. float flGroundFactor = 1.0f;
  576. if (player->m_pSurfaceData)
  577. {
  578. flGroundFactor = player->m_pSurfaceData->game.jumpFactor;
  579. }
  580. // if we weren't ducking, bots and hostages do a crouchjump programatically
  581. if ( (!player || player->IsBot()) && !(mv->m_nButtons & IN_DUCK) )
  582. {
  583. m_pCSPlayer->m_duckUntilOnGround = true;
  584. FinishDuck();
  585. }
  586. // Acclerate upward
  587. // If we are ducking...
  588. float startz = mv->m_vecVelocity[2];
  589. if ( m_pCSPlayer->m_duckUntilOnGround || ( m_pCSPlayer->m_Local.m_bDucking ) || ( m_pCSPlayer->GetFlags() & FL_DUCKING ) )
  590. {
  591. // d = 0.5 * g * t^2 - distance traveled with linear accel
  592. // t = sqrt(2.0 * 45 / g) - how long to fall 45 units
  593. // v = g * t - velocity at the end (just invert it to jump up that high)
  594. // v = g * sqrt(2.0 * 45 / g )
  595. // v^2 = g * g * 2.0 * 45 / g
  596. // v = sqrt( g * 2.0 * 45 )
  597. mv->m_vecVelocity[2] = flGroundFactor * sqrt(2 * 800 * 57.0); // 2 * gravity * height
  598. }
  599. else
  600. {
  601. mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * 57.0); // 2 * gravity * height
  602. }
  603. if ( m_pCSPlayer->m_flStamina > 0 )
  604. {
  605. float flRatio;
  606. flRatio = ( STAMINA_MAX - ( ( m_pCSPlayer->m_flStamina / 1000.0 ) * STAMINA_RECOVER_RATE ) ) / STAMINA_MAX;
  607. mv->m_vecVelocity[2] *= flRatio;
  608. }
  609. m_pCSPlayer->m_flStamina = ( STAMINA_COST_JUMP / STAMINA_RECOVER_RATE ) * 1000.0;
  610. FinishGravity();
  611. mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz;
  612. mv->m_outStepHeight += 0.1f;
  613. OnJump(mv->m_outWishVel.z);
  614. #ifndef CLIENT_DLL
  615. // allow bots to react
  616. IGameEvent * event = gameeventmanager->CreateEvent( "player_jump" );
  617. if ( event )
  618. {
  619. event->SetInt( "userid", m_pCSPlayer->GetUserID() );
  620. gameeventmanager->FireEvent( event );
  621. }
  622. #endif
  623. // Flag that we jumped.
  624. mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
  625. return true;
  626. }
  627. void CCSGameMovement::DecayPunchAngle( void )
  628. {
  629. float len;
  630. Vector vPunchAngle;
  631. vPunchAngle.x = m_pCSPlayer->m_Local.m_vecPunchAngle->x;
  632. vPunchAngle.y = m_pCSPlayer->m_Local.m_vecPunchAngle->y;
  633. vPunchAngle.z = m_pCSPlayer->m_Local.m_vecPunchAngle->z;
  634. len = VectorNormalize ( vPunchAngle );
  635. len -= (10.0 + len * 0.5) * gpGlobals->frametime;
  636. len = MAX( len, 0.0 );
  637. VectorScale ( vPunchAngle, len, vPunchAngle );
  638. m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 0, vPunchAngle.x );
  639. m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 1, vPunchAngle.y );
  640. m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 2, vPunchAngle.z );
  641. }
  642. void CCSGameMovement::HandleDuckingSpeedCrop()
  643. {
  644. //=============================================================================
  645. // HPE_BEGIN:
  646. // [Forrest]
  647. //=============================================================================
  648. // Movement speed in free look camera mode is unaffected by ducking state.
  649. if ( player->GetObserverMode() == OBS_MODE_ROAMING )
  650. return;
  651. //=============================================================================
  652. // HPE_END
  653. //=============================================================================
  654. if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) )
  655. {
  656. if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
  657. {
  658. mv->m_flForwardMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
  659. mv->m_flSideMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
  660. mv->m_flUpMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
  661. m_iSpeedCropped |= SPEED_CROPPED_DUCK;
  662. }
  663. }
  664. }
  665. bool CCSGameMovement::CanUnduck()
  666. {
  667. trace_t trace;
  668. Vector newOrigin;
  669. VectorCopy( mv->GetAbsOrigin(), newOrigin );
  670. if ( player->GetGroundEntity() != NULL )
  671. {
  672. newOrigin += VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  673. }
  674. else
  675. {
  676. // If in air an letting go of croush, make sure we can offset origin to make
  677. // up for uncrouching
  678. Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  679. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
  680. newOrigin += -0.5f * ( hullSizeNormal - hullSizeCrouch );
  681. }
  682. UTIL_TraceHull( mv->GetAbsOrigin(), newOrigin, VEC_HULL_MIN_SCALED( player ), VEC_HULL_MAX_SCALED( player ), PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  683. if ( trace.startsolid || ( trace.fraction != 1.0f ) )
  684. return false;
  685. return true;
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose: Stop ducking
  689. //-----------------------------------------------------------------------------
  690. void CCSGameMovement::FinishUnDuck( void )
  691. {
  692. trace_t trace;
  693. Vector newOrigin;
  694. VectorCopy( mv->GetAbsOrigin(), newOrigin );
  695. if ( player->GetGroundEntity() != NULL )
  696. {
  697. newOrigin += VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  698. }
  699. else
  700. {
  701. // If in air an letting go of croush, make sure we can offset origin to make
  702. // up for uncrouching
  703. Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  704. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
  705. Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeCrouch );
  706. VectorAdd( newOrigin, viewDelta, newOrigin );
  707. }
  708. player->m_Local.m_bDucked = false;
  709. player->RemoveFlag( FL_DUCKING );
  710. player->m_Local.m_bDucking = false;
  711. player->SetViewOffset( GetPlayerViewOffset( false ) );
  712. player->m_Local.m_flDucktime = 0;
  713. mv->SetAbsOrigin( newOrigin );
  714. // Recategorize position since ducking can change origin
  715. CategorizePosition();
  716. }
  717. //-----------------------------------------------------------------------------
  718. // Purpose: Finish ducking
  719. //-----------------------------------------------------------------------------
  720. void CCSGameMovement::FinishDuck( void )
  721. {
  722. Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  723. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
  724. Vector viewDelta = 0.5f * ( hullSizeNormal - hullSizeCrouch );
  725. player->SetViewOffset( GetPlayerViewOffset( true ) );
  726. player->AddFlag( FL_DUCKING );
  727. player->m_Local.m_bDucking = false;
  728. if ( !player->m_Local.m_bDucked )
  729. {
  730. Vector org = mv->GetAbsOrigin();
  731. if ( player->GetGroundEntity() != NULL )
  732. {
  733. org -= VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  734. }
  735. else
  736. {
  737. org += viewDelta;
  738. }
  739. mv->SetAbsOrigin( org );
  740. player->m_Local.m_bDucked = true;
  741. }
  742. // See if we are stuck?
  743. FixPlayerCrouchStuck( true );
  744. // Recategorize position since ducking can change origin
  745. CategorizePosition();
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose: See if duck button is pressed and do the appropriate things
  749. //-----------------------------------------------------------------------------
  750. void CCSGameMovement::Duck( void )
  751. {
  752. // Fix taken from zblock for rapid crouch/stand not showing stand on other clients
  753. if ( player->GetFlags() & FL_ONGROUND )
  754. {
  755. // if prevent crouch
  756. if ( !( mv->m_nButtons & IN_DUCK ) && ( mv->m_nOldButtons & IN_DUCK ) )
  757. {
  758. // Player has released crouch and moving to standing
  759. m_fTimeLastUnducked = gpGlobals->curtime;
  760. }
  761. else if ( ( mv->m_nButtons & IN_DUCK ) && !( mv->m_nOldButtons & IN_DUCK ) )
  762. {
  763. // Crouch from standing
  764. if ( ( player->GetFlags() & FL_DUCKING )
  765. && ( m_fTimeLastUnducked > (gpGlobals->curtime - sv_timebetweenducks.GetFloat() ) ) )
  766. {
  767. // if the server thinks the player is still crouched
  768. // AND the time the player started to stand (from being ducked) was less than 300ms ago
  769. // prevent the player from ducking again
  770. mv->m_nButtons &= ~IN_DUCK;
  771. }
  772. }
  773. }
  774. int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame
  775. int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed"
  776. int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released"
  777. // Check to see if we are in the air.
  778. bool bInAir = player->GetGroundEntity() == NULL && player->GetMoveType() != MOVETYPE_LADDER;
  779. if ( mv->m_nButtons & IN_DUCK )
  780. {
  781. mv->m_nOldButtons |= IN_DUCK;
  782. }
  783. else
  784. {
  785. mv->m_nOldButtons &= ~IN_DUCK;
  786. }
  787. if ( IsDead() )
  788. {
  789. // Unduck
  790. if ( player->GetFlags() & FL_DUCKING )
  791. {
  792. FinishUnDuck();
  793. }
  794. return;
  795. }
  796. HandleDuckingSpeedCrop();
  797. if ( m_pCSPlayer->m_duckUntilOnGround )
  798. {
  799. if ( !bInAir )
  800. {
  801. m_pCSPlayer->m_duckUntilOnGround = false;
  802. if ( CanUnduck() )
  803. {
  804. FinishUnDuck();
  805. }
  806. return;
  807. }
  808. else
  809. {
  810. if ( mv->m_vecVelocity.z > 0.0f )
  811. return;
  812. // Check if we can un-duck. We want to unduck if we have space for the standing hull, and
  813. // if it is less than 2 inches off the ground.
  814. trace_t trace;
  815. Vector newOrigin;
  816. Vector groundCheck;
  817. VectorCopy( mv->GetAbsOrigin(), newOrigin );
  818. Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
  819. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
  820. newOrigin -= ( hullSizeNormal - hullSizeCrouch );
  821. groundCheck = newOrigin;
  822. groundCheck.z -= player->GetStepSize();
  823. UTIL_TraceHull( newOrigin, groundCheck, VEC_HULL_MIN_SCALED( player ), VEC_HULL_MAX_SCALED( player ), PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  824. if ( trace.startsolid || trace.fraction == 1.0f )
  825. return; // Can't even stand up, or there's no ground underneath us
  826. m_pCSPlayer->m_duckUntilOnGround = false;
  827. if ( CanUnduck() )
  828. {
  829. FinishUnDuck();
  830. }
  831. return;
  832. }
  833. }
  834. // Holding duck, in process of ducking or fully ducked?
  835. if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
  836. {
  837. if ( mv->m_nButtons & IN_DUCK )
  838. {
  839. bool alreadyDucked = ( player->GetFlags() & FL_DUCKING ) ? true : false;
  840. if ( (buttonsPressed & IN_DUCK ) && !( player->GetFlags() & FL_DUCKING ) )
  841. {
  842. // Use 1 second so super long jump will work
  843. player->m_Local.m_flDucktime = 1000;
  844. player->m_Local.m_bDucking = true;
  845. }
  846. float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
  847. float duckseconds = duckmilliseconds / 1000.0f;
  848. //time = MAX( 0.0, ( 1.0 - (float)player->m_Local.m_flDucktime / 1000.0 ) );
  849. if ( player->m_Local.m_bDucking )
  850. {
  851. if ( !( player->GetFlags() & FL_ANIMDUCKING ) )
  852. player->AddFlag( FL_ANIMDUCKING );
  853. // Finish ducking immediately if duck time is over or not on ground
  854. if ( ( duckseconds > TIME_TO_DUCK ) ||
  855. ( player->GetGroundEntity() == NULL ) ||
  856. alreadyDucked)
  857. {
  858. FinishDuck();
  859. }
  860. else
  861. {
  862. // Calc parametric time
  863. float duckFraction = SimpleSpline( duckseconds / TIME_TO_DUCK );
  864. SetDuckedEyeOffset( duckFraction );
  865. }
  866. }
  867. }
  868. else
  869. {
  870. // Try to unduck unless automovement is not allowed
  871. // NOTE: When not onground, you can always unduck
  872. if ( player->m_Local.m_bAllowAutoMovement || player->GetGroundEntity() == NULL )
  873. {
  874. if ( (buttonsReleased & IN_DUCK ) && ( player->GetFlags() & FL_DUCKING ) )
  875. {
  876. // Use 1 second so super long jump will work
  877. player->m_Local.m_flDucktime = 1000;
  878. player->m_Local.m_bDucking = true; // or unducking
  879. }
  880. float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
  881. float duckseconds = duckmilliseconds / 1000.0f;
  882. if ( CanUnduck() )
  883. {
  884. if ( player->m_Local.m_bDucking ||
  885. player->m_Local.m_bDucked ) // or unducking
  886. {
  887. if ( player->GetFlags() & FL_ANIMDUCKING )
  888. player->RemoveFlag( FL_ANIMDUCKING );
  889. // Finish ducking immediately if duck time is over or not on ground
  890. if ( ( duckseconds > TIME_TO_UNDUCK ) ||
  891. ( player->GetGroundEntity() == NULL ) )
  892. {
  893. FinishUnDuck();
  894. }
  895. else
  896. {
  897. // Calc parametric time
  898. float duckFraction = SimpleSpline( 1.0f - ( duckseconds / TIME_TO_UNDUCK ) );
  899. SetDuckedEyeOffset( duckFraction );
  900. }
  901. }
  902. }
  903. else
  904. {
  905. // Still under something where we can't unduck, so make sure we reset this timer so
  906. // that we'll unduck once we exit the tunnel, etc.
  907. player->m_Local.m_flDucktime = 1000;
  908. }
  909. }
  910. }
  911. }
  912. }
  913. void CCSGameMovement::OnJump( float fImpulse )
  914. {
  915. m_pCSPlayer->OnJump( fImpulse );
  916. }
  917. void CCSGameMovement::OnLand( float fVelocity )
  918. {
  919. m_pCSPlayer->OnLand( fVelocity );
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Purpose: Essentially the same as TracePlayerBBox, but adds a callback to
  923. // exclude entities that are not standable (except for other players)
  924. //-----------------------------------------------------------------------------
  925. void CCSGameMovement::TryTouchGround( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, unsigned int fMask, int collisionGroup, trace_t& pm )
  926. {
  927. VPROF( "CCSGameMovement::TryTouchGround" );
  928. Ray_t ray;
  929. ray.Init( start, end, mins, maxs );
  930. ShouldHitFunc_t pStandingTestCallback = sv_enableboost.GetBool() ? NULL : CheckForStandable;
  931. UTIL_TraceRay( ray, fMask, mv->m_nPlayerHandle.Get(), collisionGroup, &pm, pStandingTestCallback );
  932. }