|
|
//========= 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 ); }
|