//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
# include "cbase.h"
# include "gamemovement.h"
# include "in_buttons.h"
# include <stdarg.h>
# include "movevars_shared.h"
# include "engine/IEngineTrace.h"
# include "SoundEmitterSystem/isoundemittersystembase.h"
# include "decals.h"
# include "coordsize.h"
# include "rumble_shared.h"
# if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
# include "hl_movedata.h"
# endif
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
# define STOP_EPSILON 0.1
# define MAX_CLIP_PLANES 5
# include "filesystem.h"
# include <stdarg.h>
extern IFileSystem * filesystem ;
# ifndef CLIENT_DLL
# include "env_player_surface_trigger.h"
static ConVar dispcoll_drawplane ( " dispcoll_drawplane " , " 0 " ) ;
# endif
// tickcount currently isn't set during prediction, although gpGlobals->curtime and
// gpGlobals->frametime are. We should probably set tickcount (to player->m_nTickBase),
// but we're REALLY close to shipping, so we can change that later and people can use
// player->CurrentCommandNumber() in the meantime.
# define tickcount USE_PLAYER_CURRENT_COMMAND_NUMBER__INSTEAD_OF_TICKCOUNT
# if defined( HL2_DLL )
ConVar xc_uncrouch_on_jump ( " xc_uncrouch_on_jump " , " 1 " , FCVAR_ARCHIVE , " Uncrouch when jump occurs " ) ;
# endif
# if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
ConVar player_limit_jump_speed ( " player_limit_jump_speed " , " 1 " , FCVAR_REPLICATED ) ;
# endif
// option_duck_method is a carrier convar. Its sole purpose is to serve an easy-to-flip
// convar which is ONLY set by the X360 controller menu to tell us which way to bind the
// duck controls. Its value is meaningless anytime we don't have the options window open.
ConVar option_duck_method ( " option_duck_method " , " 1 " , FCVAR_REPLICATED | FCVAR_ARCHIVE ) ; // 0 = HOLD to duck, 1 = Duck is a toggle
# ifdef STAGING_ONLY
# ifdef CLIENT_DLL
ConVar debug_latch_reset_onduck ( " debug_latch_reset_onduck " , " 1 " , FCVAR_CHEAT ) ;
# endif
# endif
// [MD] I'll remove this eventually. For now, I want the ability to A/B the optimizations.
bool g_bMovementOptimizations = true ;
// Roughly how often we want to update the info about the ground surface we're on.
// We don't need to do this very often.
# define CATEGORIZE_GROUND_SURFACE_INTERVAL 0.3f
# define CATEGORIZE_GROUND_SURFACE_TICK_INTERVAL ( (int)( CATEGORIZE_GROUND_SURFACE_INTERVAL / TICK_INTERVAL ) )
# define CHECK_STUCK_INTERVAL 1.0f
# define CHECK_STUCK_TICK_INTERVAL ( (int)( CHECK_STUCK_INTERVAL / TICK_INTERVAL ) )
# define CHECK_STUCK_INTERVAL_SP 0.2f
# define CHECK_STUCK_TICK_INTERVAL_SP ( (int)( CHECK_STUCK_INTERVAL_SP / TICK_INTERVAL ) )
# define CHECK_LADDER_INTERVAL 0.2f
# define CHECK_LADDER_TICK_INTERVAL ( (int)( CHECK_LADDER_INTERVAL / TICK_INTERVAL ) )
# define NUM_CROUCH_HINTS 3
extern IGameMovement * g_pGameMovement ;
# if defined( PLAYER_GETTING_STUCK_TESTING )
// If you ever get stuck walking around, then you can run this code to find the code which would leave the player in a bad spot
void CMoveData : : SetAbsOrigin ( const Vector & vec )
{
CGameMovement * gm = dynamic_cast < CGameMovement * > ( g_pGameMovement ) ;
if ( gm & & gm - > GetMoveData ( ) & &
gm - > player & &
gm - > player - > entindex ( ) = = 1 & &
gm - > player - > GetMoveType ( ) = = MOVETYPE_WALK )
{
trace_t pm ;
gm - > TracePlayerBBox ( vec , vec , gm - > PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
if ( pm . startsolid | | pm . allsolid | | pm . fraction ! = 1.0f )
{
Msg ( " Player will become stuck at %f %f %f \n " , VectorExpand ( vec ) ) ;
}
}
m_vecAbsOrigin = vec ;
}
# endif
// See shareddefs.h
# if PREDICTION_ERROR_CHECK_LEVEL > 0
static ConVar diffcheck ( " diffcheck " , " 0 " , FCVAR_REPLICATED ) ;
class IDiffMgr
{
public :
virtual void StartCommand ( bool bServer , int nCommandNumber ) = 0 ;
virtual void AddToDiff ( bool bServer , int nCommandNumber , char const * string ) = 0 ;
virtual void Validate ( bool bServer , int nCommandNumber ) = 0 ;
} ;
static IDiffMgr * g_pDiffMgr = NULL ;
class CDiffStr
{
public :
CDiffStr ( )
{
m_str [ 0 ] = 0 ;
}
CDiffStr ( char const * str )
{
Q_strncpy ( m_str , str , sizeof ( m_str ) ) ;
}
CDiffStr ( const CDiffStr & src )
{
Q_strncpy ( m_str , src . m_str , sizeof ( m_str ) ) ;
}
char const * String ( )
{
return m_str ;
}
private :
char m_str [ 128 ] ;
} ;
// Per tick data
class CDiffInfo
{
public :
CDiffInfo ( ) : m_nCommandNumber ( 0 ) { }
CDiffInfo ( const CDiffInfo & src )
{
m_nCommandNumber = src . m_nCommandNumber ;
for ( int i = 0 ; i < src . m_Lines . Count ( ) ; + + i )
{
m_Lines . AddToTail ( src . m_Lines [ i ] ) ;
}
}
static bool Less ( const CDiffInfo & lhs , const CDiffInfo & rhs )
{
return lhs . m_nCommandNumber < rhs . m_nCommandNumber ;
}
int m_nCommandNumber ;
CUtlVector < CDiffStr > m_Lines ;
bool m_bChecked ;
} ;
class CDiffManager : public IDiffMgr
{
public :
CDiffManager ( ) :
m_Client ( 0 , 0 , CDiffInfo : : Less ) ,
m_Server ( 0 , 0 , CDiffInfo : : Less ) ,
m_flLastSpew ( - 1.0f )
{
g_pDiffMgr = this ;
}
virtual void StartCommand ( bool bServer , int nCommandNumber )
{
# if defined( CLIENT_DLL )
if ( ! diffcheck . GetInt ( ) )
return ;
g_pDiffMgr = reinterpret_cast < IDiffMgr * > ( diffcheck . GetInt ( ) ) ;
g_pDiffMgr - > StartCommand ( bServer , nCommandNumber ) ;
return ;
# endif
// Msg( "%s Startcommand %d\n", bServer ? "sv" : "cl", nCommandNumber );
diffcheck . SetValue ( reinterpret_cast < int > ( this ) ) ;
Assert ( CBaseEntity : : IsServer ( ) ) ;
CUtlRBTree < CDiffInfo , int > & rb = bServer ? m_Server : m_Client ;
CDiffInfo search ;
search . m_nCommandNumber = nCommandNumber ;
int idx = rb . Find ( search ) ;
if ( idx = = rb . InvalidIndex ( ) )
{
idx = rb . Insert ( search ) ;
}
CDiffInfo * slot = & rb [ idx ] ;
slot - > m_Lines . RemoveAll ( ) ;
}
virtual void AddToDiff ( bool bServer , int nCommandNumber , char const * string )
{
# if defined( CLIENT_DLL )
if ( ! diffcheck . GetInt ( ) )
return ;
g_pDiffMgr = reinterpret_cast < IDiffMgr * > ( diffcheck . GetInt ( ) ) ;
g_pDiffMgr - > AddToDiff ( bServer , nCommandNumber , string ) ;
return ;
# endif
Assert ( CBaseEntity : : IsServer ( ) ) ;
// Msg( "%s Add %d %s\n", bServer ? "sv" : "cl", nCommandNumber, string );
CUtlRBTree < CDiffInfo , int > & rb = bServer ? m_Server : m_Client ;
CDiffInfo search ;
search . m_nCommandNumber = nCommandNumber ;
int idx = rb . Find ( search ) ;
if ( idx = = rb . InvalidIndex ( ) )
{
Assert ( 0 ) ;
idx = rb . Insert ( search ) ;
}
CDiffInfo * slot = & rb [ idx ] ;
CDiffStr line ( string ) ;
slot - > m_Lines . AddToTail ( line ) ;
}
enum EMismatched
{
DIFFCHECK_NOTREADY = 0 ,
DIFFCHECK_MATCHED ,
DIFFCHECK_DIFFERS
} ;
bool ClientRecordExists ( int cmd )
{
CDiffInfo clsearch ;
clsearch . m_nCommandNumber = cmd ;
int clidx = m_Client . Find ( clsearch ) ;
return m_Client . IsValidIndex ( clidx ) ;
}
EMismatched IsMismatched ( int svidx )
{
CDiffInfo * serverslot = & m_Server [ svidx ] ;
// Now find the client version of this one
CDiffInfo clsearch ;
clsearch . m_nCommandNumber = serverslot - > m_nCommandNumber ;
int clidx = m_Client . Find ( clsearch ) ;
if ( clidx = = m_Client . InvalidIndex ( ) )
return DIFFCHECK_NOTREADY ;
// Now compare them
CDiffInfo * clientslot = & m_Client [ clidx ] ;
bool bSpew = false ;
if ( serverslot - > m_Lines . Count ( ) ! =
clientslot - > m_Lines . Count ( ) )
{
return DIFFCHECK_DIFFERS ;
}
int maxSlot = MAX ( serverslot - > m_Lines . Count ( ) , clientslot - > m_Lines . Count ( ) ) ;
if ( ! bSpew )
{
for ( int i = 0 ; i < maxSlot ; + + i )
{
CDiffStr * sv = NULL ;
CDiffStr * cl = NULL ;
if ( i < serverslot - > m_Lines . Count ( ) )
{
sv = & serverslot - > m_Lines [ i ] ;
}
if ( i < clientslot - > m_Lines . Count ( ) )
{
cl = & clientslot - > m_Lines [ i ] ;
}
if ( Q_stricmp ( sv ? sv - > String ( ) : " (missing) " , cl ? cl - > String ( ) : " (missing) " ) )
{
return DIFFCHECK_DIFFERS ;
}
}
}
return DIFFCHECK_MATCHED ;
}
virtual void Validate ( bool bServer , int nCommandNumber )
{
# if defined( CLIENT_DLL )
if ( ! diffcheck . GetInt ( ) )
return ;
g_pDiffMgr = reinterpret_cast < IDiffMgr * > ( diffcheck . GetInt ( ) ) ;
g_pDiffMgr - > Validate ( bServer , nCommandNumber ) ;
return ;
# endif
Assert ( CBaseEntity : : IsServer ( ) ) ;
// Only do this on the client
if ( ! bServer )
return ;
// Find the last server command number
if ( m_Server . Count ( ) < = 0 )
return ;
int svidx = m_Server . LastInorder ( ) ;
EMismatched eMisMatched = IsMismatched ( svidx ) ;
if ( eMisMatched = = DIFFCHECK_NOTREADY )
{
return ;
}
if ( eMisMatched = = DIFFCHECK_DIFFERS )
{
CUtlVector < int > vecPrev ;
int nCur = svidx ;
do
{
int prev = m_Server . PrevInorder ( nCur ) ;
if ( m_Server . IsValidIndex ( prev ) & &
ClientRecordExists ( m_Server [ prev ] . m_nCommandNumber ) )
{
//SpewRecords( "prev", prev );
vecPrev . AddToHead ( prev ) ;
}
else
{
break ;
}
nCur = prev ;
} while ( vecPrev . Count ( ) < 10 ) ;
Msg ( " ----- \n " ) ;
for ( int p = 0 ; p < vecPrev . Count ( ) ; + + p )
{
SpewRecords ( " prev " , vecPrev [ p ] ) ;
}
SpewRecords ( " bad " , svidx ) ;
}
}
void SpewRecords ( char const * prefix , int svidx )
{
CDiffInfo * serverslot = & m_Server [ svidx ] ;
// Now find the client version of this one
CDiffInfo clsearch ;
clsearch . m_nCommandNumber = serverslot - > m_nCommandNumber ;
int clidx = m_Client . Find ( clsearch ) ;
if ( clidx = = m_Client . InvalidIndex ( ) )
return ;
// Now compare them
CDiffInfo * clientslot = & m_Client [ clidx ] ;
int maxSlot = MAX ( serverslot - > m_Lines . Count ( ) , clientslot - > m_Lines . Count ( ) ) ;
for ( int i = 0 ; i < maxSlot ; + + i )
{
char const * sv = " (missing) " ;
char const * cl = " (missing) " ;
if ( i < serverslot - > m_Lines . Count ( ) )
{
sv = serverslot - > m_Lines [ i ] . String ( ) ;
}
if ( i < clientslot - > m_Lines . Count ( ) )
{
cl = clientslot - > m_Lines [ i ] . String ( ) ;
}
bool bDiffers = Q_stricmp ( sv , cl ) ? true : false ;
Msg ( " %s%s%d: sv[%50.50s] cl[%50.50s] \n " ,
prefix ,
bDiffers ? " +++ " : " " ,
serverslot - > m_nCommandNumber ,
sv ,
cl ) ;
}
}
private :
CUtlRBTree < CDiffInfo , int > m_Server ;
CUtlRBTree < CDiffInfo , int > m_Client ;
float m_flLastSpew ;
} ;
static CDiffManager g_DiffMgr ;
void DiffPrint ( bool bServer , int nCommandNumber , char const * fmt , . . . )
{
// Only track stuff for local player
CBasePlayer * pPlayer = CBaseEntity : : GetPredictionPlayer ( ) ;
if ( pPlayer & & pPlayer - > entindex ( ) ! = 1 )
{
return ;
}
va_list argptr ;
char string [ 1024 ] ;
va_start ( argptr , fmt ) ;
int len = Q_vsnprintf ( string , sizeof ( string ) , fmt , argptr ) ;
va_end ( argptr ) ;
if ( g_pDiffMgr )
{
// Strip any \n at the end that the user accidently put int
if ( len > 0 & & string [ len - 1 ] = = ' \n ' )
{
string [ len - 1 ] = 0 ;
}
g_pDiffMgr - > AddToDiff ( bServer , nCommandNumber , string ) ;
}
}
void _CheckV ( int tick , char const * ctx , const Vector & vel )
{
DiffPrint ( CBaseEntity : : IsServer ( ) , tick , " %20.20s %f %f %f " , ctx , vel . x , vel . y , vel . z ) ;
}
# define CheckV( tick, ctx, vel ) _CheckV( tick, ctx, vel );
static void StartCommand ( bool bServer , int nCommandNumber )
{
// Only track stuff for local player
CBasePlayer * pPlayer = CBaseEntity : : GetPredictionPlayer ( ) ;
if ( pPlayer & & pPlayer - > entindex ( ) ! = 1 )
{
return ;
}
if ( g_pDiffMgr )
{
g_pDiffMgr - > StartCommand ( bServer , nCommandNumber ) ;
}
}
static void Validate ( bool bServer , int nCommandNumber )
{
// Only track stuff for local player
CBasePlayer * pPlayer = CBaseEntity : : GetPredictionPlayer ( ) ;
if ( pPlayer & & pPlayer - > entindex ( ) ! = 1 )
{
return ;
}
if ( g_pDiffMgr )
{
g_pDiffMgr - > Validate ( bServer , nCommandNumber ) ;
}
}
void CGameMovement : : DiffPrint ( char const * fmt , . . . )
{
if ( ! player )
return ;
va_list argptr ;
char string [ 1024 ] ;
va_start ( argptr , fmt ) ;
Q_vsnprintf ( string , sizeof ( string ) , fmt , argptr ) ;
va_end ( argptr ) ;
: : DiffPrint ( CBaseEntity : : IsServer ( ) , player - > CurrentCommandNumber ( ) , " %s " , string ) ;
}
# else
static void DiffPrint ( bool bServer , int nCommandNumber , char const * fmt , . . . )
{
// Nothing
}
static void StartCommand ( bool bServer , int nCommandNumber )
{
}
static void Validate ( bool bServer , int nCommandNumber )
{
}
# define CheckV( tick, ctx, vel )
void CGameMovement : : DiffPrint ( char const * fmt , . . . )
{
}
# endif // !PREDICTION_ERROR_CHECK_LEVEL
# ifndef _XBOX
void COM_Log ( char * pszFile , const char * fmt , . . . )
{
va_list argptr ;
char string [ 1024 ] ;
FileHandle_t fp ;
const char * pfilename ;
if ( ! pszFile )
{
pfilename = " hllog.txt " ;
}
else
{
pfilename = pszFile ;
}
va_start ( argptr , fmt ) ;
Q_vsnprintf ( string , sizeof ( string ) , fmt , argptr ) ;
va_end ( argptr ) ;
fp = filesystem - > Open ( pfilename , " a+t " ) ;
if ( fp )
{
filesystem - > FPrintf ( fp , " %s " , string ) ;
filesystem - > Close ( fp ) ;
}
}
# endif
# ifndef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Debug - draw the displacement collision plane.
//-----------------------------------------------------------------------------
void DrawDispCollPlane ( CBaseTrace * pTrace )
{
float flLength = 30.0f ;
// Create a basis, based on the impact normal.
int nMajorAxis = 0 ;
Vector vecBasisU , vecBasisV , vecNormal ;
vecNormal = pTrace - > plane . normal ;
float flAxisValue = vecNormal [ 0 ] ;
if ( fabs ( vecNormal [ 1 ] ) > fabs ( flAxisValue ) ) { nMajorAxis = 1 ; flAxisValue = vecNormal [ 1 ] ; }
if ( fabs ( vecNormal [ 2 ] ) > fabs ( flAxisValue ) ) { nMajorAxis = 2 ; }
if ( ( nMajorAxis = = 1 ) | | ( nMajorAxis = = 2 ) )
{
vecBasisU . Init ( 1.0f , 0.0f , 0.0f ) ;
}
else
{
vecBasisU . Init ( 0.0f , 1.0f , 0.0f ) ;
}
vecBasisV = vecNormal . Cross ( vecBasisU ) ;
VectorNormalize ( vecBasisV ) ;
vecBasisU = vecBasisV . Cross ( vecNormal ) ;
VectorNormalize ( vecBasisU ) ;
// Create the impact point. Push off the surface a bit.
Vector vecImpactPoint = pTrace - > startpos + pTrace - > fraction * ( pTrace - > endpos - pTrace - > startpos ) ;
vecImpactPoint + = vecNormal ;
// Generate a quad to represent the plane.
Vector vecPlanePoints [ 4 ] ;
vecPlanePoints [ 0 ] = vecImpactPoint + ( vecBasisU * - flLength ) + ( vecBasisV * - flLength ) ;
vecPlanePoints [ 1 ] = vecImpactPoint + ( vecBasisU * - flLength ) + ( vecBasisV * flLength ) ;
vecPlanePoints [ 2 ] = vecImpactPoint + ( vecBasisU * flLength ) + ( vecBasisV * flLength ) ;
vecPlanePoints [ 3 ] = vecImpactPoint + ( vecBasisU * flLength ) + ( vecBasisV * - flLength ) ;
#if 0
// Test facing.
Vector vecEdges [ 2 ] ;
vecEdges [ 0 ] = vecPlanePoints [ 1 ] - vecPlanePoints [ 0 ] ;
vecEdges [ 1 ] = vecPlanePoints [ 2 ] - vecPlanePoints [ 0 ] ;
Vector vecCross = vecEdges [ 0 ] . Cross ( vecEdges [ 1 ] ) ;
if ( vecCross . Dot ( vecNormal ) < 0.0f )
{
// Reverse winding.
}
# endif
// Draw the plane.
NDebugOverlay : : Triangle ( vecPlanePoints [ 0 ] , vecPlanePoints [ 1 ] , vecPlanePoints [ 2 ] , 125 , 125 , 125 , 125 , false , 5.0f ) ;
NDebugOverlay : : Triangle ( vecPlanePoints [ 0 ] , vecPlanePoints [ 2 ] , vecPlanePoints [ 3 ] , 125 , 125 , 125 , 125 , false , 5.0f ) ;
NDebugOverlay : : Line ( vecPlanePoints [ 0 ] , vecPlanePoints [ 1 ] , 255 , 255 , 255 , false , 5.0f ) ;
NDebugOverlay : : Line ( vecPlanePoints [ 1 ] , vecPlanePoints [ 2 ] , 255 , 255 , 255 , false , 5.0f ) ;
NDebugOverlay : : Line ( vecPlanePoints [ 2 ] , vecPlanePoints [ 3 ] , 255 , 255 , 255 , false , 5.0f ) ;
NDebugOverlay : : Line ( vecPlanePoints [ 3 ] , vecPlanePoints [ 0 ] , 255 , 255 , 255 , false , 5.0f ) ;
// Draw the normal.
NDebugOverlay : : Line ( vecImpactPoint , vecImpactPoint + ( vecNormal * flLength ) , 255 , 0 , 0 , false , 5.0f ) ;
}
# endif
//-----------------------------------------------------------------------------
// Purpose: Constructs GameMovement interface
//-----------------------------------------------------------------------------
CGameMovement : : CGameMovement ( void )
{
m_nOldWaterLevel = WL_NotInWater ;
m_flWaterEntryTime = 0 ;
m_nOnLadder = 0 ;
mv = NULL ;
memset ( m_flStuckCheckTime , 0 , sizeof ( m_flStuckCheckTime ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CGameMovement : : ~ CGameMovement ( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Allow bots etc to use slightly different solid masks
//-----------------------------------------------------------------------------
unsigned int CGameMovement : : PlayerSolidMask ( bool brushOnly )
{
return ( brushOnly ) ? MASK_PLAYERSOLID_BRUSHONLY : MASK_PLAYERSOLID ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : type -
// Output : int
//-----------------------------------------------------------------------------
int CGameMovement : : GetCheckInterval ( IntervalType_t type )
{
int tickInterval = 1 ;
switch ( type )
{
default :
tickInterval = 1 ;
break ;
case GROUND :
tickInterval = CATEGORIZE_GROUND_SURFACE_TICK_INTERVAL ;
break ;
case STUCK :
// If we are in the process of being "stuck", then try a new position every command tick until m_StuckLast gets reset back down to zero
if ( player - > m_StuckLast ! = 0 )
{
tickInterval = 1 ;
}
else
{
if ( gpGlobals - > maxClients = = 1 )
{
tickInterval = CHECK_STUCK_TICK_INTERVAL_SP ;
}
else
{
tickInterval = CHECK_STUCK_TICK_INTERVAL ;
}
}
break ;
case LADDER :
tickInterval = CHECK_LADDER_TICK_INTERVAL ;
break ;
}
return tickInterval ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : type -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameMovement : : CheckInterval ( IntervalType_t type )
{
int tickInterval = GetCheckInterval ( type ) ;
if ( g_bMovementOptimizations )
{
return ( player - > CurrentCommandNumber ( ) + player - > entindex ( ) ) % tickInterval = = 0 ;
}
else
{
return true ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ducked -
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CGameMovement : : GetPlayerMins ( bool ducked ) const
{
return ducked ? VEC_DUCK_HULL_MIN_SCALED ( player ) : VEC_HULL_MIN_SCALED ( player ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ducked -
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CGameMovement : : GetPlayerMaxs ( bool ducked ) const
{
return ducked ? VEC_DUCK_HULL_MAX_SCALED ( player ) : VEC_HULL_MAX_SCALED ( player ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CGameMovement : : GetPlayerMins ( void ) const
{
if ( player - > IsObserver ( ) )
{
return VEC_OBS_HULL_MIN_SCALED ( player ) ;
}
else
{
return player - > m_Local . m_bDucked ? VEC_DUCK_HULL_MIN_SCALED ( player ) : VEC_HULL_MIN_SCALED ( player ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CGameMovement : : GetPlayerMaxs ( void ) const
{
if ( player - > IsObserver ( ) )
{
return VEC_OBS_HULL_MAX_SCALED ( player ) ;
}
else
{
return player - > m_Local . m_bDucked ? VEC_DUCK_HULL_MAX_SCALED ( player ) : VEC_HULL_MAX_SCALED ( player ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : ducked -
// Output : const Vector
//-----------------------------------------------------------------------------
Vector CGameMovement : : GetPlayerViewOffset ( bool ducked ) const
{
return ducked ? VEC_DUCK_VIEW_SCALED ( player ) : VEC_VIEW_SCALED ( player ) ;
}
#if 0
//-----------------------------------------------------------------------------
// Traces player movement + position
//-----------------------------------------------------------------------------
inline void CGameMovement : : TracePlayerBBox ( const Vector & start , const Vector & end , unsigned int fMask , int collisionGroup , trace_t & pm )
{
VPROF ( " CGameMovement::TracePlayerBBox " ) ;
Ray_t ray ;
ray . Init ( start , end , GetPlayerMins ( ) , GetPlayerMaxs ( ) ) ;
UTIL_TraceRay ( ray , fMask , mv - > m_nPlayerHandle . Get ( ) , collisionGroup , & pm ) ;
}
# endif
CBaseHandle CGameMovement : : TestPlayerPosition ( const Vector & pos , int collisionGroup , trace_t & pm )
{
Ray_t ray ;
ray . Init ( pos , pos , GetPlayerMins ( ) , GetPlayerMaxs ( ) ) ;
UTIL_TraceRay ( ray , PlayerSolidMask ( ) , mv - > m_nPlayerHandle . Get ( ) , collisionGroup , & pm ) ;
if ( ( pm . contents & PlayerSolidMask ( ) ) & & pm . m_pEnt )
{
return pm . m_pEnt - > GetRefEHandle ( ) ;
}
else
{
return INVALID_EHANDLE_INDEX ;
}
}
/*
// FIXME FIXME: Does this need to be hooked up?
bool CGameMovement : : IsWet ( ) const
{
return ( ( pev - > flags & FL_INRAIN ) ! = 0 ) | | ( m_WetTime > = gpGlobals - > time ) ;
}
//-----------------------------------------------------------------------------
// Plants player footprint decals
//-----------------------------------------------------------------------------
# define PLAYER_HALFWIDTH 12
void CGameMovement : : PlantFootprint ( surfacedata_t * psurface )
{
// Can't plant footprints on fake materials (ladders, wading)
if ( psurface - > gameMaterial ! = ' X ' )
{
int footprintDecal = - 1 ;
// Figure out which footprint type to plant...
// Use the wet footprint if we're wet...
if ( IsWet ( ) )
{
footprintDecal = DECAL_FOOTPRINT_WET ;
}
else
{
// FIXME: Activate this once we decide to pull the trigger on it.
// NOTE: We could add in snow, mud, others here
// switch(psurface->gameMaterial)
// {
// case 'D':
// footprintDecal = DECAL_FOOTPRINT_DIRT;
// break;
// }
}
if ( footprintDecal ! = - 1 )
{
Vector right ;
AngleVectors ( pev - > angles , 0 , & right , 0 ) ;
// Figure out where the top of the stepping leg is
trace_t tr ;
Vector hipOrigin ;
VectorMA ( pev - > origin ,
m_IsFootprintOnLeft ? - PLAYER_HALFWIDTH : PLAYER_HALFWIDTH ,
right , hipOrigin ) ;
// Find where that leg hits the ground
UTIL_TraceLine ( hipOrigin , hipOrigin + Vector ( 0 , 0 , - COORD_EXTENT * 1.74 ) ,
MASK_SOLID_BRUSHONLY , edict ( ) , COLLISION_GROUP_NONE , & tr ) ;
unsigned char mType = TEXTURETYPE_Find ( & tr ) ;
// Splat a decal
CPVSFilter filter ( tr . endpos ) ;
te - > FootprintDecal ( filter , 0.0f , & tr . endpos , & right , ENTINDEX ( tr . u . ent ) ,
gDecals [ footprintDecal ] . index , mType ) ;
}
}
// Switch feet for next time
m_IsFootprintOnLeft = ! m_IsFootprintOnLeft ;
}
# define WET_TIME 5.f // how many seconds till we're completely wet/dry
# define DRY_TIME 20.f // how many seconds till we're completely wet/dry
void CBasePlayer : : UpdateWetness ( )
{
// BRJ 1/7/01
// Check for whether we're in a rainy area....
// Do this by tracing a line straight down with a size guaranteed to
// be larger than the map
// Update wetness based on whether we're in rain or not...
trace_t tr ;
UTIL_TraceLine ( pev - > origin , pev - > origin + Vector ( 0 , 0 , - COORD_EXTENT * 1.74 ) ,
MASK_SOLID_BRUSHONLY , edict ( ) , COLLISION_GROUP_NONE , & tr ) ;
if ( tr . surface . flags & SURF_WET )
{
if ( ! ( pev - > flags & FL_INRAIN ) )
{
// Transition...
// Figure out how wet we are now (we were drying off...)
float wetness = ( m_WetTime - gpGlobals - > time ) / DRY_TIME ;
if ( wetness < 0.0f )
wetness = 0.0f ;
// Here, wet time represents the time at which we get totally wet
m_WetTime = gpGlobals - > time + ( 1.0 - wetness ) * WET_TIME ;
pev - > flags | = FL_INRAIN ;
}
}
else
{
if ( ( pev - > flags & FL_INRAIN ) ! = 0 )
{
// Transition...
// Figure out how wet we are now (we were getting more wet...)
float wetness = 1.0f + ( gpGlobals - > time - m_WetTime ) / WET_TIME ;
if ( wetness > 1.0f )
wetness = 1.0f ;
// Here, wet time represents the time at which we get totally dry
m_WetTime = gpGlobals - > time + wetness * DRY_TIME ;
pev - > flags & = ~ FL_INRAIN ;
}
}
}
*/
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : CategorizeGroundSurface ( trace_t & pm )
{
IPhysicsSurfaceProps * physprops = MoveHelper ( ) - > GetSurfaceProps ( ) ;
player - > m_surfaceProps = pm . surface . surfaceProps ;
player - > m_pSurfaceData = physprops - > GetSurfaceData ( player - > m_surfaceProps ) ;
physprops - > GetPhysicsProperties ( player - > m_surfaceProps , NULL , NULL , & player - > m_surfaceFriction , NULL ) ;
// HACKHACK: Scale this to fudge the relationship between vphysics friction values and player friction values.
// A value of 0.8f feels pretty normal for vphysics, whereas 1.0f is normal for players.
// This scaling trivially makes them equivalent. REVISIT if this affects low friction surfaces too much.
player - > m_surfaceFriction * = 1.25f ;
if ( player - > m_surfaceFriction > 1.0f )
player - > m_surfaceFriction = 1.0f ;
player - > m_chTextureType = player - > m_pSurfaceData - > game . material ;
}
bool CGameMovement : : IsDead ( void ) const
{
return ( player - > m_iHealth < = 0 & & ! player - > IsAlive ( ) ) ;
}
//-----------------------------------------------------------------------------
// Figures out how the constraint should slow us down
//-----------------------------------------------------------------------------
float CGameMovement : : ComputeConstraintSpeedFactor ( void )
{
// If we have a constraint, slow down because of that too.
if ( ! mv | | mv - > m_flConstraintRadius = = 0.0f )
return 1.0f ;
float flDistSq = mv - > GetAbsOrigin ( ) . DistToSqr ( mv - > m_vecConstraintCenter ) ;
float flOuterRadiusSq = mv - > m_flConstraintRadius * mv - > m_flConstraintRadius ;
float flInnerRadiusSq = mv - > m_flConstraintRadius - mv - > m_flConstraintWidth ;
flInnerRadiusSq * = flInnerRadiusSq ;
// Only slow us down if we're inside the constraint ring
if ( ( flDistSq < = flInnerRadiusSq ) | | ( flDistSq > = flOuterRadiusSq ) )
return 1.0f ;
// Only slow us down if we're running away from the center
Vector vecDesired ;
VectorMultiply ( m_vecForward , mv - > m_flForwardMove , vecDesired ) ;
VectorMA ( vecDesired , mv - > m_flSideMove , m_vecRight , vecDesired ) ;
VectorMA ( vecDesired , mv - > m_flUpMove , m_vecUp , vecDesired ) ;
Vector vecDelta ;
VectorSubtract ( mv - > GetAbsOrigin ( ) , mv - > m_vecConstraintCenter , vecDelta ) ;
VectorNormalize ( vecDelta ) ;
VectorNormalize ( vecDesired ) ;
if ( DotProduct ( vecDelta , vecDesired ) < 0.0f )
return 1.0f ;
float flFrac = ( sqrt ( flDistSq ) - ( mv - > m_flConstraintRadius - mv - > m_flConstraintWidth ) ) / mv - > m_flConstraintWidth ;
float flSpeedFactor = Lerp ( flFrac , 1.0f , mv - > m_flConstraintSpeedFactor ) ;
return flSpeedFactor ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : CheckParameters ( void )
{
QAngle v_angle ;
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 - > 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 ;
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_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 ;
}
}
void CGameMovement : : ReduceTimers ( void )
{
float frame_msec = 1000.0f * gpGlobals - > frametime ;
if ( player - > m_Local . m_flDucktime > 0 )
{
player - > m_Local . m_flDucktime - = frame_msec ;
if ( player - > m_Local . m_flDucktime < 0 )
{
player - > m_Local . m_flDucktime = 0 ;
}
}
if ( player - > m_Local . m_flDuckJumpTime > 0 )
{
player - > m_Local . m_flDuckJumpTime - = frame_msec ;
if ( player - > m_Local . m_flDuckJumpTime < 0 )
{
player - > m_Local . m_flDuckJumpTime = 0 ;
}
}
if ( player - > m_Local . m_flJumpTime > 0 )
{
player - > m_Local . m_flJumpTime - = frame_msec ;
if ( player - > m_Local . m_flJumpTime < 0 )
{
player - > m_Local . m_flJumpTime = 0 ;
}
}
if ( player - > m_flSwimSoundTime > 0 )
{
player - > m_flSwimSoundTime - = frame_msec ;
if ( player - > m_flSwimSoundTime < 0 )
{
player - > m_flSwimSoundTime = 0 ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pMove -
//-----------------------------------------------------------------------------
void CGameMovement : : ProcessMovement ( CBasePlayer * pPlayer , CMoveData * pMove )
{
Assert ( pMove & & pPlayer ) ;
float flStoreFrametime = gpGlobals - > frametime ;
//!!HACK HACK: Adrian - slow down all player movement by this factor.
//!!Blame Yahn for this one.
gpGlobals - > frametime * = pPlayer - > GetLaggedMovementValue ( ) ;
ResetGetPointContentsCache ( ) ;
// Cropping movement speed scales mv->m_fForwardSpeed etc. globally
// Once we crop, we don't want to recursively crop again, so we set the crop
// flag globally here once per usercmd cycle.
m_iSpeedCropped = SPEED_CROPPED_RESET ;
// StartTrackPredictionErrors should have set this
Assert ( player = = pPlayer ) ;
player = pPlayer ;
mv = pMove ;
mv - > m_flMaxSpeed = pPlayer - > GetPlayerMaxSpeed ( ) ;
// CheckV( player->CurrentCommandNumber(), "StartPos", mv->GetAbsOrigin() );
DiffPrint ( " start %f %f %f " , mv - > GetAbsOrigin ( ) . x , mv - > GetAbsOrigin ( ) . y , mv - > GetAbsOrigin ( ) . z ) ;
// Run the command.
PlayerMove ( ) ;
FinishMove ( ) ;
DiffPrint ( " end %f %f %f " , mv - > GetAbsOrigin ( ) . x , mv - > GetAbsOrigin ( ) . y , mv - > GetAbsOrigin ( ) . z ) ;
// CheckV( player->CurrentCommandNumber(), "EndPos", mv->GetAbsOrigin() );
//This is probably not needed, but just in case.
gpGlobals - > frametime = flStoreFrametime ;
// player = NULL;
}
void CGameMovement : : StartTrackPredictionErrors ( CBasePlayer * pPlayer )
{
player = pPlayer ;
# if PREDICTION_ERROR_CHECK_LEVEL > 0
StartCommand ( CBaseEntity : : IsServer ( ) , player - > CurrentCommandNumber ( ) ) ;
# endif
}
void CGameMovement : : FinishTrackPredictionErrors ( CBasePlayer * pPlayer )
{
# if PREDICTION_ERROR_CHECK_LEVEL > 0
Assert ( player = = pPlayer ) ;
// DiffPrint( "end %f", player->m_Local.m_vecPunchAngleVel.m_Value.x );
// Call validate at end of checking
Validate ( CBaseEntity : : IsServer ( ) , player - > CurrentCommandNumber ( ) ) ;
# endif
}
//-----------------------------------------------------------------------------
// Purpose: Sets ground entity
//-----------------------------------------------------------------------------
void CGameMovement : : FinishMove ( void )
{
mv - > m_nOldButtons = mv - > m_nButtons ;
}
# define PUNCH_DAMPING 9.0f // bigger number makes the response more damped, smaller is less damped
// currently the system will overshoot, with larger damping values it won't
# define PUNCH_SPRING_CONSTANT 65.0f // bigger number increases the speed at which the view corrects
//-----------------------------------------------------------------------------
// Purpose: Decays the punchangle toward 0,0,0.
// Modelled as a damped spring
//-----------------------------------------------------------------------------
void CGameMovement : : DecayPunchAngle ( void )
{
if ( player - > m_Local . m_vecPunchAngle - > LengthSqr ( ) > 0.001 | | player - > m_Local . m_vecPunchAngleVel - > LengthSqr ( ) > 0.001 )
{
player - > m_Local . m_vecPunchAngle + = player - > m_Local . m_vecPunchAngleVel * gpGlobals - > frametime ;
float damping = 1 - ( PUNCH_DAMPING * gpGlobals - > frametime ) ;
if ( damping < 0 )
{
damping = 0 ;
}
player - > m_Local . m_vecPunchAngleVel * = damping ;
// torsional spring
// UNDONE: Per-axis spring constant?
float springForceMagnitude = PUNCH_SPRING_CONSTANT * gpGlobals - > frametime ;
springForceMagnitude = clamp ( springForceMagnitude , 0.f , 2.f ) ;
player - > m_Local . m_vecPunchAngleVel - = player - > m_Local . m_vecPunchAngle * springForceMagnitude ;
// don't wrap around
player - > m_Local . m_vecPunchAngle . Init (
clamp ( player - > m_Local . m_vecPunchAngle - > x , - 89.f , 89.f ) ,
clamp ( player - > m_Local . m_vecPunchAngle - > y , - 179.f , 179.f ) ,
clamp ( player - > m_Local . m_vecPunchAngle - > z , - 89.f , 89.f ) ) ;
}
else
{
player - > m_Local . m_vecPunchAngle . Init ( 0 , 0 , 0 ) ;
player - > m_Local . m_vecPunchAngleVel . Init ( 0 , 0 , 0 ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : StartGravity ( void )
{
float ent_gravity ;
if ( player - > GetGravity ( ) )
ent_gravity = player - > GetGravity ( ) ;
else
ent_gravity = 1.0 ;
// Add gravity so they'll be in the correct position during movement
// yes, this 0.5 looks wrong, but it's not.
mv - > m_vecVelocity [ 2 ] - = ( ent_gravity * GetCurrentGravity ( ) * 0.5 * gpGlobals - > frametime ) ;
mv - > m_vecVelocity [ 2 ] + = player - > GetBaseVelocity ( ) [ 2 ] * gpGlobals - > frametime ;
Vector temp = player - > GetBaseVelocity ( ) ;
temp [ 2 ] = 0 ;
player - > SetBaseVelocity ( temp ) ;
CheckVelocity ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : CheckWaterJump ( void )
{
Vector flatforward ;
Vector forward ;
Vector flatvelocity ;
float curspeed ;
AngleVectors ( mv - > m_vecViewAngles , & forward ) ; // Determine movement angles
// Already water jumping.
if ( player - > m_flWaterJumpTime )
return ;
// Don't hop out if we just jumped in
if ( mv - > m_vecVelocity [ 2 ] < - 180 )
return ; // only hop out if we are moving up
// See if we are backing up
flatvelocity [ 0 ] = mv - > m_vecVelocity [ 0 ] ;
flatvelocity [ 1 ] = mv - > m_vecVelocity [ 1 ] ;
flatvelocity [ 2 ] = 0 ;
// Must be moving
curspeed = VectorNormalize ( flatvelocity ) ;
// see if near an edge
flatforward [ 0 ] = forward [ 0 ] ;
flatforward [ 1 ] = forward [ 1 ] ;
flatforward [ 2 ] = 0 ;
VectorNormalize ( flatforward ) ;
// Are we backing into water from steps or something? If so, don't pop forward
if ( curspeed ! = 0.0 & & ( DotProduct ( flatvelocity , flatforward ) < 0.0 ) )
return ;
Vector vecStart ;
// Start line trace at waist height (using the center of the player for this here)
vecStart = mv - > GetAbsOrigin ( ) + ( GetPlayerMins ( ) + GetPlayerMaxs ( ) ) * 0.5 ;
Vector vecEnd ;
VectorMA ( vecStart , 24.0f , flatforward , vecEnd ) ;
trace_t tr ;
TracePlayerBBox ( vecStart , vecEnd , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , tr ) ;
if ( tr . fraction < 1.0 ) // solid at waist
{
IPhysicsObject * pPhysObj = tr . m_pEnt - > VPhysicsGetObject ( ) ;
if ( pPhysObj )
{
if ( pPhysObj - > GetGameFlags ( ) & FVPHYSICS_PLAYER_HELD )
return ;
}
vecStart . z = mv - > GetAbsOrigin ( ) . z + player - > GetViewOffset ( ) . z + WATERJUMP_HEIGHT ;
VectorMA ( vecStart , 24.0f , flatforward , vecEnd ) ;
VectorMA ( vec3_origin , - 50.0f , tr . plane . normal , player - > m_vecWaterJumpVel ) ;
TracePlayerBBox ( vecStart , vecEnd , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , tr ) ;
if ( tr . fraction = = 1.0 ) // open at eye level
{
// Now trace down to see if we would actually land on a standable surface.
VectorCopy ( vecEnd , vecStart ) ;
vecEnd . z - = 1024.0f ;
TracePlayerBBox ( vecStart , vecEnd , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , tr ) ;
if ( ( tr . fraction < 1.0f ) & & ( tr . plane . normal . z > = 0.7 ) )
{
mv - > m_vecVelocity [ 2 ] = 256.0f ; // Push up
mv - > m_nOldButtons | = IN_JUMP ; // Don't jump again until released
player - > AddFlag ( FL_WATERJUMP ) ;
player - > m_flWaterJumpTime = 2000.0f ; // Do this for 2 seconds
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : WaterJump ( void )
{
if ( player - > m_flWaterJumpTime > 10000 )
player - > m_flWaterJumpTime = 10000 ;
if ( ! player - > m_flWaterJumpTime )
return ;
player - > m_flWaterJumpTime - = 1000.0f * gpGlobals - > frametime ;
if ( player - > m_flWaterJumpTime < = 0 | | ! player - > GetWaterLevel ( ) )
{
player - > m_flWaterJumpTime = 0 ;
player - > RemoveFlag ( FL_WATERJUMP ) ;
}
mv - > m_vecVelocity [ 0 ] = player - > m_vecWaterJumpVel [ 0 ] ;
mv - > m_vecVelocity [ 1 ] = player - > m_vecWaterJumpVel [ 1 ] ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : WaterMove ( void )
{
int i ;
Vector wishvel ;
float wishspeed ;
Vector wishdir ;
Vector start , dest ;
Vector temp ;
trace_t pm ;
float speed , newspeed , addspeed , accelspeed ;
Vector forward , right , up ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
//
// user intentions
//
for ( i = 0 ; i < 3 ; i + + )
{
wishvel [ i ] = forward [ i ] * mv - > m_flForwardMove + right [ i ] * mv - > m_flSideMove ;
}
// if we have the jump key down, move us up as well
if ( mv - > m_nButtons & IN_JUMP )
{
wishvel [ 2 ] + = mv - > m_flClientMaxSpeed ;
}
// Sinking after no other movement occurs
else if ( ! mv - > m_flForwardMove & & ! mv - > m_flSideMove & & ! mv - > m_flUpMove )
{
wishvel [ 2 ] - = 60 ; // drift towards bottom
}
else // Go straight up by upmove amount.
{
// exaggerate upward movement along forward as well
float upwardMovememnt = mv - > m_flForwardMove * forward . z * 2 ;
upwardMovememnt = clamp ( upwardMovememnt , 0.f , mv - > m_flClientMaxSpeed ) ;
wishvel [ 2 ] + = mv - > m_flUpMove + upwardMovememnt ;
}
// Copy it over and determine speed
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
// Cap speed.
if ( wishspeed > mv - > m_flMaxSpeed )
{
VectorScale ( wishvel , mv - > m_flMaxSpeed / wishspeed , wishvel ) ;
wishspeed = mv - > m_flMaxSpeed ;
}
// Slow us down a bit.
wishspeed * = 0.8 ;
// Water friction
VectorCopy ( mv - > m_vecVelocity , temp ) ;
speed = VectorNormalize ( temp ) ;
if ( speed )
{
newspeed = speed - gpGlobals - > frametime * speed * sv_friction . GetFloat ( ) * player - > m_surfaceFriction ;
if ( newspeed < 0.1f )
{
newspeed = 0 ;
}
VectorScale ( mv - > m_vecVelocity , newspeed / speed , mv - > m_vecVelocity ) ;
}
else
{
newspeed = 0 ;
}
// water acceleration
if ( wishspeed > = 0.1f ) // old !
{
addspeed = wishspeed - newspeed ;
if ( addspeed > 0 )
{
VectorNormalize ( wishvel ) ;
accelspeed = sv_accelerate . GetFloat ( ) * wishspeed * gpGlobals - > frametime * player - > m_surfaceFriction ;
if ( accelspeed > addspeed )
{
accelspeed = addspeed ;
}
for ( i = 0 ; i < 3 ; i + + )
{
float deltaSpeed = accelspeed * wishvel [ i ] ;
mv - > m_vecVelocity [ i ] + = deltaSpeed ;
mv - > m_outWishVel [ i ] + = deltaSpeed ;
}
}
}
VectorAdd ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
// Now move
// assume it is a stair or a slope, so press down from stepheight above
VectorMA ( mv - > GetAbsOrigin ( ) , gpGlobals - > frametime , mv - > m_vecVelocity , dest ) ;
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , dest , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
if ( pm . fraction = = 1.0f )
{
VectorCopy ( dest , start ) ;
if ( player - > m_Local . m_bAllowAutoMovement )
{
start [ 2 ] + = player - > m_Local . m_flStepSize + 1 ;
}
TracePlayerBBox ( start , dest , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
if ( ! pm . startsolid & & ! pm . allsolid )
{
float stepDist = pm . endpos . z - mv - > GetAbsOrigin ( ) . z ;
mv - > m_outStepHeight + = stepDist ;
// walked up the step, so just keep result and exit
mv - > SetAbsOrigin ( pm . endpos ) ;
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
return ;
}
// Try moving straight along out normal path.
TryPlayerMove ( ) ;
}
else
{
if ( ! player - > GetGroundEntity ( ) )
{
TryPlayerMove ( ) ;
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
return ;
}
StepMove ( dest , pm ) ;
}
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Does the basic move attempting to climb up step heights. It uses
// the mv->GetAbsOrigin() and mv->m_vecVelocity. It returns a new
// new mv->GetAbsOrigin(), mv->m_vecVelocity, and mv->m_outStepHeight.
//-----------------------------------------------------------------------------
void CGameMovement : : StepMove ( Vector & vecDestination , trace_t & trace )
{
Vector vecEndPos ;
VectorCopy ( vecDestination , vecEndPos ) ;
// Try sliding forward both on ground and up 16 pixels
// take the move that goes farthest
Vector vecPos , vecVel ;
VectorCopy ( mv - > GetAbsOrigin ( ) , vecPos ) ;
VectorCopy ( mv - > m_vecVelocity , vecVel ) ;
// Slide move down.
TryPlayerMove ( & vecEndPos , & trace ) ;
// Down results.
Vector vecDownPos , vecDownVel ;
VectorCopy ( mv - > GetAbsOrigin ( ) , vecDownPos ) ;
VectorCopy ( mv - > m_vecVelocity , vecDownVel ) ;
// Reset original values.
mv - > SetAbsOrigin ( vecPos ) ;
VectorCopy ( vecVel , mv - > m_vecVelocity ) ;
// Move up a stair height.
VectorCopy ( mv - > GetAbsOrigin ( ) , vecEndPos ) ;
if ( player - > m_Local . m_bAllowAutoMovement )
{
vecEndPos . z + = player - > m_Local . m_flStepSize + DIST_EPSILON ;
}
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , vecEndPos , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
if ( ! trace . startsolid & & ! trace . allsolid )
{
mv - > SetAbsOrigin ( trace . endpos ) ;
}
// Slide move up.
TryPlayerMove ( ) ;
// Move down a stair (attempt to).
VectorCopy ( mv - > GetAbsOrigin ( ) , vecEndPos ) ;
if ( player - > m_Local . m_bAllowAutoMovement )
{
vecEndPos . z - = player - > m_Local . m_flStepSize + DIST_EPSILON ;
}
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , vecEndPos , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
// If we are not on the ground any more then use the original movement attempt.
if ( trace . plane . normal [ 2 ] < 0.7 )
{
mv - > SetAbsOrigin ( vecDownPos ) ;
VectorCopy ( vecDownVel , mv - > m_vecVelocity ) ;
float flStepDist = mv - > GetAbsOrigin ( ) . z - vecPos . z ;
if ( flStepDist > 0.0f )
{
mv - > m_outStepHeight + = flStepDist ;
}
return ;
}
// If the trace ended up in empty space, copy the end over to the origin.
if ( ! trace . startsolid & & ! trace . allsolid )
{
mv - > SetAbsOrigin ( trace . endpos ) ;
}
// Copy this origin to up.
Vector vecUpPos ;
VectorCopy ( mv - > GetAbsOrigin ( ) , vecUpPos ) ;
// decide which one went farther
float flDownDist = ( vecDownPos . x - vecPos . x ) * ( vecDownPos . x - vecPos . x ) + ( vecDownPos . y - vecPos . y ) * ( vecDownPos . y - vecPos . y ) ;
float flUpDist = ( vecUpPos . x - vecPos . x ) * ( vecUpPos . x - vecPos . x ) + ( vecUpPos . y - vecPos . y ) * ( vecUpPos . y - vecPos . y ) ;
if ( flDownDist > flUpDist )
{
mv - > SetAbsOrigin ( vecDownPos ) ;
VectorCopy ( vecDownVel , mv - > m_vecVelocity ) ;
}
else
{
// copy z value from slide move
mv - > m_vecVelocity . z = vecDownVel . z ;
}
float flStepDist = mv - > GetAbsOrigin ( ) . z - vecPos . z ;
if ( flStepDist > 0 )
{
mv - > m_outStepHeight + = flStepDist ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : Friction ( void )
{
float speed , newspeed , control ;
float friction ;
float drop ;
// If we are in water jump cycle, don't apply friction
if ( player - > m_flWaterJumpTime )
return ;
// Calculate speed
speed = VectorLength ( mv - > m_vecVelocity ) ;
// If too slow, return
if ( speed < 0.1f )
{
return ;
}
drop = 0 ;
// apply ground friction
if ( player - > GetGroundEntity ( ) ! = NULL ) // On an entity that is the ground
{
friction = sv_friction . GetFloat ( ) * player - > m_surfaceFriction ;
// Bleed off some speed, but if we have less than the bleed
// threshold, bleed the threshold amount.
if ( IsX360 ( ) )
{
if ( player - > m_Local . m_bDucked )
{
control = ( speed < sv_stopspeed . GetFloat ( ) ) ? sv_stopspeed . GetFloat ( ) : speed ;
}
else
{
# if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
control = ( speed < sv_stopspeed . GetFloat ( ) ) ? sv_stopspeed . GetFloat ( ) : speed ;
# else
control = ( speed < sv_stopspeed . GetFloat ( ) ) ? ( sv_stopspeed . GetFloat ( ) * 2.0f ) : speed ;
# endif
}
}
else
{
control = ( speed < sv_stopspeed . GetFloat ( ) ) ? sv_stopspeed . GetFloat ( ) : speed ;
}
// Add the amount to the drop amount.
drop + = control * friction * gpGlobals - > frametime ;
}
// scale the velocity
newspeed = speed - drop ;
if ( newspeed < 0 )
newspeed = 0 ;
if ( newspeed ! = speed )
{
// Determine proportion of old speed we are using.
newspeed / = speed ;
// Adjust velocity according to proportion.
VectorScale ( mv - > m_vecVelocity , newspeed , mv - > m_vecVelocity ) ;
}
mv - > m_outWishVel - = ( 1.f - newspeed ) * mv - > m_vecVelocity ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FinishGravity ( void )
{
float ent_gravity ;
if ( player - > m_flWaterJumpTime )
return ;
if ( player - > GetGravity ( ) )
ent_gravity = player - > GetGravity ( ) ;
else
ent_gravity = 1.0 ;
// Get the correct velocity for the end of the dt
mv - > m_vecVelocity [ 2 ] - = ( ent_gravity * GetCurrentGravity ( ) * gpGlobals - > frametime * 0.5 ) ;
CheckVelocity ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : wishdir -
// accel -
//-----------------------------------------------------------------------------
void CGameMovement : : AirAccelerate ( Vector & wishdir , float wishspeed , float accel )
{
int i ;
float addspeed , accelspeed , currentspeed ;
float wishspd ;
wishspd = wishspeed ;
if ( player - > pl . deadflag )
return ;
if ( player - > m_flWaterJumpTime )
return ;
// Cap speed
if ( wishspd > GetAirSpeedCap ( ) )
wishspd = GetAirSpeedCap ( ) ;
// Determine veer amount
currentspeed = mv - > m_vecVelocity . Dot ( wishdir ) ;
// See how much to add
addspeed = wishspd - currentspeed ;
// If not adding any, done.
if ( addspeed < = 0 )
return ;
// Determine acceleration speed after acceleration
accelspeed = accel * wishspeed * gpGlobals - > frametime * player - > m_surfaceFriction ;
// Cap it
if ( accelspeed > addspeed )
accelspeed = addspeed ;
// Adjust pmove vel.
for ( i = 0 ; i < 3 ; i + + )
{
mv - > m_vecVelocity [ i ] + = accelspeed * wishdir [ i ] ;
mv - > m_outWishVel [ i ] + = accelspeed * wishdir [ i ] ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : AirMove ( void )
{
int i ;
Vector wishvel ;
float fmove , smove ;
Vector wishdir ;
float wishspeed ;
Vector forward , right , up ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
// Copy movement amounts
fmove = mv - > m_flForwardMove ;
smove = mv - > m_flSideMove ;
// Zero out z components of movement vectors
forward [ 2 ] = 0 ;
right [ 2 ] = 0 ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors
VectorNormalize ( right ) ; //
for ( i = 0 ; i < 2 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] = 0 ; // Zero out z part of velocity
VectorCopy ( wishvel , wishdir ) ; // Determine maginitude of speed of move
wishspeed = VectorNormalize ( wishdir ) ;
//
// clamp to server defined max speed
//
if ( wishspeed ! = 0 & & ( wishspeed > mv - > m_flMaxSpeed ) )
{
VectorScale ( wishvel , mv - > m_flMaxSpeed / wishspeed , wishvel ) ;
wishspeed = mv - > m_flMaxSpeed ;
}
AirAccelerate ( wishdir , wishspeed , sv_airaccelerate . GetFloat ( ) ) ;
// Add in any base velocity to the current velocity.
VectorAdd ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
TryPlayerMove ( ) ;
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
}
bool CGameMovement : : CanAccelerate ( )
{
// Dead players don't accelerate.
if ( player - > pl . deadflag )
return false ;
// If waterjumping, don't accelerate
if ( player - > m_flWaterJumpTime )
return false ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : wishdir -
// wishspeed -
// accel -
//-----------------------------------------------------------------------------
void CGameMovement : : Accelerate ( Vector & wishdir , float wishspeed , float accel )
{
int i ;
float addspeed , accelspeed , currentspeed ;
// This gets overridden because some games (CSPort) want to allow dead (observer) players
// to be able to move around.
if ( ! CanAccelerate ( ) )
return ;
// See if we are changing direction a bit
currentspeed = mv - > m_vecVelocity . Dot ( wishdir ) ;
// Reduce wishspeed by the amount of veer.
addspeed = wishspeed - currentspeed ;
// If not going to add any speed, done.
if ( addspeed < = 0 )
return ;
// Determine amount of accleration.
accelspeed = accel * gpGlobals - > frametime * wishspeed * player - > m_surfaceFriction ;
// Cap at addspeed
if ( accelspeed > addspeed )
accelspeed = addspeed ;
// Adjust velocity.
for ( i = 0 ; i < 3 ; i + + )
{
mv - > m_vecVelocity [ i ] + = accelspeed * wishdir [ i ] ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Try to keep a walking player on the ground when running down slopes etc
//-----------------------------------------------------------------------------
void CGameMovement : : StayOnGround ( void )
{
trace_t trace ;
Vector start ( mv - > GetAbsOrigin ( ) ) ;
Vector end ( mv - > GetAbsOrigin ( ) ) ;
start . z + = 2 ;
end . z - = player - > GetStepSize ( ) ;
// See how far up we can go without getting stuck
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , start , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
start = trace . endpos ;
// using trace.startsolid is unreliable here, it doesn't get set when
// tracing bounding box vs. terrain
// Now trace down from a known safe position
TracePlayerBBox ( start , end , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
if ( trace . fraction > 0.0f & & // must go somewhere
trace . fraction < 1.0f & & // must hit something
! trace . startsolid & & // can't be embedded in a solid
trace . plane . normal [ 2 ] > = 0.7 ) // can't hit a steep slope that we can't stand on anyway
{
float flDelta = fabs ( mv - > GetAbsOrigin ( ) . z - trace . endpos . z ) ;
//This is incredibly hacky. The real problem is that trace returning that strange value we can't network over.
if ( flDelta > 0.5f * COORD_RESOLUTION )
{
mv - > SetAbsOrigin ( trace . endpos ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : WalkMove ( void )
{
int i ;
Vector wishvel ;
float spd ;
float fmove , smove ;
Vector wishdir ;
float wishspeed ;
Vector dest ;
trace_t pm ;
Vector forward , right , up ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
CHandle < CBaseEntity > oldground ;
oldground = player - > GetGroundEntity ( ) ;
// Copy movement amounts
fmove = mv - > m_flForwardMove ;
smove = mv - > m_flSideMove ;
// Zero out z components of movement vectors
if ( g_bMovementOptimizations )
{
if ( forward [ 2 ] ! = 0 )
{
forward [ 2 ] = 0 ;
VectorNormalize ( forward ) ;
}
if ( right [ 2 ] ! = 0 )
{
right [ 2 ] = 0 ;
VectorNormalize ( right ) ;
}
}
else
{
forward [ 2 ] = 0 ;
right [ 2 ] = 0 ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors.
VectorNormalize ( right ) ; //
}
for ( i = 0 ; i < 2 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] = 0 ; // Zero out z part of velocity
VectorCopy ( wishvel , wishdir ) ; // Determine maginitude of speed of move
wishspeed = VectorNormalize ( wishdir ) ;
//
// Clamp to server defined max speed
//
if ( ( wishspeed ! = 0.0f ) & & ( wishspeed > mv - > m_flMaxSpeed ) )
{
VectorScale ( wishvel , mv - > m_flMaxSpeed / wishspeed , wishvel ) ;
wishspeed = mv - > m_flMaxSpeed ;
}
// Set pmove velocity
mv - > m_vecVelocity [ 2 ] = 0 ;
Accelerate ( wishdir , wishspeed , sv_accelerate . GetFloat ( ) ) ;
mv - > m_vecVelocity [ 2 ] = 0 ;
// Add in any base velocity to the current velocity.
VectorAdd ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
spd = VectorLength ( mv - > m_vecVelocity ) ;
if ( spd < 1.0f )
{
mv - > m_vecVelocity . Init ( ) ;
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
return ;
}
// first try just moving to the destination
dest [ 0 ] = mv - > GetAbsOrigin ( ) [ 0 ] + mv - > m_vecVelocity [ 0 ] * gpGlobals - > frametime ;
dest [ 1 ] = mv - > GetAbsOrigin ( ) [ 1 ] + mv - > m_vecVelocity [ 1 ] * gpGlobals - > frametime ;
dest [ 2 ] = mv - > GetAbsOrigin ( ) [ 2 ] ;
// first try moving directly to the next spot
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , dest , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
// If we made it all the way, then copy trace end as new player position.
mv - > m_outWishVel + = wishdir * wishspeed ;
if ( pm . fraction = = 1 )
{
mv - > SetAbsOrigin ( pm . endpos ) ;
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
StayOnGround ( ) ;
return ;
}
// Don't walk up stairs if not on ground.
if ( oldground = = NULL & & player - > GetWaterLevel ( ) = = 0 )
{
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
return ;
}
// If we are jumping out of water, don't do anything more.
if ( player - > m_flWaterJumpTime )
{
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
return ;
}
StepMove ( dest , pm ) ;
// Now pull the base velocity back out. Base velocity is set if you are on a moving object, like a conveyor (or maybe another monster?)
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
StayOnGround ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FullWalkMove ( )
{
if ( ! CheckWater ( ) )
{
StartGravity ( ) ;
}
// If we are leaping out of the water, just update the counters.
if ( player - > m_flWaterJumpTime )
{
WaterJump ( ) ;
TryPlayerMove ( ) ;
// See if we are still in water?
CheckWater ( ) ;
return ;
}
// If we are swimming in the water, see if we are nudging against a place we can jump up out
// of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0
if ( player - > GetWaterLevel ( ) > = WL_Waist )
{
if ( player - > GetWaterLevel ( ) = = WL_Waist )
{
CheckWaterJump ( ) ;
}
// If we are falling again, then we must not trying to jump out of water any more.
if ( mv - > m_vecVelocity [ 2 ] < 0 & &
player - > m_flWaterJumpTime )
{
player - > m_flWaterJumpTime = 0 ;
}
// Was jump button pressed?
if ( mv - > m_nButtons & IN_JUMP )
{
CheckJumpButton ( ) ;
}
else
{
mv - > m_nOldButtons & = ~ IN_JUMP ;
}
// Perform regular water movement
WaterMove ( ) ;
// Redetermine position vars
CategorizePosition ( ) ;
// If we are on ground, no downward velocity.
if ( player - > GetGroundEntity ( ) ! = NULL )
{
mv - > m_vecVelocity [ 2 ] = 0 ;
}
}
else
// Not fully underwater
{
// Was jump button pressed?
if ( mv - > m_nButtons & IN_JUMP )
{
CheckJumpButton ( ) ;
}
else
{
mv - > m_nOldButtons & = ~ IN_JUMP ;
}
// Fricion is handled before we add in any base velocity. That way, if we are on a conveyor,
// we don't slow when standing still, relative to the conveyor.
if ( player - > GetGroundEntity ( ) ! = NULL )
{
mv - > m_vecVelocity [ 2 ] = 0.0 ;
Friction ( ) ;
}
// Make sure velocity is valid.
CheckVelocity ( ) ;
if ( player - > GetGroundEntity ( ) ! = NULL )
{
WalkMove ( ) ;
}
else
{
AirMove ( ) ; // Take into account movement when in air.
}
// Set final flags.
CategorizePosition ( ) ;
// Make sure velocity is valid.
CheckVelocity ( ) ;
// Add any remaining gravitational component.
if ( ! CheckWater ( ) )
{
FinishGravity ( ) ;
}
// If we are on ground, no downward velocity.
if ( player - > GetGroundEntity ( ) ! = NULL )
{
mv - > m_vecVelocity [ 2 ] = 0 ;
}
CheckFalling ( ) ;
}
if ( ( m_nOldWaterLevel = = WL_NotInWater & & player - > GetWaterLevel ( ) ! = WL_NotInWater ) | |
( m_nOldWaterLevel ! = WL_NotInWater & & player - > GetWaterLevel ( ) = = WL_NotInWater ) )
{
PlaySwimSound ( ) ;
# if !defined( CLIENT_DLL )
player - > Splash ( ) ;
# endif
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FullObserverMove ( void )
{
int mode = player - > GetObserverMode ( ) ;
if ( mode = = OBS_MODE_IN_EYE | | mode = = OBS_MODE_CHASE )
{
CBaseEntity * target = player - > GetObserverTarget ( ) ;
if ( target ! = NULL )
{
mv - > SetAbsOrigin ( target - > GetAbsOrigin ( ) ) ;
mv - > m_vecViewAngles = target - > GetAbsAngles ( ) ;
mv - > m_vecVelocity = target - > GetAbsVelocity ( ) ;
}
return ;
}
if ( mode ! = OBS_MODE_ROAMING )
{
// don't move in fixed or death cam mode
return ;
}
if ( sv_specnoclip . GetBool ( ) )
{
// roam in noclip mode
FullNoClipMove ( sv_specspeed . GetFloat ( ) , sv_specaccelerate . GetFloat ( ) ) ;
return ;
}
// do a full clipped free roam move:
Vector wishvel ;
Vector forward , right , up ;
Vector wishdir , wishend ;
float wishspeed ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
// Copy movement amounts
float factor = sv_specspeed . GetFloat ( ) ;
if ( mv - > m_nButtons & IN_SPEED )
{
factor / = 2.0f ;
}
float fmove = mv - > m_flForwardMove * factor ;
float smove = mv - > m_flSideMove * factor ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors
VectorNormalize ( right ) ; //
for ( int i = 0 ; i < 3 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] + = mv - > m_flUpMove ;
VectorCopy ( wishvel , wishdir ) ; // Determine maginitude of speed of move
wishspeed = VectorNormalize ( wishdir ) ;
//
// Clamp to server defined max speed
//
float maxspeed = sv_maxvelocity . GetFloat ( ) ;
if ( wishspeed > maxspeed )
{
VectorScale ( wishvel , mv - > m_flMaxSpeed / wishspeed , wishvel ) ;
wishspeed = maxspeed ;
}
// Set pmove velocity, give observer 50% acceration bonus
Accelerate ( wishdir , wishspeed , sv_specaccelerate . GetFloat ( ) ) ;
float spd = VectorLength ( mv - > m_vecVelocity ) ;
if ( spd < 1.0f )
{
mv - > m_vecVelocity . Init ( ) ;
return ;
}
float friction = sv_friction . GetFloat ( ) ;
// Add the amount to the drop amount.
float drop = spd * friction * gpGlobals - > frametime ;
// scale the velocity
float newspeed = spd - drop ;
if ( newspeed < 0 )
newspeed = 0 ;
// Determine proportion of old speed we are using.
newspeed / = spd ;
VectorScale ( mv - > m_vecVelocity , newspeed , mv - > m_vecVelocity ) ;
CheckVelocity ( ) ;
TryPlayerMove ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FullNoClipMove ( float factor , float maxacceleration )
{
Vector wishvel ;
Vector forward , right , up ;
Vector wishdir ;
float wishspeed ;
float maxspeed = sv_maxspeed . GetFloat ( ) * factor ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
if ( mv - > m_nButtons & IN_SPEED )
{
factor / = 2.0f ;
}
// Copy movement amounts
float fmove = mv - > m_flForwardMove * factor ;
float smove = mv - > m_flSideMove * factor ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors
VectorNormalize ( right ) ; //
for ( int i = 0 ; i < 3 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] + = mv - > m_flUpMove * factor ;
VectorCopy ( wishvel , wishdir ) ; // Determine maginitude of speed of move
wishspeed = VectorNormalize ( wishdir ) ;
//
// Clamp to server defined max speed
//
if ( wishspeed > maxspeed )
{
VectorScale ( wishvel , maxspeed / wishspeed , wishvel ) ;
wishspeed = maxspeed ;
}
if ( maxacceleration > 0.0 )
{
// Set pmove velocity
Accelerate ( wishdir , wishspeed , maxacceleration ) ;
float spd = VectorLength ( mv - > m_vecVelocity ) ;
if ( spd < 1.0f )
{
mv - > m_vecVelocity . Init ( ) ;
return ;
}
// Bleed off some speed, but if we have less than the bleed
// threshhold, bleed the theshold amount.
float control = ( spd < maxspeed / 4.0 ) ? maxspeed / 4.0 : spd ;
float friction = sv_friction . GetFloat ( ) * player - > m_surfaceFriction ;
// Add the amount to the drop amount.
float drop = control * friction * gpGlobals - > frametime ;
// scale the velocity
float newspeed = spd - drop ;
if ( newspeed < 0 )
newspeed = 0 ;
// Determine proportion of old speed we are using.
newspeed / = spd ;
VectorScale ( mv - > m_vecVelocity , newspeed , mv - > m_vecVelocity ) ;
}
else
{
VectorCopy ( wishvel , mv - > m_vecVelocity ) ;
}
// Just move ( don't clip or anything )
Vector out ;
VectorMA ( mv - > GetAbsOrigin ( ) , gpGlobals - > frametime , mv - > m_vecVelocity , out ) ;
mv - > SetAbsOrigin ( out ) ;
// Zero out velocity if in noaccel mode
if ( maxacceleration < 0.0f )
{
mv - > m_vecVelocity . Init ( ) ;
}
}
//-----------------------------------------------------------------------------
// Checks to see if we should actually jump
//-----------------------------------------------------------------------------
void CGameMovement : : PlaySwimSound ( )
{
MoveHelper ( ) - > StartSound ( mv - > GetAbsOrigin ( ) , " Player.Swim " ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CGameMovement : : CheckJumpButton ( void )
{
if ( player - > 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 ( player - > m_flWaterJumpTime )
{
player - > m_flWaterJumpTime - = gpGlobals - > frametime ;
if ( player - > m_flWaterJumpTime < 0 )
player - > m_flWaterJumpTime = 0 ;
return false ;
}
// If we are in the water most of the way...
if ( player - > GetWaterLevel ( ) > = 2 )
{
// swimming, not jumping
SetGroundEntity ( NULL ) ;
if ( player - > GetWaterType ( ) = = CONTENTS_WATER ) // We move up a certain amount
mv - > m_vecVelocity [ 2 ] = 100 ;
else if ( player - > GetWaterType ( ) = = CONTENTS_SLIME )
mv - > m_vecVelocity [ 2 ] = 80 ;
// play swiming sound
if ( player - > m_flSwimSoundTime < = 0 )
{
// Don't play sound again for 1 second
player - > m_flSwimSoundTime = 1000 ;
PlaySwimSound ( ) ;
}
return false ;
}
// No more effect
if ( player - > GetGroundEntity ( ) = = NULL )
{
mv - > m_nOldButtons | = IN_JUMP ;
return false ; // in air, so no effect
}
// Don't allow jumping when the player is in a stasis field.
# ifndef HL2_EPISODIC
if ( player - > m_Local . m_bSlowMovement )
return false ;
# endif
if ( mv - > m_nOldButtons & IN_JUMP )
return false ; // don't pogo stick
// Cannot jump will in the unduck transition.
if ( player - > m_Local . m_bDucking & & ( player - > GetFlags ( ) & FL_DUCKING ) )
return false ;
// Still updating the eye position.
if ( player - > m_Local . m_flDuckJumpTime > 0.0f )
return false ;
// In the air now.
SetGroundEntity ( NULL ) ;
player - > PlayStepSound ( ( Vector & ) mv - > GetAbsOrigin ( ) , player - > m_pSurfaceData , 1.0 , true ) ;
MoveHelper ( ) - > PlayerSetAnimation ( PLAYER_JUMP ) ;
float flGroundFactor = 1.0f ;
if ( player - > m_pSurfaceData )
{
flGroundFactor = player - > m_pSurfaceData - > game . jumpFactor ;
}
float flMul ;
if ( g_bMovementOptimizations )
{
# if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
Assert ( GetCurrentGravity ( ) = = 600.0f ) ;
flMul = 160.0f ; // approx. 21 units.
# else
Assert ( GetCurrentGravity ( ) = = 800.0f ) ;
flMul = 268.3281572999747f ;
# endif
}
else
{
flMul = sqrt ( 2 * GetCurrentGravity ( ) * GAMEMOVEMENT_JUMP_HEIGHT ) ;
}
// Acclerate upward
// If we are ducking...
float startz = mv - > m_vecVelocity [ 2 ] ;
if ( ( player - > m_Local . m_bDucking ) | | ( player - > 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 * flMul ; // 2 * gravity * height
}
else
{
mv - > m_vecVelocity [ 2 ] + = flGroundFactor * flMul ; // 2 * gravity * height
}
// Add a little forward velocity based on your current forward velocity - if you are not sprinting.
# if defined( HL2_DLL ) || defined( HL2_CLIENT_DLL )
if ( gpGlobals - > maxClients = = 1 )
{
CHLMoveData * pMoveData = ( CHLMoveData * ) mv ;
Vector vecForward ;
AngleVectors ( mv - > m_vecViewAngles , & vecForward ) ;
vecForward . z = 0 ;
VectorNormalize ( vecForward ) ;
// We give a certain percentage of the current forward movement as a bonus to the jump speed. That bonus is clipped
// to not accumulate over time.
float flSpeedBoostPerc = ( ! pMoveData - > m_bIsSprinting & & ! player - > m_Local . m_bDucked ) ? 0.5f : 0.1f ;
float flSpeedAddition = fabs ( mv - > m_flForwardMove * flSpeedBoostPerc ) ;
float flMaxSpeed = mv - > m_flMaxSpeed + ( mv - > m_flMaxSpeed * flSpeedBoostPerc ) ;
float flNewSpeed = ( flSpeedAddition + mv - > m_vecVelocity . Length2D ( ) ) ;
// If we're over the maximum, we want to only boost as much as will get us to the goal speed
if ( flNewSpeed > flMaxSpeed )
{
flSpeedAddition - = flNewSpeed - flMaxSpeed ;
}
if ( mv - > m_flForwardMove < 0.0f )
flSpeedAddition * = - 1.0f ;
// Add it on
VectorAdd ( ( vecForward * flSpeedAddition ) , mv - > m_vecVelocity , mv - > m_vecVelocity ) ;
}
# endif
FinishGravity ( ) ;
CheckV ( player - > CurrentCommandNumber ( ) , " CheckJump " , mv - > m_vecVelocity ) ;
mv - > m_outJumpVel . z + = mv - > m_vecVelocity [ 2 ] - startz ;
mv - > m_outStepHeight + = 0.15f ;
OnJump ( mv - > m_outJumpVel . z ) ;
// Set jump time.
if ( gpGlobals - > maxClients = = 1 )
{
player - > m_Local . m_flJumpTime = GAMEMOVEMENT_JUMP_TIME ;
player - > m_Local . m_bInDuckJump = true ;
}
# if defined( HL2_DLL )
if ( xc_uncrouch_on_jump . GetBool ( ) )
{
// Uncrouch when jumping
if ( player - > GetToggledDuckState ( ) )
{
player - > ToggleDuck ( ) ;
}
}
# endif
// Flag that we jumped.
mv - > m_nOldButtons | = IN_JUMP ; // don't jump again until released
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FullLadderMove ( )
{
CheckWater ( ) ;
// Was jump button pressed? If so, set velocity to 270 away from ladder.
if ( mv - > m_nButtons & IN_JUMP )
{
CheckJumpButton ( ) ;
}
else
{
mv - > m_nOldButtons & = ~ IN_JUMP ;
}
// Perform the move accounting for any base velocity.
VectorAdd ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
TryPlayerMove ( ) ;
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CGameMovement : : TryPlayerMove ( Vector * pFirstDest , trace_t * pFirstTrace )
{
int bumpcount , numbumps ;
Vector dir ;
float d ;
int numplanes ;
Vector planes [ MAX_CLIP_PLANES ] ;
Vector primal_velocity , original_velocity ;
Vector new_velocity ;
int i , j ;
trace_t pm ;
Vector end ;
float time_left , allFraction ;
int blocked ;
numbumps = 4 ; // Bump up to four times
blocked = 0 ; // Assume not blocked
numplanes = 0 ; // and not sliding along any planes
VectorCopy ( mv - > m_vecVelocity , original_velocity ) ; // Store original velocity
VectorCopy ( mv - > m_vecVelocity , primal_velocity ) ;
allFraction = 0 ;
time_left = gpGlobals - > frametime ; // Total time for this movement operation.
new_velocity . Init ( ) ;
for ( bumpcount = 0 ; bumpcount < numbumps ; bumpcount + + )
{
if ( mv - > m_vecVelocity . Length ( ) = = 0.0 )
break ;
// Assume we can move all the way from the current origin to the
// end point.
VectorMA ( mv - > GetAbsOrigin ( ) , time_left , mv - > m_vecVelocity , end ) ;
// See if we can make it from origin to end point.
if ( g_bMovementOptimizations )
{
// If their velocity Z is 0, then we can avoid an extra trace here during WalkMove.
if ( pFirstDest & & end = = * pFirstDest )
pm = * pFirstTrace ;
else
{
# if defined( PLAYER_GETTING_STUCK_TESTING )
trace_t foo ;
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , mv - > GetAbsOrigin ( ) , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , foo ) ;
if ( foo . startsolid | | foo . fraction ! = 1.0f )
{
Msg ( " bah \n " ) ;
}
# endif
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , end , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
}
}
else
{
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , end , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
}
allFraction + = pm . fraction ;
// If we started in a solid object, or we were in solid space
// the whole way, zero out our velocity and return that we
// are blocked by floor and wall.
if ( pm . allsolid )
{
// entity is trapped in another solid
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
return 4 ;
}
// If we moved some portion of the total distance, then
// copy the end position into the pmove.origin and
// zero the plane counter.
if ( pm . fraction > 0 )
{
if ( numbumps > 0 & & pm . fraction = = 1 )
{
// There's a precision issue with terrain tracing that can cause a swept box to successfully trace
// when the end position is stuck in the triangle. Re-run the test with an uswept box to catch that
// case until the bug is fixed.
// If we detect getting stuck, don't allow the movement
trace_t stuck ;
TracePlayerBBox ( pm . endpos , pm . endpos , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , stuck ) ;
if ( stuck . startsolid | | stuck . fraction ! = 1.0f )
{
//Msg( "Player will become stuck!!!\n" );
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
break ;
}
}
# if defined( PLAYER_GETTING_STUCK_TESTING )
trace_t foo ;
TracePlayerBBox ( pm . endpos , pm . endpos , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , foo ) ;
if ( foo . startsolid | | foo . fraction ! = 1.0f )
{
Msg ( " Player will become stuck!!! \n " ) ;
}
# endif
// actually covered some distance
mv - > SetAbsOrigin ( pm . endpos ) ;
VectorCopy ( mv - > m_vecVelocity , original_velocity ) ;
numplanes = 0 ;
}
// If we covered the entire distance, we are done
// and can return.
if ( pm . fraction = = 1 )
{
break ; // moved the entire distance
}
// Save entity that blocked us (since fraction was < 1.0)
// for contact
// Add it if it's not already in the list!!!
MoveHelper ( ) - > AddToTouched ( pm , mv - > m_vecVelocity ) ;
// If the plane we hit has a high z component in the normal, then
// it's probably a floor
if ( pm . plane . normal [ 2 ] > 0.7 )
{
blocked | = 1 ; // floor
}
// If the plane has a zero z component in the normal, then it's a
// step or wall
if ( ! pm . plane . normal [ 2 ] )
{
blocked | = 2 ; // step / wall
}
// Reduce amount of m_flFrameTime left by total time left * fraction
// that we covered.
time_left - = time_left * pm . fraction ;
// Did we run out of planes to clip against?
if ( numplanes > = MAX_CLIP_PLANES )
{
// this shouldn't really happen
// Stop our movement if so.
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
//Con_DPrintf("Too many planes 4\n");
break ;
}
// Set up next clipping plane
VectorCopy ( pm . plane . normal , planes [ numplanes ] ) ;
numplanes + + ;
// modify original_velocity so it parallels all of the clip planes
//
// reflect player velocity
// Only give this a try for first impact plane because you can get yourself stuck in an acute corner by jumping in place
// and pressing forward and nobody was really using this bounce/reflection feature anyway...
if ( numplanes = = 1 & &
player - > GetMoveType ( ) = = MOVETYPE_WALK & &
player - > GetGroundEntity ( ) = = NULL )
{
for ( i = 0 ; i < numplanes ; i + + )
{
if ( planes [ i ] [ 2 ] > 0.7 )
{
// floor or slope
ClipVelocity ( original_velocity , planes [ i ] , new_velocity , 1 ) ;
VectorCopy ( new_velocity , original_velocity ) ;
}
else
{
ClipVelocity ( original_velocity , planes [ i ] , new_velocity , 1.0 + sv_bounce . GetFloat ( ) * ( 1 - player - > m_surfaceFriction ) ) ;
}
}
VectorCopy ( new_velocity , mv - > m_vecVelocity ) ;
VectorCopy ( new_velocity , original_velocity ) ;
}
else
{
for ( i = 0 ; i < numplanes ; i + + )
{
ClipVelocity (
original_velocity ,
planes [ i ] ,
mv - > m_vecVelocity ,
1 ) ;
for ( j = 0 ; j < numplanes ; j + + )
if ( j ! = i )
{
// Are we now moving against this plane?
if ( mv - > m_vecVelocity . Dot ( planes [ j ] ) < 0 )
break ; // not ok
}
if ( j = = numplanes ) // Didn't have to clip, so we're ok
break ;
}
// Did we go all the way through plane set
if ( i ! = numplanes )
{ // go along this plane
// pmove.velocity is set in clipping call, no need to set again.
;
}
else
{ // go along the crease
if ( numplanes ! = 2 )
{
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
break ;
}
CrossProduct ( planes [ 0 ] , planes [ 1 ] , dir ) ;
dir . NormalizeInPlace ( ) ;
d = dir . Dot ( mv - > m_vecVelocity ) ;
VectorScale ( dir , d , mv - > m_vecVelocity ) ;
}
//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
d = mv - > m_vecVelocity . Dot ( primal_velocity ) ;
if ( d < = 0 )
{
//Con_DPrintf("Back\n");
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
break ;
}
}
}
if ( allFraction = = 0 )
{
VectorCopy ( vec3_origin , mv - > m_vecVelocity ) ;
}
// Check if they slammed into a wall
float fSlamVol = 0.0f ;
float fLateralStoppingAmount = primal_velocity . Length2D ( ) - mv - > m_vecVelocity . Length2D ( ) ;
if ( fLateralStoppingAmount > PLAYER_MAX_SAFE_FALL_SPEED * 2.0f )
{
fSlamVol = 1.0f ;
}
else if ( fLateralStoppingAmount > PLAYER_MAX_SAFE_FALL_SPEED )
{
fSlamVol = 0.85f ;
}
PlayerRoughLandingEffects ( fSlamVol ) ;
return blocked ;
}
//-----------------------------------------------------------------------------
// Purpose: Determine whether or not the player is on a ladder (physprop or world).
//-----------------------------------------------------------------------------
inline bool CGameMovement : : OnLadder ( trace_t & trace )
{
if ( trace . contents & CONTENTS_LADDER )
return true ;
IPhysicsSurfaceProps * pPhysProps = MoveHelper ( ) - > GetSurfaceProps ( ) ;
if ( pPhysProps )
{
const surfacedata_t * pSurfaceData = pPhysProps - > GetSurfaceData ( trace . surface . surfaceProps ) ;
if ( pSurfaceData )
{
if ( pSurfaceData - > game . climbable ! = 0 )
return true ;
}
}
return false ;
}
//=============================================================================
// HPE_BEGIN
// [sbodenbender] make ladders easier to climb in cstrike
//=============================================================================
# if defined (CSTRIKE_DLL)
ConVar sv_ladder_dampen ( " sv_ladder_dampen " , " 0.2 " , FCVAR_REPLICATED , " Amount to dampen perpendicular movement on a ladder " , true , 0.0f , true , 1.0f ) ;
ConVar sv_ladder_angle ( " sv_ladder_angle " , " -0.707 " , FCVAR_REPLICATED , " Cos of angle of incidence to ladder perpendicular for applying ladder_dampen " , true , - 1.0f , true , 1.0f ) ;
# endif
//=============================================================================
// HPE_END
//=============================================================================
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CGameMovement : : LadderMove ( void )
{
trace_t pm ;
bool onFloor ;
Vector floor ;
Vector wishdir ;
Vector end ;
if ( player - > GetMoveType ( ) = = MOVETYPE_NOCLIP )
return false ;
if ( ! GameHasLadders ( ) )
return false ;
// If I'm already moving on a ladder, use the previous ladder direction
if ( player - > GetMoveType ( ) = = MOVETYPE_LADDER )
{
wishdir = - player - > m_vecLadderNormal ;
}
else
{
// otherwise, use the direction player is attempting to move
if ( mv - > m_flForwardMove | | mv - > m_flSideMove )
{
for ( int i = 0 ; i < 3 ; i + + ) // Determine x and y parts of velocity
wishdir [ i ] = m_vecForward [ i ] * mv - > m_flForwardMove + m_vecRight [ i ] * mv - > m_flSideMove ;
VectorNormalize ( wishdir ) ;
}
else
{
// Player is not attempting to move, no ladder behavior
return false ;
}
}
// wishdir points toward the ladder if any exists
VectorMA ( mv - > GetAbsOrigin ( ) , LadderDistance ( ) , wishdir , end ) ;
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , end , LadderMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
// no ladder in that direction, return
if ( pm . fraction = = 1.0f | | ! OnLadder ( pm ) )
return false ;
player - > SetMoveType ( MOVETYPE_LADDER ) ;
player - > SetMoveCollide ( MOVECOLLIDE_DEFAULT ) ;
player - > m_vecLadderNormal = pm . plane . normal ;
// On ladder, convert movement to be relative to the ladder
VectorCopy ( mv - > GetAbsOrigin ( ) , floor ) ;
floor [ 2 ] + = GetPlayerMins ( ) [ 2 ] - 1 ;
if ( enginetrace - > GetPointContents ( floor ) = = CONTENTS_SOLID | | player - > GetGroundEntity ( ) ! = NULL )
{
onFloor = true ;
}
else
{
onFloor = false ;
}
player - > SetGravity ( 0 ) ;
float climbSpeed = ClimbSpeed ( ) ;
float forwardSpeed = 0 , rightSpeed = 0 ;
if ( mv - > m_nButtons & IN_BACK )
forwardSpeed - = climbSpeed ;
if ( mv - > m_nButtons & IN_FORWARD )
forwardSpeed + = climbSpeed ;
if ( mv - > m_nButtons & IN_MOVELEFT )
rightSpeed - = climbSpeed ;
if ( mv - > m_nButtons & IN_MOVERIGHT )
rightSpeed + = climbSpeed ;
if ( mv - > m_nButtons & IN_JUMP )
{
player - > SetMoveType ( MOVETYPE_WALK ) ;
player - > SetMoveCollide ( MOVECOLLIDE_DEFAULT ) ;
VectorScale ( pm . plane . normal , 270 , mv - > m_vecVelocity ) ;
}
else
{
if ( forwardSpeed ! = 0 | | rightSpeed ! = 0 )
{
Vector velocity , perp , cross , lateral , tmp ;
//ALERT(at_console, "pev %.2f %.2f %.2f - ",
// pev->velocity.x, pev->velocity.y, pev->velocity.z);
// Calculate player's intended velocity
//Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right);
VectorScale ( m_vecForward , forwardSpeed , velocity ) ;
VectorMA ( velocity , rightSpeed , m_vecRight , velocity ) ;
// Perpendicular in the ladder plane
VectorCopy ( vec3_origin , tmp ) ;
tmp [ 2 ] = 1 ;
CrossProduct ( tmp , pm . plane . normal , perp ) ;
VectorNormalize ( perp ) ;
// decompose velocity into ladder plane
float normal = DotProduct ( velocity , pm . plane . normal ) ;
// This is the velocity into the face of the ladder
VectorScale ( pm . plane . normal , normal , cross ) ;
// This is the player's additional velocity
VectorSubtract ( velocity , cross , lateral ) ;
// This turns the velocity into the face of the ladder into velocity that
// is roughly vertically perpendicular to the face of the ladder.
// NOTE: It IS possible to face up and move down or face down and move up
// because the velocity is a sum of the directional velocity and the converted
// velocity through the face of the ladder -- by design.
CrossProduct ( pm . plane . normal , perp , tmp ) ;
//=============================================================================
// HPE_BEGIN
// [sbodenbender] make ladders easier to climb in cstrike
//=============================================================================
# if defined (CSTRIKE_DLL)
// break lateral into direction along tmp (up the ladder) and direction along perp (perpendicular to ladder)
float tmpDist = DotProduct ( tmp , lateral ) ;
float perpDist = DotProduct ( perp , lateral ) ;
Vector angleVec = perp * perpDist ;
angleVec + = cross ;
// angleVec is our desired movement in the ladder normal/perpendicular plane
VectorNormalize ( angleVec ) ;
float angleDot = DotProduct ( angleVec , pm . plane . normal ) ;
// angleDot is our angle of incidence to the laddernormal in the ladder normal/perpendicular plane
if ( angleDot < sv_ladder_angle . GetFloat ( ) )
lateral = ( tmp * tmpDist ) + ( perp * sv_ladder_dampen . GetFloat ( ) * perpDist ) ;
# endif // CSTRIKE_DLL
//=============================================================================
// HPE_END
//=============================================================================
VectorMA ( lateral , - normal , tmp , mv - > m_vecVelocity ) ;
if ( onFloor & & normal > 0 ) // On ground moving away from the ladder
{
VectorMA ( mv - > m_vecVelocity , MAX_CLIMB_SPEED , pm . plane . normal , mv - > m_vecVelocity ) ;
}
//pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal);
}
else
{
mv - > m_vecVelocity . Init ( ) ;
}
}
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : axis -
// Output : const char
//-----------------------------------------------------------------------------
# if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
const char * DescribeAxis ( int axis )
{
static char sz [ 32 ] ;
switch ( axis )
{
case 0 :
Q_strncpy ( sz , " X " , sizeof ( sz ) ) ;
break ;
case 1 :
Q_strncpy ( sz , " Y " , sizeof ( sz ) ) ;
break ;
case 2 :
default :
Q_strncpy ( sz , " Z " , sizeof ( sz ) ) ;
break ;
}
return sz ;
}
# else
const char * DescribeAxis ( int axis ) ;
# endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : CheckVelocity ( void )
{
int i ;
//
// bound velocity
//
Vector org = mv - > GetAbsOrigin ( ) ;
for ( i = 0 ; i < 3 ; i + + )
{
// See if it's bogus.
if ( IS_NAN ( mv - > m_vecVelocity [ i ] ) )
{
DevMsg ( 1 , " PM Got a NaN velocity %s \n " , DescribeAxis ( i ) ) ;
mv - > m_vecVelocity [ i ] = 0 ;
}
if ( IS_NAN ( org [ i ] ) )
{
DevMsg ( 1 , " PM Got a NaN origin on %s \n " , DescribeAxis ( i ) ) ;
org [ i ] = 0 ;
mv - > SetAbsOrigin ( org ) ;
}
// Bound it.
if ( mv - > m_vecVelocity [ i ] > sv_maxvelocity . GetFloat ( ) )
{
DevMsg ( 1 , " PM Got a velocity too high on %s \n " , DescribeAxis ( i ) ) ;
mv - > m_vecVelocity [ i ] = sv_maxvelocity . GetFloat ( ) ;
}
else if ( mv - > m_vecVelocity [ i ] < - sv_maxvelocity . GetFloat ( ) )
{
DevMsg ( 1 , " PM Got a velocity too low on %s \n " , DescribeAxis ( i ) ) ;
mv - > m_vecVelocity [ i ] = - sv_maxvelocity . GetFloat ( ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : AddGravity ( void )
{
float ent_gravity ;
if ( player - > m_flWaterJumpTime )
return ;
if ( player - > GetGravity ( ) )
ent_gravity = player - > GetGravity ( ) ;
else
ent_gravity = 1.0 ;
// Add gravity incorrectly
mv - > m_vecVelocity [ 2 ] - = ( ent_gravity * GetCurrentGravity ( ) * gpGlobals - > frametime ) ;
mv - > m_vecVelocity [ 2 ] + = player - > GetBaseVelocity ( ) [ 2 ] * gpGlobals - > frametime ;
Vector temp = player - > GetBaseVelocity ( ) ;
temp [ 2 ] = 0 ;
player - > SetBaseVelocity ( temp ) ;
CheckVelocity ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : push -
// Output : trace_t
//-----------------------------------------------------------------------------
void CGameMovement : : PushEntity ( Vector & push , trace_t * pTrace )
{
Vector end ;
VectorAdd ( mv - > GetAbsOrigin ( ) , push , end ) ;
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , end , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , * pTrace ) ;
mv - > SetAbsOrigin ( pTrace - > endpos ) ;
// So we can run impact function afterwards.
// If
if ( pTrace - > fraction < 1.0 & & ! pTrace - > allsolid )
{
MoveHelper ( ) - > AddToTouched ( * pTrace , mv - > m_vecVelocity ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : in -
// normal -
// out -
// overbounce -
// Output : int
//-----------------------------------------------------------------------------
int CGameMovement : : ClipVelocity ( Vector & in , Vector & normal , Vector & out , float overbounce )
{
float backoff ;
float change ;
float angle ;
int i , blocked ;
angle = normal [ 2 ] ;
blocked = 0x00 ; // Assume unblocked.
if ( angle > 0 ) // If the plane that is blocking us has a positive z component, then assume it's a floor.
blocked | = 0x01 ; //
if ( ! angle ) // If the plane has no Z, it is vertical (wall/step)
blocked | = 0x02 ; //
// Determine how far along plane to slide based on incoming direction.
backoff = DotProduct ( in , normal ) * overbounce ;
for ( i = 0 ; i < 3 ; i + + )
{
change = normal [ i ] * backoff ;
out [ i ] = in [ i ] - change ;
}
// iterate once to make sure we aren't still moving through the plane
float adjust = DotProduct ( out , normal ) ;
if ( adjust < 0.0f )
{
out - = ( normal * adjust ) ;
// Msg( "Adjustment = %lf\n", adjust );
}
// Return blocking flags.
return blocked ;
}
//-----------------------------------------------------------------------------
// Purpose: Computes roll angle for a certain movement direction and velocity
// Input : angles -
// velocity -
// rollangle -
// rollspeed -
// Output : float
//-----------------------------------------------------------------------------
float CGameMovement : : CalcRoll ( const QAngle & angles , const Vector & velocity , float rollangle , float rollspeed )
{
float sign ;
float side ;
float value ;
Vector forward , right , up ;
AngleVectors ( angles , & forward , & right , & up ) ;
side = DotProduct ( velocity , right ) ;
sign = side < 0 ? - 1 : 1 ;
side = fabs ( side ) ;
value = rollangle ;
if ( side < rollspeed )
{
side = side * value / rollspeed ;
}
else
{
side = value ;
}
return side * sign ;
}
# define CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly.
# if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
Vector rgv3tStuckTable [ 54 ] ;
# else
extern Vector rgv3tStuckTable [ 54 ] ;
# endif
# if !defined(_STATIC_LINKED) || defined(CLIENT_DLL)
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CreateStuckTable ( void )
{
float x , y , z ;
int idx ;
int i ;
float zi [ 3 ] ;
static int firsttime = 1 ;
if ( ! firsttime )
return ;
firsttime = 0 ;
memset ( rgv3tStuckTable , 0 , sizeof ( rgv3tStuckTable ) ) ;
idx = 0 ;
// Little Moves.
x = y = 0 ;
// Z moves
for ( z = - 0.125 ; z < = 0.125 ; z + = 0.125 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
x = z = 0 ;
// Y moves
for ( y = - 0.125 ; y < = 0.125 ; y + = 0.125 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
y = z = 0 ;
// X moves
for ( x = - 0.125 ; x < = 0.125 ; x + = 0.125 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
// Remaining multi axis nudges.
for ( x = - 0.125 ; x < = 0.125 ; x + = 0.250 )
{
for ( y = - 0.125 ; y < = 0.125 ; y + = 0.250 )
{
for ( z = - 0.125 ; z < = 0.125 ; z + = 0.250 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
}
}
// Big Moves.
x = y = 0 ;
zi [ 0 ] = 0.0f ;
zi [ 1 ] = 1.0f ;
zi [ 2 ] = 6.0f ;
for ( i = 0 ; i < 3 ; i + + )
{
// Z moves
z = zi [ i ] ;
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
x = z = 0 ;
// Y moves
for ( y = - 2.0f ; y < = 2.0f ; y + = 2.0 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
y = z = 0 ;
// X moves
for ( x = - 2.0f ; x < = 2.0f ; x + = 2.0f )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
// Remaining multi axis nudges.
for ( i = 0 ; i < 3 ; i + + )
{
z = zi [ i ] ;
for ( x = - 2.0f ; x < = 2.0f ; x + = 2.0f )
{
for ( y = - 2.0f ; y < = 2.0f ; y + = 2.0 )
{
rgv3tStuckTable [ idx ] [ 0 ] = x ;
rgv3tStuckTable [ idx ] [ 1 ] = y ;
rgv3tStuckTable [ idx ] [ 2 ] = z ;
idx + + ;
}
}
}
Assert ( idx < sizeof ( rgv3tStuckTable ) / sizeof ( rgv3tStuckTable [ 0 ] ) ) ;
}
# else
extern void CreateStuckTable ( void ) ;
# endif
//-----------------------------------------------------------------------------
// Purpose:
// Input : nIndex -
// server -
// offset -
// Output : int
//-----------------------------------------------------------------------------
int GetRandomStuckOffsets ( CBasePlayer * pPlayer , Vector & offset )
{
// Last time we did a full
int idx ;
idx = pPlayer - > m_StuckLast + + ;
VectorCopy ( rgv3tStuckTable [ idx % 54 ] , offset ) ;
return ( idx % 54 ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nIndex -
// server -
//-----------------------------------------------------------------------------
void ResetStuckOffsets ( CBasePlayer * pPlayer )
{
pPlayer - > m_StuckLast = 0 ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &input -
// Output : int
//-----------------------------------------------------------------------------
int CGameMovement : : CheckStuck ( void )
{
Vector base ;
Vector offset ;
Vector test ;
EntityHandle_t hitent ;
int idx ;
float fTime ;
trace_t traceresult ;
CreateStuckTable ( ) ;
hitent = TestPlayerPosition ( mv - > GetAbsOrigin ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , traceresult ) ;
if ( hitent = = INVALID_ENTITY_HANDLE )
{
ResetStuckOffsets ( player ) ;
return 0 ;
}
// Deal with stuckness...
# ifndef DEDICATED
if ( developer . GetBool ( ) )
{
bool isServer = player - > IsServer ( ) ;
engine - > Con_NPrintf ( isServer , " %s stuck on object %i/%s " ,
isServer ? " server " : " client " ,
hitent . GetEntryIndex ( ) , MoveHelper ( ) - > GetName ( hitent ) ) ;
}
# endif
VectorCopy ( mv - > GetAbsOrigin ( ) , base ) ;
//
// Deal with precision error in network.
//
// World or BSP model
if ( ! player - > IsServer ( ) )
{
if ( MoveHelper ( ) - > IsWorldEntity ( hitent ) )
{
int nReps = 0 ;
ResetStuckOffsets ( player ) ;
do
{
GetRandomStuckOffsets ( player , offset ) ;
VectorAdd ( base , offset , test ) ;
if ( TestPlayerPosition ( test , COLLISION_GROUP_PLAYER_MOVEMENT , traceresult ) = = INVALID_ENTITY_HANDLE )
{
ResetStuckOffsets ( player ) ;
mv - > SetAbsOrigin ( test ) ;
return 0 ;
}
nReps + + ;
} while ( nReps < 54 ) ;
}
}
// Only an issue on the client.
idx = player - > IsServer ( ) ? 0 : 1 ;
fTime = engine - > Time ( ) ;
// Too soon?
if ( m_flStuckCheckTime [ player - > entindex ( ) ] [ idx ] > = fTime - CHECKSTUCK_MINTIME )
{
return 1 ;
}
m_flStuckCheckTime [ player - > entindex ( ) ] [ idx ] = fTime ;
MoveHelper ( ) - > AddToTouched ( traceresult , mv - > m_vecVelocity ) ;
GetRandomStuckOffsets ( player , offset ) ;
VectorAdd ( base , offset , test ) ;
if ( TestPlayerPosition ( test , COLLISION_GROUP_PLAYER_MOVEMENT , traceresult ) = = INVALID_ENTITY_HANDLE )
{
ResetStuckOffsets ( player ) ;
mv - > SetAbsOrigin ( test ) ;
return 0 ;
}
return 1 ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : bool
//-----------------------------------------------------------------------------
bool CGameMovement : : InWater ( void )
{
return ( player - > GetWaterLevel ( ) > WL_Feet ) ;
}
void CGameMovement : : ResetGetPointContentsCache ( )
{
for ( int slot = 0 ; slot < MAX_PC_CACHE_SLOTS ; + + slot )
{
for ( int i = 0 ; i < MAX_PLAYERS ; + + i )
{
m_CachedGetPointContents [ i ] [ slot ] = - 9999 ;
}
}
}
int CGameMovement : : GetPointContentsCached ( const Vector & point , int slot )
{
if ( g_bMovementOptimizations )
{
Assert ( player ) ;
Assert ( slot > = 0 & & slot < MAX_PC_CACHE_SLOTS ) ;
int idx = player - > entindex ( ) - 1 ;
if ( m_CachedGetPointContents [ idx ] [ slot ] = = - 9999 | | point . DistToSqr ( m_CachedGetPointContentsPoint [ idx ] [ slot ] ) > 1 )
{
m_CachedGetPointContents [ idx ] [ slot ] = enginetrace - > GetPointContents ( point ) ;
m_CachedGetPointContentsPoint [ idx ] [ slot ] = point ;
}
return m_CachedGetPointContents [ idx ] [ slot ] ;
}
else
{
return enginetrace - > GetPointContents ( point ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &input -
// Output : bool
//-----------------------------------------------------------------------------
bool CGameMovement : : CheckWater ( void )
{
Vector point ;
int cont ;
Vector vPlayerMins = GetPlayerMins ( ) ;
Vector vPlayerMaxs = GetPlayerMaxs ( ) ;
// Pick a spot just above the players feet.
point [ 0 ] = mv - > GetAbsOrigin ( ) [ 0 ] + ( vPlayerMins [ 0 ] + vPlayerMaxs [ 0 ] ) * 0.5 ;
point [ 1 ] = mv - > GetAbsOrigin ( ) [ 1 ] + ( vPlayerMins [ 1 ] + vPlayerMaxs [ 1 ] ) * 0.5 ;
point [ 2 ] = mv - > GetAbsOrigin ( ) [ 2 ] + vPlayerMins [ 2 ] + 1 ;
// Assume that we are not in water at all.
player - > SetWaterLevel ( WL_NotInWater ) ;
player - > SetWaterType ( CONTENTS_EMPTY ) ;
// Grab point contents.
cont = GetPointContentsCached ( point , 0 ) ;
// Are we under water? (not solid and not empty?)
if ( cont & MASK_WATER )
{
// Set water type
player - > SetWaterType ( cont ) ;
// We are at least at level one
player - > SetWaterLevel ( WL_Feet ) ;
// Now check a point that is at the player hull midpoint.
point [ 2 ] = mv - > GetAbsOrigin ( ) [ 2 ] + ( vPlayerMins [ 2 ] + vPlayerMaxs [ 2 ] ) * 0.5 ;
cont = GetPointContentsCached ( point , 1 ) ;
// If that point is also under water...
if ( cont & MASK_WATER )
{
// Set a higher water level.
player - > SetWaterLevel ( WL_Waist ) ;
// Now check the eye position. (view_ofs is relative to the origin)
point [ 2 ] = mv - > GetAbsOrigin ( ) [ 2 ] + player - > GetViewOffset ( ) [ 2 ] ;
cont = GetPointContentsCached ( point , 2 ) ;
if ( cont & MASK_WATER )
player - > SetWaterLevel ( WL_Eyes ) ; // In over our eyes
}
// Adjust velocity based on water current, if any.
if ( cont & MASK_CURRENT )
{
Vector v ;
VectorClear ( v ) ;
if ( cont & CONTENTS_CURRENT_0 )
v [ 0 ] + = 1 ;
if ( cont & CONTENTS_CURRENT_90 )
v [ 1 ] + = 1 ;
if ( cont & CONTENTS_CURRENT_180 )
v [ 0 ] - = 1 ;
if ( cont & CONTENTS_CURRENT_270 )
v [ 1 ] - = 1 ;
if ( cont & CONTENTS_CURRENT_UP )
v [ 2 ] + = 1 ;
if ( cont & CONTENTS_CURRENT_DOWN )
v [ 2 ] - = 1 ;
// BUGBUG -- this depends on the value of an unspecified enumerated type
// The deeper we are, the stronger the current.
Vector temp ;
VectorMA ( player - > GetBaseVelocity ( ) , 50.0 * player - > GetWaterLevel ( ) , v , temp ) ;
player - > SetBaseVelocity ( temp ) ;
}
}
// if we just transitioned from not in water to in water, record the time it happened
if ( ( WL_NotInWater = = m_nOldWaterLevel ) & & ( player - > GetWaterLevel ( ) > WL_NotInWater ) )
{
m_flWaterEntryTime = gpGlobals - > curtime ;
}
return ( player - > GetWaterLevel ( ) > WL_Feet ) ;
}
void CGameMovement : : SetGroundEntity ( trace_t * pm )
{
CBaseEntity * newGround = pm ? pm - > m_pEnt : NULL ;
CBaseEntity * oldGround = player - > GetGroundEntity ( ) ;
Vector vecBaseVelocity = player - > GetBaseVelocity ( ) ;
if ( ! oldGround & & newGround )
{
// Subtract ground velocity at instant we hit ground jumping
vecBaseVelocity - = newGround - > GetAbsVelocity ( ) ;
vecBaseVelocity . z = newGround - > GetAbsVelocity ( ) . z ;
}
else if ( oldGround & & ! newGround )
{
// Add in ground velocity at instant we started jumping
vecBaseVelocity + = oldGround - > GetAbsVelocity ( ) ;
vecBaseVelocity . z = oldGround - > GetAbsVelocity ( ) . z ;
}
player - > SetBaseVelocity ( vecBaseVelocity ) ;
player - > SetGroundEntity ( newGround ) ;
// If we are on something...
if ( newGround )
{
CategorizeGroundSurface ( * pm ) ;
// Then we are not in water jump sequence
player - > m_flWaterJumpTime = 0 ;
// Standing on an entity other than the world, so signal that we are touching something.
if ( ! pm - > DidHitWorld ( ) )
{
MoveHelper ( ) - > AddToTouched ( * pm , mv - > m_vecVelocity ) ;
}
mv - > m_vecVelocity . z = 0.0f ;
}
}
//-----------------------------------------------------------------------------
// Traces the player's collision bounds in quadrants, looking for a plane that
// can be stood upon (normal's z >= 0.7f). Regardless of success or failure,
// replace the fraction and endpos with the original ones, so we don't try to
// move the player down to the new floor and get stuck on a leaning wall that
// the original trace hit first.
//-----------------------------------------------------------------------------
void TracePlayerBBoxForGround ( const Vector & start , const Vector & end , const Vector & minsSrc ,
const Vector & maxsSrc , IHandleEntity * player , unsigned int fMask ,
int collisionGroup , trace_t & pm )
{
VPROF ( " TracePlayerBBoxForGround " ) ;
Ray_t ray ;
Vector mins , maxs ;
float fraction = pm . fraction ;
Vector endpos = pm . endpos ;
// Check the -x, -y quadrant
mins = minsSrc ;
maxs . Init ( MIN ( 0 , maxsSrc . x ) , MIN ( 0 , maxsSrc . y ) , maxsSrc . z ) ;
ray . Init ( start , end , mins , maxs ) ;
UTIL_TraceRay ( ray , fMask , player , collisionGroup , & pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the +x, +y quadrant
mins . Init ( MAX ( 0 , minsSrc . x ) , MAX ( 0 , minsSrc . y ) , minsSrc . z ) ;
maxs = maxsSrc ;
ray . Init ( start , end , mins , maxs ) ;
UTIL_TraceRay ( ray , fMask , player , collisionGroup , & pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the -x, +y quadrant
mins . Init ( minsSrc . x , MAX ( 0 , minsSrc . y ) , minsSrc . z ) ;
maxs . Init ( MIN ( 0 , maxsSrc . x ) , maxsSrc . y , maxsSrc . z ) ;
ray . Init ( start , end , mins , maxs ) ;
UTIL_TraceRay ( ray , fMask , player , collisionGroup , & pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the +x, -y quadrant
mins . Init ( MAX ( 0 , minsSrc . x ) , minsSrc . y , minsSrc . z ) ;
maxs . Init ( maxsSrc . x , MIN ( 0 , maxsSrc . y ) , maxsSrc . z ) ;
ray . Init ( start , end , mins , maxs ) ;
UTIL_TraceRay ( ray , fMask , player , collisionGroup , & pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
pm . fraction = fraction ;
pm . endpos = endpos ;
}
//-----------------------------------------------------------------------------
// Traces the player's collision bounds in quadrants, looking for a plane that
// can be stood upon (normal's z >= 0.7f). Regardless of success or failure,
// replace the fraction and endpos with the original ones, so we don't try to
// move the player down to the new floor and get stuck on a leaning wall that
// the original trace hit first.
//-----------------------------------------------------------------------------
void CGameMovement : : TryTouchGroundInQuadrants ( const Vector & start , const Vector & end , unsigned int fMask , int collisionGroup , trace_t & pm )
{
VPROF ( " CGameMovement::TryTouchGroundInQuadrants " ) ;
Vector mins , maxs ;
Vector minsSrc = GetPlayerMins ( ) ;
Vector maxsSrc = GetPlayerMaxs ( ) ;
float fraction = pm . fraction ;
Vector endpos = pm . endpos ;
// Check the -x, -y quadrant
mins = minsSrc ;
maxs . Init ( MIN ( 0 , maxsSrc . x ) , MIN ( 0 , maxsSrc . y ) , maxsSrc . z ) ;
TryTouchGround ( start , end , mins , maxs , fMask , collisionGroup , pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the +x, +y quadrant
mins . Init ( MAX ( 0 , minsSrc . x ) , MAX ( 0 , minsSrc . y ) , minsSrc . z ) ;
maxs = maxsSrc ;
TryTouchGround ( start , end , mins , maxs , fMask , collisionGroup , pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the -x, +y quadrant
mins . Init ( minsSrc . x , MAX ( 0 , minsSrc . y ) , minsSrc . z ) ;
maxs . Init ( MIN ( 0 , maxsSrc . x ) , maxsSrc . y , maxsSrc . z ) ;
TryTouchGround ( start , end , mins , maxs , fMask , collisionGroup , pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
// Check the +x, -y quadrant
mins . Init ( MAX ( 0 , minsSrc . x ) , minsSrc . y , minsSrc . z ) ;
maxs . Init ( maxsSrc . x , MIN ( 0 , maxsSrc . y ) , maxsSrc . z ) ;
TryTouchGround ( start , end , mins , maxs , fMask , collisionGroup , pm ) ;
if ( pm . m_pEnt & & pm . plane . normal [ 2 ] > = 0.7 )
{
pm . fraction = fraction ;
pm . endpos = endpos ;
return ;
}
pm . fraction = fraction ;
pm . endpos = endpos ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &input -
//-----------------------------------------------------------------------------
void CGameMovement : : CategorizePosition ( void )
{
Vector point ;
trace_t pm ;
// Reset this each time we-recategorize, otherwise we have bogus friction when we jump into water and plunge downward really quickly
player - > m_surfaceFriction = 1.0f ;
// if the player hull point one unit down is solid, the player
// is on ground
// see if standing on something solid
// Doing this before we move may introduce a potential latency in water detection, but
// doing it after can get us stuck on the bottom in water if the amount we move up
// is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call
// this several times per frame, so we really need to avoid sticking to the bottom of
// water on each call, and the converse case will correct itself if called twice.
CheckWater ( ) ;
// observers don't have a ground entity
if ( player - > IsObserver ( ) )
return ;
float flOffset = 2.0f ;
point [ 0 ] = mv - > GetAbsOrigin ( ) [ 0 ] ;
point [ 1 ] = mv - > GetAbsOrigin ( ) [ 1 ] ;
point [ 2 ] = mv - > GetAbsOrigin ( ) [ 2 ] - flOffset ;
Vector bumpOrigin ;
bumpOrigin = mv - > GetAbsOrigin ( ) ;
// Shooting up really fast. Definitely not on ground.
// On ladder moving up, so not on ground either
// NOTE: 145 is a jump.
# define NON_JUMP_VELOCITY 140.0f
float zvel = mv - > m_vecVelocity [ 2 ] ;
bool bMovingUp = zvel > 0.0f ;
bool bMovingUpRapidly = zvel > NON_JUMP_VELOCITY ;
float flGroundEntityVelZ = 0.0f ;
if ( bMovingUpRapidly )
{
// Tracker 73219, 75878: ywb 8/2/07
// After save/restore (and maybe at other times), we can get a case where we were saved on a lift and
// after restore we'll have a high local velocity due to the lift making our abs velocity appear high.
// We need to account for standing on a moving ground object in that case in order to determine if we really
// are moving away from the object we are standing on at too rapid a speed. Note that CheckJump already sets
// ground entity to NULL, so this wouldn't have any effect unless we are moving up rapidly not from the jump button.
CBaseEntity * ground = player - > GetGroundEntity ( ) ;
if ( ground )
{
flGroundEntityVelZ = ground - > GetAbsVelocity ( ) . z ;
bMovingUpRapidly = ( zvel - flGroundEntityVelZ ) > NON_JUMP_VELOCITY ;
}
}
// Was on ground, but now suddenly am not
if ( bMovingUpRapidly | |
( bMovingUp & & player - > GetMoveType ( ) = = MOVETYPE_LADDER ) )
{
SetGroundEntity ( NULL ) ;
}
else
{
// Try and move down.
TryTouchGround ( bumpOrigin , point , GetPlayerMins ( ) , GetPlayerMaxs ( ) , MASK_PLAYERSOLID , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
// Was on ground, but now suddenly am not. If we hit a steep plane, we are not on ground
if ( ! pm . m_pEnt | | pm . plane . normal [ 2 ] < 0.7 )
{
// Test four sub-boxes, to see if any of them would have found shallower slope we could actually stand on
TryTouchGroundInQuadrants ( bumpOrigin , point , MASK_PLAYERSOLID , COLLISION_GROUP_PLAYER_MOVEMENT , pm ) ;
if ( ! pm . m_pEnt | | pm . plane . normal [ 2 ] < 0.7 )
{
SetGroundEntity ( NULL ) ;
// probably want to add a check for a +z velocity too!
if ( ( mv - > m_vecVelocity . z > 0.0f ) & &
( player - > GetMoveType ( ) ! = MOVETYPE_NOCLIP ) )
{
player - > m_surfaceFriction = 0.25f ;
}
}
else
{
SetGroundEntity ( & pm ) ;
}
}
else
{
SetGroundEntity ( & pm ) ; // Otherwise, point to index of ent under us.
}
# ifndef CLIENT_DLL
//Adrian: vehicle code handles for us.
if ( player - > IsInAVehicle ( ) = = false )
{
// If our gamematerial has changed, tell any player surface triggers that are watching
IPhysicsSurfaceProps * physprops = MoveHelper ( ) - > GetSurfaceProps ( ) ;
surfacedata_t * pSurfaceProp = physprops - > GetSurfaceData ( pm . surface . surfaceProps ) ;
char cCurrGameMaterial = pSurfaceProp - > game . material ;
if ( ! player - > GetGroundEntity ( ) )
{
cCurrGameMaterial = 0 ;
}
// Changed?
if ( player - > m_chPreviousTextureType ! = cCurrGameMaterial )
{
CEnvPlayerSurfaceTrigger : : SetPlayerSurface ( player , cCurrGameMaterial ) ;
}
player - > m_chPreviousTextureType = cCurrGameMaterial ;
}
# endif
}
}
//-----------------------------------------------------------------------------
// Purpose: Determine if the player has hit the ground while falling, apply
// damage, and play the appropriate impact sound.
//-----------------------------------------------------------------------------
void CGameMovement : : CheckFalling ( void )
{
// this function really deals with landing, not falling, so early out otherwise
if ( player - > GetGroundEntity ( ) = = NULL | | player - > m_Local . m_flFallVelocity < = 0 )
return ;
if ( ! IsDead ( ) & & player - > m_Local . m_flFallVelocity > = PLAYER_FALL_PUNCH_THRESHOLD )
{
bool bAlive = true ;
float fvol = 0.5 ;
if ( player - > GetWaterLevel ( ) > 0 )
{
// They landed in water.
}
else
{
// Scale it down if we landed on something that's floating...
if ( player - > GetGroundEntity ( ) - > IsFloating ( ) )
{
player - > m_Local . m_flFallVelocity - = PLAYER_LAND_ON_FLOATING_OBJECT ;
}
//
// They hit the ground.
//
if ( player - > GetGroundEntity ( ) - > GetAbsVelocity ( ) . z < 0.0f )
{
// Player landed on a descending object. Subtract the velocity of the ground entity.
player - > m_Local . m_flFallVelocity + = player - > GetGroundEntity ( ) - > GetAbsVelocity ( ) . z ;
player - > m_Local . m_flFallVelocity = MAX ( 0.1f , player - > m_Local . m_flFallVelocity ) ;
}
if ( player - > m_Local . m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED )
{
//
// If they hit the ground going this fast they may take damage (and die).
//
bAlive = MoveHelper ( ) - > PlayerFallingDamage ( ) ;
fvol = 1.0 ;
}
else if ( player - > m_Local . m_flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 )
{
fvol = 0.85 ;
}
else if ( player - > m_Local . m_flFallVelocity < PLAYER_MIN_BOUNCE_SPEED )
{
fvol = 0 ;
}
}
PlayerRoughLandingEffects ( fvol ) ;
if ( bAlive )
{
MoveHelper ( ) - > PlayerSetAnimation ( PLAYER_WALK ) ;
}
}
// let any subclasses know that the player has landed and how hard
OnLand ( player - > m_Local . m_flFallVelocity ) ;
//
// Clear the fall velocity so the impact doesn't happen again.
//
player - > m_Local . m_flFallVelocity = 0 ;
}
void CGameMovement : : PlayerRoughLandingEffects ( float fvol )
{
if ( fvol > 0.0 )
{
//
// Play landing sound right away.
player - > m_flStepSoundTime = 400 ;
// Play step sound for current texture.
player - > PlayStepSound ( ( Vector & ) mv - > GetAbsOrigin ( ) , player - > m_pSurfaceData , fvol , true ) ;
//
// Knock the screen around a little bit, temporary effect.
//
player - > m_Local . m_vecPunchAngle . Set ( ROLL , player - > m_Local . m_flFallVelocity * 0.013 ) ;
if ( player - > m_Local . m_vecPunchAngle [ PITCH ] > 8 )
{
player - > m_Local . m_vecPunchAngle . Set ( PITCH , 8 ) ;
}
# if !defined( CLIENT_DLL )
player - > RumbleEffect ( ( fvol > 0.85f ) ? ( RUMBLE_FALL_LONG ) : ( RUMBLE_FALL_SHORT ) , 0 , RUMBLE_FLAGS_NONE ) ;
# endif
}
}
//-----------------------------------------------------------------------------
// Purpose: Use for ease-in, ease-out style interpolation (accel/decel) Used by ducking code.
// Input : value -
// scale -
// Output : float
//-----------------------------------------------------------------------------
float CGameMovement : : SplineFraction ( float value , float scale )
{
float valueSquared ;
value = scale * value ;
valueSquared = value * value ;
// Nice little ease-in, ease-out spline-like curve
return 3 * valueSquared - 2 * valueSquared * value ;
}
//-----------------------------------------------------------------------------
// Purpose: Determine if crouch/uncrouch caused player to get stuck in world
// Input : direction -
//-----------------------------------------------------------------------------
void CGameMovement : : FixPlayerCrouchStuck ( bool upward )
{
EntityHandle_t hitent ;
int i ;
Vector test ;
trace_t dummy ;
int direction = upward ? 1 : 0 ;
hitent = TestPlayerPosition ( mv - > GetAbsOrigin ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , dummy ) ;
if ( hitent = = INVALID_ENTITY_HANDLE )
return ;
VectorCopy ( mv - > GetAbsOrigin ( ) , test ) ;
for ( i = 0 ; i < 36 ; i + + )
{
Vector org = mv - > GetAbsOrigin ( ) ;
org . z + = direction ;
mv - > SetAbsOrigin ( org ) ;
hitent = TestPlayerPosition ( mv - > GetAbsOrigin ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , dummy ) ;
if ( hitent = = INVALID_ENTITY_HANDLE )
return ;
}
mv - > SetAbsOrigin ( test ) ; // Failed
}
bool CGameMovement : : CanUnduck ( )
{
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
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 ) ;
}
bool saveducked = player - > m_Local . m_bDucked ;
player - > m_Local . m_bDucked = false ;
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , newOrigin , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
player - > m_Local . m_bDucked = saveducked ;
if ( trace . startsolid | | ( trace . fraction ! = 1.0f ) )
return false ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Stop ducking
//-----------------------------------------------------------------------------
void CGameMovement : : 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
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 ;
player - > m_Local . m_bInDuckJump = false ;
player - > SetViewOffset ( GetPlayerViewOffset ( false ) ) ;
player - > m_Local . m_flDucktime = 0 ;
mv - > SetAbsOrigin ( newOrigin ) ;
# ifdef CLIENT_DLL
# ifdef STAGING_ONLY
if ( debug_latch_reset_onduck . GetBool ( ) )
{
player - > ResetLatched ( ) ;
}
# else
player - > ResetLatched ( ) ;
# endif
# endif // CLIENT_DLL
// Recategorize position since ducking can change origin
CategorizePosition ( ) ;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CGameMovement : : UpdateDuckJumpEyeOffset ( void )
{
if ( player - > m_Local . m_flDuckJumpTime ! = 0.0f )
{
float flDuckMilliseconds = MAX ( 0.0f , GAMEMOVEMENT_DUCK_TIME - ( float ) player - > m_Local . m_flDuckJumpTime ) ;
float flDuckSeconds = flDuckMilliseconds / GAMEMOVEMENT_DUCK_TIME ;
if ( flDuckSeconds > TIME_TO_UNDUCK )
{
player - > m_Local . m_flDuckJumpTime = 0.0f ;
SetDuckedEyeOffset ( 0.0f ) ;
}
else
{
float flDuckFraction = SimpleSpline ( 1.0f - ( flDuckSeconds / TIME_TO_UNDUCK ) ) ;
SetDuckedEyeOffset ( flDuckFraction ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FinishUnDuckJump ( trace_t & trace )
{
Vector vecNewOrigin ;
VectorCopy ( mv - > GetAbsOrigin ( ) , vecNewOrigin ) ;
// 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 = ( hullSizeNormal - hullSizeCrouch ) ;
float flDeltaZ = viewDelta . z ;
viewDelta . z * = trace . fraction ;
flDeltaZ - = viewDelta . z ;
player - > RemoveFlag ( FL_DUCKING ) ;
player - > m_Local . m_bDucked = false ;
player - > m_Local . m_bDucking = false ;
player - > m_Local . m_bInDuckJump = false ;
player - > m_Local . m_flDucktime = 0.0f ;
player - > m_Local . m_flDuckJumpTime = 0.0f ;
player - > m_Local . m_flJumpTime = 0.0f ;
Vector vecViewOffset = GetPlayerViewOffset ( false ) ;
vecViewOffset . z - = flDeltaZ ;
player - > SetViewOffset ( vecViewOffset ) ;
VectorSubtract ( vecNewOrigin , viewDelta , vecNewOrigin ) ;
mv - > SetAbsOrigin ( vecNewOrigin ) ;
// Recategorize position since ducking can change origin
CategorizePosition ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Finish ducking
//-----------------------------------------------------------------------------
void CGameMovement : : FinishDuck ( void )
{
if ( player - > GetFlags ( ) & FL_DUCKING )
return ;
player - > AddFlag ( FL_DUCKING ) ;
player - > m_Local . m_bDucked = true ;
player - > m_Local . m_bDucking = false ;
player - > SetViewOffset ( GetPlayerViewOffset ( true ) ) ;
// HACKHACK - Fudge for collision bug - no time to fix this properly
if ( player - > GetGroundEntity ( ) ! = NULL )
{
for ( int i = 0 ; i < 3 ; i + + )
{
Vector org = mv - > GetAbsOrigin ( ) ;
org [ i ] - = ( VEC_DUCK_HULL_MIN_SCALED ( player ) [ i ] - VEC_HULL_MIN_SCALED ( player ) [ i ] ) ;
mv - > SetAbsOrigin ( org ) ;
}
}
else
{
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 ) ;
Vector out ;
VectorAdd ( mv - > GetAbsOrigin ( ) , viewDelta , out ) ;
mv - > SetAbsOrigin ( out ) ;
# ifdef CLIENT_DLL
# ifdef STAGING_ONLY
if ( debug_latch_reset_onduck . GetBool ( ) )
{
player - > ResetLatched ( ) ;
}
# else
player - > ResetLatched ( ) ;
# endif
# endif // CLIENT_DLL
}
// See if we are stuck?
FixPlayerCrouchStuck ( true ) ;
// Recategorize position since ducking can change origin
CategorizePosition ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : StartUnDuckJump ( void )
{
player - > AddFlag ( FL_DUCKING ) ;
player - > m_Local . m_bDucked = true ;
player - > m_Local . m_bDucking = false ;
player - > SetViewOffset ( GetPlayerViewOffset ( true ) ) ;
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 ) ;
Vector out ;
VectorAdd ( mv - > GetAbsOrigin ( ) , viewDelta , out ) ;
mv - > SetAbsOrigin ( out ) ;
// See if we are stuck?
FixPlayerCrouchStuck ( true ) ;
// Recategorize position since ducking can change origin
CategorizePosition ( ) ;
}
//
//-----------------------------------------------------------------------------
// Purpose:
// Input : duckFraction -
//-----------------------------------------------------------------------------
void CGameMovement : : SetDuckedEyeOffset ( float duckFraction )
{
Vector vDuckHullMin = GetPlayerMins ( true ) ;
Vector vStandHullMin = GetPlayerMins ( false ) ;
float fMore = ( vDuckHullMin . z - vStandHullMin . z ) ;
Vector vecDuckViewOffset = GetPlayerViewOffset ( true ) ;
Vector vecStandViewOffset = GetPlayerViewOffset ( false ) ;
Vector temp = player - > GetViewOffset ( ) ;
temp . z = ( ( vecDuckViewOffset . z - fMore ) * duckFraction ) +
( vecStandViewOffset . z * ( 1 - duckFraction ) ) ;
player - > SetViewOffset ( temp ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Crop the speed of the player when ducking and on the ground.
// Input: bInDuck - is the player already ducking
// bInAir - is the player in air
// NOTE: Only crop player speed once.
//-----------------------------------------------------------------------------
void CGameMovement : : HandleDuckingSpeedCrop ( void )
{
if ( ! ( m_iSpeedCropped & SPEED_CROPPED_DUCK ) & & ( player - > GetFlags ( ) & FL_DUCKING ) & & ( player - > GetGroundEntity ( ) ! = NULL ) )
{
float frac = 0.33333333f ;
mv - > m_flForwardMove * = frac ;
mv - > m_flSideMove * = frac ;
mv - > m_flUpMove * = frac ;
m_iSpeedCropped | = SPEED_CROPPED_DUCK ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Check to see if we are in a situation where we can unduck jump.
//-----------------------------------------------------------------------------
bool CGameMovement : : CanUnDuckJump ( trace_t & trace )
{
// Trace down to the stand position and see if we can stand.
Vector vecEnd ( mv - > GetAbsOrigin ( ) ) ;
vecEnd . z - = 36.0f ; // This will have to change if bounding hull change!
TracePlayerBBox ( mv - > GetAbsOrigin ( ) , vecEnd , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , trace ) ;
if ( trace . fraction < 1.0f )
{
// Find the endpoint.
vecEnd . z = mv - > GetAbsOrigin ( ) . z + ( - 36.0f * trace . fraction ) ;
// Test a normal hull.
trace_t traceUp ;
bool bWasDucked = player - > m_Local . m_bDucked ;
player - > m_Local . m_bDucked = false ;
TracePlayerBBox ( vecEnd , vecEnd , PlayerSolidMask ( ) , COLLISION_GROUP_PLAYER_MOVEMENT , traceUp ) ;
player - > m_Local . m_bDucked = bWasDucked ;
if ( ! traceUp . startsolid )
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
// Purpose: See if duck button is pressed and do the appropriate things
//-----------------------------------------------------------------------------
void CGameMovement : : 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"
// Check to see if we are in the air.
bool bInAir = ( player - > GetGroundEntity ( ) = = NULL ) ;
bool bInDuck = ( player - > GetFlags ( ) & FL_DUCKING ) ? true : false ;
bool bDuckJump = ( player - > m_Local . m_flJumpTime > 0.0f ) ;
bool bDuckJumpTime = ( player - > m_Local . m_flDuckJumpTime > 0.0f ) ;
if ( mv - > m_nButtons & IN_DUCK )
{
mv - > m_nOldButtons | = IN_DUCK ;
}
else
{
mv - > m_nOldButtons & = ~ IN_DUCK ;
}
// Handle death.
if ( IsDead ( ) )
return ;
// Slow down ducked players.
HandleDuckingSpeedCrop ( ) ;
// If the player is holding down the duck button, the player is in duck transition, ducking, or duck-jumping.
if ( ( mv - > m_nButtons & IN_DUCK ) | | player - > m_Local . m_bDucking | | bInDuck | | bDuckJump )
{
// DUCK
if ( ( mv - > m_nButtons & IN_DUCK ) | | bDuckJump )
{
// XBOX SERVER ONLY
# if !defined(CLIENT_DLL)
if ( IsX360 ( ) & & buttonsPressed & IN_DUCK )
{
// Hinting logic
if ( player - > GetToggledDuckState ( ) & & player - > m_nNumCrouches < NUM_CROUCH_HINTS )
{
UTIL_HudHintText ( player , " #Valve_Hint_Crouch " ) ;
player - > m_nNumCrouches + + ;
}
}
# endif
// Have the duck button pressed, but the player currently isn't in the duck position.
if ( ( buttonsPressed & IN_DUCK ) & & ! bInDuck & & ! bDuckJump & & ! bDuckJumpTime )
{
player - > m_Local . m_flDucktime = GAMEMOVEMENT_DUCK_TIME ;
player - > m_Local . m_bDucking = true ;
}
// The player is in duck transition and not duck-jumping.
if ( player - > m_Local . m_bDucking & & ! bDuckJump & & ! bDuckJumpTime )
{
float flDuckMilliseconds = MAX ( 0.0f , GAMEMOVEMENT_DUCK_TIME - ( float ) player - > m_Local . m_flDucktime ) ;
float flDuckSeconds = flDuckMilliseconds * 0.001f ;
// Finish in duck transition when transition time is over, in "duck", in air.
if ( ( flDuckSeconds > TIME_TO_DUCK ) | | bInDuck | | bInAir )
{
FinishDuck ( ) ;
}
else
{
// Calc parametric time
float flDuckFraction = SimpleSpline ( flDuckSeconds / TIME_TO_DUCK ) ;
SetDuckedEyeOffset ( flDuckFraction ) ;
}
}
if ( bDuckJump )
{
// Make the bounding box small immediately.
if ( ! bInDuck )
{
StartUnDuckJump ( ) ;
}
else
{
// Check for a crouch override.
if ( ! ( mv - > m_nButtons & IN_DUCK ) )
{
trace_t trace ;
if ( CanUnDuckJump ( trace ) )
{
FinishUnDuckJump ( trace ) ;
player - > m_Local . m_flDuckJumpTime = ( GAMEMOVEMENT_TIME_TO_UNDUCK * ( 1.0f - trace . fraction ) ) + GAMEMOVEMENT_TIME_TO_UNDUCK_INV ;
}
}
}
}
}
// UNDUCK (or attempt to...)
else
{
if ( player - > m_Local . m_bInDuckJump )
{
// Check for a crouch override.
if ( ! ( mv - > m_nButtons & IN_DUCK ) )
{
trace_t trace ;
if ( CanUnDuckJump ( trace ) )
{
FinishUnDuckJump ( trace ) ;
if ( trace . fraction < 1.0f )
{
player - > m_Local . m_flDuckJumpTime = ( GAMEMOVEMENT_TIME_TO_UNDUCK * ( 1.0f - trace . fraction ) ) + GAMEMOVEMENT_TIME_TO_UNDUCK_INV ;
}
}
}
else
{
player - > m_Local . m_bInDuckJump = false ;
}
}
if ( bDuckJumpTime )
return ;
// Try to unduck unless automovement is not allowed
// NOTE: When not onground, you can always unduck
if ( player - > m_Local . m_bAllowAutoMovement | | bInAir | | player - > m_Local . m_bDucking )
{
// We released the duck button, we aren't in "duck" and we are not in the air - start unduck transition.
if ( ( buttonsReleased & IN_DUCK ) )
{
if ( bInDuck & & ! bDuckJump )
{
player - > m_Local . m_flDucktime = GAMEMOVEMENT_DUCK_TIME ;
}
else if ( player - > m_Local . m_bDucking & & ! player - > m_Local . m_bDucked )
{
// Invert time if release before fully ducked!!!
float unduckMilliseconds = 1000.0f * TIME_TO_UNDUCK ;
float duckMilliseconds = 1000.0f * TIME_TO_DUCK ;
float elapsedMilliseconds = GAMEMOVEMENT_DUCK_TIME - player - > m_Local . m_flDucktime ;
float fracDucked = elapsedMilliseconds / duckMilliseconds ;
float remainingUnduckMilliseconds = fracDucked * unduckMilliseconds ;
player - > m_Local . m_flDucktime = GAMEMOVEMENT_DUCK_TIME - unduckMilliseconds + remainingUnduckMilliseconds ;
}
}
// Check to see if we are capable of unducking.
if ( CanUnduck ( ) )
{
// or unducking
if ( ( player - > m_Local . m_bDucking | | player - > m_Local . m_bDucked ) )
{
float flDuckMilliseconds = MAX ( 0.0f , GAMEMOVEMENT_DUCK_TIME - ( float ) player - > m_Local . m_flDucktime ) ;
float flDuckSeconds = flDuckMilliseconds * 0.001f ;
// Finish ducking immediately if duck time is over or not on ground
if ( flDuckSeconds > TIME_TO_UNDUCK | | ( bInAir & & ! bDuckJump ) )
{
FinishUnDuck ( ) ;
}
else
{
// Calc parametric time
float flDuckFraction = SimpleSpline ( 1.0f - ( flDuckSeconds / TIME_TO_UNDUCK ) ) ;
SetDuckedEyeOffset ( flDuckFraction ) ;
player - > m_Local . m_bDucking = true ;
}
}
}
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.
if ( player - > m_Local . m_flDucktime ! = GAMEMOVEMENT_DUCK_TIME )
{
SetDuckedEyeOffset ( 1.0f ) ;
player - > m_Local . m_flDucktime = GAMEMOVEMENT_DUCK_TIME ;
player - > m_Local . m_bDucked = true ;
player - > m_Local . m_bDucking = false ;
player - > AddFlag ( FL_DUCKING ) ;
}
}
}
}
}
// HACK: (jimd 5/25/2006) we have a reoccuring bug (#50063 in Tracker) where the player's
// view height gets left at the ducked height while the player is standing, but we haven't
// been able to repro it to find the cause. It may be fixed now due to a change I'm
// also making in UpdateDuckJumpEyeOffset but just in case, this code will sense the
// problem and restore the eye to the proper position. It doesn't smooth the transition,
// but it is preferable to leaving the player's view too low.
//
// If the player is still alive and not an observer, check to make sure that
// his view height is at the standing height.
else if ( ! IsDead ( ) & & ! player - > IsObserver ( ) & & ! player - > IsInAVehicle ( ) )
{
if ( ( player - > m_Local . m_flDuckJumpTime = = 0.0f ) & & ( fabs ( player - > GetViewOffset ( ) . z - GetPlayerViewOffset ( false ) . z ) > 0.1 ) )
{
// we should rarely ever get here, so assert so a coder knows when it happens
Assert ( 0 ) ;
DevMsg ( 1 , " Restoring player view height \n " ) ;
// set the eye height to the non-ducked height
SetDuckedEyeOffset ( 0.0f ) ;
}
}
}
static ConVar sv_optimizedmovement ( " sv_optimizedmovement " , " 1 " , FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY ) ;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : PlayerMove ( void )
{
VPROF ( " CGameMovement::PlayerMove " ) ;
CheckParameters ( ) ;
// clear output applied velocity
mv - > m_outWishVel . Init ( ) ;
mv - > m_outJumpVel . Init ( ) ;
MoveHelper ( ) - > ResetTouchList ( ) ; // Assume we don't touch anything
ReduceTimers ( ) ;
AngleVectors ( mv - > m_vecViewAngles , & m_vecForward , & m_vecRight , & m_vecUp ) ; // Determine movement angles
// Always try and unstick us unless we are using a couple of the movement modes
if ( player - > GetMoveType ( ) ! = MOVETYPE_NOCLIP & &
player - > GetMoveType ( ) ! = MOVETYPE_NONE & &
player - > GetMoveType ( ) ! = MOVETYPE_ISOMETRIC & &
player - > GetMoveType ( ) ! = MOVETYPE_OBSERVER & &
! player - > pl . deadflag )
{
if ( CheckInterval ( STUCK ) )
{
if ( CheckStuck ( ) )
{
// Can't move, we're stuck
return ;
}
}
}
// Now that we are "unstuck", see where we are (player->GetWaterLevel() and type, player->GetGroundEntity()).
if ( player - > GetMoveType ( ) ! = MOVETYPE_WALK | |
mv - > m_bGameCodeMovedPlayer | |
! sv_optimizedmovement . GetBool ( ) )
{
CategorizePosition ( ) ;
}
else
{
if ( mv - > m_vecVelocity . z > 250.0f )
{
SetGroundEntity ( NULL ) ;
}
}
// Store off the starting water level
m_nOldWaterLevel = player - > GetWaterLevel ( ) ;
// If we are not on ground, store off how fast we are moving down
if ( player - > GetGroundEntity ( ) = = NULL )
{
player - > m_Local . m_flFallVelocity = - mv - > m_vecVelocity [ 2 ] ;
}
m_nOnLadder = 0 ;
player - > UpdateStepSound ( player - > m_pSurfaceData , mv - > GetAbsOrigin ( ) , mv - > m_vecVelocity ) ;
UpdateDuckJumpEyeOffset ( ) ;
Duck ( ) ;
// Don't run ladder code if dead on on a train
if ( ! player - > pl . deadflag & & ! ( player - > GetFlags ( ) & FL_ONTRAIN ) )
{
// If was not on a ladder now, but was on one before,
// get off of the ladder
// TODO: this causes lots of weirdness.
//bool bCheckLadder = CheckInterval( LADDER );
//if ( bCheckLadder || player->GetMoveType() == MOVETYPE_LADDER )
{
if ( ! LadderMove ( ) & &
( player - > GetMoveType ( ) = = MOVETYPE_LADDER ) )
{
// Clear ladder stuff unless player is dead or riding a train
// It will be reset immediately again next frame if necessary
player - > SetMoveType ( MOVETYPE_WALK ) ;
player - > SetMoveCollide ( MOVECOLLIDE_DEFAULT ) ;
}
}
}
#if 0
Msg ( " %i, %i, %s, player = %8x, move type = %2i, ground entity = %8x, velocity = (%f %f %f) \n " ,
player - > CurrentCommandNumber ( ) ,
player - > m_nTickBase ,
player - > IsServer ( ) ? " SERVER " : " CLIENT " ,
player ,
player - > GetMoveType ( ) ,
player - > GetGroundEntity ( ) ,
mv - > m_vecVelocity [ 0 ] , mv - > m_vecVelocity [ 1 ] , mv - > m_vecVelocity [ 2 ] ) ;
# endif
// Handle movement modes.
switch ( player - > GetMoveType ( ) )
{
case MOVETYPE_NONE :
break ;
case MOVETYPE_NOCLIP :
FullNoClipMove ( sv_noclipspeed . GetFloat ( ) , sv_noclipaccelerate . GetFloat ( ) ) ;
break ;
case MOVETYPE_FLY :
case MOVETYPE_FLYGRAVITY :
FullTossMove ( ) ;
break ;
case MOVETYPE_LADDER :
FullLadderMove ( ) ;
break ;
case MOVETYPE_WALK :
FullWalkMove ( ) ;
break ;
case MOVETYPE_ISOMETRIC :
//IsometricMove();
// Could also try: FullTossMove();
FullWalkMove ( ) ;
break ;
case MOVETYPE_OBSERVER :
FullObserverMove ( ) ; // clips against world&players
break ;
default :
DevMsg ( 1 , " Bogus pmove player movetype %i on (%i) 0=cl 1=sv \n " , player - > GetMoveType ( ) , player - > IsServer ( ) ) ;
break ;
}
}
//-----------------------------------------------------------------------------
// Performs the collision resolution for fliers.
//-----------------------------------------------------------------------------
void CGameMovement : : PerformFlyCollisionResolution ( trace_t & pm , Vector & move )
{
Vector base ;
float vel ;
float backoff ;
switch ( player - > GetMoveCollide ( ) )
{
case MOVECOLLIDE_FLY_CUSTOM :
// Do nothing; the velocity should have been modified by touch
// FIXME: It seems wrong for touch to modify velocity
// given that it can be called in a number of places
// where collision resolution do *not* in fact occur
// Should this ever occur for players!?
Assert ( 0 ) ;
break ;
case MOVECOLLIDE_FLY_BOUNCE :
case MOVECOLLIDE_DEFAULT :
{
if ( player - > GetMoveCollide ( ) = = MOVECOLLIDE_FLY_BOUNCE )
backoff = 2.0 - player - > m_surfaceFriction ;
else
backoff = 1 ;
ClipVelocity ( mv - > m_vecVelocity , pm . plane . normal , mv - > m_vecVelocity , backoff ) ;
}
break ;
default :
// Invalid collide type!
Assert ( 0 ) ;
break ;
}
// stop if on ground
if ( pm . plane . normal [ 2 ] > 0.7 )
{
base . Init ( ) ;
if ( mv - > m_vecVelocity [ 2 ] < GetCurrentGravity ( ) * gpGlobals - > frametime )
{
// we're rolling on the ground, add static friction.
SetGroundEntity ( & pm ) ;
mv - > m_vecVelocity [ 2 ] = 0 ;
}
vel = DotProduct ( mv - > m_vecVelocity , mv - > m_vecVelocity ) ;
// Con_DPrintf("%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] );
if ( vel < ( 30 * 30 ) | | ( player - > GetMoveCollide ( ) ! = MOVECOLLIDE_FLY_BOUNCE ) )
{
SetGroundEntity ( & pm ) ;
mv - > m_vecVelocity . Init ( ) ;
}
else
{
VectorScale ( mv - > m_vecVelocity , ( 1.0 - pm . fraction ) * gpGlobals - > frametime * 0.9 , move ) ;
PushEntity ( move , & pm ) ;
}
VectorSubtract ( mv - > m_vecVelocity , base , mv - > m_vecVelocity ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameMovement : : FullTossMove ( void )
{
trace_t pm ;
Vector move ;
CheckWater ( ) ;
// add velocity if player is moving
if ( ( mv - > m_flForwardMove ! = 0.0f ) | | ( mv - > m_flSideMove ! = 0.0f ) | | ( mv - > m_flUpMove ! = 0.0f ) )
{
Vector forward , right , up ;
float fmove , smove ;
Vector wishdir , wishvel ;
float wishspeed ;
int i ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
// Copy movement amounts
fmove = mv - > m_flForwardMove ;
smove = mv - > m_flSideMove ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors.
VectorNormalize ( right ) ; //
for ( i = 0 ; i < 3 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] + = mv - > m_flUpMove ;
VectorCopy ( wishvel , wishdir ) ; // Determine maginitude of speed of move
wishspeed = VectorNormalize ( wishdir ) ;
//
// Clamp to server defined max speed
//
if ( wishspeed > mv - > m_flMaxSpeed )
{
VectorScale ( wishvel , mv - > m_flMaxSpeed / wishspeed , wishvel ) ;
wishspeed = mv - > m_flMaxSpeed ;
}
// Set pmove velocity
Accelerate ( wishdir , wishspeed , sv_accelerate . GetFloat ( ) ) ;
}
if ( mv - > m_vecVelocity [ 2 ] > 0 )
{
SetGroundEntity ( NULL ) ;
}
// If on ground and not moving, return.
if ( player - > GetGroundEntity ( ) ! = NULL )
{
if ( VectorCompare ( player - > GetBaseVelocity ( ) , vec3_origin ) & &
VectorCompare ( mv - > m_vecVelocity , vec3_origin ) )
return ;
}
CheckVelocity ( ) ;
// add gravity
if ( player - > GetMoveType ( ) = = MOVETYPE_FLYGRAVITY )
{
AddGravity ( ) ;
}
// move origin
// Base velocity is not properly accounted for since this entity will move again after the bounce without
// taking it into account
VectorAdd ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
CheckVelocity ( ) ;
VectorScale ( mv - > m_vecVelocity , gpGlobals - > frametime , move ) ;
VectorSubtract ( mv - > m_vecVelocity , player - > GetBaseVelocity ( ) , mv - > m_vecVelocity ) ;
PushEntity ( move , & pm ) ; // Should this clear basevelocity
CheckVelocity ( ) ;
if ( pm . allsolid )
{
// entity is trapped in another solid
SetGroundEntity ( & pm ) ;
mv - > m_vecVelocity . Init ( ) ;
return ;
}
if ( pm . fraction ! = 1 )
{
PerformFlyCollisionResolution ( pm , move ) ;
}
// check for in water
CheckWater ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: TF2 commander mode movement logic
//-----------------------------------------------------------------------------
# pragma warning (disable : 4701)
void CGameMovement : : IsometricMove ( void )
{
int i ;
Vector wishvel ;
float fmove , smove ;
Vector forward , right , up ;
AngleVectors ( mv - > m_vecViewAngles , & forward , & right , & up ) ; // Determine movement angles
// Copy movement amounts
fmove = mv - > m_flForwardMove ;
smove = mv - > m_flSideMove ;
// No up / down movement
forward [ 2 ] = 0 ;
right [ 2 ] = 0 ;
VectorNormalize ( forward ) ; // Normalize remainder of vectors
VectorNormalize ( right ) ; //
for ( i = 0 ; i < 3 ; i + + ) // Determine x and y parts of velocity
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
//wishvel[2] += mv->m_flUpMove;
Vector out ;
VectorMA ( mv - > GetAbsOrigin ( ) , gpGlobals - > frametime , wishvel , out ) ;
mv - > SetAbsOrigin ( out ) ;
// Zero out the velocity so that we don't accumulate a huge downward velocity from
// gravity, etc.
mv - > m_vecVelocity . Init ( ) ;
}
# pragma warning (default : 4701)
bool CGameMovement : : GameHasLadders ( ) const
{
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Traces player movement + position
//-----------------------------------------------------------------------------
void CGameMovement : : TracePlayerBBox ( const Vector & start , const Vector & end , unsigned int fMask , int collisionGroup , trace_t & pm )
{
VPROF ( " CGameMovement::TracePlayerBBox " ) ;
Ray_t ray ;
ray . Init ( start , end , GetPlayerMins ( ) , GetPlayerMaxs ( ) ) ;
UTIL_TraceRay ( ray , fMask , mv - > m_nPlayerHandle . Get ( ) , collisionGroup , & pm ) ;
}
//-----------------------------------------------------------------------------
// Purpose: overridded by game classes to limit results (to standable objects for example)
//-----------------------------------------------------------------------------
void CGameMovement : : TryTouchGround ( const Vector & start , const Vector & end , const Vector & mins , const Vector & maxs , unsigned int fMask , int collisionGroup , trace_t & pm )
{
VPROF ( " CGameMovement::TryTouchGround " ) ;
Ray_t ray ;
ray . Init ( start , end , mins , maxs ) ;
UTIL_TraceRay ( ray , fMask , mv - > m_nPlayerHandle . Get ( ) , collisionGroup , & pm ) ;
}