summaryrefslogtreecommitdiff
path: root/game/shared/cstrike/cs_gamemovement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/cstrike/cs_gamemovement.cpp')
-rw-r--r--game/shared/cstrike/cs_gamemovement.cpp1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/game/shared/cstrike/cs_gamemovement.cpp b/game/shared/cstrike/cs_gamemovement.cpp
new file mode 100644
index 0000000..fa5c52a
--- /dev/null
+++ b/game/shared/cstrike/cs_gamemovement.cpp
@@ -0,0 +1,1144 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "gamemovement.h"
+#include "cs_gamerules.h"
+#include "in_buttons.h"
+#include "movevars_shared.h"
+#include "weapon_csbase.h"
+
+#ifdef CLIENT_DLL
+ #include "c_cs_player.h"
+#else
+ #include "cs_player.h"
+ #include "KeyValues.h"
+#endif
+
+#define STAMINA_MAX 100.0
+#define STAMINA_COST_JUMP 25.0
+#define STAMINA_COST_FALL 20.0
+#define STAMINA_RECOVER_RATE 19.0
+
+extern bool g_bMovementOptimizations;
+
+ConVar sv_timebetweenducks( "sv_timebetweenducks", "0", FCVAR_REPLICATED, "Minimum time before recognizing consecutive duck key", true, 0.0, true, 2.0 );
+ConVar sv_enableboost( "sv_enableboost", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Allow boost exploits");
+
+
+class CCSGameMovement : public CGameMovement
+{
+public:
+ DECLARE_CLASS( CCSGameMovement, CGameMovement );
+
+ CCSGameMovement();
+
+ virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
+ virtual bool CanAccelerate();
+ virtual bool CheckJumpButton( void );
+ virtual void PreventBunnyJumping( void );
+ virtual void ReduceTimers( void );
+ virtual void WalkMove( void );
+ virtual void AirMove( void );
+ virtual bool LadderMove( void );
+ virtual void DecayPunchAngle( void );
+ virtual void CheckParameters( void );
+
+ // allow overridden versions to respond to jumping
+ virtual void OnJump( float fImpulse );
+ virtual void OnLand( float fVelocity );
+
+ // Ducking
+ virtual void Duck( void );
+ virtual void FinishUnDuck( void );
+ virtual void FinishDuck( void );
+ virtual bool CanUnduck();
+ virtual void HandleDuckingSpeedCrop();
+
+
+ virtual bool OnLadder( trace_t &trace );
+ virtual float LadderDistance( void ) const
+ {
+ if ( player->GetMoveType() == MOVETYPE_LADDER )
+ return 10.0f;
+ return 2.0f;
+ }
+
+ virtual unsigned int LadderMask( void ) const
+ {
+ return MASK_PLAYERSOLID & ( ~CONTENTS_PLAYERCLIP );
+ }
+
+ virtual float ClimbSpeed( void ) const;
+ virtual float LadderLateralMultiplier( void ) const;
+
+ virtual void TryTouchGround( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, unsigned int fMask, int collisionGroup, trace_t& pm );
+
+
+protected:
+ virtual void PlayerMove();
+
+ void CheckForLadders( bool wasOnGround );
+ virtual unsigned int PlayerSolidMask( bool brushOnly = false ); ///< returns the solid mask for the given player, so bots can have a more-restrictive set
+
+ float m_fTimeLastUnducked;
+
+public:
+ CCSPlayer *m_pCSPlayer;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: used by the TryTouchGround function to exclude non-standables from
+// consideration
+//-----------------------------------------------------------------------------
+
+bool CheckForStandable( IHandleEntity *pHandleEntity, int contentsMask )
+{
+ CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
+
+ if ( !pEntity )
+ return false;
+
+ return ( pEntity->IsPlayer() && pEntity->GetGroundEntity() != NULL ) || pEntity->IsStandable();
+}
+
+
+// Expose our interface.
+static CCSGameMovement g_GameMovement;
+IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
+
+
+// ---------------------------------------------------------------------------------------- //
+// CCSGameMovement.
+// ---------------------------------------------------------------------------------------- //
+
+CCSGameMovement::CCSGameMovement()
+{
+ m_fTimeLastUnducked = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Allow bots etc to use slightly different solid masks
+//-----------------------------------------------------------------------------
+unsigned int CCSGameMovement::PlayerSolidMask( bool brushOnly )
+{
+ bool isBot = !player || player->IsBot();
+
+ if ( brushOnly )
+ {
+ if ( isBot )
+ {
+ return MASK_PLAYERSOLID_BRUSHONLY | CONTENTS_MONSTERCLIP;
+ }
+ else
+ {
+ return MASK_PLAYERSOLID_BRUSHONLY;
+ }
+ }
+ else
+ {
+ if ( isBot )
+ {
+ return MASK_PLAYERSOLID | CONTENTS_MONSTERCLIP;
+ }
+ else
+ {
+ return MASK_PLAYERSOLID;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSGameMovement::CheckParameters( void )
+{
+ QAngle v_angle;
+
+ // maintaining auto-duck during jumps
+ if ( m_pCSPlayer->m_duckUntilOnGround )
+ {
+ if ( !player->GetGroundEntity() )
+ {
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ m_pCSPlayer->m_duckUntilOnGround = false; // player hit +duck, so cancel our auto duck
+ }
+ else
+ {
+ mv->m_nButtons |= IN_DUCK;
+ }
+ }
+ }
+
+ // it would be nice to put this into the player->GetPlayerMaxSpeed() method, but
+ // this flag is only stored in the move!
+ if ( mv->m_nButtons & IN_SPEED )
+ {
+ mv->m_flMaxSpeed *= CS_PLAYER_SPEED_WALK_MODIFIER;
+ }
+
+ if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
+ player->GetMoveType() != MOVETYPE_NOCLIP &&
+ player->GetMoveType() != MOVETYPE_OBSERVER )
+ {
+ float spd;
+
+ spd = ( mv->m_flForwardMove * mv->m_flForwardMove ) +
+ ( mv->m_flSideMove * mv->m_flSideMove ) +
+ ( mv->m_flUpMove * mv->m_flUpMove );
+
+
+ // Slow down by the speed factor
+ float flSpeedFactor = 1.0f;
+ if (player->m_pSurfaceData)
+ {
+ flSpeedFactor = player->m_pSurfaceData->game.maxSpeedFactor;
+ }
+
+ // If we have a constraint, slow down because of that too.
+ float flConstraintSpeedFactor = ComputeConstraintSpeedFactor();
+ if (flConstraintSpeedFactor < flSpeedFactor)
+ flSpeedFactor = flConstraintSpeedFactor;
+
+ // Take the player's velocity modifier into account
+ if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
+ {
+ flSpeedFactor *= m_pCSPlayer->m_flVelocityModifier;
+ }
+
+
+ mv->m_flMaxSpeed *= flSpeedFactor;
+
+ if ( g_bMovementOptimizations )
+ {
+ // Same thing but only do the sqrt if we have to.
+ if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed*mv->m_flMaxSpeed ) )
+ {
+ float fRatio = mv->m_flMaxSpeed / sqrt( spd );
+ mv->m_flForwardMove *= fRatio;
+ mv->m_flSideMove *= fRatio;
+ mv->m_flUpMove *= fRatio;
+ }
+ }
+ else
+ {
+ spd = sqrt( spd );
+ if ( ( spd != 0.0 ) && ( spd > mv->m_flMaxSpeed ) )
+ {
+ float fRatio = mv->m_flMaxSpeed / spd;
+ mv->m_flForwardMove *= fRatio;
+ mv->m_flSideMove *= fRatio;
+ mv->m_flUpMove *= fRatio;
+ }
+ }
+ }
+
+
+ if ( player->GetFlags() & FL_FROZEN ||
+ player->GetFlags() & FL_ONTRAIN ||
+ IsDead() )
+ {
+ mv->m_flForwardMove = 0;
+ mv->m_flSideMove = 0;
+ mv->m_flUpMove = 0;
+ }
+
+ DecayPunchAngle();
+
+ // Take angles from command.
+ if ( !IsDead() )
+ {
+ v_angle = mv->m_vecAngles;
+ v_angle = v_angle + player->m_Local.m_vecPunchAngle;
+
+ // Now adjust roll angle
+ if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
+ player->GetMoveType() != MOVETYPE_NOCLIP )
+ {
+ mv->m_vecAngles[ROLL] = CalcRoll( v_angle, mv->m_vecVelocity, sv_rollangle.GetFloat(), sv_rollspeed.GetFloat() );
+ }
+ else
+ {
+ mv->m_vecAngles[ROLL] = 0.0; // v_angle[ ROLL ];
+ }
+ mv->m_vecAngles[PITCH] = v_angle[PITCH];
+ mv->m_vecAngles[YAW] = v_angle[YAW];
+ }
+ else
+ {
+ mv->m_vecAngles = mv->m_vecOldAngles;
+ }
+
+ // Set dead player view_offset
+ if ( IsDead() )
+ {
+ player->SetViewOffset( VEC_DEAD_VIEWHEIGHT );
+ }
+
+ // Adjust client view angles to match values used on server.
+ if ( mv->m_vecAngles[YAW] > 180.0f )
+ {
+ mv->m_vecAngles[YAW] -= 360.0f;
+ }
+
+ // If we're standing on a player, then force them off.
+ if ( !player->IsObserver() && ( player->GetMoveType() != MOVETYPE_LADDER ) )
+ {
+ int nLevels = 0;
+ CBaseEntity *pCurGround = player->GetGroundEntity();
+ while ( pCurGround && pCurGround->IsPlayer() && nLevels < 1000 )
+ {
+ pCurGround = pCurGround->GetGroundEntity();
+ ++nLevels;
+ }
+ if ( nLevels == 1000 )
+ Warning( "BUG: CCSGameMovement::CheckParameters - too many stacking levels.\n" );
+
+ // If they're stacked too many levels deep, slide them off.
+ if ( nLevels > 1 )
+ {
+ mv->m_flForwardMove = mv->m_flMaxSpeed * 3;
+ mv->m_flSideMove = 0;
+ mv->m_nButtons = 0;
+ mv->m_nImpulseCommand = 0;
+ }
+ }
+}
+
+
+void CCSGameMovement::ProcessMovement( CBasePlayer *pBasePlayer, CMoveData *pMove )
+{
+ m_pCSPlayer = ToCSPlayer( pBasePlayer );
+ Assert( m_pCSPlayer );
+
+ BaseClass::ProcessMovement( pBasePlayer, pMove );
+}
+
+
+bool CCSGameMovement::CanAccelerate()
+{
+ // Only allow the player to accelerate when in certain states.
+ CSPlayerState curState = m_pCSPlayer->State_Get();
+ if ( curState == STATE_ACTIVE )
+ {
+ return player->GetWaterJumpTime() == 0;
+ }
+ else if ( player->IsObserver() )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void CCSGameMovement::PlayerMove()
+{
+ if ( !m_pCSPlayer->CanMove() )
+ {
+ mv->m_flForwardMove = 0;
+ mv->m_flSideMove = 0;
+ mv->m_flUpMove = 0;
+ mv->m_nButtons &= ~(IN_JUMP | IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT);
+ }
+
+ BaseClass::PlayerMove();
+
+ if ( FBitSet( m_pCSPlayer->GetFlags(), FL_ONGROUND ) )
+ {
+ if ( m_pCSPlayer->m_flVelocityModifier < 1.0 )
+ {
+ m_pCSPlayer->m_flVelocityModifier += gpGlobals->frametime / 3.0f;
+ }
+
+ if ( m_pCSPlayer->m_flVelocityModifier > 1.0 )
+ m_pCSPlayer->m_flVelocityModifier = 1.0;
+ }
+
+#if !defined(CLIENT_DLL)
+ if ( m_pCSPlayer->IsAlive() )
+ {
+ // Check if our eye height is too close to the ceiling and lower it.
+ // This is needed because we have taller models with the old collision bounds.
+
+ const float eyeClearance = 12.0f; // eye pos must be this far below the ceiling
+
+ Vector offset = player->GetViewOffset();
+
+ Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
+ vHullMin.z = 0.0f;
+ Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
+
+ Vector start = player->GetAbsOrigin();
+ start.z += vHullMax.z;
+ Vector end = start;
+ end.z += eyeClearance - vHullMax.z;
+ end.z += player->m_Local.m_bDucked ? VEC_DUCK_VIEW_SCALED( player ).z : VEC_VIEW_SCALED( player ).z;
+
+ vHullMax.z = 0.0f;
+
+ Vector fudge( 1, 1, 0 );
+ vHullMin += fudge;
+ vHullMax -= fudge;
+
+ trace_t trace;
+ Ray_t ray;
+ ray.Init( start, end, vHullMin, vHullMax );
+ UTIL_TraceRay( ray, PlayerSolidMask(), mv->m_nPlayerHandle.Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
+
+ if ( trace.fraction < 1.0f )
+ {
+ float est = start.z + trace.fraction * (end.z - start.z) - player->GetAbsOrigin().z - eyeClearance;
+ if ( ( player->GetFlags() & FL_DUCKING ) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked )
+ {
+ offset.z = est;
+ }
+ else
+ {
+ offset.z = MIN( est, offset.z );
+ }
+ player->SetViewOffset( offset );
+ }
+ else
+ {
+ if ( ( player->GetFlags() & FL_DUCKING ) == 0 && !player->m_Local.m_bDucking && !player->m_Local.m_bDucked )
+ {
+
+ player->SetViewOffset( VEC_VIEW_SCALED( player ) );
+ }
+ else if ( m_pCSPlayer->m_duckUntilOnGround )
+ {
+ // Duck Hull, but we're in the air. Calculate where the view would be.
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+
+ // We've got the duck hull, pulled up to the top of where the player should be
+ Vector lowerClearance = hullSizeNormal - hullSizeCrouch;
+ Vector duckEyeHeight = GetPlayerViewOffset( false ) - lowerClearance;
+ player->SetViewOffset( duckEyeHeight );
+ }
+ else if( player->m_Local.m_bDucked && !player->m_Local.m_bDucking )
+ {
+ player->SetViewOffset( VEC_DUCK_VIEW );
+ }
+ }
+ }
+#endif
+}
+
+
+void CCSGameMovement::WalkMove( void )
+{
+ if ( m_pCSPlayer->m_flStamina > 0 )
+ {
+ float flRatio;
+
+ flRatio = ( STAMINA_MAX - ( ( m_pCSPlayer->m_flStamina / 1000.0 ) * STAMINA_RECOVER_RATE ) ) / STAMINA_MAX;
+
+ // This Goldsrc code was run with variable timesteps and it had framerate dependencies.
+ // People looking at Goldsrc for reference are usually
+ // (these days) measuring the stoppage at 60fps or greater, so we need
+ // to account for the fact that Goldsrc was applying more stopping power
+ // since it applied the slowdown across more frames.
+ float flReferenceFrametime = 1.0f / 70.0f;
+ float flFrametimeRatio = gpGlobals->frametime / flReferenceFrametime;
+
+ flRatio = pow( flRatio, flFrametimeRatio );
+
+ mv->m_vecVelocity.x *= flRatio;
+ mv->m_vecVelocity.y *= flRatio;
+ }
+
+ BaseClass::WalkMove();
+
+ CheckForLadders( player->GetGroundEntity() != NULL );
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+void CCSGameMovement::AirMove( void )
+{
+ BaseClass::AirMove();
+
+ CheckForLadders( false );
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+bool CCSGameMovement::OnLadder( trace_t &trace )
+{
+ if ( trace.plane.normal.z == 1.0f )
+ return false;
+
+ return BaseClass::OnLadder( trace );
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+bool CCSGameMovement::LadderMove( void )
+{
+ bool isOnLadder = BaseClass::LadderMove();
+ if ( isOnLadder && m_pCSPlayer )
+ {
+ m_pCSPlayer->SurpressLadderChecks( mv->GetAbsOrigin(), m_pCSPlayer->m_vecLadderNormal );
+ }
+
+ return isOnLadder;
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+/**
+ * In CS, crouching up ladders goes slowly and doesn't make a sound.
+ */
+float CCSGameMovement::ClimbSpeed( void ) const
+{
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ return BaseClass::ClimbSpeed() * CS_PLAYER_SPEED_CLIMB_MODIFIER;
+ }
+ else
+ {
+ return BaseClass::ClimbSpeed();
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+/**
+* In CS, strafing on ladders goes slowly.
+*/
+float CCSGameMovement::LadderLateralMultiplier( void ) const
+{
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ return 1.0f;
+ }
+ else
+ {
+ return 0.5f;
+ }
+}
+
+
+//-------------------------------------------------------------------------------------------------------------------------------
+/**
+ * Looks behind and beneath the player in the air, in case he skips out over the top of a ladder. If the
+ * trace hits a ladder, the player is snapped to the ladder.
+ */
+void CCSGameMovement::CheckForLadders( bool wasOnGround )
+{
+ if ( !wasOnGround )
+ {
+ // If we're higher than the last place we were on the ground, bail - obviously we're not dropping
+ // past a ladder we might want to grab.
+ if ( mv->GetAbsOrigin().z > m_pCSPlayer->m_lastStandingPos.z )
+ return;
+
+ Vector dir = -m_pCSPlayer->m_lastStandingPos + mv->GetAbsOrigin();
+ if ( !dir.x && !dir.y )
+ {
+ // If we're dropping straight down, we don't know which way to look for a ladder. Oh well.
+ return;
+ }
+
+ dir.z = 0.0f;
+ float dist = dir.NormalizeInPlace();
+ if ( dist > 64.0f )
+ {
+ // Don't grab ladders too far behind us.
+ return;
+ }
+
+ trace_t trace;
+
+ TracePlayerBBox(
+ mv->GetAbsOrigin(),
+ m_pCSPlayer->m_lastStandingPos - dir*(5+dist),
+ (PlayerSolidMask() & (~CONTENTS_PLAYERCLIP)), COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ if ( trace.fraction != 1.0f && OnLadder( trace ) && trace.plane.normal.z != 1.0f )
+ {
+ if ( m_pCSPlayer->CanGrabLadder( trace.endpos, trace.plane.normal ) )
+ {
+ player->SetMoveType( MOVETYPE_LADDER );
+ player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
+
+ player->SetLadderNormal( trace.plane.normal );
+ mv->m_vecVelocity.Init();
+
+ // The ladder check ignored playerclips, to fix a bug exposed by de_train, where a clipbrush is
+ // flush with a ladder. This causes the above tracehull to fail unless we ignore playerclips.
+ // However, we have to check for playerclips before we snap to that pos, so we don't warp a
+ // player into a clipbrush.
+ TracePlayerBBox(
+ mv->GetAbsOrigin(),
+ m_pCSPlayer->m_lastStandingPos - dir*(5+dist),
+ PlayerSolidMask(), COLLISION_GROUP_PLAYER_MOVEMENT, trace );
+
+ mv->SetAbsOrigin( trace.endpos );
+ }
+ }
+ }
+ else
+ {
+ m_pCSPlayer->m_lastStandingPos = mv->GetAbsOrigin();
+ }
+}
+
+
+void CCSGameMovement::ReduceTimers( void )
+{
+ float frame_msec = 1000.0f * gpGlobals->frametime;
+
+ if ( m_pCSPlayer->m_flStamina > 0 )
+ {
+ m_pCSPlayer->m_flStamina -= frame_msec;
+
+ if ( m_pCSPlayer->m_flStamina < 0 )
+ {
+ m_pCSPlayer->m_flStamina = 0;
+ }
+ }
+
+ BaseClass::ReduceTimers();
+}
+
+ConVar sv_enablebunnyhopping( "sv_enablebunnyhopping", "0", FCVAR_REPLICATED | FCVAR_NOTIFY );
+
+// Only allow bunny jumping up to 1.1x server / player maxspeed setting
+#define BUNNYJUMP_MAX_SPEED_FACTOR 1.1f
+
+// taken from TF2 but changed BUNNYJUMP_MAX_SPEED_FACTOR from 1.1 to 1.0
+void CCSGameMovement::PreventBunnyJumping()
+{
+ // Speed at which bunny jumping is limited
+ float maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * player->m_flMaxspeed;
+ if ( maxscaledspeed <= 0.0f )
+ return;
+
+ // Current player speed
+ float spd = mv->m_vecVelocity.Length();
+
+ if ( spd <= maxscaledspeed )
+ return;
+
+ // Apply this cropping fraction to velocity
+ float fraction = ( maxscaledspeed / spd );
+
+ mv->m_vecVelocity *= fraction;
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CCSGameMovement::CheckJumpButton( void )
+{
+ if (m_pCSPlayer->pl.deadflag)
+ {
+ mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
+ return false;
+ }
+
+ // See if we are waterjumping. If so, decrement count and return.
+ if (m_pCSPlayer->m_flWaterJumpTime)
+ {
+ m_pCSPlayer->m_flWaterJumpTime -= gpGlobals->frametime;
+ if (m_pCSPlayer->m_flWaterJumpTime < 0)
+ m_pCSPlayer->m_flWaterJumpTime = 0;
+
+ return false;
+ }
+
+ // If we are in the water most of the way...
+ if ( m_pCSPlayer->GetWaterLevel() >= 2 )
+ {
+ // swimming, not jumping
+ SetGroundEntity( NULL );
+
+ if(m_pCSPlayer->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
+ mv->m_vecVelocity[2] = 100;
+ else if (m_pCSPlayer->GetWaterType() == CONTENTS_SLIME)
+ mv->m_vecVelocity[2] = 80;
+
+ // play swiming sound
+ if ( m_pCSPlayer->m_flSwimSoundTime <= 0 )
+ {
+ // Don't play sound again for 1 second
+ m_pCSPlayer->m_flSwimSoundTime = 1000;
+ PlaySwimSound();
+ }
+
+ return false;
+ }
+
+ // No more effect
+ if (m_pCSPlayer->GetGroundEntity() == NULL)
+ {
+ mv->m_nOldButtons |= IN_JUMP;
+ return false; // in air, so no effect
+ }
+
+ if ( mv->m_nOldButtons & IN_JUMP )
+ return false; // don't pogo stick
+
+ if ( !sv_enablebunnyhopping.GetBool() )
+ {
+ PreventBunnyJumping();
+ }
+
+ // In the air now.
+ SetGroundEntity( NULL );
+
+ m_pCSPlayer->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->m_pSurfaceData, 1.0, true );
+
+ //MoveHelper()->PlayerSetAnimation( PLAYER_JUMP );
+ m_pCSPlayer->DoAnimationEvent( PLAYERANIMEVENT_JUMP );
+
+ float flGroundFactor = 1.0f;
+ if (player->m_pSurfaceData)
+ {
+ flGroundFactor = player->m_pSurfaceData->game.jumpFactor;
+ }
+
+ // if we weren't ducking, bots and hostages do a crouchjump programatically
+ if ( (!player || player->IsBot()) && !(mv->m_nButtons & IN_DUCK) )
+ {
+ m_pCSPlayer->m_duckUntilOnGround = true;
+ FinishDuck();
+ }
+
+ // Acclerate upward
+ // If we are ducking...
+ float startz = mv->m_vecVelocity[2];
+ if ( m_pCSPlayer->m_duckUntilOnGround || ( m_pCSPlayer->m_Local.m_bDucking ) || ( m_pCSPlayer->GetFlags() & FL_DUCKING ) )
+ {
+ // d = 0.5 * g * t^2 - distance traveled with linear accel
+ // t = sqrt(2.0 * 45 / g) - how long to fall 45 units
+ // v = g * t - velocity at the end (just invert it to jump up that high)
+ // v = g * sqrt(2.0 * 45 / g )
+ // v^2 = g * g * 2.0 * 45 / g
+ // v = sqrt( g * 2.0 * 45 )
+
+ mv->m_vecVelocity[2] = flGroundFactor * sqrt(2 * 800 * 57.0); // 2 * gravity * height
+ }
+ else
+ {
+ mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * 57.0); // 2 * gravity * height
+ }
+
+ if ( m_pCSPlayer->m_flStamina > 0 )
+ {
+ float flRatio;
+
+ flRatio = ( STAMINA_MAX - ( ( m_pCSPlayer->m_flStamina / 1000.0 ) * STAMINA_RECOVER_RATE ) ) / STAMINA_MAX;
+
+ mv->m_vecVelocity[2] *= flRatio;
+ }
+
+ m_pCSPlayer->m_flStamina = ( STAMINA_COST_JUMP / STAMINA_RECOVER_RATE ) * 1000.0;
+
+ FinishGravity();
+
+ mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz;
+ mv->m_outStepHeight += 0.1f;
+
+ OnJump(mv->m_outWishVel.z);
+
+#ifndef CLIENT_DLL
+ // allow bots to react
+ IGameEvent * event = gameeventmanager->CreateEvent( "player_jump" );
+ if ( event )
+ {
+ event->SetInt( "userid", m_pCSPlayer->GetUserID() );
+ gameeventmanager->FireEvent( event );
+ }
+#endif
+
+ // Flag that we jumped.
+ mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
+ return true;
+}
+
+
+void CCSGameMovement::DecayPunchAngle( void )
+{
+ float len;
+
+ Vector vPunchAngle;
+
+ vPunchAngle.x = m_pCSPlayer->m_Local.m_vecPunchAngle->x;
+ vPunchAngle.y = m_pCSPlayer->m_Local.m_vecPunchAngle->y;
+ vPunchAngle.z = m_pCSPlayer->m_Local.m_vecPunchAngle->z;
+
+ len = VectorNormalize ( vPunchAngle );
+ len -= (10.0 + len * 0.5) * gpGlobals->frametime;
+ len = MAX( len, 0.0 );
+ VectorScale ( vPunchAngle, len, vPunchAngle );
+
+ m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 0, vPunchAngle.x );
+ m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 1, vPunchAngle.y );
+ m_pCSPlayer->m_Local.m_vecPunchAngle.Set( 2, vPunchAngle.z );
+}
+
+
+void CCSGameMovement::HandleDuckingSpeedCrop()
+{
+ //=============================================================================
+ // HPE_BEGIN:
+ // [Forrest]
+ //=============================================================================
+ // Movement speed in free look camera mode is unaffected by ducking state.
+ if ( player->GetObserverMode() == OBS_MODE_ROAMING )
+ return;
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) )
+ {
+ if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
+ {
+ mv->m_flForwardMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
+ mv->m_flSideMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
+ mv->m_flUpMove *= CS_PLAYER_SPEED_DUCK_MODIFIER;
+ m_iSpeedCropped |= SPEED_CROPPED_DUCK;
+ }
+ }
+}
+
+bool CCSGameMovement::CanUnduck()
+{
+ trace_t trace;
+ Vector newOrigin;
+
+ VectorCopy( mv->GetAbsOrigin(), newOrigin );
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ newOrigin += VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ }
+ else
+ {
+ // If in air an letting go of croush, make sure we can offset origin to make
+ // up for uncrouching
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+
+ newOrigin += -0.5f * ( hullSizeNormal - hullSizeCrouch );
+ }
+
+ UTIL_TraceHull( mv->GetAbsOrigin(), newOrigin, VEC_HULL_MIN_SCALED( player ), VEC_HULL_MAX_SCALED( player ), PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
+
+ if ( trace.startsolid || ( trace.fraction != 1.0f ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Stop ducking
+//-----------------------------------------------------------------------------
+void CCSGameMovement::FinishUnDuck( void )
+{
+ trace_t trace;
+ Vector newOrigin;
+
+ VectorCopy( mv->GetAbsOrigin(), newOrigin );
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ newOrigin += VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ }
+ else
+ {
+ // If in air an letting go of croush, make sure we can offset origin to make
+ // up for uncrouching
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+
+ Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeCrouch );
+
+ VectorAdd( newOrigin, viewDelta, newOrigin );
+ }
+
+ player->m_Local.m_bDucked = false;
+ player->RemoveFlag( FL_DUCKING );
+ player->m_Local.m_bDucking = false;
+ player->SetViewOffset( GetPlayerViewOffset( false ) );
+ player->m_Local.m_flDucktime = 0;
+
+ mv->SetAbsOrigin( newOrigin );
+
+ // Recategorize position since ducking can change origin
+ CategorizePosition();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finish ducking
+//-----------------------------------------------------------------------------
+void CCSGameMovement::FinishDuck( void )
+{
+
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+
+ Vector viewDelta = 0.5f * ( hullSizeNormal - hullSizeCrouch );
+
+ player->SetViewOffset( GetPlayerViewOffset( true ) );
+ player->AddFlag( FL_DUCKING );
+ player->m_Local.m_bDucking = false;
+
+ if ( !player->m_Local.m_bDucked )
+ {
+
+ Vector org = mv->GetAbsOrigin();
+
+ if ( player->GetGroundEntity() != NULL )
+ {
+ org -= VEC_DUCK_HULL_MIN_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ }
+ else
+ {
+ org += viewDelta;
+ }
+ mv->SetAbsOrigin( org );
+
+ player->m_Local.m_bDucked = true;
+ }
+
+ // See if we are stuck?
+ FixPlayerCrouchStuck( true );
+
+ // Recategorize position since ducking can change origin
+ CategorizePosition();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if duck button is pressed and do the appropriate things
+//-----------------------------------------------------------------------------
+void CCSGameMovement::Duck( void )
+{
+
+ // Fix taken from zblock for rapid crouch/stand not showing stand on other clients
+
+ if ( player->GetFlags() & FL_ONGROUND )
+ {
+ // if prevent crouch
+ if ( !( mv->m_nButtons & IN_DUCK ) && ( mv->m_nOldButtons & IN_DUCK ) )
+ {
+ // Player has released crouch and moving to standing
+ m_fTimeLastUnducked = gpGlobals->curtime;
+ }
+ else if ( ( mv->m_nButtons & IN_DUCK ) && !( mv->m_nOldButtons & IN_DUCK ) )
+ {
+ // Crouch from standing
+ if ( ( player->GetFlags() & FL_DUCKING )
+ && ( m_fTimeLastUnducked > (gpGlobals->curtime - sv_timebetweenducks.GetFloat() ) ) )
+ {
+ // if the server thinks the player is still crouched
+ // AND the time the player started to stand (from being ducked) was less than 300ms ago
+ // prevent the player from ducking again
+ mv->m_nButtons &= ~IN_DUCK;
+ }
+ }
+ }
+
+ int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame
+ int buttonsPressed = buttonsChanged & mv->m_nButtons; // The changed ones still down are "pressed"
+ int buttonsReleased = buttonsChanged & mv->m_nOldButtons; // The changed ones which were previously down are "released"
+
+ // Check to see if we are in the air.
+ bool bInAir = player->GetGroundEntity() == NULL && player->GetMoveType() != MOVETYPE_LADDER;
+
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ mv->m_nOldButtons |= IN_DUCK;
+ }
+ else
+ {
+ mv->m_nOldButtons &= ~IN_DUCK;
+ }
+
+ if ( IsDead() )
+ {
+ // Unduck
+ if ( player->GetFlags() & FL_DUCKING )
+ {
+ FinishUnDuck();
+ }
+ return;
+ }
+
+ HandleDuckingSpeedCrop();
+
+ if ( m_pCSPlayer->m_duckUntilOnGround )
+ {
+ if ( !bInAir )
+ {
+ m_pCSPlayer->m_duckUntilOnGround = false;
+ if ( CanUnduck() )
+ {
+ FinishUnDuck();
+ }
+ return;
+ }
+ else
+ {
+ if ( mv->m_vecVelocity.z > 0.0f )
+ return;
+
+ // Check if we can un-duck. We want to unduck if we have space for the standing hull, and
+ // if it is less than 2 inches off the ground.
+ trace_t trace;
+ Vector newOrigin;
+ Vector groundCheck;
+
+ VectorCopy( mv->GetAbsOrigin(), newOrigin );
+ Vector hullSizeNormal = VEC_HULL_MAX_SCALED( player ) - VEC_HULL_MIN_SCALED( player );
+ Vector hullSizeCrouch = VEC_DUCK_HULL_MAX_SCALED( player ) - VEC_DUCK_HULL_MIN_SCALED( player );
+ newOrigin -= ( hullSizeNormal - hullSizeCrouch );
+ groundCheck = newOrigin;
+ groundCheck.z -= player->GetStepSize();
+
+ UTIL_TraceHull( newOrigin, groundCheck, VEC_HULL_MIN_SCALED( player ), VEC_HULL_MAX_SCALED( player ), PlayerSolidMask(), player, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
+
+ if ( trace.startsolid || trace.fraction == 1.0f )
+ return; // Can't even stand up, or there's no ground underneath us
+
+ m_pCSPlayer->m_duckUntilOnGround = false;
+ if ( CanUnduck() )
+ {
+ FinishUnDuck();
+ }
+ return;
+ }
+ }
+
+ // Holding duck, in process of ducking or fully ducked?
+ if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
+ {
+ if ( mv->m_nButtons & IN_DUCK )
+ {
+ bool alreadyDucked = ( player->GetFlags() & FL_DUCKING ) ? true : false;
+
+ if ( (buttonsPressed & IN_DUCK ) && !( player->GetFlags() & FL_DUCKING ) )
+ {
+ // Use 1 second so super long jump will work
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true;
+ }
+
+ float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
+ float duckseconds = duckmilliseconds / 1000.0f;
+
+ //time = MAX( 0.0, ( 1.0 - (float)player->m_Local.m_flDucktime / 1000.0 ) );
+
+ if ( player->m_Local.m_bDucking )
+ {
+ if ( !( player->GetFlags() & FL_ANIMDUCKING ) )
+ player->AddFlag( FL_ANIMDUCKING );
+
+ // Finish ducking immediately if duck time is over or not on ground
+ if ( ( duckseconds > TIME_TO_DUCK ) ||
+ ( player->GetGroundEntity() == NULL ) ||
+ alreadyDucked)
+ {
+ FinishDuck();
+ }
+ else
+ {
+ // Calc parametric time
+ float duckFraction = SimpleSpline( duckseconds / TIME_TO_DUCK );
+ SetDuckedEyeOffset( duckFraction );
+ }
+ }
+ }
+ else
+ {
+ // Try to unduck unless automovement is not allowed
+ // NOTE: When not onground, you can always unduck
+ if ( player->m_Local.m_bAllowAutoMovement || player->GetGroundEntity() == NULL )
+ {
+ if ( (buttonsReleased & IN_DUCK ) && ( player->GetFlags() & FL_DUCKING ) )
+ {
+ // Use 1 second so super long jump will work
+ player->m_Local.m_flDucktime = 1000;
+ player->m_Local.m_bDucking = true; // or unducking
+ }
+
+ float duckmilliseconds = MAX( 0.0f, 1000.0f - (float)player->m_Local.m_flDucktime );
+ float duckseconds = duckmilliseconds / 1000.0f;
+
+ if ( CanUnduck() )
+ {
+ if ( player->m_Local.m_bDucking ||
+ player->m_Local.m_bDucked ) // or unducking
+ {
+ if ( player->GetFlags() & FL_ANIMDUCKING )
+ player->RemoveFlag( FL_ANIMDUCKING );
+
+ // Finish ducking immediately if duck time is over or not on ground
+ if ( ( duckseconds > TIME_TO_UNDUCK ) ||
+ ( player->GetGroundEntity() == NULL ) )
+ {
+ FinishUnDuck();
+ }
+ else
+ {
+ // Calc parametric time
+ float duckFraction = SimpleSpline( 1.0f - ( duckseconds / TIME_TO_UNDUCK ) );
+ SetDuckedEyeOffset( duckFraction );
+ }
+ }
+ }
+ else
+ {
+ // Still under something where we can't unduck, so make sure we reset this timer so
+ // that we'll unduck once we exit the tunnel, etc.
+ player->m_Local.m_flDucktime = 1000;
+ }
+ }
+ }
+ }
+}
+
+
+void CCSGameMovement::OnJump( float fImpulse )
+{
+ m_pCSPlayer->OnJump( fImpulse );
+}
+
+void CCSGameMovement::OnLand( float fVelocity )
+{
+ m_pCSPlayer->OnLand( fVelocity );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Essentially the same as TracePlayerBBox, but adds a callback to
+// exclude entities that are not standable (except for other players)
+//-----------------------------------------------------------------------------
+void CCSGameMovement::TryTouchGround( const Vector& start, const Vector& end, const Vector& mins, const Vector& maxs, unsigned int fMask, int collisionGroup, trace_t& pm )
+{
+ VPROF( "CCSGameMovement::TryTouchGround" );
+
+ Ray_t ray;
+ ray.Init( start, end, mins, maxs );
+
+ ShouldHitFunc_t pStandingTestCallback = sv_enableboost.GetBool() ? NULL : CheckForStandable;
+
+ UTIL_TraceRay( ray, fMask, mv->m_nPlayerHandle.Get(), collisionGroup, &pm, pStandingTestCallback );
+
+}