2025-02-19 18:39:00 -05:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL1.
//
// $NoKeywords: $
//=============================================================================//
# include "cbase.h"
# include "sdk_player.h"
# include "sdk_gamerules.h"
# include "weapon_sdkbase.h"
# include "predicted_viewmodel.h"
# include "iservervehicle.h"
# include "viewport_panel_names.h"
extern int gEvilImpulse101 ;
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. " ) ;
# define SDK_PLAYER_MODEL "models / player / terror.mdl"
// -------------------------------------------------------------------------------- //
// 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 ) ;
} ;
# define THROWGRENADE_COUNTER_BITS 3
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 ) ;
}
// -------------------------------------------------------------------------------- //
// Tables.
// -------------------------------------------------------------------------------- //
BEGIN_DATADESC ( CSDKPlayer )
DEFINE_THINKFUNC ( SDKPushawayThink ) ,
END_DATADESC ( )
LINK_ENTITY_TO_CLASS ( player , CSDKPlayer ) ;
PRECACHE_REGISTER ( player ) ;
BEGIN_SEND_TABLE_NOBASE ( CSDKPlayer , DT_SDKLocalPlayerExclusive )
SendPropInt ( SENDINFO ( m_iShotsFired ) , 8 , SPROP_UNSIGNED ) ,
END_SEND_TABLE ( )
IMPLEMENT_SERVERCLASS_ST ( CSDKPlayer , DT_SDKPlayer )
SendPropExclude ( " DT_BaseAnimating " , " m_flPoseParameter " ) ,
SendPropExclude ( " DT_BaseAnimating " , " m_flPlaybackRate " ) ,
SendPropExclude ( " DT_BaseAnimating " , " m_nSequence " ) ,
SendPropExclude ( " DT_BaseEntity " , " m_angRotation " ) ,
SendPropExclude ( " DT_BaseAnimatingOverlay " , " overlay_vars " ) ,
// playeranimstate and clientside animation takes care of these on the client
SendPropExclude ( " DT_ServerAnimationData " , " m_flCycle " ) ,
SendPropExclude ( " DT_AnimTimeMustBeFirst " , " m_flAnimTime " ) ,
// Data that only gets sent to the local player.
SendPropDataTable ( " sdklocaldata " , 0 , & REFERENCE_SEND_TABLE ( DT_SDKLocalPlayerExclusive ) , SendProxy_SendLocalDataTable ) ,
SendPropAngle ( SENDINFO_VECTORELEM ( m_angEyeAngles , 0 ) , 11 ) ,
SendPropAngle ( SENDINFO_VECTORELEM ( m_angEyeAngles , 1 ) , 11 ) ,
SendPropEHandle ( SENDINFO ( m_hRagdoll ) ) ,
SendPropInt ( SENDINFO ( m_iThrowGrenadeCounter ) , THROWGRENADE_COUNTER_BITS , SPROP_UNSIGNED ) ,
END_SEND_TABLE ( )
class CSDKRagdoll : public CBaseAnimatingOverlay
{
public :
DECLARE_CLASS ( CSDKRagdoll , CBaseAnimatingOverlay ) ;
DECLARE_SERVERCLASS ( ) ;
// Transmit ragdolls to everyone.
virtual int UpdateTransmitState ( )
{
return SetTransmitState ( FL_EDICT_ALWAYS ) ;
}
public :
// In case the client has the player entity, we transmit the player index.
// In case the client doesn't have it, we transmit the player's model index, origin, and angles
// so they can create a ragdoll in the right place.
CNetworkHandle ( CBaseEntity , m_hPlayer ) ; // networked entity handle
CNetworkVector ( m_vecRagdollVelocity ) ;
CNetworkVector ( m_vecRagdollOrigin ) ;
} ;
LINK_ENTITY_TO_CLASS ( sdk_ragdoll , CSDKRagdoll ) ;
IMPLEMENT_SERVERCLASS_ST_NOBASE ( CSDKRagdoll , DT_SDKRagdoll )
SendPropVector ( SENDINFO ( m_vecRagdollOrigin ) , - 1 , SPROP_COORD ) ,
SendPropEHandle ( SENDINFO ( m_hPlayer ) ) ,
SendPropModelIndex ( SENDINFO ( m_nModelIndex ) ) ,
SendPropInt ( SENDINFO ( m_nForceBone ) , 8 , 0 ) ,
SendPropVector ( SENDINFO ( m_vecForce ) , - 1 , SPROP_NOSCALE ) ,
SendPropVector ( SENDINFO ( m_vecRagdollVelocity ) )
END_SEND_TABLE ( )
// -------------------------------------------------------------------------------- //
void cc_CreatePredictionError_f ( )
{
CBaseEntity * pEnt = CBaseEntity : : Instance ( 1 ) ;
pEnt - > SetAbsOrigin ( pEnt - > GetAbsOrigin ( ) + Vector ( 63 , 0 , 0 ) ) ;
}
ConCommand cc_CreatePredictionError ( " CreatePredictionError " , cc_CreatePredictionError_f , " Create a prediction error " , FCVAR_CHEAT ) ;
CSDKPlayer : : CSDKPlayer ( )
{
m_PlayerAnimState = CreatePlayerAnimState ( this , this , LEGANIM_9WAY , true ) ;
UseClientSideAnimation ( ) ;
m_angEyeAngles . Init ( ) ;
SetViewOffset ( SDK_PLAYER_VIEW_OFFSET ) ;
m_iThrowGrenadeCounter = 0 ;
}
CSDKPlayer : : ~ CSDKPlayer ( )
{
m_PlayerAnimState - > Release ( ) ;
}
CSDKPlayer * CSDKPlayer : : CreatePlayer ( const char * className , edict_t * ed )
{
CSDKPlayer : : s_PlayerEdict = ed ;
return ( CSDKPlayer * ) CreateEntityByName ( className ) ;
}
void CSDKPlayer : : LeaveVehicle ( const Vector & vecExitPoint , const QAngle & vecExitAngles )
{
BaseClass : : LeaveVehicle ( vecExitPoint , vecExitAngles ) ;
//teleport physics shadow too
// Vector newPos = GetAbsOrigin();
// QAngle newAng = GetAbsAngles();
// Teleport( &newPos, &newAng, &vec3_origin );
}
void CSDKPlayer : : PreThink ( void )
{
// Riding a vehicle?
if ( IsInAVehicle ( ) )
{
// make sure we update the client, check for timed damage and update suit even if we are in a vehicle
UpdateClientData ( ) ;
CheckTimeBasedDamage ( ) ;
// Allow the suit to recharge when in the vehicle.
CheckSuitUpdate ( ) ;
WaterMove ( ) ;
return ;
}
BaseClass : : PreThink ( ) ;
}
void CSDKPlayer : : PostThink ( )
{
BaseClass : : PostThink ( ) ;
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 ] ) ;
}
void CSDKPlayer : : Precache ( )
{
PrecacheModel ( SDK_PLAYER_MODEL ) ;
BaseClass : : Precache ( ) ;
}
void CSDKPlayer : : Spawn ( )
{
SetModel ( SDK_PLAYER_MODEL ) ;
SetMoveType ( MOVETYPE_WALK ) ;
RemoveSolidFlags ( FSOLID_NOT_SOLID ) ;
m_hRagdoll = NULL ;
BaseClass : : Spawn ( ) ;
}
void CSDKPlayer : : InitialSpawn ( void )
{
BaseClass : : InitialSpawn ( ) ;
const ConVar * hostname = cvar - > FindVar ( " hostname " ) ;
const char * title = ( hostname ) ? hostname - > GetString ( ) : " MESSAGE OF THE DAY " ;
// open info panel on client showing MOTD:
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_IMPULSE101 ) ; // exec this command if panel closed
data - > SetBool ( " unload " , sv_motd_unload_on_dismissal . GetBool ( ) ) ;
ShowViewPortPanel ( PANEL_INFO , true , data ) ;
data - > deleteThis ( ) ;
}
void CSDKPlayer : : Event_Killed ( const CTakeDamageInfo & info )
{
// 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.
BaseClass : : Event_Killed ( info ) ;
CreateRagdollEntity ( ) ;
}
void CSDKPlayer : : CreateRagdollEntity ( )
{
// If we already have a ragdoll, don't make another one.
CSDKRagdoll * pRagdoll = dynamic_cast < CSDKRagdoll * > ( m_hRagdoll . Get ( ) ) ;
if ( ! pRagdoll )
{
// create a new one
pRagdoll = dynamic_cast < CSDKRagdoll * > ( CreateEntityByName ( " sdk_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 = Vector ( 0 , 0 , 0 ) ;
}
// ragdolls will be removed on round restart automatically
m_hRagdoll = pRagdoll ;
}
void CSDKPlayer : : 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.
}
}
CWeaponSDKBase * CSDKPlayer : : GetActiveSDKWeapon ( ) const
{
return dynamic_cast < CWeaponSDKBase * > ( GetActiveWeapon ( ) ) ;
}
void CSDKPlayer : : 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 ) ;
}
}
void CSDKPlayer : : CheatImpulseCommands ( int iImpulse )
{
if ( iImpulse ! = 101 )
{
BaseClass : : CheatImpulseCommands ( iImpulse ) ;
return ;
}
gEvilImpulse101 = true ;
EquipSuit ( ) ;
GiveNamedItem ( " weapon_mp5 " ) ;
GiveNamedItem ( " weapon_grenade " ) ;
GiveNamedItem ( " weapon_shotgun " ) ;
// Give the player everything!
GiveAmmo ( 90 , AMMO_BULLETS ) ;
GiveAmmo ( 3 , AMMO_GRENADE ) ;
if ( GetHealth ( ) < 100 )
{
TakeHealth ( 25 , DMG_GENERIC ) ;
}
gEvilImpulse101 = false ;
}
void CSDKPlayer : : FlashlightTurnOn ( void )
{
AddEffects ( EF_DIMLIGHT ) ;
}
void CSDKPlayer : : FlashlightTurnOff ( void )
{
RemoveEffects ( EF_DIMLIGHT ) ;
}
int CSDKPlayer : : FlashlightIsOn ( void )
{
return IsEffectActive ( EF_DIMLIGHT ) ;
}