2013-06-26 15:22:04 -07:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL2.
//
//=============================================================================//
# include "cbase.h"
# include "weapon_hl2mpbasehlmpcombatweapon.h"
# include "hl2mp_player.h"
# include "globalstate.h"
# include "game.h"
# include "gamerules.h"
# include "hl2mp_player_shared.h"
# include "predicted_viewmodel.h"
# include "in_buttons.h"
# include "hl2mp_gamerules.h"
# include "KeyValues.h"
# include "team.h"
# include "weapon_hl2mpbase.h"
# include "grenade_satchel.h"
# include "eventqueue.h"
# include "gamestats.h"
# include "engine/IEngineSound.h"
# include "SoundEmitterSystem/isoundemittersystembase.h"
# include "ilagcompensationmanager.h"
int g_iLastCitizenModel = 0 ;
int g_iLastCombineModel = 0 ;
CBaseEntity * g_pLastCombineSpawn = NULL ;
CBaseEntity * g_pLastRebelSpawn = NULL ;
extern CBaseEntity * g_pLastSpawn ;
# define HL2MP_COMMAND_MAX_RATE 0.3
void DropPrimedFragGrenade ( CHL2MP_Player * pPlayer , CBaseCombatWeapon * pGrenade ) ;
LINK_ENTITY_TO_CLASS ( player , CHL2MP_Player ) ;
LINK_ENTITY_TO_CLASS ( info_player_combine , CPointEntity ) ;
LINK_ENTITY_TO_CLASS ( info_player_rebel , CPointEntity ) ;
IMPLEMENT_SERVERCLASS_ST ( CHL2MP_Player , DT_HL2MP_Player )
SendPropAngle ( SENDINFO_VECTORELEM ( m_angEyeAngles , 0 ) , 11 , SPROP_CHANGES_OFTEN ) ,
SendPropAngle ( SENDINFO_VECTORELEM ( m_angEyeAngles , 1 ) , 11 , SPROP_CHANGES_OFTEN ) ,
SendPropEHandle ( SENDINFO ( m_hRagdoll ) ) ,
SendPropInt ( SENDINFO ( m_iSpawnInterpCounter ) , 4 ) ,
SendPropInt ( SENDINFO ( m_iPlayerSoundType ) , 3 ) ,
SendPropExclude ( " DT_BaseAnimating " , " m_flPoseParameter " ) ,
SendPropExclude ( " DT_BaseFlex " , " m_viewtarget " ) ,
// SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
// SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
END_SEND_TABLE ( )
BEGIN_DATADESC ( CHL2MP_Player )
END_DATADESC ( )
const char * g_ppszRandomCitizenModels [ ] =
{
" models/humans/group03/male_01.mdl " ,
" models/humans/group03/male_02.mdl " ,
" models/humans/group03/female_01.mdl " ,
" models/humans/group03/male_03.mdl " ,
" models/humans/group03/female_02.mdl " ,
" models/humans/group03/male_04.mdl " ,
" models/humans/group03/female_03.mdl " ,
" models/humans/group03/male_05.mdl " ,
" models/humans/group03/female_04.mdl " ,
" models/humans/group03/male_06.mdl " ,
" models/humans/group03/female_06.mdl " ,
" models/humans/group03/male_07.mdl " ,
" models/humans/group03/female_07.mdl " ,
" models/humans/group03/male_08.mdl " ,
" models/humans/group03/male_09.mdl " ,
} ;
const char * g_ppszRandomCombineModels [ ] =
{
" models/combine_soldier.mdl " ,
" models/combine_soldier_prisonguard.mdl " ,
" models/combine_super_soldier.mdl " ,
" models/police.mdl " ,
} ;
# define MAX_COMBINE_MODELS 4
# define MODEL_CHANGE_INTERVAL 5.0f
# define TEAM_CHANGE_INTERVAL 5.0f
# define HL2MPPLAYER_PHYSDAMAGE_SCALE 4.0f
2013-10-06 13:46:15 -04:00
# ifdef _WIN32
2013-06-26 15:22:04 -07:00
# pragma warning( disable : 4355 )
2013-10-06 13:46:15 -04:00
# endif
2013-06-26 15:22:04 -07:00
CHL2MP_Player : : CHL2MP_Player ( ) : m_PlayerAnimState ( this )
{
m_angEyeAngles . Init ( ) ;
m_iLastWeaponFireUsercmd = 0 ;
m_flNextModelChangeTime = 0.0f ;
m_flNextTeamChangeTime = 0.0f ;
m_iSpawnInterpCounter = 0 ;
m_bEnterObserver = false ;
m_bReady = false ;
BaseClass : : ChangeTeam ( 0 ) ;
// UseClientSideAnimation();
}
CHL2MP_Player : : ~ CHL2MP_Player ( void )
{
}
void CHL2MP_Player : : UpdateOnRemove ( void )
{
if ( m_hRagdoll )
{
UTIL_RemoveImmediate ( m_hRagdoll ) ;
m_hRagdoll = NULL ;
}
BaseClass : : UpdateOnRemove ( ) ;
}
void CHL2MP_Player : : Precache ( void )
{
BaseClass : : Precache ( ) ;
PrecacheModel ( " sprites/glow01.vmt " ) ;
//Precache Citizen models
int nHeads = ARRAYSIZE ( g_ppszRandomCitizenModels ) ;
int i ;
for ( i = 0 ; i < nHeads ; + + i )
PrecacheModel ( g_ppszRandomCitizenModels [ i ] ) ;
//Precache Combine Models
nHeads = ARRAYSIZE ( g_ppszRandomCombineModels ) ;
for ( i = 0 ; i < nHeads ; + + i )
PrecacheModel ( g_ppszRandomCombineModels [ i ] ) ;
PrecacheFootStepSounds ( ) ;
PrecacheScriptSound ( " NPC_MetroPolice.Die " ) ;
PrecacheScriptSound ( " NPC_CombineS.Die " ) ;
PrecacheScriptSound ( " NPC_Citizen.die " ) ;
}
void CHL2MP_Player : : GiveAllItems ( void )
{
EquipSuit ( ) ;
CBasePlayer : : GiveAmmo ( 255 , " Pistol " ) ;
CBasePlayer : : GiveAmmo ( 255 , " AR2 " ) ;
CBasePlayer : : GiveAmmo ( 5 , " AR2AltFire " ) ;
CBasePlayer : : GiveAmmo ( 255 , " SMG1 " ) ;
CBasePlayer : : GiveAmmo ( 1 , " smg1_grenade " ) ;
CBasePlayer : : GiveAmmo ( 255 , " Buckshot " ) ;
CBasePlayer : : GiveAmmo ( 32 , " 357 " ) ;
CBasePlayer : : GiveAmmo ( 3 , " rpg_round " ) ;
CBasePlayer : : GiveAmmo ( 1 , " grenade " ) ;
CBasePlayer : : GiveAmmo ( 2 , " slam " ) ;
GiveNamedItem ( " weapon_crowbar " ) ;
GiveNamedItem ( " weapon_stunstick " ) ;
GiveNamedItem ( " weapon_pistol " ) ;
GiveNamedItem ( " weapon_357 " ) ;
GiveNamedItem ( " weapon_smg1 " ) ;
GiveNamedItem ( " weapon_ar2 " ) ;
GiveNamedItem ( " weapon_shotgun " ) ;
GiveNamedItem ( " weapon_frag " ) ;
GiveNamedItem ( " weapon_crossbow " ) ;
GiveNamedItem ( " weapon_rpg " ) ;
GiveNamedItem ( " weapon_slam " ) ;
GiveNamedItem ( " weapon_physcannon " ) ;
}
void CHL2MP_Player : : GiveDefaultItems ( void )
{
EquipSuit ( ) ;
CBasePlayer : : GiveAmmo ( 255 , " Pistol " ) ;
CBasePlayer : : GiveAmmo ( 45 , " SMG1 " ) ;
CBasePlayer : : GiveAmmo ( 1 , " grenade " ) ;
CBasePlayer : : GiveAmmo ( 6 , " Buckshot " ) ;
CBasePlayer : : GiveAmmo ( 6 , " 357 " ) ;
if ( GetPlayerModelType ( ) = = PLAYER_SOUNDS_METROPOLICE | | GetPlayerModelType ( ) = = PLAYER_SOUNDS_COMBINESOLDIER )
{
GiveNamedItem ( " weapon_stunstick " ) ;
}
else if ( GetPlayerModelType ( ) = = PLAYER_SOUNDS_CITIZEN )
{
GiveNamedItem ( " weapon_crowbar " ) ;
}
GiveNamedItem ( " weapon_pistol " ) ;
GiveNamedItem ( " weapon_smg1 " ) ;
GiveNamedItem ( " weapon_frag " ) ;
GiveNamedItem ( " weapon_physcannon " ) ;
const char * szDefaultWeaponName = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_defaultweapon " ) ;
CBaseCombatWeapon * pDefaultWeapon = Weapon_OwnsThisType ( szDefaultWeaponName ) ;
if ( pDefaultWeapon )
{
Weapon_Switch ( pDefaultWeapon ) ;
}
else
{
Weapon_Switch ( Weapon_OwnsThisType ( " weapon_physcannon " ) ) ;
}
}
void CHL2MP_Player : : PickDefaultSpawnTeam ( void )
{
if ( GetTeamNumber ( ) = = 0 )
{
if ( HL2MPRules ( ) - > IsTeamplay ( ) = = false )
{
if ( GetModelPtr ( ) = = NULL )
{
const char * szModelName = NULL ;
szModelName = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_playermodel " ) ;
if ( ValidatePlayerModel ( szModelName ) = = false )
{
char szReturnString [ 512 ] ;
Q_snprintf ( szReturnString , sizeof ( szReturnString ) , " cl_playermodel models/combine_soldier.mdl \n " ) ;
engine - > ClientCommand ( edict ( ) , szReturnString ) ;
}
ChangeTeam ( TEAM_UNASSIGNED ) ;
}
}
else
{
CTeam * pCombine = g_Teams [ TEAM_COMBINE ] ;
CTeam * pRebels = g_Teams [ TEAM_REBELS ] ;
if ( pCombine = = NULL | | pRebels = = NULL )
{
ChangeTeam ( random - > RandomInt ( TEAM_COMBINE , TEAM_REBELS ) ) ;
}
else
{
if ( pCombine - > GetNumPlayers ( ) > pRebels - > GetNumPlayers ( ) )
{
ChangeTeam ( TEAM_REBELS ) ;
}
else if ( pCombine - > GetNumPlayers ( ) < pRebels - > GetNumPlayers ( ) )
{
ChangeTeam ( TEAM_COMBINE ) ;
}
else
{
ChangeTeam ( random - > RandomInt ( TEAM_COMBINE , TEAM_REBELS ) ) ;
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets HL2 specific defaults.
//-----------------------------------------------------------------------------
void CHL2MP_Player : : Spawn ( void )
{
m_flNextModelChangeTime = 0.0f ;
m_flNextTeamChangeTime = 0.0f ;
PickDefaultSpawnTeam ( ) ;
BaseClass : : Spawn ( ) ;
if ( ! IsObserver ( ) )
{
pl . deadflag = false ;
RemoveSolidFlags ( FSOLID_NOT_SOLID ) ;
RemoveEffects ( EF_NODRAW ) ;
GiveDefaultItems ( ) ;
}
SetNumAnimOverlays ( 3 ) ;
ResetAnimation ( ) ;
m_nRenderFX = kRenderNormal ;
m_Local . m_iHideHUD = 0 ;
AddFlag ( FL_ONGROUND ) ; // set the player on the ground at the start of the round.
m_impactEnergyScale = HL2MPPLAYER_PHYSDAMAGE_SCALE ;
if ( HL2MPRules ( ) - > IsIntermission ( ) )
{
AddFlag ( FL_FROZEN ) ;
}
else
{
RemoveFlag ( FL_FROZEN ) ;
}
m_iSpawnInterpCounter = ( m_iSpawnInterpCounter + 1 ) % 8 ;
m_Local . m_bDucked = false ;
SetPlayerUnderwater ( false ) ;
m_bReady = false ;
}
void CHL2MP_Player : : PickupObject ( CBaseEntity * pObject , bool bLimitMassAndSize )
{
}
bool CHL2MP_Player : : ValidatePlayerModel ( const char * pModel )
{
int iModels = ARRAYSIZE ( g_ppszRandomCitizenModels ) ;
int i ;
for ( i = 0 ; i < iModels ; + + i )
{
if ( ! Q_stricmp ( g_ppszRandomCitizenModels [ i ] , pModel ) )
{
return true ;
}
}
iModels = ARRAYSIZE ( g_ppszRandomCombineModels ) ;
for ( i = 0 ; i < iModels ; + + i )
{
if ( ! Q_stricmp ( g_ppszRandomCombineModels [ i ] , pModel ) )
{
return true ;
}
}
return false ;
}
void CHL2MP_Player : : SetPlayerTeamModel ( void )
{
const char * szModelName = NULL ;
szModelName = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_playermodel " ) ;
int modelIndex = modelinfo - > GetModelIndex ( szModelName ) ;
if ( modelIndex = = - 1 | | ValidatePlayerModel ( szModelName ) = = false )
{
szModelName = " models/Combine_Soldier.mdl " ;
m_iModelType = TEAM_COMBINE ;
char szReturnString [ 512 ] ;
Q_snprintf ( szReturnString , sizeof ( szReturnString ) , " cl_playermodel %s \n " , szModelName ) ;
engine - > ClientCommand ( edict ( ) , szReturnString ) ;
}
if ( GetTeamNumber ( ) = = TEAM_COMBINE )
{
if ( Q_stristr ( szModelName , " models/human " ) )
{
int nHeads = ARRAYSIZE ( g_ppszRandomCombineModels ) ;
g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads ;
szModelName = g_ppszRandomCombineModels [ g_iLastCombineModel ] ;
}
m_iModelType = TEAM_COMBINE ;
}
else if ( GetTeamNumber ( ) = = TEAM_REBELS )
{
if ( ! Q_stristr ( szModelName , " models/human " ) )
{
int nHeads = ARRAYSIZE ( g_ppszRandomCitizenModels ) ;
g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads ;
szModelName = g_ppszRandomCitizenModels [ g_iLastCitizenModel ] ;
}
m_iModelType = TEAM_REBELS ;
}
SetModel ( szModelName ) ;
SetupPlayerSoundsByModel ( szModelName ) ;
m_flNextModelChangeTime = gpGlobals - > curtime + MODEL_CHANGE_INTERVAL ;
}
void CHL2MP_Player : : SetPlayerModel ( void )
{
const char * szModelName = NULL ;
const char * pszCurrentModelName = modelinfo - > GetModelName ( GetModel ( ) ) ;
szModelName = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_playermodel " ) ;
if ( ValidatePlayerModel ( szModelName ) = = false )
{
char szReturnString [ 512 ] ;
if ( ValidatePlayerModel ( pszCurrentModelName ) = = false )
{
pszCurrentModelName = " models/Combine_Soldier.mdl " ;
}
Q_snprintf ( szReturnString , sizeof ( szReturnString ) , " cl_playermodel %s \n " , pszCurrentModelName ) ;
engine - > ClientCommand ( edict ( ) , szReturnString ) ;
szModelName = pszCurrentModelName ;
}
if ( GetTeamNumber ( ) = = TEAM_COMBINE )
{
int nHeads = ARRAYSIZE ( g_ppszRandomCombineModels ) ;
g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads ;
szModelName = g_ppszRandomCombineModels [ g_iLastCombineModel ] ;
m_iModelType = TEAM_COMBINE ;
}
else if ( GetTeamNumber ( ) = = TEAM_REBELS )
{
int nHeads = ARRAYSIZE ( g_ppszRandomCitizenModels ) ;
g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads ;
szModelName = g_ppszRandomCitizenModels [ g_iLastCitizenModel ] ;
m_iModelType = TEAM_REBELS ;
}
else
{
if ( Q_strlen ( szModelName ) = = 0 )
{
szModelName = g_ppszRandomCitizenModels [ 0 ] ;
}
if ( Q_stristr ( szModelName , " models/human " ) )
{
m_iModelType = TEAM_REBELS ;
}
else
{
m_iModelType = TEAM_COMBINE ;
}
}
int modelIndex = modelinfo - > GetModelIndex ( szModelName ) ;
if ( modelIndex = = - 1 )
{
szModelName = " models/Combine_Soldier.mdl " ;
m_iModelType = TEAM_COMBINE ;
char szReturnString [ 512 ] ;
Q_snprintf ( szReturnString , sizeof ( szReturnString ) , " cl_playermodel %s \n " , szModelName ) ;
engine - > ClientCommand ( edict ( ) , szReturnString ) ;
}
SetModel ( szModelName ) ;
SetupPlayerSoundsByModel ( szModelName ) ;
m_flNextModelChangeTime = gpGlobals - > curtime + MODEL_CHANGE_INTERVAL ;
}
void CHL2MP_Player : : SetupPlayerSoundsByModel ( const char * pModelName )
{
if ( Q_stristr ( pModelName , " models/human " ) )
{
m_iPlayerSoundType = ( int ) PLAYER_SOUNDS_CITIZEN ;
}
else if ( Q_stristr ( pModelName , " police " ) )
{
m_iPlayerSoundType = ( int ) PLAYER_SOUNDS_METROPOLICE ;
}
else if ( Q_stristr ( pModelName , " combine " ) )
{
m_iPlayerSoundType = ( int ) PLAYER_SOUNDS_COMBINESOLDIER ;
}
}
void CHL2MP_Player : : ResetAnimation ( void )
{
if ( IsAlive ( ) )
{
SetSequence ( - 1 ) ;
SetActivity ( ACT_INVALID ) ;
if ( ! GetAbsVelocity ( ) . x & & ! GetAbsVelocity ( ) . y )
SetAnimation ( PLAYER_IDLE ) ;
else if ( ( GetAbsVelocity ( ) . x | | GetAbsVelocity ( ) . y ) & & ( GetFlags ( ) & FL_ONGROUND ) )
SetAnimation ( PLAYER_WALK ) ;
else if ( GetWaterLevel ( ) > 1 )
SetAnimation ( PLAYER_WALK ) ;
}
}
bool CHL2MP_Player : : Weapon_Switch ( CBaseCombatWeapon * pWeapon , int viewmodelindex )
{
bool bRet = BaseClass : : Weapon_Switch ( pWeapon , viewmodelindex ) ;
if ( bRet = = true )
{
ResetAnimation ( ) ;
}
return bRet ;
}
void CHL2MP_Player : : PreThink ( void )
{
QAngle vOldAngles = GetLocalAngles ( ) ;
QAngle vTempAngles = GetLocalAngles ( ) ;
vTempAngles = EyeAngles ( ) ;
if ( vTempAngles [ PITCH ] > 180.0f )
{
vTempAngles [ PITCH ] - = 360.0f ;
}
SetLocalAngles ( vTempAngles ) ;
BaseClass : : PreThink ( ) ;
State_PreThink ( ) ;
//Reset bullet force accumulator, only lasts one frame
m_vecTotalBulletForce = vec3_origin ;
SetLocalAngles ( vOldAngles ) ;
}
void CHL2MP_Player : : PostThink ( void )
{
BaseClass : : PostThink ( ) ;
if ( GetFlags ( ) & FL_DUCKING )
{
SetCollisionBounds ( VEC_CROUCH_TRACE_MIN , VEC_CROUCH_TRACE_MAX ) ;
}
m_PlayerAnimState . Update ( ) ;
// Store the eye angles pitch so the client can compute its animation state correctly.
m_angEyeAngles = EyeAngles ( ) ;
QAngle angles = GetLocalAngles ( ) ;
angles [ PITCH ] = 0 ;
SetLocalAngles ( angles ) ;
}
void CHL2MP_Player : : PlayerDeathThink ( )
{
if ( ! IsObserver ( ) )
{
BaseClass : : PlayerDeathThink ( ) ;
}
}
void CHL2MP_Player : : FireBullets ( const FireBulletsInfo_t & info )
{
// Move other players back to history positions based on local player's lag
lagcompensation - > StartLagCompensation ( this , this - > GetCurrentCommand ( ) ) ;
FireBulletsInfo_t modinfo = info ;
CWeaponHL2MPBase * pWeapon = dynamic_cast < CWeaponHL2MPBase * > ( GetActiveWeapon ( ) ) ;
if ( pWeapon )
{
modinfo . m_iPlayerDamage = modinfo . m_flDamage = pWeapon - > GetHL2MPWpnData ( ) . m_iPlayerDamage ;
}
NoteWeaponFired ( ) ;
BaseClass : : FireBullets ( modinfo ) ;
// Move other players back to history positions based on local player's lag
lagcompensation - > FinishLagCompensation ( this ) ;
}
void CHL2MP_Player : : NoteWeaponFired ( void )
{
Assert ( m_pCurrentCommand ) ;
if ( m_pCurrentCommand )
{
m_iLastWeaponFireUsercmd = m_pCurrentCommand - > command_number ;
}
}
extern ConVar sv_maxunlag ;
bool CHL2MP_Player : : WantsLagCompensationOnEntity ( const CBasePlayer * pPlayer , const CUserCmd * pCmd , const CBitVec < MAX_EDICTS > * pEntityTransmitBits ) const
{
// No need to lag compensate at all if we're not attacking in this command and
// we haven't attacked recently.
if ( ! ( pCmd - > buttons & IN_ATTACK ) & & ( pCmd - > command_number - m_iLastWeaponFireUsercmd > 5 ) )
return false ;
// If this entity hasn't been transmitted to us and acked, then don't bother lag compensating it.
if ( pEntityTransmitBits & & ! pEntityTransmitBits - > Get ( pPlayer - > entindex ( ) ) )
return false ;
const Vector & vMyOrigin = GetAbsOrigin ( ) ;
const Vector & vHisOrigin = pPlayer - > GetAbsOrigin ( ) ;
// get max distance player could have moved within max lag compensation time,
// multiply by 1.5 to to avoid "dead zones" (sqrt(2) would be the exact value)
float maxDistance = 1.5 * pPlayer - > MaxSpeed ( ) * sv_maxunlag . GetFloat ( ) ;
// If the player is within this distance, lag compensate them in case they're running past us.
if ( vHisOrigin . DistTo ( vMyOrigin ) < maxDistance )
return true ;
// If their origin is not within a 45 degree cone in front of us, no need to lag compensate.
Vector vForward ;
AngleVectors ( pCmd - > viewangles , & vForward ) ;
Vector vDiff = vHisOrigin - vMyOrigin ;
VectorNormalize ( vDiff ) ;
float flCosAngle = 0.707107f ; // 45 degree angle
if ( vForward . Dot ( vDiff ) < flCosAngle )
return false ;
return true ;
}
Activity CHL2MP_Player : : TranslateTeamActivity ( Activity ActToTranslate )
{
if ( m_iModelType = = TEAM_COMBINE )
return ActToTranslate ;
if ( ActToTranslate = = ACT_RUN )
return ACT_RUN_AIM_AGITATED ;
if ( ActToTranslate = = ACT_IDLE )
return ACT_IDLE_AIM_AGITATED ;
if ( ActToTranslate = = ACT_WALK )
return ACT_WALK_AIM_AGITATED ;
return ActToTranslate ;
}
extern ConVar hl2_normspeed ;
// Set the activity based on an event or current state
void CHL2MP_Player : : SetAnimation ( PLAYER_ANIM playerAnim )
{
int animDesired ;
float speed ;
speed = GetAbsVelocity ( ) . Length2D ( ) ;
// bool bRunning = true;
//Revisit!
/* if ( ( m_nButtons & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) )
{
if ( speed > 1.0f & & speed < hl2_normspeed . GetFloat ( ) - 20.0f )
{
bRunning = false ;
}
} */
if ( GetFlags ( ) & ( FL_FROZEN | FL_ATCONTROLS ) )
{
speed = 0 ;
playerAnim = PLAYER_IDLE ;
}
Activity idealActivity = ACT_HL2MP_RUN ;
// This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
if ( playerAnim = = PLAYER_JUMP )
{
idealActivity = ACT_HL2MP_JUMP ;
}
else if ( playerAnim = = PLAYER_DIE )
{
if ( m_lifeState = = LIFE_ALIVE )
{
return ;
}
}
else if ( playerAnim = = PLAYER_ATTACK1 )
{
if ( GetActivity ( ) = = ACT_HOVER | |
GetActivity ( ) = = ACT_SWIM | |
GetActivity ( ) = = ACT_HOP | |
GetActivity ( ) = = ACT_LEAP | |
GetActivity ( ) = = ACT_DIESIMPLE )
{
idealActivity = GetActivity ( ) ;
}
else
{
idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK ;
}
}
else if ( playerAnim = = PLAYER_RELOAD )
{
idealActivity = ACT_HL2MP_GESTURE_RELOAD ;
}
else if ( playerAnim = = PLAYER_IDLE | | playerAnim = = PLAYER_WALK )
{
if ( ! ( GetFlags ( ) & FL_ONGROUND ) & & GetActivity ( ) = = ACT_HL2MP_JUMP ) // Still jumping
{
idealActivity = GetActivity ( ) ;
}
/*
else if ( GetWaterLevel ( ) > 1 )
{
if ( speed = = 0 )
idealActivity = ACT_HOVER ;
else
idealActivity = ACT_SWIM ;
}
*/
else
{
if ( GetFlags ( ) & FL_DUCKING )
{
if ( speed > 0 )
{
idealActivity = ACT_HL2MP_WALK_CROUCH ;
}
else
{
idealActivity = ACT_HL2MP_IDLE_CROUCH ;
}
}
else
{
if ( speed > 0 )
{
/*
if ( bRunning = = false )
{
idealActivity = ACT_WALK ;
}
else
*/
{
idealActivity = ACT_HL2MP_RUN ;
}
}
else
{
idealActivity = ACT_HL2MP_IDLE ;
}
}
}
idealActivity = TranslateTeamActivity ( idealActivity ) ;
}
if ( idealActivity = = ACT_HL2MP_GESTURE_RANGE_ATTACK )
{
RestartGesture ( Weapon_TranslateActivity ( idealActivity ) ) ;
// FIXME: this seems a bit wacked
Weapon_SetActivity ( Weapon_TranslateActivity ( ACT_RANGE_ATTACK1 ) , 0 ) ;
return ;
}
else if ( idealActivity = = ACT_HL2MP_GESTURE_RELOAD )
{
RestartGesture ( Weapon_TranslateActivity ( idealActivity ) ) ;
return ;
}
else
{
SetActivity ( idealActivity ) ;
animDesired = SelectWeightedSequence ( Weapon_TranslateActivity ( idealActivity ) ) ;
if ( animDesired = = - 1 )
{
animDesired = SelectWeightedSequence ( idealActivity ) ;
if ( animDesired = = - 1 )
{
animDesired = 0 ;
}
}
// Already using the desired animation?
if ( GetSequence ( ) = = animDesired )
return ;
m_flPlaybackRate = 1.0 ;
ResetSequence ( animDesired ) ;
SetCycle ( 0 ) ;
return ;
}
// Already using the desired animation?
if ( GetSequence ( ) = = animDesired )
return ;
//Msg( "Set animation to %d\n", animDesired );
// Reset to first frame of desired animation
ResetSequence ( animDesired ) ;
SetCycle ( 0 ) ;
}
extern int gEvilImpulse101 ;
//-----------------------------------------------------------------------------
// Purpose: Player reacts to bumping a weapon.
// Input : pWeapon - the weapon that the player bumped into.
// Output : Returns true if player picked up the weapon
//-----------------------------------------------------------------------------
bool CHL2MP_Player : : BumpWeapon ( CBaseCombatWeapon * pWeapon )
{
CBaseCombatCharacter * pOwner = pWeapon - > GetOwner ( ) ;
// Can I have this weapon type?
if ( ! IsAllowedToPickupWeapons ( ) )
return false ;
if ( pOwner | | ! Weapon_CanUse ( pWeapon ) | | ! g_pGameRules - > CanHavePlayerItem ( this , pWeapon ) )
{
if ( gEvilImpulse101 )
{
UTIL_Remove ( pWeapon ) ;
}
return false ;
}
// Don't let the player fetch weapons through walls (use MASK_SOLID so that you can't pickup through windows)
if ( ! pWeapon - > FVisible ( this , MASK_SOLID ) & & ! ( GetFlags ( ) & FL_NOTARGET ) )
{
return false ;
}
bool bOwnsWeaponAlready = ! ! Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) , pWeapon - > GetSubType ( ) ) ;
if ( bOwnsWeaponAlready = = true )
{
//If we have room for the ammo, then "take" the weapon too.
if ( Weapon_EquipAmmoOnly ( pWeapon ) )
{
pWeapon - > CheckRespawn ( ) ;
UTIL_Remove ( pWeapon ) ;
return true ;
}
else
{
return false ;
}
}
pWeapon - > CheckRespawn ( ) ;
Weapon_Equip ( pWeapon ) ;
return true ;
}
void CHL2MP_Player : : ChangeTeam ( int iTeam )
{
/* if ( GetNextTeamChangeTime() >= gpGlobals->curtime )
{
char szReturnString [ 128 ] ;
Q_snprintf ( szReturnString , sizeof ( szReturnString ) , " Please wait %d more seconds before trying to switch teams again. \n " , ( int ) ( GetNextTeamChangeTime ( ) - gpGlobals - > curtime ) ) ;
ClientPrint ( this , HUD_PRINTTALK , szReturnString ) ;
return ;
} */
bool bKill = false ;
if ( HL2MPRules ( ) - > IsTeamplay ( ) ! = true & & iTeam ! = TEAM_SPECTATOR )
{
//don't let them try to join combine or rebels during deathmatch.
iTeam = TEAM_UNASSIGNED ;
}
if ( HL2MPRules ( ) - > IsTeamplay ( ) = = true )
{
if ( iTeam ! = GetTeamNumber ( ) & & GetTeamNumber ( ) ! = TEAM_UNASSIGNED )
{
bKill = true ;
}
}
BaseClass : : ChangeTeam ( iTeam ) ;
m_flNextTeamChangeTime = gpGlobals - > curtime + TEAM_CHANGE_INTERVAL ;
if ( HL2MPRules ( ) - > IsTeamplay ( ) = = true )
{
SetPlayerTeamModel ( ) ;
}
else
{
SetPlayerModel ( ) ;
}
if ( iTeam = = TEAM_SPECTATOR )
{
RemoveAllItems ( true ) ;
State_Transition ( STATE_OBSERVER_MODE ) ;
}
if ( bKill = = true )
{
CommitSuicide ( ) ;
}
}
bool CHL2MP_Player : : HandleCommand_JoinTeam ( int team )
{
if ( ! GetGlobalTeam ( team ) | | team = = 0 )
{
Warning ( " HandleCommand_JoinTeam( %d ) - invalid team index. \n " , team ) ;
return false ;
}
if ( team = = TEAM_SPECTATOR )
{
// Prevent this is the cvar is set
if ( ! mp_allowspectators . GetInt ( ) )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Cannot_Be_Spectator " ) ;
return false ;
}
if ( GetTeamNumber ( ) ! = TEAM_UNASSIGNED & & ! IsDead ( ) )
{
m_fNextSuicideTime = gpGlobals - > curtime ; // allow the suicide to work
CommitSuicide ( ) ;
// add 1 to frags to balance out the 1 subtracted for killing yourself
IncrementFragCount ( 1 ) ;
}
ChangeTeam ( TEAM_SPECTATOR ) ;
return true ;
}
else
{
StopObserverMode ( ) ;
State_Transition ( STATE_ACTIVE ) ;
}
// Switch their actual team...
ChangeTeam ( team ) ;
return true ;
}
bool CHL2MP_Player : : ClientCommand ( const CCommand & args )
{
if ( FStrEq ( args [ 0 ] , " spectate " ) )
{
if ( ShouldRunRateLimitedCommand ( args ) )
{
// instantly join spectators
HandleCommand_JoinTeam ( TEAM_SPECTATOR ) ;
}
return true ;
}
else if ( FStrEq ( args [ 0 ] , " jointeam " ) )
{
if ( args . ArgC ( ) < 2 )
{
Warning ( " Player sent bad jointeam syntax \n " ) ;
}
if ( ShouldRunRateLimitedCommand ( args ) )
{
int iTeam = atoi ( args [ 1 ] ) ;
HandleCommand_JoinTeam ( iTeam ) ;
}
return true ;
}
else if ( FStrEq ( args [ 0 ] , " joingame " ) )
{
return true ;
}
return BaseClass : : ClientCommand ( args ) ;
}
void CHL2MP_Player : : CheatImpulseCommands ( int iImpulse )
{
switch ( iImpulse )
{
case 101 :
{
if ( sv_cheats - > GetBool ( ) )
{
GiveAllItems ( ) ;
}
}
break ;
default :
BaseClass : : CheatImpulseCommands ( iImpulse ) ;
}
}
bool CHL2MP_Player : : ShouldRunRateLimitedCommand ( const CCommand & args )
{
int i = m_RateLimitLastCommandTimes . Find ( args [ 0 ] ) ;
if ( i = = m_RateLimitLastCommandTimes . InvalidIndex ( ) )
{
m_RateLimitLastCommandTimes . Insert ( args [ 0 ] , gpGlobals - > curtime ) ;
return true ;
}
else if ( ( gpGlobals - > curtime - m_RateLimitLastCommandTimes [ i ] ) < HL2MP_COMMAND_MAX_RATE )
{
// Too fast.
return false ;
}
else
{
m_RateLimitLastCommandTimes [ i ] = gpGlobals - > curtime ;
return true ;
}
}
void CHL2MP_Player : : CreateViewModel ( int index /*=0*/ )
{
Assert ( index > = 0 & & index < MAX_VIEWMODELS ) ;
if ( GetViewModel ( index ) )
return ;
CPredictedViewModel * vm = ( CPredictedViewModel * ) CreateEntityByName ( " predicted_viewmodel " ) ;
if ( vm )
{
vm - > SetAbsOrigin ( GetAbsOrigin ( ) ) ;
vm - > SetOwner ( this ) ;
vm - > SetIndex ( index ) ;
DispatchSpawn ( vm ) ;
vm - > FollowEntity ( this , false ) ;
m_hViewModel . Set ( index , vm ) ;
}
}
bool CHL2MP_Player : : BecomeRagdollOnClient ( const Vector & force )
{
return true ;
}
// -------------------------------------------------------------------------------- //
// Ragdoll entities.
// -------------------------------------------------------------------------------- //
class CHL2MPRagdoll : public CBaseAnimatingOverlay
{
public :
DECLARE_CLASS ( CHL2MPRagdoll , CBaseAnimatingOverlay ) ;
DECLARE_SERVERCLASS ( ) ;
// Transmit ragdolls to everyone.
virtual int UpdateTransmitState ( )
{
return SetTransmitState ( FL_EDICT_ALWAYS ) ;
}
public :
// In case the client has the player entity, we transmit the player index.
// In case the client doesn't have it, we transmit the player's model index, origin, and angles
// so they can create a ragdoll in the right place.
CNetworkHandle ( CBaseEntity , m_hPlayer ) ; // networked entity handle
CNetworkVector ( m_vecRagdollVelocity ) ;
CNetworkVector ( m_vecRagdollOrigin ) ;
} ;
LINK_ENTITY_TO_CLASS ( hl2mp_ragdoll , CHL2MPRagdoll ) ;
IMPLEMENT_SERVERCLASS_ST_NOBASE ( CHL2MPRagdoll , DT_HL2MPRagdoll )
SendPropVector ( SENDINFO ( m_vecRagdollOrigin ) , - 1 , SPROP_COORD ) ,
SendPropEHandle ( SENDINFO ( m_hPlayer ) ) ,
SendPropModelIndex ( SENDINFO ( m_nModelIndex ) ) ,
SendPropInt ( SENDINFO ( m_nForceBone ) , 8 , 0 ) ,
SendPropVector ( SENDINFO ( m_vecForce ) , - 1 , SPROP_NOSCALE ) ,
SendPropVector ( SENDINFO ( m_vecRagdollVelocity ) )
END_SEND_TABLE ( )
void CHL2MP_Player : : CreateRagdollEntity ( void )
{
if ( m_hRagdoll )
{
UTIL_RemoveImmediate ( m_hRagdoll ) ;
m_hRagdoll = NULL ;
}
// If we already have a ragdoll, don't make another one.
CHL2MPRagdoll * pRagdoll = dynamic_cast < CHL2MPRagdoll * > ( m_hRagdoll . Get ( ) ) ;
if ( ! pRagdoll )
{
// create a new one
pRagdoll = dynamic_cast < CHL2MPRagdoll * > ( CreateEntityByName ( " hl2mp_ragdoll " ) ) ;
}
if ( pRagdoll )
{
pRagdoll - > m_hPlayer = this ;
pRagdoll - > m_vecRagdollOrigin = GetAbsOrigin ( ) ;
pRagdoll - > m_vecRagdollVelocity = GetAbsVelocity ( ) ;
pRagdoll - > m_nModelIndex = m_nModelIndex ;
pRagdoll - > m_nForceBone = m_nForceBone ;
pRagdoll - > m_vecForce = m_vecTotalBulletForce ;
pRagdoll - > SetAbsOrigin ( GetAbsOrigin ( ) ) ;
}
// ragdolls will be removed on round restart automatically
m_hRagdoll = pRagdoll ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CHL2MP_Player : : FlashlightIsOn ( void )
{
return IsEffectActive ( EF_DIMLIGHT ) ;
}
extern ConVar flashlight ;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2MP_Player : : FlashlightTurnOn ( void )
{
if ( flashlight . GetInt ( ) > 0 & & IsAlive ( ) )
{
AddEffects ( EF_DIMLIGHT ) ;
EmitSound ( " HL2Player.FlashlightOn " ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CHL2MP_Player : : FlashlightTurnOff ( void )
{
RemoveEffects ( EF_DIMLIGHT ) ;
if ( IsAlive ( ) )
{
EmitSound ( " HL2Player.FlashlightOff " ) ;
}
}
void CHL2MP_Player : : Weapon_Drop ( CBaseCombatWeapon * pWeapon , const Vector * pvecTarget , const Vector * pVelocity )
{
//Drop a grenade if it's primed.
if ( GetActiveWeapon ( ) )
{
CBaseCombatWeapon * pGrenade = Weapon_OwnsThisType ( " weapon_frag " ) ;
if ( GetActiveWeapon ( ) = = pGrenade )
{
if ( ( m_nButtons & IN_ATTACK ) | | ( m_nButtons & IN_ATTACK2 ) )
{
DropPrimedFragGrenade ( this , pGrenade ) ;
return ;
}
}
}
BaseClass : : Weapon_Drop ( pWeapon , pvecTarget , pVelocity ) ;
}
void CHL2MP_Player : : DetonateTripmines ( void )
{
CBaseEntity * pEntity = NULL ;
while ( ( pEntity = gEntList . FindEntityByClassname ( pEntity , " npc_satchel " ) ) ! = NULL )
{
CSatchelCharge * pSatchel = dynamic_cast < CSatchelCharge * > ( pEntity ) ;
if ( pSatchel - > m_bIsLive & & pSatchel - > GetThrower ( ) = = this )
{
g_EventQueue . AddEvent ( pSatchel , " Explode " , 0.20 , this , this ) ;
}
}
// Play sound for pressing the detonator
EmitSound ( " Weapon_SLAM.SatchelDetonate " ) ;
}
void CHL2MP_Player : : Event_Killed ( const CTakeDamageInfo & info )
{
//update damage info with our accumulated physics force
CTakeDamageInfo subinfo = info ;
subinfo . SetDamageForce ( m_vecTotalBulletForce ) ;
SetNumAnimOverlays ( 0 ) ;
// Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
// because we still want to transmit to the clients in our PVS.
CreateRagdollEntity ( ) ;
DetonateTripmines ( ) ;
BaseClass : : Event_Killed ( subinfo ) ;
if ( info . GetDamageType ( ) & DMG_DISSOLVE )
{
if ( m_hRagdoll )
{
m_hRagdoll - > GetBaseAnimating ( ) - > Dissolve ( NULL , gpGlobals - > curtime , false , ENTITY_DISSOLVE_NORMAL ) ;
}
}
CBaseEntity * pAttacker = info . GetAttacker ( ) ;
if ( pAttacker )
{
int iScoreToAdd = 1 ;
if ( pAttacker = = this )
{
iScoreToAdd = - 1 ;
}
GetGlobalTeam ( pAttacker - > GetTeamNumber ( ) ) - > AddScore ( iScoreToAdd ) ;
}
FlashlightTurnOff ( ) ;
m_lifeState = LIFE_DEAD ;
RemoveEffects ( EF_NODRAW ) ; // still draw player body
StopZooming ( ) ;
}
int CHL2MP_Player : : OnTakeDamage ( const CTakeDamageInfo & inputInfo )
{
//return here if the player is in the respawn grace period vs. slams.
if ( gpGlobals - > curtime < m_flSlamProtectTime & & ( inputInfo . GetDamageType ( ) = = DMG_BLAST ) )
return 0 ;
m_vecTotalBulletForce + = inputInfo . GetDamageForce ( ) ;
gamestats - > Event_PlayerDamage ( this , inputInfo ) ;
return BaseClass : : OnTakeDamage ( inputInfo ) ;
}
void CHL2MP_Player : : DeathSound ( const CTakeDamageInfo & info )
{
if ( m_hRagdoll & & m_hRagdoll - > GetBaseAnimating ( ) - > IsDissolving ( ) )
return ;
char szStepSound [ 128 ] ;
Q_snprintf ( szStepSound , sizeof ( szStepSound ) , " %s.Die " , GetPlayerModelSoundPrefix ( ) ) ;
const char * pModelName = STRING ( GetModelName ( ) ) ;
CSoundParameters params ;
if ( GetParametersForSound ( szStepSound , params , pModelName ) = = false )
return ;
Vector vecOrigin = GetAbsOrigin ( ) ;
CRecipientFilter filter ;
filter . AddRecipientsByPAS ( vecOrigin ) ;
EmitSound_t ep ;
ep . m_nChannel = params . channel ;
ep . m_pSoundName = params . soundname ;
ep . m_flVolume = params . volume ;
ep . m_SoundLevel = params . soundlevel ;
ep . m_nFlags = 0 ;
ep . m_nPitch = params . pitch ;
ep . m_pOrigin = & vecOrigin ;
EmitSound ( filter , entindex ( ) , ep ) ;
}
CBaseEntity * CHL2MP_Player : : EntSelectSpawnPoint ( void )
{
CBaseEntity * pSpot = NULL ;
CBaseEntity * pLastSpawnPoint = g_pLastSpawn ;
edict_t * player = edict ( ) ;
const char * pSpawnpointName = " info_player_deathmatch " ;
if ( HL2MPRules ( ) - > IsTeamplay ( ) = = true )
{
if ( GetTeamNumber ( ) = = TEAM_COMBINE )
{
pSpawnpointName = " info_player_combine " ;
pLastSpawnPoint = g_pLastCombineSpawn ;
}
else if ( GetTeamNumber ( ) = = TEAM_REBELS )
{
pSpawnpointName = " info_player_rebel " ;
pLastSpawnPoint = g_pLastRebelSpawn ;
}
if ( gEntList . FindEntityByClassname ( NULL , pSpawnpointName ) = = NULL )
{
pSpawnpointName = " info_player_deathmatch " ;
pLastSpawnPoint = g_pLastSpawn ;
}
}
pSpot = pLastSpawnPoint ;
// Randomize the start spot
for ( int i = random - > RandomInt ( 1 , 5 ) ; i > 0 ; i - - )
pSpot = gEntList . FindEntityByClassname ( pSpot , pSpawnpointName ) ;
if ( ! pSpot ) // skip over the null point
pSpot = gEntList . FindEntityByClassname ( pSpot , pSpawnpointName ) ;
CBaseEntity * pFirstSpot = pSpot ;
do
{
if ( pSpot )
{
// check if pSpot is valid
if ( g_pGameRules - > IsSpawnPointValid ( pSpot , this ) )
{
if ( pSpot - > GetLocalOrigin ( ) = = vec3_origin )
{
pSpot = gEntList . FindEntityByClassname ( pSpot , pSpawnpointName ) ;
continue ;
}
// if so, go to pSpot
goto ReturnSpot ;
}
}
// increment pSpot
pSpot = gEntList . FindEntityByClassname ( pSpot , pSpawnpointName ) ;
} while ( pSpot ! = pFirstSpot ) ; // loop if we're not back to the start
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
if ( pSpot )
{
CBaseEntity * ent = NULL ;
for ( CEntitySphereQuery sphere ( pSpot - > GetAbsOrigin ( ) , 128 ) ; ( ent = sphere . GetCurrentEntity ( ) ) ! = NULL ; sphere . NextEntity ( ) )
{
// if ent is a client, kill em (unless they are ourselves)
if ( ent - > IsPlayer ( ) & & ! ( ent - > edict ( ) = = player ) )
ent - > TakeDamage ( CTakeDamageInfo ( GetContainingEntity ( INDEXENT ( 0 ) ) , GetContainingEntity ( INDEXENT ( 0 ) ) , 300 , DMG_GENERIC ) ) ;
}
goto ReturnSpot ;
}
if ( ! pSpot )
{
pSpot = gEntList . FindEntityByClassname ( pSpot , " info_player_start " ) ;
if ( pSpot )
goto ReturnSpot ;
}
ReturnSpot :
if ( HL2MPRules ( ) - > IsTeamplay ( ) = = true )
{
if ( GetTeamNumber ( ) = = TEAM_COMBINE )
{
g_pLastCombineSpawn = pSpot ;
}
else if ( GetTeamNumber ( ) = = TEAM_REBELS )
{
g_pLastRebelSpawn = pSpot ;
}
}
g_pLastSpawn = pSpot ;
m_flSlamProtectTime = gpGlobals - > curtime + 0.5 ;
return pSpot ;
}
CON_COMMAND ( timeleft , " prints the time remaining in the match " )
{
CHL2MP_Player * pPlayer = ToHL2MPPlayer ( UTIL_GetCommandClient ( ) ) ;
int iTimeRemaining = ( int ) HL2MPRules ( ) - > GetMapRemainingTime ( ) ;
if ( iTimeRemaining = = 0 )
{
if ( pPlayer )
{
ClientPrint ( pPlayer , HUD_PRINTTALK , " This game has no timelimit. " ) ;
}
else
{
Msg ( " * No Time Limit * \n " ) ;
}
}
else
{
int iMinutes , iSeconds ;
iMinutes = iTimeRemaining / 60 ;
iSeconds = iTimeRemaining % 60 ;
char minutes [ 8 ] ;
char seconds [ 8 ] ;
Q_snprintf ( minutes , sizeof ( minutes ) , " %d " , iMinutes ) ;
Q_snprintf ( seconds , sizeof ( seconds ) , " %2.2d " , iSeconds ) ;
if ( pPlayer )
{
ClientPrint ( pPlayer , HUD_PRINTTALK , " Time left in map: %s1:%s2 " , minutes , seconds ) ;
}
else
{
Msg ( " Time Remaining: %s:%s \n " , minutes , seconds ) ;
}
}
}
void CHL2MP_Player : : Reset ( )
{
ResetDeathCount ( ) ;
ResetFragCount ( ) ;
}
bool CHL2MP_Player : : IsReady ( )
{
return m_bReady ;
}
void CHL2MP_Player : : SetReady ( bool bReady )
{
m_bReady = bReady ;
}
void CHL2MP_Player : : CheckChatText ( char * p , int bufsize )
{
//Look for escape sequences and replace
char * buf = new char [ bufsize ] ;
int pos = 0 ;
// Parse say text for escape sequences
for ( char * pSrc = p ; pSrc ! = NULL & & * pSrc ! = 0 & & pos < bufsize - 1 ; pSrc + + )
{
// copy each char across
buf [ pos ] = * pSrc ;
pos + + ;
}
buf [ pos ] = ' \0 ' ;
// copy buf back into p
Q_strncpy ( p , buf , bufsize ) ;
delete [ ] buf ;
const char * pReadyCheck = p ;
HL2MPRules ( ) - > CheckChatForReadySignal ( this , pReadyCheck ) ;
}
void CHL2MP_Player : : State_Transition ( HL2MPPlayerState newState )
{
State_Leave ( ) ;
State_Enter ( newState ) ;
}
void CHL2MP_Player : : State_Enter ( HL2MPPlayerState newState )
{
m_iPlayerState = newState ;
m_pCurStateInfo = State_LookupInfo ( newState ) ;
// Initialize the new state.
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnEnterState )
( this - > * m_pCurStateInfo - > pfnEnterState ) ( ) ;
}
void CHL2MP_Player : : State_Leave ( )
{
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnLeaveState )
{
( this - > * m_pCurStateInfo - > pfnLeaveState ) ( ) ;
}
}
void CHL2MP_Player : : State_PreThink ( )
{
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnPreThink )
{
( this - > * m_pCurStateInfo - > pfnPreThink ) ( ) ;
}
}
CHL2MPPlayerStateInfo * CHL2MP_Player : : State_LookupInfo ( HL2MPPlayerState state )
{
// This table MUST match the
static CHL2MPPlayerStateInfo playerStateInfos [ ] =
{
{ STATE_ACTIVE , " STATE_ACTIVE " , & CHL2MP_Player : : State_Enter_ACTIVE , NULL , & CHL2MP_Player : : State_PreThink_ACTIVE } ,
{ STATE_OBSERVER_MODE , " STATE_OBSERVER_MODE " , & CHL2MP_Player : : State_Enter_OBSERVER_MODE , NULL , & CHL2MP_Player : : State_PreThink_OBSERVER_MODE }
} ;
for ( int i = 0 ; i < ARRAYSIZE ( playerStateInfos ) ; i + + )
{
if ( playerStateInfos [ i ] . m_iPlayerState = = state )
return & playerStateInfos [ i ] ;
}
return NULL ;
}
bool CHL2MP_Player : : StartObserverMode ( int mode )
{
//we only want to go into observer mode if the player asked to, not on a death timeout
if ( m_bEnterObserver = = true )
{
VPhysicsDestroyObject ( ) ;
return BaseClass : : StartObserverMode ( mode ) ;
}
return false ;
}
void CHL2MP_Player : : StopObserverMode ( )
{
m_bEnterObserver = false ;
BaseClass : : StopObserverMode ( ) ;
}
void CHL2MP_Player : : State_Enter_OBSERVER_MODE ( )
{
int observerMode = m_iObserverLastMode ;
if ( IsNetClient ( ) )
{
const char * pIdealMode = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_spec_mode " ) ;
if ( pIdealMode )
{
observerMode = atoi ( pIdealMode ) ;
if ( observerMode < = OBS_MODE_FIXED | | observerMode > OBS_MODE_ROAMING )
{
observerMode = m_iObserverLastMode ;
}
}
}
m_bEnterObserver = true ;
StartObserverMode ( observerMode ) ;
}
void CHL2MP_Player : : State_PreThink_OBSERVER_MODE ( )
{
// Make sure nobody has changed any of our state.
// Assert( GetMoveType() == MOVETYPE_FLY );
Assert ( m_takedamage = = DAMAGE_NO ) ;
Assert ( IsSolidFlagSet ( FSOLID_NOT_SOLID ) ) ;
// Assert( IsEffectActive( EF_NODRAW ) );
// Must be dead.
Assert ( m_lifeState = = LIFE_DEAD ) ;
Assert ( pl . deadflag ) ;
}
void CHL2MP_Player : : State_Enter_ACTIVE ( )
{
SetMoveType ( MOVETYPE_WALK ) ;
// md 8/15/07 - They'll get set back to solid when they actually respawn. If we set them solid now and mp_forcerespawn
// is false, then they'll be spectating but blocking live players from moving.
// RemoveSolidFlags( FSOLID_NOT_SOLID );
m_Local . m_iHideHUD = 0 ;
}
void CHL2MP_Player : : State_PreThink_ACTIVE ( )
{
//we don't really need to do anything here.
//This state_prethink structure came over from CS:S and was doing an assert check that fails the way hl2dm handles death
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHL2MP_Player : : CanHearAndReadChatFrom ( CBasePlayer * pPlayer )
{
// can always hear the console unless we're ignoring all chat
if ( ! pPlayer )
return false ;
return true ;
}