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.
 
 
 
 
 
 

1405 lines
38 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "gamemovement.h"
#include "dod_gamerules.h"
#include "dod_shareddefs.h"
#include "in_buttons.h"
#include "movevars_shared.h"
#include "weapon_dodsniper.h"
#include "weapon_dodbaserpg.h"
#include "weapon_dodsemiauto.h"
#ifdef CLIENT_DLL
#include "c_dod_player.h"
#else
#include "dod_player.h"
#endif
extern bool g_bMovementOptimizations;
class CDODGameMovement : public CGameMovement
{
public:
DECLARE_CLASS( CDODGameMovement, CGameMovement );
CDODGameMovement();
virtual ~CDODGameMovement();
void SetPlayerSpeed( void );
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMove );
virtual bool CanAccelerate();
virtual bool CheckJumpButton( void );
virtual void ReduceTimers( void );
virtual void WalkMove( void );
virtual void AirMove( void );
virtual void CheckParameters( void );
virtual void CheckFalling( void );
// Ducking
virtual void Duck( void );
virtual void FinishUnDuck( void );
virtual void FinishDuck( void );
virtual void HandleDuckingSpeedCrop();
void SetDODDuckedEyeOffset( float duckFraction );
void SetDeployedEyeOffset( void );
// Prone
void SetProneEyeOffset( float proneFraction );
void FinishProne( void );
void FinishUnProne( void );
bool CanUnprone();
virtual Vector GetPlayerMins( void ) const; // uses local player
virtual Vector GetPlayerMaxs( void ) const; // uses local player
// IGameMovement interface
virtual Vector GetPlayerMins( bool ducked ) const { return BaseClass::GetPlayerMins(ducked); }
virtual Vector GetPlayerMaxs( bool ducked ) const { return BaseClass::GetPlayerMaxs(ducked); }
virtual Vector GetPlayerViewOffset( bool ducked ) const { return BaseClass::GetPlayerViewOffset(ducked); }
void ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type );
void SetViewOffset( Vector vecViewOffset );
virtual unsigned int PlayerSolidMask( bool brushOnly = false );
protected:
virtual void PlayerMove();
void CheckForLadders( bool wasOnGround );
bool ResolveStanding( void );
void TracePlayerBBoxWithStep( const Vector &vStart, const Vector &vEnd, unsigned int fMask, int collisionGroup, trace_t &trace );
public:
CDODPlayer *m_pDODPlayer;
bool m_bUnProneToDuck;
};
// Expose our interface.
static CDODGameMovement g_GameMovement;
IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
// ---------------------------------------------------------------------------------------- //
// CDODGameMovement.
// ---------------------------------------------------------------------------------------- //
CDODGameMovement::CDODGameMovement()
{
// Don't set any member variables here, or you'll get an access
// violation exception on LoadLibrary, and will have to stay up til
// 3 in the morning figuring out where you did bad things.
m_bUnProneToDuck = false;
}
CDODGameMovement::~CDODGameMovement()
{
}
void CDODGameMovement::SetPlayerSpeed( void )
{
if( DODGameRules()->State_Get() == STATE_PREROUND )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
return;
}
if ( m_pDODPlayer->m_Shared.IsPlanting() ||
m_pDODPlayer->m_Shared.IsDefusing() )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
return;
}
bool bZoomed = ( m_pDODPlayer->GetFOV() < m_pDODPlayer->GetDefaultFOV() );
bool bBazookaDeployed = false;
bool bZoomingIn = false;
CWeaponDODBase *pWpn = m_pDODPlayer->GetActiveDODWeapon();
if( pWpn )
{
if( pWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_BAZOOKA )
{
CDODBaseRocketWeapon *pBazooka = (CDODBaseRocketWeapon *)pWpn;
bBazookaDeployed = pBazooka->ShouldPlayerBeSlow();
}
if ( pWpn->GetDODWpnData().m_WeaponType == WPN_TYPE_SNIPER )
{
CDODSniperWeapon *pSniper = dynamic_cast<CDODSniperWeapon *>( pWpn );
if ( pSniper )
{
bZoomingIn = !bZoomed && pSniper->IsZoomingIn();
}
}
}
// are we zooming?
if ( m_pDODPlayer->m_Shared.IsInMGDeploy() )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_FROZEN;
}
else if ( m_pDODPlayer->m_Shared.IsProne() &&
!m_pDODPlayer->m_Shared.IsGettingUpFromProne() &&
m_pDODPlayer->GetGroundEntity() != NULL )
{
if ( bZoomed )
mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE_ZOOMED;
else if ( bBazookaDeployed )
mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE_BAZOOKA_DEPLOYED;
else
mv->m_flClientMaxSpeed = PLAYER_SPEED_PRONE; //Base prone speed
}
else //not prone, dead or deployed - standing or crouching and possibly moving
{
float stamina = m_pDODPlayer->m_Shared.GetStamina();
if ( bZoomed )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_ZOOMED;
}
else if ( bBazookaDeployed )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_BAZOOKA_DEPLOYED;
}
else if ( mv->m_nButtons & IN_DUCK )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_RUN; //gets cut in fraction later
}
// check for slowed from leg hit or firing a machine gun
else if ( m_pDODPlayer->m_Shared.GetSlowedTime() > gpGlobals->curtime )
{
mv->m_flClientMaxSpeed = PLAYER_SPEED_SLOWED;
}
else
{
float flMaxSpeed;
if ( ( mv->m_nButtons & IN_SPEED ) && ( stamina > 0 ) && ( mv->m_nButtons & IN_FORWARD ) && !bZoomingIn )
{
flMaxSpeed = PLAYER_SPEED_SPRINT; //sprinting
}
else
{
flMaxSpeed = PLAYER_SPEED_RUN; //jogging
}
mv->m_flClientMaxSpeed = flMaxSpeed - 100 + stamina;
}
}
if ( m_pDODPlayer->GetGroundEntity() != NULL )
{
if( m_pDODPlayer->m_Shared.IsGoingProne() )
{
float pronetime = m_pDODPlayer->m_Shared.m_flGoProneTime - gpGlobals->curtime;
//interp to prone speed
float flProneFraction = SimpleSpline( pronetime / TIME_TO_PRONE );
float maxSpeed = mv->m_flClientMaxSpeed;
if ( m_bUnProneToDuck )
maxSpeed *= 0.33;
mv->m_flClientMaxSpeed = ( ( 1 - flProneFraction ) * PLAYER_SPEED_PRONE ) + ( flProneFraction * maxSpeed );
}
else if( m_pDODPlayer->m_Shared.IsGettingUpFromProne() )
{
float pronetime = m_pDODPlayer->m_Shared.m_flUnProneTime - gpGlobals->curtime;
//interp to regular speed speed
float flProneFraction = SimpleSpline( pronetime / TIME_TO_PRONE );
float maxSpeed = mv->m_flClientMaxSpeed;
if ( m_bUnProneToDuck )
maxSpeed *= 0.33;
mv->m_flClientMaxSpeed = ( flProneFraction * PLAYER_SPEED_PRONE ) + ( ( 1 - flProneFraction ) * maxSpeed );
}
}
}
ConVar cl_show_speed( "cl_show_speed", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "spam console with local player speed" );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODGameMovement::CheckParameters( void )
{
QAngle v_angle;
SetPlayerSpeed();
if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
player->GetMoveType() != MOVETYPE_NOCLIP &&
player->GetMoveType() != MOVETYPE_OBSERVER )
{
float spd;
float maxspeed;
spd = ( mv->m_flForwardMove * mv->m_flForwardMove ) +
( mv->m_flSideMove * mv->m_flSideMove ) +
( mv->m_flUpMove * mv->m_flUpMove );
maxspeed = mv->m_flClientMaxSpeed;
if ( maxspeed != 0.0 )
{
mv->m_flMaxSpeed = MIN( maxspeed, mv->m_flMaxSpeed );
}
// Slow down by the speed factor
float flSpeedFactor = 1.0f;
if ( player->GetSurfaceData() )
{
flSpeedFactor = player->GetSurfaceData()->game.maxSpeedFactor;
}
// If we have a constraint, slow down because of that too.
float flConstraintSpeedFactor = ComputeConstraintSpeedFactor();
if (flConstraintSpeedFactor < flSpeedFactor)
flSpeedFactor = flConstraintSpeedFactor;
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() )
{
SetViewOffset( VEC_DEAD_VIEWHEIGHT_SCALED( player ) );
}
// Adjust client view angles to match values used on server.
if ( mv->m_vecAngles[YAW] > 180.0f )
{
mv->m_vecAngles[YAW] -= 360.0f;
}
if ( cl_show_speed.GetBool() )
{
Vector vel = m_pDODPlayer->GetAbsVelocity();
float actual_speed = sqrt( vel.x * vel.x + vel.y * vel.y );
Msg( "player speed %.1f\n",actual_speed );
}
}
void CDODGameMovement::CheckFalling( void )
{
// if we landed on the ground
if ( player->GetGroundEntity() != NULL && !IsDead() )
{
if ( player->m_Local.m_flFallVelocity >= 300 )
{
CPASFilter filter( player->GetAbsOrigin() );
filter.UsePredictionRules();
player->EmitSound( filter, player->entindex(), "Player.JumpLanding" );
}
// turn off the jumping flag if we're on ground after a jump
if ( m_pDODPlayer->m_Shared.IsJumping() )
{
m_pDODPlayer->m_Shared.SetJumping( false );
// if we landed from a jump, slow us
if ( player->m_Local.m_flFallVelocity > 50 )
m_pDODPlayer->m_Shared.SetSlowedTime( 0.5 );
}
}
BaseClass::CheckFalling();
}
void CDODGameMovement::ProcessMovement( CBasePlayer *pBasePlayer, CMoveData *pMove )
{
//Store the player pointer
m_pDODPlayer = ToDODPlayer( pBasePlayer );
Assert( m_pDODPlayer );
m_pDODPlayer->m_Shared.ViewAnimThink();
BaseClass::ProcessMovement( pBasePlayer, pMove );
}
bool CDODGameMovement::CanAccelerate()
{
// Only allow the player to accelerate when in certain states.
DODPlayerState curState = m_pDODPlayer->State_Get();
if ( curState == STATE_ACTIVE )
{
return player->GetWaterJumpTime() == 0;
}
else if ( player->IsObserver() )
{
return true;
}
else
{
return false;
}
}
void CDODGameMovement::PlayerMove()
{
BaseClass::PlayerMove();
if ( player->GetMoveType() != MOVETYPE_ISOMETRIC &&
player->GetMoveType() != MOVETYPE_NOCLIP &&
player->GetMoveType() != MOVETYPE_OBSERVER )
{
// Cap actual player speed, fix wall running
float spd = mv->m_vecVelocity[0] * mv->m_vecVelocity[0] +
mv->m_vecVelocity[1] * mv->m_vecVelocity[1];
if( spd > 0.0 && spd > ( mv->m_flMaxSpeed * mv->m_flMaxSpeed ) )
{
float fRatio = mv->m_flMaxSpeed / sqrt( spd );
mv->m_vecVelocity[0] *= fRatio;
mv->m_vecVelocity[1] *= fRatio;
}
}
}
void CDODGameMovement::WalkMove( void )
{
float flSpeed = m_pDODPlayer->GetAbsVelocity().Length2D();
bool bSprintButtonPressed = ( mv->m_nButtons & IN_SPEED ) > 0;
if( bSprintButtonPressed &&
( mv->m_nButtons & IN_FORWARD ) &&
!m_pDODPlayer->m_Shared.IsProne() &&
!m_pDODPlayer->m_Shared.IsDucking() &&
flSpeed > 80 )
{
m_pDODPlayer->SetSprinting( true );
}
else
{
m_pDODPlayer->SetSprinting( false );
}
BaseClass::WalkMove();
//CheckForLadders( true );
//ResolveStanding();
}
//-----------------------------------------------------------------------------
// Purpose: Allow bots etc to use slightly different solid masks
//-----------------------------------------------------------------------------
unsigned int CDODGameMovement::PlayerSolidMask( bool brushOnly )
{
int mask = 0;
switch ( m_pDODPlayer->GetTeamNumber() )
{
case TEAM_ALLIES:
mask = CONTENTS_TEAM1;
break;
case TEAM_AXIS:
mask = CONTENTS_TEAM2;
break;
}
return ( mask | BaseClass::PlayerSolidMask( brushOnly ) );
}
void CDODGameMovement::AirMove( void )
{
BaseClass::AirMove();
//CheckForLadders( false );
}
void CDODGameMovement::CheckForLadders( bool wasOnGround )
{
if ( !wasOnGround || !ResolveStanding() )
{
trace_t trace;
TracePlayerBBox( mv->GetAbsOrigin(), mv->GetAbsOrigin() + Vector( 0, 0, -5), MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
if ( trace.fraction == 1.0f )
{
Vector vel = -m_pDODPlayer->m_lastStandingPos + mv->GetAbsOrigin();
if ( !vel.x && !vel.y )
{
return;
}
vel.NormalizeInPlace();
vel *= 5.0f;
Vector vecStartPos( mv->GetAbsOrigin().x + vel.x, mv->GetAbsOrigin().y + vel.y, mv->GetAbsOrigin().z );
vel *= 5.0f;
Vector vecStandPos( mv->GetAbsOrigin().x - vel.x, mv->GetAbsOrigin().y - vel.y, mv->GetAbsOrigin().z - ( player->m_Local.m_flStepSize * 1.0f ) );
TracePlayerBBoxWithStep( vecStartPos, vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
if ( trace.fraction != 1.0f && OnLadder( trace ) && trace.plane.normal.z != 1.0f )
{
if ( trace.fraction > 0.6 )
{
vel.NormalizeInPlace();
Vector org = mv->GetAbsOrigin();
org -= vel*5;
mv->SetAbsOrigin( org );
}
player->SetMoveType( MOVETYPE_LADDER );
player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
player->SetLadderNormal( trace.plane.normal );
mv->m_vecVelocity.Init();
}
}
}
else
{
m_pDODPlayer->m_lastStandingPos = mv->GetAbsOrigin();
}
}
inline void CDODGameMovement::TracePlayerBBoxWithStep( const Vector &vStart, const Vector &vEnd,
unsigned int fMask, int collisionGroup, trace_t &trace )
{
VPROF( "CDODGameMovement::TracePlayerBBoxWithStep" );
Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
vHullMin.z += player->m_Local.m_flStepSize;
Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
Ray_t ray;
ray.Init( vStart, vEnd, vHullMin, vHullMax );
UTIL_TraceRay( ray, fMask, mv->m_nPlayerHandle.Get(), collisionGroup, &trace );
}
// Taken from TF2 to prevent bouncing down slopes
bool CDODGameMovement::ResolveStanding( void )
{
VPROF( "CDODGameMovement::ResolveStanding" );
//
// Attempt to move down twice your step height. Anything between 0.5 and 1.0
// is a valid "stand" value.
//
// Matt - don't move twice your step height, only check a little bit down
// this will keep us relatively glued to stairs without feeling too snappy
float flMaxStepDrop = 8.0f;
Vector vecStandPos( mv->GetAbsOrigin().x, mv->GetAbsOrigin().y, mv->GetAbsOrigin().z - ( flMaxStepDrop ) );
trace_t trace;
TracePlayerBBoxWithStep( mv->GetAbsOrigin(), vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
// Anything between 0.5 and 1.0 is a valid stand value
if ( fabs( trace.fraction - 0.5 ) < 0.0004f )
{
return true;
}
if ( trace.fraction > 0.5f )
{
trace.fraction -= 0.5f;
Vector vecNewOrigin;
vecNewOrigin = mv->GetAbsOrigin() + trace.fraction * ( vecStandPos - mv->GetAbsOrigin() );
mv->SetAbsOrigin( vecNewOrigin );
return false;
}
// Less than 0.5 mean we need to attempt to push up the difference.
vecStandPos.z = ( mv->GetAbsOrigin().z + ( ( 0.5f - trace.fraction ) * ( player->m_Local.m_flStepSize * 2.0f ) ) );
TracePlayerBBoxWithStep( mv->GetAbsOrigin(), vecStandPos, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
// A fraction of 1.0 means we stood up fine - done.
if ( trace.fraction == 1.0f )
{
mv->SetAbsOrigin( trace.endpos );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Recover stamina
//-----------------------------------------------------------------------------
void CDODGameMovement::ReduceTimers( void )
{
Vector vecPlayerVelocity = m_pDODPlayer->GetAbsVelocity();
float flStamina = m_pDODPlayer->m_Shared.GetStamina();
float fl2DVelocitySquared = vecPlayerVelocity.x * vecPlayerVelocity.x +
vecPlayerVelocity.y * vecPlayerVelocity.y;
if ( !( mv->m_nButtons & IN_SPEED ) )
{
m_pDODPlayer->m_Shared.ResetSprintPenalty();
}
// Can only sprint in forward direction.
bool bSprinting = ( (mv->m_nButtons & IN_SPEED) && ( mv->m_nButtons & IN_FORWARD ) );
// If we're holding the sprint key and also actually moving, remove some stamina
Vector vel = m_pDODPlayer->GetAbsVelocity();
if ( bSprinting && fl2DVelocitySquared > 10000 ) //speed > 100
{
//flStamina -= 30 * gpGlobals->frametime; //reduction for sprinting
//flStamina += 10 * gpGlobals->frametime; //addition for recovering
flStamina -= 20 * gpGlobals->frametime;
m_pDODPlayer->m_Shared.SetStamina( flStamina );
}
else
{
//gain some back
if ( fl2DVelocitySquared <= 0 )
{
flStamina += 60 * gpGlobals->frametime;
}
else if ( ( m_pDODPlayer->GetFlags() & FL_ONGROUND ) &&
( mv->m_nButtons & IN_DUCK ) &&
( m_pDODPlayer->GetFlags() & FL_DUCKING ) )
{
flStamina += 50 * gpGlobals->frametime;
}
else
{
flStamina += 10 * gpGlobals->frametime;
}
m_pDODPlayer->m_Shared.SetStamina( flStamina );
}
#ifdef CLIENT_DLL
if ( bSprinting && flStamina < 25 )
{
m_pDODPlayer->HintMessage( HINT_LOW_STAMINA );
}
#endif
BaseClass::ReduceTimers();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CDODGameMovement::CheckJumpButton( void )
{
if (m_pDODPlayer->pl.deadflag)
{
mv->m_nOldButtons |= IN_JUMP ; // don't jump again until released
return false;
}
if( m_pDODPlayer->m_Shared.IsProne() ||
m_pDODPlayer->m_Shared.IsGettingUpFromProne() ||
m_pDODPlayer->m_Shared.IsGoingProne() )
{
mv->m_nOldButtons |= IN_JUMP;
return false;
}
// See if we are waterjumping. If so, decrement count and return.
float flWaterJumpTime = player->GetWaterJumpTime();
if ( flWaterJumpTime > 0 )
{
flWaterJumpTime -= gpGlobals->frametime;
if (flWaterJumpTime < 0)
flWaterJumpTime = 0;
player->SetWaterJumpTime( flWaterJumpTime );
return false;
}
// If we are in the water most of the way...
if ( m_pDODPlayer->GetWaterLevel() >= 2 )
{
// swimming, not jumping
SetGroundEntity( NULL );
if(m_pDODPlayer->GetWaterType() == CONTENTS_WATER) // We move up a certain amount
mv->m_vecVelocity[2] = 100;
else if (m_pDODPlayer->GetWaterType() == CONTENTS_SLIME)
mv->m_vecVelocity[2] = 80;
// play swiming sound
if ( player->GetSwimSoundTime() <= 0 )
{
// Don't play sound again for 1 second
player->SetSwimSoundTime( 1000 );
PlaySwimSound();
}
return false;
}
// No more effect
if (m_pDODPlayer->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( m_pDODPlayer->m_Shared.IsInMGDeploy() )
{
return false;
}
// In the air now.
SetGroundEntity( NULL );
m_pDODPlayer->PlayStepSound( (Vector &)mv->GetAbsOrigin(), player->GetSurfaceData(), 1.0, true );
m_pDODPlayer->DoAnimationEvent( PLAYERANIMEVENT_JUMP );
// make the jump sound
CPASFilter filter( m_pDODPlayer->GetAbsOrigin() );
filter.UsePredictionRules();
m_pDODPlayer->EmitSound( filter, m_pDODPlayer->entindex(), "Player.Jump" );
float flGroundFactor = 1.0f;
if ( player->GetSurfaceData() )
{
flGroundFactor = player->GetSurfaceData()->game.jumpFactor;
}
/*
// old and busted
float flStamina = m_pDODPlayer->m_Shared.GetStamina();
//15.0 is the base height. the player will always jump this high
//regardless of stamina. Also the player will be able to jump max height
//until he is below 60 stamina. Then the height will decrease proportionately
float flJumpSpeed = 15.0; //base jump height
if( flStamina >= 60.0f )
{
flJumpSpeed += 30.0;
}
else
{
flJumpSpeed += (30.0 * ( flStamina / 60.0f ) );
}
//Remove stamina for a successful jump
m_pDODPlayer->m_Shared.SetStamina( flStamina - 40 );
*/
// new hotness - constant jumpspeed of 45
//m_pDODPlayer->m_Shared.SetSlowedTime( 1.0f );
Assert( GetCurrentGravity() == 800.0f );
// Accelerate upward
// If we are ducking...
float startz = mv->m_vecVelocity[2];
if ( ( m_pDODPlayer->m_Local.m_bDucking ) || ( m_pDODPlayer->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 * 268.3281572999747f; // flJumpSpeed of 45
//mv->m_vecVelocity[2] = flGroundFactor * sqrt(2 * 800 * flJumpSpeed); // 2 * gravity * height
}
else
{
mv->m_vecVelocity[2] += flGroundFactor * 268.3281572999747f; // flJumpSpeed of 45
//mv->m_vecVelocity[2] += flGroundFactor * sqrt(2 * 800 * flJumpSpeed); // 2 * gravity * height
}
FinishGravity();
mv->m_outWishVel.z += mv->m_vecVelocity[2] - startz;
mv->m_outStepHeight += 0.1f;
// Flag that we jumped.
mv->m_nOldButtons |= IN_JUMP; // don't jump again until released
m_pDODPlayer->m_Shared.SetJumping( true );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Limit speed if we are ducking
//-----------------------------------------------------------------------------
void CDODGameMovement::HandleDuckingSpeedCrop()
{
if ( !( m_iSpeedCropped & SPEED_CROPPED_DUCK ) )
{
if ( ( mv->m_nButtons & IN_DUCK ) || ( player->m_Local.m_bDucking ) || ( player->GetFlags() & FL_DUCKING ) )
{
float frac = 0.33333333f;
mv->m_flForwardMove *= frac;
mv->m_flSideMove *= frac;
mv->m_flUpMove *= frac;
m_iSpeedCropped |= SPEED_CROPPED_DUCK;
}
}
}
bool CDODGameMovement::CanUnprone()
{
int i;
trace_t trace;
Vector newOrigin;
VectorCopy( mv->GetAbsOrigin(), newOrigin );
Vector vecMins, vecMaxs;
if ( mv->m_nButtons & IN_DUCK )
{
vecMins = VEC_DUCK_HULL_MIN_SCALED( player );
vecMaxs = VEC_DUCK_HULL_MAX_SCALED( player );
}
else
{
vecMins = VEC_HULL_MIN_SCALED( player );
vecMaxs = VEC_HULL_MAX_SCALED( player );
}
if ( player->GetGroundEntity() != NULL )
{
for ( i = 0; i < 3; i++ )
{
newOrigin[i] += ( VEC_PRONE_HULL_MIN_SCALED( player )[i] - vecMins[i] );
}
}
else
{
// If in air an letting go of crouch, make sure we can offset origin to make
// up for uncrouching
Vector hullSizeNormal = vecMaxs - vecMins;
Vector hullSizeProne = VEC_PRONE_HULL_MAX_SCALED( player ) - VEC_PRONE_HULL_MIN_SCALED( player );
Vector viewDelta = -0.5f * ( hullSizeNormal - hullSizeProne );
VectorAdd( newOrigin, viewDelta, newOrigin );
}
bool saveprone = m_pDODPlayer->m_Shared.IsProne();
bool saveducked = player->m_Local.m_bDucked;
// pretend we're not prone
m_pDODPlayer->m_Shared.SetProne( false );
if ( mv->m_nButtons & IN_DUCK )
player->m_Local.m_bDucked = true;
TracePlayerBBox( mv->GetAbsOrigin(), newOrigin, MASK_PLAYERSOLID, COLLISION_GROUP_PLAYER_MOVEMENT, trace );
// revert to reality
m_pDODPlayer->m_Shared.SetProne( saveprone );
player->m_Local.m_bDucked = saveducked;
if ( trace.startsolid || ( trace.fraction != 1.0f ) )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Stop ducking
//-----------------------------------------------------------------------------
void CDODGameMovement::FinishUnDuck( void )
{
int i;
trace_t trace;
Vector newOrigin;
VectorCopy( mv->GetAbsOrigin(), newOrigin );
if ( player->GetGroundEntity() != NULL )
{
for ( i = 0; i < 3; i++ )
{
newOrigin[i] += ( VEC_DUCK_HULL_MIN_SCALED( player )[i] - VEC_HULL_MIN_SCALED( player )[i] );
}
}
else
{
// If in air an letting go of crouch, make sure we can offset origin to make
// up for uncrouching
// orange box patch - made this match the check in CanUnduck()
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 = ( hullSizeNormal - hullSizeCrouch );
viewDelta.Negate();
VectorAdd( newOrigin, viewDelta, newOrigin );
}
player->m_Local.m_bDucked = false;
player->RemoveFlag( FL_DUCKING );
player->m_Local.m_bDucking = false;
SetViewOffset( GetPlayerViewOffset( false ) );
player->m_Local.m_flDucktime = 0;
mv->SetAbsOrigin( newOrigin );
// Recategorize position since ducking can change origin
CategorizePosition();
}
//-----------------------------------------------------------------------------
// Purpose: Finish ducking
//-----------------------------------------------------------------------------
void CDODGameMovement::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 );
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
{
VectorAdd( org, viewDelta, org );
}
mv->SetAbsOrigin( org );
player->m_Local.m_bDucked = true;
}
// See if we are stuck?
FixPlayerCrouchStuck( true );
// Recategorize position since ducking can change origin
CategorizePosition();
}
// Being deployed or undeploying totally stomps the duck view offset
void CDODGameMovement::SetDeployedEyeOffset( void )
{
if ( m_pDODPlayer->m_Shared.IsProne() || m_pDODPlayer->m_Shared.IsGettingUpFromProne() )
return;
if ( !m_pDODPlayer->IsAlive() )
return;
float flTimeSinceDeployChange = gpGlobals->curtime - m_pDODPlayer->m_Shared.m_flDeployChangeTime;
if ( m_pDODPlayer->m_Shared.IsInMGDeploy() || flTimeSinceDeployChange < TIME_TO_DEPLOY )
{
if ( m_pDODPlayer->m_Shared.IsInMGDeploy() )
{
// anim to deployed
if ( m_pDODPlayer->m_Shared.GetLastViewAnimTime() < m_pDODPlayer->m_Shared.m_flDeployChangeTime.m_Value )
{
// Deployed height
float flViewOffset = clamp( m_pDODPlayer->m_Shared.GetDeployedHeight(),
CROUCHING_DEPLOY_HEIGHT,
STANDING_DEPLOY_HEIGHT );
Vector vecView = player->GetViewOffset();
vecView.z = flViewOffset;
ViewOffsetAnimation( vecView, TIME_TO_DEPLOY, VIEW_ANIM_LINEAR_Z_ONLY );
m_pDODPlayer->m_Shared.SetLastViewAnimTime( gpGlobals->curtime );
}
}
else
{
// anim to undeployed
if ( m_pDODPlayer->m_Shared.GetLastViewAnimTime() < m_pDODPlayer->m_Shared.m_flDeployChangeTime.m_Value )
{
ViewOffsetAnimation( GetPlayerViewOffset( player->m_Local.m_bDucked ), TIME_TO_DEPLOY, VIEW_ANIM_LINEAR_Z_ONLY );
m_pDODPlayer->m_Shared.SetLastViewAnimTime( gpGlobals->curtime );
}
}
if ( flTimeSinceDeployChange >= TIME_TO_DEPLOY )
{
player->m_Local.m_bDucked = false;
player->RemoveFlag( FL_DUCKING );
player->m_Local.m_bDucking = false;
player->m_Local.m_flDucktime = 0;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : duckFraction -
//-----------------------------------------------------------------------------
void CDODGameMovement::SetDODDuckedEyeOffset( float duckFraction )
{
// Different from CGameMovement in that
Vector vDuckHullMin = GetPlayerMins( true );
Vector vStandHullMin = GetPlayerMins( false );
float fMore = ( vDuckHullMin.z - vStandHullMin.z );
Vector vecStandViewOffset = GetPlayerViewOffset( false );
Vector vecDuckViewOffset = GetPlayerViewOffset( true );
Vector temp = player->GetViewOffset();
temp.z = ( ( vecDuckViewOffset.z - fMore ) * duckFraction ) +
( vecStandViewOffset.z * ( 1 - duckFraction ) );
SetViewOffset( temp );
}
void CDODGameMovement::SetProneEyeOffset( float proneFraction )
{
Vector vecPropViewOffset = VEC_PRONE_VIEW;
Vector vecStandViewOffset = GetPlayerViewOffset( player->m_Local.m_bDucked );
Vector temp = player->GetViewOffset();
temp.z = SimpleSplineRemapVal( proneFraction, 1.0, 0.0, vecPropViewOffset.z, vecStandViewOffset.z );
SetViewOffset( temp );
}
void CDODGameMovement::FinishUnProne( void )
{
m_pDODPlayer->m_Shared.m_flUnProneTime = 0.0f;
SetProneEyeOffset( 0.0 );
Vector vHullMin = GetPlayerMins( player->m_Local.m_bDucked );
Vector vHullMax = GetPlayerMaxs( player->m_Local.m_bDucked );
if ( m_bUnProneToDuck )
{
FinishDuck();
}
else
{
CategorizePosition();
if ( mv->m_nButtons & 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;
}
}
}
void CDODGameMovement::FinishProne( void )
{
m_pDODPlayer->m_Shared.SetProne( true );
m_pDODPlayer->m_Shared.m_flGoProneTime = 0.0f;
#ifndef CLIENT_DLL
m_pDODPlayer->HintMessage( HINT_PRONE );
#endif
FinishUnDuck(); // clear ducking
SetProneEyeOffset( 1.0 );
FixPlayerCrouchStuck(true);
CategorizePosition();
}
//-----------------------------------------------------------------------------
// Purpose: See if duck button is pressed and do the appropriate things
//-----------------------------------------------------------------------------
void CDODGameMovement::Duck( void )
{
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"
if ( mv->m_nButtons & IN_DUCK )
{
mv->m_nOldButtons |= IN_DUCK;
}
else
{
mv->m_nOldButtons &= ~IN_DUCK;
}
if ( !player->IsAlive() )
{
if( m_pDODPlayer->m_Shared.IsProne() )
{
FinishUnProne();
}
// Unduck
if ( player->m_Local.m_bDucking || player->m_Local.m_bDucked )
{
FinishUnDuck();
}
return;
}
static int iState = 0;
// Prone / UnProne - we don't duck or deploy if this is happening
if( m_pDODPlayer->m_Shared.m_flUnProneTime > 0.0f )
{
float pronetime = m_pDODPlayer->m_Shared.m_flUnProneTime - gpGlobals->curtime;
if( pronetime < 0 )
{
FinishUnProne();
if ( !m_bUnProneToDuck && ( mv->m_nButtons & IN_DUCK ) )
{
buttonsPressed |= IN_DUCK;
mv->m_nOldButtons &= ~IN_DUCK;
}
}
// Set these, so that as soon as we stop unproning, we don't pop to standing
// the information that we let go of the duck key has been lost by now.
if ( m_bUnProneToDuck )
{
player->m_Local.m_flDucktime = 1000;
player->m_Local.m_bDucking = true;
}
//don't deal with ducking while we're proning
return;
}
else if( m_pDODPlayer->m_Shared.m_flGoProneTime > 0.0f )
{
float pronetime = m_pDODPlayer->m_Shared.m_flGoProneTime - gpGlobals->curtime;
if( pronetime < 0 )
{
FinishProne();
}
//don't deal with ducking while we're proning
return;
}
if ( gpGlobals->curtime > m_pDODPlayer->m_Shared.m_flNextProneCheck )
{
if ( buttonsPressed & IN_ALT1 && m_pDODPlayer->m_Shared.CanChangePosition() )
{
if( m_pDODPlayer->m_Shared.IsProne() == false &&
m_pDODPlayer->m_Shared.IsGettingUpFromProne() == false )
{
m_pDODPlayer->m_Shared.StartGoingProne();
// do unprone anim
ViewOffsetAnimation( VEC_PRONE_VIEW, TIME_TO_PRONE, VIEW_ANIM_EXPONENTIAL_Z_ONLY );
}
else if( CanUnprone() )
{
m_pDODPlayer->m_Shared.SetProne( false );
m_pDODPlayer->m_Shared.StandUpFromProne();
// do unprone anim
ViewOffsetAnimation( GetPlayerViewOffset( m_bUnProneToDuck ),
TIME_TO_PRONE,
VIEW_ANIM_EXPONENTIAL_Z_ONLY );
m_bUnProneToDuck = ( mv->m_nButtons & IN_DUCK ) > 0;
}
m_pDODPlayer->m_Shared.m_flNextProneCheck = gpGlobals->curtime + 1.0f;
return;
}
}
SetDeployedEyeOffset();
if ( m_pDODPlayer->m_Shared.IsProne() &&
m_pDODPlayer->m_Shared.CanChangePosition() &&
!m_pDODPlayer->m_Shared.IsGettingUpFromProne() &&
( buttonsPressed & IN_DUCK ) &&
CanUnprone() ) // BUGBUG - even calling this will unzoom snipers.
{
// If the player presses duck while prone,
// unprone them to the duck position
m_pDODPlayer->m_Shared.SetProne( false );
m_pDODPlayer->m_Shared.StandUpFromProne();
m_bUnProneToDuck = true;
// do unprone anim
ViewOffsetAnimation( GetPlayerViewOffset( m_bUnProneToDuck ),
TIME_TO_PRONE,
VIEW_ANIM_EXPONENTIAL_Z_ONLY );
// simulate a duck that was pressed while we were prone
player->AddFlag( FL_DUCKING );
player->m_Local.m_bDucked = true;
player->m_Local.m_flDucktime = 1000;
player->m_Local.m_bDucking = true;
}
// no ducking or unducking while deployed or prone
if( m_pDODPlayer->m_Shared.IsProne() ||
m_pDODPlayer->m_Shared.IsGettingUpFromProne() ||
!m_pDODPlayer->m_Shared.CanChangePosition() )
{
return;
}
HandleDuckingSpeedCrop();
if ( !( player->GetFlags() & FL_DUCKING ) && ( player->m_Local.m_bDucked ) )
{
player->m_Local.m_bDucked = false;
}
/*
Msg( "duck button %s ducking %s ducked %s duck flags %s\n",
( mv->m_nButtons & IN_DUCK ) ? "down" : "up",
( player->m_Local.m_bDucking ) ? "yes" : "no",
( player->m_Local.m_bDucked ) ? "yes" : "no",
( player->GetFlags() & FL_DUCKING ) ? "set" : "not set" );*/
// 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 )
{
// 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 flDuckFraction = SimpleSpline( duckseconds / TIME_TO_DUCK );
SetDODDuckedEyeOffset( flDuckFraction );
}
}
}
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
{
// 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 ) );
SetDODDuckedEyeOffset( 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;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CDODGameMovement::GetPlayerMins( void ) const
{
if ( !player )
{
return vec3_origin;
}
if ( player->IsObserver() )
{
return VEC_OBS_HULL_MIN_SCALED( player );
}
else
{
if ( player->m_Local.m_bDucked )
return VEC_DUCK_HULL_MIN_SCALED( player );
else if ( m_pDODPlayer->m_Shared.IsProne() )
return VEC_PRONE_HULL_MIN_SCALED( player );
else
return VEC_HULL_MIN_SCALED( player );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CDODGameMovement::GetPlayerMaxs( void ) const
{
if ( !player )
{
return vec3_origin;
}
if ( player->IsObserver() )
{
return VEC_OBS_HULL_MAX_SCALED( player );
}
else
{
if ( player->m_Local.m_bDucked )
return VEC_DUCK_HULL_MAX_SCALED( player );
else if ( m_pDODPlayer->m_Shared.IsProne() )
return VEC_PRONE_HULL_MAX_SCALED( player );
else
return VEC_HULL_MAX_SCALED( player );
}
}
void CDODGameMovement::SetViewOffset( Vector vecViewOffset )
{
// call this instead of player->SetViewOffset directly, so we can cancel any
// animation in progress
m_pDODPlayer->m_Shared.ResetViewOffsetAnimation();
player->SetViewOffset( vecViewOffset );
}
void CDODGameMovement::ViewOffsetAnimation( Vector vecDest, float flTime, ViewAnimationType type )
{
m_pDODPlayer->m_Shared.ViewOffsetAnimation( vecDest, flTime, type );
}