Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1467 lines
46 KiB

  1. //========= Copyright � 1996-2005, 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. #include "vguicenterprint.h"
  16. #else
  17. #include "cs_player.h"
  18. #include "keyvalues.h"
  19. #endif
  20. // NOTE: This has to be the last file included!
  21. #include "tier0/memdbgon.h"
  22. #define STAMINA_RANGE 100.0
  23. ConVar sv_staminajumpcost( "sv_staminajumpcost", ".080", FCVAR_RELEASE | FCVAR_REPLICATED, "Stamina penalty for jumping", true, 0.0, false, 0.0 );
  24. ConVar sv_staminalandcost( "sv_staminalandcost", ".050", FCVAR_RELEASE | FCVAR_REPLICATED, "Stamina penalty for landing", true, 0.0, false, 0.0 );
  25. ConVar sv_staminarecoveryrate( "sv_staminarecoveryrate", "60", FCVAR_RELEASE | FCVAR_REPLICATED, "Rate at which stamina recovers (units/sec)", true, 0.0, false, 0.0 );
  26. ConVar sv_staminamax( "sv_staminamax", "80", FCVAR_RELEASE | FCVAR_REPLICATED, "Maximum stamina penalty", true, 0.0, true, 100.0 );
  27. #define get_sv_crouch_spam_penalty 2.0f
  28. // Prevent super-fast duck-spam while in air
  29. ConVar sv_timebetweenducks( "sv_timebetweenducks", "0.4", FCVAR_REPLICATED | FCVAR_RELEASE, "Minimum time before recognizing consecutive duck key", true, 0.0, true, 2.0 );
  30. extern bool g_bMovementOptimizations;
  31. extern ConVar sv_accelerate_use_weapon_speed;
  32. extern ConVar sv_accelerate_debug_speed;
  33. #define SV_ACCELERATE_EXPONENT_TIME 0
  34. #define SV_ACCELERATE_EXPONENT 1
  35. // Not ready to ship yet... previous value was 2.0
  36. ConVar sv_extreme_strafe_accuracy_fishtail( "sv_extreme_strafe_accuracy_fishtail", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Number of degrees of aim 'fishtail' when making an extreme strafe direction change", true, -5.0, true, 5.0 );
  37. // sqrt(2 * 800 * 57) = sqrt(2 * gravity * height)
  38. ConVar sv_jump_impulse( "sv_jump_impulse", "301.993377", FCVAR_REPLICATED | FCVAR_RELEASE, "Initial upward velocity for player jumps; sqrt(2*gravity*height).", true, 0.0f, false, 0.0f );
  39. class CCSGameMovement : public CGameMovement
  40. {
  41. public:
  42. DECLARE_CLASS( CCSGameMovement, CGameMovement );
  43. CCSGameMovement();
  44. virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
  45. virtual bool CanAccelerate();
  46. virtual bool CheckJumpButton( void );
  47. virtual void PreventBunnyJumping( void );
  48. virtual void ReduceTimers( void );
  49. virtual void WalkMove( void );
  50. virtual void AirMove( void );
  51. virtual bool LadderMove( void );
  52. virtual void DecayAimPunchAngle( void );
  53. virtual void CheckParameters( void );
  54. // allow overridden versions to respond to jumping
  55. virtual void OnJump( float fImpulse );
  56. virtual void OnLand( float fVelocity );
  57. // Ducking
  58. virtual void Duck( void );
  59. virtual void FinishUnDuck( void );
  60. virtual void FinishDuck( void );
  61. virtual bool CanUnduck();
  62. virtual void Accelerate( Vector& wishdir, float wishspeed, float accel);
  63. virtual bool OnLadder( trace_t &trace );
  64. virtual float LadderDistance( void ) const
  65. {
  66. if ( player->GetMoveType() == MOVETYPE_LADDER )
  67. return 10.0f;
  68. return 2.0f;
  69. }
  70. virtual unsigned int LadderMask( void ) const
  71. {
  72. return MASK_PLAYERSOLID & ( ~CONTENTS_PLAYERCLIP );
  73. }
  74. virtual float ClimbSpeed( void ) const;
  75. virtual float LadderLateralMultiplier( void ) const;
  76. protected:
  77. virtual void PlayerMove();
  78. virtual unsigned int PlayerSolidMask( bool brushOnly = false, CBasePlayer *testPlayer = NULL ) const; ///< returns the solid mask for the given player, so bots can have a more-restrictive set
  79. public:
  80. CCSPlayer *m_pCSPlayer;
  81. private:
  82. void HandleDuckingSpeedCrop( float duckFraction );
  83. inline float GetDuckSpeedModifier( float duckFraction ) const { return CS_PLAYER_SPEED_DUCK_MODIFIER * duckFraction + 1.0f - duckFraction; }
  84. bool DuckingEnabled();
  85. };
  86. // Expose our interface.
  87. static CCSGameMovement g_GameMovement;
  88. IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
  89. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
  90. // ---------------------------------------------------------------------------------------- //
  91. // CCSGameMovement.
  92. // ---------------------------------------------------------------------------------------- //
  93. CCSGameMovement::CCSGameMovement()
  94. {
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose: Allow bots etc to use slightly different solid masks
  98. //-----------------------------------------------------------------------------
  99. unsigned int CCSGameMovement::PlayerSolidMask( bool brushOnly, CBasePlayer *testPlayer ) const
  100. {
  101. bool isBot = !player || player->IsBot();
  102. unsigned int uMask = MASK_PLAYERSOLID_BRUSHONLY;
  103. if ( !brushOnly )
  104. {
  105. uMask = player->PhysicsSolidMaskForEntity();
  106. }
  107. if ( isBot )
  108. {
  109. uMask |= CONTENTS_MONSTERCLIP;
  110. }
  111. return uMask;
  112. }
  113. bool CCSGameMovement::DuckingEnabled()
  114. {
  115. // Anti-duck-spam: If mashing duck key too much, treat as unpressed to avoid being
  116. // able to "camp" in half-ducked positions by pressing/releasing near a target height.
  117. if ( m_pCSPlayer->m_flDuckSpeed < 1.5f )
  118. return false;
  119. // After completing a duck/unduck, we can't re-duck for a minimum amount of time.
  120. // This is to minimize ugly camera shaking due to immediate duck/un-duck in the air.
  121. // before the above anti-spam code kicks in.
  122. if ( ( player->GetFlags() & FL_DUCKING ) == 0
  123. && gpGlobals->curtime < player->m_Local.m_flLastDuckTime + sv_timebetweenducks.GetFloat() )
  124. return false;
  125. return true;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose:
  129. //-----------------------------------------------------------------------------
  130. void CCSGameMovement::CheckParameters( void )
  131. {
  132. // HACK: IN_BULLRUSH isn't used anywhere. We use it to store the "raw" value of whether
  133. // IN_DUCK was held, before it is modified by code. This way when m_nButtons is
  134. // copied to m_nOldButtons we can tell if duck was pressed or released on the next
  135. // frame.
  136. #define IN_RAWDUCK IN_BULLRUSH
  137. QAngle v_angle;
  138. // Save off state of IN_DUCK before we set/unset it from gameplay effects
  139. if ( ( mv->m_nButtons & IN_DUCK ) != 0 )
  140. mv->m_nButtons |= IN_RAWDUCK;
  141. // Add duck-spam speed penalty when we press or release the duck key.
  142. // (this is the only place that IN_RAWDUCK is checked)
  143. if ( ( mv->m_nButtons & IN_RAWDUCK ) != ( mv->m_nOldButtons & IN_RAWDUCK ) )
  144. {
  145. player->m_flDuckSpeed = MAX( 0, player->m_flDuckSpeed - get_sv_crouch_spam_penalty );
  146. }
  147. // Cancel auto-duck if player hits +duck, so cancel our auto duck
  148. // Note: only bots use m_duckUntilOnGround
  149. if ( m_pCSPlayer->m_duckUntilOnGround && ( mv->m_nButtons & IN_DUCK ) )
  150. {
  151. m_pCSPlayer->m_duckUntilOnGround = false;
  152. }
  153. // Anti-duck-spam: If mashing duck key too much, treat as unpressed to avoid being
  154. // able to "camp" in half-ducked positions by pressing/releasing near a target height.
  155. if ( !DuckingEnabled() )
  156. {
  157. mv->m_nButtons &= ~IN_DUCK;
  158. }
  159. // maintaining auto-duck during jumps
  160. // Note: only bots use m_duckUntilOnGround
  161. if ( m_pCSPlayer->m_duckUntilOnGround && !player->GetGroundEntity() && player->GetMoveType() != MOVETYPE_LADDER )
  162. {
  163. mv->m_nButtons |= IN_DUCK;
  164. }
  165. // Always duck during bomb-plant animation
  166. if ( m_pCSPlayer->m_bDuckOverride )
  167. {
  168. mv->m_nButtons |= IN_DUCK;
  169. }
  170. // it would be nice to put this into the player->GetPlayerMaxSpeed() method, but
  171. // this flag is only stored in the move!
  172. bool walkButtonIsDown = ( mv->m_nButtons & ( /*IN_WALK | */ IN_SPEED ) ) != 0;
  173. bool runButtonIsDown = ( mv->m_nButtons & ( IN_FORWARD | IN_BACK | IN_MOVERIGHT | IN_MOVELEFT | IN_RUN) ) != 0;
  174. bool moveForward = ( mv->m_nButtons & ( IN_FORWARD ) ) != 0;
  175. bool moveBackward = ( mv->m_nButtons & ( IN_BACK ) ) != 0;
  176. bool moveRight = ( mv->m_nButtons & ( IN_MOVERIGHT ) ) != 0;
  177. bool moveLeft = ( mv->m_nButtons & ( IN_MOVELEFT ) ) != 0;
  178. bool opposingForwardBack = ( moveForward && moveBackward );
  179. bool opposingRightLeft = ( moveRight && moveLeft );
  180. // NOTE[pmf] ignore the walk button when we're ducking; this test matches that in CCSGameMovement::HandleDuckingSpeedCrop()
  181. // we can't simply test mv->m_iSpeedCropped == SPEED_CROPPED_DUCK, because that is set AFTER this code executes
  182. if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
  183. {
  184. walkButtonIsDown = false;
  185. }
  186. if ( walkButtonIsDown )
  187. {
  188. // we don't cap walk immediately, let the player decelerate and only cap when the speed is really close
  189. float currentspeed = m_pCSPlayer->GetLocalVelocity( ).Length( );
  190. if ( currentspeed < ( ( mv->m_flMaxSpeed * CS_PLAYER_SPEED_WALK_MODIFIER ) + 25 ) )
  191. {
  192. mv->m_flMaxSpeed *= CS_PLAYER_SPEED_WALK_MODIFIER;
  193. m_pCSPlayer->m_bIsWalking = true;
  194. }
  195. }
  196. else
  197. {
  198. m_pCSPlayer->m_bIsWalking = false;
  199. }
  200. float speed_squared = 0.0f;
  201. if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
  202. player->GetMoveType() != MOVETYPE_NOCLIP &&
  203. player->GetMoveType() != MOVETYPE_OBSERVER )
  204. {
  205. speed_squared = ( mv->m_flForwardMove * mv->m_flForwardMove ) +
  206. ( mv->m_flSideMove * mv->m_flSideMove ) +
  207. ( mv->m_flUpMove * mv->m_flUpMove );
  208. // Slow down by the speed factor
  209. float flSpeedFactor = 1.0f;
  210. if (player->m_pSurfaceData)
  211. {
  212. flSpeedFactor = player->m_pSurfaceData->game.maxSpeedFactor;
  213. }
  214. // If we have a constraint, slow down because of that too.
  215. float flConstraintSpeedFactor = ComputeConstraintSpeedFactor();
  216. if (flConstraintSpeedFactor < flSpeedFactor)
  217. flSpeedFactor = flConstraintSpeedFactor;
  218. // Take the player's velocity modifier into account
  219. if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
  220. {
  221. flSpeedFactor *= m_pCSPlayer->m_flVelocityModifier;
  222. }
  223. mv->m_flMaxSpeed *= flSpeedFactor;
  224. // stamina slowing factor
  225. if ( m_pCSPlayer->m_flStamina > 0 )
  226. {
  227. float fSpeedScale = clamp(1.0f - m_pCSPlayer->m_flStamina / STAMINA_RANGE, 0.f, 1.f);
  228. fSpeedScale *= fSpeedScale; // square the scale factor so that it correlates more closely with the jump penalty (i.e. a 50% stamina jumps .25 * normal height)
  229. mv->m_flMaxSpeed *= fSpeedScale;
  230. }
  231. if ( g_bMovementOptimizations )
  232. {
  233. // Same thing but only do the sqrt if we have to.
  234. if ( ( speed_squared != 0.0 ) && ( speed_squared > mv->m_flMaxSpeed*mv->m_flMaxSpeed ) )
  235. {
  236. float fRatio = mv->m_flMaxSpeed / sqrt( speed_squared );
  237. mv->m_flForwardMove *= fRatio;
  238. mv->m_flSideMove *= fRatio;
  239. mv->m_flUpMove *= fRatio;
  240. }
  241. }
  242. else
  243. {
  244. float spd = sqrt( speed_squared );
  245. if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed ) )
  246. {
  247. float fRatio = mv->m_flMaxSpeed / spd;
  248. mv->m_flForwardMove *= fRatio;
  249. mv->m_flSideMove *= fRatio;
  250. mv->m_flUpMove *= fRatio;
  251. }
  252. }
  253. }
  254. if ( player->GetFlags() & FL_FROZEN ||
  255. player->GetFlags() & FL_ONTRAIN ||
  256. IsDead() )
  257. {
  258. if ( player->GetObserverMode() != OBS_MODE_ROAMING )
  259. {
  260. mv->m_flForwardMove = 0;
  261. mv->m_flSideMove = 0;
  262. mv->m_flUpMove = 0;
  263. }
  264. }
  265. DecayViewPunchAngle();
  266. DecayAimPunchAngle();
  267. // Take angles from command.
  268. if ( !IsDead() )
  269. {
  270. v_angle = mv->m_vecAngles;
  271. v_angle = v_angle + player->m_Local.m_viewPunchAngle;
  272. // Now adjust roll angle
  273. if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
  274. player->GetMoveType() != MOVETYPE_NOCLIP )
  275. {
  276. mv->m_vecAngles[ROLL] = CalcRoll( v_angle, mv->m_vecVelocity, sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
  277. }
  278. else
  279. {
  280. mv->m_vecAngles[ROLL] = 0.0; // v_angle[ ROLL ];
  281. }
  282. mv->m_vecAngles[PITCH] = v_angle[PITCH];
  283. mv->m_vecAngles[YAW] = v_angle[YAW];
  284. }
  285. else
  286. {
  287. mv->m_vecAngles = mv->m_vecOldAngles;
  288. }
  289. // Set dead player view_offset
  290. if ( IsDead() &&
  291. player->GetObserverMode() == OBS_MODE_DEATHCAM )
  292. {
  293. player->SetViewOffset( VEC_DEAD_VIEWHEIGHT );
  294. }
  295. // Adjust client view angles to match values used on server.
  296. mv->m_vecAngles[YAW] = AngleNormalize( mv->m_vecAngles[YAW] );
  297. // If we're standing on a player, then force them off.
  298. if ( !player->IsObserver() && ( player->GetMoveType() != MOVETYPE_LADDER ) )
  299. {
  300. int nLevels = 0;
  301. CBaseEntity *pCurGround = player->GetGroundEntity();
  302. while ( pCurGround && pCurGround->IsPlayer() && nLevels < 1000 )
  303. {
  304. pCurGround = pCurGround->GetGroundEntity();
  305. ++nLevels;
  306. }
  307. if ( nLevels == 1000 )
  308. Warning( "BUG: CCSGameMovement::CheckParameters - too many stacking levels.\n" );
  309. // If they're stacked too many levels deep, slide them off.
  310. if ( nLevels > 1 )
  311. {
  312. mv->m_flForwardMove = mv->m_flMaxSpeed * 3;
  313. mv->m_flSideMove = 0;
  314. mv->m_nButtons = 0;
  315. mv->m_nImpulseCommand = 0;
  316. }
  317. }
  318. // Determine if the player is trying to run / move at full speed.
  319. m_pCSPlayer->m_iMoveState = MOVESTATE_IDLE; // idle, not driving the character
  320. if ( runButtonIsDown )
  321. {
  322. if ( opposingForwardBack && opposingRightLeft )
  323. {
  324. m_pCSPlayer->m_iMoveState = MOVESTATE_IDLE; // Idle, don't move if we are holding all 4 directions down.
  325. }
  326. else if ( opposingForwardBack || opposingRightLeft )
  327. {
  328. if ( ( opposingForwardBack && ( moveRight || moveLeft ) ) || ( opposingRightLeft && ( moveForward || moveBackward ) ) )
  329. {
  330. m_pCSPlayer->m_iMoveState = MOVESTATE_RUN; // Run, move if we are holding 3 buttons down, 2 are opposing directions.
  331. }
  332. else
  333. {
  334. m_pCSPlayer->m_iMoveState = MOVESTATE_IDLE; // Idle, don't move if we are holding just 2 opposing directions down.
  335. }
  336. }
  337. else
  338. {
  339. m_pCSPlayer->m_iMoveState = MOVESTATE_RUN; // Run
  340. }
  341. }
  342. if ( ( m_pCSPlayer->m_iMoveState == MOVESTATE_RUN ) && walkButtonIsDown )
  343. {
  344. m_pCSPlayer->m_iMoveState = MOVESTATE_WALK; // Walk
  345. }
  346. }
  347. void CCSGameMovement::ProcessMovement( CBasePlayer *pBasePlayer, CMoveData *pMove )
  348. {
  349. m_pCSPlayer = static_cast<CCSPlayer *>( pBasePlayer );
  350. if ( m_pCSPlayer->IsBot() && m_pCSPlayer->IsDormant() )
  351. return;
  352. BaseClass::ProcessMovement( pBasePlayer, pMove );
  353. }
  354. bool CCSGameMovement::CanAccelerate()
  355. {
  356. // Only allow the player to accelerate when in certain states.
  357. CSPlayerState curState = m_pCSPlayer->State_Get();
  358. if ( curState == STATE_ACTIVE )
  359. {
  360. return player->GetWaterJumpTime() == 0;
  361. }
  362. else if ( player->IsObserver() )
  363. {
  364. return true;
  365. }
  366. else
  367. {
  368. return false;
  369. }
  370. }
  371. void CCSGameMovement::PlayerMove()
  372. {
  373. if ( !m_pCSPlayer->CanMove() )
  374. {
  375. mv->m_flForwardMove = 0;
  376. mv->m_flSideMove = 0;
  377. mv->m_flUpMove = 0;
  378. mv->m_nButtons &= ~(IN_JUMP | IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT);
  379. }
  380. BaseClass::PlayerMove();
  381. if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
  382. {
  383. const float kVelocityRecoveryRate = 1.f / 2.5f;
  384. if ( m_pCSPlayer->m_flVelocityModifier < 1.0 )
  385. {
  386. m_pCSPlayer->m_flVelocityModifier = clamp(m_pCSPlayer->m_flVelocityModifier + gpGlobals->frametime * kVelocityRecoveryRate, 0.0f, 1.0f);
  387. }
  388. }
  389. #if !defined(CLIENT_DLL)
  390. if( player &&
  391. player->GetTeamNumber() == TEAM_SPECTATOR &&
  392. player->GetObserverMode() == OBS_MODE_FIXED )
  393. {
  394. // [dkorus] if we're using a fixed view mode when spectating, we need to make sure we bump the camera up off the ground
  395. player->SetViewOffset( VEC_VIEW );
  396. }
  397. if ( m_pCSPlayer->IsAlive() )
  398. {
  399. if ( ( player->GetFlags() & FL_DUCKING ) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked )
  400. {
  401. player->SetViewOffset( VEC_VIEW );
  402. }
  403. else if ( m_pCSPlayer->m_duckUntilOnGround )
  404. {
  405. // Duck Hull, but we're in the air. Calculate where the view would be.
  406. Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
  407. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
  408. // We've got the duck hull, pulled up to the top of where the player should be
  409. Vector lowerClearance = hullSizeNormal - hullSizeCrouch;
  410. Vector duckEyeHeight = GetPlayerViewOffset( false ) - lowerClearance;
  411. player->SetViewOffset( duckEyeHeight );
  412. }
  413. else if( player->m_Local.m_bDucked && !player->m_Local.m_bDucking )
  414. {
  415. player->SetViewOffset( VEC_DUCK_VIEW );
  416. }
  417. }
  418. if ( !m_pCSPlayer->m_bHasMovedSinceSpawn && Vector2DLength( mv->m_vecVelocity.AsVector2D() ) != 0 )
  419. m_pCSPlayer->m_bHasMovedSinceSpawn = true;
  420. #endif
  421. }
  422. void CCSGameMovement::WalkMove( void )
  423. {
  424. BaseClass::WalkMove();
  425. }
  426. //-------------------------------------------------------------------------------------------------------------------------------
  427. void CCSGameMovement::AirMove( void )
  428. {
  429. BaseClass::AirMove();
  430. }
  431. //-------------------------------------------------------------------------------------------------------------------------------
  432. bool CCSGameMovement::OnLadder( trace_t &trace )
  433. {
  434. if ( trace.plane.normal.z == 1.0f )
  435. return false;
  436. return BaseClass::OnLadder( trace );
  437. }
  438. //-------------------------------------------------------------------------------------------------------------------------------
  439. bool CCSGameMovement::LadderMove( void )
  440. {
  441. bool isOnLadder = BaseClass::LadderMove();
  442. if ( isOnLadder && m_pCSPlayer )
  443. {
  444. m_pCSPlayer->SurpressLadderChecks( mv->GetAbsOrigin(), m_pCSPlayer->m_vecLadderNormal );
  445. }
  446. return isOnLadder;
  447. }
  448. //-------------------------------------------------------------------------------------------------------------------------------
  449. /**
  450. * In CS, crouching or walking up ladders goes slowly and shouldn't make a sound.
  451. */
  452. float CCSGameMovement::ClimbSpeed( void ) const
  453. {
  454. if ( ( mv->m_nButtons & IN_DUCK ) || ( mv->m_nButtons & IN_SPEED ) )
  455. {
  456. return BaseClass::ClimbSpeed() * CS_PLAYER_SPEED_CLIMB_MODIFIER;
  457. }
  458. else
  459. {
  460. return BaseClass::ClimbSpeed();
  461. }
  462. }
  463. //-------------------------------------------------------------------------------------------------------------------------------
  464. /**
  465. * In CS, strafing on ladders goes slowly.
  466. */
  467. float CCSGameMovement::LadderLateralMultiplier( void ) const
  468. {
  469. if ( mv->m_nButtons & IN_DUCK )
  470. {
  471. return 1.0f;
  472. }
  473. else
  474. {
  475. return 0.5f;
  476. }
  477. }
  478. void CCSGameMovement::ReduceTimers( void )
  479. {
  480. if ( m_pCSPlayer->m_flStamina > 0 )
  481. {
  482. m_pCSPlayer->m_flStamina -= gpGlobals->frametime * sv_staminarecoveryrate.GetFloat();
  483. if ( m_pCSPlayer->m_flStamina < 0 )
  484. {
  485. m_pCSPlayer->m_flStamina = 0;
  486. }
  487. }
  488. BaseClass::ReduceTimers();
  489. }
  490. ConVar sv_enablebunnyhopping( "sv_enablebunnyhopping", "0", FCVAR_RELEASE | FCVAR_REPLICATED, "Allow player speed to exceed maximum running speed" );
  491. ConVar sv_autobunnyhopping( "sv_autobunnyhopping", "0", FCVAR_RELEASE | FCVAR_REPLICATED, "Players automatically re-jump while holding jump button" );
  492. // Only allow bunny jumping up to 1.1x server / player maxspeed setting
  493. #define BUNNYJUMP_MAX_SPEED_FACTOR 1.1f
  494. // taken from TF2 but changed BUNNYJUMP_MAX_SPEED_FACTOR from 1.1 to 1.0
  495. void CCSGameMovement::PreventBunnyJumping()
  496. {
  497. // Speed at which bunny jumping is limited
  498. float maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * player->m_flMaxspeed;
  499. if ( maxscaledspeed <= 0.0f )
  500. return;
  501. // Current player speed
  502. float spd = mv->m_vecVelocity.Length();
  503. if ( spd <= maxscaledspeed )
  504. return;
  505. // Apply this cropping fraction to velocity
  506. float fraction = ( maxscaledspeed / spd );
  507. mv->m_vecVelocity *= fraction;
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose:
  511. //-----------------------------------------------------------------------------
  512. bool CCSGameMovement::CheckJumpButton( void )
  513. {
  514. if (m_pCSPlayer->pl.deadflag)
  515. {
  516. mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
  517. return false;
  518. }
  519. // See if we are waterjumping. If so, decrement count and return.
  520. if (m_pCSPlayer->m_flWaterJumpTime)
  521. {
  522. m_pCSPlayer->m_flWaterJumpTime -= gpGlobals->frametime;
  523. if (m_pCSPlayer->m_flWaterJumpTime < 0)
  524. m_pCSPlayer->m_flWaterJumpTime = 0;
  525. return false;
  526. }
  527. // Can't jump while in a thirdperson taunt
  528. if ( m_pCSPlayer->IsTaunting() && m_pCSPlayer->IsThirdPersonTaunt() )
  529. return false;
  530. //#if !defined(CLIENT_DLL)
  531. // if ( m_pCSPlayer->IsTaunting() )
  532. // {
  533. // // They jumped so break out of the taunt!
  534. // m_pCSPlayer->StopTaunting();
  535. // }
  536. //#endif
  537. // If we are in the water most of the way...
  538. if ( m_pCSPlayer->GetWaterLevel() >= WL_Waist )
  539. {
  540. // swimming, not jumping
  541. SetGroundEntity( NULL );
  542. if(m_pCSPlayer->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
  543. mv->m_vecVelocity[2] = 100;
  544. else if (m_pCSPlayer->GetWaterType() == CONTENTS_SLIME)
  545. mv->m_vecVelocity[2] = 80;
  546. // play swiming sound
  547. if ( m_pCSPlayer->m_flSwimSoundTime <= 0 )
  548. {
  549. // Don't play sound again for 1 second
  550. m_pCSPlayer->m_flSwimSoundTime = 1000;
  551. PlaySwimSound();
  552. }
  553. return false;
  554. }
  555. // are we jumping on another player's head?
  556. bool bStandingOnOtherPlayer = false;
  557. bool bStandingOnFallingPlayer = false;
  558. CBaseEntity *groundEntity = m_pCSPlayer->GetGroundEntity();
  559. if ( groundEntity && !groundEntity->IsWorld() && groundEntity->IsPlayer() )
  560. {
  561. bStandingOnOtherPlayer = true;
  562. if ( groundEntity->GetGroundEntity() == NULL )
  563. {
  564. bStandingOnFallingPlayer = true;
  565. }
  566. }
  567. // the player jumped so this bool will remain false until the player next walks
  568. player->m_bHasWalkMovedSinceLastJump = false;
  569. // No more effect
  570. if (m_pCSPlayer->GetGroundEntity() == NULL)
  571. {
  572. mv->m_nOldButtons |= IN_JUMP;
  573. return false; // in air, so no effect
  574. }
  575. if ( ( mv->m_nOldButtons & IN_JUMP ) != 0 && !sv_autobunnyhopping.GetBool() )
  576. return false; // don't pogo stick
  577. if ( !sv_enablebunnyhopping.GetBool() )
  578. {
  579. PreventBunnyJumping();
  580. }
  581. // In the air now.
  582. SetGroundEntity( NULL );
  583. // if we're walking or standing still, play only a local sounds
  584. if ( mv->m_vecVelocity.Length() > 126 )
  585. {
  586. m_pCSPlayer->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->m_pSurfaceData, 1.0, true );
  587. }
  588. #ifdef CLIENT_DLL
  589. m_pCSPlayer->PlayClientJumpSound();
  590. #endif
  591. //MoveHelper()->PlayerSetAnimation( PLAYER_JUMP );
  592. m_pCSPlayer->DoAnimationEvent( PLAYERANIMEVENT_JUMP );
  593. float flGroundFactor = 1.0f;
  594. if (player->m_pSurfaceData)
  595. {
  596. flGroundFactor = player->m_pSurfaceData->game.jumpFactor;
  597. }
  598. // if we weren't ducking, bots and hostages do a crouchjump programatically
  599. if ( (!player || player->IsBot()) && !(mv->m_nButtons & IN_DUCK) )
  600. {
  601. m_pCSPlayer->m_duckUntilOnGround = true;
  602. FinishDuck();
  603. }
  604. // Acclerate upward
  605. // If we are ducking...
  606. float startz = mv->m_vecVelocity[2];
  607. if ( bStandingOnFallingPlayer )
  608. {
  609. mv->m_vecVelocity[2] = 0.0f;
  610. }
  611. else if ( m_pCSPlayer->m_duckUntilOnGround || ( m_pCSPlayer->m_Local.m_bDucking ) || ( m_pCSPlayer->GetFlags() & FL_DUCKING ) || bStandingOnOtherPlayer )
  612. {
  613. // d = 0.5 * g * t^2 - distance traveled with linear accel
  614. // t = sqrt(2.0 * 45 / g) - how long to fall 45 units
  615. // v = g * t - velocity at the end (just invert it to jump up that high)
  616. // v = g * sqrt(2.0 * 45 / g )
  617. // v^2 = g * g * 2.0 * 45 / g
  618. // v = sqrt( g * 2.0 * 45 )
  619. mv->m_vecVelocity[2] = flGroundFactor * sv_jump_impulse.GetFloat(); // 2 * gravity * height
  620. }
  621. else
  622. {
  623. mv->m_vecVelocity[2] += flGroundFactor * sv_jump_impulse.GetFloat(); // 2 * gravity * height
  624. }
  625. if ( m_pCSPlayer->m_flStamina > 0 )
  626. {
  627. mv->m_vecVelocity[2] *= clamp(1.0f - m_pCSPlayer->m_flStamina / STAMINA_RANGE, 0.f, 1.f);
  628. }
  629. FinishGravity();
  630. mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz;
  631. mv->m_outStepHeight += 0.1f;
  632. OnJump(mv->m_outWishVel.z);
  633. #ifndef CLIENT_DLL
  634. // allow bots to react
  635. IGameEvent * event = gameeventmanager->CreateEvent( "player_jump" );
  636. if ( event )
  637. {
  638. event->SetInt( "userid", m_pCSPlayer->GetUserID() );
  639. gameeventmanager->FireEvent( event );
  640. }
  641. #endif
  642. // Flag that we jumped.
  643. mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
  644. return true;
  645. }
  646. void HybridDecay( QAngle& v, float fExp, float fLin, float dT )
  647. {
  648. fExp *= dT;
  649. fLin *= dT;
  650. v *= expf(-fExp);
  651. float fMag = v.Length();
  652. if ( fMag > fLin )
  653. {
  654. v *= (1.0f - fLin / fMag);
  655. }
  656. else
  657. {
  658. v.Init(0.0f, 0.0f, 0.0f);
  659. }
  660. }
  661. void CCSGameMovement::DecayAimPunchAngle( void )
  662. {
  663. QAngle punchAngle = m_pCSPlayer->m_Local.m_aimPunchAngle;
  664. QAngle punchAngleVel = m_pCSPlayer->m_Local.m_aimPunchAngleVel;
  665. // decay the punch angle
  666. HybridDecay(punchAngle, weapon_recoil_decay2_exp.GetFloat(), weapon_recoil_decay2_lin.GetFloat(), TICK_INTERVAL);
  667. // add in the velocity
  668. punchAngle += punchAngleVel * TICK_INTERVAL * 0.5f;
  669. // decay the punch angle velocity
  670. punchAngleVel *= expf(TICK_INTERVAL * -weapon_recoil_vel_decay.GetFloat());
  671. punchAngle += punchAngleVel * TICK_INTERVAL * 0.5f;
  672. // save off the new values
  673. m_pCSPlayer->m_Local.m_aimPunchAngle = punchAngle;
  674. m_pCSPlayer->m_Local.m_aimPunchAngleVel = punchAngleVel;
  675. }
  676. void CCSGameMovement::HandleDuckingSpeedCrop( float duckFraction )
  677. {
  678. // [Forrest] Movement speed in free look camera mode is unaffected by ducking state.
  679. if ( player->GetObserverMode() == OBS_MODE_ROAMING )
  680. return;
  681. if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) )
  682. {
  683. if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
  684. {
  685. float duckSpeedModifier = GetDuckSpeedModifier(duckFraction);
  686. //DevMsg( "duckSpeedModifier = %f\n", duckSpeedModifier );
  687. mv->m_flForwardMove *= duckSpeedModifier;
  688. mv->m_flSideMove *= duckSpeedModifier;
  689. mv->m_flUpMove *= duckSpeedModifier;
  690. mv->m_flMaxSpeed *= duckSpeedModifier;
  691. m_iSpeedCropped |= SPEED_CROPPED_DUCK;
  692. }
  693. }
  694. }
  695. bool CCSGameMovement::CanUnduck()
  696. {
  697. // Can't unduck if we are planting the bomb.
  698. if ( m_pCSPlayer->m_bDuckOverride )
  699. return false;
  700. // Can always unduck if we are no-clipping
  701. if ( player->GetMoveType() == MOVETYPE_NOCLIP )
  702. return true;
  703. // Check to see if we would collide on anything if we unducked.
  704. trace_t trace;
  705. Vector newOrigin;
  706. VectorCopy( mv->GetAbsOrigin(), newOrigin );
  707. if ( player->GetGroundEntity() != NULL )
  708. {
  709. newOrigin += VEC_DUCK_HULL_MIN - VEC_HULL_MIN;
  710. }
  711. else
  712. {
  713. // If in air an letting go of crouch, make sure we can offset origin to make
  714. // up for uncrouching
  715. Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
  716. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
  717. newOrigin += -0.5f * ( hullSizeNormal - hullSizeCrouch );
  718. }
  719. UTIL_TraceHull( mv->GetAbsOrigin(), newOrigin, VEC_HULL_MIN, VEC_HULL_MAX, PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  720. if ( trace.startsolid || ( trace.fraction != 1.0f ) )
  721. return false;
  722. return true;
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: Stop ducking
  726. //-----------------------------------------------------------------------------
  727. void CCSGameMovement::FinishUnDuck( void )
  728. {
  729. Vector newOrigin = mv->GetAbsOrigin();
  730. if ( player->GetGroundEntity() != NULL || player->GetMoveType() == MOVETYPE_LADDER )
  731. {
  732. Vector hullMinDelta = VEC_DUCK_HULL_MIN - VEC_HULL_MIN;
  733. newOrigin += hullMinDelta;
  734. }
  735. else
  736. {
  737. // If in air an letting go of croush, make sure we can offset origin to make
  738. // up for uncrouching
  739. Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
  740. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
  741. Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeCrouch );
  742. newOrigin += viewDelta;
  743. }
  744. mv->SetAbsOrigin( newOrigin );
  745. player->RemoveFlag( FL_DUCKING | FL_ANIMDUCKING );
  746. player->m_Local.m_bDucked = false;
  747. player->m_Local.m_bDucking = false;
  748. player->m_Local.m_nDuckTimeMsecs = 0; // legacy
  749. player->SetViewOffset( GetPlayerViewOffset( false ) );
  750. // Recategorize position since ducking can change origin
  751. CategorizePosition();
  752. player->m_flDuckAmount = 0.0f;
  753. }
  754. //-----------------------------------------------------------------------------
  755. // Purpose: Finish ducking
  756. //-----------------------------------------------------------------------------
  757. void CCSGameMovement::FinishDuck( void )
  758. {
  759. Assert( !player->m_Local.m_bDucked );
  760. Vector newOrigin = mv->GetAbsOrigin();
  761. if ( player->GetGroundEntity() != NULL || player->GetMoveType() == MOVETYPE_LADDER )
  762. {
  763. Vector hullMinDelta = VEC_DUCK_HULL_MIN - VEC_HULL_MIN;
  764. newOrigin -= hullMinDelta;
  765. }
  766. else
  767. {
  768. Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
  769. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
  770. Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeCrouch );
  771. newOrigin -= viewDelta;
  772. }
  773. mv->SetAbsOrigin( newOrigin );
  774. player->SetViewOffset( GetPlayerViewOffset( true ) );
  775. player->m_Local.m_bDucking = false;
  776. player->m_Local.m_bDucked = true;
  777. player->m_Local.m_flLastDuckTime = gpGlobals->curtime;
  778. player->AddFlag( FL_ANIMDUCKING | FL_DUCKING );
  779. // See if we are stuck?
  780. FixPlayerCrouchStuck( true );
  781. // Recategorize position since ducking can change origin
  782. CategorizePosition();
  783. player->m_flDuckAmount = 1.0f;
  784. }
  785. //-----------------------------------------------------------------------------
  786. // Purpose: See if duck button is pressed and do the appropriate things
  787. //-----------------------------------------------------------------------------
  788. void CCSGameMovement::Duck( void )
  789. {
  790. const bool playerTouchingGround = player->GetGroundEntity() != NULL;
  791. // Check to see if we are in the air.
  792. const bool bInAir = !playerTouchingGround && player->GetMoveType() != MOVETYPE_LADDER;
  793. if ( mv->m_nButtons & IN_DUCK )
  794. {
  795. mv->m_nOldButtons |= IN_DUCK;
  796. }
  797. else
  798. {
  799. mv->m_nOldButtons &= ~IN_DUCK;
  800. }
  801. // Dead players don't duck.
  802. if ( IsDead() && !player->IsObserver() )
  803. {
  804. // They also don't plant the bomb.
  805. m_pCSPlayer->m_bDuckOverride = false;
  806. if ( player->GetFlags() & FL_DUCKING )
  807. {
  808. FinishUnDuck();
  809. }
  810. return;
  811. }
  812. if ( m_pCSPlayer->m_duckUntilOnGround )
  813. {
  814. // This code handles the case where a bot is jumping; they
  815. // automatically crouch jump, and we want to decide if they are
  816. // ready to un-duck here.
  817. // TODO: Should we move this code into the bot movement logic
  818. // instead?
  819. // $$$REI There still seems to be a way to end up in this state if the bot
  820. // was crouch-jumping at the end of the round; I haven't found where
  821. // his flags are getting reset. Will fix later, and just reset the
  822. // inconsistent state here. Next tick the bot will behave normally.
  823. // Assert( player->GetFlags() & FL_DUCKING );
  824. if ( ( player->GetFlags() & FL_DUCKING ) == 0 )
  825. {
  826. m_pCSPlayer->m_duckUntilOnGround = false;
  827. return;
  828. }
  829. // If we have landed, we are done with 'duck until on ground'.
  830. if ( !bInAir )
  831. {
  832. m_pCSPlayer->m_duckUntilOnGround = false;
  833. // Stop crouching if possible
  834. if ( CanUnduck() )
  835. {
  836. FinishUnDuck();
  837. }
  838. return;
  839. }
  840. // Otherwise we are still in the air.
  841. // Try to un-duck just as we land, for better animation and movement.
  842. // If we're still going up, we aren't about to land. Early-out.
  843. if ( mv->m_vecVelocity.z > 0.0f )
  844. return;
  845. // Check if we are close enough to the ground and that there is room to un-duck.
  846. trace_t trace;
  847. Vector newOrigin;
  848. Vector groundCheck;
  849. VectorCopy( mv->GetAbsOrigin(), newOrigin );
  850. Vector hullSizeNormal = VEC_HULL_MAX - VEC_HULL_MIN;
  851. Vector hullSizeCrouch = VEC_DUCK_HULL_MAX - VEC_DUCK_HULL_MIN;
  852. newOrigin -= ( hullSizeNormal - hullSizeCrouch );
  853. groundCheck = newOrigin;
  854. groundCheck.z -= player->GetStepSize();
  855. UTIL_TraceHull( newOrigin, groundCheck, VEC_HULL_MIN, VEC_HULL_MAX, PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
  856. if ( trace.startsolid // No room to unduck.
  857. || trace.fraction == 1.0f // We are still in the air
  858. )
  859. return;
  860. // Success! We can un-duck. Remove "un-duck when possible" flag.
  861. m_pCSPlayer->m_duckUntilOnGround = false;
  862. // Theoretically CanUnduck() should always succeed here since we just did a hull trace.
  863. // REI: But the hulltrace in CanUnduck() looks slightly different than this one; it uses
  864. // newOrigin = mv->GetAbsOrigin() + -0.5f * ( hullSizeNormal - hullSizeCrouch )
  865. // and traces from mv->GetAbsOrigin() to newOrigin instead of from newOrigin to a
  866. // step away.
  867. if ( CanUnduck() )
  868. {
  869. FinishUnDuck();
  870. }
  871. return;
  872. }
  873. // Reduce duck-spam penalty over time
  874. player->m_flDuckSpeed = Approach( CS_PLAYER_DUCK_SPEED_IDEAL, player->m_flDuckSpeed, gpGlobals->frametime * 3.0f );
  875. // Use the last-known position of full crouch speed to restore crouch speed as a function of physical player position.
  876. // The goal is that moving a sufficient distance should reset crouch speed in an intuitive manner.
  877. if ( player->m_flDuckSpeed >= CS_PLAYER_DUCK_SPEED_IDEAL )
  878. {
  879. player->m_vecLastPositionAtFullCrouchSpeed = player->GetAbsOrigin().AsVector2D();
  880. }
  881. else if ( player->m_flDuckAmount <= 0 || player->m_flDuckAmount >= 1 )
  882. {
  883. //debugoverlay->AddLineOverlay( player->m_vecLastPositionAtFullCrouchSpeed, player->GetAbsOrigin(), 255,0,0, true, 0.1f );
  884. //debugoverlay->AddTextOverlay( player->GetAbsOrigin(), 0.1f, "%f", player->m_flDuckSpeed );
  885. float flDistToLastPositionAtFullCrouchSpeed = player->m_vecLastPositionAtFullCrouchSpeed.DistToSqr( player->GetAbsOrigin().AsVector2D() );
  886. // if we're sufficiently far from the last full crouch speed location, we can safely restore crouch speed faster.
  887. if ( flDistToLastPositionAtFullCrouchSpeed > (64*64) )
  888. {
  889. player->m_flDuckSpeed = Approach( CS_PLAYER_DUCK_SPEED_IDEAL, player->m_flDuckSpeed, gpGlobals->frametime * 6.0f );
  890. }
  891. }
  892. bool duckButtonHeld = ( mv->m_nButtons & IN_DUCK ) != 0;
  893. if ( !duckButtonHeld && player->m_flDuckAmount > 0 )
  894. {
  895. // Not sure if this is the appropriate use of this flag. It seems odd to have a dedicated variable that effectively means crouch-is-not-zero-or-one.
  896. // When the round restarts with the player in the ducked state, they can get stuck crouched.
  897. // To prevent this, I'm setting the "duck-in-progress" bool (m_bDucking) to true if
  898. // the player is ever in the state of NOT holding the duck button but is still ducked.
  899. player->m_Local.m_bDucking = true;
  900. }
  901. else if ( duckButtonHeld && player->m_flDuckAmount < 1 )
  902. {
  903. // or if the player IS holding the duck button but isn't yet fully ducked.
  904. player->m_Local.m_bDucking = true;
  905. }
  906. // Handle animating into the ducking pose.
  907. if ( duckButtonHeld && player->m_Local.m_bDucking )
  908. {
  909. Assert( !player->m_Local.m_bDucked );
  910. // ducking is always a little slower than unducking
  911. float duckSpeed = player->m_flDuckSpeed * 0.8f;
  912. // Reduce crouch/uncrouch speed significantly while defusing
  913. if ( m_pCSPlayer->m_bIsDefusing )
  914. duckSpeed *= 0.4f;
  915. player->m_flDuckAmount = Approach( 1.0f, player->m_flDuckAmount, gpGlobals->frametime * duckSpeed );
  916. // Finish ducking immediately if duck time is over or not on ground
  917. if ( player->m_flDuckAmount >= 1.0f || !playerTouchingGround )
  918. {
  919. FinishDuck();
  920. }
  921. else
  922. {
  923. SetDuckedEyeOffset( player->m_flDuckAmount );
  924. }
  925. // REI: For some reason we don't set this flag immediately, but wait until you have ducked a little bit. Investigate?
  926. if ( player->m_flDuckAmount >= 0.1f && !( player->GetFlags() & FL_ANIMDUCKING ) )
  927. {
  928. player->AddFlag( FL_ANIMDUCKING );
  929. }
  930. }
  931. // Handle animating out of ducking pose.
  932. if ( !duckButtonHeld && player->m_Local.m_bDucking
  933. // Try to unduck unless automovement is not allowed
  934. // NOTE: When not onground, you can always unduck
  935. // REI: Cloned behavior from old code, not sure when m_bAllowAutomovement is used?
  936. && ( player->m_Local.m_bAllowAutoMovement || !playerTouchingGround ) )
  937. {
  938. if ( CanUnduck() )
  939. {
  940. // Always unduck at at least 1.5 to prevent advantageous semi-ducked positions
  941. float duckSpeed = MAX( 1.5f, player->m_flDuckSpeed );
  942. // Reduce crouch/uncrouch speed significantly while defusing
  943. if ( m_pCSPlayer->m_bIsDefusing )
  944. duckSpeed *= 0.4f;
  945. player->m_flDuckAmount = Approach( 0.0f, player->m_flDuckAmount, gpGlobals->frametime * duckSpeed );
  946. player->m_Local.m_bDucked = false;
  947. if ( player->m_flDuckAmount <= 0.0f || !playerTouchingGround )
  948. {
  949. FinishUnDuck();
  950. }
  951. else
  952. {
  953. SetDuckedEyeOffset( player->m_flDuckAmount );
  954. }
  955. // Remove the ducked flags if we're not fully ducked anymore.
  956. // REI: This is inconsistent with the documentation for these flags, but I'm not sure why the code
  957. // is doing this. It does mean you lose your ducking accuracy bonus very early in the un-duck,
  958. // which is certainly important.
  959. if ( player->m_flDuckAmount <= 0.75f && player->GetFlags() & ( FL_ANIMDUCKING | FL_DUCKING ) )
  960. {
  961. player->RemoveFlag( FL_ANIMDUCKING | FL_DUCKING );
  962. }
  963. }
  964. else
  965. {
  966. // Reset to fully-ducked as we went under something we can't un-duck from.
  967. // We'll try again once the player has moved out of the obstructing obstacle.
  968. player->m_flDuckAmount = 1.0f;
  969. player->m_Local.m_bDucked = true;
  970. player->m_Local.m_bDucking = false;
  971. player->AddFlag( FL_ANIMDUCKING | FL_DUCKING );
  972. SetDuckedEyeOffset( player->m_flDuckAmount );
  973. }
  974. }
  975. #ifdef AUTHOR_RYANI
  976. // REI: Consistency checks for fully ducked/unducked states
  977. if ( player->m_flDuckAmount >= 1.0f )
  978. {
  979. AssertMsg1( ( player->GetFlags() & ( FL_DUCKING | FL_ANIMDUCKING ) ) == ( FL_DUCKING | FL_ANIMDUCKING ),
  980. "ryan: inconsistent state in new duck code for %s.", player->GetPlayerName() );
  981. }
  982. else if ( player->m_flDuckAmount <= 0.0f )
  983. {
  984. AssertMsg1( ( player->GetFlags() & ( FL_DUCKING | FL_ANIMDUCKING ) ) == 0,
  985. "ryan: inconsistent state in new duck code for %s.", player->GetPlayerName() );
  986. }
  987. #endif
  988. // REI: I think I've fixed all cases of this happening. Leaving it in for now. $$$REI remove this after testing shows it never happening again.
  989. if ( player->m_flDuckAmount <= 0 && (player->GetFlags() & FL_ANIMDUCKING) )
  990. {
  991. AssertMsg1( false, "Clearing FL_ANIMDUCKING flag on player %s to prevent crab-walk. Please let Ryan know if you hit this.", player->GetPlayerName() );
  992. player->RemoveFlag( FL_ANIMDUCKING );
  993. }
  994. #ifdef CLIENT_DLL
  995. if ( IsPreCrouchUpdateDemo() )
  996. {
  997. // compatibility for old demos using the old crouch values
  998. if ( player->m_Local.m_nDuckTimeMsecs )
  999. {
  1000. player->AddFlag( FL_ANIMDUCKING | FL_DUCKING );
  1001. }
  1002. else
  1003. {
  1004. player->RemoveFlag( FL_ANIMDUCKING | FL_DUCKING );
  1005. }
  1006. const float CS_DUCK_TIME_MSECS = 150.0f;
  1007. int millisecondsDucked = MAX( 0, CS_DUCK_TIME_MSECS - player->m_Local.m_nDuckTimeMsecs );
  1008. player->m_flDuckAmount = (float)millisecondsDucked / (float)CS_DUCK_TIME_MSECS;
  1009. SetDuckedEyeOffset( player->m_flDuckAmount );
  1010. }
  1011. #endif
  1012. HandleDuckingSpeedCrop( player->m_flDuckAmount );
  1013. }
  1014. void CCSGameMovement::OnJump( float fImpulse )
  1015. {
  1016. float flStamCost = sv_staminajumpcost.GetFloat( );
  1017. m_pCSPlayer->m_flStamina = clamp( m_pCSPlayer->m_flStamina + flStamCost * fImpulse, 0.0f, sv_staminamax.GetFloat( ) );
  1018. m_pCSPlayer->OnJump( fImpulse );
  1019. }
  1020. void CCSGameMovement::OnLand( float fVelocity )
  1021. {
  1022. m_pCSPlayer->m_flStamina = clamp( m_pCSPlayer->m_flStamina + sv_staminalandcost.GetFloat() * fVelocity, 0.0f, sv_staminamax.GetFloat());
  1023. m_pCSPlayer->OnLand( fVelocity );
  1024. }
  1025. // override the default behavior in order to change acceleration based on movement modifiers
  1026. void CCSGameMovement::Accelerate( Vector& wishdir, float wishspeed, float accel )
  1027. {
  1028. if ( !CanAccelerate() )
  1029. return;
  1030. float flStoredAccel = accel;
  1031. // See if we are changing direction a bit
  1032. float currentspeed = mv->m_vecVelocity.Dot(wishdir);
  1033. float flUnmodifiedSpeed = currentspeed;
  1034. // Reduce wishspeed by the amount of veer.
  1035. float addspeed = wishspeed - currentspeed;
  1036. // If not going to add any speed, done.
  1037. if (addspeed <= 0)
  1038. return;
  1039. if ( currentspeed < 0 )
  1040. currentspeed = 0;
  1041. bool bIsDucking = ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING );
  1042. bool bIsWalking = ( mv->m_nButtons & ( /*IN_WALK | */ IN_SPEED ) ) != 0 && !bIsDucking;
  1043. float flMaxSpeed = 250.0f;
  1044. float fAccelerationScale = MAX(flMaxSpeed, wishspeed);
  1045. float flGoalSpeed = fAccelerationScale;
  1046. // if this convar is set, we ignore the passed in accel value (sv_acceleration) and accelerate based on the one below instead
  1047. float flZeroToMaxSpeedTime = SV_ACCELERATE_EXPONENT_TIME;
  1048. CWeaponCSBase *csWeapon = dynamic_cast< CWeaponCSBase * >( player->GetActiveWeapon() );
  1049. /* flMaxScaleSpeed = mv->m_flMaxSpeed;*/
  1050. bool bIsSlowSniperScoped = false;
  1051. flGoalSpeed = fAccelerationScale;
  1052. if ( sv_accelerate_use_weapon_speed.GetBool( ) && csWeapon )
  1053. {
  1054. bIsSlowSniperScoped = (csWeapon->GetCSZoomLevel() > 0 && csWeapon->GetZoomLevels() > 1
  1055. && (csWeapon->GetMaxSpeed( ) * CS_PLAYER_SPEED_WALK_MODIFIER) < 110.0);
  1056. flGoalSpeed *= MIN( 1.0f, ( csWeapon->GetMaxSpeed( ) / flMaxSpeed ) );
  1057. if ( (!bIsDucking && !bIsWalking) || (( bIsWalking || bIsDucking) && bIsSlowSniperScoped) )
  1058. fAccelerationScale *= MIN( 1.0f, (csWeapon->GetMaxSpeed() / flMaxSpeed));
  1059. }
  1060. // TODO: make this number not a magic number
  1061. if ( bIsDucking )
  1062. {
  1063. if ( !bIsSlowSniperScoped )
  1064. fAccelerationScale *= CS_PLAYER_SPEED_DUCK_MODIFIER;
  1065. flGoalSpeed *= CS_PLAYER_SPEED_DUCK_MODIFIER;
  1066. }
  1067. if ( bIsWalking )
  1068. {
  1069. if ( !bIsSlowSniperScoped )
  1070. fAccelerationScale *= CS_PLAYER_SPEED_WALK_MODIFIER;
  1071. flGoalSpeed *= CS_PLAYER_SPEED_WALK_MODIFIER;
  1072. }
  1073. /*
  1074. bool bShouldStutter = (wishspeed > 200.0f);
  1075. if ( bShouldStutter == false && bIsDucking == false && bIsWalking == false )
  1076. {
  1077. flStoredAccel *= 0.75;//clamp( 1.0f - ( MAX( 0.0f, currentspeed - ( flGoalSpeed - 5 ) ) / MAX( 0.0f, flGoalSpeed - ( flGoalSpeed - 5 ) ) ), 0.0f, 1.0f );
  1078. }
  1079. // we no longer just clamp player's max speed when they hit the walk key
  1080. else if (bIsWalking && currentspeed > (flGoalSpeed-5) )*/
  1081. if (bIsWalking && currentspeed > (flGoalSpeed-5) )
  1082. {
  1083. // we now only clamp it when it's within a certain range of walking, otherwise we stop adding speed to let them decelerate naturally
  1084. flStoredAccel *= clamp( 1.0f - ( MAX( 0.0f, currentspeed - ( flGoalSpeed - 5 ) ) / MAX( 0.0f, flGoalSpeed - ( flGoalSpeed - 5 ) ) ), 0.0f, 1.0f );
  1085. }
  1086. // Determine amount of acceleration.
  1087. float accelspeed = 0;
  1088. float flCounterSpeed = 0;
  1089. float flMaxAccelspeed = 0;
  1090. if ( flZeroToMaxSpeedTime > 0 )
  1091. {
  1092. currentspeed = MAX( 5, currentspeed );
  1093. float flRawAccelExponent = MAX(1, SV_ACCELERATE_EXPONENT);
  1094. float flAccelExponentTop = (flRawAccelExponent-1);
  1095. flAccelExponentTop *= MAX( 0.0001, 1-(MAX( 0, (fAccelerationScale-220) )/(flGoalSpeed-220) ) );
  1096. if ( bIsDucking || bIsWalking )
  1097. flAccelExponentTop *= 0.05;
  1098. float flAccelExponent = flAccelExponentTop + 1;
  1099. float flMoveFracActual = pow( currentspeed/flGoalSpeed, 1/flAccelExponent );
  1100. float flLastTimeDelta = gpGlobals->curtime - m_pCSPlayer->m_flGroundAccelLinearFracLastTime;
  1101. if ( currentspeed <= 1 || flLastTimeDelta > 0.1 )
  1102. flLastTimeDelta = 0.015;
  1103. // get friction because we're going to counter it a bit on accelerate
  1104. float flFriction = (sv_friction.GetFloat() * player->m_surfaceFriction);
  1105. float flControl = (currentspeed < sv_stopspeed.GetFloat()) ? sv_stopspeed.GetFloat() : currentspeed;
  1106. flCounterSpeed = flControl*flFriction*gpGlobals->frametime;
  1107. float flTimeSinceStart = (flZeroToMaxSpeedTime * flMoveFracActual);
  1108. float flNewTime = (flTimeSinceStart + flLastTimeDelta);
  1109. float flNewFrac = MIN( 1, (flNewTime / flZeroToMaxSpeedTime) );
  1110. // if ( flNewFrac > 1 )
  1111. // {
  1112. // int x = 1;
  1113. // x++;
  1114. // }
  1115. float flNewSpeed = pow( flNewFrac, flAccelExponent ) * flGoalSpeed;
  1116. flStoredAccel = flNewSpeed-currentspeed;
  1117. // we're stutter stepping, counter the current speed here
  1118. if ( flUnmodifiedSpeed < -(flMaxSpeed*CS_PLAYER_SPEED_WALK_MODIFIER) )
  1119. flCounterSpeed += -(flUnmodifiedSpeed/3);
  1120. flMaxAccelspeed = accel * gpGlobals->frametime * fAccelerationScale * player->m_surfaceFriction;
  1121. // apply the speed
  1122. accelspeed = MIN( flMaxAccelspeed, (flStoredAccel * gpGlobals->frametime * fAccelerationScale)+flCounterSpeed );
  1123. }
  1124. else
  1125. {
  1126. // apply the speed
  1127. accelspeed = flStoredAccel * gpGlobals->frametime * fAccelerationScale * player->m_surfaceFriction;
  1128. }
  1129. // if ( accelspeed < 16 && accelspeed > 11 )
  1130. // {
  1131. // Msg( "BLAH!!!" );
  1132. // }
  1133. // Cap at addspeed
  1134. if (accelspeed > addspeed)
  1135. accelspeed = addspeed;
  1136. mv->m_vecVelocity += (accelspeed * wishdir);
  1137. // store the last time we updated the speed
  1138. m_pCSPlayer->m_flGroundAccelLinearFracLastTime = gpGlobals->curtime;
  1139. #if !defined(CLIENT_DLL)
  1140. if ( sv_accelerate_debug_speed.GetBool() )
  1141. DevMsg( "------- accelspeed = %f, flGoalSpeed = %f, flStoredAccel = %f\n", accelspeed, flGoalSpeed, flStoredAccel );
  1142. #endif
  1143. //DevMsg( "TRAILING MOVESPEED %f!\n", mv->m_vecTrailingVelocity.AsVector2D().Length() );
  1144. if ( mv->m_vecTrailingVelocity.IsZero() || ( gpGlobals->curtime - mv->m_flTrailingVelocityTime ) > 0.35f )
  1145. {
  1146. // Do a full update
  1147. mv->m_vecTrailingVelocity = mv->m_vecVelocity;
  1148. mv->m_flTrailingVelocityTime = gpGlobals->curtime;
  1149. }
  1150. else
  1151. {
  1152. Vector2D vNormalizedCurrent = mv->m_vecVelocity.AsVector2D();
  1153. Vector2DNormalize( vNormalizedCurrent );
  1154. Vector2D vNormalizedPrev = mv->m_vecTrailingVelocity.AsVector2D();
  1155. Vector2DNormalize( vNormalizedPrev );
  1156. // Check if they're pointed roughly the same direction
  1157. float flDot = vNormalizedCurrent.Dot( vNormalizedPrev );
  1158. if ( flDot > 0.8f )
  1159. {
  1160. // Check if the current has a larger magnitude
  1161. if ( mv->m_vecTrailingVelocity.AsVector2D().LengthSqr() < mv->m_vecVelocity.AsVector2D().LengthSqr() )
  1162. {
  1163. mv->m_vecTrailingVelocity = mv->m_vecVelocity;
  1164. mv->m_flTrailingVelocityTime = gpGlobals->curtime;
  1165. }
  1166. }
  1167. // Check if they're going the opposite direction
  1168. else if ( flDot < -0.8f )
  1169. {
  1170. // Check if the velocity difference is extreme
  1171. if ( mv->m_vecTrailingVelocity.AsVector2D().Length() < 225.0f && mv->m_vecTrailingVelocity.AsVector2D().Length() > 115.0f && mv->m_vecVelocity.AsVector2D().Length() > 115.0f )
  1172. {
  1173. // Check if the player is moving perpendicular
  1174. Vector vEyeForward;
  1175. m_pCSPlayer->EyeVectors( &vEyeForward );
  1176. float flEyeDot = vEyeForward.AsVector2D().Dot( vNormalizedCurrent );
  1177. if ( flEyeDot > -0.3f && flEyeDot < 0.3f )
  1178. {
  1179. CWeaponCSBase *pWeapon = m_pCSPlayer->GetActiveCSWeapon();
  1180. if ( pWeapon )
  1181. {
  1182. #if defined( WEAPON_FIRE_BULLETS_ACCURACY_FISHTAIL_FEATURE )
  1183. //DevMsg( "FISHTAIL %s!\n", flEyeDot > 0.0f ? "left" : "right" );
  1184. /*if ( sv_extreme_strafe_aim_punch.GetBool() )
  1185. {
  1186. m_pCSPlayer->KickBack( flEyeDot > 0.0f ? 90.0f : 270.0f, sv_extreme_strafe_accuracy_fishtail.GetFloat() * 15.0f );
  1187. }
  1188. else*/
  1189. {
  1190. pWeapon->SetAccuracyFishtail( flEyeDot > 0.0f ? -sv_extreme_strafe_accuracy_fishtail.GetFloat() : sv_extreme_strafe_accuracy_fishtail.GetFloat() );
  1191. }
  1192. #endif
  1193. mv->m_vecTrailingVelocity = mv->m_vecVelocity;
  1194. mv->m_flTrailingVelocityTime = gpGlobals->curtime;
  1195. }
  1196. }
  1197. }
  1198. }
  1199. }
  1200. }