mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2024-12-23 01:59:43 +08:00
2012 lines
57 KiB
C++
2012 lines
57 KiB
C++
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =====//
|
|
//
|
|
// Purpose: Client-side CBasePlayer.
|
|
//
|
|
// - Manages the player's flashlight effect.
|
|
//
|
|
//===========================================================================//
|
|
#include "cbase.h"
|
|
#include "c_baseplayer.h"
|
|
#include "flashlighteffect.h"
|
|
#include "weapon_selection.h"
|
|
#include "history_resource.h"
|
|
#include "iinput.h"
|
|
#include "input.h"
|
|
#include "view.h"
|
|
#include "iviewrender.h"
|
|
#include "iclientmode.h"
|
|
#include "in_buttons.h"
|
|
#include "engine/IEngineSound.h"
|
|
#include "c_soundscape.h"
|
|
#include "usercmd.h"
|
|
#include "c_playerresource.h"
|
|
#include "iclientvehicle.h"
|
|
#include "view_shared.h"
|
|
#include "C_VguiScreen.h"
|
|
#include "movevars_shared.h"
|
|
#include "prediction.h"
|
|
#include "tier0/vprof.h"
|
|
#include "filesystem.h"
|
|
#include "bitbuf.h"
|
|
#include "KeyValues.h"
|
|
#include "particles_simple.h"
|
|
#include "fx_water.h"
|
|
#include "hltvcamera.h"
|
|
#include "toolframework/itoolframework.h"
|
|
#include "toolframework_client.h"
|
|
#include "view_scene.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
// Don't alias here
|
|
#if defined( CBasePlayer )
|
|
#undef CBasePlayer
|
|
#endif
|
|
|
|
int g_nKillCamMode = OBS_MODE_NONE;
|
|
int g_nKillCamTarget1 = 0;
|
|
int g_nKillCamTarget2 = 0;
|
|
int g_nUsedPrediction = 1;
|
|
|
|
extern ConVar mp_forcecamera; // in gamevars_shared.h
|
|
|
|
#define FLASHLIGHT_DISTANCE 1000
|
|
#define MAX_VGUI_INPUT_MODE_SPEED 30
|
|
#define MAX_VGUI_INPUT_MODE_SPEED_SQ (MAX_VGUI_INPUT_MODE_SPEED*MAX_VGUI_INPUT_MODE_SPEED)
|
|
|
|
static Vector WALL_MIN(-WALL_OFFSET,-WALL_OFFSET,-WALL_OFFSET);
|
|
static Vector WALL_MAX(WALL_OFFSET,WALL_OFFSET,WALL_OFFSET);
|
|
|
|
extern ConVar default_fov;
|
|
#ifndef _XBOX
|
|
extern ConVar sensitivity;
|
|
#endif
|
|
|
|
static C_BasePlayer *s_pLocalPlayer = NULL;
|
|
|
|
static ConVar cl_customsounds ( "cl_customsounds", "0", 0, "Enable customized player sound playback" );
|
|
static ConVar spec_track ( "spec_track", "0", 0, "Tracks an entity in spec mode" );
|
|
static ConVar cl_smooth ( "cl_smooth", "1", 0, "Smooth view/eye origin after prediction errors" );
|
|
static ConVar cl_smoothtime (
|
|
"cl_smoothtime",
|
|
"0.1",
|
|
0,
|
|
"Smooth client's view after prediction error over this many seconds",
|
|
true, 0.01, // min/max is 0.01/2.0
|
|
true, 2.0
|
|
);
|
|
|
|
ConVar zoom_sensitivity_ratio( "zoom_sensitivity_ratio", "1.0", 0, "Additional mouse sensitivity scale factor applied when FOV is zoomed in." );
|
|
void RecvProxy_FOV( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
void RecvProxy_DefaultFOV( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
|
|
void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
|
|
void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut );
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// RecvTable for CPlayerState.
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
BEGIN_RECV_TABLE_NOBASE(CPlayerState, DT_PlayerState)
|
|
RecvPropInt (RECVINFO(deadflag)),
|
|
END_RECV_TABLE()
|
|
|
|
|
|
BEGIN_RECV_TABLE_NOBASE( CPlayerLocalData, DT_Local )
|
|
RecvPropArray3( RECVINFO_ARRAY(m_chAreaBits), RecvPropInt(RECVINFO(m_chAreaBits[0]))),
|
|
RecvPropArray3( RECVINFO_ARRAY(m_chAreaPortalBits), RecvPropInt(RECVINFO(m_chAreaPortalBits[0]))),
|
|
RecvPropInt(RECVINFO(m_iHideHUD)),
|
|
|
|
// View
|
|
|
|
RecvPropFloat(RECVINFO(m_flFOVRate)),
|
|
|
|
RecvPropInt (RECVINFO(m_bDucked)),
|
|
RecvPropInt (RECVINFO(m_bDucking)),
|
|
RecvPropInt (RECVINFO(m_bInDuckJump)),
|
|
RecvPropFloat (RECVINFO(m_flDucktime)),
|
|
RecvPropFloat (RECVINFO(m_flDuckJumpTime)),
|
|
RecvPropFloat (RECVINFO(m_flJumpTime)),
|
|
RecvPropFloat (RECVINFO(m_flFallVelocity)),
|
|
// RecvPropInt (RECVINFO(m_nOldButtons)),
|
|
RecvPropVector (RECVINFO(m_vecPunchAngle)),
|
|
RecvPropVector (RECVINFO(m_vecPunchAngleVel)),
|
|
RecvPropInt (RECVINFO(m_bDrawViewmodel)),
|
|
RecvPropInt (RECVINFO(m_bWearingSuit)),
|
|
RecvPropBool (RECVINFO(m_bPoisoned)),
|
|
RecvPropFloat (RECVINFO(m_flStepSize)),
|
|
RecvPropInt (RECVINFO(m_bAllowAutoMovement)),
|
|
|
|
// 3d skybox data
|
|
RecvPropInt(RECVINFO(m_skybox3d.scale)),
|
|
RecvPropVector(RECVINFO(m_skybox3d.origin)),
|
|
RecvPropInt(RECVINFO(m_skybox3d.area)),
|
|
|
|
// 3d skybox fog data
|
|
RecvPropInt( RECVINFO( m_skybox3d.fog.enable ) ),
|
|
RecvPropInt( RECVINFO( m_skybox3d.fog.blend ) ),
|
|
RecvPropVector( RECVINFO( m_skybox3d.fog.dirPrimary ) ),
|
|
RecvPropInt( RECVINFO( m_skybox3d.fog.colorPrimary ) ),
|
|
RecvPropInt( RECVINFO( m_skybox3d.fog.colorSecondary ) ),
|
|
RecvPropFloat( RECVINFO( m_skybox3d.fog.start ) ),
|
|
RecvPropFloat( RECVINFO( m_skybox3d.fog.end ) ),
|
|
|
|
// fog data
|
|
RecvPropInt( RECVINFO( m_fog.enable ) ),
|
|
RecvPropInt( RECVINFO( m_fog.blend ) ),
|
|
RecvPropVector( RECVINFO( m_fog.dirPrimary ) ),
|
|
RecvPropInt( RECVINFO( m_fog.colorPrimary ) ),
|
|
RecvPropInt( RECVINFO( m_fog.colorSecondary ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.start ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.end ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.farz ) ),
|
|
|
|
RecvPropInt( RECVINFO( m_fog.colorPrimaryLerpTo ) ),
|
|
RecvPropInt( RECVINFO( m_fog.colorSecondaryLerpTo ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.startLerpTo ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.endLerpTo ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.lerptime ) ),
|
|
RecvPropFloat( RECVINFO( m_fog.duration ) ),
|
|
|
|
// audio data
|
|
RecvPropVector( RECVINFO( m_audio.localSound[0] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[1] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[2] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[3] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[4] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[5] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[6] ) ),
|
|
RecvPropVector( RECVINFO( m_audio.localSound[7] ) ),
|
|
RecvPropInt( RECVINFO( m_audio.soundscapeIndex ) ),
|
|
RecvPropInt( RECVINFO( m_audio.localBits ) ),
|
|
RecvPropEHandle( RECVINFO( m_audio.ent ) ),
|
|
END_RECV_TABLE()
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// This data only gets sent to clients that ARE this player entity.
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
BEGIN_RECV_TABLE_NOBASE( C_BasePlayer, DT_LocalPlayerExclusive )
|
|
|
|
RecvPropDataTable ( RECVINFO_DT(m_Local),0, &REFERENCE_RECV_TABLE(DT_Local) ),
|
|
|
|
RecvPropFloat ( RECVINFO(m_vecViewOffset[0]) ),
|
|
RecvPropFloat ( RECVINFO(m_vecViewOffset[1]) ),
|
|
RecvPropFloat ( RECVINFO(m_vecViewOffset[2]) ),
|
|
RecvPropFloat ( RECVINFO(m_flFriction) ),
|
|
|
|
RecvPropArray3 ( RECVINFO_ARRAY(m_iAmmo), RecvPropInt( RECVINFO(m_iAmmo[0])) ),
|
|
|
|
RecvPropInt ( RECVINFO(m_fOnTarget) ),
|
|
|
|
RecvPropInt ( RECVINFO( m_nTickBase ) ),
|
|
RecvPropInt ( RECVINFO( m_nNextThinkTick ) ),
|
|
|
|
RecvPropEHandle ( RECVINFO( m_hLastWeapon ) ),
|
|
RecvPropEHandle ( RECVINFO( m_hGroundEntity ) ),
|
|
|
|
RecvPropFloat ( RECVINFO(m_vecVelocity[0]), 0, RecvProxy_LocalVelocityX ),
|
|
RecvPropFloat ( RECVINFO(m_vecVelocity[1]), 0, RecvProxy_LocalVelocityY ),
|
|
RecvPropFloat ( RECVINFO(m_vecVelocity[2]), 0, RecvProxy_LocalVelocityZ ),
|
|
|
|
RecvPropVector ( RECVINFO( m_vecBaseVelocity ) ),
|
|
|
|
RecvPropEHandle ( RECVINFO( m_hConstraintEntity)),
|
|
RecvPropVector ( RECVINFO( m_vecConstraintCenter) ),
|
|
RecvPropFloat ( RECVINFO( m_flConstraintRadius )),
|
|
RecvPropFloat ( RECVINFO( m_flConstraintWidth )),
|
|
RecvPropFloat ( RECVINFO( m_flConstraintSpeedFactor )),
|
|
|
|
RecvPropFloat ( RECVINFO( m_flDeathTime )),
|
|
|
|
RecvPropInt ( RECVINFO( m_nWaterLevel ) ),
|
|
RecvPropFloat ( RECVINFO( m_flLaggedMovementValue )),
|
|
|
|
END_RECV_TABLE()
|
|
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// DT_BasePlayer datatable.
|
|
// -------------------------------------------------------------------------------- //
|
|
IMPLEMENT_CLIENTCLASS_DT(C_BasePlayer, DT_BasePlayer, CBasePlayer)
|
|
// We have both the local and nonlocal data in here, but the server proxies
|
|
// only send one.
|
|
RecvPropDataTable( "localdata", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalPlayerExclusive) ),
|
|
|
|
RecvPropDataTable(RECVINFO_DT(pl), 0, &REFERENCE_RECV_TABLE(DT_PlayerState), DataTableRecvProxy_StaticDataTable),
|
|
|
|
RecvPropInt (RECVINFO(m_iFOV), 0, RecvProxy_FOV),
|
|
RecvPropInt (RECVINFO(m_iDefaultFOV), 0, RecvProxy_DefaultFOV),
|
|
|
|
RecvPropEHandle( RECVINFO(m_hVehicle) ),
|
|
RecvPropEHandle( RECVINFO(m_hUseEntity) ),
|
|
|
|
RecvPropInt (RECVINFO(m_iHealth)),
|
|
RecvPropInt (RECVINFO(m_lifeState)),
|
|
|
|
RecvPropFloat (RECVINFO(m_flMaxspeed)),
|
|
RecvPropInt (RECVINFO(m_fFlags)),
|
|
|
|
|
|
RecvPropInt (RECVINFO(m_iObserverMode) ),
|
|
RecvPropEHandle (RECVINFO(m_hObserverTarget), RecvProxy_ObserverTarget ),
|
|
RecvPropArray ( RecvPropEHandle( RECVINFO( m_hViewModel[0] ) ), m_hViewModel ),
|
|
|
|
|
|
RecvPropString( RECVINFO(m_szLastPlaceName) ),
|
|
|
|
END_RECV_TABLE()
|
|
|
|
BEGIN_PREDICTION_DATA_NO_BASE( CPlayerState )
|
|
|
|
DEFINE_PRED_FIELD( deadflag, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
// DEFINE_FIELD( netname, string_t ),
|
|
// DEFINE_FIELD( fixangle, FIELD_INTEGER ),
|
|
// DEFINE_FIELD( anglechange, FIELD_FLOAT ),
|
|
// DEFINE_FIELD( v_angle, FIELD_VECTOR ),
|
|
|
|
END_PREDICTION_DATA()
|
|
|
|
BEGIN_PREDICTION_DATA_NO_BASE( CPlayerLocalData )
|
|
|
|
// DEFINE_PRED_TYPEDESCRIPTION( m_skybox3d, sky3dparams_t ),
|
|
// DEFINE_PRED_TYPEDESCRIPTION( m_fog, fogparams_t ),
|
|
// DEFINE_PRED_TYPEDESCRIPTION( m_audio, audioparams_t ),
|
|
DEFINE_FIELD( m_nStepside, FIELD_INTEGER ),
|
|
|
|
DEFINE_PRED_FIELD( m_iHideHUD, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD_TOL( m_vecPunchAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
|
|
DEFINE_PRED_FIELD_TOL( m_vecPunchAngleVel, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.125f ),
|
|
DEFINE_PRED_FIELD( m_bDrawViewmodel, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_bWearingSuit, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_bPoisoned, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_bAllowAutoMovement, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_FIELD( m_bDucked, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_bDucking, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_bInDuckJump, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_flDucktime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_flDuckJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_flJumpTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD_TOL( m_flFallVelocity, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
|
|
// DEFINE_PRED_FIELD( m_nOldButtons, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_FIELD( m_nOldButtons, FIELD_INTEGER ),
|
|
DEFINE_PRED_FIELD( m_flStepSize, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
|
|
|
|
END_PREDICTION_DATA()
|
|
|
|
BEGIN_PREDICTION_DATA( C_BasePlayer )
|
|
|
|
DEFINE_PRED_TYPEDESCRIPTION( m_Local, CPlayerLocalData ),
|
|
DEFINE_PRED_TYPEDESCRIPTION( pl, CPlayerState ),
|
|
|
|
DEFINE_PRED_FIELD( m_iFOV, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_FIELD( m_hVehicle, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD_TOL( m_flMaxspeed, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.5f ),
|
|
DEFINE_PRED_FIELD( m_iHealth, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_fOnTarget, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_lifeState, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_nWaterLevel, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_FIELD_TOL( m_vecBaseVelocity, FIELD_VECTOR, FTYPEDESC_INSENDTABLE, 0.05 ),
|
|
|
|
DEFINE_FIELD( m_nButtons, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_flWaterJumpTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_nImpulse, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_flStepSoundTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_flSwimSoundTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_vecLadderNormal, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_flPhysics, FIELD_INTEGER ),
|
|
DEFINE_AUTO_ARRAY( m_szAnimExtension, FIELD_CHARACTER ),
|
|
DEFINE_FIELD( m_afButtonLast, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_afButtonPressed, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_afButtonReleased, FIELD_INTEGER ),
|
|
// DEFINE_FIELD( m_vecOldViewAngles, FIELD_VECTOR ),
|
|
|
|
// DEFINE_ARRAY( m_iOldAmmo, FIELD_INTEGER, MAX_AMMO_TYPES ),
|
|
|
|
//DEFINE_FIELD( m_hOldVehicle, FIELD_EHANDLE ),
|
|
// DEFINE_FIELD( m_pModelLight, dlight_t* ),
|
|
// DEFINE_FIELD( m_pEnvironmentLight, dlight_t* ),
|
|
// DEFINE_FIELD( m_pBrightLight, dlight_t* ),
|
|
DEFINE_PRED_FIELD( m_hLastWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_FIELD( m_nTickBase, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_FIELD( m_hGroundEntity, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
|
|
|
DEFINE_PRED_ARRAY( m_hViewModel, FIELD_EHANDLE, MAX_VIEWMODELS, FTYPEDESC_INSENDTABLE ),
|
|
|
|
END_PREDICTION_DATA()
|
|
|
|
LINK_ENTITY_TO_CLASS( player, C_BasePlayer );
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// Functions.
|
|
// -------------------------------------------------------------------------------- //
|
|
C_BasePlayer::C_BasePlayer() : m_iv_vecViewOffset( "C_BasePlayer::m_iv_vecViewOffset" )
|
|
{
|
|
AddVar( &m_vecViewOffset, &m_iv_vecViewOffset, LATCH_SIMULATION_VAR );
|
|
|
|
#ifdef _DEBUG
|
|
m_vecLadderNormal.Init();
|
|
m_vecOldViewAngles.Init();
|
|
#endif
|
|
|
|
m_pFlashlight = NULL;
|
|
|
|
m_pCurrentVguiScreen = NULL;
|
|
m_pCurrentCommand = NULL;
|
|
|
|
m_flPredictionErrorTime = -100;
|
|
m_StuckLast = 0;
|
|
m_bWasFrozen = false;
|
|
|
|
m_bResampleWaterSurface = true;
|
|
|
|
ResetObserverMode();
|
|
|
|
m_vecPredictionError.Init();
|
|
m_flPredictionErrorTime = 0;
|
|
|
|
m_surfaceProps = 0;
|
|
m_pSurfaceData = NULL;
|
|
m_surfaceFriction = 1.0f;
|
|
m_chTextureType = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
C_BasePlayer::~C_BasePlayer()
|
|
{
|
|
DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
|
|
if ( this == s_pLocalPlayer )
|
|
{
|
|
s_pLocalPlayer = NULL;
|
|
}
|
|
|
|
if (m_pFlashlight)
|
|
{
|
|
delete m_pFlashlight;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::Spawn( void )
|
|
{
|
|
// Clear all flags except for FL_FULLEDICT
|
|
ClearFlags();
|
|
AddFlag( FL_CLIENT );
|
|
|
|
int effects = GetEffects() & EF_NOSHADOW;
|
|
SetEffects( effects );
|
|
|
|
m_iFOV = 0; // init field of view.
|
|
|
|
SetModel( "models/player.mdl" );
|
|
|
|
Precache();
|
|
|
|
SetThink(NULL);
|
|
|
|
SharedSpawn();
|
|
}
|
|
|
|
bool C_BasePlayer::IsHLTV() const
|
|
{
|
|
return ( IsLocalPlayer() && engine->IsHLTV() );
|
|
}
|
|
|
|
CBaseEntity *C_BasePlayer::GetObserverTarget() const // returns players targer or NULL
|
|
{
|
|
#ifndef _XBOX
|
|
if ( IsHLTV() )
|
|
{
|
|
return HLTVCamera()->GetPrimaryTarget();
|
|
}
|
|
#endif
|
|
|
|
if ( GetObserverMode() == OBS_MODE_ROAMING )
|
|
{
|
|
return NULL; // no target in roaming mode
|
|
}
|
|
else
|
|
{
|
|
return m_hObserverTarget;
|
|
}
|
|
}
|
|
|
|
// Called from Recv Proxy, mainly to reset tone map scale
|
|
void C_BasePlayer::SetObserverTarget( EHANDLE hObserverTarget )
|
|
{
|
|
// If the observer target is changing to an entity that the client doesn't know about yet,
|
|
// it can resolve to NULL. If the client didn't have an observer target before, then
|
|
// comparing EHANDLEs directly will see them as equal, since it uses Get(), and compares
|
|
// NULL to NULL. To combat this, we need to check against GetEntryIndex() and
|
|
// GetSerialNumber().
|
|
if ( hObserverTarget.GetEntryIndex() != m_hObserverTarget.GetEntryIndex() ||
|
|
hObserverTarget.GetSerialNumber() != m_hObserverTarget.GetSerialNumber())
|
|
{
|
|
// Init based on the new handle's entry index and serial number, so that it's Get()
|
|
// has a chance to become non-NULL even if it currently resolves to NULL.
|
|
m_hObserverTarget.Init( hObserverTarget.GetEntryIndex(), hObserverTarget.GetSerialNumber() );
|
|
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
ResetToneMapping(1.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
int C_BasePlayer::GetObserverMode() const
|
|
{
|
|
#ifndef _XBOX
|
|
if ( IsHLTV() )
|
|
{
|
|
return HLTVCamera()->GetMode();
|
|
}
|
|
#endif
|
|
|
|
return m_iObserverMode;
|
|
}
|
|
|
|
bool C_BasePlayer::ViewModel_IsTransparent( void )
|
|
{
|
|
return IsTransparent();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Used by prediction, sets the view angles for the player
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::SetLocalViewAngles( const QAngle &viewAngles )
|
|
{
|
|
pl.v_angle = viewAngles;
|
|
}
|
|
|
|
surfacedata_t* C_BasePlayer::GetGroundSurface()
|
|
{
|
|
//
|
|
// Find the name of the material that lies beneath the player.
|
|
//
|
|
Vector start, end;
|
|
VectorCopy( GetAbsOrigin(), start );
|
|
VectorCopy( start, end );
|
|
|
|
// Straight down
|
|
end.z -= 64;
|
|
|
|
// Fill in default values, just in case.
|
|
|
|
Ray_t ray;
|
|
ray.Init( start, end, GetPlayerMins(), GetPlayerMaxs() );
|
|
|
|
trace_t trace;
|
|
UTIL_TraceRay( ray, MASK_PLAYERSOLID_BRUSHONLY, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace );
|
|
|
|
if ( trace.fraction == 1.0f )
|
|
return NULL; // no ground
|
|
|
|
return physprops->GetSurfaceData( trace.surface.surfaceProps );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// returns the player name
|
|
//-----------------------------------------------------------------------------
|
|
const char * C_BasePlayer::GetPlayerName()
|
|
{
|
|
return g_PR ? g_PR->GetPlayerName( entindex() ) : "";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Is the player dead?
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::IsPlayerDead()
|
|
{
|
|
return pl.deadflag == true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::SetVehicleRole( int nRole )
|
|
{
|
|
if ( !IsInAVehicle() )
|
|
return;
|
|
|
|
// HL2 has only a player in a vehicle.
|
|
if ( nRole > VEHICLE_ROLE_DRIVER )
|
|
return;
|
|
|
|
char szCmd[64];
|
|
Q_snprintf( szCmd, sizeof( szCmd ), "vehicleRole %i\n", nRole );
|
|
engine->ServerCmd( szCmd );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Store original ammo data to see what has changed
|
|
// Input : bnewentity -
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::OnPreDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
for (int i = 0; i < MAX_AMMO_TYPES; ++i)
|
|
{
|
|
m_iOldAmmo[i] = GetAmmoCount(i);
|
|
}
|
|
|
|
BaseClass::OnPreDataChanged( updateType );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : updateType -
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::PostDataUpdate( DataUpdateType_t updateType )
|
|
{
|
|
// This has to occur here as opposed to OnDataChanged so that EHandles to the player created
|
|
// on this same frame are not stomped because prediction thinks there
|
|
// isn't a local player yet!!!
|
|
|
|
if ( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
// Make sure s_pLocalPlayer is correct
|
|
|
|
int iLocalPlayerIndex = engine->GetLocalPlayer();
|
|
|
|
if ( g_nKillCamMode )
|
|
iLocalPlayerIndex = g_nKillCamTarget1;
|
|
|
|
if ( iLocalPlayerIndex == index )
|
|
{
|
|
Assert( s_pLocalPlayer == NULL );
|
|
s_pLocalPlayer = this;
|
|
}
|
|
}
|
|
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
SetSimulatedEveryTick( true );
|
|
}
|
|
else
|
|
{
|
|
SetSimulatedEveryTick( false );
|
|
|
|
// estimate velocity for non local players
|
|
float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime;
|
|
if ( flTimeDelta > 0 && !IsEffectActive(EF_NOINTERP) )
|
|
{
|
|
Vector newVelo = (GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta;
|
|
SetAbsVelocity( newVelo);
|
|
}
|
|
}
|
|
|
|
BaseClass::PostDataUpdate( updateType );
|
|
|
|
// Only care about this for local player
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
default_fov.SetValue( m_iDefaultFOV );
|
|
|
|
//Update our FOV, including any zooms going on
|
|
int iDefaultFOV = default_fov.GetInt();
|
|
int localFOV = GetFOV();
|
|
int min_fov = GetMinFOV();
|
|
|
|
// Don't let it go too low
|
|
localFOV = MAX( min_fov, localFOV );
|
|
|
|
gHUD.m_flFOVSensitivityAdjust = 1.0f;
|
|
#ifndef _XBOX
|
|
if ( gHUD.m_flMouseSensitivityFactor )
|
|
{
|
|
gHUD.m_flMouseSensitivity = sensitivity.GetFloat() * gHUD.m_flMouseSensitivityFactor;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// No override, don't use huge sensitivity
|
|
if ( localFOV == iDefaultFOV )
|
|
{
|
|
#ifndef _XBOX
|
|
// reset to saved sensitivity
|
|
gHUD.m_flMouseSensitivity = 0;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Set a new sensitivity that is proportional to the change from the FOV default and scaled
|
|
// by a separate compensating factor
|
|
gHUD.m_flFOVSensitivityAdjust =
|
|
((float)localFOV / (float)iDefaultFOV) * // linear fov downscale
|
|
zoom_sensitivity_ratio.GetFloat(); // sensitivity scale factor
|
|
#ifndef _XBOX
|
|
gHUD.m_flMouseSensitivity = gHUD.m_flFOVSensitivityAdjust * sensitivity.GetFloat(); // regular sensitivity
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
QAngle angles;
|
|
engine->GetViewAngles( angles );
|
|
SetLocalViewAngles( angles );
|
|
m_flOldPlayerZ = GetLocalOrigin().z;
|
|
}
|
|
}
|
|
|
|
// If we are updated while paused, allow the player origin to be snapped by the
|
|
// server if we receive a packet from the server
|
|
if ( engine->IsPaused() )
|
|
{
|
|
ResetLatched();
|
|
}
|
|
}
|
|
|
|
void C_BasePlayer::ReceiveMessage( int classID, bf_read &msg )
|
|
{
|
|
if ( classID != GetClientClass()->m_ClassID )
|
|
{
|
|
// message is for subclass
|
|
BaseClass::ReceiveMessage( classID, msg );
|
|
return;
|
|
}
|
|
|
|
int messageType = msg.ReadByte();
|
|
|
|
switch( messageType )
|
|
{
|
|
case PLAY_PLAYER_JINGLE:
|
|
PlayPlayerJingle();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void C_BasePlayer::OnRestore()
|
|
{
|
|
BaseClass::OnRestore();
|
|
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
// debounce the attack key, for if it was used for restore
|
|
input->ClearInputButton( IN_ATTACK | IN_ATTACK2 );
|
|
// GetButtonBits() has to be called for the above to take effect
|
|
input->GetButtonBits( 0 );
|
|
}
|
|
|
|
// For ammo history icons to current value so they don't flash on level transtions
|
|
for ( int i = 0; i < MAX_AMMO_TYPES; i++ )
|
|
{
|
|
m_iOldAmmo[i] = GetAmmoCount(i);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Process incoming data
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::OnDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
SetPredictionEligible( true );
|
|
}
|
|
#endif
|
|
|
|
BaseClass::OnDataChanged( updateType );
|
|
|
|
// Only care about this for local player
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
// Reset engine areabits pointer
|
|
render->SetAreaState( m_Local.m_chAreaBits, m_Local.m_chAreaPortalBits );
|
|
|
|
// Check for Ammo pickups.
|
|
for ( int i = 0; i < MAX_AMMO_TYPES; i++ )
|
|
{
|
|
if ( GetAmmoCount(i) > m_iOldAmmo[i] )
|
|
{
|
|
// Don't add to ammo pickup if the ammo doesn't do it
|
|
const FileWeaponInfo_t *pWeaponData = gWR.GetWeaponFromAmmo(i);
|
|
|
|
if ( !pWeaponData || !( pWeaponData->iFlags & ITEM_FLAG_NOAMMOPICKUPS ) )
|
|
{
|
|
// We got more ammo for this ammo index. Add it to the ammo history
|
|
CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
|
|
if( pHudHR )
|
|
{
|
|
pHudHR->AddToHistory( HISTSLOT_AMMO, i, abs(GetAmmoCount(i) - m_iOldAmmo[i]) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Soundscape_Update( m_Local.m_audio );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Did we just enter a vehicle this frame?
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::JustEnteredVehicle()
|
|
{
|
|
if ( !IsInAVehicle() )
|
|
return false;
|
|
|
|
return ( m_hOldVehicle == m_hVehicle );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Are we in VGUI input mode?.
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::IsInVGuiInputMode() const
|
|
{
|
|
return (m_pCurrentVguiScreen.Get() != NULL);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Check to see if we're in vgui input mode...
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::DetermineVguiInputMode( CUserCmd *pCmd )
|
|
{
|
|
// If we're dead, close down and abort!
|
|
if ( !IsAlive() )
|
|
{
|
|
DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
|
|
m_pCurrentVguiScreen.Set( NULL );
|
|
return;
|
|
}
|
|
|
|
// If we're in vgui mode *and* we're holding down mouse buttons,
|
|
// stay in vgui mode even if we're outside the screen bounds
|
|
if (m_pCurrentVguiScreen.Get() && (pCmd->buttons & (IN_ATTACK | IN_ATTACK2)) )
|
|
{
|
|
SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
|
|
|
|
// Kill all attack inputs if we're in vgui screen mode
|
|
pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
|
|
return;
|
|
}
|
|
|
|
// We're not in vgui input mode if we're moving, or have hit a key
|
|
// that will make us move...
|
|
|
|
// Not in vgui mode if we're moving too quickly
|
|
// ROBIN: Disabled movement preventing VGUI screen usage
|
|
//if (GetVelocity().LengthSqr() > MAX_VGUI_INPUT_MODE_SPEED_SQ)
|
|
if ( 0 )
|
|
{
|
|
DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
|
|
m_pCurrentVguiScreen.Set( NULL );
|
|
return;
|
|
}
|
|
|
|
// Don't enter vgui mode if we've got combat buttons held down
|
|
bool bAttacking = false;
|
|
if ( ((pCmd->buttons & IN_ATTACK) || (pCmd->buttons & IN_ATTACK2)) && !m_pCurrentVguiScreen.Get() )
|
|
{
|
|
bAttacking = true;
|
|
}
|
|
|
|
// Not in vgui mode if we're pushing any movement key at all
|
|
// Not in vgui mode if we're in a vehicle...
|
|
// ROBIN: Disabled movement preventing VGUI screen usage
|
|
//if ((pCmd->forwardmove > MAX_VGUI_INPUT_MODE_SPEED) ||
|
|
// (pCmd->sidemove > MAX_VGUI_INPUT_MODE_SPEED) ||
|
|
// (pCmd->upmove > MAX_VGUI_INPUT_MODE_SPEED) ||
|
|
// (pCmd->buttons & IN_JUMP) ||
|
|
// (bAttacking) )
|
|
if ( bAttacking || IsInAVehicle() )
|
|
{
|
|
DeactivateVguiScreen( m_pCurrentVguiScreen.Get() );
|
|
m_pCurrentVguiScreen.Set( NULL );
|
|
return;
|
|
}
|
|
|
|
// Not in vgui mode if there are no nearby screens
|
|
C_BaseEntity *pOldScreen = m_pCurrentVguiScreen.Get();
|
|
|
|
m_pCurrentVguiScreen = FindNearbyVguiScreen( EyePosition(), pCmd->viewangles, GetTeamNumber() );
|
|
|
|
if (pOldScreen != m_pCurrentVguiScreen)
|
|
{
|
|
DeactivateVguiScreen( pOldScreen );
|
|
ActivateVguiScreen( m_pCurrentVguiScreen.Get() );
|
|
}
|
|
|
|
if (m_pCurrentVguiScreen.Get())
|
|
{
|
|
SetVGuiScreenButtonState( m_pCurrentVguiScreen.Get(), pCmd->buttons );
|
|
|
|
// Kill all attack inputs if we're in vgui screen mode
|
|
pCmd->buttons &= ~(IN_ATTACK | IN_ATTACK2);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Input handling
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd )
|
|
{
|
|
// Allow the vehicle to clamp the view angles
|
|
if ( IsInAVehicle() )
|
|
{
|
|
IClientVehicle *pVehicle = m_hVehicle.Get()->GetClientVehicle();
|
|
if ( pVehicle )
|
|
{
|
|
pVehicle->UpdateViewAngles( this, pCmd );
|
|
engine->SetViewAngles( pCmd->viewangles );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef _XBOX
|
|
if ( joy_autosprint.GetBool() )
|
|
#endif
|
|
{
|
|
if ( input->KeyState( &in_joyspeed ) != 0.0f )
|
|
{
|
|
pCmd->buttons |= IN_SPEED;
|
|
}
|
|
}
|
|
|
|
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
|
|
if ( pWeapon )
|
|
{
|
|
pWeapon->CreateMove( flInputSampleTime, pCmd, m_vecOldViewAngles );
|
|
}
|
|
}
|
|
|
|
// If the frozen flag is set, prevent view movement (server prevents the rest of the movement)
|
|
if ( GetFlags() & FL_FROZEN )
|
|
{
|
|
// Don't stomp the first time we get frozen
|
|
if ( m_bWasFrozen )
|
|
{
|
|
// Stomp the new viewangles with old ones
|
|
pCmd->viewangles = m_vecOldViewAngles;
|
|
engine->SetViewAngles( pCmd->viewangles );
|
|
}
|
|
else
|
|
{
|
|
m_bWasFrozen = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bWasFrozen = false;
|
|
}
|
|
|
|
m_vecOldViewAngles = pCmd->viewangles;
|
|
|
|
// Check to see if we're in vgui input mode...
|
|
DetermineVguiInputMode( pCmd );
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Player has changed to a new team
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::TeamChange( int iNewTeam )
|
|
{
|
|
// Base class does nothing
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Creates, destroys, and updates the flashlight effect as needed.
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::UpdateFlashlight()
|
|
{
|
|
// The dim light is the flashlight.
|
|
if ( IsEffectActive( EF_DIMLIGHT ) )
|
|
{
|
|
if (!m_pFlashlight)
|
|
{
|
|
// Turned on the headlight; create it.
|
|
m_pFlashlight = new CFlashlightEffect(index);
|
|
|
|
if (!m_pFlashlight)
|
|
return;
|
|
|
|
m_pFlashlight->TurnOn();
|
|
}
|
|
|
|
Vector vecForward, vecRight, vecUp;
|
|
EyeVectors( &vecForward, &vecRight, &vecUp );
|
|
|
|
// Update the light with the new position and direction.
|
|
m_pFlashlight->UpdateLight( EyePosition(), vecForward, vecRight, vecUp, FLASHLIGHT_DISTANCE );
|
|
}
|
|
else if (m_pFlashlight)
|
|
{
|
|
// Turned off the flashlight; delete it.
|
|
delete m_pFlashlight;
|
|
m_pFlashlight = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Creates player flashlight if it's ative
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::Flashlight( void )
|
|
{
|
|
UpdateFlashlight();
|
|
|
|
// Check for muzzle flash and apply to view model
|
|
C_BaseAnimating *ve = this;
|
|
if ( GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
ve = dynamic_cast< C_BaseAnimating* >( GetObserverTarget() );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Engine is asking whether to add this player to the visible entities list
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::AddEntity( void )
|
|
{
|
|
// FIXME/UNDONE: Should the local player say yes to adding itself now
|
|
// and then, when it ges time to render and it shouldn't still do the render with
|
|
// STUDIO_EVENTS set so that its attachment points will get updated even if not
|
|
// in third person?
|
|
|
|
// Add in water effects
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
CreateWaterEffects();
|
|
}
|
|
|
|
// If set to invisible, skip. Do this before resetting the entity pointer so it has
|
|
// valid data to decide whether it's visible.
|
|
if ( !IsVisible() || !g_pClientMode->ShouldDrawLocalPlayer( this ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Server says don't interpolate this frame, so set previous info to new info.
|
|
if ( IsEffectActive(EF_NOINTERP) ||
|
|
Teleported() )
|
|
{
|
|
ResetLatched();
|
|
}
|
|
|
|
// Add in lighting effects
|
|
CreateLightEffects();
|
|
}
|
|
|
|
extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::CreateWaterEffects( void )
|
|
{
|
|
// Must be completely submerged to bother
|
|
if ( GetWaterLevel() < 3 )
|
|
{
|
|
m_bResampleWaterSurface = true;
|
|
return;
|
|
}
|
|
|
|
// Do special setup if this is our first time back underwater
|
|
if ( m_bResampleWaterSurface )
|
|
{
|
|
// Reset our particle timer
|
|
m_tWaterParticleTimer.Init( 32 );
|
|
|
|
// Find the surface of the water to clip against
|
|
m_flWaterSurfaceZ = UTIL_WaterLevel( WorldSpaceCenter(), WorldSpaceCenter().z, WorldSpaceCenter().z + 256 );
|
|
m_bResampleWaterSurface = false;
|
|
}
|
|
|
|
// Make sure the emitter is setup
|
|
if ( m_pWaterEmitter == NULL )
|
|
{
|
|
if ( ( m_pWaterEmitter = WaterDebrisEffect::Create( "splish" ) ) == NULL )
|
|
return;
|
|
}
|
|
|
|
Vector vecVelocity;
|
|
GetVectors( &vecVelocity, NULL, NULL );
|
|
|
|
Vector offset = WorldSpaceCenter();
|
|
|
|
m_pWaterEmitter->SetSortOrigin( offset );
|
|
|
|
PMaterialHandle hMaterial[2];
|
|
hMaterial[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1" );
|
|
hMaterial[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" );
|
|
|
|
SimpleParticle *pParticle;
|
|
|
|
float curTime = gpGlobals->frametime;
|
|
|
|
// Add as many particles as we need
|
|
while ( m_tWaterParticleTimer.NextEvent( curTime ) )
|
|
{
|
|
offset = WorldSpaceCenter() + ( vecVelocity * 128.0f ) + RandomVector( -128, 128 );
|
|
|
|
// Make sure we don't start out of the water!
|
|
if ( offset.z > m_flWaterSurfaceZ )
|
|
{
|
|
offset.z = ( m_flWaterSurfaceZ - 8.0f );
|
|
}
|
|
|
|
pParticle = (SimpleParticle *) m_pWaterEmitter->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset );
|
|
|
|
if (pParticle == NULL)
|
|
continue;
|
|
|
|
pParticle->m_flLifetime = 0.0f;
|
|
pParticle->m_flDieTime = random->RandomFloat( 2.0f, 4.0f );
|
|
|
|
pParticle->m_vecVelocity = RandomVector( -2.0f, 2.0f );
|
|
|
|
//FIXME: We should tint these based on the water's fog value!
|
|
float color = random->RandomInt( 32, 128 );
|
|
pParticle->m_uchColor[0] = color;
|
|
pParticle->m_uchColor[1] = color;
|
|
pParticle->m_uchColor[2] = color;
|
|
|
|
pParticle->m_uchStartSize = 1;
|
|
pParticle->m_uchEndSize = 1;
|
|
|
|
pParticle->m_uchStartAlpha = 255;
|
|
pParticle->m_uchEndAlpha = 0;
|
|
|
|
pParticle->m_flRoll = random->RandomInt( 0, 360 );
|
|
pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Called when not in tactical mode. Allows view to be overriden for things like driving a tank.
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::OverrideView( CViewSetup *pSetup )
|
|
{
|
|
}
|
|
|
|
bool C_BasePlayer::ShouldInterpolate()
|
|
{
|
|
// always interpolate myself
|
|
if ( IsLocalPlayer() )
|
|
return true;
|
|
#ifndef _XBOX
|
|
// always interpolate entity if followed by HLTV
|
|
if ( HLTVCamera()->GetCameraMan() == this )
|
|
return true;
|
|
#endif
|
|
return BaseClass::ShouldInterpolate();
|
|
}
|
|
|
|
|
|
bool C_BasePlayer::ShouldDraw()
|
|
{
|
|
return ( !IsLocalPlayer() || C_BasePlayer::ShouldDrawLocalPlayer() || (GetObserverMode() == OBS_MODE_DEATHCAM ) ) &&
|
|
BaseClass::ShouldDraw();
|
|
}
|
|
|
|
int C_BasePlayer::DrawModel( int flags )
|
|
{
|
|
// if local player is spectating this player in first person mode, don't draw it
|
|
C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( player && player->IsObserver() )
|
|
{
|
|
if ( player->GetObserverMode() == OBS_MODE_IN_EYE &&
|
|
player->GetObserverTarget() == this )
|
|
return 0;
|
|
}
|
|
|
|
return BaseClass::DrawModel( flags );
|
|
}
|
|
|
|
void C_BasePlayer::CalcChaseCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
|
|
{
|
|
C_BaseEntity *target = GetObserverTarget();
|
|
|
|
if ( !target )
|
|
{
|
|
// just copy a save in-map position
|
|
VectorCopy( EyePosition(), eyeOrigin );
|
|
VectorCopy( EyeAngles(), eyeAngles );
|
|
return;
|
|
};
|
|
|
|
// QAngle tmpangles;
|
|
|
|
Vector forward, viewpoint;
|
|
|
|
// GetRenderOrigin() returns ragdoll pos if player is ragdolled
|
|
Vector origin = target->GetRenderOrigin();
|
|
|
|
C_BasePlayer *player = ToBasePlayer( target );
|
|
|
|
if ( player && player->IsAlive() )
|
|
{
|
|
if( player->GetFlags() & FL_DUCKING )
|
|
{
|
|
VectorAdd( origin, VEC_DUCK_VIEW, origin );
|
|
}
|
|
else
|
|
{
|
|
VectorAdd( origin, VEC_VIEW, origin );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// assume it's the players ragdoll
|
|
VectorAdd( origin, VEC_DEAD_VIEWHEIGHT, origin );
|
|
}
|
|
|
|
QAngle viewangles;
|
|
|
|
if ( GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
viewangles = eyeAngles;
|
|
}
|
|
else if ( IsLocalPlayer() )
|
|
{
|
|
engine->GetViewAngles( viewangles );
|
|
}
|
|
else
|
|
{
|
|
viewangles = EyeAngles();
|
|
}
|
|
|
|
m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
|
|
m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE );
|
|
|
|
AngleVectors( viewangles, &forward );
|
|
|
|
VectorNormalize( forward );
|
|
|
|
VectorMA(origin, -m_flObserverChaseDistance, forward, viewpoint );
|
|
|
|
trace_t trace;
|
|
C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
|
|
UTIL_TraceHull( origin, viewpoint, WALL_MIN, WALL_MAX, MASK_SOLID, target, COLLISION_GROUP_NONE, &trace );
|
|
C_BaseEntity::PopEnableAbsRecomputations();
|
|
|
|
if (trace.fraction < 1.0)
|
|
{
|
|
viewpoint = trace.endpos;
|
|
m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
|
|
}
|
|
|
|
VectorCopy( viewangles, eyeAngles );
|
|
VectorCopy( viewpoint, eyeOrigin );
|
|
|
|
fov = GetFOV();
|
|
}
|
|
|
|
void C_BasePlayer::CalcRoamingView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
|
|
{
|
|
C_BaseEntity *target = GetObserverTarget();
|
|
|
|
if ( !target )
|
|
{
|
|
target = this;
|
|
}
|
|
|
|
m_flObserverChaseDistance = 0.0;
|
|
|
|
eyeOrigin = target->EyePosition();
|
|
eyeAngles = target->EyeAngles();
|
|
|
|
if ( spec_track.GetInt() > 0 )
|
|
{
|
|
C_BaseEntity *target = ClientEntityList().GetBaseEntity( spec_track.GetInt() );
|
|
|
|
if ( target )
|
|
{
|
|
Vector v = target->GetAbsOrigin(); v.z += 54;
|
|
QAngle a; VectorAngles( v - eyeOrigin, a );
|
|
|
|
NormalizeAngles( a );
|
|
eyeAngles = a;
|
|
engine->SetViewAngles( a );
|
|
}
|
|
}
|
|
|
|
// Apply a smoothing offset to smooth out prediction errors.
|
|
Vector vSmoothOffset;
|
|
GetPredictionErrorSmoothingVector( vSmoothOffset );
|
|
eyeOrigin += vSmoothOffset;
|
|
|
|
fov = GetFOV();
|
|
}
|
|
|
|
void C_BasePlayer::CalcInEyeCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
|
|
{
|
|
C_BaseEntity *target = GetObserverTarget();
|
|
|
|
if ( !target )
|
|
{
|
|
// just copy a save in-map position
|
|
VectorCopy( EyePosition(), eyeOrigin );
|
|
VectorCopy( EyeAngles(), eyeAngles );
|
|
return;
|
|
};
|
|
|
|
if ( !target->IsAlive() )
|
|
{
|
|
// if dead, show from 3rd person
|
|
CalcChaseCamView( eyeOrigin, eyeAngles, fov );
|
|
return;
|
|
}
|
|
|
|
fov = GetFOV(); // TODO use tragets FOV
|
|
|
|
m_flObserverChaseDistance = 0.0;
|
|
|
|
eyeAngles = target->EyeAngles();
|
|
eyeOrigin = target->GetAbsOrigin();
|
|
|
|
// Apply punch angle
|
|
VectorAdd( eyeAngles, GetPunchAngle(), eyeAngles );
|
|
|
|
if( engine->IsHLTV() )
|
|
{
|
|
if ( target->GetFlags() & FL_DUCKING )
|
|
{
|
|
eyeOrigin += VEC_DUCK_VIEW;
|
|
}
|
|
else
|
|
{
|
|
eyeOrigin += VEC_VIEW;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector offset = m_vecViewOffset;
|
|
#ifdef HL2MP
|
|
offset = target->GetViewOffset();
|
|
#endif
|
|
eyeOrigin += offset; // hack hack
|
|
}
|
|
|
|
engine->SetViewAngles( eyeAngles );
|
|
}
|
|
|
|
void C_BasePlayer::CalcDeathCamView(Vector& eyeOrigin, QAngle& eyeAngles, float& fov)
|
|
{
|
|
CBaseEntity * pKiller = NULL;
|
|
|
|
if ( mp_forcecamera.GetInt() == OBS_ALLOW_ALL )
|
|
{
|
|
// if mp_forcecamera is off let user see killer or look around
|
|
pKiller = GetObserverTarget();
|
|
eyeAngles = EyeAngles();
|
|
}
|
|
|
|
float interpolation = ( gpGlobals->curtime - m_flDeathTime ) / DEATH_ANIMATION_TIME;
|
|
interpolation = clamp( interpolation, 0.0f, 1.0f );
|
|
|
|
m_flObserverChaseDistance += gpGlobals->frametime*48.0f;
|
|
m_flObserverChaseDistance = clamp( m_flObserverChaseDistance, 16, CHASE_CAM_DISTANCE );
|
|
|
|
QAngle aForward = eyeAngles;
|
|
Vector origin = EyePosition();
|
|
|
|
IRagdoll *pRagdoll = GetRepresentativeRagdoll();
|
|
if ( pRagdoll )
|
|
{
|
|
origin = pRagdoll->GetRagdollOrigin();
|
|
origin.z += VEC_DEAD_VIEWHEIGHT.z; // look over ragdoll, not through
|
|
}
|
|
|
|
if ( pKiller && pKiller->IsPlayer() && (pKiller != this) )
|
|
{
|
|
Vector vKiller = pKiller->EyePosition() - origin;
|
|
QAngle aKiller; VectorAngles( vKiller, aKiller );
|
|
InterpolateAngles( aForward, aKiller, eyeAngles, interpolation );
|
|
};
|
|
|
|
Vector vForward; AngleVectors( eyeAngles, &vForward );
|
|
|
|
VectorNormalize( vForward );
|
|
|
|
VectorMA( origin, -m_flObserverChaseDistance, vForward, eyeOrigin );
|
|
|
|
trace_t trace; // clip against world
|
|
C_BaseEntity::PushEnableAbsRecomputations( false ); // HACK don't recompute positions while doing RayTrace
|
|
UTIL_TraceHull( origin, eyeOrigin, WALL_MIN, WALL_MAX, MASK_SOLID, this, COLLISION_GROUP_NONE, &trace );
|
|
C_BaseEntity::PopEnableAbsRecomputations();
|
|
|
|
if (trace.fraction < 1.0)
|
|
{
|
|
eyeOrigin = trace.endpos;
|
|
m_flObserverChaseDistance = VectorLength(origin - eyeOrigin);
|
|
}
|
|
|
|
fov = GetFOV();
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Return the weapon to have open the weapon selection on, based upon our currently active weapon
|
|
// Base class just uses the weapon that's currently active.
|
|
//-----------------------------------------------------------------------------
|
|
C_BaseCombatWeapon *C_BasePlayer::GetActiveWeaponForSelection( void )
|
|
{
|
|
return GetActiveWeapon();
|
|
}
|
|
|
|
C_BaseAnimating* C_BasePlayer::GetRenderedWeaponModel()
|
|
{
|
|
// Attach to either their weapon model or their view model.
|
|
if ( ShouldDrawLocalPlayer() || !IsLocalPlayer() )
|
|
{
|
|
return GetActiveWeapon();
|
|
}
|
|
else
|
|
{
|
|
return GetViewModel();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Gets a pointer to the local player, if it exists yet.
|
|
// Output : C_BasePlayer
|
|
//-----------------------------------------------------------------------------
|
|
C_BasePlayer *C_BasePlayer::GetLocalPlayer( void )
|
|
{
|
|
return s_pLocalPlayer;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: single place to decide whether the local player should draw
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::ShouldDrawLocalPlayer()
|
|
{
|
|
return input->CAM_IsThirdPerson() || ( ToolsEnabled() && ToolFramework_IsThirdPersonCamera() );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::IsLocalPlayer( void ) const
|
|
{
|
|
return ( GetLocalPlayer() == this );
|
|
}
|
|
|
|
int C_BasePlayer::GetUserID( void )
|
|
{
|
|
player_info_t pi;
|
|
|
|
if ( !engine->GetPlayerInfo( entindex(), &pi ) )
|
|
return -1;
|
|
|
|
return pi.userID;
|
|
}
|
|
|
|
|
|
// For weapon prediction
|
|
void C_BasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
|
|
{
|
|
// FIXME
|
|
}
|
|
|
|
void C_BasePlayer::UpdateClientData( void )
|
|
{
|
|
// Update all the items
|
|
for ( int i = 0; i < WeaponCount(); i++ )
|
|
{
|
|
if ( GetWeapon(i) ) // each item updates it's successors
|
|
GetWeapon(i)->UpdateClientData( this );
|
|
}
|
|
}
|
|
|
|
// Prediction stuff
|
|
void C_BasePlayer::PreThink( void )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
ItemPreFrame();
|
|
|
|
UpdateClientData();
|
|
|
|
if (m_lifeState >= LIFE_DYING)
|
|
return;
|
|
|
|
//
|
|
// If we're not on the ground, we're falling. Update our falling velocity.
|
|
//
|
|
if ( !( GetFlags() & FL_ONGROUND ) )
|
|
{
|
|
m_Local.m_flFallVelocity = -GetAbsVelocity().z;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void C_BasePlayer::PostThink( void )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
if ( IsAlive())
|
|
{
|
|
// do weapon stuff
|
|
ItemPostFrame();
|
|
|
|
if ( GetFlags() & FL_ONGROUND )
|
|
{
|
|
m_Local.m_flFallVelocity = 0;
|
|
}
|
|
|
|
// Don't allow bogus sequence on player
|
|
if ( GetSequence() == -1 )
|
|
{
|
|
SetSequence( 0 );
|
|
}
|
|
|
|
StudioFrameAdvance();
|
|
}
|
|
|
|
// Even if dead simulate entities
|
|
SimulatePlayerSimulatedEntities();
|
|
#endif
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: send various tool messages - viewoffset, and base class messages (flex and bones)
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::GetToolRecordingState( KeyValues *msg )
|
|
{
|
|
if ( !ToolsEnabled() )
|
|
return;
|
|
|
|
VPROF_BUDGET( "C_BasePlayer::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
|
|
|
|
BaseClass::GetToolRecordingState( msg );
|
|
|
|
msg->SetInt( "baseplayer", 1 );
|
|
msg->SetInt( "localplayer", IsLocalPlayer() ? 1 : 0 );
|
|
msg->SetString( "playername", GetPlayerName() );
|
|
|
|
static CameraRecordingState_t state;
|
|
state.m_flFOV = GetFOV();
|
|
|
|
float flZNear = view->GetZNear();
|
|
float flZFar = view->GetZFar();
|
|
CalcView( state.m_vecEyePosition, state.m_vecEyeAngles, flZNear, flZFar, state.m_flFOV );
|
|
msg->SetPtr( "camera", &state );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Simulate the player for this frame
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::Simulate()
|
|
{
|
|
//Frame updates
|
|
if ( this == C_BasePlayer::GetLocalPlayer() )
|
|
{
|
|
//Update the flashlight
|
|
Flashlight();
|
|
}
|
|
else
|
|
{
|
|
// update step sounds for all other players
|
|
Vector vel;
|
|
EstimateAbsVelocity( vel );
|
|
UpdateStepSound( GetGroundSurface(), GetAbsOrigin(), vel );
|
|
}
|
|
|
|
BaseClass::Simulate();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : CBaseViewModel
|
|
//-----------------------------------------------------------------------------
|
|
C_BaseViewModel *C_BasePlayer::GetViewModel( int index /*= 0*/ )
|
|
{
|
|
Assert( index >= 0 && index < MAX_VIEWMODELS );
|
|
|
|
C_BaseViewModel *vm = m_hViewModel[ index ];
|
|
|
|
if ( GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
C_BasePlayer *target = ToBasePlayer( GetObserverTarget() );
|
|
|
|
if ( target && target != this )
|
|
{
|
|
vm = target->GetViewModel( index );
|
|
}
|
|
}
|
|
|
|
return vm;
|
|
}
|
|
|
|
C_BaseCombatWeapon *C_BasePlayer::GetActiveWeapon( void ) const
|
|
{
|
|
const C_BasePlayer *fromPlayer = this;
|
|
|
|
// if localplayer is in InEye spectator mode, return weapon on chased player
|
|
if ( (fromPlayer == GetLocalPlayer()) && ( GetObserverMode() == OBS_MODE_IN_EYE) )
|
|
{
|
|
C_BaseEntity *target = GetObserverTarget();
|
|
|
|
if ( target && target->IsPlayer() )
|
|
{
|
|
fromPlayer = ToBasePlayer( target );
|
|
}
|
|
}
|
|
|
|
return fromPlayer->C_BaseCombatCharacter::GetActiveWeapon();
|
|
}
|
|
|
|
//=========================================================
|
|
// Autoaim
|
|
// set crosshair position to point to enemey
|
|
//=========================================================
|
|
Vector C_BasePlayer::GetAutoaimVector( float flScale )
|
|
{
|
|
// Never autoaim a predicted weapon (for now)
|
|
Vector forward;
|
|
AngleVectors( GetAbsAngles() + m_Local.m_vecPunchAngle, &forward );
|
|
return forward;
|
|
}
|
|
|
|
void C_BasePlayer::PlayPlayerJingle()
|
|
{
|
|
#ifndef _XBOX
|
|
// Find player sound for shooter
|
|
player_info_t info;
|
|
engine->GetPlayerInfo( entindex(), &info );
|
|
|
|
if ( !cl_customsounds.GetBool() )
|
|
return;
|
|
|
|
// Doesn't have a jingle sound
|
|
if ( !info.customFiles[1] )
|
|
return;
|
|
|
|
char soundhex[ 16 ];
|
|
Q_binarytohex( (byte *)&info.customFiles[1], sizeof( info.customFiles[1] ), soundhex, sizeof( soundhex ) );
|
|
|
|
// See if logo has been downloaded.
|
|
char fullsoundname[ 512 ];
|
|
Q_snprintf( fullsoundname, sizeof( fullsoundname ), "sound/temp/%s.wav", soundhex );
|
|
|
|
if ( !filesystem->FileExists( fullsoundname ) )
|
|
{
|
|
char custname[ 512 ];
|
|
Q_snprintf( custname, sizeof( custname ), "downloads/%s.dat", soundhex );
|
|
// it may have been downloaded but not copied under materials folder
|
|
if ( !filesystem->FileExists( custname ) )
|
|
return; // not downloaded yet
|
|
|
|
// copy from download folder to materials/temp folder
|
|
// this is done since material system can access only materials/*.vtf files
|
|
|
|
if ( !engine->CopyFile( custname, fullsoundname) )
|
|
return;
|
|
}
|
|
|
|
Q_snprintf( fullsoundname, sizeof( fullsoundname ), "temp/%s.wav", soundhex );
|
|
|
|
CLocalPlayerFilter filter;
|
|
|
|
EmitSound_t ep;
|
|
ep.m_nChannel = CHAN_VOICE;
|
|
ep.m_pSoundName = fullsoundname;
|
|
ep.m_flVolume = VOL_NORM;
|
|
ep.m_SoundLevel = SNDLVL_NORM;
|
|
|
|
C_BaseEntity::EmitSound( filter, GetSoundSourceIndex(), ep );
|
|
#endif
|
|
}
|
|
|
|
// Stuff for prediction
|
|
void C_BasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeat)
|
|
{
|
|
// FIXME: Do something here?
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::ResetAutoaim( void )
|
|
{
|
|
#if 0
|
|
if (m_vecAutoAim.x != 0 || m_vecAutoAim.y != 0)
|
|
{
|
|
m_vecAutoAim = QAngle( 0, 0, 0 );
|
|
engine->CrosshairAngle( edict(), 0, 0 );
|
|
}
|
|
#endif
|
|
m_fOnTarget = false;
|
|
}
|
|
|
|
bool C_BasePlayer::ShouldPredict( void )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
// Do this before calling into baseclass so prediction data block gets allocated
|
|
if ( IsLocalPlayer() )
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Special processing for player simulation
|
|
// NOTE: Don't chain to BaseClass!!!!
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::PhysicsSimulate( void )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
VPROF( "C_BasePlayer::PhysicsSimulate" );
|
|
// If we've got a moveparent, we must simulate that first.
|
|
CBaseEntity *pMoveParent = GetMoveParent();
|
|
if (pMoveParent)
|
|
{
|
|
pMoveParent->PhysicsSimulate();
|
|
}
|
|
|
|
// Make sure not to simulate this guy twice per frame
|
|
if (m_nSimulationTick == gpGlobals->tickcount)
|
|
return;
|
|
|
|
m_nSimulationTick = gpGlobals->tickcount;
|
|
|
|
if ( !IsLocalPlayer() )
|
|
return;
|
|
|
|
C_CommandContext *ctx = GetCommandContext();
|
|
Assert( ctx );
|
|
Assert( ctx->needsprocessing );
|
|
if ( !ctx->needsprocessing )
|
|
return;
|
|
|
|
ctx->needsprocessing = false;
|
|
|
|
// Handle FL_FROZEN.
|
|
if(GetFlags() & FL_FROZEN)
|
|
{
|
|
ctx->cmd.forwardmove = 0;
|
|
ctx->cmd.sidemove = 0;
|
|
ctx->cmd.upmove = 0;
|
|
ctx->cmd.buttons = 0;
|
|
ctx->cmd.impulse = 0;
|
|
//VectorCopy ( pl.v_angle, ctx->cmd.viewangles );
|
|
}
|
|
|
|
// Run the next command
|
|
prediction->RunCommand(
|
|
this,
|
|
&ctx->cmd,
|
|
MoveHelper() );
|
|
#endif
|
|
}
|
|
|
|
const QAngle& C_BasePlayer::GetPunchAngle()
|
|
{
|
|
return m_Local.m_vecPunchAngle.Get();
|
|
}
|
|
|
|
|
|
void C_BasePlayer::SetPunchAngle( const QAngle &angle )
|
|
{
|
|
m_Local.m_vecPunchAngle = angle;
|
|
}
|
|
|
|
|
|
float C_BasePlayer::GetWaterJumpTime() const
|
|
{
|
|
return m_flWaterJumpTime;
|
|
}
|
|
|
|
void C_BasePlayer::SetWaterJumpTime( float flWaterJumpTime )
|
|
{
|
|
m_flWaterJumpTime = flWaterJumpTime;
|
|
}
|
|
|
|
float C_BasePlayer::GetSwimSoundTime() const
|
|
{
|
|
return m_flSwimSoundTime;
|
|
}
|
|
|
|
void C_BasePlayer::SetSwimSoundTime( float flSwimSoundTime )
|
|
{
|
|
m_flSwimSoundTime = flSwimSoundTime;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Return true if this object can be +used by the player
|
|
//-----------------------------------------------------------------------------
|
|
bool C_BasePlayer::IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : float
|
|
//-----------------------------------------------------------------------------
|
|
float C_BasePlayer::GetFOV( void )
|
|
{
|
|
if ( GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
C_BasePlayer *pTargetPlayer = dynamic_cast<C_BasePlayer*>( GetObserverTarget() );
|
|
|
|
if ( pTargetPlayer )
|
|
{
|
|
return pTargetPlayer->GetFOV();
|
|
}
|
|
}
|
|
|
|
float fFOV = m_iFOV;
|
|
|
|
// Allow our vehicle to override our FOV if it's currently at the default FOV.
|
|
IClientVehicle *pVehicle = GetVehicle();
|
|
if ( pVehicle && ( fFOV == 0 ) )
|
|
{
|
|
pVehicle->GetVehicleFOV( fFOV );
|
|
}
|
|
|
|
if ( fFOV == 0 )
|
|
{
|
|
fFOV = default_fov.GetInt();
|
|
}
|
|
|
|
//See if we need to lerp the values for local player
|
|
if ( IsLocalPlayer() && ( fFOV != m_iFOVStart ) && (m_Local.m_flFOVRate > 0.0f ) )
|
|
{
|
|
float deltaTime = (float)( gpGlobals->curtime - m_flFOVTime ) / m_Local.m_flFOVRate;
|
|
|
|
if ( deltaTime >= 1.0f )
|
|
{
|
|
//If we're past the zoom time, just take the new value and stop lerping
|
|
m_iFOVStart = fFOV;
|
|
}
|
|
else
|
|
{
|
|
fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_iFOVStart, fFOV );
|
|
}
|
|
}
|
|
|
|
return fFOV;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called when the FOV changes from the server-side
|
|
// Input : *pData -
|
|
// *pStruct -
|
|
// *pOut -
|
|
//-----------------------------------------------------------------------------
|
|
void RecvProxy_FOV( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
//Hold onto the old FOV as our starting point
|
|
int iNewFov = pData->m_Value.m_Int;
|
|
|
|
if ( pPlayer->m_iFOV == iNewFov )
|
|
return;
|
|
|
|
// Get the true current FOV of the player at this point
|
|
pPlayer->m_iFOVStart = pPlayer->GetFOV();
|
|
|
|
//Get our start time for the zoom
|
|
pPlayer->m_flFOVTime = gpGlobals->curtime;
|
|
pPlayer->m_iFOV = iNewFov;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called when the default FOV changes from the server-side
|
|
// Input : *pData -
|
|
// *pStruct -
|
|
// *pOut -
|
|
//-----------------------------------------------------------------------------
|
|
void RecvProxy_DefaultFOV( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
//Hold onto the old FOV as our starting point
|
|
int iNewFov = pData->m_Value.m_Int;
|
|
|
|
if ( pPlayer->m_iDefaultFOV != iNewFov )
|
|
{
|
|
// Don't lerp
|
|
pPlayer->m_Local.m_flFOVRate = 0.0f;
|
|
|
|
pPlayer->m_iDefaultFOV = iNewFov;
|
|
}
|
|
}
|
|
|
|
void RecvProxy_LocalVelocityX( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
Assert( pPlayer );
|
|
|
|
float flNewVel_x = pData->m_Value.m_Float;
|
|
|
|
Vector vecVelocity = pPlayer->GetLocalVelocity();
|
|
|
|
if( vecVelocity.x != flNewVel_x ) // Should this use an epsilon check?
|
|
{
|
|
vecVelocity.x = flNewVel_x;
|
|
pPlayer->SetLocalVelocity( vecVelocity );
|
|
}
|
|
}
|
|
|
|
void RecvProxy_LocalVelocityY( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
Assert( pPlayer );
|
|
|
|
float flNewVel_y = pData->m_Value.m_Float;
|
|
|
|
Vector vecVelocity = pPlayer->GetLocalVelocity();
|
|
|
|
if( vecVelocity.y != flNewVel_y )
|
|
{
|
|
vecVelocity.y = flNewVel_y;
|
|
pPlayer->SetLocalVelocity( vecVelocity );
|
|
}
|
|
}
|
|
|
|
void RecvProxy_LocalVelocityZ( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
Assert( pPlayer );
|
|
|
|
float flNewVel_z = pData->m_Value.m_Float;
|
|
|
|
Vector vecVelocity = pPlayer->GetLocalVelocity();
|
|
|
|
if( vecVelocity.z != flNewVel_z )
|
|
{
|
|
vecVelocity.z = flNewVel_z;
|
|
pPlayer->SetLocalVelocity( vecVelocity );
|
|
}
|
|
}
|
|
|
|
void RecvProxy_ObserverTarget( const CRecvProxyData *pData, void *pStruct, void *pOut )
|
|
{
|
|
C_BasePlayer *pPlayer = (C_BasePlayer *) pStruct;
|
|
|
|
Assert( pPlayer );
|
|
|
|
EHANDLE hTarget;
|
|
|
|
RecvProxy_IntToEHandle( pData, pStruct, &hTarget );
|
|
|
|
pPlayer->SetObserverTarget( hTarget );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Remove this player from a vehicle
|
|
//-----------------------------------------------------------------------------
|
|
void C_BasePlayer::LeaveVehicle( void )
|
|
{
|
|
if ( NULL == m_hVehicle.Get() )
|
|
return;
|
|
|
|
// Let server do this for now
|
|
#if 0
|
|
IClientVehicle *pVehicle = GetVehicle();
|
|
Assert( pVehicle );
|
|
|
|
int nRole = pVehicle->GetPassengerRole( this );
|
|
Assert( nRole != VEHICLE_ROLE_NONE );
|
|
|
|
SetParent( NULL );
|
|
|
|
// Find the first non-blocked exit point:
|
|
Vector vNewPos = GetAbsOrigin();
|
|
QAngle qAngles = GetAbsAngles();
|
|
pVehicle->GetPassengerExitPoint( nRole, &vNewPos, &qAngles );
|
|
OnVehicleEnd( vNewPos );
|
|
SetAbsOrigin( vNewPos );
|
|
SetAbsAngles( qAngles );
|
|
|
|
m_Local.m_iHideHUD &= ~HIDEHUD_WEAPONSELECTION;
|
|
RemoveEffects( EF_NODRAW );
|
|
|
|
SetMoveType( MOVETYPE_WALK );
|
|
SetCollisionGroup( COLLISION_GROUP_PLAYER );
|
|
|
|
qAngles[ROLL] = 0;
|
|
SnapEyeAngles( qAngles );
|
|
|
|
m_hVehicle = NULL;
|
|
pVehicle->SetPassenger(nRole, NULL);
|
|
|
|
Weapon_Switch( m_hLastWeapon );
|
|
#endif
|
|
}
|
|
|
|
|
|
float C_BasePlayer::GetMinFOV() const
|
|
{
|
|
if ( gpGlobals->maxClients == 1 )
|
|
{
|
|
// Let them do whatever they want, more or less, in single player
|
|
return 5;
|
|
}
|
|
else
|
|
{
|
|
return 75;
|
|
}
|
|
}
|
|
|
|
float C_BasePlayer::GetFinalPredictedTime() const
|
|
{
|
|
return ( m_nFinalPredictedTick * TICK_INTERVAL );
|
|
}
|
|
|
|
void C_BasePlayer::NotePredictionError( const Vector &vDelta )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
Vector vOldDelta;
|
|
|
|
GetPredictionErrorSmoothingVector( vOldDelta );
|
|
|
|
// sum all errors within smoothing time
|
|
m_vecPredictionError = vDelta + vOldDelta;
|
|
|
|
// remember when last error happened
|
|
m_flPredictionErrorTime = gpGlobals->curtime;
|
|
|
|
ResetLatched();
|
|
#endif
|
|
}
|
|
|
|
void C_BasePlayer::GetPredictionErrorSmoothingVector( Vector &vOffset )
|
|
{
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
if ( engine->IsPlayingDemo() || !cl_smooth.GetInt() || !cl_predict.GetBool() )
|
|
{
|
|
vOffset.Init();
|
|
return;
|
|
}
|
|
|
|
float errorAmount = ( gpGlobals->curtime - m_flPredictionErrorTime ) / cl_smoothtime.GetFloat();
|
|
|
|
if ( errorAmount >= 1.0f )
|
|
{
|
|
vOffset.Init();
|
|
return;
|
|
}
|
|
|
|
errorAmount = 1.0f - errorAmount;
|
|
|
|
vOffset = m_vecPredictionError * errorAmount;
|
|
#else
|
|
vOffset.Init();
|
|
#endif
|
|
}
|
|
|
|
|
|
IRagdoll* C_BasePlayer::GetRepresentativeRagdoll() const
|
|
{
|
|
return m_pRagdoll;
|
|
}
|
|
|