2020-04-22 18:56:21 +02:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL1.
//
// $NoKeywords: $
//=============================================================================//
# include "cbase.h"
# include "cs_player.h"
# include "cs_gamerules.h"
2024-07-12 03:59:34 +02:00
# include "dt_send.h"
2020-04-22 18:56:21 +02:00
# include "trains.h"
# include "vcollide_parse.h"
# include "in_buttons.h"
# include "igamemovement.h"
# include "ai_hull.h"
# include "ndebugoverlay.h"
# include "weapon_csbase.h"
# include "decals.h"
# include "cs_ammodef.h"
# include "IEffects.h"
# include "cs_client.h"
# include "client.h"
# include "cs_shareddefs.h"
# include "shake.h"
# include "team.h"
# include "weapon_c4.h"
# include "weapon_parse.h"
# include "weapon_knife.h"
# include "movehelper_server.h"
# include "tier0/vprof.h"
# include "te_effect_dispatch.h"
# include "vphysics/player_controller.h"
# include "weapon_hegrenade.h"
# include "weapon_flashbang.h"
# include "weapon_csbasegun.h"
# include "weapon_smokegrenade.h"
# include <KeyValues.h>
# include "engine/IEngineSound.h"
# include "bot.h"
# include "studio.h"
# include <coordsize.h>
# include "predicted_viewmodel.h"
# include "props_shared.h"
# include "tier0/icommandline.h"
# include "info_camera_link.h"
# include "hintmessage.h"
# include "obstacle_pushaway.h"
# include "movevars_shared.h"
# include "death_pose.h"
# include "basecsgrenade_projectile.h"
# include "SoundEmitterSystem/isoundemittersystembase.h"
# include "CRagdollMagnet.h"
# include "datacache/imdlcache.h"
# include "npcevent.h"
# include "cs_gamestats.h"
# include "gamestats.h"
# include "holiday_gift.h"
# include "../../shared/cstrike/cs_achievement_constants.h"
//=============================================================================
// HPE_BEGIN
//=============================================================================
// [dwenger] Needed for global hostage list
# include "cs_simple_hostage.h"
// [dwenger] Needed for weapon type used tracking
# include "../../shared/cstrike/cs_weapon_parse.h"
# define REPORT_PLAYER_DAMAGE 0
//=============================================================================
// HPE_END
//=============================================================================
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
# pragma optimize( "", off )
# pragma warning( disable : 4355 )
// Minimum interval between rate-limited commands that players can run.
# define CS_COMMAND_MAX_RATE 0.3
const float CycleLatchInterval = 0.2f ;
# define CS_PUSHAWAY_THINK_CONTEXT "CSPushawayThink"
ConVar cs_ShowStateTransitions ( " cs_ShowStateTransitions " , " -2 " , FCVAR_CHEAT , " cs_ShowStateTransitions <ent index or -1 for all>. Show player state transitions. " ) ;
ConVar sv_max_usercmd_future_ticks ( " sv_max_usercmd_future_ticks " , " 8 " , 0 , " Prevents clients from running usercmds too far in the future. Prevents speed hacks. " ) ;
ConVar sv_motd_unload_on_dismissal ( " sv_motd_unload_on_dismissal " , " 0 " , 0 , " If enabled, the MOTD contents will be unloaded when the player closes the MOTD. " ) ;
//=============================================================================
// HPE_BEGIN:
// [Forrest] Allow MVP to be turned off for a server
// [Forrest] Allow freezecam to be turned off for a server
// [Forrest] Allow win panel to be turned off for a server
//=============================================================================
static void SvNoMVPChangeCallback ( IConVar * pConVar , const char * pOldValue , float flOldValue )
{
ConVarRef var ( pConVar ) ;
if ( var . IsValid ( ) & & var . GetBool ( ) )
{
// Clear the MVPs of all players when MVP is turned off.
for ( int i = 1 ; i < = MAX_PLAYERS ; i + + )
{
CCSPlayer * pPlayer = ToCSPlayer ( UTIL_PlayerByIndex ( i ) ) ;
if ( pPlayer )
{
pPlayer - > SetNumMVPs ( 0 ) ;
}
}
}
}
ConVar sv_nomvp ( " sv_nomvp " , " 0 " , 0 , " Disable MVP awards. " , SvNoMVPChangeCallback ) ;
ConVar sv_disablefreezecam ( " sv_disablefreezecam " , " 0 " , FCVAR_REPLICATED , " Turn on/off freezecam on server " ) ;
ConVar sv_nowinpanel ( " sv_nowinpanel " , " 0 " , FCVAR_REPLICATED , " Turn on/off win panel on server " ) ;
//=============================================================================
// HPE_END
//=============================================================================
// ConVar bot_mimic( "bot_mimic", "0", FCVAR_CHEAT );
ConVar bot_freeze ( " bot_freeze " , " 0 " , FCVAR_CHEAT ) ;
ConVar bot_crouch ( " bot_crouch " , " 0 " , FCVAR_CHEAT ) ;
ConVar bot_mimic_yaw_offset ( " bot_mimic_yaw_offset " , " 180 " , FCVAR_CHEAT ) ;
ConVar sv_legacy_grenade_damage ( " sv_legacy_grenade_damage " , " 0 " , FCVAR_REPLICATED , " Enable to replicate grenade damage behavior of the original Counter-Strike Source game. " ) ;
extern ConVar mp_autokick ;
extern ConVar mp_holiday_nogifts ;
extern ConVar sv_turbophysics ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Added in convars for freeze cam time length
//=============================================================================
extern ConVar spec_freeze_time ;
extern ConVar spec_freeze_traveltime ;
//=============================================================================
// HPE_END
//=============================================================================
extern ConVar ammo_hegrenade_max ;
extern ConVar ammo_flashbang_max ;
extern ConVar ammo_smokegrenade_max ;
# define THROWGRENADE_COUNTER_BITS 3
EHANDLE g_pLastCTSpawn ;
EHANDLE g_pLastTerroristSpawn ;
void TE_RadioIcon ( IRecipientFilter & filter , float delay , CBaseEntity * pPlayer ) ;
// -------------------------------------------------------------------------------- //
// Classes
// -------------------------------------------------------------------------------- //
class CPhysicsPlayerCallback : public IPhysicsPlayerControllerEvent
{
public :
int ShouldMoveTo ( IPhysicsObject * pObject , const Vector & position )
{
CCSPlayer * pPlayer = ( CCSPlayer * ) pObject - > GetGameData ( ) ;
if ( pPlayer )
{
if ( pPlayer - > TouchedPhysics ( ) )
{
return 0 ;
}
}
return 1 ;
}
} ;
static CPhysicsPlayerCallback playerCallback ;
// -------------------------------------------------------------------------------- //
// Ragdoll entities.
// -------------------------------------------------------------------------------- //
class CCSRagdoll : public CBaseAnimatingOverlay
{
public :
DECLARE_CLASS ( CCSRagdoll , CBaseAnimatingOverlay ) ;
DECLARE_SERVERCLASS ( ) ;
// Transmit ragdolls to everyone.
virtual int UpdateTransmitState ( )
{
return SetTransmitState ( FL_EDICT_ALWAYS ) ;
}
void Init ( void )
{
SetSolid ( SOLID_BBOX ) ;
SetMoveType ( MOVETYPE_STEP ) ;
SetFriction ( 1.0f ) ;
SetCollisionBounds ( VEC_DUCK_HULL_MIN , VEC_DUCK_HULL_MAX ) ;
m_takedamage = DAMAGE_NO ;
SetCollisionGroup ( COLLISION_GROUP_DEBRIS ) ;
SetAbsOrigin ( m_hPlayer - > GetAbsOrigin ( ) ) ;
SetAbsVelocity ( m_hPlayer - > GetAbsVelocity ( ) ) ;
AddSolidFlags ( FSOLID_NOT_SOLID ) ;
ChangeTeam ( m_hPlayer - > GetTeamNumber ( ) ) ;
}
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 ) ;
CNetworkVar ( int , m_iDeathPose ) ;
CNetworkVar ( int , m_iDeathFrame ) ;
} ;
LINK_ENTITY_TO_CLASS ( cs_ragdoll , CCSRagdoll ) ;
IMPLEMENT_SERVERCLASS_ST_NOBASE ( CCSRagdoll , DT_CSRagdoll )
SendPropVector ( SENDINFO ( m_vecOrigin ) , - 1 , SPROP_COORD | SPROP_CHANGES_OFTEN , 0.0f , HIGH_DEFAULT , SendProxy_Origin ) ,
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 ) ) ,
SendPropInt ( SENDINFO ( m_iDeathPose ) , ANIMATION_SEQUENCE_BITS , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iDeathFrame ) , 5 ) ,
SendPropInt ( SENDINFO ( m_iTeamNum ) , TEAMNUM_NUM_BITS , 0 ) ,
SendPropInt ( SENDINFO ( m_bClientSideAnimation ) , 1 , SPROP_UNSIGNED ) ,
END_SEND_TABLE ( )
// -------------------------------------------------------------------------------- //
// Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
// -------------------------------------------------------------------------------- //
class CTEPlayerAnimEvent : public CBaseTempEntity
{
public :
DECLARE_CLASS ( CTEPlayerAnimEvent , CBaseTempEntity ) ;
DECLARE_SERVERCLASS ( ) ;
CTEPlayerAnimEvent ( const char * name ) : CBaseTempEntity ( name )
{
}
CNetworkHandle ( CBasePlayer , m_hPlayer ) ;
CNetworkVar ( int , m_iEvent ) ;
CNetworkVar ( int , m_nData ) ;
} ;
IMPLEMENT_SERVERCLASS_ST_NOBASE ( CTEPlayerAnimEvent , DT_TEPlayerAnimEvent )
SendPropEHandle ( SENDINFO ( m_hPlayer ) ) ,
SendPropInt ( SENDINFO ( m_iEvent ) , Q_log2 ( PLAYERANIMEVENT_COUNT ) + 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_nData ) , 32 )
END_SEND_TABLE ( )
static CTEPlayerAnimEvent g_TEPlayerAnimEvent ( " PlayerAnimEvent " ) ;
void TE_PlayerAnimEvent ( CBasePlayer * pPlayer , PlayerAnimEvent_t event , int nData )
{
CPVSFilter filter ( ( const Vector & ) pPlayer - > EyePosition ( ) ) ;
g_TEPlayerAnimEvent . m_hPlayer = pPlayer ;
g_TEPlayerAnimEvent . m_iEvent = event ;
g_TEPlayerAnimEvent . m_nData = nData ;
g_TEPlayerAnimEvent . Create ( filter , 0 ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Filters updates to a variable so that only non-local players see
// the changes. This is so we can send a low-res origin to non-local players
// while sending a hi-res one to the local player.
// Input : *pVarData -
// *pOut -
// objectID -
//-----------------------------------------------------------------------------
void * SendProxy_SendNonLocalDataTable ( const SendProp * pProp , const void * pStruct , const void * pVarData , CSendProxyRecipients * pRecipients , int objectID )
{
pRecipients - > SetAllRecipients ( ) ;
pRecipients - > ClearRecipient ( objectID - 1 ) ;
return ( void * ) pVarData ;
}
REGISTER_SEND_PROXY_NON_MODIFIED_POINTER ( SendProxy_SendNonLocalDataTable ) ;
// -------------------------------------------------------------------------------- //
// Tables.
// -------------------------------------------------------------------------------- //
LINK_ENTITY_TO_CLASS ( player , CCSPlayer ) ;
PRECACHE_REGISTER ( player ) ;
BEGIN_SEND_TABLE_NOBASE ( CCSPlayer , DT_CSLocalPlayerExclusive )
SendPropFloat ( SENDINFO ( m_flStamina ) , 14 , 0 , 0 , 1400 ) ,
SendPropInt ( SENDINFO ( m_iDirection ) , 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iShotsFired ) , 8 , SPROP_UNSIGNED ) ,
SendPropFloat ( SENDINFO ( m_flVelocityModifier ) , 8 , 0 , 0 , 1 ) ,
//=============================================================================
// HPE_BEGIN:
// [tj]Set up the send table for per-client domination data
//=============================================================================
SendPropArray3 ( SENDINFO_ARRAY3 ( m_bPlayerDominated ) , SendPropBool ( SENDINFO_ARRAY ( m_bPlayerDominated ) ) ) ,
SendPropArray3 ( SENDINFO_ARRAY3 ( m_bPlayerDominatingMe ) , SendPropBool ( SENDINFO_ARRAY ( m_bPlayerDominatingMe ) ) ) ,
//=============================================================================
// HPE_END
//=============================================================================
END_SEND_TABLE ( )
IMPLEMENT_SERVERCLASS_ST ( CCSPlayer , DT_CSPlayer )
// Data that only gets sent to the local player.
SendPropDataTable ( " cslocaldata " , 0 , & REFERENCE_SEND_TABLE ( DT_CSLocalPlayerExclusive ) , SendProxy_SendLocalDataTable ) ,
SendPropInt ( SENDINFO ( m_iThrowGrenadeCounter ) , THROWGRENADE_COUNTER_BITS , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iAddonBits ) , NUM_ADDON_BITS , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iPrimaryAddon ) , 8 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iSecondaryAddon ) , 8 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iPlayerState ) , Q_log2 ( NUM_PLAYER_STATES ) + 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iAccount ) , 16 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_bInBombZone ) , 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_bInBuyZone ) , 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_iClass ) , Q_log2 ( CS_NUM_CLASSES ) + 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_ArmorValue ) , 8 ) ,
2024-07-12 03:59:34 +02:00
SendPropQAngles ( SENDINFO ( m_angEyeAngles ) ) ,
2020-04-22 18:56:21 +02:00
SendPropBool ( SENDINFO ( m_bHasDefuser ) ) ,
SendPropBool ( SENDINFO ( m_bNightVisionOn ) ) , //send as int so we can use a RecvProxy on the client
SendPropBool ( SENDINFO ( m_bHasNightVision ) ) ,
//=============================================================================
// HPE_BEGIN:
// [dwenger] Added for fun-fact support
//=============================================================================
//SendPropBool( SENDINFO( m_bPickedUpDefuser ) ),
//SendPropBool( SENDINFO( m_bDefusedWithPickedUpKit) ),
//=============================================================================
// HPE_END
//=============================================================================
SendPropBool ( SENDINFO ( m_bInHostageRescueZone ) ) ,
SendPropBool ( SENDINFO ( m_bIsDefusing ) ) ,
SendPropBool ( SENDINFO ( m_bResumeZoom ) ) ,
SendPropInt ( SENDINFO ( m_iLastZoom ) , 8 , SPROP_UNSIGNED ) ,
# ifdef CS_SHIELD_ENABLED
SendPropBool ( SENDINFO ( m_bHasShield ) ) ,
SendPropBool ( SENDINFO ( m_bShieldDrawn ) ) ,
# endif
SendPropBool ( SENDINFO ( m_bHasHelmet ) ) ,
SendPropFloat ( SENDINFO ( m_flFlashDuration ) , 0 , SPROP_NOSCALE ) ,
SendPropFloat ( SENDINFO ( m_flFlashMaxAlpha ) , 0 , SPROP_NOSCALE ) ,
SendPropInt ( SENDINFO ( m_iProgressBarDuration ) , 4 , SPROP_UNSIGNED ) ,
SendPropFloat ( SENDINFO ( m_flProgressBarStartTime ) , 0 , SPROP_NOSCALE ) ,
2024-07-12 03:59:34 +02:00
SendPropEHandle ( SENDINFO ( m_hRagdoll ) )
2020-04-22 18:56:21 +02:00
END_SEND_TABLE ( )
BEGIN_DATADESC ( CCSPlayer )
DEFINE_INPUTFUNC ( FIELD_VOID , " OnRescueZoneTouch " , RescueZoneTouch ) ,
DEFINE_THINKFUNC ( PushawayThink )
END_DATADESC ( )
// has to be included after above macros
# include "cs_bot.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
// -------------------------------------------------------------------------------- //
void cc_CreatePredictionError_f ( const CCommand & args )
{
float distance = 32 ;
if ( args . ArgC ( ) > = 2 )
{
distance = atof ( args [ 1 ] ) ;
}
CBaseEntity * pEnt = CBaseEntity : : Instance ( 1 ) ;
pEnt - > SetAbsOrigin ( pEnt - > GetAbsOrigin ( ) + Vector ( distance , 0 , 0 ) ) ;
}
ConCommand cc_CreatePredictionError ( " CreatePredictionError " , cc_CreatePredictionError_f , " Create a prediction error " , FCVAR_CHEAT ) ;
// -------------------------------------------------------------------------------- //
// CCSPlayer implementation.
// -------------------------------------------------------------------------------- //
CCSPlayer : : CCSPlayer ( )
{
m_PlayerAnimState = CreatePlayerAnimState ( this , this , LEGANIM_9WAY , true ) ;
m_iLastWeaponFireUsercmd = 0 ;
m_iAddonBits = 0 ;
m_bEscaped = false ;
m_iAccount = 0 ;
m_bIsVIP = false ;
m_iClass = ( int ) CS_CLASS_NONE ;
m_angEyeAngles . Init ( ) ;
SetViewOffset ( VEC_VIEW_SCALED ( this ) ) ;
m_pCurStateInfo = NULL ; // no state yet
m_iThrowGrenadeCounter = 0 ;
m_lifeState = LIFE_DEAD ; // Start "dead".
m_bInBombZone = false ;
m_bInBuyZone = false ;
m_bInHostageRescueZone = false ;
m_flDeathTime = 0.0f ;
m_iHostagesKilled = 0 ;
iRadioMenu = - 1 ;
m_bTeamChanged = false ;
m_iShotsFired = 0 ;
m_iDirection = 0 ;
m_receivesMoneyNextRound = true ;
m_bIsBeingGivenItem = false ;
m_isVIP = false ;
m_bJustKilledTeammate = false ;
m_bPunishedForTK = false ;
m_iTeamKills = 0 ;
m_flLastMovement = gpGlobals - > curtime ;
m_iNextTimeCheck = 0 ;
m_szNewName [ 0 ] = 0 ;
m_szClanTag [ 0 ] = 0 ;
for ( int i = 0 ; i < NAME_CHANGE_HISTORY_SIZE ; i + + )
{
m_flNameChangeHistory [ i ] = - NAME_CHANGE_HISTORY_INTERVAL ;
}
m_iIgnoreGlobalChat = 0 ;
m_bIgnoreRadio = false ;
m_pHintMessageQueue = new CHintMessageQueue ( this ) ;
m_iDisplayHistoryBits = 0 ;
m_bShowHints = true ;
m_flNextMouseoverUpdate = gpGlobals - > curtime ;
m_lastDamageHealth = 0 ;
m_lastDamageArmor = 0 ;
2024-07-12 03:59:34 +02:00
m_applyDeafnessTime = 0.0f ;
2020-04-22 18:56:21 +02:00
m_iShouldHaveCash = 0 ;
m_lastNavArea = NULL ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Init achievement variables
// [menglish] Init bullet collision variables
//=============================================================================
m_NumEnemiesKilledThisRound = 0 ;
m_NumEnemiesAtRoundStart = 0 ;
m_KillingSpreeStartTime = - 1 ;
m_firstKillBlindStartTime = - 1 ;
m_killsWhileBlind = 0 ;
m_bSurvivedHeadshotDueToHelmet = false ;
m_pGooseChaseDistractingPlayer = NULL ;
m_gooseChaseStep = GC_NONE ;
m_defuseDefenseStep = DD_NONE ;
m_lastRoundResult = Invalid_Round_End_Reason ;
m_bMadeFootstepNoise = false ;
m_bombPickupTime = - 1 ;
m_bMadePurchseThisRound = false ;
m_roundsWonWithoutPurchase = 0 ;
m_iDeathFlags = 0 ;
m_lastFlashBangAttacker = NULL ;
m_iMVPs = 0 ;
m_bKilledDefuser = false ;
m_bKilledRescuer = false ;
m_maxGrenadeKills = 0 ;
m_grenadeDamageTakenThisRound = 0 ;
m_vLastHitLocationObjectSpace = Vector ( 0 , 0 , 0 ) ;
m_wasNotKilledNaturally = false ;
//=============================================================================
// HPE_END
//=============================================================================
}
CCSPlayer : : ~ CCSPlayer ( )
{
delete m_pHintMessageQueue ;
m_pHintMessageQueue = NULL ;
// delete the records of damage taken and given
ResetDamageCounters ( ) ;
m_PlayerAnimState - > Release ( ) ;
}
CCSPlayer * CCSPlayer : : CreatePlayer ( const char * className , edict_t * ed )
{
CCSPlayer : : s_PlayerEdict = ed ;
return ( CCSPlayer * ) CreateEntityByName ( className ) ;
}
void CCSPlayer : : Precache ( )
{
Vector mins ( - 13 , - 13 , - 10 ) ;
Vector maxs ( 13 , 13 , 75 ) ;
int i ;
for ( i = 0 ; i < CTPlayerModels . Count ( ) ; + + i )
{
PrecacheModel ( CTPlayerModels [ i ] ) ;
engine - > ForceModelBounds ( CTPlayerModels [ i ] , mins , maxs ) ;
}
for ( i = 0 ; i < TerroristPlayerModels . Count ( ) ; + + i )
{
PrecacheModel ( TerroristPlayerModels [ i ] ) ;
engine - > ForceModelBounds ( TerroristPlayerModels [ i ] , mins , maxs ) ;
}
// Sigh - have to force identical VMTs for the player models. I'm just going to hard-code these
// strings here, rather than have char***'s or the CUtlVector<CUtlVector<>> equivalent.
engine - > ForceSimpleMaterial ( " materials/models/player/ct_urban/ct_urban.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_urban/ct_urban_glass.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_sas/ct_sas.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_sas/ct_sas_glass.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_gsg9/ct_gsg9.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_gign/ct_gign.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/ct_gign/ct_gign_glass.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/t_phoenix/t_phoenix.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/t_guerilla/t_guerilla.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/t_leet/t_leet.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/t_leet/t_leet_glass.vmt " ) ;
engine - > ForceSimpleMaterial ( " materials/models/player/t_arctic/t_arctic.vmt " ) ;
# ifdef CS_SHIELD_ENABLED
PrecacheModel ( SHIELD_VIEW_MODEL ) ;
# endif
PrecacheScriptSound ( " Player.DeathHeadShot " ) ;
PrecacheScriptSound ( " Player.Death " ) ;
PrecacheScriptSound ( " Player.DamageHelmet " ) ;
PrecacheScriptSound ( " Player.DamageHeadShot " ) ;
PrecacheScriptSound ( " Flesh.BulletImpact " ) ;
PrecacheScriptSound ( " Player.DamageKevlar " ) ;
PrecacheScriptSound ( " Player.PickupWeapon " ) ;
PrecacheScriptSound ( " Player.NightVisionOff " ) ;
PrecacheScriptSound ( " Player.NightVisionOn " ) ;
PrecacheScriptSound ( " Player.FlashlightOn " ) ;
PrecacheScriptSound ( " Player.FlashlightOff " ) ;
// CS Bot sounds
PrecacheScriptSound ( " Bot.StuckSound " ) ;
PrecacheScriptSound ( " Bot.StuckStart " ) ;
PrecacheScriptSound ( " Bot.FellOff " ) ;
UTIL_PrecacheOther ( " item_kevlar " ) ;
UTIL_PrecacheOther ( " item_assaultsuit " ) ;
UTIL_PrecacheOther ( " item_defuser " ) ;
PrecacheModel ( " sprites/glow01.vmt " ) ;
PrecacheModel ( " models/items/cs_gift.mdl " ) ;
BaseClass : : Precache ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Allow pre-frame adjustments on the player
//-----------------------------------------------------------------------------
ConVar sv_runcmds ( " sv_runcmds " , " 1 " ) ;
void CCSPlayer : : PlayerRunCommand ( CUserCmd * ucmd , IMoveHelper * moveHelper )
{
VPROF ( " CCSPlayer::PlayerRunCommand " ) ;
if ( ! sv_runcmds . GetInt ( ) )
return ;
// don't run commands in the future
if ( ! IsEngineThreaded ( ) & &
( ucmd - > tick_count > ( gpGlobals - > tickcount + sv_max_usercmd_future_ticks . GetInt ( ) ) ) )
{
DevMsg ( " Client cmd out of sync (delta %i). \n " , ucmd - > tick_count - gpGlobals - > tickcount ) ;
return ;
}
// If they use a negative bot_mimic value, then don't process their usercmds, but have
// bots process them instead (so they can stay still and have the bot move around).
CUserCmd tempCmd ;
if ( - bot_mimic . GetInt ( ) = = entindex ( ) )
{
tempCmd = * ucmd ;
ucmd = & tempCmd ;
ucmd - > forwardmove = ucmd - > sidemove = ucmd - > upmove = 0 ;
ucmd - > buttons = 0 ;
ucmd - > impulse = 0 ;
}
if ( IsBot ( ) & & bot_crouch . GetInt ( ) )
ucmd - > buttons | = IN_DUCK ;
BaseClass : : PlayerRunCommand ( ucmd , moveHelper ) ;
}
bool CCSPlayer : : RunMimicCommand ( CUserCmd & cmd )
{
if ( ! IsBot ( ) )
return false ;
int iMimic = abs ( bot_mimic . GetInt ( ) ) ;
if ( iMimic > gpGlobals - > maxClients )
return false ;
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( iMimic ) ;
if ( ! pPlayer )
return false ;
if ( ! pPlayer - > GetLastUserCommand ( ) )
return false ;
cmd = * pPlayer - > GetLastUserCommand ( ) ;
cmd . viewangles [ YAW ] + = bot_mimic_yaw_offset . GetFloat ( ) ;
pl . fixangle = FIXANGLE_NONE ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose: Simulates a single frame of movement for a player
//-----------------------------------------------------------------------------
void CCSPlayer : : RunPlayerMove ( const QAngle & viewangles , float forwardmove , float sidemove , float upmove , unsigned short buttons , byte impulse , float frametime )
{
CUserCmd cmd ;
// Store off the globals.. they're gonna get whacked
float flOldFrametime = gpGlobals - > frametime ;
float flOldCurtime = gpGlobals - > curtime ;
float flTimeBase = gpGlobals - > curtime + gpGlobals - > frametime - frametime ;
this - > SetTimeBase ( flTimeBase ) ;
CUserCmd lastUserCmd = * GetLastUserCommand ( ) ;
Q_memset ( & cmd , 0 , sizeof ( cmd ) ) ;
if ( ! RunMimicCommand ( cmd ) )
{
cmd . forwardmove = forwardmove ;
cmd . sidemove = sidemove ;
cmd . upmove = upmove ;
cmd . buttons = buttons ;
cmd . impulse = impulse ;
VectorCopy ( viewangles , cmd . viewangles ) ;
cmd . random_seed = random - > RandomInt ( 0 , 0x7fffffff ) ;
}
MoveHelperServer ( ) - > SetHost ( this ) ;
PlayerRunCommand ( & cmd , MoveHelperServer ( ) ) ;
// save off the last good usercmd
if ( - bot_mimic . GetInt ( ) = = entindex ( ) )
{
CUserCmd lastCmd = * GetLastUserCommand ( ) ;
lastCmd . command_number = cmd . command_number ;
lastCmd . tick_count = cmd . tick_count ;
SetLastUserCommand ( lastCmd ) ;
}
else
{
SetLastUserCommand ( cmd ) ;
}
// Clear out any fixangle that has been set
pl . fixangle = FIXANGLE_NONE ;
// Restore the globals..
gpGlobals - > frametime = flOldFrametime ;
gpGlobals - > curtime = flOldCurtime ;
MoveHelperServer ( ) - > SetHost ( NULL ) ;
}
void CCSPlayer : : InitialSpawn ( void )
{
BaseClass : : InitialSpawn ( ) ;
// we're going to give the bots money here instead of FinishClientPutInServer()
// because of the bots' timing for purchasing weapons/items.
if ( IsBot ( ) )
{
m_iAccount = CSGameRules ( ) - > GetStartMoney ( ) ;
}
if ( ! engine - > IsDedicatedServer ( ) & & TheNavMesh - > IsOutOfDate ( ) & & this = = UTIL_GetListenServerHost ( ) )
{
ClientPrint ( this , HUD_PRINTCENTER , " The Navigation Mesh was built using a different version of this map. " ) ;
}
State_Enter ( STATE_WELCOME ) ;
//=============================================================================
// HPE_BEGIN:
// [tj] We reset the stats at the beginning of the map (including domination tracking)
//=============================================================================
CCS_GameStats . ResetPlayerStats ( this ) ;
RemoveNemesisRelationships ( ) ;
//=============================================================================
// HPE_END
//=============================================================================
}
void CCSPlayer : : SetModelFromClass ( void )
{
if ( GetTeamNumber ( ) = = TEAM_TERRORIST )
{
int index = m_iClass - FIRST_T_CLASS ;
if ( index < 0 | | index > = TerroristPlayerModels . Count ( ) )
{
index = RandomInt ( 0 , TerroristPlayerModels . Count ( ) - 1 ) ;
m_iClass = index + FIRST_T_CLASS ; // clean up players who selected a higher class than we support yet
}
SetModel ( TerroristPlayerModels [ index ] ) ;
}
else if ( GetTeamNumber ( ) = = TEAM_CT )
{
int index = m_iClass - FIRST_CT_CLASS ;
if ( index < 0 | | index > = CTPlayerModels . Count ( ) )
{
index = RandomInt ( 0 , CTPlayerModels . Count ( ) - 1 ) ;
m_iClass = index + FIRST_CT_CLASS ; // clean up players who selected a higher class than we support yet
}
SetModel ( CTPlayerModels [ index ] ) ;
}
else
{
SetModel ( CTPlayerModels [ 0 ] ) ;
}
}
void CCSPlayer : : Spawn ( )
{
m_RateLimitLastCommandTimes . Purge ( ) ;
// Get rid of the progress bar...
SetProgressBarTime ( 0 ) ;
CreateViewModel ( 1 ) ;
// Set their player model.
SetModelFromClass ( ) ;
BaseClass : : Spawn ( ) ;
//=============================================================================
// HPE_BEGIN:
// [pfreese] Clear the last known nav area (used to be done by CBasePlayer)
//=============================================================================
m_lastNavArea = NULL ;
//=============================================================================
// HPE_END
//=============================================================================
AddFlag ( FL_ONGROUND ) ; // set the player on the ground at the start of the round.
// Override what CBasePlayer set for the view offset.
SetViewOffset ( VEC_VIEW_SCALED ( this ) ) ;
//
// Our player movement speed is set once here. This will override the cl_xxxx
// cvars unless they are set to be lower than this.
//
SetMaxSpeed ( CS_PLAYER_SPEED_RUN ) ;
SetFOV ( this , 0 ) ;
m_bIsDefusing = false ;
//=============================================================================
// HPE_BEGIN
// [dwenger] Reset hostage-related variables
//=============================================================================
m_bIsRescuing = false ;
m_bInjuredAHostage = false ;
m_iNumFollowers = 0 ;
// [tj] Reset this flag if the player is not in observer mode (as happens when a player spawns late)
if ( m_iPlayerState ! = STATE_OBSERVER_MODE )
{
m_wasNotKilledNaturally = false ;
}
//=============================================================================
// HPE_END
//=============================================================================
m_iShotsFired = 0 ;
m_iDirection = 0 ;
if ( m_pHintMessageQueue )
{
m_pHintMessageQueue - > Reset ( ) ;
}
m_iDisplayHistoryBits & = ~ DHM_ROUND_CLEAR ;
// Special-case here. A bunch of things happen in CBasePlayer::Spawn(), and we really want the
// player states to control these things, so give whatever player state we're in a chance
// to reinitialize itself.
State_Transition ( m_iPlayerState ) ;
ClearFlashbangScreenFade ( ) ;
m_flVelocityModifier = 1.0f ;
ResetStamina ( ) ;
m_flLastRadarUpdateTime = 0.0f ;
m_iNumSpawns + + ;
if ( ! engine - > IsDedicatedServer ( ) & & CSGameRules ( ) - > m_iTotalRoundsPlayed < 2 & & TheNavMesh - > IsOutOfDate ( ) & & this = = UTIL_GetListenServerHost ( ) )
{
ClientPrint ( this , HUD_PRINTCENTER , " The Navigation Mesh was built using a different version of this map. " ) ;
}
m_bTeamChanged = false ;
m_iOldTeam = TEAM_UNASSIGNED ;
m_iRadioMessages = 60 ;
m_flRadioTime = gpGlobals - > curtime ;
if ( m_hRagdoll )
{
UTIL_Remove ( m_hRagdoll ) ;
}
m_hRagdoll = NULL ;
// did we change our name while we were dead?
if ( m_szNewName [ 0 ] ! = 0 )
{
ChangeName ( m_szNewName ) ;
m_szNewName [ 0 ] = 0 ;
}
if ( m_bIsVIP )
{
HintMessage ( " #Hint_you_are_the_vip " , true , true ) ;
}
m_bIsInAutoBuy = false ;
m_bIsInRebuy = false ;
m_bAutoReload = false ;
SetContextThink ( & CCSPlayer : : PushawayThink , gpGlobals - > curtime + PUSHAWAY_THINK_INTERVAL , CS_PUSHAWAY_THINK_CONTEXT ) ;
if ( GetActiveWeapon ( ) & & ! IsObserver ( ) )
{
GetActiveWeapon ( ) - > Deploy ( ) ;
m_flNextAttack = gpGlobals - > curtime ; // Allow reloads to finish, since we're playing the deploy anim instead. This mimics goldsrc behavior, anyway.
}
2024-07-12 03:59:34 +02:00
m_applyDeafnessTime = 0.0f ;
2020-04-22 18:56:21 +02:00
StockPlayerAmmo ( ) ;
}
void CCSPlayer : : ShowViewPortPanel ( const char * name , bool bShow , KeyValues * data )
{
if ( CSGameRules ( ) - > IsLogoMap ( ) )
return ;
if ( CommandLine ( ) - > FindParm ( " -makedevshots " ) )
return ;
BaseClass : : ShowViewPortPanel ( name , bShow , data ) ;
}
void CCSPlayer : : ClearFlashbangScreenFade ( void )
{
if ( IsBlind ( ) )
{
color32 clr = { 0 , 0 , 0 , 0 } ;
UTIL_ScreenFade ( this , clr , 0.01 , 0.0 , FFADE_OUT | FFADE_PURGE ) ;
m_flFlashDuration = 0.0f ;
m_flFlashMaxAlpha = 255.0f ;
}
// clear blind time (after screen fades are canceled)
m_blindUntilTime = 0.0f ;
m_blindStartTime = 0.0f ;
}
void CCSPlayer : : GiveDefaultItems ( )
{
// Always give the player the knife.
CBaseCombatWeapon * pistol = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( pistol )
{
return ;
}
m_bUsingDefaultPistol = true ;
if ( GetTeamNumber ( ) = = TEAM_CT )
{
GiveNamedItem ( " weapon_knife " ) ;
GiveNamedItem ( " weapon_usp " ) ;
GiveAmmo ( 24 , BULLET_PLAYER_45ACP ) ;
}
else if ( GetTeamNumber ( ) = = TEAM_TERRORIST )
{
GiveNamedItem ( " weapon_knife " ) ;
GiveNamedItem ( " weapon_glock " ) ;
GiveAmmo ( 40 , BULLET_PLAYER_9MM ) ;
}
}
void CCSPlayer : : SetClanTag ( const char * pTag )
{
if ( pTag )
{
Q_strncpy ( m_szClanTag , pTag , sizeof ( m_szClanTag ) ) ;
}
}
void CCSPlayer : : CreateRagdollEntity ( )
{
// If we already have a ragdoll, don't make another one.
CCSRagdoll * pRagdoll = dynamic_cast < CCSRagdoll * > ( m_hRagdoll . Get ( ) ) ;
if ( ! pRagdoll )
{
// create a new one
pRagdoll = dynamic_cast < CCSRagdoll * > ( CreateEntityByName ( " cs_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 - > m_iDeathPose = m_iDeathPose ;
pRagdoll - > m_iDeathFrame = m_iDeathFrame ;
pRagdoll - > Init ( ) ;
}
// ragdolls will be removed on round restart automatically
m_hRagdoll = pRagdoll ;
}
int CCSPlayer : : OnTakeDamage_Alive ( const CTakeDamageInfo & info )
{
// set damage type sustained
m_bitsDamageType | = info . GetDamageType ( ) ;
if ( ! CBaseCombatCharacter : : OnTakeDamage_Alive ( info ) )
return 0 ;
// don't apply damage forces in CS
// fire global game event
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_hurt " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetInt ( " health " , MAX ( 0 , m_iHealth ) ) ;
event - > SetInt ( " armor " , MAX ( 0 , ArmorValue ( ) ) ) ;
event - > SetInt ( " dmg_health " , m_lastDamageHealth ) ;
event - > SetInt ( " dmg_armor " , m_lastDamageArmor ) ;
if ( info . GetDamageType ( ) & DMG_BLAST )
{
event - > SetInt ( " hitgroup " , HITGROUP_GENERIC ) ;
}
else
{
event - > SetInt ( " hitgroup " , m_LastHitGroup ) ;
}
CBaseEntity * attacker = info . GetAttacker ( ) ;
const char * weaponName = " " ;
if ( attacker - > IsPlayer ( ) )
{
CBasePlayer * player = ToBasePlayer ( attacker ) ;
event - > SetInt ( " attacker " , player - > GetUserID ( ) ) ; // hurt by other player
CBaseEntity * pInflictor = info . GetInflictor ( ) ;
if ( pInflictor )
{
if ( pInflictor = = player )
{
// If the inflictor is the killer, then it must be their current weapon doing the damage
if ( player - > GetActiveWeapon ( ) )
{
weaponName = player - > GetActiveWeapon ( ) - > GetClassname ( ) ;
}
}
else
{
weaponName = STRING ( pInflictor - > m_iClassname ) ; // it's just that easy
}
}
}
else
{
event - > SetInt ( " attacker " , 0 ) ; // hurt by "world"
}
if ( strncmp ( weaponName , " weapon_ " , 7 ) = = 0 )
{
weaponName + = 7 ;
}
else if ( strncmp ( weaponName , " hegrenade " , 9 ) = = 0 ) //"hegrenade_projectile"
{
//=============================================================================
// HPE_BEGIN:
// [tj] Handle grenade-surviving achievement
//=============================================================================
if ( info . GetAttacker ( ) - > GetTeamNumber ( ) ! = GetTeamNumber ( ) )
{
m_grenadeDamageTakenThisRound + = info . GetDamage ( ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
weaponName = " hegrenade " ;
}
else if ( strncmp ( weaponName , " flashbang " , 9 ) = = 0 ) //"flashbang_projectile"
{
weaponName = " flashbang " ;
}
else if ( strncmp ( weaponName , " smokegrenade " , 12 ) = = 0 ) //"smokegrenade_projectile"
{
weaponName = " smokegrenade " ;
}
event - > SetString ( " weapon " , weaponName ) ;
event - > SetInt ( " priority " , 5 ) ;
gameeventmanager - > FireEvent ( event ) ;
}
return 1 ;
}
//=============================================================================
// HPE_BEGIN:
// [dwenger] Supports fun-fact
//=============================================================================
// Returns the % of the enemies this player killed in the round
int CCSPlayer : : GetPercentageOfEnemyTeamKilled ( )
{
if ( m_NumEnemiesAtRoundStart > 0 )
{
return ( int ) ( ( ( float ) m_NumEnemiesKilledThisRound / ( float ) m_NumEnemiesAtRoundStart ) * 100.0f ) ;
}
return 0 ;
}
//=============================================================================
// HPE_END
//=============================================================================
void CCSPlayer : : Event_Killed ( const CTakeDamageInfo & info )
{
//=============================================================================
// HPE_BEGIN:
// [pfreese] Process on-death achievements
//=============================================================================
ProcessPlayerDeathAchievements ( ToCSPlayer ( info . GetAttacker ( ) ) , this , info ) ;
//=============================================================================
// HPE_END
//=============================================================================
SetArmorValue ( 0 ) ;
//=============================================================================
// HPE_BEGIN:
// [tj] Added a parameter so we know if it was death that caused the drop
// [menglish] Keep track of what the player has dropped for the freeze panel callouts
//=============================================================================
CBaseEntity * pAttacker = info . GetAttacker ( ) ;
bool friendlyFire = pAttacker & & pAttacker - > GetTeamNumber ( ) = = GetTeamNumber ( ) ;
//Only count the drop if it was not friendly fire
DropWeapons ( true , ! friendlyFire ) ;
//=============================================================================
// HPE_END
//=============================================================================
// Just in case the progress bar is on screen, kill it.
SetProgressBarTime ( 0 ) ;
m_bIsDefusing = false ;
m_bHasNightVision = false ;
m_bNightVisionOn = false ;
//=============================================================================
// HPE_BEGIN:
// [dwenger] Added for fun-fact support
//=============================================================================
m_bPickedUpDefuser = false ;
m_bDefusedWithPickedUpKit = false ;
//=============================================================================
// HPE_END
//=============================================================================
m_bHasHelmet = false ;
m_flFlashDuration = 0.0f ;
FlashlightTurnOff ( ) ;
// show killer in death cam mode
if ( IsValidObserverTarget ( info . GetAttacker ( ) ) )
{
SetObserverTarget ( info . GetAttacker ( ) ) ;
}
else
{
ResetObserverMode ( ) ;
}
//update damage info with our accumulated physics force
CTakeDamageInfo subinfo = info ;
// HACK[pfreese]: scale impulse up for visual effect
const float kImpulseBonusScale = 2.0f ;
subinfo . SetDamageForce ( m_vecTotalBulletForce * kImpulseBonusScale ) ;
//Adrian: Select a death pose to extrapolate the ragdoll's velocity.
SelectDeathPose ( info ) ;
// See if there's a ragdoll magnet that should influence our force.
CRagdollMagnet * pMagnet = CRagdollMagnet : : FindBestMagnet ( this ) ;
if ( pMagnet )
{
m_vecTotalBulletForce + = pMagnet - > GetForceVector ( this ) ;
}
// 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 ( ) ;
// Special code to drop holiday gifts for the holiday achievement
if ( ( mp_holiday_nogifts . GetBool ( ) = = false ) & & UTIL_IsHolidayActive ( 3 /*kHoliday_Christmas*/ ) )
{
if ( RandomInt ( 0 , 100 ) < 20 )
{
CHolidayGift : : Create ( WorldSpaceCenter ( ) , GetAbsAngles ( ) , EyeAngles ( ) , GetAbsVelocity ( ) , this ) ;
}
}
State_Transition ( STATE_DEATH_ANIM ) ; // Transition into the dying state.
BaseClass : : Event_Killed ( subinfo ) ;
//=============================================================================
// HPE_BEGIN:
// [pfreese] If this kill ended the round, award the MVP to someone on the
// winning team.
// TODO - move this code somewhere else more MVP related
//=============================================================================
bool roundWasAlreadyWon = ( CSGameRules ( ) - > m_iRoundWinStatus ! = WINNER_NONE ) ;
bool roundIsWonNow = CSGameRules ( ) - > CheckWinConditions ( ) ;
if ( ! roundWasAlreadyWon & & roundIsWonNow )
{
CCSPlayer * pMVP = NULL ;
int maxKills = 0 ;
int maxDamage = 0 ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = ToCSPlayer ( UTIL_PlayerByIndex ( i ) ) ;
if ( pPlayer )
{
// only consider players on the winning team
if ( pPlayer - > GetTeamNumber ( ) ! = CSGameRules ( ) - > m_iRoundWinStatus )
continue ;
int nKills = CCS_GameStats . FindPlayerStats ( pPlayer ) . statsCurrentRound [ CSSTAT_KILLS ] ;
int nDamage = CCS_GameStats . FindPlayerStats ( pPlayer ) . statsCurrentRound [ CSSTAT_DAMAGE ] ;
if ( nKills > maxKills | | ( nKills = = maxKills & & nDamage > maxDamage ) )
{
pMVP = pPlayer ;
maxKills = nKills ;
maxDamage = nDamage ;
}
}
}
if ( pMVP )
{
pMVP - > IncrementNumMVPs ( CSMVP_ELIMINATION ) ;
}
}
//=============================================================================
// HPE_END
//=============================================================================
OutputDamageGiven ( ) ;
OutputDamageTaken ( ) ;
ResetDamageCounters ( ) ;
if ( m_bPunishedForTK )
{
m_bPunishedForTK = false ;
HintMessage ( " #Hint_cannot_play_because_tk " , true , true ) ;
}
if ( ! ( m_iDisplayHistoryBits & DHF_SPEC_DUCK ) )
{
m_iDisplayHistoryBits | = DHF_SPEC_DUCK ;
HintMessage ( " #Spec_Duck " , true , true ) ;
}
}
//=============================================================================
// HPE_BEGIN:
// [menglish, tj] Update and check any one-off achievements based on the kill
//=============================================================================
// Notify that I've killed some other entity. (called from Victim's Event_Killed).
void CCSPlayer : : Event_KilledOther ( CBaseEntity * pVictim , const CTakeDamageInfo & info )
{
BaseClass : : Event_KilledOther ( pVictim , info ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
void CCSPlayer : : DeathSound ( const CTakeDamageInfo & info )
{
if ( m_LastHitGroup = = HITGROUP_HEAD )
{
EmitSound ( " Player.DeathHeadShot " ) ;
}
else
{
EmitSound ( " Player.Death " ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayer : : InitVCollision ( const Vector & vecAbsOrigin , const Vector & vecAbsVelocity )
{
BaseClass : : InitVCollision ( vecAbsOrigin , vecAbsVelocity ) ;
if ( sv_turbophysics . GetBool ( ) )
return ;
// Setup the HL2 specific callback.
GetPhysicsController ( ) - > SetEventHandler ( & playerCallback ) ;
}
void CCSPlayer : : VPhysicsShadowUpdate ( IPhysicsObject * pPhysics )
{
if ( ! CanMove ( ) )
return ;
BaseClass : : VPhysicsShadowUpdate ( pPhysics ) ;
}
bool CCSPlayer : : HasShield ( ) const
{
# ifdef CS_SHIELD_ENABLED
return m_bHasShield ;
# else
return false ;
# endif
}
bool CCSPlayer : : IsShieldDrawn ( ) const
{
# ifdef CS_SHIELD_ENABLED
return m_bShieldDrawn ;
# else
return false ;
# endif
}
void CCSPlayer : : CheatImpulseCommands ( int iImpulse )
{
switch ( iImpulse )
{
case 101 :
{
if ( sv_cheats - > GetBool ( ) )
{
extern int gEvilImpulse101 ;
gEvilImpulse101 = true ;
AddAccount ( 16000 ) ;
GiveAmmo ( 250 , BULLET_PLAYER_50AE ) ;
GiveAmmo ( 250 , BULLET_PLAYER_762MM ) ;
GiveAmmo ( 250 , BULLET_PLAYER_338MAG ) ;
GiveAmmo ( 250 , BULLET_PLAYER_556MM ) ;
GiveAmmo ( 250 , BULLET_PLAYER_556MM_BOX ) ;
GiveAmmo ( 250 , BULLET_PLAYER_9MM ) ;
GiveAmmo ( 250 , BULLET_PLAYER_BUCKSHOT ) ;
GiveAmmo ( 250 , BULLET_PLAYER_45ACP ) ;
GiveAmmo ( 250 , BULLET_PLAYER_357SIG ) ;
GiveAmmo ( 250 , BULLET_PLAYER_57MM ) ;
gEvilImpulse101 = false ;
}
}
break ;
default :
{
BaseClass : : CheatImpulseCommands ( iImpulse ) ;
}
}
}
void CCSPlayer : : SetupVisibility ( CBaseEntity * pViewEntity , unsigned char * pvs , int pvssize )
{
BaseClass : : SetupVisibility ( pViewEntity , pvs , pvssize ) ;
int area = pViewEntity ? pViewEntity - > NetworkProp ( ) - > AreaNum ( ) : NetworkProp ( ) - > AreaNum ( ) ;
PointCameraSetupVisibility ( this , area , pvs , pvssize ) ;
}
void CCSPlayer : : UpdateAddonBits ( )
{
int iNewBits = 0 ;
int nFlashbang = GetAmmoCount ( GetAmmoDef ( ) - > Index ( AMMO_TYPE_FLASHBANG ) ) ;
if ( dynamic_cast < CFlashbang * > ( GetActiveWeapon ( ) ) )
{
- - nFlashbang ;
}
if ( nFlashbang > = 1 )
iNewBits | = ADDON_FLASHBANG_1 ;
if ( nFlashbang > = 2 )
iNewBits | = ADDON_FLASHBANG_2 ;
if ( GetAmmoCount ( GetAmmoDef ( ) - > Index ( AMMO_TYPE_HEGRENADE ) ) & &
! dynamic_cast < CHEGrenade * > ( GetActiveWeapon ( ) ) )
{
iNewBits | = ADDON_HE_GRENADE ;
}
if ( GetAmmoCount ( GetAmmoDef ( ) - > Index ( AMMO_TYPE_SMOKEGRENADE ) ) & &
! dynamic_cast < CSmokeGrenade * > ( GetActiveWeapon ( ) ) )
{
iNewBits | = ADDON_SMOKE_GRENADE ;
}
if ( HasC4 ( ) & & ! dynamic_cast < CC4 * > ( GetActiveWeapon ( ) ) )
iNewBits | = ADDON_C4 ;
if ( HasDefuser ( ) )
iNewBits | = ADDON_DEFUSEKIT ;
CWeaponCSBase * weapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ) ;
if ( weapon & & weapon ! = GetActiveWeapon ( ) )
{
iNewBits | = ADDON_PRIMARY ;
m_iPrimaryAddon = weapon - > GetWeaponID ( ) ;
}
else
{
m_iPrimaryAddon = WEAPON_NONE ;
}
weapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ) ;
if ( weapon & & weapon ! = GetActiveWeapon ( ) )
{
iNewBits | = ADDON_PISTOL ;
if ( weapon - > GetWeaponID ( ) = = WEAPON_ELITE )
{
iNewBits | = ADDON_PISTOL2 ;
}
m_iSecondaryAddon = weapon - > GetWeaponID ( ) ;
}
else if ( weapon & & weapon - > GetWeaponID ( ) = = WEAPON_ELITE )
{
// The active weapon is weapon_elite. Set ADDON_PISTOL2 without ADDON_PISTOL, so we know
// to display the empty holster.
iNewBits | = ADDON_PISTOL2 ;
m_iSecondaryAddon = weapon - > GetWeaponID ( ) ;
}
else
{
m_iSecondaryAddon = WEAPON_NONE ;
}
m_iAddonBits = iNewBits ;
}
void CCSPlayer : : UpdateRadar ( )
{
// update once a second
if ( ( m_flLastRadarUpdateTime + 1.0 ) > gpGlobals - > curtime )
return ;
m_flLastRadarUpdateTime = gpGlobals - > curtime ;
// update positions of all players outside of my PVS
CBitVec < ABSOLUTE_PLAYER_LIMIT > playerbits ;
engine - > Message_DetermineMulticastRecipients ( false , EyePosition ( ) , playerbits ) ;
CSingleUserRecipientFilter user ( this ) ;
UserMessageBegin ( user , " UpdateRadar " ) ;
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
CCSPlayer * pPlayer = ToCSPlayer ( UTIL_PlayerByIndex ( i + 1 ) ) ;
if ( ! pPlayer )
continue ; // nothing there
bool bSameTeam = pPlayer - > GetTeamNumber ( ) = = GetTeamNumber ( ) ;
if ( playerbits . Get ( i ) & & bSameTeam = = true )
continue ; // this player is in my PVS and not in my team, don't update radar pos
if ( pPlayer = = this )
continue ;
if ( ! pPlayer - > IsAlive ( ) | | pPlayer - > IsObserver ( ) | | ! pPlayer - > IsConnected ( ) )
continue ; // don't update specattors or dead players
WRITE_BYTE ( i + 1 ) ; // player index as entity
WRITE_SBITLONG ( pPlayer - > GetAbsOrigin ( ) . x / 4 , COORD_INTEGER_BITS - 1 ) ;
WRITE_SBITLONG ( pPlayer - > GetAbsOrigin ( ) . y / 4 , COORD_INTEGER_BITS - 1 ) ;
WRITE_SBITLONG ( pPlayer - > GetAbsOrigin ( ) . z / 4 , COORD_INTEGER_BITS - 1 ) ;
WRITE_SBITLONG ( AngleNormalize ( pPlayer - > GetAbsAngles ( ) . y ) , 9 ) ;
}
WRITE_BYTE ( 0 ) ; // end marker
MessageEnd ( ) ;
}
void CCSPlayer : : UpdateMouseoverHints ( )
{
if ( IsBlind ( ) | | IsObserver ( ) )
return ;
Vector forward , up ;
EyeVectors ( & forward , NULL , & up ) ;
trace_t tr ;
// Search for objects in a sphere (tests for entities that are not solid, yet still useable)
Vector searchStart = EyePosition ( ) ;
Vector searchEnd = searchStart + forward * 2048 ;
int useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_VISIBLE_AND_NPCS ;
UTIL_TraceLine ( searchStart , searchEnd , useableContents , this , COLLISION_GROUP_NONE , & tr ) ;
if ( tr . fraction ! = 1.0f )
{
if ( tr . DidHitNonWorldEntity ( ) & & tr . m_pEnt )
{
CBaseEntity * pObject = tr . m_pEnt ;
switch ( pObject - > Classify ( ) )
{
case CLASS_PLAYER :
{
const float grenadeBloat = 1.2f ; // Be conservative in estimating what a player can distinguish
if ( ! TheBots - > IsLineBlockedBySmoke ( EyePosition ( ) , pObject - > EyePosition ( ) , grenadeBloat ) )
{
if ( g_pGameRules - > PlayerRelationship ( this , pObject ) = = GR_TEAMMATE )
{
if ( ! ( m_iDisplayHistoryBits & DHF_FRIEND_SEEN ) )
{
m_iDisplayHistoryBits | = DHF_FRIEND_SEEN ;
HintMessage ( " #Hint_spotted_a_friend " , true ) ;
}
}
else
{
if ( ! ( m_iDisplayHistoryBits & DHF_ENEMY_SEEN ) )
{
m_iDisplayHistoryBits | = DHF_ENEMY_SEEN ;
HintMessage ( " #Hint_spotted_an_enemy " , true ) ;
}
}
}
}
break ;
case CLASS_PLAYER_ALLY :
switch ( GetTeamNumber ( ) )
{
case TEAM_CT :
if ( ! ( m_iDisplayHistoryBits & DHF_HOSTAGE_SEEN_FAR ) & & tr . fraction > 0.1f )
{
m_iDisplayHistoryBits | = DHF_HOSTAGE_SEEN_FAR ;
HintMessage ( " #Hint_rescue_the_hostages " , true ) ;
}
else if ( ! ( m_iDisplayHistoryBits & DHF_HOSTAGE_SEEN_NEAR ) & & tr . fraction < = 0.1f )
{
m_iDisplayHistoryBits | = DHF_HOSTAGE_SEEN_FAR ;
m_iDisplayHistoryBits | = DHF_HOSTAGE_SEEN_NEAR ;
HintMessage ( " #Hint_press_use_so_hostage_will_follow " , false ) ;
}
break ;
case TEAM_TERRORIST :
if ( ! ( m_iDisplayHistoryBits & DHF_HOSTAGE_SEEN_FAR ) )
{
m_iDisplayHistoryBits | = DHF_HOSTAGE_SEEN_FAR ;
HintMessage ( " #Hint_prevent_hostage_rescue " , true ) ;
}
break ;
}
break ;
}
}
}
}
void CCSPlayer : : PostThink ( )
{
BaseClass : : PostThink ( ) ;
UpdateAddonBits ( ) ;
UpdateRadar ( ) ;
if ( ! ( m_iDisplayHistoryBits & DHF_ROUND_STARTED ) & & CanPlayerBuy ( false ) )
{
HintMessage ( " #Hint_press_buy_to_purchase " , false ) ;
m_iDisplayHistoryBits | = DHF_ROUND_STARTED ;
}
if ( m_flNextMouseoverUpdate < gpGlobals - > curtime )
{
m_flNextMouseoverUpdate = gpGlobals - > curtime + 0.2f ;
if ( m_bShowHints )
{
UpdateMouseoverHints ( ) ;
}
}
if ( GetActiveWeapon ( ) & & ! ( m_iDisplayHistoryBits & DHF_AMMO_EXHAUSTED ) )
{
CBaseCombatWeapon * pWeapon = GetActiveWeapon ( ) ;
if ( ! pWeapon - > HasAnyAmmo ( ) & & ! ( pWeapon - > GetWpnData ( ) . iFlags & ITEM_FLAG_EXHAUSTIBLE ) )
{
m_iDisplayHistoryBits | = DHF_AMMO_EXHAUSTED ;
HintMessage ( " #Hint_out_of_ammo " , false ) ;
}
}
QAngle angles = GetLocalAngles ( ) ;
angles [ PITCH ] = 0 ;
SetLocalAngles ( angles ) ;
// Store the eye angles pitch so the client can compute its animation state correctly.
m_angEyeAngles = EyeAngles ( ) ;
m_PlayerAnimState - > Update ( m_angEyeAngles [ YAW ] , m_angEyeAngles [ PITCH ] ) ;
// check if we need to apply a deafness DSP effect.
if ( ( m_applyDeafnessTime ! = 0.0f ) & & ( m_applyDeafnessTime < = gpGlobals - > curtime ) )
{
ApplyDeafnessEffect ( ) ;
}
if ( IsPlayerUnderwater ( ) & & GetWaterLevel ( ) < 3 )
{
StopSound ( " Player.AmbientUnderWater " ) ;
SetPlayerUnderwater ( false ) ;
}
}
void CCSPlayer : : PushawayThink ( )
{
// Push physics props out of our way.
PerformObstaclePushaway ( this ) ;
SetNextThink ( gpGlobals - > curtime + PUSHAWAY_THINK_INTERVAL , CS_PUSHAWAY_THINK_CONTEXT ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not we can switch to the given weapon.
// Input : pWeapon -
//-----------------------------------------------------------------------------
bool CCSPlayer : : Weapon_CanSwitchTo ( CBaseCombatWeapon * pWeapon )
{
if ( ! pWeapon - > CanDeploy ( ) )
return false ;
if ( GetActiveWeapon ( ) )
{
if ( ! GetActiveWeapon ( ) - > CanHolster ( ) )
return false ;
}
return true ;
}
bool CCSPlayer : : ShouldDoLargeFlinch ( int nHitGroup , CBaseEntity * pAttacker )
{
if ( FBitSet ( GetFlags ( ) , FL_DUCKING ) )
return FALSE ;
if ( nHitGroup = = HITGROUP_LEFTLEG )
return FALSE ;
if ( nHitGroup = = HITGROUP_RIGHTLEG )
return FALSE ;
CCSPlayer * pPlayer = ToCSPlayer ( pAttacker ) ;
if ( pPlayer = = NULL | | ! pPlayer - > IsPlayer ( ) )
pPlayer = NULL ;
if ( pPlayer )
{
CWeaponCSBase * pWeapon = pPlayer - > GetActiveCSWeapon ( ) ;
if ( pWeapon )
{
if ( pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_RIFLE | |
pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_SHOTGUN | |
pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_SNIPER_RIFLE )
return true ;
}
else
return false ;
}
return false ;
}
bool CCSPlayer : : IsArmored ( int nHitGroup )
{
bool bApplyArmor = false ;
if ( ArmorValue ( ) > 0 )
{
switch ( nHitGroup )
{
case HITGROUP_GENERIC :
case HITGROUP_CHEST :
case HITGROUP_STOMACH :
case HITGROUP_LEFTARM :
case HITGROUP_RIGHTARM :
bApplyArmor = true ;
break ;
case HITGROUP_HEAD :
if ( m_bHasHelmet )
{
bApplyArmor = true ;
}
break ;
default :
break ;
}
}
return bApplyArmor ;
}
void CCSPlayer : : Pain ( bool bHasArmour )
{
switch ( m_LastHitGroup )
{
case HITGROUP_HEAD :
if ( m_bHasHelmet ) // He's wearing a helmet
{
EmitSound ( " Player.DamageHelmet " ) ;
}
else // He's not wearing a helmet
{
EmitSound ( " Player.DamageHeadShot " ) ;
}
break ;
default :
if ( bHasArmour = = false )
{
EmitSound ( " Flesh.BulletImpact " ) ;
}
else
{
EmitSound ( " Player.DamageKevlar " ) ;
}
break ;
}
}
int CCSPlayer : : OnTakeDamage ( const CTakeDamageInfo & inputInfo )
{
CTakeDamageInfo info = inputInfo ;
CBaseEntity * pInflictor = info . GetInflictor ( ) ;
if ( ! pInflictor )
return 0 ;
if ( GetMoveType ( ) = = MOVETYPE_NOCLIP | | GetMoveType ( ) = = MOVETYPE_OBSERVER )
return 0 ;
const float flArmorBonus = 0.5f ;
float flArmorRatio = 0.5f ;
float flDamage = info . GetDamage ( ) ;
bool bFriendlyFire = CSGameRules ( ) - > IsFriendlyFireOn ( ) ;
//=============================================================================
// HPE_BEGIN:
// [tj] Added properties for goose chase achievement
//=============================================================================
CSGameRules ( ) - > PlayerTookDamage ( this , inputInfo ) ;
//Check "Goose Chase" achievement
CCSPlayer * pAttacker = ToCSPlayer ( info . GetAttacker ( ) ) ;
if ( m_bIsDefusing & & m_gooseChaseStep = = GC_NONE & & pAttacker & & pAttacker - > GetTeamNumber ( ) ! = GetTeamNumber ( ) )
{
//Count enemies
int livingEnemies = 0 ;
CTeam * pAttackerTeam = GetGlobalTeam ( pAttacker - > GetTeamNumber ( ) ) ;
for ( int iPlayer = 0 ; iPlayer < pAttackerTeam - > GetNumPlayers ( ) ; iPlayer + + )
{
CCSPlayer * pPlayer = ToCSPlayer ( pAttackerTeam - > GetPlayer ( iPlayer ) ) ;
Assert ( pPlayer ) ;
if ( ! pPlayer )
continue ;
Assert ( pPlayer - > GetTeamNumber ( ) = = pAttackerTeam - > GetTeamNumber ( ) ) ;
if ( pPlayer - > m_lifeState = = LIFE_ALIVE )
{
livingEnemies + + ;
}
}
//Must be last enemy alive;
if ( livingEnemies = = 1 )
{
m_gooseChaseStep = GC_SHOT_DURING_DEFUSE ;
m_pGooseChaseDistractingPlayer = pAttacker ;
}
}
//=============================================================================
// HPE_END
//=============================================================================
// warn about team attacks
if ( bFriendlyFire & & pInflictor - > GetTeamNumber ( ) = = GetTeamNumber ( ) & & pInflictor ! = this & & info . GetAttacker ( ) ! = this )
{
CCSPlayer * pCSAttacker = ToCSPlayer ( pInflictor ) ;
if ( ! pCSAttacker )
pCSAttacker = ToCSPlayer ( info . GetAttacker ( ) ) ;
if ( pCSAttacker )
{
if ( ! ( pCSAttacker - > m_iDisplayHistoryBits & DHF_FRIEND_INJURED ) )
{
pCSAttacker - > HintMessage ( " #Hint_try_not_to_injure_teammates " , false ) ;
pCSAttacker - > m_iDisplayHistoryBits | = DHF_FRIEND_INJURED ;
}
if ( ( pCSAttacker - > m_flLastAttackedTeammate + 0.6f ) < gpGlobals - > curtime )
{
pCSAttacker - > m_flLastAttackedTeammate = gpGlobals - > curtime ;
// tell the rest of this player's team
Msg ( " %s attacked a teammate \n " , pCSAttacker - > GetPlayerName ( ) ) ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; + + i )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( i ) ;
if ( pPlayer & & pPlayer - > GetTeamNumber ( ) = = GetTeamNumber ( ) )
{
ClientPrint ( pPlayer , HUD_PRINTTALK , " #Game_teammate_attack " , pCSAttacker - > GetPlayerName ( ) ) ;
}
}
}
}
}
if ( bFriendlyFire | |
pInflictor - > GetTeamNumber ( ) ! = GetTeamNumber ( ) | |
pInflictor = = this | |
info . GetAttacker ( ) = = this )
{
if ( bFriendlyFire & & ( info . GetDamageType ( ) & DMG_BLAST ) = = 0 )
{
if ( pInflictor - > GetTeamNumber ( ) = = GetTeamNumber ( ) )
{
flDamage * = 0.35 ; // bullets hurt teammates less
}
}
if ( ShouldDoLargeFlinch ( m_LastHitGroup , info . GetAttacker ( ) ) )
{
if ( GetAbsVelocity ( ) . Length ( ) < 300 )
{
m_flVelocityModifier = 0.65 ;
}
}
else
{
m_flVelocityModifier = 0.5 ;
}
//=============================================================================
// HPE_BEGIN:
//=============================================================================
// [menglish] Store whether or not the knife did this damage as knives do bullet damage,
// so we need to specifically check the weapon here
bool bKnifeDamage = false ;
CCSPlayer * pPlayer = ToCSPlayer ( info . GetAttacker ( ) ) ;
if ( pPlayer )
{
// [paquin. forest] if this is blast damage, and we haven't opted out with a cvar,
// we need to get the armor ratio out of the inflictor
if ( ( info . GetDamageType ( ) & DMG_BLAST ) & & ! sv_legacy_grenade_damage . GetBool ( ) )
{
// [paquin] if we know this is a grenade, use it's armor ratio, otherwise
// use the he grenade armor ratio
CBaseCSGrenadeProjectile * pGrenade = dynamic_cast < CBaseCSGrenadeProjectile * > ( pInflictor ) ;
CCSWeaponInfo * pWeaponInfo ;
if ( pGrenade & & pGrenade - > m_pWeaponInfo )
{
pWeaponInfo = pGrenade - > m_pWeaponInfo ;
}
else
{
pWeaponInfo = GetWeaponInfo ( WEAPON_HEGRENADE ) ;
}
if ( pWeaponInfo )
{
flArmorRatio * = pWeaponInfo - > m_flArmorRatio ;
}
}
else
{
CWeaponCSBase * pWeapon = pPlayer - > GetActiveCSWeapon ( ) ;
if ( pWeapon )
{
flArmorRatio * = pWeapon - > GetCSWpnData ( ) . m_flArmorRatio ;
//Knives do bullet damage, so we need to specifically check the weapon here
bKnifeDamage = pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_KNIFE ;
if ( info . GetDamageType ( ) & DMG_BULLET & & ! bKnifeDamage & & pPlayer - > GetTeam ( ) ! = GetTeam ( ) )
{
CCS_GameStats . Event_ShotHit ( pPlayer , info ) ;
}
}
}
}
//=============================================================================
// HPE_END
//=============================================================================
// keep track of amount of damage last sustained
m_lastDamageAmount = flDamage ;
// Deal with Armour
if ( ArmorValue ( ) & & ! ( info . GetDamageType ( ) & ( DMG_FALL | DMG_DROWN ) ) & & IsArmored ( m_LastHitGroup ) )
{
float fDamageToHealth = flDamage * flArmorRatio ;
float fDamageToArmor = ( flDamage - fDamageToHealth ) * flArmorBonus ;
int armorValue = ArmorValue ( ) ;
// Does this use more armor than we have?
if ( fDamageToArmor > armorValue )
{
fDamageToHealth = flDamage - armorValue / flArmorBonus ;
fDamageToArmor = armorValue ;
armorValue = 0 ;
}
else
{
if ( fDamageToArmor < 0 )
fDamageToArmor = 1 ;
armorValue - = fDamageToArmor ;
}
m_lastDamageArmor = ( int ) fDamageToArmor ;
SetArmorValue ( armorValue ) ;
//=============================================================================
// HPE_BEGIN:
// [tj] Handle headshot-surviving achievement
//=============================================================================
if ( m_LastHitGroup = = HITGROUP_HEAD & & flDamage > m_iHealth & & fDamageToHealth < m_iHealth )
{
m_bSurvivedHeadshotDueToHelmet = true ;
}
//=============================================================================
// HPE_END
//=============================================================================
flDamage = fDamageToHealth ;
info . SetDamage ( flDamage ) ;
if ( ArmorValue ( ) < = 0.0 )
m_bHasHelmet = false ;
if ( ! ( info . GetDamageType ( ) & DMG_FALL ) )
Pain ( true /*has armor*/ ) ;
}
else
{
m_lastDamageArmor = 0 ;
if ( ! ( info . GetDamageType ( ) & DMG_FALL ) )
Pain ( false /*no armor*/ ) ;
}
// round damage to integer
m_lastDamageHealth = ( int ) flDamage ;
info . SetDamage ( m_lastDamageHealth ) ;
if ( info . GetDamage ( ) < = 0 )
return 0 ;
CSingleUserRecipientFilter user ( this ) ;
user . MakeReliable ( ) ;
UserMessageBegin ( user , " Damage " ) ;
WRITE_BYTE ( ( int ) info . GetDamage ( ) ) ;
WRITE_VEC3COORD ( info . GetInflictor ( ) - > WorldSpaceCenter ( ) ) ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Send the info about where the player was hit
//=============================================================================
if ( ! ( info . GetDamageType ( ) & DMG_BULLET ) | | bKnifeDamage )
{
WRITE_LONG ( - 1 ) ;
}
else
{
WRITE_LONG ( m_LastHitBox ) ;
}
WRITE_VEC3COORD ( m_vLastHitLocationObjectSpace ) ;
//=============================================================================
// HPE_END
//=============================================================================
MessageEnd ( ) ;
// Do special explosion damage effect
if ( info . GetDamageType ( ) & DMG_BLAST )
{
OnDamagedByExplosion ( info ) ;
}
//=============================================================================
// HPE_BEGIN:
// [menglish] Achievement award for kill stealing i.e. killing an enemy who was very damaged from other players
// [Forrest] Moved this check before RecordDamageTaken so that the damage currently being dealt by this player
// won't disqualify them from getting the achievement.
//=============================================================================
if ( m_iHealth - info . GetDamage ( ) < = 0 & & m_iHealth < = AchievementConsts : : KillLowDamage_MaxHealthLeft )
{
bool onlyDamage = true ;
CCSPlayer * pAttacker = ToCSPlayer ( info . GetAttacker ( ) ) ;
if ( pAttacker & & pAttacker - > GetTeamNumber ( ) ! = GetTeamNumber ( ) )
{
//Verify that the killer has not done damage to this player beforehand
FOR_EACH_LL ( m_DamageTakenList , i )
{
if ( Q_strncmp ( pAttacker - > GetPlayerName ( ) , m_DamageTakenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 )
{
onlyDamage = false ;
break ;
}
}
if ( onlyDamage )
{
pAttacker - > AwardAchievement ( CSKillLowDamage ) ;
}
}
}
//=============================================================================
// HPE_END
//=============================================================================
# if REPORT_PLAYER_DAMAGE
// damage output spew
char dmgtype [ 64 ] ;
CTakeDamageInfo : : DebugGetDamageTypeString ( info . GetDamageType ( ) , dmgtype , sizeof ( dmgtype ) ) ;
if ( info . GetDamageType ( ) & DMG_HEADSHOT )
Q_strncat ( dmgtype , " HEADSHOT " , sizeof ( dmgtype ) ) ;
char outputString [ 256 ] ;
Q_snprintf ( outputString , sizeof ( outputString ) , " %f: Player %s incoming %f damage from %s, type %s; applied %d health and %d armor \n " ,
gpGlobals - > curtime , GetPlayerName ( ) ,
inputInfo . GetDamage ( ) , info . GetInflictor ( ) - > GetDebugName ( ) , dmgtype ,
m_lastDamageHealth , m_lastDamageArmor ) ;
Msg ( outputString ) ;
# endif
if ( pPlayer )
{
// Record for the shooter
pPlayer - > RecordDamageGiven ( GetPlayerName ( ) , info . GetDamage ( ) ) ;
// And for the victim
RecordDamageTaken ( pPlayer - > GetPlayerName ( ) , info . GetDamage ( ) ) ;
}
else
{
RecordDamageTaken ( " world " , info . GetDamage ( ) ) ;
}
m_vecTotalBulletForce + = info . GetDamageForce ( ) ;
gamestats - > Event_PlayerDamage ( this , info ) ;
return CBaseCombatCharacter : : OnTakeDamage ( info ) ;
}
else
{
return 0 ;
}
}
//MIKETODO: this probably should let the shield model catch the trace attacks.
bool CCSPlayer : : IsHittingShield ( const Vector & vecDirection , trace_t * ptr )
{
if ( HasShield ( ) = = false )
return false ;
if ( IsShieldDrawn ( ) = = false )
return false ;
float flDot ;
Vector vForward ;
Vector2D vec2LOS = vecDirection . AsVector2D ( ) ;
AngleVectors ( GetLocalAngles ( ) , & vForward ) ;
Vector2DNormalize ( vForward . AsVector2D ( ) ) ;
Vector2DNormalize ( vec2LOS ) ;
flDot = DotProduct2D ( vec2LOS , vForward . AsVector2D ( ) ) ;
if ( flDot < - 0.87f )
return true ;
return false ;
}
void CCSPlayer : : TraceAttack ( const CTakeDamageInfo & info , const Vector & vecDir , trace_t * ptr , CDmgAccumulator * pAccumulator )
{
bool bShouldBleed = true ;
bool bShouldSpark = false ;
bool bHitShield = IsHittingShield ( vecDir , ptr ) ;
CBasePlayer * pAttacker = ( CBasePlayer * ) ToBasePlayer ( info . GetAttacker ( ) ) ;
// show blood for firendly fire only if FF is on
if ( pAttacker & & ( GetTeamNumber ( ) = = pAttacker - > GetTeamNumber ( ) ) )
bShouldBleed = CSGameRules ( ) - > IsFriendlyFireOn ( ) ;
if ( m_takedamage ! = DAMAGE_YES )
return ;
m_LastHitGroup = ptr - > hitgroup ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Used when calculating the position this player was hit at in the bone space
//=============================================================================
m_LastHitBox = ptr - > hitbox ;
//=============================================================================
// HPE_END
//=============================================================================
m_nForceBone = ptr - > physicsbone ; //Save this bone for ragdoll
float flDamage = info . GetDamage ( ) ;
bool bHeadShot = false ;
if ( bHitShield )
{
flDamage = 0 ;
bShouldBleed = false ;
bShouldSpark = true ;
}
else if ( info . GetDamageType ( ) & DMG_BLAST )
{
if ( ArmorValue ( ) > 0 )
bShouldBleed = false ;
if ( bShouldBleed = = true )
{
// punch view if we have no armor
QAngle punchAngle = GetPunchAngle ( ) ;
punchAngle . x = flDamage * - 0.1 ;
if ( punchAngle . x < - 4 )
punchAngle . x = - 4 ;
SetPunchAngle ( punchAngle ) ;
}
}
else
{
//=============================================================================
// HPE_BEGIN:
// [menglish] Calculate the position this player was hit at in the bone space
//=============================================================================
matrix3x4_t boneTransformToWorld , boneTransformToObject ;
GetBoneTransform ( GetHitboxBone ( ptr - > hitbox ) , boneTransformToWorld ) ;
MatrixInvert ( boneTransformToWorld , boneTransformToObject ) ;
VectorTransform ( ptr - > endpos , boneTransformToObject , m_vLastHitLocationObjectSpace ) ;
//=============================================================================
// HPE_END
//=============================================================================
switch ( ptr - > hitgroup )
{
case HITGROUP_GENERIC :
break ;
case HITGROUP_HEAD :
if ( m_bHasHelmet )
{
// bShouldBleed = false;
bShouldSpark = true ;
}
flDamage * = 4 ;
if ( ! m_bHasHelmet )
{
QAngle punchAngle = GetPunchAngle ( ) ;
punchAngle . x = flDamage * - 0.5 ;
if ( punchAngle . x < - 12 )
punchAngle . x = - 12 ;
punchAngle . z = flDamage * random - > RandomFloat ( - 1 , 1 ) ;
if ( punchAngle . z < - 9 )
punchAngle . z = - 9 ;
else if ( punchAngle . z > 9 )
punchAngle . z = 9 ;
SetPunchAngle ( punchAngle ) ;
}
bHeadShot = true ;
break ;
case HITGROUP_CHEST :
flDamage * = 1.0 ;
if ( ArmorValue ( ) < = 0 )
{
QAngle punchAngle = GetPunchAngle ( ) ;
punchAngle . x = flDamage * - 0.1 ;
if ( punchAngle . x < - 4 )
punchAngle . x = - 4 ;
SetPunchAngle ( punchAngle ) ;
}
break ;
case HITGROUP_STOMACH :
flDamage * = 1.25 ;
if ( ArmorValue ( ) < = 0 )
{
QAngle punchAngle = GetPunchAngle ( ) ;
punchAngle . x = flDamage * - 0.1 ;
if ( punchAngle . x < - 4 )
punchAngle . x = - 4 ;
SetPunchAngle ( punchAngle ) ;
}
break ;
case HITGROUP_LEFTARM :
case HITGROUP_RIGHTARM :
flDamage * = 1.0 ;
break ;
case HITGROUP_LEFTLEG :
case HITGROUP_RIGHTLEG :
flDamage * = 0.75 ;
break ;
default :
break ;
}
}
// Since this code only runs on the server, make sure it shows the tempents it creates.
CDisablePredictionFiltering disabler ;
if ( bShouldBleed )
{
// This does smaller splotches on the guy and splats blood on the world.
TraceBleed ( flDamage , vecDir , ptr , info . GetDamageType ( ) ) ;
CEffectData data ;
data . m_vOrigin = ptr - > endpos ;
data . m_vNormal = vecDir * - 1 ;
data . m_nEntIndex = ptr - > m_pEnt ? ptr - > m_pEnt - > entindex ( ) : 0 ;
data . m_flMagnitude = flDamage ;
// reduce blood effect if target has armor
if ( ArmorValue ( ) > 0 )
data . m_flMagnitude * = 0.5f ;
// reduce blood effect if target is hit in the helmet
if ( ptr - > hitgroup = = HITGROUP_HEAD & & bShouldSpark )
data . m_flMagnitude * = 0.5 ;
DispatchEffect ( " csblood " , data ) ;
}
if ( ( ptr - > hitgroup = = HITGROUP_HEAD | | bHitShield ) & & bShouldSpark ) // they hit a helmet
{
// show metal spark effect
g_pEffects - > Sparks ( ptr - > endpos , 1 , 1 , & ptr - > plane . normal ) ;
}
if ( ! bHitShield )
{
CTakeDamageInfo subInfo = info ;
subInfo . SetDamage ( flDamage ) ;
if ( bHeadShot )
subInfo . AddDamageType ( DMG_HEADSHOT ) ;
AddMultiDamage ( subInfo , this ) ;
}
}
void CCSPlayer : : Reset ( )
{
ResetFragCount ( ) ;
ResetDeathCount ( ) ;
m_iAccount = 0 ;
AddAccount ( - 16000 , false ) ;
//remove any weapons they bought before the round started
RemoveAllItems ( true ) ;
//RemoveShield();
AddAccount ( CSGameRules ( ) - > GetStartMoney ( ) , true ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Displays a hint message to the player
// Input : *pMessage -
// bDisplayIfDead -
// bOverrideClientSettings -
//-----------------------------------------------------------------------------
void CCSPlayer : : HintMessage ( const char * pMessage , bool bDisplayIfDead , bool bOverrideClientSettings )
{
if ( ( ! bDisplayIfDead & & ! IsAlive ( ) ) | | ! IsNetClient ( ) | | ! m_pHintMessageQueue )
return ;
if ( bOverrideClientSettings | | m_bShowHints )
m_pHintMessageQueue - > AddMessage ( pMessage ) ;
}
void CCSPlayer : : AddAccount ( int amount , bool bTrackChange , bool bItemBought , const char * pItemName )
{
m_iAccount + = amount ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Description of reason for change
//=============================================================================
if ( amount > 0 )
{
CCS_GameStats . Event_MoneyEarned ( this , amount ) ;
}
else if ( amount < 0 & & bItemBought )
{
CCS_GameStats . Event_MoneySpent ( this , ABS ( amount ) , pItemName ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
if ( m_iAccount < 0 )
m_iAccount = 0 ;
else if ( m_iAccount > 16000 )
m_iAccount = 16000 ;
}
void CCSPlayer : : MarkAsNotReceivingMoneyNextRound ( )
{
m_receivesMoneyNextRound = false ;
}
bool CCSPlayer : : DoesPlayerGetRoundStartMoney ( )
{
return m_receivesMoneyNextRound ;
}
CCSPlayer * CCSPlayer : : Instance ( int iEnt )
{
return dynamic_cast < CCSPlayer * > ( CBaseEntity : : Instance ( INDEXENT ( iEnt ) ) ) ;
}
void CCSPlayer : : DropC4 ( )
{
}
bool CCSPlayer : : HasDefuser ( )
{
return m_bHasDefuser ;
}
void CCSPlayer : : RemoveDefuser ( )
{
m_bHasDefuser = false ;
}
void CCSPlayer : : GiveDefuser ( bool bPickedUp /* = false */ )
{
if ( ! m_bHasDefuser )
{
IGameEvent * event = gameeventmanager - > CreateEvent ( " item_pickup " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " item " , " defuser " ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
m_bHasDefuser = true ;
//=============================================================================
// HPE_BEGIN:
// [dwenger] Added for fun-fact support
//=============================================================================
m_bPickedUpDefuser = bPickedUp ;
//=============================================================================
// HPE_END
//=============================================================================
}
// player blinded by a flashbang
void CCSPlayer : : Blind ( float holdTime , float fadeTime , float startingAlpha )
{
// Don't flash a spectator.
color32 clr = { 255 , 255 , 255 , 255 } ;
clr . a = startingAlpha ;
// estimate when we can see again
float oldBlindUntilTime = m_blindUntilTime ;
float oldBlindStartTime = m_blindStartTime ;
m_blindUntilTime = MAX ( m_blindUntilTime , gpGlobals - > curtime + holdTime + 0.5f * fadeTime ) ;
m_blindStartTime = gpGlobals - > curtime ;
// Spectators get a lessened flash.
if ( ( GetObserverMode ( ) ! = OBS_MODE_NONE ) & & ( GetObserverMode ( ) ! = OBS_MODE_IN_EYE ) )
{
if ( ! mp_fadetoblack . GetBool ( ) )
{
clr . a = 150 ;
fadeTime = MIN ( fadeTime , 0.5f ) ; // make sure the spectator flashbang time is 1/2 second or less.
holdTime = MIN ( holdTime , fadeTime * 0.5f ) ; // adjust the hold time to match the fade time.
UTIL_ScreenFade ( this , clr , fadeTime , holdTime , FFADE_IN ) ;
}
}
else
{
fadeTime / = 1.4 ;
if ( gpGlobals - > curtime > oldBlindUntilTime )
{
// The previous flashbang is wearing off, or completely gone
m_flFlashDuration = fadeTime ;
m_flFlashMaxAlpha = startingAlpha ;
}
else
{
// The previous flashbang is still going strong - only extend the duration
float remainingDuration = oldBlindStartTime + m_flFlashDuration - gpGlobals - > curtime ;
m_flFlashDuration = MAX ( remainingDuration , fadeTime ) ;
m_flFlashMaxAlpha = MAX ( m_flFlashMaxAlpha , startingAlpha ) ;
}
// allow bots to react
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_blind " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
}
void CCSPlayer : : Deafen ( float flDistance )
{
// Spectators don't get deafened
if ( ( GetObserverMode ( ) = = OBS_MODE_NONE ) | | ( GetObserverMode ( ) = = OBS_MODE_IN_EYE ) )
{
// dsp presets are defined in hl2/scripts/dsp_presets.txt
int effect ;
if ( flDistance < 600 )
{
effect = 134 ;
}
else if ( flDistance < 800 )
{
effect = 135 ;
}
else if ( flDistance < 1000 )
{
effect = 136 ;
}
else
{
// too far for us to get an effect
return ;
}
CSingleUserRecipientFilter user ( this ) ;
enginesound - > SetPlayerDSP ( user , effect , false ) ;
//TODO: bots can't hear sound for a while?
}
}
void CCSPlayer : : GiveShield ( void )
{
# ifdef CS_SHIELD_ENABLED
m_bHasShield = true ;
m_bShieldDrawn = false ;
if ( HasSecondaryWeapon ( ) )
{
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
pWeapon - > SetModel ( pWeapon - > GetViewModel ( ) ) ;
pWeapon - > Deploy ( ) ;
}
CBaseViewModel * pVM = GetViewModel ( 1 ) ;
if ( pVM )
{
ShowViewModel ( true ) ;
pVM - > RemoveEffects ( EF_NODRAW ) ;
pVM - > SetWeaponModel ( SHIELD_VIEW_MODEL , GetActiveWeapon ( ) ) ;
pVM - > SendViewModelMatchingSequence ( 1 ) ;
}
# endif
}
void CCSPlayer : : RemoveShield ( void )
{
# ifdef CS_SHIELD_ENABLED
m_bHasShield = false ;
CBaseViewModel * pVM = GetViewModel ( 1 ) ;
if ( pVM )
{
pVM - > AddEffects ( EF_NODRAW ) ;
}
# endif
}
void CCSPlayer : : RemoveAllItems ( bool removeSuit )
{
if ( HasDefuser ( ) )
{
RemoveDefuser ( ) ;
}
if ( HasShield ( ) )
{
RemoveShield ( ) ;
}
m_bHasNightVision = false ;
m_bNightVisionOn = false ;
//=============================================================================
// HPE_BEGIN:
// [dwenger] Added for fun-fact support
//=============================================================================
m_bPickedUpDefuser = false ;
m_bDefusedWithPickedUpKit = false ;
//=============================================================================
// HPE_END
//=============================================================================
if ( removeSuit )
{
m_bHasHelmet = false ;
SetArmorValue ( 0 ) ;
}
BaseClass : : RemoveAllItems ( removeSuit ) ;
}
void CCSPlayer : : ObserverRoundRespawn ( )
{
ClearFlashbangScreenFade ( ) ;
// did we change our name last round?
if ( m_szNewName [ 0 ] ! = 0 )
{
// ... and force the name change now. After this happens, the gamerules will get
// a ClientSettingsChanged callback from the above ClientCommand, but the name
// matches what we're setting here, so it will do nothing.
ChangeName ( m_szNewName ) ;
m_szNewName [ 0 ] = 0 ;
}
}
void CCSPlayer : : RoundRespawn ( )
{
//MIKETODO: menus
//if ( m_iMenu != Menu_ChooseAppearance )
{
// Put them back into the game.
StopObserverMode ( ) ;
State_Transition ( STATE_ACTIVE ) ;
respawn ( this , false ) ;
m_nButtons = 0 ;
SetNextThink ( TICK_NEVER_THINK ) ;
}
m_receivesMoneyNextRound = true ; // reset this variable so they can receive their cash next round.
//If they didn't die, this will print out their damage info
OutputDamageGiven ( ) ;
OutputDamageTaken ( ) ;
ResetDamageCounters ( ) ;
}
void CCSPlayer : : CheckTKPunishment ( void )
{
// teamkill punishment..
if ( ( m_bJustKilledTeammate = = true ) & & mp_tkpunish . GetInt ( ) )
{
m_bJustKilledTeammate = false ;
m_bPunishedForTK = true ;
CommitSuicide ( ) ;
}
}
CWeaponCSBase * CCSPlayer : : GetActiveCSWeapon ( ) const
{
return dynamic_cast < CWeaponCSBase * > ( GetActiveWeapon ( ) ) ;
}
void CCSPlayer : : PreThink ( )
{
BaseClass : : PreThink ( ) ;
if ( m_bAutoReload )
{
m_bAutoReload = false ;
m_nButtons | = IN_RELOAD ;
}
if ( m_afButtonLast ! = m_nButtons )
m_flLastMovement = gpGlobals - > curtime ;
if ( g_fGameOver )
return ;
State_PreThink ( ) ;
if ( m_pHintMessageQueue )
m_pHintMessageQueue - > Update ( ) ;
//Reset bullet force accumulator, only lasts one frame
m_vecTotalBulletForce = vec3_origin ;
if ( mp_autokick . GetBool ( ) & & ! IsBot ( ) & & ! IsHLTV ( ) & & ! IsAutoKickDisabled ( ) )
{
if ( m_flLastMovement + CSGameRules ( ) - > GetRoundLength ( ) * 2 < gpGlobals - > curtime )
{
UTIL_ClientPrintAll ( HUD_PRINTCONSOLE , " #Game_idle_kick " , GetPlayerName ( ) ) ;
engine - > ServerCommand ( UTIL_VarArgs ( " kickid %d \n " , GetUserID ( ) ) ) ;
m_flLastMovement = gpGlobals - > curtime ;
}
}
# ifndef _XBOX
// CS would like their players to continue to update their LastArea since it is displayed in the hud voice chat UI
// But we won't do the population tracking while dead.
CNavArea * area = TheNavMesh - > GetNavArea ( GetAbsOrigin ( ) , 1000 ) ;
if ( area & & area ! = m_lastNavArea )
{
m_lastNavArea = area ;
if ( area - > GetPlace ( ) ! = UNDEFINED_PLACE )
{
const char * placeName = TheNavMesh - > PlaceToName ( area - > GetPlace ( ) ) ;
if ( placeName & & * placeName )
{
Q_strncpy ( m_szLastPlaceName . GetForModify ( ) , placeName , MAX_PLACE_NAME_LENGTH ) ;
}
}
}
# endif
}
void CCSPlayer : : MoveToNextIntroCamera ( )
{
m_pIntroCamera = gEntList . FindEntityByClassname ( m_pIntroCamera , " point_viewcontrol " ) ;
// if m_pIntroCamera is NULL we just were at end of list, start searching from start again
if ( ! m_pIntroCamera )
m_pIntroCamera = gEntList . FindEntityByClassname ( m_pIntroCamera , " point_viewcontrol " ) ;
// find the target
CBaseEntity * Target = NULL ;
if ( m_pIntroCamera )
{
Target = gEntList . FindEntityByName ( NULL , STRING ( m_pIntroCamera - > m_target ) ) ;
}
// if we still couldn't find a camera, goto T spawn
if ( ! m_pIntroCamera )
m_pIntroCamera = gEntList . FindEntityByClassname ( m_pIntroCamera , " info_player_terrorist " ) ;
SetViewOffset ( vec3_origin ) ; // no view offset
UTIL_SetSize ( this , vec3_origin , vec3_origin ) ; // no bbox
if ( ! Target ) //if there are no cameras(or the camera has no target, find a spawn point and black out the screen
{
if ( m_pIntroCamera . IsValid ( ) )
SetAbsOrigin ( m_pIntroCamera - > GetAbsOrigin ( ) + VEC_VIEW ) ;
SetAbsAngles ( QAngle ( 0 , 0 , 0 ) ) ;
m_pIntroCamera = NULL ; // never update again
return ;
}
Vector vCamera = Target - > GetAbsOrigin ( ) - m_pIntroCamera - > GetAbsOrigin ( ) ;
Vector vIntroCamera = m_pIntroCamera - > GetAbsOrigin ( ) ;
VectorNormalize ( vCamera ) ;
QAngle CamAngles ;
VectorAngles ( vCamera , CamAngles ) ;
SetAbsOrigin ( vIntroCamera ) ;
SetAbsAngles ( CamAngles ) ;
SnapEyeAngles ( CamAngles ) ;
m_fIntroCamTime = gpGlobals - > curtime + 6 ;
}
class NotVIP
{
public :
bool operator ( ) ( CBasePlayer * player )
{
CCSPlayer * csPlayer = static_cast < CCSPlayer * > ( player ) ;
csPlayer - > MakeVIP ( false ) ;
return true ;
}
} ;
// Expose the VIP selection to plugins, since we don't have an official VIP mode. This
// allows plugins to access the (limited) VIP functionality already present (scoreboard
// identification and radar color).
CON_COMMAND ( cs_make_vip , " Marks a player as the VIP " )
{
if ( ! UTIL_IsCommandIssuedByServerAdmin ( ) )
return ;
if ( args . ArgC ( ) ! = 2 )
{
return ;
}
CCSPlayer * player = static_cast < CCSPlayer * > ( UTIL_PlayerByIndex ( atoi ( args [ 1 ] ) ) ) ;
if ( ! player )
{
// Invalid value clears out VIP
NotVIP notVIP ;
ForEachPlayer ( notVIP ) ;
return ;
}
player - > MakeVIP ( true ) ;
}
void CCSPlayer : : MakeVIP ( bool isVIP )
{
if ( isVIP )
{
NotVIP notVIP ;
ForEachPlayer ( notVIP ) ;
}
m_isVIP = isVIP ;
}
bool CCSPlayer : : IsVIP ( ) const
{
return m_isVIP ;
}
void CCSPlayer : : DropShield ( void )
{
# ifdef CS_SHIELD_ENABLED
//Drop an item_defuser
Vector vForward , vRight ;
AngleVectors ( GetAbsAngles ( ) , & vForward , & vRight , NULL ) ;
RemoveShield ( ) ;
CBaseAnimating * pShield = ( CBaseAnimating * ) CBaseEntity : : Create ( " item_shield " , WorldSpaceCenter ( ) , GetLocalAngles ( ) ) ;
pShield - > ApplyAbsVelocityImpulse ( vForward * 200 + vRight * random - > RandomFloat ( - 50 , 50 ) ) ;
CBaseCombatWeapon * pActive = GetActiveWeapon ( ) ;
if ( pActive )
{
pActive - > Deploy ( ) ;
}
# endif
}
void CCSPlayer : : SetShieldDrawnState ( bool bState )
{
# ifdef CS_SHIELD_ENABLED
m_bShieldDrawn = bState ;
# endif
}
bool CCSPlayer : : CSWeaponDrop ( CBaseCombatWeapon * pWeapon , bool bDropShield , bool bThrowForward )
{
bool bSuccess = false ;
if ( HasShield ( ) & & bDropShield = = true )
{
DropShield ( ) ;
return true ;
}
if ( pWeapon )
{
Vector vForward ;
AngleVectors ( EyeAngles ( ) , & vForward , NULL , NULL ) ;
//GetVectors( &vForward, NULL, NULL );
Vector vTossPos = WorldSpaceCenter ( ) ;
if ( bThrowForward )
vTossPos = vTossPos + vForward * 64 ;
Weapon_Drop ( pWeapon , & vTossPos , NULL ) ;
pWeapon - > SetSolidFlags ( FSOLID_NOT_STANDABLE | FSOLID_TRIGGER | FSOLID_USE_TRIGGER_BOUNDS ) ;
pWeapon - > SetMoveCollide ( MOVECOLLIDE_FLY_BOUNCE ) ;
CWeaponCSBase * pCSWeapon = dynamic_cast < CWeaponCSBase * > ( pWeapon ) ;
if ( pCSWeapon )
{
pCSWeapon - > SetWeaponModelIndex ( pCSWeapon - > GetCSWpnData ( ) . szWorldModel ) ;
//Find out the index of the ammo type
int iAmmoIndex = pCSWeapon - > GetPrimaryAmmoType ( ) ;
//If it has an ammo type, find out how much the player has
if ( iAmmoIndex ! = - 1 )
{
// Check to make sure we don't have other weapons using this ammo type
bool bAmmoTypeInUse = false ;
if ( IsAlive ( ) & & GetHealth ( ) > 0 )
{
for ( int i = 0 ; i < MAX_WEAPONS ; + + i )
{
CBaseCombatWeapon * pOtherWeapon = GetWeapon ( i ) ;
if ( pOtherWeapon & & pOtherWeapon ! = pWeapon & & pOtherWeapon - > GetPrimaryAmmoType ( ) = = iAmmoIndex )
{
bAmmoTypeInUse = true ;
break ;
}
}
}
if ( ! bAmmoTypeInUse )
{
int iAmmoToDrop = GetAmmoCount ( iAmmoIndex ) ;
//Add this much to the dropped weapon
pCSWeapon - > SetExtraAmmoCount ( iAmmoToDrop ) ;
//Remove all ammo of this type from the player
SetAmmoCount ( 0 , iAmmoIndex ) ;
}
}
}
//=========================================
// Teleport the weapon to the player's hand
//=========================================
int iBIndex = - 1 ;
int iWeaponBoneIndex = - 1 ;
MDLCACHE_CRITICAL_SECTION ( ) ;
CStudioHdr * hdr = pWeapon - > GetModelPtr ( ) ;
// If I have a hand, set the weapon position to my hand bone position.
if ( hdr & & hdr - > numbones ( ) > 0 )
{
// Assume bone zero is the root
for ( iWeaponBoneIndex = 0 ; iWeaponBoneIndex < hdr - > numbones ( ) ; + + iWeaponBoneIndex )
{
iBIndex = LookupBone ( hdr - > pBone ( iWeaponBoneIndex ) - > pszName ( ) ) ;
// Found one!
if ( iBIndex ! = - 1 )
{
break ;
}
}
if ( iWeaponBoneIndex = = hdr - > numbones ( ) )
return true ;
if ( iBIndex = = - 1 )
{
iBIndex = LookupBone ( " ValveBiped.Bip01_R_Hand " ) ;
}
}
else
{
iBIndex = LookupBone ( " ValveBiped.Bip01_R_Hand " ) ;
}
if ( iBIndex ! = - 1 )
{
Vector origin ;
QAngle angles ;
matrix3x4_t transform ;
// Get the transform for the weapon bonetoworldspace in the NPC
GetBoneTransform ( iBIndex , transform ) ;
// find offset of root bone from origin in local space
// Make sure we're detached from hierarchy before doing this!!!
pWeapon - > StopFollowingEntity ( ) ;
pWeapon - > SetAbsOrigin ( Vector ( 0 , 0 , 0 ) ) ;
pWeapon - > SetAbsAngles ( QAngle ( 0 , 0 , 0 ) ) ;
pWeapon - > InvalidateBoneCache ( ) ;
matrix3x4_t rootLocal ;
pWeapon - > GetBoneTransform ( iWeaponBoneIndex , rootLocal ) ;
// invert it
matrix3x4_t rootInvLocal ;
MatrixInvert ( rootLocal , rootInvLocal ) ;
matrix3x4_t weaponMatrix ;
ConcatTransforms ( transform , rootInvLocal , weaponMatrix ) ;
MatrixAngles ( weaponMatrix , angles , origin ) ;
pWeapon - > Teleport ( & origin , & angles , NULL ) ;
//Have to teleport the physics object as well
IPhysicsObject * pWeaponPhys = pWeapon - > VPhysicsGetObject ( ) ;
if ( pWeaponPhys )
{
Vector vPos ;
QAngle vAngles ;
pWeaponPhys - > GetPosition ( & vPos , & vAngles ) ;
pWeaponPhys - > SetPosition ( vPos , angles , true ) ;
AngularImpulse angImp ( 0 , 0 , 0 ) ;
Vector vecAdd = GetAbsVelocity ( ) ;
pWeaponPhys - > AddVelocity ( & vecAdd , & angImp ) ;
}
}
bSuccess = true ;
}
return bSuccess ;
}
bool CCSPlayer : : DropRifle ( bool fromDeath )
{
bool bSuccess = false ;
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
if ( pWeapon )
{
bSuccess = CSWeaponDrop ( pWeapon , false ) ;
}
//=============================================================================
// HPE_BEGIN:
// [menglish] Add the dropped weapon to the dropped equipment list
//=============================================================================
if ( fromDeath & & bSuccess )
{
m_hDroppedEquipment [ DROPPED_WEAPON ] = static_cast < CBaseEntity * > ( pWeapon ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
return bSuccess ;
}
bool CCSPlayer : : DropPistol ( bool fromDeath )
{
bool bSuccess = false ;
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( pWeapon )
{
bSuccess = CSWeaponDrop ( pWeapon , false ) ;
m_bUsingDefaultPistol = false ;
}
//=============================================================================
// HPE_BEGIN:
// [menglish] Add the dropped weapon to the dropped equipment list
//=============================================================================
if ( fromDeath & & bSuccess )
{
m_hDroppedEquipment [ DROPPED_WEAPON ] = static_cast < CBaseEntity * > ( pWeapon ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
return bSuccess ;
}
bool CCSPlayer : : HasPrimaryWeapon ( void )
{
bool bSuccess = false ;
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
if ( pWeapon )
{
bSuccess = true ;
}
return bSuccess ;
}
bool CCSPlayer : : HasSecondaryWeapon ( void )
{
bool bSuccess = false ;
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( pWeapon )
{
bSuccess = true ;
}
return bSuccess ;
}
bool CCSPlayer : : IsInBuyZone ( )
{
return m_bInBuyZone & & ! IsVIP ( ) ;
}
bool CCSPlayer : : CanPlayerBuy ( bool display )
{
// is the player in a buy zone?
if ( ! IsInBuyZone ( ) )
{
return false ;
}
CCSGameRules * mp = CSGameRules ( ) ;
// is the player alive?
if ( m_lifeState ! = LIFE_ALIVE )
{
return false ;
}
int buyTime = ( int ) ( mp_buytime . GetFloat ( ) * 60 ) ;
if ( mp - > IsBuyTimeElapsed ( ) )
{
if ( display = = true )
{
char strBuyTime [ 16 ] ;
Q_snprintf ( strBuyTime , sizeof ( strBuyTime ) , " %d " , buyTime ) ;
ClientPrint ( this , HUD_PRINTCENTER , " #Cant_buy " , strBuyTime ) ;
}
return false ;
}
if ( m_bIsVIP )
{
if ( display = = true )
ClientPrint ( this , HUD_PRINTCENTER , " #VIP_cant_buy " ) ;
return false ;
}
if ( mp - > m_bCTCantBuy & & ( GetTeamNumber ( ) = = TEAM_CT ) )
{
if ( display = = true )
ClientPrint ( this , HUD_PRINTCENTER , " #CT_cant_buy " ) ;
return false ;
}
if ( mp - > m_bTCantBuy & & ( GetTeamNumber ( ) = = TEAM_TERRORIST ) )
{
if ( display = = true )
ClientPrint ( this , HUD_PRINTCENTER , " #Terrorist_cant_buy " ) ;
return false ;
}
return true ;
}
BuyResult_e CCSPlayer : : AttemptToBuyVest ( void )
{
int iKevlarPrice = KEVLAR_PRICE ;
if ( CSGameRules ( ) - > IsBlackMarket ( ) )
{
iKevlarPrice = CSGameRules ( ) - > GetBlackMarketPriceForWeapon ( WEAPON_KEVLAR ) ;
}
if ( ArmorValue ( ) > = 100 )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_Kevlar " ) ;
return BUY_ALREADY_HAVE ;
}
else if ( m_iAccount < iKevlarPrice )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
return BUY_CANT_AFFORD ;
}
else
{
if ( m_bHasHelmet )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_Helmet_Bought_Kevlar " ) ;
}
IGameEvent * event = gameeventmanager - > CreateEvent ( " item_pickup " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " item " , " vest " ) ;
gameeventmanager - > FireEvent ( event ) ;
}
GiveNamedItem ( " item_kevlar " ) ;
AddAccount ( - iKevlarPrice , true , true , " item_kevlar " ) ;
BlackMarketAddWeapon ( " item_kevlar " , this ) ;
return BUY_BOUGHT ;
}
}
BuyResult_e CCSPlayer : : AttemptToBuyAssaultSuit ( void )
{
// WARNING: This price logic also exists in C_CSPlayer::GetCurrentAssaultSuitPrice
// and must be kept in sync if changes are made.
int fullArmor = ArmorValue ( ) > = 100 ? 1 : 0 ;
int price = 0 , enoughMoney = 0 ;
int iHelmetPrice = HELMET_PRICE ;
int iKevlarPrice = KEVLAR_PRICE ;
int iAssaultSuitPrice = ASSAULTSUIT_PRICE ;
if ( CSGameRules ( ) - > IsBlackMarket ( ) )
{
iKevlarPrice = CSGameRules ( ) - > GetBlackMarketPriceForWeapon ( WEAPON_KEVLAR ) ;
iAssaultSuitPrice = CSGameRules ( ) - > GetBlackMarketPriceForWeapon ( WEAPON_ASSAULTSUIT ) ;
iHelmetPrice = iAssaultSuitPrice - iKevlarPrice ;
}
if ( fullArmor & & m_bHasHelmet )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_Kevlar_Helmet " ) ;
return BUY_ALREADY_HAVE ;
}
else if ( fullArmor & & ! m_bHasHelmet & & m_iAccount > = iHelmetPrice )
{
enoughMoney = 1 ;
price = iHelmetPrice ;
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_Kevlar_Bought_Helmet " ) ;
}
else if ( ! fullArmor & & m_bHasHelmet & & m_iAccount > = iKevlarPrice )
{
enoughMoney = 1 ;
price = iKevlarPrice ;
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_Helmet_Bought_Kevlar " ) ;
}
else if ( m_iAccount > = iAssaultSuitPrice )
{
enoughMoney = 1 ;
price = iAssaultSuitPrice ;
}
// process the result
if ( ! enoughMoney )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
return BUY_CANT_AFFORD ;
}
else
{
IGameEvent * event = gameeventmanager - > CreateEvent ( " item_pickup " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " item " , " vesthelm " ) ;
gameeventmanager - > FireEvent ( event ) ;
}
GiveNamedItem ( " item_assaultsuit " ) ;
AddAccount ( - price , true , true , " item_assaultsuit " ) ;
BlackMarketAddWeapon ( " item_assaultsuit " , this ) ;
return BUY_BOUGHT ;
}
}
BuyResult_e CCSPlayer : : AttemptToBuyShield ( void )
{
# ifdef CS_SHIELD_ENABLED
if ( HasShield ( ) ) // prevent this guy from buying more than 1 Defuse Kit
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_One " ) ;
return BUY_ALREADY_HAVE ;
}
else if ( m_iAccount < SHIELD_PRICE )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
return BUY_CANT_AFFORD ;
}
else
{
if ( HasSecondaryWeapon ( ) )
{
CBaseCombatWeapon * pWeapon = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
CWeaponCSBase * pCSWeapon = dynamic_cast < CWeaponCSBase * > ( pWeapon ) ;
if ( pCSWeapon & & pCSWeapon - > GetCSWpnData ( ) . m_bCanUseWithShield = = false )
return ;
}
if ( HasPrimaryWeapon ( ) )
DropRifle ( ) ;
GiveShield ( ) ;
CPASAttenuationFilter filter ( this , " Player.PickupWeapon " ) ;
EmitSound ( filter , entindex ( ) , " Player.PickupWeapon " ) ;
m_bAnythingBought = true ;
AddAccount ( - SHIELD_PRICE , true , true , " item_shield " ) ;
return BUY_BOUGHT ;
}
# else
ClientPrint ( this , HUD_PRINTCENTER , " Tactical shield disabled " ) ;
return BUY_NOT_ALLOWED ;
# endif
}
BuyResult_e CCSPlayer : : AttemptToBuyDefuser ( void )
{
CCSGameRules * MPRules = CSGameRules ( ) ;
if ( ( GetTeamNumber ( ) = = TEAM_CT ) & & MPRules - > IsBombDefuseMap ( ) )
{
if ( HasDefuser ( ) ) // prevent this guy from buying more than 1 Defuse Kit
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_One " ) ;
return BUY_ALREADY_HAVE ;
}
else if ( m_iAccount < DEFUSEKIT_PRICE )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
return BUY_CANT_AFFORD ;
}
else
{
GiveDefuser ( ) ;
CPASAttenuationFilter filter ( this , " Player.PickupWeapon " ) ;
EmitSound ( filter , entindex ( ) , " Player.PickupWeapon " ) ;
AddAccount ( - DEFUSEKIT_PRICE , true , true , " item_defuser " ) ;
return BUY_BOUGHT ;
}
}
return BUY_NOT_ALLOWED ;
}
BuyResult_e CCSPlayer : : AttemptToBuyNightVision ( void )
{
int iNVGPrice = NVG_PRICE ;
if ( CSGameRules ( ) - > IsBlackMarket ( ) )
{
iNVGPrice = CSGameRules ( ) - > GetBlackMarketPriceForWeapon ( WEAPON_NVG ) ;
}
if ( m_bHasNightVision = = TRUE )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Already_Have_One " ) ;
return BUY_ALREADY_HAVE ;
}
else if ( m_iAccount < iNVGPrice )
{
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
return BUY_CANT_AFFORD ;
}
else
{
IGameEvent * event = gameeventmanager - > CreateEvent ( " item_pickup " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " item " , " nvgs " ) ;
gameeventmanager - > FireEvent ( event ) ;
}
GiveNamedItem ( " item_nvgs " ) ;
AddAccount ( - iNVGPrice , true , true ) ;
BlackMarketAddWeapon ( " nightvision " , this ) ;
if ( ! ( m_iDisplayHistoryBits & DHF_NIGHTVISION ) )
{
HintMessage ( " #Hint_use_nightvision " , false ) ;
m_iDisplayHistoryBits | = DHF_NIGHTVISION ;
}
return BUY_BOUGHT ;
}
}
// Handles the special "buy" alias commands we're creating to accommodate the buy
// scripts players use (now that we've rearranged the buy menus and broken the scripts)
//=============================================================================
// HPE_BEGIN:
//[tj] This is essentially a shim so I can easily check the return
// value without adding new code to all the return points.
//=============================================================================
BuyResult_e CCSPlayer : : HandleCommand_Buy ( const char * item )
{
BuyResult_e result = HandleCommand_Buy_Internal ( item ) ;
if ( result = = BUY_BOUGHT )
{
m_bMadePurchseThisRound = true ;
CCS_GameStats . IncrementStat ( this , CSSTAT_ITEMS_PURCHASED , 1 ) ;
}
return result ;
}
BuyResult_e CCSPlayer : : HandleCommand_Buy_Internal ( const char * wpnName )
//=============================================================================
// HPE_END
//=============================================================================
{
BuyResult_e result = CanPlayerBuy ( false ) ? BUY_PLAYER_CANT_BUY : BUY_INVALID_ITEM ; // set some defaults
// translate the new weapon names to the old ones that are actually being used.
wpnName = GetTranslatedWeaponAlias ( wpnName ) ;
CCSWeaponInfo * pWeaponInfo = GetWeaponInfo ( AliasToWeaponID ( wpnName ) ) ;
if ( pWeaponInfo = = NULL )
{
if ( Q_stricmp ( wpnName , " primammo " ) = = 0 )
{
result = AttemptToBuyAmmo ( 0 ) ;
}
else if ( Q_stricmp ( wpnName , " secammo " ) = = 0 )
{
result = AttemptToBuyAmmo ( 1 ) ;
}
else if ( Q_stristr ( wpnName , " defuser " ) )
{
if ( CanPlayerBuy ( true ) )
{
result = AttemptToBuyDefuser ( ) ;
}
}
}
else
{
if ( ! CanPlayerBuy ( true ) )
{
return BUY_PLAYER_CANT_BUY ;
}
BuyResult_e equipResult = BUY_INVALID_ITEM ;
if ( Q_stristr ( wpnName , " kevlar " ) )
{
equipResult = AttemptToBuyVest ( ) ;
}
else if ( Q_stristr ( wpnName , " assaultsuit " ) )
{
equipResult = AttemptToBuyAssaultSuit ( ) ;
}
else if ( Q_stristr ( wpnName , " shield " ) )
{
equipResult = AttemptToBuyShield ( ) ;
}
else if ( Q_stristr ( wpnName , " nightvision " ) )
{
equipResult = AttemptToBuyNightVision ( ) ;
}
if ( equipResult ! = BUY_INVALID_ITEM )
{
if ( equipResult = = BUY_BOUGHT )
{
BuildRebuyStruct ( ) ;
}
return equipResult ; // intentional early return here
}
bool bPurchase = false ;
// MIKETODO: assasination maps have a specific set of weapons that can be used in them.
if ( pWeaponInfo - > m_iTeam ! = TEAM_UNASSIGNED & & GetTeamNumber ( ) ! = pWeaponInfo - > m_iTeam )
{
result = BUY_NOT_ALLOWED ;
if ( pWeaponInfo - > m_WrongTeamMsg [ 0 ] ! = 0 )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Alias_Not_Avail " , pWeaponInfo - > m_WrongTeamMsg ) ;
}
}
else if ( pWeaponInfo - > GetWeaponPrice ( ) < = 0 )
{
// ClientPrint( this, HUD_PRINTCENTER, "#Cant_buy_this_item", pWeaponInfo->m_WrongTeamMsg );
}
else if ( pWeaponInfo - > m_WeaponType = = WEAPONTYPE_GRENADE )
{
// make sure the player can afford this item.
if ( m_iAccount > = pWeaponInfo - > GetWeaponPrice ( ) )
{
bPurchase = true ;
const char * szWeaponName = NULL ;
int ammoMax = 0 ;
if ( Q_strstr ( pWeaponInfo - > szClassName , " flashbang " ) )
{
szWeaponName = " weapon_flashbang " ;
ammoMax = ammo_flashbang_max . GetInt ( ) ;
}
else if ( Q_strstr ( pWeaponInfo - > szClassName , " hegrenade " ) )
{
szWeaponName = " weapon_hegrenade " ;
ammoMax = ammo_hegrenade_max . GetInt ( ) ;
}
else if ( Q_strstr ( pWeaponInfo - > szClassName , " smokegrenade " ) )
{
szWeaponName = " weapon_smokegrenade " ;
ammoMax = ammo_smokegrenade_max . GetInt ( ) ;
}
if ( szWeaponName ! = NULL )
{
CBaseCombatWeapon * pGrenadeWeapon = Weapon_OwnsThisType ( szWeaponName ) ;
{
if ( pGrenadeWeapon ! = NULL )
{
int nAmmoType = pGrenadeWeapon - > GetPrimaryAmmoType ( ) ;
if ( nAmmoType ! = - 1 )
{
if ( GetAmmoCount ( nAmmoType ) > = ammoMax )
{
result = BUY_ALREADY_HAVE ;
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Cannot_Carry_Anymore " ) ;
bPurchase = false ;
}
}
}
}
}
}
}
else if ( ! Weapon_OwnsThisType ( pWeaponInfo - > szClassName ) ) //don't buy duplicate weapons
{
// do they have enough money?
if ( m_iAccount > = pWeaponInfo - > GetWeaponPrice ( ) )
{
if ( m_lifeState ! = LIFE_DEAD )
{
if ( pWeaponInfo - > iSlot = = WEAPON_SLOT_PISTOL )
{
DropPistol ( ) ;
}
else if ( pWeaponInfo - > iSlot = = WEAPON_SLOT_RIFLE )
{
DropRifle ( ) ;
}
}
bPurchase = true ;
}
else
{
result = BUY_CANT_AFFORD ;
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
}
}
else
{
result = BUY_ALREADY_HAVE ;
}
if ( HasShield ( ) )
{
if ( pWeaponInfo - > m_bCanUseWithShield = = false )
{
result = BUY_NOT_ALLOWED ;
bPurchase = false ;
}
}
if ( bPurchase )
{
result = BUY_BOUGHT ;
if ( bPurchase & & pWeaponInfo - > iSlot = = WEAPON_SLOT_PISTOL )
m_bUsingDefaultPistol = false ;
GiveNamedItem ( pWeaponInfo - > szClassName ) ;
AddAccount ( - pWeaponInfo - > GetWeaponPrice ( ) , true , true , pWeaponInfo - > szClassName ) ;
BlackMarketAddWeapon ( wpnName , this ) ;
}
}
if ( result = = BUY_BOUGHT )
{
BuildRebuyStruct ( ) ;
}
return result ;
}
BuyResult_e CCSPlayer : : BuyGunAmmo ( CBaseCombatWeapon * pWeapon , bool bBlinkMoney )
{
if ( ! CanPlayerBuy ( false ) )
{
return BUY_PLAYER_CANT_BUY ;
}
// Ensure that the weapon uses ammo
int nAmmo = pWeapon - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
// Can only buy if the player does not already have full ammo
if ( GetAmmoCount ( nAmmo ) > = GetAmmoDef ( ) - > MaxCarry ( nAmmo ) )
{
return BUY_ALREADY_HAVE ;
}
// Purchase the ammo if the player has enough money
if ( m_iAccount > = GetCSAmmoDef ( ) - > GetCost ( nAmmo ) )
{
GiveAmmo ( GetCSAmmoDef ( ) - > GetBuySize ( nAmmo ) , nAmmo , true ) ;
AddAccount ( - GetCSAmmoDef ( ) - > GetCost ( nAmmo ) , true , true , GetCSAmmoDef ( ) - > GetAmmoOfIndex ( nAmmo ) - > pName ) ;
return BUY_BOUGHT ;
}
if ( bBlinkMoney )
{
// Not enough money.. let the player know
if ( ! m_bIsInAutoBuy & & ! m_bIsInRebuy )
ClientPrint ( this , HUD_PRINTCENTER , " #Not_Enough_Money " ) ;
}
return BUY_CANT_AFFORD ;
}
BuyResult_e CCSPlayer : : BuyAmmo ( int nSlot , bool bBlinkMoney )
{
if ( ! CanPlayerBuy ( false ) )
{
return BUY_PLAYER_CANT_BUY ;
}
if ( nSlot < 0 | | nSlot > 1 )
{
return BUY_INVALID_ITEM ;
}
// Buy one ammo clip for all weapons in the given slot
//
// nSlot == 1 : Primary weapons
// nSlot == 2 : Secondary weapons
CBaseCombatWeapon * pSlot = Weapon_GetSlot ( nSlot ) ;
if ( ! pSlot )
return BUY_INVALID_ITEM ;
//MIKETODO: shield.
//if ( player->HasShield() && player->m_rgpPlayerItems[2] )
// pItem = player->m_rgpPlayerItems[2];
return BuyGunAmmo ( pSlot , bBlinkMoney ) ;
}
BuyResult_e CCSPlayer : : AttemptToBuyAmmo ( int iAmmoType )
{
Assert ( iAmmoType = = 0 | | iAmmoType = = 1 ) ;
BuyResult_e result = BuyAmmo ( iAmmoType , true ) ;
if ( result = = BUY_BOUGHT )
{
while ( BuyAmmo ( iAmmoType , false ) = = BUY_BOUGHT )
{
// empty loop - keep buying
}
return BUY_BOUGHT ;
}
return result ;
}
BuyResult_e CCSPlayer : : AttemptToBuyAmmoSingle ( int iAmmoType )
{
Assert ( iAmmoType = = 0 | | iAmmoType = = 1 ) ;
BuyResult_e result = BuyAmmo ( iAmmoType , true ) ;
if ( result = = BUY_BOUGHT )
{
BuildRebuyStruct ( ) ;
}
return result ;
}
const char * RadioEventName [ RADIO_NUM_EVENTS + 1 ] =
{
" RADIO_INVALID " ,
" EVENT_START_RADIO_1 " ,
" EVENT_RADIO_COVER_ME " ,
" EVENT_RADIO_YOU_TAKE_THE_POINT " ,
" EVENT_RADIO_HOLD_THIS_POSITION " ,
" EVENT_RADIO_REGROUP_TEAM " ,
" EVENT_RADIO_FOLLOW_ME " ,
" EVENT_RADIO_TAKING_FIRE " ,
" EVENT_START_RADIO_2 " ,
" EVENT_RADIO_GO_GO_GO " ,
" EVENT_RADIO_TEAM_FALL_BACK " ,
" EVENT_RADIO_STICK_TOGETHER_TEAM " ,
" EVENT_RADIO_GET_IN_POSITION_AND_WAIT " ,
" EVENT_RADIO_STORM_THE_FRONT " ,
" EVENT_RADIO_REPORT_IN_TEAM " ,
" EVENT_START_RADIO_3 " ,
" EVENT_RADIO_AFFIRMATIVE " ,
" EVENT_RADIO_ENEMY_SPOTTED " ,
" EVENT_RADIO_NEED_BACKUP " ,
" EVENT_RADIO_SECTOR_CLEAR " ,
" EVENT_RADIO_IN_POSITION " ,
" EVENT_RADIO_REPORTING_IN " ,
" EVENT_RADIO_GET_OUT_OF_THERE " ,
" EVENT_RADIO_NEGATIVE " ,
" EVENT_RADIO_ENEMY_DOWN " ,
" EVENT_RADIO_END " ,
NULL // must be NULL-terminated
} ;
/**
* Convert name to RadioType
*/
RadioType NameToRadioEvent ( const char * name )
{
for ( int i = 0 ; RadioEventName [ i ] ; + + i )
if ( ! stricmp ( RadioEventName [ i ] , name ) )
return static_cast < RadioType > ( i ) ;
return RADIO_INVALID ;
}
void CCSPlayer : : HandleMenu_Radio1 ( int slot )
{
if ( m_iRadioMessages < 0 )
return ;
if ( m_flRadioTime > gpGlobals - > curtime )
return ;
m_iRadioMessages - - ;
m_flRadioTime = gpGlobals - > curtime + 1.5 ;
switch ( slot )
{
case 1 :
Radio ( " Radio.CoverMe " , " #Cstrike_TitlesTXT_Cover_me " ) ;
break ;
case 2 :
Radio ( " Radio.YouTakeThePoint " , " #Cstrike_TitlesTXT_You_take_the_point " ) ;
break ;
case 3 :
Radio ( " Radio.HoldPosition " , " #Cstrike_TitlesTXT_Hold_this_position " ) ;
break ;
case 4 :
Radio ( " Radio.Regroup " , " #Cstrike_TitlesTXT_Regroup_team " ) ;
break ;
case 5 :
Radio ( " Radio.FollowMe " , " #Cstrike_TitlesTXT_Follow_me " ) ;
break ;
case 6 :
Radio ( " Radio.TakingFire " , " #Cstrike_TitlesTXT_Taking_fire " ) ;
break ;
}
// tell bots about radio message
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_radio " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetInt ( " slot " , RADIO_START_1 + slot ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
void CCSPlayer : : HandleMenu_Radio2 ( int slot )
{
if ( m_iRadioMessages < 0 )
return ;
if ( m_flRadioTime > gpGlobals - > curtime )
return ;
m_iRadioMessages - - ;
m_flRadioTime = gpGlobals - > curtime + 1.5 ;
switch ( slot )
{
case 1 :
Radio ( " Radio.GoGoGo " , " #Cstrike_TitlesTXT_Go_go_go " ) ;
break ;
case 2 :
Radio ( " Radio.TeamFallBack " , " #Cstrike_TitlesTXT_Team_fall_back " ) ;
break ;
case 3 :
Radio ( " Radio.StickTogether " , " #Cstrike_TitlesTXT_Stick_together_team " ) ;
break ;
case 4 :
Radio ( " Radio.GetInPosition " , " #Cstrike_TitlesTXT_Get_in_position_and_wait " ) ;
break ;
case 5 :
Radio ( " Radio.StormFront " , " #Cstrike_TitlesTXT_Storm_the_front " ) ;
break ;
case 6 :
Radio ( " Radio.ReportInTeam " , " #Cstrike_TitlesTXT_Report_in_team " ) ;
break ;
}
// tell bots about radio message
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_radio " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetInt ( " slot " , RADIO_START_2 + slot ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
void CCSPlayer : : HandleMenu_Radio3 ( int slot )
{
if ( m_iRadioMessages < 0 )
return ;
if ( m_flRadioTime > gpGlobals - > curtime )
return ;
m_iRadioMessages - - ;
m_flRadioTime = gpGlobals - > curtime + 1.5 ;
switch ( slot )
{
case 1 :
if ( random - > RandomInt ( 0 , 1 ) )
Radio ( " Radio.Affirmitive " , " #Cstrike_TitlesTXT_Affirmative " ) ;
else
Radio ( " Radio.Roger " , " #Cstrike_TitlesTXT_Roger_that " ) ;
break ;
case 2 :
Radio ( " Radio.EnemySpotted " , " #Cstrike_TitlesTXT_Enemy_spotted " ) ;
break ;
case 3 :
Radio ( " Radio.NeedBackup " , " #Cstrike_TitlesTXT_Need_backup " ) ;
break ;
case 4 :
Radio ( " Radio.SectorClear " , " #Cstrike_TitlesTXT_Sector_clear " ) ;
break ;
case 5 :
Radio ( " Radio.InPosition " , " #Cstrike_TitlesTXT_In_position " ) ;
break ;
case 6 :
Radio ( " Radio.ReportingIn " , " #Cstrike_TitlesTXT_Reporting_in " ) ;
break ;
case 7 :
Radio ( " Radio.GetOutOfThere " , " #Cstrike_TitlesTXT_Get_out_of_there " ) ;
break ;
case 8 :
Radio ( " Radio.Negative " , " #Cstrike_TitlesTXT_Negative " ) ;
break ;
case 9 :
Radio ( " Radio.EnemyDown " , " #Cstrike_TitlesTXT_Enemy_down " ) ;
break ;
}
// tell bots about radio message
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_radio " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetInt ( " slot " , RADIO_START_3 + slot ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
void UTIL_CSRadioMessage ( IRecipientFilter & filter , int iClient , int msg_dest , const char * msg_name , const char * param1 = NULL , const char * param2 = NULL , const char * param3 = NULL , const char * param4 = NULL )
{
UserMessageBegin ( filter , " RadioText " ) ;
WRITE_BYTE ( msg_dest ) ;
WRITE_BYTE ( iClient ) ;
WRITE_STRING ( msg_name ) ;
if ( param1 )
WRITE_STRING ( param1 ) ;
else
WRITE_STRING ( " " ) ;
if ( param2 )
WRITE_STRING ( param2 ) ;
else
WRITE_STRING ( " " ) ;
if ( param3 )
WRITE_STRING ( param3 ) ;
else
WRITE_STRING ( " " ) ;
if ( param4 )
WRITE_STRING ( param4 ) ;
else
WRITE_STRING ( " " ) ;
MessageEnd ( ) ;
}
void CCSPlayer : : ConstructRadioFilter ( CRecipientFilter & filter )
{
filter . MakeReliable ( ) ;
int localTeam = GetTeamNumber ( ) ;
int i ;
for ( i = 1 ; i < = gpGlobals - > maxClients ; + + i )
{
CCSPlayer * player = static_cast < CCSPlayer * > ( UTIL_PlayerByIndex ( i ) ) ;
if ( ! player )
continue ;
// Skip players ignoring the radio
if ( player - > m_bIgnoreRadio )
continue ;
if ( player - > GetTeamNumber ( ) = = TEAM_SPECTATOR )
{
// add spectators
if ( player - > m_iObserverMode = = OBS_MODE_IN_EYE | | player - > m_iObserverMode = = OBS_MODE_CHASE )
{
filter . AddRecipient ( player ) ;
}
}
else if ( player - > GetTeamNumber ( ) = = localTeam )
{
// add teammates
filter . AddRecipient ( player ) ;
}
}
}
void CCSPlayer : : Radio ( const char * pszRadioSound , const char * pszRadioText )
{
if ( ! IsAlive ( ) )
return ;
if ( IsObserver ( ) )
return ;
CRecipientFilter filter ;
ConstructRadioFilter ( filter ) ;
if ( pszRadioText )
{
const char * pszLocationText = CSGameRules ( ) - > GetChatLocation ( true , this ) ;
if ( pszLocationText & & * pszLocationText )
{
UTIL_CSRadioMessage ( filter , entindex ( ) , HUD_PRINTTALK , " #Game_radio_location " , GetPlayerName ( ) , pszLocationText , pszRadioText ) ;
}
else
{
UTIL_CSRadioMessage ( filter , entindex ( ) , HUD_PRINTTALK , " #Game_radio " , GetPlayerName ( ) , pszRadioText ) ;
}
}
UserMessageBegin ( filter , " SendAudio " ) ;
WRITE_STRING ( pszRadioSound ) ;
MessageEnd ( ) ;
//icon over the head for teammates
TE_RadioIcon ( filter , 0.0 , this ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Outputs currently connected players to the console
//-----------------------------------------------------------------------------
void CCSPlayer : : ListPlayers ( )
{
char buf [ 64 ] ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = dynamic_cast < CCSPlayer * > ( UTIL_PlayerByIndex ( i ) ) ;
if ( pPlayer & & ! pPlayer - > IsDormant ( ) )
{
if ( pPlayer - > IsBot ( ) )
{
Q_snprintf ( buf , sizeof ( buf ) , " B %d : %s " , pPlayer - > GetUserID ( ) , pPlayer - > GetPlayerName ( ) ) ;
}
else
{
Q_snprintf ( buf , sizeof ( buf ) , " %d : %s " , pPlayer - > GetUserID ( ) , pPlayer - > GetPlayerName ( ) ) ;
}
ClientPrint ( this , HUD_PRINTCONSOLE , buf ) ;
}
}
ClientPrint ( this , HUD_PRINTCONSOLE , " \n " ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &info -
//-----------------------------------------------------------------------------
void CCSPlayer : : OnDamagedByExplosion ( const CTakeDamageInfo & info )
{
float lastDamage = info . GetDamage ( ) ;
//Adrian - This is hacky since we might have been damaged by something else
//but since the round is ending, who cares.
if ( CSGameRules ( ) - > m_bTargetBombed = = true )
return ;
float distanceFromPlayer = 9999.0f ;
CBaseEntity * inflictor = info . GetInflictor ( ) ;
if ( inflictor )
{
Vector delta = GetAbsOrigin ( ) - inflictor - > GetAbsOrigin ( ) ;
distanceFromPlayer = delta . Length ( ) ;
}
bool shock = lastDamage > = 30.0f ;
if ( ! shock )
return ;
m_applyDeafnessTime = gpGlobals - > curtime + 0.3 ;
m_currentDeafnessFilter = 0 ;
}
void CCSPlayer : : ApplyDeafnessEffect ( )
{
// what's happening here is that the low-pass filter and the oscillator frequency effects need
// to fade in and out slowly. So we have several filters that we switch between to achieve this
// effect. The first 3rd of the total effect will be the "fade in" of the effect. Which means going
// from filter to filter from the first to the last. Then we keep on the "last" filter for another
// third of the total effect time. Then the last third of the time we go back from the last filter
// to the first. Clear as mud?
// glossary:
// filter: an individual filter as defined in dsp_presets.txt
// section: one of the sections for the total effect, fade in, full, fade out are the possible sections
// effect: the total effect of combining all the sections, the whole of what the player hears from start to finish.
const int firstGrenadeFilterIndex = 137 ;
const int lastGrenadeFilterIndex = 139 ;
const float grenadeEffectLengthInSecs = 4.5f ; // time of the total effect
const float fadeInSectionTime = 0.1f ;
const float fadeOutSectionTime = 1.5f ;
const float timeForEachFilterInFadeIn = fadeInSectionTime / ( lastGrenadeFilterIndex - firstGrenadeFilterIndex ) ;
const float timeForEachFilterInFadeOut = fadeOutSectionTime / ( lastGrenadeFilterIndex - firstGrenadeFilterIndex ) ;
float timeIntoEffect = gpGlobals - > curtime - m_applyDeafnessTime ;
if ( timeIntoEffect > = grenadeEffectLengthInSecs )
{
// the effect is done, so reset the deafness variables.
m_applyDeafnessTime = 0.0f ;
m_currentDeafnessFilter = 0 ;
return ;
}
int section = 0 ;
if ( timeIntoEffect < fadeInSectionTime )
{
section = 0 ;
}
else if ( timeIntoEffect < ( grenadeEffectLengthInSecs - fadeOutSectionTime ) )
{
section = 1 ;
}
else
{
section = 2 ;
}
int filterToUse = 0 ;
if ( section = = 0 )
{
// fade into the effect.
int filterIndex = ( int ) ( timeIntoEffect / timeForEachFilterInFadeIn ) ;
filterToUse = filterIndex + = firstGrenadeFilterIndex ;
}
else if ( section = = 1 )
{
// in full effect.
filterToUse = lastGrenadeFilterIndex ;
}
else if ( section = = 2 )
{
// fade out of the effect
float timeIntoSection = timeIntoEffect - ( grenadeEffectLengthInSecs - fadeOutSectionTime ) ;
int filterIndex = ( int ) ( timeIntoSection / timeForEachFilterInFadeOut ) ;
filterToUse = lastGrenadeFilterIndex - filterIndex - 1 ;
}
if ( filterToUse ! = m_currentDeafnessFilter )
{
m_currentDeafnessFilter = filterToUse ;
CSingleUserRecipientFilter user ( this ) ;
enginesound - > SetPlayerDSP ( user , m_currentDeafnessFilter , false ) ;
}
}
void CCSPlayer : : NoteWeaponFired ( )
{
Assert ( m_pCurrentCommand ) ;
if ( m_pCurrentCommand )
{
m_iLastWeaponFireUsercmd = m_pCurrentCommand - > command_number ;
}
}
2024-01-25 13:27:03 +01:00
bool CCSPlayer : : WantsLagCompensationOnEntity ( const CBasePlayer * pPlayer , const CUserCmd * pCmd , const CBitVec < MAX_EDICTS > * pEntityTransmitBits )
2020-04-22 18:56:21 +02:00
{
2024-01-25 13:27:03 +01:00
// No need to check for IN_ATTACK etc since it is called in firebullet
2020-04-22 18:56:21 +02:00
return BaseClass : : WantsLagCompensationOnEntity ( pPlayer , pCmd , pEntityTransmitBits ) ;
}
// Handles the special "radio" alias commands we're creating to accommodate the scripts players use
// ** Returns true if we've handled the command **
bool HandleRadioAliasCommands ( CCSPlayer * pPlayer , const char * pszCommand )
{
bool bRetVal = false ;
// don't execute them if we are not alive or are an observer
if ( ! pPlayer - > IsAlive ( ) | | pPlayer - > IsObserver ( ) )
return false ;
// Radio1 commands
if ( FStrEq ( pszCommand , " coverme " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 1 ) ;
}
else if ( FStrEq ( pszCommand , " takepoint " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 2 ) ;
}
else if ( FStrEq ( pszCommand , " holdpos " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 3 ) ;
}
else if ( FStrEq ( pszCommand , " regroup " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 4 ) ;
}
else if ( FStrEq ( pszCommand , " followme " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 5 ) ;
}
else if ( FStrEq ( pszCommand , " takingfire " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio1 ( 6 ) ;
}
// Radio2 commands
else if ( FStrEq ( pszCommand , " go " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 1 ) ;
}
else if ( FStrEq ( pszCommand , " fallback " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 2 ) ;
}
else if ( FStrEq ( pszCommand , " sticktog " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 3 ) ;
}
else if ( FStrEq ( pszCommand , " getinpos " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 4 ) ;
}
else if ( FStrEq ( pszCommand , " stormfront " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 5 ) ;
}
else if ( FStrEq ( pszCommand , " report " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio2 ( 6 ) ;
}
// Radio3 commands
else if ( FStrEq ( pszCommand , " roger " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 1 ) ;
}
else if ( FStrEq ( pszCommand , " enemyspot " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 2 ) ;
}
else if ( FStrEq ( pszCommand , " needbackup " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 3 ) ;
}
else if ( FStrEq ( pszCommand , " sectorclear " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 4 ) ;
}
else if ( FStrEq ( pszCommand , " inposition " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 5 ) ;
}
else if ( FStrEq ( pszCommand , " reportingin " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 6 ) ;
}
else if ( FStrEq ( pszCommand , " getout " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 7 ) ;
}
else if ( FStrEq ( pszCommand , " negative " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 8 ) ;
}
else if ( FStrEq ( pszCommand , " enemydown " ) )
{
bRetVal = true ;
pPlayer - > HandleMenu_Radio3 ( 9 ) ;
}
return bRetVal ;
}
bool CCSPlayer : : ShouldRunRateLimitedCommand ( const CCommand & args )
{
const char * pcmd = args [ 0 ] ;
int i = m_RateLimitLastCommandTimes . Find ( pcmd ) ;
if ( i = = m_RateLimitLastCommandTimes . InvalidIndex ( ) )
{
m_RateLimitLastCommandTimes . Insert ( pcmd , gpGlobals - > curtime ) ;
return true ;
}
else if ( ( gpGlobals - > curtime - m_RateLimitLastCommandTimes [ i ] ) < CS_COMMAND_MAX_RATE )
{
// Too fast.
return false ;
}
else
{
m_RateLimitLastCommandTimes [ i ] = gpGlobals - > curtime ;
return true ;
}
}
bool CCSPlayer : : ClientCommand ( const CCommand & args )
{
const char * pcmd = args [ 0 ] ;
// Bots mimic our client commands.
/*
if ( bot_mimic . GetInt ( ) & & ! ( GetFlags ( ) & FL_FAKECLIENT ) )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = dynamic_cast < CCSPlayer * > ( UTIL_PlayerByIndex ( i ) ) ;
if ( pPlayer & & pPlayer ! = this & & ( pPlayer - > GetFlags ( ) & FL_FAKECLIENT ) )
{
pPlayer - > ClientCommand ( pcmd ) ;
}
}
}
*/
# if defined ( DEBUG )
if ( FStrEq ( pcmd , " bot_cmd " ) )
{
CCSPlayer * pPlayer = dynamic_cast < CCSPlayer * > ( UTIL_PlayerByIndex ( atoi ( args [ 1 ] ) ) ) ;
if ( pPlayer & & pPlayer ! = this & & ( pPlayer - > GetFlags ( ) & FL_FAKECLIENT ) )
{
CCommand botArgs ( args . ArgC ( ) - 2 , & args . ArgV ( ) [ 2 ] ) ;
pPlayer - > ClientCommand ( botArgs ) ;
pPlayer - > RemoveEffects ( EF_NODRAW ) ;
}
return true ;
}
if ( FStrEq ( pcmd , " blind " ) )
{
if ( ShouldRunRateLimitedCommand ( args ) )
{
if ( args . ArgC ( ) = = 3 )
{
Blind ( atof ( args [ 1 ] ) , atof ( args [ 2 ] ) ) ;
}
else
{
ClientPrint ( this , HUD_PRINTCONSOLE , " usage: blind holdtime fadetime \n " ) ;
}
}
return true ;
}
if ( FStrEq ( pcmd , " deafen " ) )
{
Deafen ( 0.0f ) ;
return true ;
}
if ( FStrEq ( pcmd , " he_deafen " ) )
{
m_applyDeafnessTime = gpGlobals - > curtime + 0.3 ;
m_currentDeafnessFilter = 0 ;
return true ;
}
if ( FStrEq ( pcmd , " hint_reset " ) )
{
m_iDisplayHistoryBits = 0 ;
return true ;
}
if ( FStrEq ( pcmd , " punch " ) )
{
float flDamage = 100 ;
QAngle punchAngle = GetPunchAngle ( ) ;
punchAngle . x = flDamage * random - > RandomFloat ( - 0.15 , 0.15 ) ;
punchAngle . y = flDamage * random - > RandomFloat ( - 0.15 , 0.15 ) ;
punchAngle . z = flDamage * random - > RandomFloat ( - 0.15 , 0.15 ) ;
clamp ( punchAngle . x , - 4 , punchAngle . x ) ;
clamp ( punchAngle . y , - 5 , 5 ) ;
clamp ( punchAngle . z , - 5 , 5 ) ;
// +y == down
// +x == left
// +z == roll clockwise
if ( args . ArgC ( ) = = 4 )
{
punchAngle . x = atof ( args [ 1 ] ) ;
punchAngle . y = atof ( args [ 2 ] ) ;
punchAngle . z = atof ( args [ 3 ] ) ;
}
SetPunchAngle ( punchAngle ) ;
return true ;
}
# endif //DEBUG
if ( FStrEq ( pcmd , " 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 ( pcmd , " spectate " ) )
{
if ( ShouldRunRateLimitedCommand ( args ) )
{
// instantly join spectators
HandleCommand_JoinTeam ( TEAM_SPECTATOR ) ;
}
return true ;
}
else if ( FStrEq ( pcmd , " joingame " ) )
{
// player just closed MOTD dialog
if ( m_iPlayerState = = STATE_WELCOME )
{
State_Transition ( STATE_PICKINGTEAM ) ;
}
return true ;
}
else if ( FStrEq ( pcmd , " joinclass " ) )
{
if ( args . ArgC ( ) < 2 )
{
Warning ( " Player sent bad joinclass syntax \n " ) ;
}
if ( ShouldRunRateLimitedCommand ( args ) )
{
int iClass = atoi ( args [ 1 ] ) ;
HandleCommand_JoinClass ( iClass ) ;
}
return true ;
}
else if ( FStrEq ( pcmd , " drop " ) )
{
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( GetActiveWeapon ( ) ) ;
if ( pWeapon )
{
//=============================================================================
// HPE_BEGIN:
// [dwenger] Determine value of dropped item.
//=============================================================================
if ( ! pWeapon - > IsAPriorOwner ( this ) )
{
pWeapon - > AddToPriorOwnerList ( this ) ;
CCS_GameStats . IncrementStat ( this , CSTAT_ITEMS_DROPPED_VALUE , pWeapon - > GetCSWpnData ( ) . GetWeaponPrice ( ) ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
CSWeaponType type = pWeapon - > GetCSWpnData ( ) . m_WeaponType ;
if ( type ! = WEAPONTYPE_KNIFE & & type ! = WEAPONTYPE_GRENADE )
{
if ( CSGameRules ( ) - > GetCanDonateWeapon ( ) & & ! pWeapon - > GetDonated ( ) )
{
pWeapon - > SetDonated ( true ) ;
pWeapon - > SetDonor ( this ) ;
}
CSWeaponDrop ( pWeapon , true , true ) ;
}
}
return true ;
}
else if ( FStrEq ( pcmd , " buy " ) )
{
BuyResult_e result = BUY_INVALID_ITEM ;
if ( args . ArgC ( ) = = 2 )
{
result = HandleCommand_Buy ( args [ 1 ] ) ;
}
if ( result = = BUY_INVALID_ITEM )
{
// Print out a message on the console
int msg_dest = HUD_PRINTCONSOLE ;
ClientPrint ( this , msg_dest , " usage: buy <item> \n " ) ;
ClientPrint ( this , msg_dest , " primammo \n " ) ;
ClientPrint ( this , msg_dest , " secammo \n " ) ;
ClientPrint ( this , msg_dest , " vest \n " ) ;
ClientPrint ( this , msg_dest , " vesthelm \n " ) ;
ClientPrint ( this , msg_dest , " defuser \n " ) ;
//ClientPrint( this, msg_dest, " shield\n" );
ClientPrint ( this , msg_dest , " nvgs \n " ) ;
ClientPrint ( this , msg_dest , " flashbang \n " ) ;
ClientPrint ( this , msg_dest , " hegrenade \n " ) ;
ClientPrint ( this , msg_dest , " smokegrenade \n " ) ;
ClientPrint ( this , msg_dest , " galil \n " ) ;
ClientPrint ( this , msg_dest , " ak47 \n " ) ;
ClientPrint ( this , msg_dest , " scout \n " ) ;
ClientPrint ( this , msg_dest , " sg552 \n " ) ;
ClientPrint ( this , msg_dest , " awp \n " ) ;
ClientPrint ( this , msg_dest , " g3sg1 \n " ) ;
ClientPrint ( this , msg_dest , " famas \n " ) ;
ClientPrint ( this , msg_dest , " m4a1 \n " ) ;
ClientPrint ( this , msg_dest , " aug \n " ) ;
ClientPrint ( this , msg_dest , " sg550 \n " ) ;
ClientPrint ( this , msg_dest , " glock \n " ) ;
ClientPrint ( this , msg_dest , " usp \n " ) ;
ClientPrint ( this , msg_dest , " p228 \n " ) ;
ClientPrint ( this , msg_dest , " deagle \n " ) ;
ClientPrint ( this , msg_dest , " elite \n " ) ;
ClientPrint ( this , msg_dest , " fiveseven \n " ) ;
ClientPrint ( this , msg_dest , " m3 \n " ) ;
ClientPrint ( this , msg_dest , " xm1014 \n " ) ;
ClientPrint ( this , msg_dest , " mac10 \n " ) ;
ClientPrint ( this , msg_dest , " tmp \n " ) ;
ClientPrint ( this , msg_dest , " mp5navy \n " ) ;
ClientPrint ( this , msg_dest , " ump45 \n " ) ;
ClientPrint ( this , msg_dest , " p90 \n " ) ;
ClientPrint ( this , msg_dest , " m249 \n " ) ;
}
return true ;
}
else if ( FStrEq ( pcmd , " buyammo1 " ) )
{
AttemptToBuyAmmoSingle ( 0 ) ;
return true ;
}
else if ( FStrEq ( pcmd , " buyammo2 " ) )
{
AttemptToBuyAmmoSingle ( 1 ) ;
return true ;
}
else if ( FStrEq ( pcmd , " nightvision " ) )
{
if ( ShouldRunRateLimitedCommand ( args ) )
{
if ( m_bHasNightVision )
{
if ( m_bNightVisionOn )
{
CPASAttenuationFilter filter ( this ) ;
EmitSound ( filter , entindex ( ) , " Player.NightVisionOff " ) ;
}
else
{
CPASAttenuationFilter filter ( this ) ;
EmitSound ( filter , entindex ( ) , " Player.NightVisionOn " ) ;
}
m_bNightVisionOn = ! m_bNightVisionOn ;
}
}
return true ;
}
else if ( FStrEq ( pcmd , " menuselect " ) )
{
return true ;
}
else if ( HandleRadioAliasCommands ( this , pcmd ) )
{
return true ;
}
else if ( FStrEq ( pcmd , " listplayers " ) )
{
ListPlayers ( ) ;
return true ;
}
else if ( FStrEq ( pcmd , " ignorerad " ) )
{
m_bIgnoreRadio = ! m_bIgnoreRadio ;
if ( m_bIgnoreRadio )
{
ClientPrint ( this , HUD_PRINTTALK , " #Ignore_Radio " ) ;
}
else
{
ClientPrint ( this , HUD_PRINTTALK , " #Accept_Radio " ) ;
}
return true ;
}
else if ( FStrEq ( pcmd , " become_vip " ) )
{
//MIKETODO: VIP mode
/*
if ( ( CSGameRules ( ) - > m_iMapHasVIPSafetyZone = = 1 ) & & ( m_iTeam = = TEAM_CT ) )
{
mp - > AddToVIPQueue ( this ) ;
}
*/
return true ;
}
return BaseClass : : ClientCommand ( args ) ;
}
// returns true if the selection has been handled and the player's menu
// can be closed...false if the menu should be displayed again
bool CCSPlayer : : HandleCommand_JoinTeam ( int team )
{
CCSGameRules * mp = CSGameRules ( ) ;
if ( ! GetGlobalTeam ( team ) )
{
DevWarning ( " HandleCommand_JoinTeam( %d ) - invalid team index. \n " , team ) ;
return false ;
}
// If this player is a VIP, don't allow him to switch teams/appearances unless the following conditions are met :
// a) There is another TEAM_CT player who is in the queue to be a VIP
// b) This player is dead
//MIKETODO: handle this when doing VIP mode
/*
if ( m_bIsVIP = = true )
{
if ( ! IsDead ( ) )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Cannot_Switch_From_VIP " ) ;
MenuReset ( ) ;
return true ;
}
else if ( mp - > IsVIPQueueEmpty ( ) = = true )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Cannot_Switch_From_VIP " ) ;
MenuReset ( ) ;
return true ;
}
}
//MIKETODO: VIP mode
case 3 :
if ( ( mp - > m_iMapHasVIPSafetyZone = = 1 ) & & ( m_iTeam = = TEAM_CT ) )
{
mp - > AddToVIPQueue ( player ) ;
MenuReset ( ) ;
return true ;
}
else
{
return false ;
}
break ;
*/
// If we already died and changed teams once, deny
if ( m_bTeamChanged & & team ! = m_iOldTeam & & team ! = TEAM_SPECTATOR )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Only_1_Team_Change " ) ;
return true ;
}
// check if we're limited in our team selection
if ( team = = TEAM_UNASSIGNED & & ! IsBot ( ) )
{
team = mp - > GetHumanTeam ( ) ; // returns TEAM_UNASSIGNED if we're unrestricted
}
if ( team = = TEAM_UNASSIGNED )
{
// Attempt to auto-select a team, may set team to T, CT or SPEC
team = mp - > SelectDefaultTeam ( ! IsBot ( ) ) ;
if ( team = = TEAM_UNASSIGNED )
{
// still team unassigned, try to kick a bot if possible
// kick a bot to allow human to join
if ( cv_bot_auto_vacate . GetBool ( ) & & ! IsBot ( ) )
{
team = ( random - > RandomInt ( 0 , 1 ) = = 0 ) ? TEAM_TERRORIST : TEAM_CT ;
if ( UTIL_KickBotFromTeam ( team ) = = false )
{
// no bots on that team, try the other
team = ( team = = TEAM_CT ) ? TEAM_TERRORIST : TEAM_CT ;
if ( UTIL_KickBotFromTeam ( team ) = = false )
{
// couldn't kick any bots, fail
team = TEAM_UNASSIGNED ;
}
}
}
if ( team = = TEAM_UNASSIGNED )
{
ClientPrint ( this , HUD_PRINTCENTER , " #All_Teams_Full " ) ;
ShowViewPortPanel ( PANEL_TEAM ) ;
return false ;
}
}
}
if ( team = = GetTeamNumber ( ) )
{
// Let people change class (skin) by re-joining the same team
if ( GetTeamNumber ( ) = = TEAM_TERRORIST & & TerroristPlayerModels . Count ( ) > 1 )
{
ShowViewPortPanel ( PANEL_CLASS_TER ) ;
}
else if ( GetTeamNumber ( ) = = TEAM_CT & & CTPlayerModels . Count ( ) > 1 )
{
ShowViewPortPanel ( PANEL_CLASS_CT ) ;
}
return true ; // we wouldn't change the team
}
if ( mp - > TeamFull ( team ) )
{
// attempt to kick a bot to make room for this player
bool madeRoom = false ;
if ( cv_bot_auto_vacate . GetBool ( ) & & ! IsBot ( ) )
{
if ( UTIL_KickBotFromTeam ( team ) )
madeRoom = true ;
}
if ( ! madeRoom )
{
if ( team = = TEAM_TERRORIST )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Terrorists_Full " ) ;
}
else if ( team = = TEAM_CT )
{
ClientPrint ( this , HUD_PRINTCENTER , " #CTs_Full " ) ;
}
ShowViewPortPanel ( PANEL_TEAM ) ;
return false ;
}
}
// check if humans are restricted to a single team (Tour of Duty, etc)
if ( ! IsBot ( ) & & team ! = TEAM_SPECTATOR )
{
int humanTeam = mp - > GetHumanTeam ( ) ;
if ( humanTeam ! = TEAM_UNASSIGNED & & humanTeam ! = team )
{
if ( humanTeam = = TEAM_TERRORIST )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Humans_Join_Team_T " ) ;
}
else if ( humanTeam = = TEAM_CT )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Humans_Join_Team_CT " ) ;
}
ShowViewPortPanel ( PANEL_TEAM ) ;
return false ;
}
}
if ( team = = TEAM_SPECTATOR )
{
// Prevent this is the cvar is set
if ( ! mp_allowspectators . GetInt ( ) & & ! IsHLTV ( ) )
{
ClientPrint ( this , HUD_PRINTCENTER , " #Cannot_Be_Spectator " ) ;
return false ;
}
if ( GetTeamNumber ( ) ! = TEAM_UNASSIGNED & & State_Get ( ) = = STATE_ACTIVE )
{
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 ) ;
m_iClass = ( int ) CS_CLASS_NONE ;
if ( ! ( m_iDisplayHistoryBits & DHF_SPEC_DUCK ) )
{
m_iDisplayHistoryBits | = DHF_SPEC_DUCK ;
HintMessage ( " #Spec_Duck " , true , true ) ;
}
// do we have fadetoblack on? (need to fade their screen back in)
if ( mp_fadetoblack . GetBool ( ) )
{
color32_s clr = { 0 , 0 , 0 , 255 } ;
UTIL_ScreenFade ( this , clr , 0 , 0 , FFADE_IN | FFADE_PURGE ) ;
}
return true ;
}
// If the code gets this far, the team is not TEAM_UNASSIGNED
if ( mp - > TeamStacked ( team , GetTeamNumber ( ) ) ) //players are allowed to change to their own team so they can just change their model
{
// attempt to kick a bot to make room for this player
bool madeRoom = false ;
if ( cv_bot_auto_vacate . GetBool ( ) & & ! IsBot ( ) )
{
if ( UTIL_KickBotFromTeam ( team ) )
madeRoom = true ;
}
if ( ! madeRoom )
{
// The specified team is full
ClientPrint (
this ,
HUD_PRINTCENTER ,
( team = = TEAM_TERRORIST ) ? " #Too_Many_Terrorists " : " #Too_Many_CTs " ) ;
ShowViewPortPanel ( PANEL_TEAM ) ;
return false ;
}
}
// Show the appropriate Choose Appearance menu
// This must come before ClientKill() for CheckWinConditions() to function properly
// Switch their actual team...
ChangeTeam ( team ) ;
return true ;
}
bool CCSPlayer : : HandleCommand_JoinClass ( int iClass )
{
if ( iClass = = CS_CLASS_NONE )
{
// User choosed random class
switch ( GetTeamNumber ( ) )
{
case TEAM_TERRORIST : iClass = RandomInt ( FIRST_T_CLASS , LAST_T_CLASS ) ;
break ;
case TEAM_CT : iClass = RandomInt ( FIRST_CT_CLASS , LAST_CT_CLASS ) ;
break ;
default : iClass = CS_CLASS_NONE ;
break ;
}
}
// clamp to valid classes
switch ( GetTeamNumber ( ) )
{
case TEAM_TERRORIST :
iClass = clamp ( iClass , FIRST_T_CLASS , LAST_T_CLASS ) ;
break ;
case TEAM_CT :
iClass = clamp ( iClass , FIRST_CT_CLASS , LAST_CT_CLASS ) ;
break ;
default :
iClass = CS_CLASS_NONE ;
}
// Reset the player's state
if ( State_Get ( ) = = STATE_ACTIVE )
{
CSGameRules ( ) - > CheckWinConditions ( ) ;
}
if ( ! IsBot ( ) & & State_Get ( ) = = STATE_ACTIVE ) // Bots are responsible about only switching classes when they join.
{
// Kill player if switching classes while alive.
// This mimics goldsrc CS 1.6, and prevents a player from hiding, and switching classes to
// make the opposing team think there are more enemies than there really are.
CommitSuicide ( ) ;
}
m_iClass = iClass ;
if ( State_Get ( ) = = STATE_PICKINGCLASS )
{
// SetModelFromClass();
GetIntoGame ( ) ;
}
return true ;
}
/*
void CheckStartMoney ( void )
{
if ( mp_startmoney . GetInt ( ) > 16000 )
{
mp_startmoney . SetInt ( 16000 ) ;
}
else if ( mp_startmoney . GetInt ( ) < 800 )
{
mp_startmoney . SetInt ( 800 ) ;
}
}
*/
void CCSPlayer : : GetIntoGame ( )
{
// Set their model and if they're allowed to spawn right now, put them into the world.
//SetPlayerModel( iClass );
SetFOV ( this , 0 ) ;
m_flLastMovement = gpGlobals - > curtime ;
CCSGameRules * MPRules = CSGameRules ( ) ;
/* //MIKETODO: Escape gameplay ?
if ( ( MPRules - > m_bMapHasEscapeZone = = true ) & & ( m_iTeam = = TEAM_CT ) )
{
m_iAccount = 0 ;
CheckStartMoney ( ) ;
AddAccount ( ( int ) startmoney . value , true ) ;
}
*/
//****************New Code by SupraFiend************
if ( ! MPRules - > FPlayerCanRespawn ( this ) )
{
// This player is joining in the middle of a round or is an observer. Put them directly into observer mode.
//pev->deadflag = DEAD_RESPAWNABLE;
//pev->classname = MAKE_STRING("player");
//pev->flags &= ( FL_PROXY | FL_FAKECLIENT ); // clear flags, but keep proxy and bot flags that might already be set
//pev->flags |= FL_CLIENT | FL_SPECTATOR;
//SetThink(PlayerDeathThink);
if ( ! ( m_iDisplayHistoryBits & DHF_SPEC_DUCK ) )
{
m_iDisplayHistoryBits | = DHF_SPEC_DUCK ;
HintMessage ( " #Spec_Duck " , true , true ) ;
}
State_Transition ( STATE_OBSERVER_MODE ) ;
m_wasNotKilledNaturally = true ;
MPRules - > CheckWinConditions ( ) ;
}
else // else spawn them right in
{
State_Transition ( STATE_ACTIVE ) ;
Spawn ( ) ;
MPRules - > CheckWinConditions ( ) ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Have the rules update anything related to a player spawning in late
//=============================================================================
MPRules - > SpawningLatePlayer ( this ) ;
//=============================================================================
// HPE_END
//=============================================================================
if ( MPRules - > m_flRestartRoundTime = = 0.0f )
{
//Bomb target, no bomber and no bomb lying around.
if ( MPRules - > IsBombDefuseMap ( ) & & ! MPRules - > IsThereABomber ( ) & & ! MPRules - > IsThereABomb ( ) )
MPRules - > GiveC4 ( ) ; //Checks for terrorists.
}
// If a new terrorist is entering the fray, then up the # of potential escapers.
if ( GetTeamNumber ( ) = = TEAM_TERRORIST )
MPRules - > m_iNumEscapers + + ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Reset Round Based Achievement Variables
//=============================================================================
ResetRoundBasedAchievementVariables ( ) ;
//=============================================================================
// HPE_END
//=============================================================================
}
}
int CCSPlayer : : PlayerClass ( ) const
{
return m_iClass ;
}
bool CCSPlayer : : SelectSpawnSpot ( const char * pEntClassName , CBaseEntity * & pSpot )
{
// Find the next spawn spot.
pSpot = gEntList . FindEntityByClassname ( pSpot , pEntClassName ) ;
if ( pSpot = = NULL ) // skip over the null point
pSpot = gEntList . FindEntityByClassname ( pSpot , pEntClassName ) ;
CBaseEntity * pFirstSpot = pSpot ;
do
{
if ( pSpot )
{
// check if pSpot is valid
if ( g_pGameRules - > IsSpawnPointValid ( pSpot , this ) )
{
if ( pSpot - > GetAbsOrigin ( ) = = Vector ( 0 , 0 , 0 ) )
{
pSpot = gEntList . FindEntityByClassname ( pSpot , pEntClassName ) ;
continue ;
}
// if so, go to pSpot
return true ;
}
}
// increment pSpot
pSpot = gEntList . FindEntityByClassname ( pSpot , pEntClassName ) ;
} while ( pSpot ! = pFirstSpot ) ; // loop if we're not back to the start
DevMsg ( " CCSPlayer::SelectSpawnSpot: couldn't find valid spawn point. \n " ) ;
return true ;
}
CBaseEntity * CCSPlayer : : EntSelectSpawnPoint ( )
{
CBaseEntity * pSpot ;
/* MIKETODO: VIP
// VIP spawn point *************
if ( ( g_pGameRules - > IsDeathmatch ( ) ) & & ( ( ( CBasePlayer * ) pPlayer ) - > m_bIsVIP = = TRUE ) )
{
//ALERT (at_console,"Looking for a VIP spawn point\n");
// Randomize the start spot
//for ( int i = RANDOM_LONG(1,5); i > 0; i-- )
pSpot = UTIL_FindEntityByClassname ( NULL , " info_vip_start " ) ;
if ( ! FNullEnt ( pSpot ) ) // skip over the null point
goto ReturnSpot ;
else
goto CTSpawn ;
}
//
// the counter-terrorist spawns at "info_player_start"
else
*/
pSpot = NULL ;
if ( CSGameRules ( ) - > IsLogoMap ( ) )
{
// This is a logo map. Don't allow movement or logos or menus.
SelectSpawnSpot ( " info_player_logo " , pSpot ) ;
LockPlayerInPlace ( ) ;
goto ReturnSpot ;
}
else
{
if ( GetTeamNumber ( ) = = TEAM_CT )
{
pSpot = g_pLastCTSpawn ;
if ( SelectSpawnSpot ( " info_player_counterterrorist " , pSpot ) )
{
g_pLastCTSpawn = pSpot ;
goto ReturnSpot ;
}
}
/*********************************************************/
// The terrorist spawn points
else if ( GetTeamNumber ( ) = = TEAM_TERRORIST )
{
pSpot = g_pLastTerroristSpawn ;
if ( SelectSpawnSpot ( " info_player_terrorist " , pSpot ) )
{
g_pLastTerroristSpawn = pSpot ;
goto ReturnSpot ;
}
}
}
// If startspot is set, (re)spawn there.
if ( ! gpGlobals - > startspot | | ! strlen ( STRING ( gpGlobals - > startspot ) ) )
{
pSpot = gEntList . FindEntityByClassname ( NULL , " info_player_terrorist " ) ;
if ( pSpot )
goto ReturnSpot ;
}
else
{
pSpot = gEntList . FindEntityByTarget ( NULL , STRING ( gpGlobals - > startspot ) ) ;
if ( pSpot )
goto ReturnSpot ;
}
ReturnSpot :
if ( ! pSpot )
{
if ( CSGameRules ( ) - > IsLogoMap ( ) )
Warning ( " PutClientInServer: no info_player_logo on level \n " ) ;
else
Warning ( " PutClientInServer: no info_player_start on level \n " ) ;
return CBaseEntity : : Instance ( INDEXENT ( 0 ) ) ;
}
return pSpot ;
}
void CCSPlayer : : SetProgressBarTime ( int barTime )
{
m_iProgressBarDuration = barTime ;
m_flProgressBarStartTime = this - > m_flSimulationTime ;
}
void CCSPlayer : : PlayerDeathThink ( )
{
}
void CCSPlayer : : State_Transition ( CSPlayerState newState )
{
State_Leave ( ) ;
State_Enter ( newState ) ;
}
void CCSPlayer : : State_Enter ( CSPlayerState newState )
{
m_iPlayerState = newState ;
m_pCurStateInfo = State_LookupInfo ( newState ) ;
if ( cs_ShowStateTransitions . GetInt ( ) = = - 1 | | cs_ShowStateTransitions . GetInt ( ) = = entindex ( ) )
{
if ( m_pCurStateInfo )
Msg ( " ShowStateTransitions: entering '%s' \n " , m_pCurStateInfo - > m_pStateName ) ;
else
Msg ( " ShowStateTransitions: entering #%d \n " , newState ) ;
}
// Initialize the new state.
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnEnterState )
( this - > * m_pCurStateInfo - > pfnEnterState ) ( ) ;
}
void CCSPlayer : : State_Leave ( )
{
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnLeaveState )
{
( this - > * m_pCurStateInfo - > pfnLeaveState ) ( ) ;
}
}
void CCSPlayer : : State_PreThink ( )
{
if ( m_pCurStateInfo & & m_pCurStateInfo - > pfnPreThink )
{
( this - > * m_pCurStateInfo - > pfnPreThink ) ( ) ;
}
}
CCSPlayerStateInfo * CCSPlayer : : State_LookupInfo ( CSPlayerState state )
{
// This table MUST match the
static CCSPlayerStateInfo playerStateInfos [ ] =
{
{ STATE_ACTIVE , " STATE_ACTIVE " , & CCSPlayer : : State_Enter_ACTIVE , NULL , & CCSPlayer : : State_PreThink_ACTIVE } ,
{ STATE_WELCOME , " STATE_WELCOME " , & CCSPlayer : : State_Enter_WELCOME , NULL , & CCSPlayer : : State_PreThink_WELCOME } ,
{ STATE_PICKINGTEAM , " STATE_PICKINGTEAM " , & CCSPlayer : : State_Enter_PICKINGTEAM , NULL , & CCSPlayer : : State_PreThink_OBSERVER_MODE } ,
{ STATE_PICKINGCLASS , " STATE_PICKINGCLASS " , & CCSPlayer : : State_Enter_PICKINGCLASS , NULL , & CCSPlayer : : State_PreThink_OBSERVER_MODE } ,
{ STATE_DEATH_ANIM , " STATE_DEATH_ANIM " , & CCSPlayer : : State_Enter_DEATH_ANIM , NULL , & CCSPlayer : : State_PreThink_DEATH_ANIM } ,
{ STATE_DEATH_WAIT_FOR_KEY , " STATE_DEATH_WAIT_FOR_KEY " , & CCSPlayer : : State_Enter_DEATH_WAIT_FOR_KEY , NULL , & CCSPlayer : : State_PreThink_DEATH_WAIT_FOR_KEY } ,
{ STATE_OBSERVER_MODE , " STATE_OBSERVER_MODE " , & CCSPlayer : : State_Enter_OBSERVER_MODE , NULL , & CCSPlayer : : State_PreThink_OBSERVER_MODE }
} ;
for ( int i = 0 ; i < ARRAYSIZE ( playerStateInfos ) ; i + + )
{
if ( playerStateInfos [ i ] . m_iPlayerState = = state )
return & playerStateInfos [ i ] ;
}
return NULL ;
}
void CCSPlayer : : PhysObjectSleep ( )
{
IPhysicsObject * pObj = VPhysicsGetObject ( ) ;
if ( pObj )
pObj - > Sleep ( ) ;
}
void CCSPlayer : : PhysObjectWake ( )
{
IPhysicsObject * pObj = VPhysicsGetObject ( ) ;
if ( pObj )
pObj - > Wake ( ) ;
}
void CCSPlayer : : State_Enter_WELCOME ( )
{
StartObserverMode ( OBS_MODE_ROAMING ) ;
// Important to set MOVETYPE_NONE or our physics object will fall while we're sitting at one of the intro cameras.
SetMoveType ( MOVETYPE_NONE ) ;
AddSolidFlags ( FSOLID_NOT_SOLID ) ;
PhysObjectSleep ( ) ;
const ConVar * hostname = cvar - > FindVar ( " hostname " ) ;
const char * title = ( hostname ) ? hostname - > GetString ( ) : " MESSAGE OF THE DAY " ;
// Show info panel (if it's not a simple demo map).
if ( ! CSGameRules ( ) - > IsLogoMap ( ) )
{
if ( CommandLine ( ) - > FindParm ( " -makereslists " ) ) // don't show the MOTD when making reslists
{
engine - > ClientCommand ( edict ( ) , " jointeam 3 \n " ) ;
}
else
{
KeyValues * data = new KeyValues ( " data " ) ;
data - > SetString ( " title " , title ) ; // info panel title
data - > SetString ( " type " , " 1 " ) ; // show userdata from stringtable entry
data - > SetString ( " msg " , " motd " ) ; // use this stringtable entry
data - > SetInt ( " cmd " , TEXTWINDOW_CMD_JOINGAME ) ; // exec this command if panel closed
data - > SetBool ( " unload " , sv_motd_unload_on_dismissal . GetBool ( ) ) ;
ShowViewPortPanel ( PANEL_INFO , true , data ) ;
data - > deleteThis ( ) ;
}
}
}
void CCSPlayer : : State_PreThink_WELCOME ( )
{
// Verify some state.
Assert ( IsSolidFlagSet ( FSOLID_NOT_SOLID ) ) ;
Assert ( GetAbsVelocity ( ) . Length ( ) = = 0 ) ;
// Update whatever intro camera it's at.
if ( m_pIntroCamera & & ( gpGlobals - > curtime > = m_fIntroCamTime ) )
{
MoveToNextIntroCamera ( ) ;
}
}
void CCSPlayer : : State_Enter_PICKINGTEAM ( )
{
ShowViewPortPanel ( " team " ) ; // show the team menu
}
void CCSPlayer : : State_Enter_DEATH_ANIM ( )
{
if ( HasWeapons ( ) )
{
// we drop the guns here because weapons that have an area effect and can kill their user
// will sometimes crash coming back from CBasePlayer::Killed() if they kill their owner because the
// player class sometimes is freed. It's safer to manipulate the weapons once we know
// we aren't calling into any of their code anymore through the player pointer.
PackDeadPlayerItems ( ) ;
}
// Used for a timer.
m_flDeathTime = gpGlobals - > curtime ;
m_bAbortFreezeCam = false ;
StartObserverMode ( OBS_MODE_DEATHCAM ) ; // go to observer mode
RemoveEffects ( EF_NODRAW ) ; // still draw player body
if ( mp_fadetoblack . GetBool ( ) )
{
color32_s clr = { 0 , 0 , 0 , 255 } ;
UTIL_ScreenFade ( this , clr , 3 , 3 , FFADE_OUT | FFADE_STAYOUT ) ;
//Don't perform any freezecam stuff if we are fading to black
State_Transition ( STATE_DEATH_WAIT_FOR_KEY ) ;
}
}
//=============================================================================
// HPE_BEGIN:
// [menglish, pfreese] Added freeze cam logic
//=============================================================================
void CCSPlayer : : State_PreThink_DEATH_ANIM ( )
{
// If the anim is done playing, go to the next state (waiting for a keypress to
// either respawn the guy or put him into observer mode).
if ( GetFlags ( ) & FL_ONGROUND )
{
float flForward = GetAbsVelocity ( ) . Length ( ) - 20 ;
if ( flForward < = 0 )
{
SetAbsVelocity ( vec3_origin ) ;
}
else
{
Vector vAbsVel = GetAbsVelocity ( ) ;
VectorNormalize ( vAbsVel ) ;
vAbsVel * = flForward ;
SetAbsVelocity ( vAbsVel ) ;
}
}
float fDeathEnd = m_flDeathTime + CS_DEATH_ANIMATION_TIME ;
float fFreezeEnd = fDeathEnd + spec_freeze_traveltime . GetFloat ( ) + spec_freeze_time . GetFloat ( ) ;
// transition to Freezecam mode once the death animation is complete
if ( gpGlobals - > curtime > = fDeathEnd )
{
if ( GetObserverTarget ( ) & & GetObserverTarget ( ) ! = this & &
! m_bAbortFreezeCam & & gpGlobals - > curtime < fFreezeEnd & & GetObserverMode ( ) ! = OBS_MODE_FREEZECAM )
{
StartObserverMode ( OBS_MODE_FREEZECAM ) ;
}
else if ( GetObserverMode ( ) = = OBS_MODE_FREEZECAM )
{
if ( m_bAbortFreezeCam & & ! mp_fadetoblack . GetBool ( ) )
{
State_Transition ( STATE_OBSERVER_MODE ) ;
}
}
}
// Don't transfer to observer state until the freeze cam is done
if ( gpGlobals - > curtime < fFreezeEnd )
return ;
State_Transition ( STATE_OBSERVER_MODE ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
void CCSPlayer : : State_Enter_DEATH_WAIT_FOR_KEY ( )
{
// Remember when we died, so we can automatically put them into observer mode
// if they don't hit a key soon enough.
m_lifeState = LIFE_DEAD ;
StopAnimation ( ) ;
// Don't do this. The ragdoll system expects to be able to read from this player on
// the next update and will read it at the new origin if this is set.
// Since it is more complicated to redesign the ragdoll system to not need that data
// it is easier to cause a less obvious bug than popping ragdolls
//AddEffects( EF_NOINTERP );
}
void CCSPlayer : : State_PreThink_DEATH_WAIT_FOR_KEY ( )
{
// once we're done animating our death and we're on the ground, we want to set movetype to None so our dead body won't do collisions and stuff anymore
// this prevents a bug where the dead body would go to a player's head if he walked over it while the dead player was clicking their button to respawn
if ( GetMoveType ( ) ! = MOVETYPE_NONE & & ( GetFlags ( ) & FL_ONGROUND ) )
SetMoveType ( MOVETYPE_NONE ) ;
// if the player has been dead for one second longer than allowed by forcerespawn,
// forcerespawn isn't on. Send the player off to an intermission camera until they
// choose to respawn.
bool fAnyButtonDown = ( m_nButtons & ~ IN_SCORE ) ! = 0 ;
if ( mp_fadetoblack . GetBool ( ) )
fAnyButtonDown = false ;
// after a certain amount of time switch to observer mode even if they don't press a key.
if ( gpGlobals - > curtime > = ( m_flDeathTime + DEATH_ANIMATION_TIME + 3.0 ) )
{
fAnyButtonDown = true ;
}
if ( fAnyButtonDown )
{
if ( GetObserverTarget ( ) )
{
StartReplayMode ( 8 , 8 , GetObserverTarget ( ) - > entindex ( ) ) ;
}
State_Transition ( STATE_OBSERVER_MODE ) ;
}
}
void CCSPlayer : : State_Enter_OBSERVER_MODE ( )
{
// do we have fadetoblack on? (need to fade their screen back in)
if ( mp_fadetoblack . GetBool ( ) & & mp_forcecamera . GetInt ( ) ! = OBS_ALLOW_NONE )
{
color32_s clr = { 0 , 0 , 0 , 255 } ;
UTIL_ScreenFade ( this , clr , 0 , 0 , FFADE_IN | FFADE_PURGE ) ;
}
int observerMode = m_iObserverLastMode ;
if ( IsNetClient ( ) )
{
const char * pIdealMode = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_spec_mode " ) ;
if ( pIdealMode )
{
int nIdealMode = atoi ( pIdealMode ) ;
if ( nIdealMode < OBS_MODE_IN_EYE )
{
nIdealMode = OBS_MODE_IN_EYE ;
}
else if ( nIdealMode > OBS_MODE_ROAMING )
{
nIdealMode = OBS_MODE_ROAMING ;
}
observerMode = nIdealMode ;
}
}
StartObserverMode ( observerMode ) ;
PhysObjectSleep ( ) ;
}
void CCSPlayer : : 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 CCSPlayer : : State_Enter_PICKINGCLASS ( )
{
if ( CommandLine ( ) - > FindParm ( " -makereslists " ) ) // don't show the menu when making reslists
{
engine - > ClientCommand ( edict ( ) , " joinclass 0 \n " ) ;
return ;
}
// go to spec mode, if dying keep deathcam
if ( GetObserverMode ( ) = = OBS_MODE_DEATHCAM )
{
StartObserverMode ( OBS_MODE_DEATHCAM ) ;
}
else
{
StartObserverMode ( OBS_MODE_FIXED ) ;
}
m_iClass = ( int ) CS_CLASS_NONE ;
PhysObjectSleep ( ) ;
// show the class menu:
if ( GetTeamNumber ( ) = = TEAM_TERRORIST & & TerroristPlayerModels . Count ( ) > 1 )
{
ShowViewPortPanel ( PANEL_CLASS_TER ) ;
}
else if ( GetTeamNumber ( ) = = TEAM_CT & & CTPlayerModels . Count ( ) > 1 )
{
ShowViewPortPanel ( PANEL_CLASS_CT ) ;
}
else
{
HandleCommand_JoinClass ( 0 ) ;
}
}
void CCSPlayer : : State_Enter_ACTIVE ( )
{
SetMoveType ( MOVETYPE_WALK ) ;
RemoveSolidFlags ( FSOLID_NOT_SOLID ) ;
m_Local . m_iHideHUD = 0 ;
PhysObjectWake ( ) ;
}
void CCSPlayer : : State_PreThink_ACTIVE ( )
{
// We only allow noclip here only because noclip is useful for debugging.
// It would be nice if the noclip command set some flag so we could tell that they
// did it intentionally.
if ( IsEFlagSet ( EFL_NOCLIP_ACTIVE ) )
{
// Assert( GetMoveType() == MOVETYPE_NOCLIP );
}
else
{
// Assert( GetMoveType() == MOVETYPE_WALK );
}
Assert ( ! IsSolidFlagSet ( FSOLID_NOT_SOLID ) ) ;
}
void CCSPlayer : : Weapon_Equip ( CBaseCombatWeapon * pWeapon )
{
CWeaponCSBase * pCSWeapon = dynamic_cast < CWeaponCSBase * > ( pWeapon ) ;
if ( pCSWeapon )
{
// For rifles, pistols, or the knife, drop our old weapon in this slot.
if ( pCSWeapon - > GetSlot ( ) = = WEAPON_SLOT_RIFLE | |
pCSWeapon - > GetSlot ( ) = = WEAPON_SLOT_PISTOL | |
pCSWeapon - > GetSlot ( ) = = WEAPON_SLOT_KNIFE )
{
CBaseCombatWeapon * pDropWeapon = Weapon_GetSlot ( pCSWeapon - > GetSlot ( ) ) ;
if ( pDropWeapon )
{
CSWeaponDrop ( pDropWeapon , false , true ) ;
}
}
else if ( pCSWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_GRENADE )
{
//if we already have this weapon, just add the ammo and destroy it
if ( Weapon_OwnsThisType ( pCSWeapon - > GetClassname ( ) ) )
{
Weapon_EquipAmmoOnly ( pWeapon ) ;
UTIL_Remove ( pCSWeapon ) ;
return ;
}
}
pCSWeapon - > SetSolidFlags ( FSOLID_NOT_SOLID ) ;
pCSWeapon - > SetOwnerEntity ( this ) ;
}
BaseClass : : Weapon_Equip ( pWeapon ) ;
}
bool CCSPlayer : : Weapon_CanUse ( CBaseCombatWeapon * pBaseWeapon )
{
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( pBaseWeapon ) ;
if ( pWeapon )
{
// Don't give weapon_c4 to non-terrorists
if ( pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_C4 & & GetTeamNumber ( ) ! = TEAM_TERRORIST )
{
return false ;
}
}
return true ;
}
bool CCSPlayer : : BumpWeapon ( CBaseCombatWeapon * pBaseWeapon )
{
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( pBaseWeapon ) ;
if ( ! pWeapon )
{
Assert ( ! pWeapon ) ;
pBaseWeapon - > AddSolidFlags ( FSOLID_NOT_SOLID ) ;
pBaseWeapon - > AddEffects ( EF_NODRAW ) ;
Weapon_Equip ( pBaseWeapon ) ;
return true ;
}
CBaseCombatCharacter * pOwner = pWeapon - > GetOwner ( ) ;
// Can I have this weapon type?
if ( pOwner | | ! Weapon_CanUse ( pWeapon ) | | ! g_pGameRules - > CanHavePlayerItem ( this , pWeapon ) )
{
extern int gEvilImpulse101 ;
if ( gEvilImpulse101 )
{
UTIL_Remove ( pWeapon ) ;
}
return false ;
}
// Even if we already have a grenade in this slot, we can pickup another one if we don't already
// own this type of grenade.
bool bPickupGrenade = ( pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_GRENADE ) ;
/*
// ----------------------------------------
// If I already have it just take the ammo
// ----------------------------------------
if ( ! bPickupGrenade & & Weapon_SlotOccupied ( pWeapon ) )
{
Weapon_EquipAmmoOnly ( pWeapon ) ;
// Only remove me if I have no ammo left
// Can't just check HasAnyAmmo because if I don't use clips, I want to be removed,
if ( pWeapon - > UsesClipsForAmmo1 ( ) & & pWeapon - > HasPrimaryAmmo ( ) )
return false ;
UTIL_Remove ( pWeapon ) ;
return false ;
}
*/
if ( HasShield ( ) & & pWeapon - > GetCSWpnData ( ) . m_bCanUseWithShield = = false )
return false ;
// Check ammo counts for grenades, and don't try to pick up more grenades than we can carry
if ( bPickupGrenade )
{
CBaseCombatWeapon * pOwnedGrenade = Weapon_OwnsThisType ( pWeapon - > GetClassname ( ) ) ;
if ( pOwnedGrenade )
{
int numGrenades = 0 ;
int maxGrenades = 0 ;
int ammoIndex = pOwnedGrenade - > GetPrimaryAmmoType ( ) ;
if ( ammoIndex ! = - 1 )
{
numGrenades = GetAmmoCount ( ammoIndex ) ;
}
maxGrenades = GetAmmoDef ( ) - > MaxCarry ( ammoIndex ) ;
if ( numGrenades > = maxGrenades )
{
return false ;
}
}
}
if ( bPickupGrenade | | ! Weapon_SlotOccupied ( pWeapon ) )
{
pWeapon - > CheckRespawn ( ) ;
pWeapon - > AddSolidFlags ( FSOLID_NOT_SOLID ) ;
pWeapon - > AddEffects ( EF_NODRAW ) ;
CCSPlayer * pDonor = pWeapon - > GetDonor ( ) ;
if ( pDonor & & pDonor ! = this & & pWeapon - > GetCSWpnData ( ) . GetWeaponPrice ( ) > m_iAccount )
{
CCS_GameStats . Event_PlayerDonatedWeapon ( pDonor ) ;
}
pWeapon - > SetDonor ( NULL ) ;
Weapon_Equip ( pWeapon ) ;
int iExtraAmmo = pWeapon - > GetExtraAmmoCount ( ) ;
if ( iExtraAmmo & & ! bPickupGrenade )
{
//Find out the index of the ammo
int iAmmoIndex = pWeapon - > GetPrimaryAmmoType ( ) ;
if ( iAmmoIndex ! = - 1 )
{
//Remove the extra ammo from the weapon
pWeapon - > SetExtraAmmoCount ( 0 ) ;
//Give it to the player
SetAmmoCount ( iExtraAmmo , iAmmoIndex ) ;
}
}
IGameEvent * event = gameeventmanager - > CreateEvent ( " item_pickup " ) ;
if ( event )
{
const char * weaponName = pWeapon - > GetClassname ( ) ;
if ( strncmp ( weaponName , " weapon_ " , 7 ) = = 0 )
{
weaponName + = 7 ;
}
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " item " , weaponName ) ;
gameeventmanager - > FireEvent ( event ) ;
}
return true ;
}
return false ;
}
void CCSPlayer : : ResetStamina ( void )
{
m_flStamina = 0.0f ;
}
void CCSPlayer : : RescueZoneTouch ( inputdata_t & inputdata )
{
m_bInHostageRescueZone = true ;
if ( GetTeamNumber ( ) = = TEAM_CT & & ! ( m_iDisplayHistoryBits & DHF_IN_RESCUE_ZONE ) )
{
HintMessage ( " #Hint_hostage_rescue_zone " , false ) ;
m_iDisplayHistoryBits | = DHF_IN_RESCUE_ZONE ;
}
}
//------------------------------------------------------------------------------------------
CON_COMMAND ( timeleft , " prints the time remaining in the match " )
{
CCSPlayer * pPlayer = ToCSPlayer ( UTIL_GetCommandClient ( ) ) ;
if ( pPlayer & & pPlayer - > m_iNextTimeCheck > = gpGlobals - > curtime )
{
return ; // rate limiting
}
int iTimeRemaining = ( int ) CSGameRules ( ) - > GetMapRemainingTime ( ) ;
if ( iTimeRemaining < 0 )
{
if ( pPlayer )
{
ClientPrint ( pPlayer , HUD_PRINTTALK , " #Game_no_timelimit " ) ;
}
else
{
Msg ( " * No Time Limit * \n " ) ;
}
}
else if ( iTimeRemaining = = 0 )
{
if ( pPlayer )
{
ClientPrint ( pPlayer , HUD_PRINTTALK , " #Game_last_round " ) ;
}
else
{
Msg ( " * Last Round * \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 , " #Game_timelimit " , minutes , seconds ) ;
}
else
{
Msg ( " Time Remaining: %s:%s \n " , minutes , seconds ) ;
}
}
if ( pPlayer )
{
pPlayer - > m_iNextTimeCheck = gpGlobals - > curtime + 1 ;
}
}
//------------------------------------------------------------------------------------------
/**
* Emit given sound that only we can hear
*/
void CCSPlayer : : EmitPrivateSound ( const char * soundName )
{
CSoundParameters params ;
if ( ! GetParametersForSound ( soundName , params , NULL ) )
return ;
CSingleUserRecipientFilter filter ( this ) ;
EmitSound ( filter , entindex ( ) , soundName ) ;
}
//=====================
//Autobuy
//=====================
static void AutoBuy ( void )
{
CCSPlayer * player = ToCSPlayer ( UTIL_GetCommandClient ( ) ) ;
if ( player )
player - > AutoBuy ( ) ;
}
static ConCommand autobuy ( " autobuy " , AutoBuy , " Attempt to purchase items with the order listed in cl_autobuy " ) ;
//==============================================
//AutoBuy - do the work of deciding what to buy
//==============================================
void CCSPlayer : : AutoBuy ( )
{
if ( ! IsInBuyZone ( ) )
{
EmitPrivateSound ( " BuyPreset.CantBuy " ) ;
return ;
}
const char * autobuyString = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_autobuy " ) ;
if ( ! autobuyString | | ! * autobuyString )
{
EmitPrivateSound ( " BuyPreset.AlreadyBought " ) ;
return ;
}
bool boughtPrimary = false , boughtSecondary = false ;
m_bIsInAutoBuy = true ;
ParseAutoBuyString ( autobuyString , boughtPrimary , boughtSecondary ) ;
m_bIsInAutoBuy = false ;
m_bAutoReload = true ;
//TODO ?: stripped out all the attempts to buy career weapons.
// as we're not porting cs:cz, these were skipped
}
void CCSPlayer : : ParseAutoBuyString ( const char * string , bool & boughtPrimary , bool & boughtSecondary )
{
char command [ 32 ] ;
int nBuffSize = sizeof ( command ) - 1 ; // -1 to leave space for the NULL at the end of the string
const char * c = string ;
if ( c = = NULL )
{
EmitPrivateSound ( " BuyPreset.AlreadyBought " ) ;
return ;
}
BuyResult_e overallResult = BUY_ALREADY_HAVE ;
// loop through the string of commands, trying each one in turn.
while ( * c ! = 0 )
{
int i = 0 ;
// copy the next word into the command buffer.
while ( ( * c ! = 0 ) & & ( * c ! = ' ' ) & & ( i < nBuffSize ) )
{
command [ i ] = * ( c ) ;
+ + c ;
+ + i ;
}
if ( * c = = ' ' )
{
+ + c ; // skip the space.
}
command [ i ] = 0 ; // terminate the string.
// clear out any spaces.
i = 0 ;
while ( command [ i ] ! = 0 )
{
if ( command [ i ] = = ' ' )
{
command [ i ] = 0 ;
break ;
}
+ + i ;
}
// make sure we actually have a command.
if ( strlen ( command ) = = 0 )
{
continue ;
}
AutoBuyInfoStruct * commandInfo = GetAutoBuyCommandInfo ( command ) ;
if ( ShouldExecuteAutoBuyCommand ( commandInfo , boughtPrimary , boughtSecondary ) )
{
BuyResult_e result = HandleCommand_Buy ( command ) ;
overallResult = CombineBuyResults ( overallResult , result ) ;
// check to see if we actually bought a primary or secondary weapon this time.
PostAutoBuyCommandProcessing ( commandInfo , boughtPrimary , boughtSecondary ) ;
}
}
if ( overallResult = = BUY_CANT_AFFORD )
{
EmitPrivateSound ( " BuyPreset.CantBuy " ) ;
}
else if ( overallResult = = BUY_ALREADY_HAVE )
{
EmitPrivateSound ( " BuyPreset.AlreadyBought " ) ;
}
else if ( overallResult = = BUY_BOUGHT )
{
g_iAutoBuyPurchases + + ;
}
}
BuyResult_e CCSPlayer : : CombineBuyResults ( BuyResult_e prevResult , BuyResult_e newResult )
{
if ( newResult = = BUY_BOUGHT )
{
prevResult = BUY_BOUGHT ;
}
else if ( prevResult ! = BUY_BOUGHT & &
( newResult = = BUY_CANT_AFFORD | | newResult = = BUY_INVALID_ITEM | | newResult = = BUY_PLAYER_CANT_BUY ) )
{
prevResult = BUY_CANT_AFFORD ;
}
return prevResult ;
}
//==============================================
//PostAutoBuyCommandProcessing
//==============================================
void CCSPlayer : : PostAutoBuyCommandProcessing ( const AutoBuyInfoStruct * commandInfo , bool & boughtPrimary , bool & boughtSecondary )
{
if ( commandInfo = = NULL )
{
return ;
}
CBaseCombatWeapon * pPrimary = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
CBaseCombatWeapon * pSecondary = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( ( pPrimary ! = NULL ) & & ( stricmp ( pPrimary - > GetClassname ( ) , commandInfo - > m_classname ) = = 0 ) )
{
// I just bought the gun I was trying to buy.
boughtPrimary = true ;
}
else if ( ( pPrimary = = NULL ) & & ( ( commandInfo - > m_class & AUTOBUYCLASS_SHIELD ) = = AUTOBUYCLASS_SHIELD ) & & HasShield ( ) )
{
// the shield is a primary weapon even though it isn't a "real" weapon.
boughtPrimary = true ;
}
else if ( ( pSecondary ! = NULL ) & & ( stricmp ( pSecondary - > GetClassname ( ) , commandInfo - > m_classname ) = = 0 ) )
{
// I just bought the pistol I was trying to buy.
boughtSecondary = true ;
}
}
bool CCSPlayer : : ShouldExecuteAutoBuyCommand ( const AutoBuyInfoStruct * commandInfo , bool boughtPrimary , bool boughtSecondary )
{
if ( commandInfo = = NULL )
{
return false ;
}
if ( ( boughtPrimary ) & & ( ( commandInfo - > m_class & AUTOBUYCLASS_PRIMARY ) ! = 0 ) & & ( ( commandInfo - > m_class & AUTOBUYCLASS_AMMO ) = = 0 ) )
{
// this is a primary weapon and we already have one.
return false ;
}
if ( ( boughtSecondary ) & & ( ( commandInfo - > m_class & AUTOBUYCLASS_SECONDARY ) ! = 0 ) & & ( ( commandInfo - > m_class & AUTOBUYCLASS_AMMO ) = = 0 ) )
{
// this is a secondary weapon and we already have one.
return false ;
}
if ( commandInfo - > m_class & AUTOBUYCLASS_ARMOR & & ArmorValue ( ) > = 100 )
{
return false ;
}
return true ;
}
AutoBuyInfoStruct * CCSPlayer : : GetAutoBuyCommandInfo ( const char * command )
{
int i = 0 ;
AutoBuyInfoStruct * ret = NULL ;
AutoBuyInfoStruct * temp = & ( g_autoBuyInfo [ i ] ) ;
// loop through all the commands till we find the one that matches.
while ( ( ret = = NULL ) & & ( temp - > m_class ! = ( AutoBuyClassType ) 0 ) )
{
temp = & ( g_autoBuyInfo [ i ] ) ;
+ + i ;
if ( stricmp ( temp - > m_command , command ) = = 0 )
{
ret = temp ;
}
}
return ret ;
}
//==============================================
//PostAutoBuyCommandProcessing
//- reorders the tokens in autobuyString based on the order of tokens in the priorityString.
//==============================================
void CCSPlayer : : PrioritizeAutoBuyString ( char * autobuyString , const char * priorityString )
{
char newString [ 256 ] ;
int newStringPos = 0 ;
char priorityToken [ 32 ] ;
if ( ( priorityString = = NULL ) | | ( autobuyString = = NULL ) )
{
return ;
}
const char * priorityChar = priorityString ;
while ( * priorityChar ! = 0 )
{
int i = 0 ;
// get the next token from the priority string.
while ( ( * priorityChar ! = 0 ) & & ( * priorityChar ! = ' ' ) )
{
priorityToken [ i ] = * priorityChar ;
+ + i ;
+ + priorityChar ;
}
priorityToken [ i ] = 0 ;
// skip spaces
while ( * priorityChar = = ' ' )
{
+ + priorityChar ;
}
if ( strlen ( priorityToken ) = = 0 )
{
continue ;
}
// see if the priority token is in the autobuy string.
// if it is, copy that token to the new string and blank out
// that token in the autobuy string.
char * autoBuyPosition = strstr ( autobuyString , priorityToken ) ;
if ( autoBuyPosition ! = NULL )
{
while ( ( * autoBuyPosition ! = 0 ) & & ( * autoBuyPosition ! = ' ' ) )
{
newString [ newStringPos ] = * autoBuyPosition ;
* autoBuyPosition = ' ' ;
+ + newStringPos ;
+ + autoBuyPosition ;
}
newString [ newStringPos + + ] = ' ' ;
}
}
// now just copy anything left in the autobuyString to the new string in the order it's in already.
char * autobuyPosition = autobuyString ;
while ( * autobuyPosition ! = 0 )
{
// skip spaces
while ( * autobuyPosition = = ' ' )
{
+ + autobuyPosition ;
}
// copy the token over to the new string.
while ( ( * autobuyPosition ! = 0 ) & & ( * autobuyPosition ! = ' ' ) )
{
newString [ newStringPos ] = * autobuyPosition ;
+ + newStringPos ;
+ + autobuyPosition ;
}
// add a space at the end.
newString [ newStringPos + + ] = ' ' ;
}
// terminate the string. Trailing spaces shouldn't matter.
newString [ newStringPos ] = 0 ;
Q_snprintf ( autobuyString , sizeof ( autobuyString ) , " %s " , newString ) ;
}
//==============================================================
// ReBuy
// system for attempting to buy the weapons you had last round
//==============================================================
static void Rebuy ( void )
{
CCSPlayer * player = ToCSPlayer ( UTIL_GetCommandClient ( ) ) ;
if ( player )
player - > Rebuy ( ) ;
}
static ConCommand rebuy ( " rebuy " , Rebuy , " Attempt to repurchase items with the order listed in cl_rebuy " ) ;
void CCSPlayer : : BuildRebuyStruct ( )
{
if ( m_bIsInRebuy )
{
// if we are in the middle of a rebuy, we don't want to update the buy struct.
return ;
}
CBaseCombatWeapon * primary = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
CBaseCombatWeapon * secondary = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
// do the primary weapon/ammo stuff.
if ( primary = = NULL )
{
// count a shieldgun as a primary.
if ( HasShield ( ) )
{
//m_rebuyStruct.m_primaryWeapon = WEAPON_SHIELDGUN;
Q_strncpy ( m_rebuyStruct . m_szPrimaryWeapon , " shield " , sizeof ( m_rebuyStruct . m_szPrimaryWeapon ) ) ;
m_rebuyStruct . m_primaryAmmo = 0 ; // shields don't have ammo.
}
else
{
m_rebuyStruct . m_szPrimaryWeapon [ 0 ] = 0 ; // if we don't have a shield and we don't have a primary weapon, we got nuthin.
m_rebuyStruct . m_primaryAmmo = 0 ; // can't have ammo if we don't have a gun right?
}
}
else
{
//strip off the "weapon_"
const char * wpnName = primary - > GetClassname ( ) ;
Q_strncpy ( m_rebuyStruct . m_szPrimaryWeapon , wpnName + 7 , sizeof ( m_rebuyStruct . m_szPrimaryWeapon ) ) ;
if ( primary - > GetPrimaryAmmoType ( ) ! = - 1 )
{
m_rebuyStruct . m_primaryAmmo = GetAmmoCount ( primary - > GetPrimaryAmmoType ( ) ) ;
}
}
// do the secondary weapon/ammo stuff.
if ( secondary = = NULL )
{
m_rebuyStruct . m_szSecondaryWeapon [ 0 ] = 0 ;
m_rebuyStruct . m_secondaryAmmo = 0 ; // can't have ammo if we don't have a gun right?
}
else
{
const char * wpnName = secondary - > GetClassname ( ) ;
Q_strncpy ( m_rebuyStruct . m_szSecondaryWeapon , wpnName + 7 , sizeof ( m_rebuyStruct . m_szSecondaryWeapon ) ) ;
if ( secondary - > GetPrimaryAmmoType ( ) ! = - 1 )
{
m_rebuyStruct . m_secondaryAmmo = GetAmmoCount ( secondary - > GetPrimaryAmmoType ( ) ) ;
}
}
CBaseCombatWeapon * pGrenade ;
//MATTTODO: right now you can't buy more than one grenade. make it so you can
//buy more and query the number you have.
// HE Grenade
pGrenade = Weapon_OwnsThisType ( " weapon_hegrenade " ) ;
if ( pGrenade & & pGrenade - > GetPrimaryAmmoType ( ) ! = - 1 )
{
m_rebuyStruct . m_heGrenade = GetAmmoCount ( pGrenade - > GetPrimaryAmmoType ( ) ) ;
}
else
m_rebuyStruct . m_heGrenade = 0 ;
// flashbang
pGrenade = Weapon_OwnsThisType ( " weapon_flashbang " ) ;
if ( pGrenade & & pGrenade - > GetPrimaryAmmoType ( ) ! = - 1 )
{
m_rebuyStruct . m_flashbang = GetAmmoCount ( pGrenade - > GetPrimaryAmmoType ( ) ) ;
}
else
m_rebuyStruct . m_flashbang = 0 ;
// smokegrenade
pGrenade = Weapon_OwnsThisType ( " weapon_smokegrenade " ) ;
if ( pGrenade /*&& pGrenade->GetPrimaryAmmoType() != -1*/ )
{
m_rebuyStruct . m_smokeGrenade = 1 ; //GetAmmoCount(pGrenade->GetPrimaryAmmoType());
}
else
m_rebuyStruct . m_smokeGrenade = 0 ;
// defuser
m_rebuyStruct . m_defuser = HasDefuser ( ) ;
// night vision
m_rebuyStruct . m_nightVision = m_bHasNightVision . Get ( ) ; //cast to avoid strange compiler warning
// check for armor.
m_rebuyStruct . m_armor = ( m_bHasHelmet ? 2 : ( ArmorValue ( ) > 0 ? 1 : 0 ) ) ;
}
void CCSPlayer : : Rebuy ( void )
{
if ( ! IsInBuyZone ( ) )
{
EmitPrivateSound ( " BuyPreset.CantBuy " ) ;
return ;
}
const char * rebuyString = engine - > GetClientConVarValue ( engine - > IndexOfEdict ( edict ( ) ) , " cl_rebuy " ) ;
if ( ! rebuyString | | ! * rebuyString )
{
EmitPrivateSound ( " BuyPreset.AlreadyBought " ) ;
return ;
}
m_bIsInRebuy = true ;
BuyResult_e overallResult = BUY_ALREADY_HAVE ;
char token [ 256 ] ;
rebuyString = engine - > ParseFile ( rebuyString , token , sizeof ( token ) ) ;
while ( rebuyString ! = NULL )
{
BuyResult_e result = BUY_ALREADY_HAVE ;
if ( ! Q_strncmp ( token , " PrimaryWeapon " , 14 ) )
{
result = RebuyPrimaryWeapon ( ) ;
}
else if ( ! Q_strncmp ( token , " PrimaryAmmo " , 12 ) )
{
result = RebuyPrimaryAmmo ( ) ;
}
else if ( ! Q_strncmp ( token , " SecondaryWeapon " , 16 ) )
{
result = RebuySecondaryWeapon ( ) ;
}
else if ( ! Q_strncmp ( token , " SecondaryAmmo " , 14 ) )
{
result = RebuySecondaryAmmo ( ) ;
}
else if ( ! Q_strncmp ( token , " HEGrenade " , 10 ) )
{
result = RebuyHEGrenade ( ) ;
}
else if ( ! Q_strncmp ( token , " Flashbang " , 10 ) )
{
result = RebuyFlashbang ( ) ;
}
else if ( ! Q_strncmp ( token , " SmokeGrenade " , 13 ) )
{
result = RebuySmokeGrenade ( ) ;
}
else if ( ! Q_strncmp ( token , " Defuser " , 8 ) )
{
result = RebuyDefuser ( ) ;
}
else if ( ! Q_strncmp ( token , " NightVision " , 12 ) )
{
result = RebuyNightVision ( ) ;
}
else if ( ! Q_strncmp ( token , " Armor " , 6 ) )
{
result = RebuyArmor ( ) ;
}
overallResult = CombineBuyResults ( overallResult , result ) ;
rebuyString = engine - > ParseFile ( rebuyString , token , sizeof ( token ) ) ;
}
m_bIsInRebuy = false ;
// after we're done buying, the user is done with their equipment purchasing experience.
// so we are effectively out of the buy zone.
// if (TheTutor != NULL)
// {
// TheTutor->OnEvent(EVENT_PLAYER_LEFT_BUY_ZONE);
// }
m_bAutoReload = true ;
if ( overallResult = = BUY_CANT_AFFORD )
{
EmitPrivateSound ( " BuyPreset.CantBuy " ) ;
}
else if ( overallResult = = BUY_ALREADY_HAVE )
{
EmitPrivateSound ( " BuyPreset.AlreadyBought " ) ;
}
else if ( overallResult = = BUY_BOUGHT )
{
g_iReBuyPurchases + + ;
}
}
BuyResult_e CCSPlayer : : RebuyPrimaryWeapon ( )
{
CBaseCombatWeapon * primary = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
if ( primary ! = NULL )
{
return BUY_ALREADY_HAVE ; // don't drop primary weapons via rebuy - if the player picked up a different weapon, he wants to keep it.
}
if ( strlen ( m_rebuyStruct . m_szPrimaryWeapon ) > 0 )
return HandleCommand_Buy ( m_rebuyStruct . m_szPrimaryWeapon ) ;
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuySecondaryWeapon ( )
{
CBaseCombatWeapon * pistol = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( pistol ! = NULL & & ! m_bUsingDefaultPistol )
{
return BUY_ALREADY_HAVE ; // don't drop pistols via rebuy if we've bought one other than the default pistol
}
if ( strlen ( m_rebuyStruct . m_szSecondaryWeapon ) > 0 )
return HandleCommand_Buy ( m_rebuyStruct . m_szSecondaryWeapon ) ;
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuyPrimaryAmmo ( )
{
CBaseCombatWeapon * primary = Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ;
if ( primary = = NULL )
{
return BUY_ALREADY_HAVE ; // can't buy ammo when we don't even have a gun.
}
// Ensure that the weapon uses ammo
int nAmmo = primary - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
// if we had more ammo before than we have now, buy more.
if ( m_rebuyStruct . m_primaryAmmo > GetAmmoCount ( nAmmo ) )
{
return HandleCommand_Buy ( " primammo " ) ;
}
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuySecondaryAmmo ( )
{
CBaseCombatWeapon * secondary = Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ;
if ( secondary = = NULL )
{
return BUY_ALREADY_HAVE ; // can't buy ammo when we don't even have a gun.
}
// Ensure that the weapon uses ammo
int nAmmo = secondary - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
if ( m_rebuyStruct . m_secondaryAmmo > GetAmmoCount ( nAmmo ) )
{
return HandleCommand_Buy ( " secammo " ) ;
}
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuyHEGrenade ( )
{
CBaseCombatWeapon * pGrenade = Weapon_OwnsThisType ( " weapon_hegrenade " ) ;
int numGrenades = 0 ;
if ( pGrenade )
{
int nAmmo = pGrenade - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
numGrenades = GetAmmoCount ( nAmmo ) ;
}
BuyResult_e overallResult = BUY_ALREADY_HAVE ;
int numToBuy = MAX ( 0 , m_rebuyStruct . m_heGrenade - numGrenades ) ;
for ( int i = 0 ; i < numToBuy ; + + i )
{
BuyResult_e result = HandleCommand_Buy ( " hegrenade " ) ;
overallResult = CombineBuyResults ( overallResult , result ) ;
}
return overallResult ;
}
BuyResult_e CCSPlayer : : RebuyFlashbang ( )
{
CBaseCombatWeapon * pGrenade = Weapon_OwnsThisType ( " weapon_flashbang " ) ;
int numGrenades = 0 ;
if ( pGrenade )
{
int nAmmo = pGrenade - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
numGrenades = GetAmmoCount ( nAmmo ) ;
}
BuyResult_e overallResult = BUY_ALREADY_HAVE ;
int numToBuy = MAX ( 0 , m_rebuyStruct . m_flashbang - numGrenades ) ;
for ( int i = 0 ; i < numToBuy ; + + i )
{
BuyResult_e result = HandleCommand_Buy ( " flashbang " ) ;
overallResult = CombineBuyResults ( overallResult , result ) ;
}
return overallResult ;
}
BuyResult_e CCSPlayer : : RebuySmokeGrenade ( )
{
CBaseCombatWeapon * pGrenade = Weapon_OwnsThisType ( " weapon_smokegrenade " ) ;
int numGrenades = 0 ;
if ( pGrenade )
{
int nAmmo = pGrenade - > GetPrimaryAmmoType ( ) ;
if ( nAmmo = = - 1 )
{
return BUY_ALREADY_HAVE ;
}
numGrenades = GetAmmoCount ( nAmmo ) ;
}
BuyResult_e overallResult = BUY_ALREADY_HAVE ;
int numToBuy = MAX ( 0 , m_rebuyStruct . m_smokeGrenade - numGrenades ) ;
for ( int i = 0 ; i < numToBuy ; + + i )
{
BuyResult_e result = HandleCommand_Buy ( " smokegrenade " ) ;
overallResult = CombineBuyResults ( overallResult , result ) ;
}
return overallResult ;
}
BuyResult_e CCSPlayer : : RebuyDefuser ( )
{
//If we don't have a defuser, and we want one, buy it!
if ( ! HasDefuser ( ) & & m_rebuyStruct . m_defuser )
{
return HandleCommand_Buy ( " defuser " ) ;
}
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuyNightVision ( )
{
//if we don't have night vision and we want one, buy it!
if ( ! m_bHasNightVision & & m_rebuyStruct . m_nightVision )
{
return HandleCommand_Buy ( " nvgs " ) ;
}
return BUY_ALREADY_HAVE ;
}
BuyResult_e CCSPlayer : : RebuyArmor ( )
{
if ( m_rebuyStruct . m_armor > 0 )
{
int armor = 0 ;
if ( m_bHasHelmet )
armor = 2 ;
else if ( ArmorValue ( ) > 0 )
armor = 1 ;
if ( armor < m_rebuyStruct . m_armor )
{
if ( m_rebuyStruct . m_armor = = 1 )
{
return HandleCommand_Buy ( " vest " ) ;
}
else
{
return HandleCommand_Buy ( " vesthelm " ) ;
}
}
}
return BUY_ALREADY_HAVE ;
}
bool CCSPlayer : : IsUseableEntity ( CBaseEntity * pEntity , unsigned int requiredCaps )
{
CWeaponCSBase * pCSWepaon = dynamic_cast < CWeaponCSBase * > ( pEntity ) ;
if ( pCSWepaon )
{
// we can't USE dropped weapons
return true ;
}
CBaseCSGrenadeProjectile * pGrenade = dynamic_cast < CBaseCSGrenadeProjectile * > ( pEntity ) ;
if ( pGrenade )
{
// we can't USE thrown grenades
}
return BaseClass : : IsUseableEntity ( pEntity , requiredCaps ) ;
}
CBaseEntity * CCSPlayer : : FindUseEntity ( )
{
CBaseEntity * entity = NULL ;
// Check to see if the bomb is close enough to use before attempting to use anything else.
if ( CSGameRules ( ) - > IsBombDefuseMap ( ) & & GetTeamNumber ( ) = = TEAM_CT )
{
// This is done separately since there might be something blocking our LOS to it
// but we might want to use it anyway if it's close enough. This should eliminate
// the vast majority of bomb placement exploits (places where the bomb can be planted
// but can't be "used". This also mimics goldsrc cstrike behavior.
CBaseEntity * bomb = gEntList . FindEntityByClassname ( NULL , PLANTED_C4_CLASSNAME ) ;
if ( bomb ! = NULL )
{
Vector bombPos = bomb - > GetAbsOrigin ( ) ;
Vector vecLOS = EyePosition ( ) - bombPos ;
if ( vecLOS . LengthSqr ( ) < ( 96 * 96 ) ) // 64 is the distance in Goldsrc. However since Goldsrc did distance from the player's origin and we're doing distance from the player's eye, make the radius a bit bigger.
{
// bomb is close enough, now make sure the player is facing the bomb.
Vector forward ;
AngleVectors ( EyeAngles ( ) , & forward , NULL , NULL ) ;
vecLOS . NormalizeInPlace ( ) ;
float flDot = DotProduct ( forward , vecLOS ) ;
if ( flDot < - 0.7 ) // 0.7 taken from Goldsrc, +/- ~45 degrees
{
entity = bomb ;
}
}
}
}
if ( entity = = NULL )
{
entity = BaseClass : : FindUseEntity ( ) ;
}
return entity ;
}
void CCSPlayer : : StockPlayerAmmo ( CBaseCombatWeapon * pNewWeapon )
{
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( pNewWeapon ) ;
if ( pWeapon )
{
if ( pWeapon - > GetWpnData ( ) . iFlags & ITEM_FLAG_EXHAUSTIBLE )
return ;
int nAmmo = pWeapon - > GetPrimaryAmmoType ( ) ;
if ( nAmmo ! = - 1 )
{
GiveAmmo ( 9999 , GetAmmoDef ( ) - > GetAmmoOfIndex ( nAmmo ) - > pName ) ;
pWeapon - > m_iClip1 = pWeapon - > GetMaxClip1 ( ) ;
}
return ;
}
pWeapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ) ;
if ( pWeapon )
{
int nAmmo = pWeapon - > GetPrimaryAmmoType ( ) ;
if ( nAmmo ! = - 1 )
{
GiveAmmo ( 9999 , GetAmmoDef ( ) - > GetAmmoOfIndex ( nAmmo ) - > pName ) ;
pWeapon - > m_iClip1 = pWeapon - > GetMaxClip1 ( ) ;
}
}
pWeapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ) ;
if ( pWeapon )
{
int nAmmo = pWeapon - > GetPrimaryAmmoType ( ) ;
if ( nAmmo ! = - 1 )
{
GiveAmmo ( 9999 , GetAmmoDef ( ) - > GetAmmoOfIndex ( nAmmo ) - > pName ) ;
pWeapon - > m_iClip1 = pWeapon - > GetMaxClip1 ( ) ;
}
}
}
CBaseEntity * CCSPlayer : : GiveNamedItem ( const char * pszName , int iSubType )
{
EHANDLE pent ;
if ( ! pszName | | ! pszName [ 0 ] )
return NULL ;
# ifndef CS_SHIELD_ENABLED
if ( ! Q_stricmp ( pszName , " weapon_shield " ) )
return NULL ;
# endif
pent = CreateEntityByName ( pszName ) ;
if ( pent = = NULL )
{
Msg ( " NULL Ent in GiveNamedItem! \n " ) ;
return NULL ;
}
pent - > SetLocalOrigin ( GetLocalOrigin ( ) ) ;
pent - > AddSpawnFlags ( SF_NORESPAWN ) ;
CBaseCombatWeapon * pWeapon = dynamic_cast < CBaseCombatWeapon * > ( ( CBaseEntity * ) pent ) ;
if ( pWeapon )
{
if ( iSubType )
{
pWeapon - > SetSubType ( iSubType ) ;
}
}
DispatchSpawn ( pent ) ;
m_bIsBeingGivenItem = true ;
if ( pent ! = NULL & & ! ( pent - > IsMarkedForDeletion ( ) ) )
{
pent - > Touch ( this ) ;
}
m_bIsBeingGivenItem = false ;
StockPlayerAmmo ( pWeapon ) ;
return pent ;
}
void CCSPlayer : : DoAnimationEvent ( PlayerAnimEvent_t event , int nData )
{
if ( event = = PLAYERANIMEVENT_THROW_GRENADE )
{
// Grenade throwing has to synchronize exactly with the player's grenade weapon going away,
// and events get delayed a bit, so we let CCSPlayerAnimState pickup the change to this
// variable.
m_iThrowGrenadeCounter = ( m_iThrowGrenadeCounter + 1 ) % ( 1 < < THROWGRENADE_COUNTER_BITS ) ;
}
else
{
m_PlayerAnimState - > DoAnimationEvent ( event , nData ) ;
TE_PlayerAnimEvent ( this , event , nData ) ; // Send to any clients who can see this guy.
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CCSPlayer : : FlashlightIsOn ( void )
{
return IsEffectActive ( EF_DIMLIGHT ) ;
}
extern ConVar flashlight ;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CCSPlayer : : FlashlightTurnOn ( void )
{
if ( flashlight . GetInt ( ) > 0 & & IsAlive ( ) )
{
AddEffects ( EF_DIMLIGHT ) ;
EmitSound ( " Player.FlashlightOn " ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CCSPlayer : : FlashlightTurnOff ( void )
{
RemoveEffects ( EF_DIMLIGHT ) ;
if ( IsAlive ( ) )
{
EmitSound ( " Player.FlashlightOff " ) ;
}
}
//Drop the appropriate weapons:
// Defuser if we have one
// C4 if we have one
// The best weapon we have, first check primary,
// then secondary and drop the best one
//=============================================================================
// HPE_BEGIN:
// [tj] Added a parameter so we know if it was death that caused the drop
// [menglish] Clear all previously dropped equipment and add the c4 to the dropped equipment
//=============================================================================
void CCSPlayer : : DropWeapons ( bool fromDeath , bool friendlyFire )
{
for ( int i = 0 ; i < DROPPED_COUNT ; + + i )
{
m_hDroppedEquipment [ i ] = NULL ;
}
CBaseCombatWeapon * pC4 = Weapon_OwnsThisType ( " weapon_c4 " ) ;
if ( pC4 )
{
CSWeaponDrop ( pC4 , false , true ) ;
if ( fromDeath )
{
if ( friendlyFire )
{
( static_cast < CC4 * > ( pC4 ) ) - > SetDroppedFromDeath ( true ) ;
}
m_hDroppedEquipment [ DROPPED_C4 ] = static_cast < CBaseEntity * > ( pC4 ) ;
}
}
//NOTE: Function continues beyond comment block. This is just the part I touched.
//=============================================================================
// HPE_END
//=============================================================================
if ( HasDefuser ( ) )
{
//Drop an item_defuser
Vector vForward , vRight ;
AngleVectors ( GetAbsAngles ( ) , & vForward , & vRight , NULL ) ;
CBaseAnimating * pDefuser = ( CBaseAnimating * ) CBaseEntity : : Create ( " item_defuser " , WorldSpaceCenter ( ) , GetLocalAngles ( ) , this ) ;
pDefuser - > ApplyAbsVelocityImpulse ( vForward * 200 + vRight * random - > RandomFloat ( - 50 , 50 ) ) ;
RemoveDefuser ( ) ;
//=============================================================================
// HPE_BEGIN:
// [menglish] Add the newly created defuser to the dropped equipment list
//=============================================================================
if ( fromDeath )
{
m_hDroppedEquipment [ DROPPED_DEFUSE ] = static_cast < CBaseEntity * > ( pDefuser ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
}
if ( HasShield ( ) )
{
DropShield ( ) ;
}
else
{
//drop the best weapon we have
if ( ! DropRifle ( true ) )
DropPistol ( true ) ;
}
// drop any live grenades so they explode
CBaseCSGrenade * pGrenade = dynamic_cast < CBaseCSGrenade * > ( Weapon_OwnsThisType ( " weapon_hegrenade " ) ) ;
if ( pGrenade & & ( pGrenade - > IsPinPulled ( ) | | pGrenade - > IsBeingThrown ( ) ) )
{
pGrenade - > DropGrenade ( ) ;
pGrenade - > DecrementAmmo ( this ) ;
}
else
{
pGrenade = dynamic_cast < CBaseCSGrenade * > ( Weapon_OwnsThisType ( " weapon_flashbang " ) ) ;
if ( pGrenade & & ( pGrenade - > IsPinPulled ( ) | | pGrenade - > IsBeingThrown ( ) ) )
{
pGrenade - > DropGrenade ( ) ;
pGrenade - > DecrementAmmo ( this ) ;
}
else
{
pGrenade = dynamic_cast < CBaseCSGrenade * > ( Weapon_OwnsThisType ( " weapon_smokegrenade " ) ) ;
if ( pGrenade & & ( pGrenade - > IsPinPulled ( ) | | pGrenade - > IsBeingThrown ( ) ) )
{
pGrenade - > DropGrenade ( ) ;
pGrenade - > DecrementAmmo ( this ) ;
}
}
}
// drop the "best" grenade remaining
CBaseCombatWeapon * pWeapon = Weapon_OwnsThisType ( " weapon_hegrenade " ) ;
bool grenadeDrop = false ;
if ( pWeapon & & pWeapon - > HasAmmo ( ) )
{
grenadeDrop = CSWeaponDrop ( pWeapon , false ) ;
}
else
{
pWeapon = Weapon_OwnsThisType ( " weapon_flashbang " ) ;
if ( pWeapon & & pWeapon - > HasAmmo ( ) )
{
grenadeDrop = CSWeaponDrop ( pWeapon , false ) ;
}
else
{
pWeapon = Weapon_OwnsThisType ( " weapon_smokegrenade " ) ;
if ( pWeapon & & pWeapon - > HasAmmo ( ) )
{
grenadeDrop = CSWeaponDrop ( pWeapon , false ) ;
}
}
}
//=============================================================================
// HPE_BEGIN:
// [menglish] Add whichever, if any, grenade was dropped
//=============================================================================
if ( pWeapon & & grenadeDrop )
{
m_hDroppedEquipment [ DROPPED_GRENADE ] = static_cast < CBaseEntity * > ( pWeapon ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
}
//-----------------------------------------------------------------------------
// Purpose: Put the player in the specified team
//-----------------------------------------------------------------------------
void CCSPlayer : : ChangeTeam ( int iTeamNum )
{
if ( ! GetGlobalTeam ( iTeamNum ) )
{
Warning ( " CCSPlayer::ChangeTeam( %d ) - invalid team index. \n " , iTeamNum ) ;
return ;
}
int iOldTeam = GetTeamNumber ( ) ;
// if this is our current team, just abort
if ( iTeamNum = = iOldTeam )
return ;
//=============================================================================
// HPE_BEGIN:
//=============================================================================
// [tj] Added a parameter so we know if it was death that caused the drop
// Drop Our best weapon
DropWeapons ( false , false ) ;
// [tj] Clear out dominations
RemoveNemesisRelationships ( ) ;
//=============================================================================
// HPE_END
//=============================================================================
// Always allow a change to spectator, and don't count it as one of our team changes.
// We now store the old team, so if a player changes once to one team, then to spectator,
// they won't be able to change back to their old old team, but will still be able to join
// the team they initially changed to.
if ( iTeamNum ! = TEAM_SPECTATOR )
{
m_bTeamChanged = true ;
}
else
{
m_iOldTeam = iOldTeam ;
}
// do the team change:
BaseClass : : ChangeTeam ( iTeamNum ) ;
//reset class
m_iClass = ( int ) CS_CLASS_NONE ;
// update client state
if ( iTeamNum = = TEAM_UNASSIGNED )
{
State_Transition ( STATE_OBSERVER_MODE ) ;
}
else if ( iTeamNum = = TEAM_SPECTATOR )
{
//=============================================================================
// HPE_BEGIN:
// [tj] Removed these lines so players keep their money when switching to spectator.
//=============================================================================
//Reset money
//m_iAccount = 0;
//=============================================================================
// HPE_END
//=============================================================================
RemoveAllItems ( true ) ;
State_Transition ( STATE_OBSERVER_MODE ) ;
}
else // active player
{
if ( iOldTeam = = TEAM_SPECTATOR )
{
// If they're switching from being a spectator to ingame player
//=============================================================================
// HPE_BEGIN:
// [tj] Changed this so players either retain their existing money or,
// if they have less than the default, give them the default.
//=============================================================================
int startMoney = CSGameRules ( ) - > GetStartMoney ( ) ;
if ( startMoney > m_iAccount )
{
m_iAccount = startMoney ;
}
//=============================================================================
// HPE_END
//=============================================================================
}
// bots get to this state on TEAM_UNASSIGNED, yet they are marked alive. Don't kill them.
else if ( iOldTeam ! = TEAM_UNASSIGNED & & ! IsDead ( ) )
{
// Kill player if switching teams while alive
CommitSuicide ( ) ;
}
// Put up the class selection menu.
State_Transition ( STATE_PICKINGCLASS ) ;
}
// Initialize the player counts now that a player has switched teams
int NumDeadCT , NumDeadTerrorist , NumAliveTerrorist , NumAliveCT ;
CSGameRules ( ) - > InitializePlayerCounts ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Put the player in the specified team without penalty
//-----------------------------------------------------------------------------
void CCSPlayer : : SwitchTeam ( int iTeamNum )
{
if ( ! GetGlobalTeam ( iTeamNum ) | | ( iTeamNum ! = TEAM_CT & & iTeamNum ! = TEAM_TERRORIST ) )
{
Warning ( " CCSPlayer::SwitchTeam( %d ) - invalid team index. \n " , iTeamNum ) ;
return ;
}
int iOldTeam = GetTeamNumber ( ) ;
// if this is our current team, just abort
if ( iTeamNum = = iOldTeam )
return ;
// Always allow a change to spectator, and don't count it as one of our team changes.
// We now store the old team, so if a player changes once to one team, then to spectator,
// they won't be able to change back to their old old team, but will still be able to join
// the team they initially changed to.
m_bTeamChanged = true ;
// do the team change:
BaseClass : : ChangeTeam ( iTeamNum ) ;
if ( HasDefuser ( ) )
{
RemoveDefuser ( ) ;
}
//reset class
switch ( m_iClass )
{
// Terrorist -> CT
case CS_CLASS_PHOENIX_CONNNECTION :
m_iClass = ( int ) CS_CLASS_SEAL_TEAM_6 ;
break ;
case CS_CLASS_L337_KREW :
m_iClass = ( int ) CS_CLASS_GSG_9 ;
break ;
case CS_CLASS_ARCTIC_AVENGERS :
m_iClass = ( int ) CS_CLASS_SAS ;
break ;
case CS_CLASS_GUERILLA_WARFARE :
m_iClass = ( int ) CS_CLASS_GIGN ;
break ;
// CT -> Terrorist
case CS_CLASS_SEAL_TEAM_6 :
m_iClass = ( int ) CS_CLASS_PHOENIX_CONNNECTION ;
break ;
case CS_CLASS_GSG_9 :
m_iClass = ( int ) CS_CLASS_L337_KREW ;
break ;
case CS_CLASS_SAS :
m_iClass = ( int ) CS_CLASS_ARCTIC_AVENGERS ;
break ;
case CS_CLASS_GIGN :
m_iClass = ( int ) CS_CLASS_GUERILLA_WARFARE ;
break ;
case CS_CLASS_NONE :
default :
break ;
}
// Initialize the player counts now that a player has switched teams
int NumDeadCT , NumDeadTerrorist , NumAliveTerrorist , NumAliveCT ;
CSGameRules ( ) - > InitializePlayerCounts ( NumAliveTerrorist , NumAliveCT , NumDeadTerrorist , NumDeadCT ) ;
}
void CCSPlayer : : ModifyOrAppendPlayerCriteria ( AI_CriteriaSet & set )
{
// this is for giving player info to the hostage response system
// and is as yet unused.
// Eventually we could give the hostage a few tidbits about this player,
// eg their health, what weapons they have, and the hostage could
// comment accordingly.
//do not append any player data to the Criteria!
//we don't know which player we should be caring about
}
static unsigned int s_BulletGroupCounter = 0 ;
void CCSPlayer : : StartNewBulletGroup ( )
{
s_BulletGroupCounter + + ;
}
//=======================================================
// Remember this amount of damage that we dealt for stats
//=======================================================
void CCSPlayer : : RecordDamageGiven ( const char * szDamageTaker , int iDamageGiven )
{
FOR_EACH_LL ( m_DamageGivenList , i )
{
if ( Q_strncmp ( szDamageTaker , m_DamageGivenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 )
{
m_DamageGivenList [ i ] - > AddDamage ( iDamageGiven , s_BulletGroupCounter ) ;
return ;
}
}
CDamageRecord * record = new CDamageRecord ( szDamageTaker , iDamageGiven , s_BulletGroupCounter ) ;
int k = m_DamageGivenList . AddToTail ( ) ;
m_DamageGivenList [ k ] = record ;
}
//=======================================================
// Remember this amount of damage that we took for stats
//=======================================================
void CCSPlayer : : RecordDamageTaken ( const char * szDamageDealer , int iDamageTaken )
{
FOR_EACH_LL ( m_DamageTakenList , i )
{
if ( Q_strncmp ( szDamageDealer , m_DamageTakenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 )
{
m_DamageTakenList [ i ] - > AddDamage ( iDamageTaken , s_BulletGroupCounter ) ;
return ;
}
}
CDamageRecord * record = new CDamageRecord ( szDamageDealer , iDamageTaken , s_BulletGroupCounter ) ;
int k = m_DamageTakenList . AddToTail ( ) ;
m_DamageTakenList [ k ] = record ;
}
//=======================================================
// Reset our damage given and taken counters
//=======================================================
void CCSPlayer : : ResetDamageCounters ( )
{
m_DamageGivenList . PurgeAndDeleteElements ( ) ;
m_DamageTakenList . PurgeAndDeleteElements ( ) ;
}
//=======================================================
// Output the damage that we dealt to other players
//=======================================================
void CCSPlayer : : OutputDamageTaken ( void )
{
bool bPrintHeader = true ;
CDamageRecord * pRecord ;
char buf [ 64 ] ;
int msg_dest = HUD_PRINTCONSOLE ;
FOR_EACH_LL ( m_DamageTakenList , i )
{
if ( bPrintHeader )
{
ClientPrint ( this , msg_dest , " Player: %s1 - Damage Taken \n " , GetPlayerName ( ) ) ;
ClientPrint ( this , msg_dest , " ------------------------- \n " ) ;
bPrintHeader = false ;
}
pRecord = m_DamageTakenList [ i ] ;
if ( pRecord )
{
if ( pRecord - > GetNumHits ( ) = = 1 )
{
Q_snprintf ( buf , sizeof ( buf ) , " %d in %d hit " , pRecord - > GetDamage ( ) , pRecord - > GetNumHits ( ) ) ;
}
else
{
Q_snprintf ( buf , sizeof ( buf ) , " %d in %d hits " , pRecord - > GetDamage ( ) , pRecord - > GetNumHits ( ) ) ;
}
ClientPrint ( this , msg_dest , " Damage Taken from \" %s1 \" - %s2 \n " , pRecord - > GetPlayerName ( ) , buf ) ;
}
}
}
//=======================================================
// Output the damage that we took from other players
//=======================================================
void CCSPlayer : : OutputDamageGiven ( void )
{
bool bPrintHeader = true ;
CDamageRecord * pRecord ;
char buf [ 64 ] ;
int msg_dest = HUD_PRINTCONSOLE ;
FOR_EACH_LL ( m_DamageGivenList , i )
{
if ( bPrintHeader )
{
ClientPrint ( this , msg_dest , " Player: %s1 - Damage Given \n " , GetPlayerName ( ) ) ;
ClientPrint ( this , msg_dest , " ------------------------- \n " ) ;
bPrintHeader = false ;
}
pRecord = m_DamageGivenList [ i ] ;
if ( pRecord )
{
if ( pRecord - > GetNumHits ( ) = = 1 )
{
Q_snprintf ( buf , sizeof ( buf ) , " %d in %d hit " , pRecord - > GetDamage ( ) , pRecord - > GetNumHits ( ) ) ;
}
else
{
Q_snprintf ( buf , sizeof ( buf ) , " %d in %d hits " , pRecord - > GetDamage ( ) , pRecord - > GetNumHits ( ) ) ;
}
ClientPrint ( this , msg_dest , " Damage Given to \" %s1 \" - %s2 \n " , pRecord - > GetPlayerName ( ) , buf ) ;
}
}
}
void CCSPlayer : : 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 CCSPlayer : : HasC4 ( ) const
{
return ( Weapon_OwnsThisType ( " weapon_c4 " ) ! = NULL ) ;
}
int CCSPlayer : : GetNextObserverSearchStartPoint ( bool bReverse )
{
// If we are currently watching someone who is dead, they must have died while we were watching (since
// a dead guy is not a valid pick to start watching). He was given his killer as an observer target
// when he died, so let's start by trying to observe his killer. If we fail, we'll use the normal way.
// And this is just the start point anyway, but we want to start the search here in case it is okay.
if ( m_hObserverTarget & & ! m_hObserverTarget - > IsAlive ( ) )
{
CCSPlayer * targetPlayer = ToCSPlayer ( m_hObserverTarget ) ;
if ( targetPlayer & & targetPlayer - > GetObserverTarget ( ) )
return targetPlayer - > GetObserverTarget ( ) - > entindex ( ) ;
}
return BaseClass : : GetNextObserverSearchStartPoint ( bReverse ) ;
}
void CCSPlayer : : PlayStepSound ( Vector & vecOrigin , surfacedata_t * psurface , float fvol , bool force )
{
BaseClass : : PlayStepSound ( vecOrigin , psurface , fvol , force ) ;
if ( ! sv_footsteps . GetFloat ( ) )
return ;
if ( ! psurface )
return ;
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_footstep " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
gameeventmanager - > FireEvent ( event ) ;
}
m_bMadeFootstepNoise = true ;
}
void CCSPlayer : : SelectDeathPose ( const CTakeDamageInfo & info )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
if ( ! GetModelPtr ( ) )
return ;
Activity aActivity = ACT_INVALID ;
int iDeathFrame = 0 ;
SelectDeathPoseActivityAndFrame ( this , info , m_LastHitGroup , aActivity , iDeathFrame ) ;
if ( aActivity = = ACT_INVALID )
{
SetDeathPose ( ACT_INVALID ) ;
SetDeathPoseFrame ( 0 ) ;
return ;
}
SetDeathPose ( SelectWeightedSequence ( aActivity ) ) ;
SetDeathPoseFrame ( iDeathFrame ) ;
}
void CCSPlayer : : HandleAnimEvent ( animevent_t * pEvent )
{
if ( pEvent - > event = = 4001 | | pEvent - > event = = 4002 )
{
// Ignore these for now - soon we will be playing footstep sounds based on these events
// that mark footfalls in the anims.
}
else
{
BaseClass : : HandleAnimEvent ( pEvent ) ;
}
}
bool CCSPlayer : : CanChangeName ( void )
{
if ( IsBot ( ) )
return true ;
// enforce the minimum interval
if ( ( m_flNameChangeHistory [ 0 ] + MIN_NAME_CHANGE_INTERVAL ) > = gpGlobals - > curtime )
{
return false ;
}
// enforce that we dont do more than NAME_CHANGE_HISTORY_SIZE
// changes within NAME_CHANGE_HISTORY_INTERVAL
if ( ( m_flNameChangeHistory [ NAME_CHANGE_HISTORY_SIZE - 1 ] + NAME_CHANGE_HISTORY_INTERVAL ) > = gpGlobals - > curtime )
{
return false ;
}
return true ;
}
void CCSPlayer : : ChangeName ( const char * pszNewName )
{
// make sure name is not too long
char trimmedName [ MAX_PLAYER_NAME_LENGTH ] ;
Q_strncpy ( trimmedName , pszNewName , sizeof ( trimmedName ) ) ;
const char * pszOldName = GetPlayerName ( ) ;
// send colored message to everyone
CReliableBroadcastRecipientFilter filter ;
UTIL_SayText2Filter ( filter , this , false , " #Cstrike_Name_Change " , pszOldName , trimmedName ) ;
// broadcast event
IGameEvent * event = gameeventmanager - > CreateEvent ( " player_changename " ) ;
if ( event )
{
event - > SetInt ( " userid " , GetUserID ( ) ) ;
event - > SetString ( " oldname " , pszOldName ) ;
event - > SetString ( " newname " , trimmedName ) ;
gameeventmanager - > FireEvent ( event ) ;
}
// change shared player name
SetPlayerName ( trimmedName ) ;
// tell engine to use new name
engine - > ClientCommand ( edict ( ) , " name \" %s \" " , trimmedName ) ;
// remember time of name change
for ( int i = NAME_CHANGE_HISTORY_SIZE - 1 ; i > 0 ; i - - )
{
m_flNameChangeHistory [ i ] = m_flNameChangeHistory [ i - 1 ] ;
}
m_flNameChangeHistory [ 0 ] = gpGlobals - > curtime ; // last change
}
bool CCSPlayer : : StartReplayMode ( float fDelay , float fDuration , int iEntity )
{
if ( ! BaseClass : : StartReplayMode ( fDelay , fDuration , iEntity ) )
return false ;
CSingleUserRecipientFilter filter ( this ) ;
filter . MakeReliable ( ) ;
UserMessageBegin ( filter , " KillCam " ) ;
WRITE_BYTE ( OBS_MODE_IN_EYE ) ;
if ( m_hObserverTarget . Get ( ) )
{
WRITE_BYTE ( m_hObserverTarget . Get ( ) - > entindex ( ) ) ; // first target
WRITE_BYTE ( entindex ( ) ) ; //second target
}
else
{
WRITE_BYTE ( entindex ( ) ) ; // first target
WRITE_BYTE ( 0 ) ; //second target
}
MessageEnd ( ) ;
ClientPrint ( this , HUD_PRINTCENTER , " Kill Cam Replay " ) ;
return true ;
}
void CCSPlayer : : StopReplayMode ( )
{
BaseClass : : StopReplayMode ( ) ;
CSingleUserRecipientFilter filter ( this ) ;
filter . MakeReliable ( ) ;
UserMessageBegin ( filter , " KillCam " ) ;
WRITE_BYTE ( OBS_MODE_NONE ) ;
WRITE_BYTE ( 0 ) ;
WRITE_BYTE ( 0 ) ;
MessageEnd ( ) ;
}
void CCSPlayer : : PlayUseDenySound ( )
{
// Don't do a sound here because it can mute your footsteps giving you an advantage.
// The CS:S content for this sound is silent anyways.
//EmitSound( "Player.UseDeny" );
}
//=============================================================================
// HPE_BEGIN:
//=============================================================================
// [menglish, tj] This is where we reset all the per-round information for achievements for this player
void CCSPlayer : : ResetRoundBasedAchievementVariables ( )
{
m_KillingSpreeStartTime = - 1 ;
int numCTPlayers = 0 , numTPlayers = 0 ;
for ( int i = 0 ; i < g_Teams . Count ( ) ; i + + )
{
if ( g_Teams [ i ] )
{
if ( g_Teams [ i ] - > GetTeamNumber ( ) = = TEAM_CT )
numCTPlayers = g_Teams [ i ] - > GetNumPlayers ( ) ;
else if ( g_Teams [ i ] - > GetTeamNumber ( ) = = TEAM_TERRORIST )
numTPlayers = g_Teams [ i ] - > GetNumPlayers ( ) ;
}
}
m_NumEnemiesKilledThisRound = 0 ;
if ( GetTeamNumber ( ) = = TEAM_CT )
m_NumEnemiesAtRoundStart = numTPlayers ;
else if ( GetTeamNumber ( ) = = TEAM_TERRORIST )
m_NumEnemiesAtRoundStart = numCTPlayers ;
//Clear the previous owner field for currently held weapons
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_RIFLE ) ) ;
if ( pWeapon )
{
pWeapon - > SetPreviousOwner ( NULL ) ;
}
pWeapon = dynamic_cast < CWeaponCSBase * > ( Weapon_GetSlot ( WEAPON_SLOT_PISTOL ) ) ;
if ( pWeapon )
{
pWeapon - > SetPreviousOwner ( NULL ) ;
}
//Clear list of weapons used to get kills
m_killWeapons . RemoveAll ( ) ;
//Clear sliding window of kill times
m_killTimes . RemoveAll ( ) ;
//clear round kills
m_enemyPlayersKilledThisRound . RemoveAll ( ) ;
m_killsWhileBlind = 0 ;
m_bSurvivedHeadshotDueToHelmet = false ;
m_gooseChaseStep = GC_NONE ;
m_defuseDefenseStep = DD_NONE ;
m_pGooseChaseDistractingPlayer = NULL ;
m_bMadeFootstepNoise = false ;
m_bombPickupTime = - 1 ;
m_bMadePurchseThisRound = false ;
m_bKilledDefuser = false ;
m_bKilledRescuer = false ;
m_maxGrenadeKills = 0 ;
m_grenadeDamageTakenThisRound = 0 ;
//=============================================================================
// HPE_BEGIN:
// [dwenger] Needed for fun-fact implementation
//=============================================================================
WieldingKnifeAndKilledByGun ( false ) ;
m_WeaponTypesUsed . RemoveAll ( ) ;
m_bPickedUpDefuser = false ;
m_bDefusedWithPickedUpKit = false ;
//=============================================================================
// HPE_END
//=============================================================================
}
/**
* static public CCSPlayer : : GetCSWeaponIDCausingDamage ( )
*
* Helper function to get the ID of the weapon used to kill a player .
* This is slightly non - trivial because the grenade because a separate
* entity when thrown .
*
* Parameters :
* info -
*
* Returns :
* int -
*/
CSWeaponID CCSPlayer : : GetWeaponIdCausingDamange ( const CTakeDamageInfo & info )
{
CBaseEntity * pInflictor = info . GetInflictor ( ) ;
CCSPlayer * pAttacker = ToCSPlayer ( info . GetAttacker ( ) ) ;
if ( pAttacker = = pInflictor )
{
CWeaponCSBase * pAttackerWeapon = dynamic_cast < CWeaponCSBase * > ( pAttacker - > GetActiveWeapon ( ) ) ;
if ( ! pAttackerWeapon )
return WEAPON_NONE ;
return pAttackerWeapon - > GetWeaponID ( ) ;
}
else if ( pInflictor & & V_strcmp ( pInflictor - > GetClassname ( ) , " hegrenade_projectile " ) = = 0 )
{
return WEAPON_HEGRENADE ;
}
return WEAPON_NONE ;
}
//=============================================================================
// HPE_BEGIN:
// [dwenger] adding tracking for weapon used fun fact
//=============================================================================
void CCSPlayer : : PlayerUsedFirearm ( CBaseCombatWeapon * pBaseWeapon )
{
if ( pBaseWeapon )
{
CWeaponCSBase * pWeapon = dynamic_cast < CWeaponCSBase * > ( pBaseWeapon ) ;
if ( pWeapon )
{
CSWeaponType weaponType = pWeapon - > GetCSWpnData ( ) . m_WeaponType ;
CSWeaponID weaponID = pWeapon - > GetWeaponID ( ) ;
if ( weaponType ! = WEAPONTYPE_KNIFE & & weaponType ! = WEAPONTYPE_C4 & & weaponType ! = WEAPONTYPE_GRENADE )
{
if ( m_WeaponTypesUsed . Find ( weaponID ) = = - 1 )
{
// Add this weapon to the list of weapons used by the player
m_WeaponTypesUsed . AddToTail ( weaponID ) ;
}
}
}
}
}
/**
* public CCSPlayer : : ProcessPlayerDeathAchievements ( )
*
* Do Achievement processing whenever a player is killed
*
* Parameters :
* pAttacker -
* pVictim -
* info -
*/
void CCSPlayer : : ProcessPlayerDeathAchievements ( CCSPlayer * pAttacker , CCSPlayer * pVictim , const CTakeDamageInfo & info )
{
Assert ( pVictim ! = NULL ) ;
CBaseEntity * pInflictor = info . GetInflictor ( ) ;
// all these achievements require a valid attacker on a different team
if ( pAttacker ! = NULL & & pVictim ! = NULL & & pVictim - > GetTeamNumber ( ) ! = pAttacker - > GetTeamNumber ( ) )
{
// get the weapon used - some of the achievements will need this data
CWeaponCSBase * pAttackerWeapon = dynamic_cast < CWeaponCSBase * > ( pAttacker - > GetActiveWeapon ( ) ) ;
//=============================================================================
// HPE_BEGIN:
// [dwenger] Fun-fact processing
//=============================================================================
CWeaponCSBase * pVictimWeapon = dynamic_cast < CWeaponCSBase * > ( pVictim - > GetActiveWeapon ( ) ) ;
//=============================================================================
// HPE_END
//=============================================================================
CSWeaponID attackerWeaponId = GetWeaponIdCausingDamange ( info ) ;
if ( pVictim - > m_bIsDefusing )
{
pAttacker - > AwardAchievement ( CSKilledDefuser ) ;
pAttacker - > m_bKilledDefuser = true ;
if ( attackerWeaponId = = WEAPON_HEGRENADE )
{
pAttacker - > AwardAchievement ( CSKilledDefuserWithGrenade ) ;
}
}
// [pfreese] Achievement check for attacker killing player while reloading
if ( pVictim - > IsReloading ( ) )
{
pAttacker - > AwardAchievement ( CSKillEnemyReloading ) ;
}
if ( pVictim - > IsRescuing ( ) )
{
// Ensure the killer did not injure any hostages
if ( ! pAttacker - > InjuredAHostage ( ) & & pVictim - > GetNumFollowers ( ) = = g_Hostages . Count ( ) )
{
pAttacker - > AwardAchievement ( CSKilledRescuer ) ;
pAttacker - > m_bKilledRescuer = true ;
}
}
// [menglish] Achievement check for doing 95% or more damage to a player and having another player kill them
FOR_EACH_LL ( pVictim - > m_DamageTakenList , i )
{
if ( pVictim - > m_DamageTakenList [ i ] - > GetDamage ( ) > = pVictim - > GetMaxHealth ( ) - AchievementConsts : : DamageNoKill_MaxHealthLeftOnKill & &
Q_strncmp ( pAttacker - > GetPlayerName ( ) , pVictim - > m_DamageTakenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) ! = 0 )
{
//Now find the player who did that amount of damage
for ( int j = 1 ; j < = MAX_PLAYERS ; j + + )
{
CBasePlayer * pPlayerIter = UTIL_PlayerByIndex ( j ) ;
if ( pPlayerIter & & Q_strncmp ( pPlayerIter - > GetPlayerName ( ) , pVictim - > m_DamageTakenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 & &
pPlayerIter - > GetTeamNumber ( ) ! = pVictim - > GetTeamNumber ( ) )
{
ToCSPlayer ( pPlayerIter ) - > AwardAchievement ( CSDamageNoKill ) ;
break ;
}
}
}
}
pAttacker - > m_NumEnemiesKilledThisRound + + ;
//store a list of kill times for spree tracking
pAttacker - > m_killTimes . AddToTail ( gpGlobals - > curtime ) ;
//Add the victim to the list of players killed this round
pAttacker - > m_enemyPlayersKilledThisRound . AddToTail ( pVictim ) ;
//Calculate Avenging for all players the victim has killed
for ( int avengedIndex = 0 ; avengedIndex < pVictim - > m_enemyPlayersKilledThisRound . Count ( ) ; avengedIndex + + )
{
CCSPlayer * avengedPlayer = pVictim - > m_enemyPlayersKilledThisRound [ avengedIndex ] ;
if ( avengedPlayer )
{
//Make sure you are avenging someone on your own team (This is the expected flow. Just here to avoid edge cases like team-switching).
if ( pAttacker - > GetTeamNumber ( ) = = avengedPlayer - > GetTeamNumber ( ) )
{
CCS_GameStats . Event_PlayerAvengedTeammate ( pAttacker , pVictim - > m_enemyPlayersKilledThisRound [ avengedIndex ] ) ;
}
}
}
//remove elements older than a certain time
while ( pAttacker - > m_killTimes . Count ( ) > 0 & & pAttacker - > m_killTimes [ 0 ] + AchievementConsts : : KillingSpree_WindowTime < gpGlobals - > curtime )
{
pAttacker - > m_killTimes . Remove ( 0 ) ;
}
//If we killed enough players in the time window, award the achievement
if ( pAttacker - > m_killTimes . Count ( ) > = AchievementConsts : : KillingSpree_Kills )
{
pAttacker - > m_KillingSpreeStartTime = gpGlobals - > curtime ;
pAttacker - > AwardAchievement ( CSKillingSpree ) ;
}
// Did the attacker just kill someone on a killing spree?
if ( pVictim - > m_KillingSpreeStartTime > = 0 & & pVictim - > m_KillingSpreeStartTime - gpGlobals - > curtime < = AchievementConsts : : KillingSpreeEnder_TimeWindow )
{
pAttacker - > AwardAchievement ( CSKillingSpreeEnder ) ;
}
//Check the "killed someone with their own weapon" achievement
if ( pAttackerWeapon & & pAttackerWeapon - > GetPreviousOwner ( ) = = pVictim )
{
pAttacker - > AwardAchievement ( CSKillEnemyWithFormerGun ) ;
}
//If this player has killed the entire team award him the achievement
if ( pAttacker - > m_NumEnemiesKilledThisRound = = pAttacker - > m_NumEnemiesAtRoundStart & & pAttacker - > m_NumEnemiesKilledThisRound > = AchievementConsts : : KillEnemyTeam_MinKills )
{
pAttacker - > AwardAchievement ( CSKillEnemyTeam ) ;
}
//If this is a posthumous kill award the achievement
if ( ! pAttacker - > IsAlive ( ) & & attackerWeaponId = = WEAPON_HEGRENADE )
{
CCS_GameStats . IncrementStat ( pAttacker , CSSTAT_GRENADE_POSTHUMOUSKILLS , 1 ) ;
ToCSPlayer ( pAttacker ) - > AwardAchievement ( CSPosthumousGrenadeKill ) ;
}
if ( pAttacker - > GetActiveWeapon ( ) & & pAttacker - > GetActiveWeapon ( ) - > Clip1 ( ) = = 0 & & pAttackerWeapon & & pAttackerWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_SNIPER_RIFLE )
{
if ( pInflictor = = pAttacker )
{
pAttacker - > AwardAchievement ( CSKillEnemyLastBullet ) ;
CCS_GameStats . IncrementStat ( pAttacker , CSSTAT_KILLS_WITH_LAST_ROUND , 1 ) ;
}
}
//=============================================================================
// HPE_BEGIN:
// [dwenger] Fun-fact processing
//=============================================================================
if ( pVictimWeapon & & pVictimWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_KNIFE & & pAttackerWeapon & &
pAttackerWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_KNIFE & & pAttackerWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_C4 & & pAttackerWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_GRENADE )
{
// Victim was wielding knife when killed by a gun
pVictim - > WieldingKnifeAndKilledByGun ( true ) ;
}
//=============================================================================
// HPE_END
//=============================================================================
//see if this is a unique weapon
if ( attackerWeaponId ! = WEAPON_NONE )
{
if ( pAttacker - > m_killWeapons . Find ( attackerWeaponId ) = = - 1 )
{
pAttacker - > m_killWeapons . AddToTail ( attackerWeaponId ) ;
if ( pAttacker - > m_killWeapons . Count ( ) > = AchievementConsts : : KillsWithMultipleGuns_MinWeapons )
{
pAttacker - > AwardAchievement ( CSKillsWithMultipleGuns ) ;
}
}
}
//Check for kills while blind
if ( pAttacker - > IsBlindForAchievement ( ) )
{
//if this is from a different blinding, restart the kill counter and set the time
if ( pAttacker - > m_blindStartTime ! = pAttacker - > m_firstKillBlindStartTime )
{
pAttacker - > m_killsWhileBlind = 0 ;
pAttacker - > m_firstKillBlindStartTime = pAttacker - > m_blindStartTime ;
}
+ + pAttacker - > m_killsWhileBlind ;
if ( pAttacker - > m_killsWhileBlind > = AchievementConsts : : KillEnemiesWhileBlind_Kills )
{
pAttacker - > AwardAchievement ( CSKillEnemiesWhileBlind ) ;
}
if ( pAttacker - > m_killsWhileBlind > = AchievementConsts : : KillEnemiesWhileBlindHard_Kills )
{
pAttacker - > AwardAchievement ( CSKillEnemiesWhileBlindHard ) ;
}
}
//Check sniper killing achievements
bool victimZoomed = ( pVictim - > GetFOV ( ) ! = pVictim - > GetDefaultFOV ( ) ) ;
bool attackerZoomed = ( pAttacker - > GetFOV ( ) ! = pAttacker - > GetDefaultFOV ( ) ) ;
bool attackerUsedSniperRifle = pAttackerWeapon & & pAttackerWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_SNIPER_RIFLE & & pInflictor = = pAttacker ;
if ( victimZoomed & & attackerUsedSniperRifle )
{
pAttacker - > AwardAchievement ( CSKillSniperWithSniper ) ;
}
if ( attackerWeaponId = = WEAPON_KNIFE & & victimZoomed )
{
pAttacker - > AwardAchievement ( CSKillSniperWithKnife ) ;
}
if ( attackerUsedSniperRifle & & ! attackerZoomed )
{
pAttacker - > AwardAchievement ( CSHipShot ) ;
}
//Kill a player at low health
if ( pAttacker - > IsAlive ( ) & & pAttacker - > GetHealth ( ) < = AchievementConsts : : KillWhenAtLowHealth_MaxHealth )
{
pAttacker - > AwardAchievement ( CSKillWhenAtLowHealth ) ;
}
//Kill a player with a knife during the pistol round
if ( CSGameRules ( ) - > IsPistolRound ( ) )
{
if ( attackerWeaponId = = WEAPON_KNIFE )
{
pAttacker - > AwardAchievement ( CSPistolRoundKnifeKill ) ;
}
}
//[tj] Check for dual elites fight
CWeaponCSBase * victimWeapon = pVictim - > GetActiveCSWeapon ( ) ;
if ( victimWeapon )
{
CSWeaponID victimWeaponID = victimWeapon - > GetWeaponID ( ) ;
if ( attackerWeaponId = = WEAPON_ELITE & & victimWeaponID = = WEAPON_ELITE )
{
pAttacker - > AwardAchievement ( CSWinDualDuel ) ;
}
}
//[tj] See if the attacker or defender are in the air [sbodenbender] dont include ladders
bool attackerInAir = pAttacker - > GetMoveType ( ) ! = MOVETYPE_LADDER & & pAttacker - > GetNearestSurfaceBelow ( AchievementConsts : : KillInAir_MinimumHeight ) = = NULL ;
bool victimInAir = pVictim - > GetMoveType ( ) ! = MOVETYPE_LADDER & & pVictim - > GetNearestSurfaceBelow ( AchievementConsts : : KillInAir_MinimumHeight ) = = NULL ;
if ( attackerInAir )
{
pAttacker - > AwardAchievement ( CSKillWhileInAir ) ;
}
if ( victimInAir )
{
pAttacker - > AwardAchievement ( CSKillEnemyInAir ) ;
}
if ( attackerInAir & & victimInAir )
{
pAttacker - > AwardAchievement ( CSKillerAndEnemyInAir ) ;
}
//[tj] advance to the next stage of the defuse defense achievement
if ( pAttacker - > m_defuseDefenseStep = = DD_STARTED_DEFUSE )
{
pAttacker - > m_defuseDefenseStep = DD_KILLED_TERRORIST ;
}
if ( pVictim - > HasC4 ( ) & & pVictim - > GetBombPickuptime ( ) + AchievementConsts : : KillBombPickup_MaxTime > gpGlobals - > curtime )
{
pAttacker - > AwardAchievement ( CSKillBombPickup ) ;
}
}
//If you kill a friendly player while blind (from an enemy player), give the guy that blinded you an achievement
if ( pAttacker ! = NULL & & pVictim ! = NULL & & pVictim - > GetTeamNumber ( ) = = pAttacker - > GetTeamNumber ( ) & & pAttacker - > IsBlind ( ) )
{
CCSPlayer * flashbangAttacker = pAttacker - > GetLastFlashbangAttacker ( ) ;
if ( flashbangAttacker & & pAttacker - > GetTeamNumber ( ) ! = flashbangAttacker - > GetTeamNumber ( ) )
{
flashbangAttacker - > AwardAchievement ( CSCauseFriendlyFireWithFlashbang ) ;
}
}
// do a scan to determine count of players still alive
int livePlayerCount = 0 ;
int teamCount [ TEAM_MAXCOUNT ] ;
int teamIgnoreCount [ TEAM_MAXCOUNT ] ;
memset ( teamCount , 0 , sizeof ( teamCount ) ) ;
memset ( teamIgnoreCount , 0 , sizeof ( teamIgnoreCount ) ) ;
CCSPlayer * pAlivePlayer = NULL ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = ( CCSPlayer * ) UTIL_PlayerByIndex ( i ) ;
if ( pPlayer )
{
int teamNum = pPlayer - > GetTeamNumber ( ) ;
if ( teamNum > = 0 )
{
+ + teamCount [ teamNum ] ;
if ( pPlayer - > WasNotKilledNaturally ( ) )
{
teamIgnoreCount [ teamNum ] + + ;
}
}
if ( pPlayer - > IsAlive ( ) & & pPlayer ! = pVictim )
{
+ + livePlayerCount ;
pAlivePlayer = pPlayer ;
}
}
}
// Achievement check for being the last player alive in a match
if ( pAlivePlayer )
{
int alivePlayerTeam = pAlivePlayer - > GetTeamNumber ( ) ;
int alivePlayerOpposingTeam = alivePlayerTeam = = TEAM_CT ? TEAM_TERRORIST : TEAM_CT ;
if ( livePlayerCount = = 1
& & CSGameRules ( ) - > m_iRoundWinStatus = = WINNER_NONE
& & teamCount [ alivePlayerTeam ] - teamIgnoreCount [ alivePlayerTeam ] > = AchievementConsts : : LastPlayerAlive_MinPlayersOnTeam
& & teamCount [ alivePlayerOpposingTeam ] - teamIgnoreCount [ alivePlayerOpposingTeam ] > = AchievementConsts : : DefaultMinOpponentsForAchievement
& & ( ! ( pAlivePlayer - > m_iDisplayHistoryBits & DHF_FRIEND_KILLED ) ) )
{
pAlivePlayer - > AwardAchievement ( CSLastPlayerAlive ) ;
}
}
// [tj] Added hook into player killed stat that happens before weapon drop
CCS_GameStats . Event_PlayerKilled_PreWeaponDrop ( pVictim , info ) ;
}
//[tj] traces up to maxTrace units down and returns any standable object it hits
// (doesn't check slope for standability)
CBaseEntity * CCSPlayer : : GetNearestSurfaceBelow ( float maxTrace )
{
trace_t trace ;
Ray_t ray ;
Vector traceStart = this - > GetAbsOrigin ( ) ;
Vector traceEnd = traceStart ;
traceEnd . z - = maxTrace ;
Vector minExtent = this - > m_Local . m_bDucked ? VEC_DUCK_HULL_MIN_SCALED ( this ) : VEC_HULL_MIN_SCALED ( this ) ;
Vector maxExtent = this - > m_Local . m_bDucked ? VEC_DUCK_HULL_MAX_SCALED ( this ) : VEC_HULL_MAX_SCALED ( this ) ;
ray . Init ( traceStart , traceEnd , minExtent , maxExtent ) ;
UTIL_TraceRay ( ray , MASK_PLAYERSOLID , this , COLLISION_GROUP_PLAYER_MOVEMENT , & trace ) ;
return trace . m_pEnt ;
}
// [tj] Added a way to react to the round ending before we reset.
// It is important to note that this happens before the bomb explodes, so a player may die
// after this from a bomb explosion or a late kill after a defuse/detonation/rescue.
void CCSPlayer : : OnRoundEnd ( int winningTeam , int reason )
{
if ( winningTeam = = WINNER_CT | | winningTeam = = WINNER_TER )
{
int losingTeamId = ( winningTeam = = TEAM_CT ) ? TEAM_TERRORIST : TEAM_CT ;
CTeam * losingTeam = GetGlobalTeam ( losingTeamId ) ;
int losingTeamPlayers = 0 ;
if ( losingTeam )
{
losingTeamPlayers = losingTeam - > GetNumPlayers ( ) ;
int ignoreCount = 0 ;
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = ( CCSPlayer * ) UTIL_PlayerByIndex ( i ) ;
if ( pPlayer )
{
int teamNum = pPlayer - > GetTeamNumber ( ) ;
if ( teamNum = = losingTeamId )
{
if ( pPlayer - > WasNotKilledNaturally ( ) )
{
ignoreCount + + ;
}
}
}
}
losingTeamPlayers - = ignoreCount ;
}
//Check fast round win achievement
if ( IsAlive ( ) & &
gpGlobals - > curtime - CSGameRules ( ) - > GetRoundStartTime ( ) < AchievementConsts : : FastRoundWin_Time & &
GetTeamNumber ( ) = = winningTeam & &
losingTeamPlayers > = AchievementConsts : : DefaultMinOpponentsForAchievement )
{
AwardAchievement ( CSFastRoundWin ) ;
}
//Check goosechase achievement
if ( IsAlive ( ) & & reason = = Target_Bombed & & m_gooseChaseStep = = GC_STOPPED_AFTER_GETTING_SHOT & & m_pGooseChaseDistractingPlayer )
{
m_pGooseChaseDistractingPlayer - > AwardAchievement ( CSGooseChase ) ;
}
//Check Defuse Defense achievement
if ( IsAlive ( ) & & reason = = Bomb_Defused & & m_defuseDefenseStep = = DD_KILLED_TERRORIST )
{
AwardAchievement ( CSDefuseDefense ) ;
}
//Check silent win
if ( m_NumEnemiesKilledThisRound > 0 & & GetTeamNumber ( ) = = winningTeam & & ! m_bMadeFootstepNoise )
{
AwardAchievement ( CSSilentWin ) ;
}
//Process && Check "win rounds without buying" achievement
if ( GetTeamNumber ( ) = = winningTeam & & ! m_bMadePurchseThisRound )
{
m_roundsWonWithoutPurchase + + ;
if ( m_roundsWonWithoutPurchase > AchievementConsts : : WinRoundsWithoutBuying_Rounds )
{
AwardAchievement ( CSWinRoundsWithoutBuying ) ;
}
}
else
{
m_roundsWonWithoutPurchase = 0 ;
}
}
m_lastRoundResult = reason ;
}
void CCSPlayer : : OnPreResetRound ( )
{
//Check headshot survival achievement
if ( IsAlive ( ) & & m_bSurvivedHeadshotDueToHelmet )
{
AwardAchievement ( CSSurvivedHeadshotDueToHelmet ) ;
}
if ( IsAlive ( ) & & m_grenadeDamageTakenThisRound > AchievementConsts : : SurviveGrenade_MinDamage )
{
AwardAchievement ( CSSurviveGrenade ) ;
}
//Check achievement for surviving attacks from multiple players.
if ( IsAlive ( ) )
{
int numberOfEnemyDamagers = GetNumEnemyDamagers ( ) ;
if ( numberOfEnemyDamagers > = AchievementConsts : : SurviveManyAttacks_NumberDamagingPlayers )
{
AwardAchievement ( CSSurviveManyAttacks ) ;
}
}
}
void CCSPlayer : : OnCanceledDefuse ( )
{
if ( m_gooseChaseStep = = GC_SHOT_DURING_DEFUSE )
{
m_gooseChaseStep = GC_STOPPED_AFTER_GETTING_SHOT ;
}
}
void CCSPlayer : : OnStartedDefuse ( )
{
if ( m_defuseDefenseStep = = DD_NONE )
{
m_defuseDefenseStep = DD_STARTED_DEFUSE ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCSPlayer : : AttemptToExitFreezeCam ( void )
{
float fEndFreezeTravel = m_flDeathTime + CS_DEATH_ANIMATION_TIME + spec_freeze_traveltime . GetFloat ( ) ;
if ( gpGlobals - > curtime < fEndFreezeTravel )
return ;
m_bAbortFreezeCam = true ;
}
//-----------------------------------------------------------------------------
// Purpose: Sets whether this player is dominating the specified other player
//-----------------------------------------------------------------------------
void CCSPlayer : : SetPlayerDominated ( CCSPlayer * pPlayer , bool bDominated )
{
int iPlayerIndex = pPlayer - > entindex ( ) ;
m_bPlayerDominated . Set ( iPlayerIndex , bDominated ) ;
pPlayer - > SetPlayerDominatingMe ( this , bDominated ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Sets whether this player is being dominated by the other player
//-----------------------------------------------------------------------------
void CCSPlayer : : SetPlayerDominatingMe ( CCSPlayer * pPlayer , bool bDominated )
{
int iPlayerIndex = pPlayer - > entindex ( ) ;
m_bPlayerDominatingMe . Set ( iPlayerIndex , bDominated ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether this player is dominating the specified other player
//-----------------------------------------------------------------------------
bool CCSPlayer : : IsPlayerDominated ( int iPlayerIndex )
{
return m_bPlayerDominated . Get ( iPlayerIndex ) ;
}
bool CCSPlayer : : IsPlayerDominatingMe ( int iPlayerIndex )
{
return m_bPlayerDominatingMe . Get ( iPlayerIndex ) ;
}
//=============================================================================
// HPE_BEGIN:
// [menglish] MVP functions
//=============================================================================
void CCSPlayer : : IncrementNumMVPs ( CSMvpReason_t mvpReason )
{
//=============================================================================
// HPE_BEGIN:
// [Forrest] Allow MVP to be turned off for a server
//=============================================================================
if ( sv_nomvp . GetBool ( ) )
{
Msg ( " Round MVP disabled: sv_nomvp is set. \n " ) ;
return ;
}
//=============================================================================
// HPE_END
//=============================================================================
m_iMVPs + + ;
CCS_GameStats . Event_MVPEarned ( this ) ;
IGameEvent * mvpEvent = gameeventmanager - > CreateEvent ( " round_mvp " ) ;
if ( mvpEvent )
{
mvpEvent - > SetInt ( " userid " , GetUserID ( ) ) ;
mvpEvent - > SetInt ( " reason " , mvpReason ) ;
gameeventmanager - > FireEvent ( mvpEvent ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose: Sets the number of rounds this player has caused to be won for their team
//-----------------------------------------------------------------------------
void CCSPlayer : : SetNumMVPs ( int iNumMVP )
{
m_iMVPs = iNumMVP ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the number of rounds this player has caused to be won for their team
//-----------------------------------------------------------------------------
int CCSPlayer : : GetNumMVPs ( )
{
return m_iMVPs ;
}
//=============================================================================
// HPE_END
//=============================================================================
//-----------------------------------------------------------------------------
// Purpose: Removes all nemesis relationships between this player and others
//-----------------------------------------------------------------------------
void CCSPlayer : : RemoveNemesisRelationships ( )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pTemp = ToCSPlayer ( UTIL_PlayerByIndex ( i ) ) ;
if ( pTemp & & pTemp ! = this )
{
// set this player to be not dominating anyone else
SetPlayerDominated ( pTemp , false ) ;
// set no one else to be dominating this player
pTemp - > SetPlayerDominated ( this , false ) ;
}
}
}
void CCSPlayer : : CheckMaxGrenadeKills ( int grenadeKills )
{
if ( grenadeKills > m_maxGrenadeKills )
{
m_maxGrenadeKills = grenadeKills ;
}
}
void CCSPlayer : : CommitSuicide ( bool bExplode /*= false*/ , bool bForce /*= false*/ )
{
m_wasNotKilledNaturally = true ;
BaseClass : : CommitSuicide ( bExplode , bForce ) ;
}
void CCSPlayer : : CommitSuicide ( const Vector & vecForce , bool bExplode /*= false*/ , bool bForce /*= false*/ )
{
m_wasNotKilledNaturally = true ;
BaseClass : : CommitSuicide ( vecForce , bExplode , bForce ) ;
}
int CCSPlayer : : GetNumEnemyDamagers ( )
{
int numberOfEnemyDamagers = 0 ;
FOR_EACH_LL ( m_DamageTakenList , i )
{
for ( int j = 1 ; j < = MAX_PLAYERS ; j + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( j ) ;
if ( pPlayer & & V_strncmp ( pPlayer - > GetPlayerName ( ) , m_DamageTakenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 & &
pPlayer - > GetTeamNumber ( ) ! = GetTeamNumber ( ) )
{
numberOfEnemyDamagers + + ;
}
}
}
return numberOfEnemyDamagers ;
}
int CCSPlayer : : GetNumEnemiesDamaged ( )
{
int numberOfEnemiesDamaged = 0 ;
FOR_EACH_LL ( m_DamageGivenList , i )
{
for ( int j = 1 ; j < = MAX_PLAYERS ; j + + )
{
CBasePlayer * pPlayer = UTIL_PlayerByIndex ( j ) ;
if ( pPlayer & & V_strncmp ( pPlayer - > GetPlayerName ( ) , m_DamageGivenList [ i ] - > GetPlayerName ( ) , MAX_PLAYER_NAME_LENGTH ) = = 0 & &
pPlayer - > GetTeamNumber ( ) ! = GetTeamNumber ( ) )
{
numberOfEnemiesDamaged + + ;
}
}
}
return numberOfEnemiesDamaged ;
}
//=============================================================================
// HPE_END
//=============================================================================
void UTIL_AwardMoneyToTeam ( int iAmount , int iTeam , CBaseEntity * pIgnore )
{
for ( int i = 1 ; i < = gpGlobals - > maxClients ; i + + )
{
CCSPlayer * pPlayer = ( CCSPlayer * ) UTIL_PlayerByIndex ( i ) ;
if ( ! pPlayer )
continue ;
if ( pPlayer - > GetTeamNumber ( ) ! = iTeam )
continue ;
if ( pPlayer = = pIgnore )
continue ;
pPlayer - > AddAccount ( iAmount ) ;
}
}