aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/hl2mp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/server/hl2mp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/server/hl2mp')
-rw-r--r--mp/src/game/server/hl2mp/grenade_satchel.cpp217
-rw-r--r--mp/src/game/server/hl2mp/grenade_satchel.h56
-rw-r--r--mp/src/game/server/hl2mp/grenade_tripmine.cpp276
-rw-r--r--mp/src/game/server/hl2mp/grenade_tripmine.h56
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_bot_temp.cpp435
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_bot_temp.h19
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_client.cpp201
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_cvars.cpp25
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_cvars.h20
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_gameinterface.cpp32
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_gameinterface.h10
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_player.cpp1629
-rw-r--r--mp/src/game/server/hl2mp/hl2mp_player.h176
-rw-r--r--mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.cpp104
-rw-r--r--mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.h26
15 files changed, 3282 insertions, 0 deletions
diff --git a/mp/src/game/server/hl2mp/grenade_satchel.cpp b/mp/src/game/server/hl2mp/grenade_satchel.cpp
new file mode 100644
index 00000000..4d15ea24
--- /dev/null
+++ b/mp/src/game/server/hl2mp/grenade_satchel.cpp
@@ -0,0 +1,217 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "player.h"
+#include "soundenvelope.h"
+#include "engine/IEngineSound.h"
+#include "explode.h"
+#include "Sprite.h"
+#include "grenade_satchel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define SLAM_SPRITE "sprites/redglow1.vmt"
+
+ConVar sk_plr_dmg_satchel ( "sk_plr_dmg_satchel","0");
+ConVar sk_npc_dmg_satchel ( "sk_npc_dmg_satchel","0");
+ConVar sk_satchel_radius ( "sk_satchel_radius","0");
+
+BEGIN_DATADESC( CSatchelCharge )
+
+ DEFINE_FIELD( m_flNextBounceSoundTime, FIELD_TIME ),
+ DEFINE_FIELD( m_bInAir, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_vLastPosition, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_pMyWeaponSLAM, FIELD_CLASSPTR ),
+ DEFINE_FIELD( m_bIsAttached, FIELD_BOOLEAN ),
+
+ // Function Pointers
+ DEFINE_THINKFUNC( SatchelThink ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_VOID, "Explode", InputExplode),
+
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( npc_satchel, CSatchelCharge );
+
+//=========================================================
+// Deactivate - do whatever it is we do to an orphaned
+// satchel when we don't want it in the world anymore.
+//=========================================================
+void CSatchelCharge::Deactivate( void )
+{
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ UTIL_Remove( this );
+
+ if ( m_hGlowSprite != NULL )
+ {
+ UTIL_Remove( m_hGlowSprite );
+ m_hGlowSprite = NULL;
+ }
+}
+
+
+void CSatchelCharge::Spawn( void )
+{
+ Precache( );
+ SetModel( "models/Weapons/w_slam.mdl" );
+
+ VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false );
+ SetMoveType( MOVETYPE_VPHYSICS );
+
+ SetCollisionGroup( COLLISION_GROUP_WEAPON );
+
+ UTIL_SetSize(this, Vector( -6, -6, -2), Vector(6, 6, 2));
+
+ SetThink( &CSatchelCharge::SatchelThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ m_flDamage = sk_plr_dmg_satchel.GetFloat();
+ m_DmgRadius = sk_satchel_radius.GetFloat();
+ m_takedamage = DAMAGE_YES;
+ m_iHealth = 1;
+
+ SetGravity( UTIL_ScaleForGravity( 560 ) ); // slightly lower gravity
+ SetFriction( 1.0 );
+ SetSequence( 1 );
+ SetDamage( 150 );
+
+ m_bIsAttached = false;
+ m_bInAir = true;
+ m_flNextBounceSoundTime = 0;
+
+ m_vLastPosition = vec3_origin;
+
+ m_hGlowSprite = NULL;
+ CreateEffects();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Start up any effects for us
+//-----------------------------------------------------------------------------
+void CSatchelCharge::CreateEffects( void )
+{
+ // Only do this once
+ if ( m_hGlowSprite != NULL )
+ return;
+
+ // Create a blinking light to show we're an active SLAM
+ m_hGlowSprite = CSprite::SpriteCreate( SLAM_SPRITE, GetAbsOrigin(), false );
+ m_hGlowSprite->SetAttachment( this, 0 );
+ m_hGlowSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxStrobeFast );
+ m_hGlowSprite->SetBrightness( 255, 1.0f );
+ m_hGlowSprite->SetScale( 0.2f, 0.5f );
+ m_hGlowSprite->TurnOn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CSatchelCharge::InputExplode( inputdata_t &inputdata )
+{
+ ExplosionCreate( GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsAngles(), GetThrower(), GetDamage(), 200,
+ SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSMOKE, 0.0f, this);
+
+ UTIL_Remove( this );
+}
+
+
+void CSatchelCharge::SatchelThink( void )
+{
+ // If attached resize so player can pick up off wall
+ if (m_bIsAttached)
+ {
+ UTIL_SetSize(this, Vector( -2, -2, -6), Vector(2, 2, 6));
+ }
+
+ // See if I can lose my owner (has dropper moved out of way?)
+ // Want do this so owner can shoot the satchel charge
+ if (GetOwnerEntity())
+ {
+ trace_t tr;
+ Vector vUpABit = GetAbsOrigin();
+ vUpABit.z += 5.0;
+
+ CBaseEntity* saveOwner = GetOwnerEntity();
+ SetOwnerEntity( NULL );
+ UTIL_TraceEntity( this, GetAbsOrigin(), vUpABit, MASK_SOLID, &tr );
+ if ( tr.startsolid || tr.fraction != 1.0 )
+ {
+ SetOwnerEntity( saveOwner );
+ }
+ }
+
+ // Bounce movement code gets this think stuck occasionally so check if I've
+ // succeeded in moving, otherwise kill my motions.
+ else if ((GetAbsOrigin() - m_vLastPosition).LengthSqr()<1)
+ {
+ SetAbsVelocity( vec3_origin );
+
+ QAngle angVel = GetLocalAngularVelocity();
+ angVel.y = 0;
+ SetLocalAngularVelocity( angVel );
+
+ // Clear think function
+ SetThink(NULL);
+ return;
+ }
+ m_vLastPosition= GetAbsOrigin();
+
+ StudioFrameAdvance( );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ if (!IsInWorld())
+ {
+ UTIL_Remove( this );
+ return;
+ }
+
+ // Is it attached to a wall?
+ if (m_bIsAttached)
+ {
+ return;
+ }
+}
+
+void CSatchelCharge::Precache( void )
+{
+ PrecacheModel("models/Weapons/w_slam.mdl");
+ PrecacheModel(SLAM_SPRITE);
+}
+
+void CSatchelCharge::BounceSound( void )
+{
+ if (gpGlobals->curtime > m_flNextBounceSoundTime)
+ {
+ m_flNextBounceSoundTime = gpGlobals->curtime + 0.1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+CSatchelCharge::CSatchelCharge(void)
+{
+ m_vLastPosition.Init();
+ m_pMyWeaponSLAM = NULL;
+}
+
+CSatchelCharge::~CSatchelCharge(void)
+{
+ if ( m_hGlowSprite != NULL )
+ {
+ UTIL_Remove( m_hGlowSprite );
+ m_hGlowSprite = NULL;
+ }
+}
diff --git a/mp/src/game/server/hl2mp/grenade_satchel.h b/mp/src/game/server/hl2mp/grenade_satchel.h
new file mode 100644
index 00000000..a8376f33
--- /dev/null
+++ b/mp/src/game/server/hl2mp/grenade_satchel.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Satchel Charge
+//
+// $Workfile: $
+// $Date: $
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SATCHEL_H
+#define SATCHEL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basegrenade_shared.h"
+#include "hl2mp/weapon_slam.h"
+
+class CSoundPatch;
+class CSprite;
+
+class CSatchelCharge : public CBaseGrenade
+{
+public:
+ DECLARE_CLASS( CSatchelCharge, CBaseGrenade );
+
+ void Spawn( void );
+ void Precache( void );
+ void BounceSound( void );
+ void SatchelTouch( CBaseEntity *pOther );
+ void SatchelThink( void );
+
+ // Input handlers
+ void InputExplode( inputdata_t &inputdata );
+
+ float m_flNextBounceSoundTime;
+ bool m_bInAir;
+ Vector m_vLastPosition;
+
+public:
+ CWeapon_SLAM* m_pMyWeaponSLAM; // Who shot me..
+ bool m_bIsAttached;
+ void Deactivate( void );
+
+ CSatchelCharge();
+ ~CSatchelCharge();
+
+ DECLARE_DATADESC();
+
+private:
+ void CreateEffects( void );
+ CHandle<CSprite> m_hGlowSprite;
+};
+
+#endif //SATCHEL_H
diff --git a/mp/src/game/server/hl2mp/grenade_tripmine.cpp b/mp/src/game/server/hl2mp/grenade_tripmine.cpp
new file mode 100644
index 00000000..d63bf4f0
--- /dev/null
+++ b/mp/src/game/server/hl2mp/grenade_tripmine.cpp
@@ -0,0 +1,276 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements the tripmine grenade.
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "beam_shared.h"
+#include "shake.h"
+#include "grenade_tripmine.h"
+#include "vstdlib/random.h"
+#include "engine/IEngineSound.h"
+#include "explode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern const char* g_pModelNameLaser;
+
+ConVar sk_plr_dmg_tripmine ( "sk_plr_dmg_tripmine","0");
+ConVar sk_npc_dmg_tripmine ( "sk_npc_dmg_tripmine","0");
+ConVar sk_tripmine_radius ( "sk_tripmine_radius","0");
+
+LINK_ENTITY_TO_CLASS( npc_tripmine, CTripmineGrenade );
+
+BEGIN_DATADESC( CTripmineGrenade )
+
+ DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_flPowerUp, FIELD_TIME ),
+ DEFINE_FIELD( m_vecDir, FIELD_VECTOR ),
+ DEFINE_FIELD( m_vecEnd, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_flBeamLength, FIELD_FLOAT ),
+ DEFINE_FIELD( m_pBeam, FIELD_CLASSPTR ),
+ DEFINE_FIELD( m_posOwner, FIELD_POSITION_VECTOR ),
+ DEFINE_FIELD( m_angleOwner, FIELD_VECTOR ),
+
+ // Function Pointers
+ DEFINE_THINKFUNC( WarningThink ),
+ DEFINE_THINKFUNC( PowerupThink ),
+ DEFINE_THINKFUNC( BeamBreakThink ),
+ DEFINE_THINKFUNC( DelayDeathThink ),
+
+END_DATADESC()
+
+CTripmineGrenade::CTripmineGrenade()
+{
+ m_vecDir.Init();
+ m_vecEnd.Init();
+ m_posOwner.Init();
+ m_angleOwner.Init();
+}
+
+void CTripmineGrenade::Spawn( void )
+{
+ Precache( );
+ // motor
+ SetMoveType( MOVETYPE_FLY );
+ SetSolid( SOLID_BBOX );
+ SetModel( "models/Weapons/w_slam.mdl" );
+
+ IPhysicsObject *pObject = VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, true );
+ pObject->EnableMotion( false );
+ SetCollisionGroup( COLLISION_GROUP_WEAPON );
+
+ SetCycle( 0.0f );
+ m_nBody = 3;
+ m_flDamage = sk_plr_dmg_tripmine.GetFloat();
+ m_DmgRadius = sk_tripmine_radius.GetFloat();
+
+ ResetSequenceInfo( );
+ m_flPlaybackRate = 0;
+
+ UTIL_SetSize(this, Vector( -4, -4, -2), Vector(4, 4, 2));
+
+ m_flPowerUp = gpGlobals->curtime + 2.0;
+
+ SetThink( &CTripmineGrenade::PowerupThink );
+ SetNextThink( gpGlobals->curtime + 0.2 );
+
+ m_takedamage = DAMAGE_YES;
+
+ m_iHealth = 1;
+
+ EmitSound( "TripmineGrenade.Place" );
+ SetDamage ( 200 );
+
+ // Tripmine sits at 90 on wall so rotate back to get m_vecDir
+ QAngle angles = GetAbsAngles();
+ angles.x -= 90;
+
+ AngleVectors( angles, &m_vecDir );
+ m_vecEnd = GetAbsOrigin() + m_vecDir * 2048;
+
+ AddEffects( EF_NOSHADOW );
+}
+
+
+void CTripmineGrenade::Precache( void )
+{
+ PrecacheModel("models/Weapons/w_slam.mdl");
+
+ PrecacheScriptSound( "TripmineGrenade.Place" );
+ PrecacheScriptSound( "TripmineGrenade.Activate" );
+}
+
+
+void CTripmineGrenade::WarningThink( void )
+{
+ // set to power up
+ SetThink( &CTripmineGrenade::PowerupThink );
+ SetNextThink( gpGlobals->curtime + 1.0f );
+}
+
+
+void CTripmineGrenade::PowerupThink( void )
+{
+ if (gpGlobals->curtime > m_flPowerUp)
+ {
+ MakeBeam( );
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+ m_bIsLive = true;
+
+ // play enabled sound
+ EmitSound( "TripmineGrenade.Activate" );
+ }
+ SetNextThink( gpGlobals->curtime + 0.1f );
+}
+
+
+void CTripmineGrenade::KillBeam( void )
+{
+ if ( m_pBeam )
+ {
+ UTIL_Remove( m_pBeam );
+ m_pBeam = NULL;
+ }
+}
+
+
+void CTripmineGrenade::MakeBeam( void )
+{
+ trace_t tr;
+
+ UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+
+ m_flBeamLength = tr.fraction;
+
+
+
+ // If I hit a living thing, send the beam through me so it turns on briefly
+ // and then blows the living thing up
+ CBaseEntity *pEntity = tr.m_pEnt;
+ CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity );
+
+ // Draw length is not the beam length if entity is in the way
+ float drawLength = tr.fraction;
+ if (pBCC)
+ {
+ SetOwnerEntity( pBCC );
+ UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ m_flBeamLength = tr.fraction;
+ SetOwnerEntity( NULL );
+
+ }
+
+ // set to follow laser spot
+ SetThink( &CTripmineGrenade::BeamBreakThink );
+
+ // Delay first think slightly so beam has time
+ // to appear if person right in front of it
+ SetNextThink( gpGlobals->curtime + 1.0f );
+
+ Vector vecTmpEnd = GetLocalOrigin() + m_vecDir * 2048 * drawLength;
+
+ m_pBeam = CBeam::BeamCreate( g_pModelNameLaser, 0.35 );
+ m_pBeam->PointEntInit( vecTmpEnd, this );
+ m_pBeam->SetColor( 255, 55, 52 );
+ m_pBeam->SetScrollRate( 25.6 );
+ m_pBeam->SetBrightness( 64 );
+
+ int beamAttach = LookupAttachment("beam_attach");
+ m_pBeam->SetEndAttachment( beamAttach );
+}
+
+
+void CTripmineGrenade::BeamBreakThink( void )
+{
+ // See if I can go solid yet (has dropper moved out of way?)
+ if (IsSolidFlagSet( FSOLID_NOT_SOLID ))
+ {
+ trace_t tr;
+ Vector vUpBit = GetAbsOrigin();
+ vUpBit.z += 5.0;
+
+ UTIL_TraceEntity( this, GetAbsOrigin(), vUpBit, MASK_SHOT, &tr );
+ if ( !tr.startsolid && (tr.fraction == 1.0) )
+ {
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+ }
+ }
+
+ trace_t tr;
+
+ // NOT MASK_SHOT because we want only simple hit boxes
+ UTIL_TraceLine( GetAbsOrigin(), m_vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
+
+ // ALERT( at_console, "%f : %f\n", tr.flFraction, m_flBeamLength );
+
+ // respawn detect.
+ if ( !m_pBeam )
+ {
+ MakeBeam( );
+ if ( tr.m_pEnt )
+ m_hOwner = tr.m_pEnt; // reset owner too
+ }
+
+
+ CBaseEntity *pEntity = tr.m_pEnt;
+ CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pEntity );
+
+ if (pBCC || fabs( m_flBeamLength - tr.fraction ) > 0.001)
+ {
+ m_iHealth = 0;
+ Event_Killed( CTakeDamageInfo( (CBaseEntity*)m_hOwner, this, 100, GIB_NORMAL ) );
+ return;
+ }
+
+ SetNextThink( gpGlobals->curtime + 0.05f );
+}
+
+#if 0 // FIXME: OnTakeDamage_Alive() is no longer called now that base grenade derives from CBaseAnimating
+int CTripmineGrenade::OnTakeDamage_Alive( const CTakeDamageInfo &info )
+{
+ if (gpGlobals->curtime < m_flPowerUp && info.GetDamage() < m_iHealth)
+ {
+ // disable
+ // Create( "weapon_tripmine", GetLocalOrigin() + m_vecDir * 24, GetAngles() );
+ SetThink( &CTripmineGrenade::SUB_Remove );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ KillBeam();
+ return FALSE;
+ }
+ return BaseClass::OnTakeDamage_Alive( info );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CTripmineGrenade::Event_Killed( const CTakeDamageInfo &info )
+{
+ m_takedamage = DAMAGE_NO;
+
+ SetThink( &CTripmineGrenade::DelayDeathThink );
+ SetNextThink( gpGlobals->curtime + 0.25 );
+
+ EmitSound( "TripmineGrenade.StopSound" );
+}
+
+
+void CTripmineGrenade::DelayDeathThink( void )
+{
+ KillBeam();
+ trace_t tr;
+ UTIL_TraceLine ( GetAbsOrigin() + m_vecDir * 8, GetAbsOrigin() - m_vecDir * 64, MASK_SOLID, this, COLLISION_GROUP_NONE, & tr);
+ UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START );
+
+ ExplosionCreate( GetAbsOrigin() + m_vecDir * 8, GetAbsAngles(), m_hOwner, GetDamage(), 200,
+ SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSMOKE, 0.0f, this);
+
+ UTIL_Remove( this );
+}
+
diff --git a/mp/src/game/server/hl2mp/grenade_tripmine.h b/mp/src/game/server/hl2mp/grenade_tripmine.h
new file mode 100644
index 00000000..bfebcc35
--- /dev/null
+++ b/mp/src/game/server/hl2mp/grenade_tripmine.h
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GRENADE_TRIPMINE_H
+#define GRENADE_TRIPMINE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basegrenade_shared.h"
+
+class CBeam;
+
+
+class CTripmineGrenade : public CBaseGrenade
+{
+public:
+ DECLARE_CLASS( CTripmineGrenade, CBaseGrenade );
+
+ CTripmineGrenade();
+ void Spawn( void );
+ void Precache( void );
+
+#if 0 // FIXME: OnTakeDamage_Alive() is no longer called now that base grenade derives from CBaseAnimating
+ int OnTakeDamage_Alive( const CTakeDamageInfo &info );
+#endif
+ void WarningThink( void );
+ void PowerupThink( void );
+ void BeamBreakThink( void );
+ void DelayDeathThink( void );
+ void Event_Killed( const CTakeDamageInfo &info );
+
+ void MakeBeam( void );
+ void KillBeam( void );
+
+public:
+ EHANDLE m_hOwner;
+
+private:
+ float m_flPowerUp;
+ Vector m_vecDir;
+ Vector m_vecEnd;
+ float m_flBeamLength;
+
+ CBeam *m_pBeam;
+ Vector m_posOwner;
+ Vector m_angleOwner;
+
+ DECLARE_DATADESC();
+};
+
+#endif // GRENADE_TRIPMINE_H
diff --git a/mp/src/game/server/hl2mp/hl2mp_bot_temp.cpp b/mp/src/game/server/hl2mp/hl2mp_bot_temp.cpp
new file mode 100644
index 00000000..3aab7a12
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_bot_temp.cpp
@@ -0,0 +1,435 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Basic BOT handling.
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "player.h"
+#include "hl2mp_player.h"
+#include "in_buttons.h"
+#include "movehelper_server.h"
+
+void ClientPutInServer( edict_t *pEdict, const char *playername );
+void Bot_Think( CHL2MP_Player *pBot );
+
+#ifdef DEBUG
+
+ConVar bot_forcefireweapon( "bot_forcefireweapon", "", 0, "Force bots with the specified weapon to fire." );
+ConVar bot_forceattack2( "bot_forceattack2", "0", 0, "When firing, use attack2." );
+ConVar bot_forceattackon( "bot_forceattackon", "0", 0, "When firing, don't tap fire, hold it down." );
+ConVar bot_flipout( "bot_flipout", "0", 0, "When on, all bots fire their guns." );
+ConVar bot_defend( "bot_defend", "0", 0, "Set to a team number, and that team will all keep their combat shields raised." );
+ConVar bot_changeclass( "bot_changeclass", "0", 0, "Force all bots to change to the specified class." );
+ConVar bot_zombie( "bot_zombie", "0", 0, "Brraaaaaiiiins." );
+static ConVar bot_mimic_yaw_offset( "bot_mimic_yaw_offset", "0", 0, "Offsets the bot yaw." );
+ConVar bot_attack( "bot_attack", "1", 0, "Shoot!" );
+
+ConVar bot_sendcmd( "bot_sendcmd", "", 0, "Forces bots to send the specified command." );
+
+ConVar bot_crouch( "bot_crouch", "0", 0, "Bot crouches" );
+
+#ifdef NEXT_BOT
+extern ConVar bot_mimic;
+#else
+ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
+#endif
+
+static int BotNumber = 1;
+static int g_iNextBotTeam = -1;
+static int g_iNextBotClass = -1;
+
+typedef struct
+{
+ bool backwards;
+
+ float nextturntime;
+ bool lastturntoright;
+
+ float nextstrafetime;
+ float sidemove;
+
+ QAngle forwardAngle;
+ QAngle lastAngles;
+
+ float m_flJoinTeamTime;
+ int m_WantedTeam;
+ int m_WantedClass;
+} botdata_t;
+
+static botdata_t g_BotData[ MAX_PLAYERS ];
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new Bot and put it in the game.
+// Output : Pointer to the new Bot, or NULL if there's no free clients.
+//-----------------------------------------------------------------------------
+CBasePlayer *BotPutInServer( bool bFrozen, int iTeam )
+{
+ g_iNextBotTeam = iTeam;
+
+ char botname[ 64 ];
+ Q_snprintf( botname, sizeof( botname ), "Bot%02i", BotNumber );
+
+ // This is an evil hack, but we use it to prevent sv_autojointeam from kicking in.
+
+ edict_t *pEdict = engine->CreateFakeClient( botname );
+
+ if (!pEdict)
+ {
+ Msg( "Failed to create Bot.\n");
+ return NULL;
+ }
+
+ // Allocate a CBasePlayer for the bot, and call spawn
+ //ClientPutInServer( pEdict, botname );
+ CHL2MP_Player *pPlayer = ((CHL2MP_Player *)CBaseEntity::Instance( pEdict ));
+ pPlayer->ClearFlags();
+ pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT );
+
+ if ( bFrozen )
+ pPlayer->AddEFlags( EFL_BOT_FROZEN );
+
+ BotNumber++;
+
+ g_BotData[pPlayer->entindex()-1].m_WantedTeam = iTeam;
+ g_BotData[pPlayer->entindex()-1].m_flJoinTeamTime = gpGlobals->curtime + 0.3;
+
+ return pPlayer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run through all the Bots in the game and let them think.
+//-----------------------------------------------------------------------------
+void Bot_RunAll( void )
+{
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CHL2MP_Player *pPlayer = ToHL2MPPlayer( UTIL_PlayerByIndex( i ) );
+
+ if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) )
+ {
+ Bot_Think( pPlayer );
+ }
+ }
+}
+
+bool RunMimicCommand( CUserCmd& cmd )
+{
+ if ( bot_mimic.GetInt() <= 0 )
+ return false;
+
+ if ( bot_mimic.GetInt() > gpGlobals->maxClients )
+ return false;
+
+
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( bot_mimic.GetInt() );
+ if ( !pPlayer )
+ return false;
+
+ if ( !pPlayer->GetLastUserCommand() )
+ return false;
+
+ cmd = *pPlayer->GetLastUserCommand();
+ cmd.viewangles[YAW] += bot_mimic_yaw_offset.GetFloat();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Simulates a single frame of movement for a player
+// Input : *fakeclient -
+// *viewangles -
+// forwardmove -
+// sidemove -
+// upmove -
+// buttons -
+// impulse -
+// msec -
+// Output : virtual void
+//-----------------------------------------------------------------------------
+static void RunPlayerMove( CHL2MP_Player *fakeclient, const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime )
+{
+ if ( !fakeclient )
+ return;
+
+ 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;
+ fakeclient->SetTimeBase( flTimeBase );
+
+ Q_memset( &cmd, 0, sizeof( cmd ) );
+
+ if ( !RunMimicCommand( cmd ) && !bot_zombie.GetBool() )
+ {
+ VectorCopy( viewangles, cmd.viewangles );
+ cmd.forwardmove = forwardmove;
+ cmd.sidemove = sidemove;
+ cmd.upmove = upmove;
+ cmd.buttons = buttons;
+ cmd.impulse = impulse;
+ cmd.random_seed = random->RandomInt( 0, 0x7fffffff );
+ }
+
+ if( bot_crouch.GetInt() )
+ cmd.buttons |= IN_DUCK;
+
+ if ( bot_attack.GetBool() )
+ cmd.buttons |= IN_ATTACK;
+
+ MoveHelperServer()->SetHost( fakeclient );
+ fakeclient->PlayerRunCommand( &cmd, MoveHelperServer() );
+
+ // save off the last good usercmd
+ fakeclient->SetLastUserCommand( cmd );
+
+ // Clear out any fixangle that has been set
+ fakeclient->pl.fixangle = FIXANGLE_NONE;
+
+ // Restore the globals..
+ gpGlobals->frametime = flOldFrametime;
+ gpGlobals->curtime = flOldCurtime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run this Bot's AI for one frame.
+//-----------------------------------------------------------------------------
+void Bot_Think( CHL2MP_Player *pBot )
+{
+ // Make sure we stay being a bot
+ pBot->AddFlag( FL_FAKECLIENT );
+
+ botdata_t *botdata = &g_BotData[ ENTINDEX( pBot->edict() ) - 1 ];
+
+ QAngle vecViewAngles;
+ float forwardmove = 0.0;
+ float sidemove = botdata->sidemove;
+ float upmove = 0.0;
+ unsigned short buttons = 0;
+ byte impulse = 0;
+ float frametime = gpGlobals->frametime;
+
+ vecViewAngles = pBot->GetLocalAngles();
+
+
+ // Create some random values
+ if ( pBot->IsAlive() && (pBot->GetSolid() == SOLID_BBOX) )
+ {
+ trace_t trace;
+
+ // Stop when shot
+ if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) )
+ {
+ if ( pBot->m_iHealth == 100 )
+ {
+ forwardmove = 600 * ( botdata->backwards ? -1 : 1 );
+ if ( botdata->sidemove != 0.0f )
+ {
+ forwardmove *= random->RandomFloat( 0.1, 1.0f );
+ }
+ }
+ else
+ {
+ forwardmove = 0;
+ }
+ }
+
+ // Only turn if I haven't been hurt
+ if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) && pBot->m_iHealth == 100 )
+ {
+ Vector vecEnd;
+ Vector forward;
+
+ QAngle angle;
+ float angledelta = 15.0;
+
+ int maxtries = (int)360.0/angledelta;
+
+ if ( botdata->lastturntoright )
+ {
+ angledelta = -angledelta;
+ }
+
+ angle = pBot->GetLocalAngles();
+
+ Vector vecSrc;
+ while ( --maxtries >= 0 )
+ {
+ AngleVectors( angle, &forward );
+
+ vecSrc = pBot->GetLocalOrigin() + Vector( 0, 0, 36 );
+
+ vecEnd = vecSrc + forward * 10;
+
+ UTIL_TraceHull( vecSrc, vecEnd, VEC_HULL_MIN_SCALED( pBot ), VEC_HULL_MAX_SCALED( pBot ),
+ MASK_PLAYERSOLID, pBot, COLLISION_GROUP_NONE, &trace );
+
+ if ( trace.fraction == 1.0 )
+ {
+ if ( gpGlobals->curtime < botdata->nextturntime )
+ {
+ break;
+ }
+ }
+
+ angle.y += angledelta;
+
+ if ( angle.y > 180 )
+ angle.y -= 360;
+ else if ( angle.y < -180 )
+ angle.y += 360;
+
+ botdata->nextturntime = gpGlobals->curtime + 2.0;
+ botdata->lastturntoright = random->RandomInt( 0, 1 ) == 0 ? true : false;
+
+ botdata->forwardAngle = angle;
+ botdata->lastAngles = angle;
+
+ }
+
+
+ if ( gpGlobals->curtime >= botdata->nextstrafetime )
+ {
+ botdata->nextstrafetime = gpGlobals->curtime + 1.0f;
+
+ if ( random->RandomInt( 0, 5 ) == 0 )
+ {
+ botdata->sidemove = -600.0f + 1200.0f * random->RandomFloat( 0, 2 );
+ }
+ else
+ {
+ botdata->sidemove = 0;
+ }
+ sidemove = botdata->sidemove;
+
+ if ( random->RandomInt( 0, 20 ) == 0 )
+ {
+ botdata->backwards = true;
+ }
+ else
+ {
+ botdata->backwards = false;
+ }
+ }
+
+ pBot->SetLocalAngles( angle );
+ vecViewAngles = angle;
+ }
+
+ // Is my team being forced to defend?
+ if ( bot_defend.GetInt() == pBot->GetTeamNumber() )
+ {
+ buttons |= IN_ATTACK2;
+ }
+ // If bots are being forced to fire a weapon, see if I have it
+ else if ( bot_forcefireweapon.GetString() )
+ {
+ CBaseCombatWeapon *pWeapon = pBot->Weapon_OwnsThisType( bot_forcefireweapon.GetString() );
+ if ( pWeapon )
+ {
+ // Switch to it if we don't have it out
+ CBaseCombatWeapon *pActiveWeapon = pBot->GetActiveWeapon();
+
+ // Switch?
+ if ( pActiveWeapon != pWeapon )
+ {
+ pBot->Weapon_Switch( pWeapon );
+ }
+ else
+ {
+ // Start firing
+ // Some weapons require releases, so randomise firing
+ if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
+ {
+ buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
+ }
+ }
+ }
+ }
+
+ if ( bot_flipout.GetInt() )
+ {
+ if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
+ {
+ buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
+ }
+ }
+
+ if ( strlen( bot_sendcmd.GetString() ) > 0 )
+ {
+ //send the cmd from this bot
+ CCommand args;
+ args.Tokenize( bot_sendcmd.GetString() );
+ pBot->ClientCommand( args );
+
+ bot_sendcmd.SetValue("");
+ }
+ }
+ else
+ {
+ // Wait for Reinforcement wave
+ if ( !pBot->IsAlive() )
+ {
+ // Try hitting my buttons occasionally
+ if ( random->RandomInt( 0, 100 ) > 80 )
+ {
+ // Respawn the bot
+ if ( random->RandomInt( 0, 1 ) == 0 )
+ {
+ buttons |= IN_JUMP;
+ }
+ else
+ {
+ buttons = 0;
+ }
+ }
+ }
+ }
+
+ if ( bot_flipout.GetInt() >= 2 )
+ {
+
+ QAngle angOffset = RandomAngle( -1, 1 );
+
+ botdata->lastAngles += angOffset;
+
+ for ( int i = 0 ; i < 2; i++ )
+ {
+ if ( fabs( botdata->lastAngles[ i ] - botdata->forwardAngle[ i ] ) > 15.0f )
+ {
+ if ( botdata->lastAngles[ i ] > botdata->forwardAngle[ i ] )
+ {
+ botdata->lastAngles[ i ] = botdata->forwardAngle[ i ] + 15;
+ }
+ else
+ {
+ botdata->lastAngles[ i ] = botdata->forwardAngle[ i ] - 15;
+ }
+ }
+ }
+
+ botdata->lastAngles[ 2 ] = 0;
+
+ pBot->SetLocalAngles( botdata->lastAngles );
+ }
+
+ RunPlayerMove( pBot, pBot->GetLocalAngles(), forwardmove, sidemove, upmove, buttons, impulse, frametime );
+}
+
+
+
+
+#endif
+
diff --git a/mp/src/game/server/hl2mp/hl2mp_bot_temp.h b/mp/src/game/server/hl2mp/hl2mp_bot_temp.h
new file mode 100644
index 00000000..fe337bef
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_bot_temp.h
@@ -0,0 +1,19 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#ifndef BOT_BASE_H
+#define BOT_BASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+// If iTeam or iClass is -1, then a team or class is randomly chosen.
+CBasePlayer *BotPutInServer( bool bFrozen, int iTeam );
+
+
+#endif // BOT_BASE_H
+
diff --git a/mp/src/game/server/hl2mp/hl2mp_client.cpp b/mp/src/game/server/hl2mp/hl2mp_client.cpp
new file mode 100644
index 00000000..909716a5
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_client.cpp
@@ -0,0 +1,201 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+/*
+
+===== tf_client.cpp ========================================================
+
+ HL2 client/server game specific stuff
+
+*/
+
+#include "cbase.h"
+#include "hl2mp_player.h"
+#include "hl2mp_gamerules.h"
+#include "gamerules.h"
+#include "teamplay_gamerules.h"
+#include "entitylist.h"
+#include "physics.h"
+#include "game.h"
+#include "player_resource.h"
+#include "engine/IEngineSound.h"
+#include "team.h"
+#include "viewport_panel_names.h"
+
+#include "tier0/vprof.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+void Host_Say( edict_t *pEdict, bool teamonly );
+
+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." );
+
+extern CBaseEntity* FindPickerEntityClass( CBasePlayer *pPlayer, char *classname );
+extern bool g_fGameOver;
+
+void FinishClientPutInServer( CHL2MP_Player *pPlayer )
+{
+ pPlayer->InitialSpawn();
+ pPlayer->Spawn();
+
+
+ char sName[128];
+ Q_strncpy( sName, pPlayer->GetPlayerName(), sizeof( sName ) );
+
+ // First parse the name and remove any %'s
+ for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ )
+ {
+ // Replace it with a space
+ if ( *pApersand == '%' )
+ *pApersand = ' ';
+ }
+
+ // notify other clients of player joining the game
+ UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "#Game_connected", sName[0] != 0 ? sName : "<unconnected>" );
+
+ if ( HL2MPRules()->IsTeamplay() == true )
+ {
+ ClientPrint( pPlayer, HUD_PRINTTALK, "You are on team %s1\n", pPlayer->GetTeam()->GetName() );
+ }
+
+ const ConVar *hostname = cvar->FindVar( "hostname" );
+ const char *title = (hostname) ? hostname->GetString() : "MESSAGE OF THE DAY";
+
+ 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->SetBool( "unload", sv_motd_unload_on_dismissal.GetBool() );
+
+ pPlayer->ShowViewPortPanel( PANEL_INFO, true, data );
+
+ data->deleteThis();
+}
+
+/*
+===========
+ClientPutInServer
+
+called each time a player is spawned into the game
+============
+*/
+void ClientPutInServer( edict_t *pEdict, const char *playername )
+{
+ // Allocate a CBaseTFPlayer for pev, and call spawn
+ CHL2MP_Player *pPlayer = CHL2MP_Player::CreatePlayer( "player", pEdict );
+ pPlayer->SetPlayerName( playername );
+}
+
+
+void ClientActive( edict_t *pEdict, bool bLoadGame )
+{
+ // Can't load games in CS!
+ Assert( !bLoadGame );
+
+ CHL2MP_Player *pPlayer = ToHL2MPPlayer( CBaseEntity::Instance( pEdict ) );
+ FinishClientPutInServer( pPlayer );
+}
+
+
+/*
+===============
+const char *GetGameDescription()
+
+Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
+===============
+*/
+const char *GetGameDescription()
+{
+ if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
+ return g_pGameRules->GetGameDescription();
+ else
+ return "Half-Life 2 Deathmatch";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given a player and optional name returns the entity of that
+// classname that the player is nearest facing
+//
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+CBaseEntity* FindEntity( edict_t *pEdict, char *classname)
+{
+ // If no name was given set bits based on the picked
+ if (FStrEq(classname,""))
+ {
+ return (FindPickerEntityClass( static_cast<CBasePlayer*>(GetContainingEntity(pEdict)), classname ));
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Precache game-specific models & sounds
+//-----------------------------------------------------------------------------
+void ClientGamePrecache( void )
+{
+ CBaseEntity::PrecacheModel("models/player.mdl");
+ CBaseEntity::PrecacheModel( "models/gibs/agibs.mdl" );
+ CBaseEntity::PrecacheModel ("models/weapons/v_hands.mdl");
+
+ CBaseEntity::PrecacheScriptSound( "HUDQuickInfo.LowAmmo" );
+ CBaseEntity::PrecacheScriptSound( "HUDQuickInfo.LowHealth" );
+
+ CBaseEntity::PrecacheScriptSound( "FX_AntlionImpact.ShellImpact" );
+ CBaseEntity::PrecacheScriptSound( "Missile.ShotDown" );
+ CBaseEntity::PrecacheScriptSound( "Bullets.DefaultNearmiss" );
+ CBaseEntity::PrecacheScriptSound( "Bullets.GunshipNearmiss" );
+ CBaseEntity::PrecacheScriptSound( "Bullets.StriderNearmiss" );
+
+ CBaseEntity::PrecacheScriptSound( "Geiger.BeepHigh" );
+ CBaseEntity::PrecacheScriptSound( "Geiger.BeepLow" );
+}
+
+
+// called by ClientKill and DeadThink
+void respawn( CBaseEntity *pEdict, bool fCopyCorpse )
+{
+ CHL2MP_Player *pPlayer = ToHL2MPPlayer( pEdict );
+
+ if ( pPlayer )
+ {
+ if ( gpGlobals->curtime > pPlayer->GetDeathTime() + DEATH_ANIMATION_TIME )
+ {
+ // respawn player
+ pPlayer->Spawn();
+ }
+ else
+ {
+ pPlayer->SetNextThink( gpGlobals->curtime + 0.1f );
+ }
+ }
+}
+
+void GameStartFrame( void )
+{
+ VPROF("GameStartFrame()");
+ if ( g_fGameOver )
+ return;
+
+ gpGlobals->teamplay = (teamplay.GetInt() != 0);
+
+#ifdef DEBUG
+ extern void Bot_RunAll();
+ Bot_RunAll();
+#endif
+}
+
+//=========================================================
+// instantiate the proper game rules object
+//=========================================================
+void InstallGameRules()
+{
+ // vanilla deathmatch
+ CreateGameRulesObject( "CHL2MPRules" );
+}
+
diff --git a/mp/src/game/server/hl2mp/hl2mp_cvars.cpp b/mp/src/game/server/hl2mp/hl2mp_cvars.cpp
new file mode 100644
index 00000000..cfca4217
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_cvars.cpp
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "hl2mp_cvars.h"
+
+
+
+// Ready restart
+ConVar mp_readyrestart(
+ "mp_readyrestart",
+ "0",
+ FCVAR_GAMEDLL,
+ "If non-zero, game will restart once each player gives the ready signal" );
+
+// Ready signal
+ConVar mp_ready_signal(
+ "mp_ready_signal",
+ "ready",
+ FCVAR_GAMEDLL,
+ "Text that each player must speak for the match to begin" ); \ No newline at end of file
diff --git a/mp/src/game/server/hl2mp/hl2mp_cvars.h b/mp/src/game/server/hl2mp/hl2mp_cvars.h
new file mode 100644
index 00000000..4276e46a
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_cvars.h
@@ -0,0 +1,20 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef HL2MP_CVARS_H
+#define HL2MP_CVARS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#define MAX_INTERMISSION_TIME 120
+
+extern ConVar mp_restartround;
+extern ConVar mp_readyrestart;
+extern ConVar mp_ready_signal;
+
+#endif //HL2MP_CVARS_H \ No newline at end of file
diff --git a/mp/src/game/server/hl2mp/hl2mp_gameinterface.cpp b/mp/src/game/server/hl2mp/hl2mp_gameinterface.cpp
new file mode 100644
index 00000000..556176d4
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_gameinterface.cpp
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "gameinterface.h"
+#include "mapentities.h"
+#include "hl2mp_gameinterface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// -------------------------------------------------------------------------------------------- //
+// Mod-specific CServerGameClients implementation.
+// -------------------------------------------------------------------------------------------- //
+
+void CServerGameClients::GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const
+{
+ minplayers = defaultMaxPlayers = 2;
+ maxplayers = 16;
+}
+
+// -------------------------------------------------------------------------------------------- //
+// Mod-specific CServerGameDLL implementation.
+// -------------------------------------------------------------------------------------------- //
+
+void CServerGameDLL::LevelInit_ParseAllEntities( const char *pMapEntities )
+{
+}
+
diff --git a/mp/src/game/server/hl2mp/hl2mp_gameinterface.h b/mp/src/game/server/hl2mp/hl2mp_gameinterface.h
new file mode 100644
index 00000000..fcadc471
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_gameinterface.h
@@ -0,0 +1,10 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+#ifndef HL2MP_GAMEINTERFACE_H
+#define HL2MP_GAMEINTERFACE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "gameinterface.h"
+
+#endif \ No newline at end of file
diff --git a/mp/src/game/server/hl2mp/hl2mp_player.cpp b/mp/src/game/server/hl2mp/hl2mp_player.cpp
new file mode 100644
index 00000000..fa828031
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_player.cpp
@@ -0,0 +1,1629 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Player for HL2.
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "weapon_hl2mpbasehlmpcombatweapon.h"
+#include "hl2mp_player.h"
+#include "globalstate.h"
+#include "game.h"
+#include "gamerules.h"
+#include "hl2mp_player_shared.h"
+#include "predicted_viewmodel.h"
+#include "in_buttons.h"
+#include "hl2mp_gamerules.h"
+#include "KeyValues.h"
+#include "team.h"
+#include "weapon_hl2mpbase.h"
+#include "grenade_satchel.h"
+#include "eventqueue.h"
+#include "gamestats.h"
+
+#include "engine/IEngineSound.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+
+#include "ilagcompensationmanager.h"
+
+int g_iLastCitizenModel = 0;
+int g_iLastCombineModel = 0;
+
+CBaseEntity *g_pLastCombineSpawn = NULL;
+CBaseEntity *g_pLastRebelSpawn = NULL;
+extern CBaseEntity *g_pLastSpawn;
+
+#define HL2MP_COMMAND_MAX_RATE 0.3
+
+void DropPrimedFragGrenade( CHL2MP_Player *pPlayer, CBaseCombatWeapon *pGrenade );
+
+LINK_ENTITY_TO_CLASS( player, CHL2MP_Player );
+
+LINK_ENTITY_TO_CLASS( info_player_combine, CPointEntity );
+LINK_ENTITY_TO_CLASS( info_player_rebel, CPointEntity );
+
+IMPLEMENT_SERVERCLASS_ST(CHL2MP_Player, DT_HL2MP_Player)
+ SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 11, SPROP_CHANGES_OFTEN ),
+ SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 11, SPROP_CHANGES_OFTEN ),
+ SendPropEHandle( SENDINFO( m_hRagdoll ) ),
+ SendPropInt( SENDINFO( m_iSpawnInterpCounter), 4 ),
+ SendPropInt( SENDINFO( m_iPlayerSoundType), 3 ),
+
+ SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
+ SendPropExclude( "DT_BaseFlex", "m_viewtarget" ),
+
+// SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
+// SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
+
+END_SEND_TABLE()
+
+BEGIN_DATADESC( CHL2MP_Player )
+END_DATADESC()
+
+const char *g_ppszRandomCitizenModels[] =
+{
+ "models/humans/group03/male_01.mdl",
+ "models/humans/group03/male_02.mdl",
+ "models/humans/group03/female_01.mdl",
+ "models/humans/group03/male_03.mdl",
+ "models/humans/group03/female_02.mdl",
+ "models/humans/group03/male_04.mdl",
+ "models/humans/group03/female_03.mdl",
+ "models/humans/group03/male_05.mdl",
+ "models/humans/group03/female_04.mdl",
+ "models/humans/group03/male_06.mdl",
+ "models/humans/group03/female_06.mdl",
+ "models/humans/group03/male_07.mdl",
+ "models/humans/group03/female_07.mdl",
+ "models/humans/group03/male_08.mdl",
+ "models/humans/group03/male_09.mdl",
+};
+
+const char *g_ppszRandomCombineModels[] =
+{
+ "models/combine_soldier.mdl",
+ "models/combine_soldier_prisonguard.mdl",
+ "models/combine_super_soldier.mdl",
+ "models/police.mdl",
+};
+
+
+#define MAX_COMBINE_MODELS 4
+#define MODEL_CHANGE_INTERVAL 5.0f
+#define TEAM_CHANGE_INTERVAL 5.0f
+
+#define HL2MPPLAYER_PHYSDAMAGE_SCALE 4.0f
+
+#pragma warning( disable : 4355 )
+
+CHL2MP_Player::CHL2MP_Player() : m_PlayerAnimState( this )
+{
+ m_angEyeAngles.Init();
+
+ m_iLastWeaponFireUsercmd = 0;
+
+ m_flNextModelChangeTime = 0.0f;
+ m_flNextTeamChangeTime = 0.0f;
+
+ m_iSpawnInterpCounter = 0;
+
+ m_bEnterObserver = false;
+ m_bReady = false;
+
+ BaseClass::ChangeTeam( 0 );
+
+// UseClientSideAnimation();
+}
+
+CHL2MP_Player::~CHL2MP_Player( void )
+{
+
+}
+
+void CHL2MP_Player::UpdateOnRemove( void )
+{
+ if ( m_hRagdoll )
+ {
+ UTIL_RemoveImmediate( m_hRagdoll );
+ m_hRagdoll = NULL;
+ }
+
+ BaseClass::UpdateOnRemove();
+}
+
+void CHL2MP_Player::Precache( void )
+{
+ BaseClass::Precache();
+
+ PrecacheModel ( "sprites/glow01.vmt" );
+
+ //Precache Citizen models
+ int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
+ int i;
+
+ for ( i = 0; i < nHeads; ++i )
+ PrecacheModel( g_ppszRandomCitizenModels[i] );
+
+ //Precache Combine Models
+ nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
+
+ for ( i = 0; i < nHeads; ++i )
+ PrecacheModel( g_ppszRandomCombineModels[i] );
+
+ PrecacheFootStepSounds();
+
+ PrecacheScriptSound( "NPC_MetroPolice.Die" );
+ PrecacheScriptSound( "NPC_CombineS.Die" );
+ PrecacheScriptSound( "NPC_Citizen.die" );
+}
+
+void CHL2MP_Player::GiveAllItems( void )
+{
+ EquipSuit();
+
+ CBasePlayer::GiveAmmo( 255, "Pistol");
+ CBasePlayer::GiveAmmo( 255, "AR2" );
+ CBasePlayer::GiveAmmo( 5, "AR2AltFire" );
+ CBasePlayer::GiveAmmo( 255, "SMG1");
+ CBasePlayer::GiveAmmo( 1, "smg1_grenade");
+ CBasePlayer::GiveAmmo( 255, "Buckshot");
+ CBasePlayer::GiveAmmo( 32, "357" );
+ CBasePlayer::GiveAmmo( 3, "rpg_round");
+
+ CBasePlayer::GiveAmmo( 1, "grenade" );
+ CBasePlayer::GiveAmmo( 2, "slam" );
+
+ GiveNamedItem( "weapon_crowbar" );
+ GiveNamedItem( "weapon_stunstick" );
+ GiveNamedItem( "weapon_pistol" );
+ GiveNamedItem( "weapon_357" );
+
+ GiveNamedItem( "weapon_smg1" );
+ GiveNamedItem( "weapon_ar2" );
+
+ GiveNamedItem( "weapon_shotgun" );
+ GiveNamedItem( "weapon_frag" );
+
+ GiveNamedItem( "weapon_crossbow" );
+
+ GiveNamedItem( "weapon_rpg" );
+
+ GiveNamedItem( "weapon_slam" );
+
+ GiveNamedItem( "weapon_physcannon" );
+
+}
+
+void CHL2MP_Player::GiveDefaultItems( void )
+{
+ EquipSuit();
+
+ CBasePlayer::GiveAmmo( 255, "Pistol");
+ CBasePlayer::GiveAmmo( 45, "SMG1");
+ CBasePlayer::GiveAmmo( 1, "grenade" );
+ CBasePlayer::GiveAmmo( 6, "Buckshot");
+ CBasePlayer::GiveAmmo( 6, "357" );
+
+ if ( GetPlayerModelType() == PLAYER_SOUNDS_METROPOLICE || GetPlayerModelType() == PLAYER_SOUNDS_COMBINESOLDIER )
+ {
+ GiveNamedItem( "weapon_stunstick" );
+ }
+ else if ( GetPlayerModelType() == PLAYER_SOUNDS_CITIZEN )
+ {
+ GiveNamedItem( "weapon_crowbar" );
+ }
+
+ GiveNamedItem( "weapon_pistol" );
+ GiveNamedItem( "weapon_smg1" );
+ GiveNamedItem( "weapon_frag" );
+ GiveNamedItem( "weapon_physcannon" );
+
+ const char *szDefaultWeaponName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_defaultweapon" );
+
+ CBaseCombatWeapon *pDefaultWeapon = Weapon_OwnsThisType( szDefaultWeaponName );
+
+ if ( pDefaultWeapon )
+ {
+ Weapon_Switch( pDefaultWeapon );
+ }
+ else
+ {
+ Weapon_Switch( Weapon_OwnsThisType( "weapon_physcannon" ) );
+ }
+}
+
+void CHL2MP_Player::PickDefaultSpawnTeam( void )
+{
+ if ( GetTeamNumber() == 0 )
+ {
+ if ( HL2MPRules()->IsTeamplay() == false )
+ {
+ if ( GetModelPtr() == NULL )
+ {
+ const char *szModelName = NULL;
+ szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
+
+ if ( ValidatePlayerModel( szModelName ) == false )
+ {
+ char szReturnString[512];
+
+ Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel models/combine_soldier.mdl\n" );
+ engine->ClientCommand ( edict(), szReturnString );
+ }
+
+ ChangeTeam( TEAM_UNASSIGNED );
+ }
+ }
+ else
+ {
+ CTeam *pCombine = g_Teams[TEAM_COMBINE];
+ CTeam *pRebels = g_Teams[TEAM_REBELS];
+
+ if ( pCombine == NULL || pRebels == NULL )
+ {
+ ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
+ }
+ else
+ {
+ if ( pCombine->GetNumPlayers() > pRebels->GetNumPlayers() )
+ {
+ ChangeTeam( TEAM_REBELS );
+ }
+ else if ( pCombine->GetNumPlayers() < pRebels->GetNumPlayers() )
+ {
+ ChangeTeam( TEAM_COMBINE );
+ }
+ else
+ {
+ ChangeTeam( random->RandomInt( TEAM_COMBINE, TEAM_REBELS ) );
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets HL2 specific defaults.
+//-----------------------------------------------------------------------------
+void CHL2MP_Player::Spawn(void)
+{
+ m_flNextModelChangeTime = 0.0f;
+ m_flNextTeamChangeTime = 0.0f;
+
+ PickDefaultSpawnTeam();
+
+ BaseClass::Spawn();
+
+ if ( !IsObserver() )
+ {
+ pl.deadflag = false;
+ RemoveSolidFlags( FSOLID_NOT_SOLID );
+
+ RemoveEffects( EF_NODRAW );
+
+ GiveDefaultItems();
+ }
+
+ SetNumAnimOverlays( 3 );
+ ResetAnimation();
+
+ m_nRenderFX = kRenderNormal;
+
+ m_Local.m_iHideHUD = 0;
+
+ AddFlag(FL_ONGROUND); // set the player on the ground at the start of the round.
+
+ m_impactEnergyScale = HL2MPPLAYER_PHYSDAMAGE_SCALE;
+
+ if ( HL2MPRules()->IsIntermission() )
+ {
+ AddFlag( FL_FROZEN );
+ }
+ else
+ {
+ RemoveFlag( FL_FROZEN );
+ }
+
+ m_iSpawnInterpCounter = (m_iSpawnInterpCounter + 1) % 8;
+
+ m_Local.m_bDucked = false;
+
+ SetPlayerUnderwater(false);
+
+ m_bReady = false;
+}
+
+void CHL2MP_Player::PickupObject( CBaseEntity *pObject, bool bLimitMassAndSize )
+{
+
+}
+
+bool CHL2MP_Player::ValidatePlayerModel( const char *pModel )
+{
+ int iModels = ARRAYSIZE( g_ppszRandomCitizenModels );
+ int i;
+
+ for ( i = 0; i < iModels; ++i )
+ {
+ if ( !Q_stricmp( g_ppszRandomCitizenModels[i], pModel ) )
+ {
+ return true;
+ }
+ }
+
+ iModels = ARRAYSIZE( g_ppszRandomCombineModels );
+
+ for ( i = 0; i < iModels; ++i )
+ {
+ if ( !Q_stricmp( g_ppszRandomCombineModels[i], pModel ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CHL2MP_Player::SetPlayerTeamModel( void )
+{
+ const char *szModelName = NULL;
+ szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
+
+ int modelIndex = modelinfo->GetModelIndex( szModelName );
+
+ if ( modelIndex == -1 || ValidatePlayerModel( szModelName ) == false )
+ {
+ szModelName = "models/Combine_Soldier.mdl";
+ m_iModelType = TEAM_COMBINE;
+
+ char szReturnString[512];
+
+ Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", szModelName );
+ engine->ClientCommand ( edict(), szReturnString );
+ }
+
+ if ( GetTeamNumber() == TEAM_COMBINE )
+ {
+ if ( Q_stristr( szModelName, "models/human") )
+ {
+ int nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
+
+ g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads;
+ szModelName = g_ppszRandomCombineModels[g_iLastCombineModel];
+ }
+
+ m_iModelType = TEAM_COMBINE;
+ }
+ else if ( GetTeamNumber() == TEAM_REBELS )
+ {
+ if ( !Q_stristr( szModelName, "models/human") )
+ {
+ int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
+
+ g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads;
+ szModelName = g_ppszRandomCitizenModels[g_iLastCitizenModel];
+ }
+
+ m_iModelType = TEAM_REBELS;
+ }
+
+ SetModel( szModelName );
+ SetupPlayerSoundsByModel( szModelName );
+
+ m_flNextModelChangeTime = gpGlobals->curtime + MODEL_CHANGE_INTERVAL;
+}
+
+void CHL2MP_Player::SetPlayerModel( void )
+{
+ const char *szModelName = NULL;
+ const char *pszCurrentModelName = modelinfo->GetModelName( GetModel());
+
+ szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_playermodel" );
+
+ if ( ValidatePlayerModel( szModelName ) == false )
+ {
+ char szReturnString[512];
+
+ if ( ValidatePlayerModel( pszCurrentModelName ) == false )
+ {
+ pszCurrentModelName = "models/Combine_Soldier.mdl";
+ }
+
+ Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pszCurrentModelName );
+ engine->ClientCommand ( edict(), szReturnString );
+
+ szModelName = pszCurrentModelName;
+ }
+
+ if ( GetTeamNumber() == TEAM_COMBINE )
+ {
+ int nHeads = ARRAYSIZE( g_ppszRandomCombineModels );
+
+ g_iLastCombineModel = ( g_iLastCombineModel + 1 ) % nHeads;
+ szModelName = g_ppszRandomCombineModels[g_iLastCombineModel];
+
+ m_iModelType = TEAM_COMBINE;
+ }
+ else if ( GetTeamNumber() == TEAM_REBELS )
+ {
+ int nHeads = ARRAYSIZE( g_ppszRandomCitizenModels );
+
+ g_iLastCitizenModel = ( g_iLastCitizenModel + 1 ) % nHeads;
+ szModelName = g_ppszRandomCitizenModels[g_iLastCitizenModel];
+
+ m_iModelType = TEAM_REBELS;
+ }
+ else
+ {
+ if ( Q_strlen( szModelName ) == 0 )
+ {
+ szModelName = g_ppszRandomCitizenModels[0];
+ }
+
+ if ( Q_stristr( szModelName, "models/human") )
+ {
+ m_iModelType = TEAM_REBELS;
+ }
+ else
+ {
+ m_iModelType = TEAM_COMBINE;
+ }
+ }
+
+ int modelIndex = modelinfo->GetModelIndex( szModelName );
+
+ if ( modelIndex == -1 )
+ {
+ szModelName = "models/Combine_Soldier.mdl";
+ m_iModelType = TEAM_COMBINE;
+
+ char szReturnString[512];
+
+ Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", szModelName );
+ engine->ClientCommand ( edict(), szReturnString );
+ }
+
+ SetModel( szModelName );
+ SetupPlayerSoundsByModel( szModelName );
+
+ m_flNextModelChangeTime = gpGlobals->curtime + MODEL_CHANGE_INTERVAL;
+}
+
+void CHL2MP_Player::SetupPlayerSoundsByModel( const char *pModelName )
+{
+ if ( Q_stristr( pModelName, "models/human") )
+ {
+ m_iPlayerSoundType = (int)PLAYER_SOUNDS_CITIZEN;
+ }
+ else if ( Q_stristr(pModelName, "police" ) )
+ {
+ m_iPlayerSoundType = (int)PLAYER_SOUNDS_METROPOLICE;
+ }
+ else if ( Q_stristr(pModelName, "combine" ) )
+ {
+ m_iPlayerSoundType = (int)PLAYER_SOUNDS_COMBINESOLDIER;
+ }
+}
+
+void CHL2MP_Player::ResetAnimation( void )
+{
+ if ( IsAlive() )
+ {
+ SetSequence ( -1 );
+ SetActivity( ACT_INVALID );
+
+ if (!GetAbsVelocity().x && !GetAbsVelocity().y)
+ SetAnimation( PLAYER_IDLE );
+ else if ((GetAbsVelocity().x || GetAbsVelocity().y) && ( GetFlags() & FL_ONGROUND ))
+ SetAnimation( PLAYER_WALK );
+ else if (GetWaterLevel() > 1)
+ SetAnimation( PLAYER_WALK );
+ }
+}
+
+
+bool CHL2MP_Player::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex )
+{
+ bool bRet = BaseClass::Weapon_Switch( pWeapon, viewmodelindex );
+
+ if ( bRet == true )
+ {
+ ResetAnimation();
+ }
+
+ return bRet;
+}
+
+void CHL2MP_Player::PreThink( void )
+{
+ QAngle vOldAngles = GetLocalAngles();
+ QAngle vTempAngles = GetLocalAngles();
+
+ vTempAngles = EyeAngles();
+
+ if ( vTempAngles[PITCH] > 180.0f )
+ {
+ vTempAngles[PITCH] -= 360.0f;
+ }
+
+ SetLocalAngles( vTempAngles );
+
+ BaseClass::PreThink();
+ State_PreThink();
+
+ //Reset bullet force accumulator, only lasts one frame
+ m_vecTotalBulletForce = vec3_origin;
+ SetLocalAngles( vOldAngles );
+}
+
+void CHL2MP_Player::PostThink( void )
+{
+ BaseClass::PostThink();
+
+ if ( GetFlags() & FL_DUCKING )
+ {
+ SetCollisionBounds( VEC_CROUCH_TRACE_MIN, VEC_CROUCH_TRACE_MAX );
+ }
+
+ m_PlayerAnimState.Update();
+
+ // Store the eye angles pitch so the client can compute its animation state correctly.
+ m_angEyeAngles = EyeAngles();
+
+ QAngle angles = GetLocalAngles();
+ angles[PITCH] = 0;
+ SetLocalAngles( angles );
+}
+
+void CHL2MP_Player::PlayerDeathThink()
+{
+ if( !IsObserver() )
+ {
+ BaseClass::PlayerDeathThink();
+ }
+}
+
+void CHL2MP_Player::FireBullets ( const FireBulletsInfo_t &info )
+{
+ // Move other players back to history positions based on local player's lag
+ lagcompensation->StartLagCompensation( this, this->GetCurrentCommand() );
+
+ FireBulletsInfo_t modinfo = info;
+
+ CWeaponHL2MPBase *pWeapon = dynamic_cast<CWeaponHL2MPBase *>( GetActiveWeapon() );
+
+ if ( pWeapon )
+ {
+ modinfo.m_iPlayerDamage = modinfo.m_flDamage = pWeapon->GetHL2MPWpnData().m_iPlayerDamage;
+ }
+
+ NoteWeaponFired();
+
+ BaseClass::FireBullets( modinfo );
+
+ // Move other players back to history positions based on local player's lag
+ lagcompensation->FinishLagCompensation( this );
+}
+
+void CHL2MP_Player::NoteWeaponFired( void )
+{
+ Assert( m_pCurrentCommand );
+ if( m_pCurrentCommand )
+ {
+ m_iLastWeaponFireUsercmd = m_pCurrentCommand->command_number;
+ }
+}
+
+extern ConVar sv_maxunlag;
+
+bool CHL2MP_Player::WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const
+{
+ // No need to lag compensate at all if we're not attacking in this command and
+ // we haven't attacked recently.
+ if ( !( pCmd->buttons & IN_ATTACK ) && (pCmd->command_number - m_iLastWeaponFireUsercmd > 5) )
+ return false;
+
+ // If this entity hasn't been transmitted to us and acked, then don't bother lag compensating it.
+ if ( pEntityTransmitBits && !pEntityTransmitBits->Get( pPlayer->entindex() ) )
+ return false;
+
+ const Vector &vMyOrigin = GetAbsOrigin();
+ const Vector &vHisOrigin = pPlayer->GetAbsOrigin();
+
+ // get max distance player could have moved within max lag compensation time,
+ // multiply by 1.5 to to avoid "dead zones" (sqrt(2) would be the exact value)
+ float maxDistance = 1.5 * pPlayer->MaxSpeed() * sv_maxunlag.GetFloat();
+
+ // If the player is within this distance, lag compensate them in case they're running past us.
+ if ( vHisOrigin.DistTo( vMyOrigin ) < maxDistance )
+ return true;
+
+ // If their origin is not within a 45 degree cone in front of us, no need to lag compensate.
+ Vector vForward;
+ AngleVectors( pCmd->viewangles, &vForward );
+
+ Vector vDiff = vHisOrigin - vMyOrigin;
+ VectorNormalize( vDiff );
+
+ float flCosAngle = 0.707107f; // 45 degree angle
+ if ( vForward.Dot( vDiff ) < flCosAngle )
+ return false;
+
+ return true;
+}
+
+Activity CHL2MP_Player::TranslateTeamActivity( Activity ActToTranslate )
+{
+ if ( m_iModelType == TEAM_COMBINE )
+ return ActToTranslate;
+
+ if ( ActToTranslate == ACT_RUN )
+ return ACT_RUN_AIM_AGITATED;
+
+ if ( ActToTranslate == ACT_IDLE )
+ return ACT_IDLE_AIM_AGITATED;
+
+ if ( ActToTranslate == ACT_WALK )
+ return ACT_WALK_AIM_AGITATED;
+
+ return ActToTranslate;
+}
+
+extern ConVar hl2_normspeed;
+
+// Set the activity based on an event or current state
+void CHL2MP_Player::SetAnimation( PLAYER_ANIM playerAnim )
+{
+ int animDesired;
+
+ float speed;
+
+ speed = GetAbsVelocity().Length2D();
+
+
+ // bool bRunning = true;
+
+ //Revisit!
+/* if ( ( m_nButtons & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) )
+ {
+ if ( speed > 1.0f && speed < hl2_normspeed.GetFloat() - 20.0f )
+ {
+ bRunning = false;
+ }
+ }*/
+
+ if ( GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) )
+ {
+ speed = 0;
+ playerAnim = PLAYER_IDLE;
+ }
+
+ Activity idealActivity = ACT_HL2MP_RUN;
+
+ // This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
+ if ( playerAnim == PLAYER_JUMP )
+ {
+ idealActivity = ACT_HL2MP_JUMP;
+ }
+ else if ( playerAnim == PLAYER_DIE )
+ {
+ if ( m_lifeState == LIFE_ALIVE )
+ {
+ return;
+ }
+ }
+ else if ( playerAnim == PLAYER_ATTACK1 )
+ {
+ if ( GetActivity( ) == ACT_HOVER ||
+ GetActivity( ) == ACT_SWIM ||
+ GetActivity( ) == ACT_HOP ||
+ GetActivity( ) == ACT_LEAP ||
+ GetActivity( ) == ACT_DIESIMPLE )
+ {
+ idealActivity = GetActivity( );
+ }
+ else
+ {
+ idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK;
+ }
+ }
+ else if ( playerAnim == PLAYER_RELOAD )
+ {
+ idealActivity = ACT_HL2MP_GESTURE_RELOAD;
+ }
+ else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK )
+ {
+ if ( !( GetFlags() & FL_ONGROUND ) && GetActivity( ) == ACT_HL2MP_JUMP ) // Still jumping
+ {
+ idealActivity = GetActivity( );
+ }
+ /*
+ else if ( GetWaterLevel() > 1 )
+ {
+ if ( speed == 0 )
+ idealActivity = ACT_HOVER;
+ else
+ idealActivity = ACT_SWIM;
+ }
+ */
+ else
+ {
+ if ( GetFlags() & FL_DUCKING )
+ {
+ if ( speed > 0 )
+ {
+ idealActivity = ACT_HL2MP_WALK_CROUCH;
+ }
+ else
+ {
+ idealActivity = ACT_HL2MP_IDLE_CROUCH;
+ }
+ }
+ else
+ {
+ if ( speed > 0 )
+ {
+ /*
+ if ( bRunning == false )
+ {
+ idealActivity = ACT_WALK;
+ }
+ else
+ */
+ {
+ idealActivity = ACT_HL2MP_RUN;
+ }
+ }
+ else
+ {
+ idealActivity = ACT_HL2MP_IDLE;
+ }
+ }
+ }
+
+ idealActivity = TranslateTeamActivity( idealActivity );
+ }
+
+ if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK )
+ {
+ RestartGesture( Weapon_TranslateActivity( idealActivity ) );
+
+ // FIXME: this seems a bit wacked
+ Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
+
+ return;
+ }
+ else if ( idealActivity == ACT_HL2MP_GESTURE_RELOAD )
+ {
+ RestartGesture( Weapon_TranslateActivity( idealActivity ) );
+ return;
+ }
+ else
+ {
+ SetActivity( idealActivity );
+
+ animDesired = SelectWeightedSequence( Weapon_TranslateActivity ( idealActivity ) );
+
+ if (animDesired == -1)
+ {
+ animDesired = SelectWeightedSequence( idealActivity );
+
+ if ( animDesired == -1 )
+ {
+ animDesired = 0;
+ }
+ }
+
+ // Already using the desired animation?
+ if ( GetSequence() == animDesired )
+ return;
+
+ m_flPlaybackRate = 1.0;
+ ResetSequence( animDesired );
+ SetCycle( 0 );
+ return;
+ }
+
+ // Already using the desired animation?
+ if ( GetSequence() == animDesired )
+ return;
+
+ //Msg( "Set animation to %d\n", animDesired );
+ // Reset to first frame of desired animation
+ ResetSequence( animDesired );
+ SetCycle( 0 );
+}
+
+
+extern int gEvilImpulse101;
+//-----------------------------------------------------------------------------
+// Purpose: Player reacts to bumping a weapon.
+// Input : pWeapon - the weapon that the player bumped into.
+// Output : Returns true if player picked up the weapon
+//-----------------------------------------------------------------------------
+bool CHL2MP_Player::BumpWeapon( CBaseCombatWeapon *pWeapon )
+{
+ CBaseCombatCharacter *pOwner = pWeapon->GetOwner();
+
+ // Can I have this weapon type?
+ if ( !IsAllowedToPickupWeapons() )
+ return false;
+
+ if ( pOwner || !Weapon_CanUse( pWeapon ) || !g_pGameRules->CanHavePlayerItem( this, pWeapon ) )
+ {
+ if ( gEvilImpulse101 )
+ {
+ UTIL_Remove( pWeapon );
+ }
+ return false;
+ }
+
+ // Don't let the player fetch weapons through walls (use MASK_SOLID so that you can't pickup through windows)
+ if( !pWeapon->FVisible( this, MASK_SOLID ) && !(GetFlags() & FL_NOTARGET) )
+ {
+ return false;
+ }
+
+ bool bOwnsWeaponAlready = !!Weapon_OwnsThisType( pWeapon->GetClassname(), pWeapon->GetSubType());
+
+ if ( bOwnsWeaponAlready == true )
+ {
+ //If we have room for the ammo, then "take" the weapon too.
+ if ( Weapon_EquipAmmoOnly( pWeapon ) )
+ {
+ pWeapon->CheckRespawn();
+
+ UTIL_Remove( pWeapon );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ pWeapon->CheckRespawn();
+ Weapon_Equip( pWeapon );
+
+ return true;
+}
+
+void CHL2MP_Player::ChangeTeam( int iTeam )
+{
+/* if ( GetNextTeamChangeTime() >= gpGlobals->curtime )
+ {
+ char szReturnString[128];
+ Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch teams again.\n", (int)(GetNextTeamChangeTime() - gpGlobals->curtime) );
+
+ ClientPrint( this, HUD_PRINTTALK, szReturnString );
+ return;
+ }*/
+
+ bool bKill = false;
+
+ if ( HL2MPRules()->IsTeamplay() != true && iTeam != TEAM_SPECTATOR )
+ {
+ //don't let them try to join combine or rebels during deathmatch.
+ iTeam = TEAM_UNASSIGNED;
+ }
+
+ if ( HL2MPRules()->IsTeamplay() == true )
+ {
+ if ( iTeam != GetTeamNumber() && GetTeamNumber() != TEAM_UNASSIGNED )
+ {
+ bKill = true;
+ }
+ }
+
+ BaseClass::ChangeTeam( iTeam );
+
+ m_flNextTeamChangeTime = gpGlobals->curtime + TEAM_CHANGE_INTERVAL;
+
+ if ( HL2MPRules()->IsTeamplay() == true )
+ {
+ SetPlayerTeamModel();
+ }
+ else
+ {
+ SetPlayerModel();
+ }
+
+ if ( iTeam == TEAM_SPECTATOR )
+ {
+ RemoveAllItems( true );
+
+ State_Transition( STATE_OBSERVER_MODE );
+ }
+
+ if ( bKill == true )
+ {
+ CommitSuicide();
+ }
+}
+
+bool CHL2MP_Player::HandleCommand_JoinTeam( int team )
+{
+ if ( !GetGlobalTeam( team ) || team == 0 )
+ {
+ Warning( "HandleCommand_JoinTeam( %d ) - invalid team index.\n", team );
+ return false;
+ }
+
+ if ( team == TEAM_SPECTATOR )
+ {
+ // Prevent this is the cvar is set
+ if ( !mp_allowspectators.GetInt() )
+ {
+ ClientPrint( this, HUD_PRINTCENTER, "#Cannot_Be_Spectator" );
+ return false;
+ }
+
+ if ( GetTeamNumber() != TEAM_UNASSIGNED && !IsDead() )
+ {
+ m_fNextSuicideTime = gpGlobals->curtime; // allow the suicide to work
+
+ CommitSuicide();
+
+ // add 1 to frags to balance out the 1 subtracted for killing yourself
+ IncrementFragCount( 1 );
+ }
+
+ ChangeTeam( TEAM_SPECTATOR );
+
+ return true;
+ }
+ else
+ {
+ StopObserverMode();
+ State_Transition(STATE_ACTIVE);
+ }
+
+ // Switch their actual team...
+ ChangeTeam( team );
+
+ return true;
+}
+
+bool CHL2MP_Player::ClientCommand( const CCommand &args )
+{
+ if ( FStrEq( args[0], "spectate" ) )
+ {
+ if ( ShouldRunRateLimitedCommand( args ) )
+ {
+ // instantly join spectators
+ HandleCommand_JoinTeam( TEAM_SPECTATOR );
+ }
+ return true;
+ }
+ else if ( FStrEq( args[0], "jointeam" ) )
+ {
+ if ( args.ArgC() < 2 )
+ {
+ Warning( "Player sent bad jointeam syntax\n" );
+ }
+
+ if ( ShouldRunRateLimitedCommand( args ) )
+ {
+ int iTeam = atoi( args[1] );
+ HandleCommand_JoinTeam( iTeam );
+ }
+ return true;
+ }
+ else if ( FStrEq( args[0], "joingame" ) )
+ {
+ return true;
+ }
+
+ return BaseClass::ClientCommand( args );
+}
+
+void CHL2MP_Player::CheatImpulseCommands( int iImpulse )
+{
+ switch ( iImpulse )
+ {
+ case 101:
+ {
+ if( sv_cheats->GetBool() )
+ {
+ GiveAllItems();
+ }
+ }
+ break;
+
+ default:
+ BaseClass::CheatImpulseCommands( iImpulse );
+ }
+}
+
+bool CHL2MP_Player::ShouldRunRateLimitedCommand( const CCommand &args )
+{
+ int i = m_RateLimitLastCommandTimes.Find( args[0] );
+ if ( i == m_RateLimitLastCommandTimes.InvalidIndex() )
+ {
+ m_RateLimitLastCommandTimes.Insert( args[0], gpGlobals->curtime );
+ return true;
+ }
+ else if ( (gpGlobals->curtime - m_RateLimitLastCommandTimes[i]) < HL2MP_COMMAND_MAX_RATE )
+ {
+ // Too fast.
+ return false;
+ }
+ else
+ {
+ m_RateLimitLastCommandTimes[i] = gpGlobals->curtime;
+ return true;
+ }
+}
+
+void CHL2MP_Player::CreateViewModel( int index /*=0*/ )
+{
+ Assert( index >= 0 && index < MAX_VIEWMODELS );
+
+ if ( GetViewModel( index ) )
+ return;
+
+ CPredictedViewModel *vm = ( CPredictedViewModel * )CreateEntityByName( "predicted_viewmodel" );
+ if ( vm )
+ {
+ vm->SetAbsOrigin( GetAbsOrigin() );
+ vm->SetOwner( this );
+ vm->SetIndex( index );
+ DispatchSpawn( vm );
+ vm->FollowEntity( this, false );
+ m_hViewModel.Set( index, vm );
+ }
+}
+
+bool CHL2MP_Player::BecomeRagdollOnClient( const Vector &force )
+{
+ return true;
+}
+
+// -------------------------------------------------------------------------------- //
+// Ragdoll entities.
+// -------------------------------------------------------------------------------- //
+
+class CHL2MPRagdoll : public CBaseAnimatingOverlay
+{
+public:
+ DECLARE_CLASS( CHL2MPRagdoll, CBaseAnimatingOverlay );
+ DECLARE_SERVERCLASS();
+
+ // Transmit ragdolls to everyone.
+ virtual int UpdateTransmitState()
+ {
+ return SetTransmitState( FL_EDICT_ALWAYS );
+ }
+
+public:
+ // In case the client has the player entity, we transmit the player index.
+ // In case the client doesn't have it, we transmit the player's model index, origin, and angles
+ // so they can create a ragdoll in the right place.
+ CNetworkHandle( CBaseEntity, m_hPlayer ); // networked entity handle
+ CNetworkVector( m_vecRagdollVelocity );
+ CNetworkVector( m_vecRagdollOrigin );
+};
+
+LINK_ENTITY_TO_CLASS( hl2mp_ragdoll, CHL2MPRagdoll );
+
+IMPLEMENT_SERVERCLASS_ST_NOBASE( CHL2MPRagdoll, DT_HL2MPRagdoll )
+ SendPropVector( SENDINFO(m_vecRagdollOrigin), -1, SPROP_COORD ),
+ SendPropEHandle( SENDINFO( m_hPlayer ) ),
+ SendPropModelIndex( SENDINFO( m_nModelIndex ) ),
+ SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ),
+ SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ),
+ SendPropVector( SENDINFO( m_vecRagdollVelocity ) )
+END_SEND_TABLE()
+
+
+void CHL2MP_Player::CreateRagdollEntity( void )
+{
+ if ( m_hRagdoll )
+ {
+ UTIL_RemoveImmediate( m_hRagdoll );
+ m_hRagdoll = NULL;
+ }
+
+ // If we already have a ragdoll, don't make another one.
+ CHL2MPRagdoll *pRagdoll = dynamic_cast< CHL2MPRagdoll* >( m_hRagdoll.Get() );
+
+ if ( !pRagdoll )
+ {
+ // create a new one
+ pRagdoll = dynamic_cast< CHL2MPRagdoll* >( CreateEntityByName( "hl2mp_ragdoll" ) );
+ }
+
+ if ( pRagdoll )
+ {
+ pRagdoll->m_hPlayer = this;
+ pRagdoll->m_vecRagdollOrigin = GetAbsOrigin();
+ pRagdoll->m_vecRagdollVelocity = GetAbsVelocity();
+ pRagdoll->m_nModelIndex = m_nModelIndex;
+ pRagdoll->m_nForceBone = m_nForceBone;
+ pRagdoll->m_vecForce = m_vecTotalBulletForce;
+ pRagdoll->SetAbsOrigin( GetAbsOrigin() );
+ }
+
+ // ragdolls will be removed on round restart automatically
+ m_hRagdoll = pRagdoll;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CHL2MP_Player::FlashlightIsOn( void )
+{
+ return IsEffectActive( EF_DIMLIGHT );
+}
+
+extern ConVar flashlight;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CHL2MP_Player::FlashlightTurnOn( void )
+{
+ if( flashlight.GetInt() > 0 && IsAlive() )
+ {
+ AddEffects( EF_DIMLIGHT );
+ EmitSound( "HL2Player.FlashlightOn" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CHL2MP_Player::FlashlightTurnOff( void )
+{
+ RemoveEffects( EF_DIMLIGHT );
+
+ if( IsAlive() )
+ {
+ EmitSound( "HL2Player.FlashlightOff" );
+ }
+}
+
+void CHL2MP_Player::Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity )
+{
+ //Drop a grenade if it's primed.
+ if ( GetActiveWeapon() )
+ {
+ CBaseCombatWeapon *pGrenade = Weapon_OwnsThisType("weapon_frag");
+
+ if ( GetActiveWeapon() == pGrenade )
+ {
+ if ( ( m_nButtons & IN_ATTACK ) || (m_nButtons & IN_ATTACK2) )
+ {
+ DropPrimedFragGrenade( this, pGrenade );
+ return;
+ }
+ }
+ }
+
+ BaseClass::Weapon_Drop( pWeapon, pvecTarget, pVelocity );
+}
+
+
+void CHL2MP_Player::DetonateTripmines( void )
+{
+ CBaseEntity *pEntity = NULL;
+
+ while ((pEntity = gEntList.FindEntityByClassname( pEntity, "npc_satchel" )) != NULL)
+ {
+ CSatchelCharge *pSatchel = dynamic_cast<CSatchelCharge *>(pEntity);
+ if (pSatchel->m_bIsLive && pSatchel->GetThrower() == this )
+ {
+ g_EventQueue.AddEvent( pSatchel, "Explode", 0.20, this, this );
+ }
+ }
+
+ // Play sound for pressing the detonator
+ EmitSound( "Weapon_SLAM.SatchelDetonate" );
+}
+
+void CHL2MP_Player::Event_Killed( const CTakeDamageInfo &info )
+{
+ //update damage info with our accumulated physics force
+ CTakeDamageInfo subinfo = info;
+ subinfo.SetDamageForce( m_vecTotalBulletForce );
+
+ SetNumAnimOverlays( 0 );
+
+ // Note: since we're dead, it won't draw us on the client, but we don't set EF_NODRAW
+ // because we still want to transmit to the clients in our PVS.
+ CreateRagdollEntity();
+
+ DetonateTripmines();
+
+ BaseClass::Event_Killed( subinfo );
+
+ if ( info.GetDamageType() & DMG_DISSOLVE )
+ {
+ if ( m_hRagdoll )
+ {
+ m_hRagdoll->GetBaseAnimating()->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL );
+ }
+ }
+
+ CBaseEntity *pAttacker = info.GetAttacker();
+
+ if ( pAttacker )
+ {
+ int iScoreToAdd = 1;
+
+ if ( pAttacker == this )
+ {
+ iScoreToAdd = -1;
+ }
+
+ GetGlobalTeam( pAttacker->GetTeamNumber() )->AddScore( iScoreToAdd );
+ }
+
+ FlashlightTurnOff();
+
+ m_lifeState = LIFE_DEAD;
+
+ RemoveEffects( EF_NODRAW ); // still draw player body
+ StopZooming();
+}
+
+int CHL2MP_Player::OnTakeDamage( const CTakeDamageInfo &inputInfo )
+{
+ //return here if the player is in the respawn grace period vs. slams.
+ if ( gpGlobals->curtime < m_flSlamProtectTime && (inputInfo.GetDamageType() == DMG_BLAST ) )
+ return 0;
+
+ m_vecTotalBulletForce += inputInfo.GetDamageForce();
+
+ gamestats->Event_PlayerDamage( this, inputInfo );
+
+ return BaseClass::OnTakeDamage( inputInfo );
+}
+
+void CHL2MP_Player::DeathSound( const CTakeDamageInfo &info )
+{
+ if ( m_hRagdoll && m_hRagdoll->GetBaseAnimating()->IsDissolving() )
+ return;
+
+ char szStepSound[128];
+
+ Q_snprintf( szStepSound, sizeof( szStepSound ), "%s.Die", GetPlayerModelSoundPrefix() );
+
+ const char *pModelName = STRING( GetModelName() );
+
+ CSoundParameters params;
+ if ( GetParametersForSound( szStepSound, params, pModelName ) == false )
+ return;
+
+ Vector vecOrigin = GetAbsOrigin();
+
+ CRecipientFilter filter;
+ filter.AddRecipientsByPAS( vecOrigin );
+
+ EmitSound_t ep;
+ ep.m_nChannel = params.channel;
+ ep.m_pSoundName = params.soundname;
+ ep.m_flVolume = params.volume;
+ ep.m_SoundLevel = params.soundlevel;
+ ep.m_nFlags = 0;
+ ep.m_nPitch = params.pitch;
+ ep.m_pOrigin = &vecOrigin;
+
+ EmitSound( filter, entindex(), ep );
+}
+
+CBaseEntity* CHL2MP_Player::EntSelectSpawnPoint( void )
+{
+ CBaseEntity *pSpot = NULL;
+ CBaseEntity *pLastSpawnPoint = g_pLastSpawn;
+ edict_t *player = edict();
+ const char *pSpawnpointName = "info_player_deathmatch";
+
+ if ( HL2MPRules()->IsTeamplay() == true )
+ {
+ if ( GetTeamNumber() == TEAM_COMBINE )
+ {
+ pSpawnpointName = "info_player_combine";
+ pLastSpawnPoint = g_pLastCombineSpawn;
+ }
+ else if ( GetTeamNumber() == TEAM_REBELS )
+ {
+ pSpawnpointName = "info_player_rebel";
+ pLastSpawnPoint = g_pLastRebelSpawn;
+ }
+
+ if ( gEntList.FindEntityByClassname( NULL, pSpawnpointName ) == NULL )
+ {
+ pSpawnpointName = "info_player_deathmatch";
+ pLastSpawnPoint = g_pLastSpawn;
+ }
+ }
+
+ pSpot = pLastSpawnPoint;
+ // Randomize the start spot
+ for ( int i = random->RandomInt(1,5); i > 0; i-- )
+ pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
+ if ( !pSpot ) // skip over the null point
+ pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
+
+ CBaseEntity *pFirstSpot = pSpot;
+
+ do
+ {
+ if ( pSpot )
+ {
+ // check if pSpot is valid
+ if ( g_pGameRules->IsSpawnPointValid( pSpot, this ) )
+ {
+ if ( pSpot->GetLocalOrigin() == vec3_origin )
+ {
+ pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
+ continue;
+ }
+
+ // if so, go to pSpot
+ goto ReturnSpot;
+ }
+ }
+ // increment pSpot
+ pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
+ } while ( pSpot != pFirstSpot ); // loop if we're not back to the start
+
+ // we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
+ if ( pSpot )
+ {
+ CBaseEntity *ent = NULL;
+ for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() )
+ {
+ // if ent is a client, kill em (unless they are ourselves)
+ if ( ent->IsPlayer() && !(ent->edict() == player) )
+ ent->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), 300, DMG_GENERIC ) );
+ }
+ goto ReturnSpot;
+ }
+
+ if ( !pSpot )
+ {
+ pSpot = gEntList.FindEntityByClassname( pSpot, "info_player_start" );
+
+ if ( pSpot )
+ goto ReturnSpot;
+ }
+
+ReturnSpot:
+
+ if ( HL2MPRules()->IsTeamplay() == true )
+ {
+ if ( GetTeamNumber() == TEAM_COMBINE )
+ {
+ g_pLastCombineSpawn = pSpot;
+ }
+ else if ( GetTeamNumber() == TEAM_REBELS )
+ {
+ g_pLastRebelSpawn = pSpot;
+ }
+ }
+
+ g_pLastSpawn = pSpot;
+
+ m_flSlamProtectTime = gpGlobals->curtime + 0.5;
+
+ return pSpot;
+}
+
+
+CON_COMMAND( timeleft, "prints the time remaining in the match" )
+{
+ CHL2MP_Player *pPlayer = ToHL2MPPlayer( UTIL_GetCommandClient() );
+
+ int iTimeRemaining = (int)HL2MPRules()->GetMapRemainingTime();
+
+ if ( iTimeRemaining == 0 )
+ {
+ if ( pPlayer )
+ {
+ ClientPrint( pPlayer, HUD_PRINTTALK, "This game has no timelimit." );
+ }
+ else
+ {
+ Msg( "* No Time Limit *\n" );
+ }
+ }
+ else
+ {
+ int iMinutes, iSeconds;
+ iMinutes = iTimeRemaining / 60;
+ iSeconds = iTimeRemaining % 60;
+
+ char minutes[8];
+ char seconds[8];
+
+ Q_snprintf( minutes, sizeof(minutes), "%d", iMinutes );
+ Q_snprintf( seconds, sizeof(seconds), "%2.2d", iSeconds );
+
+ if ( pPlayer )
+ {
+ ClientPrint( pPlayer, HUD_PRINTTALK, "Time left in map: %s1:%s2", minutes, seconds );
+ }
+ else
+ {
+ Msg( "Time Remaining: %s:%s\n", minutes, seconds );
+ }
+ }
+}
+
+
+void CHL2MP_Player::Reset()
+{
+ ResetDeathCount();
+ ResetFragCount();
+}
+
+bool CHL2MP_Player::IsReady()
+{
+ return m_bReady;
+}
+
+void CHL2MP_Player::SetReady( bool bReady )
+{
+ m_bReady = bReady;
+}
+
+void CHL2MP_Player::CheckChatText( char *p, int bufsize )
+{
+ //Look for escape sequences and replace
+
+ char *buf = new char[bufsize];
+ int pos = 0;
+
+ // Parse say text for escape sequences
+ for ( char *pSrc = p; pSrc != NULL && *pSrc != 0 && pos < bufsize-1; pSrc++ )
+ {
+ // copy each char across
+ buf[pos] = *pSrc;
+ pos++;
+ }
+
+ buf[pos] = '\0';
+
+ // copy buf back into p
+ Q_strncpy( p, buf, bufsize );
+
+ delete[] buf;
+
+ const char *pReadyCheck = p;
+
+ HL2MPRules()->CheckChatForReadySignal( this, pReadyCheck );
+}
+
+void CHL2MP_Player::State_Transition( HL2MPPlayerState newState )
+{
+ State_Leave();
+ State_Enter( newState );
+}
+
+
+void CHL2MP_Player::State_Enter( HL2MPPlayerState newState )
+{
+ m_iPlayerState = newState;
+ m_pCurStateInfo = State_LookupInfo( newState );
+
+ // Initialize the new state.
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
+ (this->*m_pCurStateInfo->pfnEnterState)();
+}
+
+
+void CHL2MP_Player::State_Leave()
+{
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
+ {
+ (this->*m_pCurStateInfo->pfnLeaveState)();
+ }
+}
+
+
+void CHL2MP_Player::State_PreThink()
+{
+ if ( m_pCurStateInfo && m_pCurStateInfo->pfnPreThink )
+ {
+ (this->*m_pCurStateInfo->pfnPreThink)();
+ }
+}
+
+
+CHL2MPPlayerStateInfo *CHL2MP_Player::State_LookupInfo( HL2MPPlayerState state )
+{
+ // This table MUST match the
+ static CHL2MPPlayerStateInfo playerStateInfos[] =
+ {
+ { STATE_ACTIVE, "STATE_ACTIVE", &CHL2MP_Player::State_Enter_ACTIVE, NULL, &CHL2MP_Player::State_PreThink_ACTIVE },
+ { STATE_OBSERVER_MODE, "STATE_OBSERVER_MODE", &CHL2MP_Player::State_Enter_OBSERVER_MODE, NULL, &CHL2MP_Player::State_PreThink_OBSERVER_MODE }
+ };
+
+ for ( int i=0; i < ARRAYSIZE( playerStateInfos ); i++ )
+ {
+ if ( playerStateInfos[i].m_iPlayerState == state )
+ return &playerStateInfos[i];
+ }
+
+ return NULL;
+}
+
+bool CHL2MP_Player::StartObserverMode(int mode)
+{
+ //we only want to go into observer mode if the player asked to, not on a death timeout
+ if ( m_bEnterObserver == true )
+ {
+ VPhysicsDestroyObject();
+ return BaseClass::StartObserverMode( mode );
+ }
+ return false;
+}
+
+void CHL2MP_Player::StopObserverMode()
+{
+ m_bEnterObserver = false;
+ BaseClass::StopObserverMode();
+}
+
+void CHL2MP_Player::State_Enter_OBSERVER_MODE()
+{
+ int observerMode = m_iObserverLastMode;
+ if ( IsNetClient() )
+ {
+ const char *pIdealMode = engine->GetClientConVarValue( engine->IndexOfEdict( edict() ), "cl_spec_mode" );
+ if ( pIdealMode )
+ {
+ observerMode = atoi( pIdealMode );
+ if ( observerMode <= OBS_MODE_FIXED || observerMode > OBS_MODE_ROAMING )
+ {
+ observerMode = m_iObserverLastMode;
+ }
+ }
+ }
+ m_bEnterObserver = true;
+ StartObserverMode( observerMode );
+}
+
+void CHL2MP_Player::State_PreThink_OBSERVER_MODE()
+{
+ // Make sure nobody has changed any of our state.
+ // Assert( GetMoveType() == MOVETYPE_FLY );
+ Assert( m_takedamage == DAMAGE_NO );
+ Assert( IsSolidFlagSet( FSOLID_NOT_SOLID ) );
+ // Assert( IsEffectActive( EF_NODRAW ) );
+
+ // Must be dead.
+ Assert( m_lifeState == LIFE_DEAD );
+ Assert( pl.deadflag );
+}
+
+
+void CHL2MP_Player::State_Enter_ACTIVE()
+{
+ SetMoveType( MOVETYPE_WALK );
+
+ // md 8/15/07 - They'll get set back to solid when they actually respawn. If we set them solid now and mp_forcerespawn
+ // is false, then they'll be spectating but blocking live players from moving.
+ // RemoveSolidFlags( FSOLID_NOT_SOLID );
+
+ m_Local.m_iHideHUD = 0;
+}
+
+
+void CHL2MP_Player::State_PreThink_ACTIVE()
+{
+ //we don't really need to do anything here.
+ //This state_prethink structure came over from CS:S and was doing an assert check that fails the way hl2dm handles death
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHL2MP_Player::CanHearAndReadChatFrom( CBasePlayer *pPlayer )
+{
+ // can always hear the console unless we're ignoring all chat
+ if ( !pPlayer )
+ return false;
+
+ return true;
+}
diff --git a/mp/src/game/server/hl2mp/hl2mp_player.h b/mp/src/game/server/hl2mp/hl2mp_player.h
new file mode 100644
index 00000000..1c387355
--- /dev/null
+++ b/mp/src/game/server/hl2mp/hl2mp_player.h
@@ -0,0 +1,176 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifndef HL2MP_PLAYER_H
+#define HL2MP_PLAYER_H
+#pragma once
+
+class CHL2MP_Player;
+
+#include "basemultiplayerplayer.h"
+#include "hl2_playerlocaldata.h"
+#include "hl2_player.h"
+#include "simtimer.h"
+#include "soundenvelope.h"
+#include "hl2mp_player_shared.h"
+#include "hl2mp_gamerules.h"
+#include "utldict.h"
+
+//=============================================================================
+// >> HL2MP_Player
+//=============================================================================
+class CHL2MPPlayerStateInfo
+{
+public:
+ HL2MPPlayerState m_iPlayerState;
+ const char *m_pStateName;
+
+ void (CHL2MP_Player::*pfnEnterState)(); // Init and deinit the state.
+ void (CHL2MP_Player::*pfnLeaveState)();
+
+ void (CHL2MP_Player::*pfnPreThink)(); // Do a PreThink() in this state.
+};
+
+class CHL2MP_Player : public CHL2_Player
+{
+public:
+ DECLARE_CLASS( CHL2MP_Player, CHL2_Player );
+
+ CHL2MP_Player();
+ ~CHL2MP_Player( void );
+
+ static CHL2MP_Player *CreatePlayer( const char *className, edict_t *ed )
+ {
+ CHL2MP_Player::s_PlayerEdict = ed;
+ return (CHL2MP_Player*)CreateEntityByName( className );
+ }
+
+ DECLARE_SERVERCLASS();
+ DECLARE_DATADESC();
+
+ virtual void Precache( void );
+ virtual void Spawn( void );
+ virtual void PostThink( void );
+ virtual void PreThink( void );
+ virtual void PlayerDeathThink( void );
+ virtual void SetAnimation( PLAYER_ANIM playerAnim );
+ virtual bool HandleCommand_JoinTeam( int team );
+ virtual bool ClientCommand( const CCommand &args );
+ virtual void CreateViewModel( int viewmodelindex = 0 );
+ virtual bool BecomeRagdollOnClient( const Vector &force );
+ virtual void Event_Killed( const CTakeDamageInfo &info );
+ virtual int OnTakeDamage( const CTakeDamageInfo &inputInfo );
+ virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const;
+ virtual void FireBullets ( const FireBulletsInfo_t &info );
+ virtual bool Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex = 0);
+ virtual bool BumpWeapon( CBaseCombatWeapon *pWeapon );
+ virtual void ChangeTeam( int iTeam );
+ virtual void PickupObject ( CBaseEntity *pObject, bool bLimitMassAndSize );
+ virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
+ virtual void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
+ virtual void UpdateOnRemove( void );
+ virtual void DeathSound( const CTakeDamageInfo &info );
+ virtual CBaseEntity* EntSelectSpawnPoint( void );
+
+ int FlashlightIsOn( void );
+ void FlashlightTurnOn( void );
+ void FlashlightTurnOff( void );
+ void PrecacheFootStepSounds( void );
+ bool ValidatePlayerModel( const char *pModel );
+
+ QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles.Get(); }
+
+ Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
+
+ void CheatImpulseCommands( int iImpulse );
+ void CreateRagdollEntity( void );
+ void GiveAllItems( void );
+ void GiveDefaultItems( void );
+
+ void NoteWeaponFired( void );
+
+ void ResetAnimation( void );
+ void SetPlayerModel( void );
+ void SetPlayerTeamModel( void );
+ Activity TranslateTeamActivity( Activity ActToTranslate );
+
+ float GetNextModelChangeTime( void ) { return m_flNextModelChangeTime; }
+ float GetNextTeamChangeTime( void ) { return m_flNextTeamChangeTime; }
+ void PickDefaultSpawnTeam( void );
+ void SetupPlayerSoundsByModel( const char *pModelName );
+ const char *GetPlayerModelSoundPrefix( void );
+ int GetPlayerModelType( void ) { return m_iPlayerSoundType; }
+
+ void DetonateTripmines( void );
+
+ void Reset();
+
+ bool IsReady();
+ void SetReady( bool bReady );
+
+ void CheckChatText( char *p, int bufsize );
+
+ void State_Transition( HL2MPPlayerState newState );
+ void State_Enter( HL2MPPlayerState newState );
+ void State_Leave();
+ void State_PreThink();
+ CHL2MPPlayerStateInfo *State_LookupInfo( HL2MPPlayerState state );
+
+ void State_Enter_ACTIVE();
+ void State_PreThink_ACTIVE();
+ void State_Enter_OBSERVER_MODE();
+ void State_PreThink_OBSERVER_MODE();
+
+
+ virtual bool StartObserverMode( int mode );
+ virtual void StopObserverMode( void );
+
+
+ Vector m_vecTotalBulletForce; //Accumulator for bullet force in a single frame
+
+ // Tracks our ragdoll entity.
+ CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle
+
+ virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer );
+
+
+private:
+
+ CNetworkQAngle( m_angEyeAngles );
+ CPlayerAnimState m_PlayerAnimState;
+
+ int m_iLastWeaponFireUsercmd;
+ int m_iModelType;
+ CNetworkVar( int, m_iSpawnInterpCounter );
+ CNetworkVar( int, m_iPlayerSoundType );
+
+ float m_flNextModelChangeTime;
+ float m_flNextTeamChangeTime;
+
+ float m_flSlamProtectTime;
+
+ HL2MPPlayerState m_iPlayerState;
+ CHL2MPPlayerStateInfo *m_pCurStateInfo;
+
+ bool ShouldRunRateLimitedCommand( const CCommand &args );
+
+ // This lets us rate limit the commands the players can execute so they don't overflow things like reliable buffers.
+ CUtlDict<float,int> m_RateLimitLastCommandTimes;
+
+ bool m_bEnterObserver;
+ bool m_bReady;
+};
+
+inline CHL2MP_Player *ToHL2MPPlayer( CBaseEntity *pEntity )
+{
+ if ( !pEntity || !pEntity->IsPlayer() )
+ return NULL;
+
+ return dynamic_cast<CHL2MP_Player*>( pEntity );
+}
+
+#endif //HL2MP_PLAYER_H
diff --git a/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.cpp b/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.cpp
new file mode 100644
index 00000000..8db3bb47
--- /dev/null
+++ b/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.cpp
@@ -0,0 +1,104 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "basetempentity.h"
+
+
+#define NUM_BULLET_SEED_BITS 8
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Display's a blood sprite
+//-----------------------------------------------------------------------------
+class CTEHL2MPFireBullets : public CBaseTempEntity
+{
+public:
+ DECLARE_CLASS( CTEHL2MPFireBullets, CBaseTempEntity );
+ DECLARE_SERVERCLASS();
+
+ CTEHL2MPFireBullets( const char *name );
+ virtual ~CTEHL2MPFireBullets( void );
+
+public:
+ CNetworkVar( int, m_iPlayer );
+ CNetworkVector( m_vecOrigin );
+ CNetworkVector( m_vecDir );
+ CNetworkVar( int, m_iAmmoID );
+ CNetworkVar( int, m_iSeed );
+ CNetworkVar( int, m_iShots );
+ CNetworkVar( float, m_flSpread );
+ CNetworkVar( bool, m_bDoImpacts );
+ CNetworkVar( bool, m_bDoTracers );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CTEHL2MPFireBullets::CTEHL2MPFireBullets( const char *name ) :
+ CBaseTempEntity( name )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTEHL2MPFireBullets::~CTEHL2MPFireBullets( void )
+{
+}
+
+IMPLEMENT_SERVERCLASS_ST_NOBASE(CTEHL2MPFireBullets, DT_TEHL2MPFireBullets)
+ SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
+ SendPropVector( SENDINFO(m_vecDir), -1 ),
+ SendPropInt( SENDINFO( m_iAmmoID ), 5, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iSeed ), NUM_BULLET_SEED_BITS, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iShots ), 5, SPROP_UNSIGNED ),
+ SendPropInt( SENDINFO( m_iPlayer ), 6, SPROP_UNSIGNED ), // max 64 players, see MAX_PLAYERS
+ SendPropFloat( SENDINFO( m_flSpread ), 10, 0, 0, 1 ),
+ SendPropBool( SENDINFO( m_bDoImpacts ) ),
+ SendPropBool( SENDINFO( m_bDoTracers ) ),
+END_SEND_TABLE()
+
+
+// Singleton
+static CTEHL2MPFireBullets g_TEHL2MPFireBullets( "Shotgun Shot" );
+
+
+void TE_HL2MPFireBullets(
+ int iPlayerIndex,
+ const Vector &vOrigin,
+ const Vector &vDir,
+ int iAmmoID,
+ int iSeed,
+ int iShots,
+ float flSpread,
+ bool bDoTracers,
+ bool bDoImpacts )
+{
+ CPASFilter filter( vOrigin );
+ filter.UsePredictionRules();
+
+ g_TEHL2MPFireBullets.m_iPlayer = iPlayerIndex;
+ g_TEHL2MPFireBullets.m_vecOrigin = vOrigin;
+ g_TEHL2MPFireBullets.m_vecDir = vDir;
+ g_TEHL2MPFireBullets.m_iSeed = iSeed;
+ g_TEHL2MPFireBullets.m_iShots = iShots;
+ g_TEHL2MPFireBullets.m_flSpread = flSpread;
+ g_TEHL2MPFireBullets.m_iAmmoID = iAmmoID;
+ g_TEHL2MPFireBullets.m_bDoTracers = bDoTracers;
+ g_TEHL2MPFireBullets.m_bDoImpacts = bDoImpacts;
+
+ Assert( iSeed < (1 << NUM_BULLET_SEED_BITS) );
+
+ g_TEHL2MPFireBullets.Create( filter, 0 );
+}
diff --git a/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.h b/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.h
new file mode 100644
index 00000000..47948230
--- /dev/null
+++ b/mp/src/game/server/hl2mp/te_hl2mp_shotgun_shot.h
@@ -0,0 +1,26 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef TE_HL2MP_SHOTGUN_SHOT_H
+#define TE_HL2MP_SHOTGUN_SHOT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+void TE_HL2MPFireBullets(
+ int iPlayerIndex,
+ const Vector &vOrigin,
+ const Vector &vDir,
+ int iAmmoID,
+ int iSeed,
+ int iShots,
+ float flSpread,
+ bool bDoTracers,
+ bool bDoImpacts );
+
+
+#endif // TE_HL2MP_SHOTGUN_SHOT_H