aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/hl2mp/hl2mp_player.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /sp/src/game/server/hl2mp/hl2mp_player.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/game/server/hl2mp/hl2mp_player.cpp')
-rw-r--r--sp/src/game/server/hl2mp/hl2mp_player.cpp3258
1 files changed, 1629 insertions, 1629 deletions
diff --git a/sp/src/game/server/hl2mp/hl2mp_player.cpp b/sp/src/game/server/hl2mp/hl2mp_player.cpp
index fa828031..1469d842 100644
--- a/sp/src/game/server/hl2mp/hl2mp_player.cpp
+++ b/sp/src/game/server/hl2mp/hl2mp_player.cpp
@@ -1,1629 +1,1629 @@
-//========= 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
-
-#pragma warning( disable : 4355 )
-
-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;
-}
+//========= 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
+
+#pragma warning( disable : 4355 )
+
+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;
+}