aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp')
-rw-r--r--sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp2558
1 files changed, 1279 insertions, 1279 deletions
diff --git a/sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp b/sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp
index 1b7cf70f..604e409c 100644
--- a/sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp
+++ b/sp/src/game/shared/hl2mp/hl2mp_gamerules.cpp
@@ -1,1280 +1,1280 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "hl2mp_gamerules.h"
-#include "viewport_panel_names.h"
-#include "gameeventdefs.h"
-#include <KeyValues.h>
-#include "ammodef.h"
-
-#ifdef CLIENT_DLL
- #include "c_hl2mp_player.h"
-#else
-
- #include "eventqueue.h"
- #include "player.h"
- #include "gamerules.h"
- #include "game.h"
- #include "items.h"
- #include "entitylist.h"
- #include "mapentities.h"
- #include "in_buttons.h"
- #include <ctype.h>
- #include "voice_gamemgr.h"
- #include "iscorer.h"
- #include "hl2mp_player.h"
- #include "weapon_hl2mpbasehlmpcombatweapon.h"
- #include "team.h"
- #include "voice_gamemgr.h"
- #include "hl2mp_gameinterface.h"
- #include "hl2mp_cvars.h"
-
-#ifdef DEBUG
- #include "hl2mp_bot_temp.h"
-#endif
-
-extern void respawn(CBaseEntity *pEdict, bool fCopyCorpse);
-
-extern bool FindInList( const char **pStrings, const char *pToFind );
-
-ConVar sv_hl2mp_weapon_respawn_time( "sv_hl2mp_weapon_respawn_time", "20", FCVAR_GAMEDLL | FCVAR_NOTIFY );
-ConVar sv_hl2mp_item_respawn_time( "sv_hl2mp_item_respawn_time", "30", FCVAR_GAMEDLL | FCVAR_NOTIFY );
-ConVar sv_report_client_settings("sv_report_client_settings", "0", FCVAR_GAMEDLL | FCVAR_NOTIFY );
-
-extern ConVar mp_chattime;
-
-extern CBaseEntity *g_pLastCombineSpawn;
-extern CBaseEntity *g_pLastRebelSpawn;
-
-#define WEAPON_MAX_DISTANCE_FROM_SPAWN 64
-
-#endif
-
-
-REGISTER_GAMERULES_CLASS( CHL2MPRules );
-
-BEGIN_NETWORK_TABLE_NOBASE( CHL2MPRules, DT_HL2MPRules )
-
- #ifdef CLIENT_DLL
- RecvPropBool( RECVINFO( m_bTeamPlayEnabled ) ),
- #else
- SendPropBool( SENDINFO( m_bTeamPlayEnabled ) ),
- #endif
-
-END_NETWORK_TABLE()
-
-
-LINK_ENTITY_TO_CLASS( hl2mp_gamerules, CHL2MPGameRulesProxy );
-IMPLEMENT_NETWORKCLASS_ALIASED( HL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
-
-static HL2MPViewVectors g_HL2MPViewVectors(
- Vector( 0, 0, 64 ), //VEC_VIEW (m_vView)
-
- Vector(-16, -16, 0 ), //VEC_HULL_MIN (m_vHullMin)
- Vector( 16, 16, 72 ), //VEC_HULL_MAX (m_vHullMax)
-
- Vector(-16, -16, 0 ), //VEC_DUCK_HULL_MIN (m_vDuckHullMin)
- Vector( 16, 16, 36 ), //VEC_DUCK_HULL_MAX (m_vDuckHullMax)
- Vector( 0, 0, 28 ), //VEC_DUCK_VIEW (m_vDuckView)
-
- Vector(-10, -10, -10 ), //VEC_OBS_HULL_MIN (m_vObsHullMin)
- Vector( 10, 10, 10 ), //VEC_OBS_HULL_MAX (m_vObsHullMax)
-
- Vector( 0, 0, 14 ), //VEC_DEAD_VIEWHEIGHT (m_vDeadViewHeight)
-
- Vector(-16, -16, 0 ), //VEC_CROUCH_TRACE_MIN (m_vCrouchTraceMin)
- Vector( 16, 16, 60 ) //VEC_CROUCH_TRACE_MAX (m_vCrouchTraceMax)
-);
-
-static const char *s_PreserveEnts[] =
-{
- "ai_network",
- "ai_hint",
- "hl2mp_gamerules",
- "team_manager",
- "player_manager",
- "env_soundscape",
- "env_soundscape_proxy",
- "env_soundscape_triggerable",
- "env_sun",
- "env_wind",
- "env_fog_controller",
- "func_brush",
- "func_wall",
- "func_buyzone",
- "func_illusionary",
- "infodecal",
- "info_projecteddecal",
- "info_node",
- "info_target",
- "info_node_hint",
- "info_player_deathmatch",
- "info_player_combine",
- "info_player_rebel",
- "info_map_parameters",
- "keyframe_rope",
- "move_rope",
- "info_ladder",
- "player",
- "point_viewcontrol",
- "scene_manager",
- "shadow_control",
- "sky_camera",
- "soundent",
- "trigger_soundscape",
- "viewmodel",
- "predicted_viewmodel",
- "worldspawn",
- "point_devshot_camera",
- "", // END Marker
-};
-
-
-
-#ifdef CLIENT_DLL
- void RecvProxy_HL2MPRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
- {
- CHL2MPRules *pRules = HL2MPRules();
- Assert( pRules );
- *pOut = pRules;
- }
-
- BEGIN_RECV_TABLE( CHL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
- RecvPropDataTable( "hl2mp_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_HL2MPRules ), RecvProxy_HL2MPRules )
- END_RECV_TABLE()
-#else
- void* SendProxy_HL2MPRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
- {
- CHL2MPRules *pRules = HL2MPRules();
- Assert( pRules );
- return pRules;
- }
-
- BEGIN_SEND_TABLE( CHL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
- SendPropDataTable( "hl2mp_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_HL2MPRules ), SendProxy_HL2MPRules )
- END_SEND_TABLE()
-#endif
-
-#ifndef CLIENT_DLL
-
- class CVoiceGameMgrHelper : public IVoiceGameMgrHelper
- {
- public:
- virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker, bool &bProximity )
- {
- return ( pListener->GetTeamNumber() == pTalker->GetTeamNumber() );
- }
- };
- CVoiceGameMgrHelper g_VoiceGameMgrHelper;
- IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper;
-
-#endif
-
-// NOTE: the indices here must match TEAM_TERRORIST, TEAM_CT, TEAM_SPECTATOR, etc.
-char *sTeamNames[] =
-{
- "Unassigned",
- "Spectator",
- "Combine",
- "Rebels",
-};
-
-CHL2MPRules::CHL2MPRules()
-{
-#ifndef CLIENT_DLL
- // Create the team managers
- for ( int i = 0; i < ARRAYSIZE( sTeamNames ); i++ )
- {
- CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" ));
- pTeam->Init( sTeamNames[i], i );
-
- g_Teams.AddToTail( pTeam );
- }
-
- m_bTeamPlayEnabled = teamplay.GetBool();
- m_flIntermissionEndTime = 0.0f;
- m_flGameStartTime = 0;
-
- m_hRespawnableItemsAndWeapons.RemoveAll();
- m_tmNextPeriodicThink = 0;
- m_flRestartGameTime = 0;
- m_bCompleteReset = false;
- m_bHeardAllPlayersReady = false;
- m_bAwaitingReadyRestart = false;
- m_bChangelevelDone = false;
-
-#endif
-}
-
-const CViewVectors* CHL2MPRules::GetViewVectors()const
-{
- return &g_HL2MPViewVectors;
-}
-
-const HL2MPViewVectors* CHL2MPRules::GetHL2MPViewVectors()const
-{
- return &g_HL2MPViewVectors;
-}
-
-CHL2MPRules::~CHL2MPRules( void )
-{
-#ifndef CLIENT_DLL
- // Note, don't delete each team since they are in the gEntList and will
- // automatically be deleted from there, instead.
- g_Teams.Purge();
-#endif
-}
-
-void CHL2MPRules::CreateStandardEntities( void )
-{
-
-#ifndef CLIENT_DLL
- // Create the entity that will send our data to the client.
-
- BaseClass::CreateStandardEntities();
-
- g_pLastCombineSpawn = NULL;
- g_pLastRebelSpawn = NULL;
-
-#ifdef DBGFLAG_ASSERT
- CBaseEntity *pEnt =
-#endif
- CBaseEntity::Create( "hl2mp_gamerules", vec3_origin, vec3_angle );
- Assert( pEnt );
-#endif
-}
-
-//=========================================================
-// FlWeaponRespawnTime - what is the time in the future
-// at which this weapon may spawn?
-//=========================================================
-float CHL2MPRules::FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon )
-{
-#ifndef CLIENT_DLL
- if ( weaponstay.GetInt() > 0 )
- {
- // make sure it's only certain weapons
- if ( !(pWeapon->GetWeaponFlags() & ITEM_FLAG_LIMITINWORLD) )
- {
- return 0; // weapon respawns almost instantly
- }
- }
-
- return sv_hl2mp_weapon_respawn_time.GetFloat();
-#endif
-
- return 0; // weapon respawns almost instantly
-}
-
-
-bool CHL2MPRules::IsIntermission( void )
-{
-#ifndef CLIENT_DLL
- return m_flIntermissionEndTime > gpGlobals->curtime;
-#endif
-
- return false;
-}
-
-void CHL2MPRules::PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info )
-{
-#ifndef CLIENT_DLL
- if ( IsIntermission() )
- return;
- BaseClass::PlayerKilled( pVictim, info );
-#endif
-}
-
-
-void CHL2MPRules::Think( void )
-{
-
-#ifndef CLIENT_DLL
-
- CGameRules::Think();
-
- if ( g_fGameOver ) // someone else quit the game already
- {
- // check to see if we should change levels now
- if ( m_flIntermissionEndTime < gpGlobals->curtime )
- {
- if ( !m_bChangelevelDone )
- {
- ChangeLevel(); // intermission is over
- m_bChangelevelDone = true;
- }
- }
-
- return;
- }
-
-// float flTimeLimit = mp_timelimit.GetFloat() * 60;
- float flFragLimit = fraglimit.GetFloat();
-
- if ( GetMapRemainingTime() < 0 )
- {
- GoToIntermission();
- return;
- }
-
- if ( flFragLimit )
- {
- if( IsTeamplay() == true )
- {
- CTeam *pCombine = g_Teams[TEAM_COMBINE];
- CTeam *pRebels = g_Teams[TEAM_REBELS];
-
- if ( pCombine->GetScore() >= flFragLimit || pRebels->GetScore() >= flFragLimit )
- {
- GoToIntermission();
- return;
- }
- }
- else
- {
- // check if any player is over the frag limit
- for ( int i = 1; i <= gpGlobals->maxClients; i++ )
- {
- CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
-
- if ( pPlayer && pPlayer->FragCount() >= flFragLimit )
- {
- GoToIntermission();
- return;
- }
- }
- }
- }
-
- if ( gpGlobals->curtime > m_tmNextPeriodicThink )
- {
- CheckAllPlayersReady();
- CheckRestartGame();
- m_tmNextPeriodicThink = gpGlobals->curtime + 1.0;
- }
-
- if ( m_flRestartGameTime > 0.0f && m_flRestartGameTime <= gpGlobals->curtime )
- {
- RestartGame();
- }
-
- if( m_bAwaitingReadyRestart && m_bHeardAllPlayersReady )
- {
- UTIL_ClientPrintAll( HUD_PRINTCENTER, "All players ready. Game will restart in 5 seconds" );
- UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "All players ready. Game will restart in 5 seconds" );
-
- m_flRestartGameTime = gpGlobals->curtime + 5;
- m_bAwaitingReadyRestart = false;
- }
-
- ManageObjectRelocation();
-
-#endif
-}
-
-void CHL2MPRules::GoToIntermission( void )
-{
-#ifndef CLIENT_DLL
- if ( g_fGameOver )
- return;
-
- g_fGameOver = true;
-
- m_flIntermissionEndTime = gpGlobals->curtime + mp_chattime.GetInt();
-
- for ( int i = 0; i < MAX_PLAYERS; i++ )
- {
- CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
-
- if ( !pPlayer )
- continue;
-
- pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
- pPlayer->AddFlag( FL_FROZEN );
- }
-#endif
-
-}
-
-bool CHL2MPRules::CheckGameOver()
-{
-#ifndef CLIENT_DLL
- if ( g_fGameOver ) // someone else quit the game already
- {
- // check to see if we should change levels now
- if ( m_flIntermissionEndTime < gpGlobals->curtime )
- {
- ChangeLevel(); // intermission is over
- }
-
- return true;
- }
-#endif
-
- return false;
-}
-
-// when we are within this close to running out of entities, items
-// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn
-#define ENTITY_INTOLERANCE 100
-
-//=========================================================
-// FlWeaponRespawnTime - Returns 0 if the weapon can respawn
-// now, otherwise it returns the time at which it can try
-// to spawn again.
-//=========================================================
-float CHL2MPRules::FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon )
-{
-#ifndef CLIENT_DLL
- if ( pWeapon && (pWeapon->GetWeaponFlags() & ITEM_FLAG_LIMITINWORLD) )
- {
- if ( gEntList.NumberOfEntities() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) )
- return 0;
-
- // we're past the entity tolerance level, so delay the respawn
- return FlWeaponRespawnTime( pWeapon );
- }
-#endif
- return 0;
-}
-
-//=========================================================
-// VecWeaponRespawnSpot - where should this weapon spawn?
-// Some game variations may choose to randomize spawn locations
-//=========================================================
-Vector CHL2MPRules::VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon )
-{
-#ifndef CLIENT_DLL
- CWeaponHL2MPBase *pHL2Weapon = dynamic_cast< CWeaponHL2MPBase*>( pWeapon );
-
- if ( pHL2Weapon )
- {
- return pHL2Weapon->GetOriginalSpawnOrigin();
- }
-#endif
-
- return pWeapon->GetAbsOrigin();
-}
-
-#ifndef CLIENT_DLL
-
-CItem* IsManagedObjectAnItem( CBaseEntity *pObject )
-{
- return dynamic_cast< CItem*>( pObject );
-}
-
-CWeaponHL2MPBase* IsManagedObjectAWeapon( CBaseEntity *pObject )
-{
- return dynamic_cast< CWeaponHL2MPBase*>( pObject );
-}
-
-bool GetObjectsOriginalParameters( CBaseEntity *pObject, Vector &vOriginalOrigin, QAngle &vOriginalAngles )
-{
- if ( CItem *pItem = IsManagedObjectAnItem( pObject ) )
- {
- if ( pItem->m_flNextResetCheckTime > gpGlobals->curtime )
- return false;
-
- vOriginalOrigin = pItem->GetOriginalSpawnOrigin();
- vOriginalAngles = pItem->GetOriginalSpawnAngles();
-
- pItem->m_flNextResetCheckTime = gpGlobals->curtime + sv_hl2mp_item_respawn_time.GetFloat();
- return true;
- }
- else if ( CWeaponHL2MPBase *pWeapon = IsManagedObjectAWeapon( pObject ))
- {
- if ( pWeapon->m_flNextResetCheckTime > gpGlobals->curtime )
- return false;
-
- vOriginalOrigin = pWeapon->GetOriginalSpawnOrigin();
- vOriginalAngles = pWeapon->GetOriginalSpawnAngles();
-
- pWeapon->m_flNextResetCheckTime = gpGlobals->curtime + sv_hl2mp_weapon_respawn_time.GetFloat();
- return true;
- }
-
- return false;
-}
-
-void CHL2MPRules::ManageObjectRelocation( void )
-{
- int iTotal = m_hRespawnableItemsAndWeapons.Count();
-
- if ( iTotal > 0 )
- {
- for ( int i = 0; i < iTotal; i++ )
- {
- CBaseEntity *pObject = m_hRespawnableItemsAndWeapons[i].Get();
-
- if ( pObject )
- {
- Vector vSpawOrigin;
- QAngle vSpawnAngles;
-
- if ( GetObjectsOriginalParameters( pObject, vSpawOrigin, vSpawnAngles ) == true )
- {
- float flDistanceFromSpawn = (pObject->GetAbsOrigin() - vSpawOrigin ).Length();
-
- if ( flDistanceFromSpawn > WEAPON_MAX_DISTANCE_FROM_SPAWN )
- {
- bool shouldReset = false;
- IPhysicsObject *pPhysics = pObject->VPhysicsGetObject();
-
- if ( pPhysics )
- {
- shouldReset = pPhysics->IsAsleep();
- }
- else
- {
- shouldReset = (pObject->GetFlags() & FL_ONGROUND) ? true : false;
- }
-
- if ( shouldReset )
- {
- pObject->Teleport( &vSpawOrigin, &vSpawnAngles, NULL );
- pObject->EmitSound( "AlyxEmp.Charge" );
-
- IPhysicsObject *pPhys = pObject->VPhysicsGetObject();
-
- if ( pPhys )
- {
- pPhys->Wake();
- }
- }
- }
- }
- }
- }
- }
-}
-
-//=========================================================
-//AddLevelDesignerPlacedWeapon
-//=========================================================
-void CHL2MPRules::AddLevelDesignerPlacedObject( CBaseEntity *pEntity )
-{
- if ( m_hRespawnableItemsAndWeapons.Find( pEntity ) == -1 )
- {
- m_hRespawnableItemsAndWeapons.AddToTail( pEntity );
- }
-}
-
-//=========================================================
-//RemoveLevelDesignerPlacedWeapon
-//=========================================================
-void CHL2MPRules::RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity )
-{
- if ( m_hRespawnableItemsAndWeapons.Find( pEntity ) != -1 )
- {
- m_hRespawnableItemsAndWeapons.FindAndRemove( pEntity );
- }
-}
-
-//=========================================================
-// Where should this item respawn?
-// Some game variations may choose to randomize spawn locations
-//=========================================================
-Vector CHL2MPRules::VecItemRespawnSpot( CItem *pItem )
-{
- return pItem->GetOriginalSpawnOrigin();
-}
-
-//=========================================================
-// What angles should this item use to respawn?
-//=========================================================
-QAngle CHL2MPRules::VecItemRespawnAngles( CItem *pItem )
-{
- return pItem->GetOriginalSpawnAngles();
-}
-
-//=========================================================
-// At what time in the future may this Item respawn?
-//=========================================================
-float CHL2MPRules::FlItemRespawnTime( CItem *pItem )
-{
- return sv_hl2mp_item_respawn_time.GetFloat();
-}
-
-
-//=========================================================
-// CanHaveWeapon - returns false if the player is not allowed
-// to pick up this weapon
-//=========================================================
-bool CHL2MPRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pItem )
-{
- if ( weaponstay.GetInt() > 0 )
- {
- if ( pPlayer->Weapon_OwnsThisType( pItem->GetClassname(), pItem->GetSubType() ) )
- return false;
- }
-
- return BaseClass::CanHavePlayerItem( pPlayer, pItem );
-}
-
-#endif
-
-//=========================================================
-// WeaponShouldRespawn - any conditions inhibiting the
-// respawning of this weapon?
-//=========================================================
-int CHL2MPRules::WeaponShouldRespawn( CBaseCombatWeapon *pWeapon )
-{
-#ifndef CLIENT_DLL
- if ( pWeapon->HasSpawnFlags( SF_NORESPAWN ) )
- {
- return GR_WEAPON_RESPAWN_NO;
- }
-#endif
-
- return GR_WEAPON_RESPAWN_YES;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Player has just left the game
-//-----------------------------------------------------------------------------
-void CHL2MPRules::ClientDisconnected( edict_t *pClient )
-{
-#ifndef CLIENT_DLL
- // Msg( "CLIENT DISCONNECTED, REMOVING FROM TEAM.\n" );
-
- CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient );
- if ( pPlayer )
- {
- // Remove the player from his team
- if ( pPlayer->GetTeam() )
- {
- pPlayer->GetTeam()->RemovePlayer( pPlayer );
- }
- }
-
- BaseClass::ClientDisconnected( pClient );
-
-#endif
-}
-
-
-//=========================================================
-// Deathnotice.
-//=========================================================
-void CHL2MPRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
-{
-#ifndef CLIENT_DLL
- // Work out what killed the player, and send a message to all clients about it
- const char *killer_weapon_name = "world"; // by default, the player is killed by the world
- int killer_ID = 0;
-
- // Find the killer & the scorer
- CBaseEntity *pInflictor = info.GetInflictor();
- CBaseEntity *pKiller = info.GetAttacker();
- CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
-
- // Custom kill type?
- if ( info.GetDamageCustom() )
- {
- killer_weapon_name = GetDamageCustomString( info );
- if ( pScorer )
- {
- killer_ID = pScorer->GetUserID();
- }
- }
- else
- {
- // Is the killer a client?
- if ( pScorer )
- {
- killer_ID = pScorer->GetUserID();
-
- if ( pInflictor )
- {
- if ( pInflictor == pScorer )
- {
- // If the inflictor is the killer, then it must be their current weapon doing the damage
- if ( pScorer->GetActiveWeapon() )
- {
- killer_weapon_name = pScorer->GetActiveWeapon()->GetClassname();
- }
- }
- else
- {
- killer_weapon_name = pInflictor->GetClassname(); // it's just that easy
- }
- }
- }
- else
- {
- killer_weapon_name = pInflictor->GetClassname();
- }
-
- // strip the NPC_* or weapon_* from the inflictor's classname
- if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 )
- {
- killer_weapon_name += 7;
- }
- else if ( strncmp( killer_weapon_name, "npc_", 4 ) == 0 )
- {
- killer_weapon_name += 4;
- }
- else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 )
- {
- killer_weapon_name += 5;
- }
- else if ( strstr( killer_weapon_name, "physics" ) )
- {
- killer_weapon_name = "physics";
- }
-
- if ( strcmp( killer_weapon_name, "prop_combine_ball" ) == 0 )
- {
- killer_weapon_name = "combine_ball";
- }
- else if ( strcmp( killer_weapon_name, "grenade_ar2" ) == 0 )
- {
- killer_weapon_name = "smg1_grenade";
- }
- else if ( strcmp( killer_weapon_name, "satchel" ) == 0 || strcmp( killer_weapon_name, "tripmine" ) == 0)
- {
- killer_weapon_name = "slam";
- }
-
-
- }
-
- IGameEvent *event = gameeventmanager->CreateEvent( "player_death" );
- if( event )
- {
- event->SetInt("userid", pVictim->GetUserID() );
- event->SetInt("attacker", killer_ID );
- event->SetString("weapon", killer_weapon_name );
- event->SetInt( "priority", 7 );
- gameeventmanager->FireEvent( event );
- }
-#endif
-
-}
-
-void CHL2MPRules::ClientSettingsChanged( CBasePlayer *pPlayer )
-{
-#ifndef CLIENT_DLL
-
- CHL2MP_Player *pHL2Player = ToHL2MPPlayer( pPlayer );
-
- if ( pHL2Player == NULL )
- return;
-
- const char *pCurrentModel = modelinfo->GetModelName( pPlayer->GetModel() );
- const char *szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( pPlayer->edict() ), "cl_playermodel" );
-
- //If we're different.
- if ( stricmp( szModelName, pCurrentModel ) )
- {
- //Too soon, set the cvar back to what it was.
- //Note: this will make this function be called again
- //but since our models will match it'll just skip this whole dealio.
- if ( pHL2Player->GetNextModelChangeTime() >= gpGlobals->curtime )
- {
- char szReturnString[512];
-
- Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pCurrentModel );
- engine->ClientCommand ( pHL2Player->edict(), szReturnString );
-
- Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch.\n", (int)(pHL2Player->GetNextModelChangeTime() - gpGlobals->curtime) );
- ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
- return;
- }
-
- if ( HL2MPRules()->IsTeamplay() == false )
- {
- pHL2Player->SetPlayerModel();
-
- const char *pszCurrentModelName = modelinfo->GetModelName( pHL2Player->GetModel() );
-
- char szReturnString[128];
- Q_snprintf( szReturnString, sizeof( szReturnString ), "Your player model is: %s\n", pszCurrentModelName );
-
- ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
- }
- else
- {
- if ( Q_stristr( szModelName, "models/human") )
- {
- pHL2Player->ChangeTeam( TEAM_REBELS );
- }
- else
- {
- pHL2Player->ChangeTeam( TEAM_COMBINE );
- }
- }
- }
- if ( sv_report_client_settings.GetInt() == 1 )
- {
- UTIL_LogPrintf( "\"%s\" cl_cmdrate = \"%s\"\n", pHL2Player->GetPlayerName(), engine->GetClientConVarValue( pHL2Player->entindex(), "cl_cmdrate" ));
- }
-
- BaseClass::ClientSettingsChanged( pPlayer );
-#endif
-
-}
-
-int CHL2MPRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget )
-{
-#ifndef CLIENT_DLL
- // half life multiplay has a simple concept of Player Relationships.
- // you are either on another player's team, or you are not.
- if ( !pPlayer || !pTarget || !pTarget->IsPlayer() || IsTeamplay() == false )
- return GR_NOTTEAMMATE;
-
- if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) )
- {
- return GR_TEAMMATE;
- }
-#endif
-
- return GR_NOTTEAMMATE;
-}
-
-const char *CHL2MPRules::GetGameDescription( void )
-{
- if ( IsTeamplay() )
- return "Team Deathmatch";
-
- return "Deathmatch";
-}
-
-bool CHL2MPRules::IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer )
-{
- return true;
-}
-
-float CHL2MPRules::GetMapRemainingTime()
-{
- // if timelimit is disabled, return 0
- if ( mp_timelimit.GetInt() <= 0 )
- return 0;
-
- // timelimit is in minutes
-
- float timeleft = (m_flGameStartTime + mp_timelimit.GetInt() * 60.0f ) - gpGlobals->curtime;
-
- return timeleft;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CHL2MPRules::Precache( void )
-{
- CBaseEntity::PrecacheScriptSound( "AlyxEmp.Charge" );
-}
-
-bool CHL2MPRules::ShouldCollide( int collisionGroup0, int collisionGroup1 )
-{
- if ( collisionGroup0 > collisionGroup1 )
- {
- // swap so that lowest is always first
- V_swap(collisionGroup0,collisionGroup1);
- }
-
- if ( (collisionGroup0 == COLLISION_GROUP_PLAYER || collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT) &&
- collisionGroup1 == COLLISION_GROUP_WEAPON )
- {
- return false;
- }
-
- return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 );
-
-}
-
-bool CHL2MPRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
-{
-#ifndef CLIENT_DLL
- if( BaseClass::ClientCommand( pEdict, args ) )
- return true;
-
-
- CHL2MP_Player *pPlayer = (CHL2MP_Player *) pEdict;
-
- if ( pPlayer->ClientCommand( args ) )
- return true;
-#endif
-
- return false;
-}
-
-// shared ammo definition
-// JAY: Trying to make a more physical bullet response
-#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f)
-#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains))
-
-// exaggerate all of the forces, but use real numbers to keep them consistent
-#define BULLET_IMPULSE_EXAGGERATION 3.5
-// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s
-#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION)
-
-
-CAmmoDef *GetAmmoDef()
-{
- static CAmmoDef def;
- static bool bInitted = false;
-
- if ( !bInitted )
- {
- bInitted = true;
-
- def.AddAmmoType("AR2", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 60, BULLET_IMPULSE(200, 1225), 0 );
- def.AddAmmoType("AR2AltFire", DMG_DISSOLVE, TRACER_NONE, 0, 0, 3, 0, 0 );
- def.AddAmmoType("Pistol", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 150, BULLET_IMPULSE(200, 1225), 0 );
- def.AddAmmoType("SMG1", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 225, BULLET_IMPULSE(200, 1225), 0 );
- def.AddAmmoType("357", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 12, BULLET_IMPULSE(800, 5000), 0 );
- def.AddAmmoType("XBowBolt", DMG_BULLET, TRACER_LINE, 0, 0, 10, BULLET_IMPULSE(800, 8000), 0 );
- def.AddAmmoType("Buckshot", DMG_BULLET | DMG_BUCKSHOT, TRACER_LINE, 0, 0, 30, BULLET_IMPULSE(400, 1200), 0 );
- def.AddAmmoType("RPG_Round", DMG_BURN, TRACER_NONE, 0, 0, 3, 0, 0 );
- def.AddAmmoType("SMG1_Grenade", DMG_BURN, TRACER_NONE, 0, 0, 3, 0, 0 );
- def.AddAmmoType("Grenade", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0 );
- def.AddAmmoType("slam", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0 );
- }
-
- return &def;
-}
-
-#ifdef CLIENT_DLL
-
- ConVar cl_autowepswitch(
- "cl_autowepswitch",
- "1",
- FCVAR_ARCHIVE | FCVAR_USERINFO,
- "Automatically switch to picked up weapons (if more powerful)" );
-
-#else
-
-#ifdef DEBUG
-
- // Handler for the "bot" command.
- void Bot_f()
- {
- // Look at -count.
- int count = 1;
- count = clamp( count, 1, 16 );
-
- int iTeam = TEAM_COMBINE;
-
- // Look at -frozen.
- bool bFrozen = false;
-
- // Ok, spawn all the bots.
- while ( --count >= 0 )
- {
- BotPutInServer( bFrozen, iTeam );
- }
- }
-
-
- ConCommand cc_Bot( "bot", Bot_f, "Add a bot.", FCVAR_CHEAT );
-
-#endif
-
- bool CHL2MPRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon )
- {
- if ( pPlayer->GetActiveWeapon() && pPlayer->IsNetClient() )
- {
- // Player has an active item, so let's check cl_autowepswitch.
- const char *cl_autowepswitch = engine->GetClientConVarValue( engine->IndexOfEdict( pPlayer->edict() ), "cl_autowepswitch" );
- if ( cl_autowepswitch && atoi( cl_autowepswitch ) <= 0 )
- {
- return false;
- }
- }
-
- return BaseClass::FShouldSwitchWeapon( pPlayer, pWeapon );
- }
-
-#endif
-
-#ifndef CLIENT_DLL
-
-void CHL2MPRules::RestartGame()
-{
- // bounds check
- if ( mp_timelimit.GetInt() < 0 )
- {
- mp_timelimit.SetValue( 0 );
- }
- m_flGameStartTime = gpGlobals->curtime;
- if ( !IsFinite( m_flGameStartTime.Get() ) )
- {
- Warning( "Trying to set a NaN game start time\n" );
- m_flGameStartTime.GetForModify() = 0.0f;
- }
-
- CleanUpMap();
-
- // now respawn all players
- for (int i = 1; i <= gpGlobals->maxClients; i++ )
- {
- CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
-
- if ( !pPlayer )
- continue;
-
- if ( pPlayer->GetActiveWeapon() )
- {
- pPlayer->GetActiveWeapon()->Holster();
- }
- pPlayer->RemoveAllItems( true );
- respawn( pPlayer, false );
- pPlayer->Reset();
- }
-
- // Respawn entities (glass, doors, etc..)
-
- CTeam *pRebels = GetGlobalTeam( TEAM_REBELS );
- CTeam *pCombine = GetGlobalTeam( TEAM_COMBINE );
-
- if ( pRebels )
- {
- pRebels->SetScore( 0 );
- }
-
- if ( pCombine )
- {
- pCombine->SetScore( 0 );
- }
-
- m_flIntermissionEndTime = 0;
- m_flRestartGameTime = 0.0;
- m_bCompleteReset = false;
-
- IGameEvent * event = gameeventmanager->CreateEvent( "round_start" );
- if ( event )
- {
- event->SetInt("fraglimit", 0 );
- event->SetInt( "priority", 6 ); // HLTV event priority, not transmitted
-
- event->SetString("objective","DEATHMATCH");
-
- gameeventmanager->FireEvent( event );
- }
-}
-
-void CHL2MPRules::CleanUpMap()
-{
- // Recreate all the map entities from the map data (preserving their indices),
- // then remove everything else except the players.
-
- // Get rid of all entities except players.
- CBaseEntity *pCur = gEntList.FirstEnt();
- while ( pCur )
- {
- CBaseHL2MPCombatWeapon *pWeapon = dynamic_cast< CBaseHL2MPCombatWeapon* >( pCur );
- // Weapons with owners don't want to be removed..
- if ( pWeapon )
- {
- if ( !pWeapon->GetPlayerOwner() )
- {
- UTIL_Remove( pCur );
- }
- }
- // remove entities that has to be restored on roundrestart (breakables etc)
- else if ( !FindInList( s_PreserveEnts, pCur->GetClassname() ) )
- {
- UTIL_Remove( pCur );
- }
-
- pCur = gEntList.NextEnt( pCur );
- }
-
- // Really remove the entities so we can have access to their slots below.
- gEntList.CleanupDeleteList();
-
- // Cancel all queued events, in case a func_bomb_target fired some delayed outputs that
- // could kill respawning CTs
- g_EventQueue.Clear();
-
- // Now reload the map entities.
- class CHL2MPMapEntityFilter : public IMapEntityFilter
- {
- public:
- virtual bool ShouldCreateEntity( const char *pClassname )
- {
- // Don't recreate the preserved entities.
- if ( !FindInList( s_PreserveEnts, pClassname ) )
- {
- return true;
- }
- else
- {
- // Increment our iterator since it's not going to call CreateNextEntity for this ent.
- if ( m_iIterator != g_MapEntityRefs.InvalidIndex() )
- m_iIterator = g_MapEntityRefs.Next( m_iIterator );
-
- return false;
- }
- }
-
-
- virtual CBaseEntity* CreateNextEntity( const char *pClassname )
- {
- if ( m_iIterator == g_MapEntityRefs.InvalidIndex() )
- {
- // This shouldn't be possible. When we loaded the map, it should have used
- // CCSMapLoadEntityFilter, which should have built the g_MapEntityRefs list
- // with the same list of entities we're referring to here.
- Assert( false );
- return NULL;
- }
- else
- {
- CMapEntityRef &ref = g_MapEntityRefs[m_iIterator];
- m_iIterator = g_MapEntityRefs.Next( m_iIterator ); // Seek to the next entity.
-
- if ( ref.m_iEdict == -1 || engine->PEntityOfEntIndex( ref.m_iEdict ) )
- {
- // Doh! The entity was delete and its slot was reused.
- // Just use any old edict slot. This case sucks because we lose the baseline.
- return CreateEntityByName( pClassname );
- }
- else
- {
- // Cool, the slot where this entity was is free again (most likely, the entity was
- // freed above). Now create an entity with this specific index.
- return CreateEntityByName( pClassname, ref.m_iEdict );
- }
- }
- }
-
- public:
- int m_iIterator; // Iterator into g_MapEntityRefs.
- };
- CHL2MPMapEntityFilter filter;
- filter.m_iIterator = g_MapEntityRefs.Head();
-
- // DO NOT CALL SPAWN ON info_node ENTITIES!
-
- MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
-}
-
-void CHL2MPRules::CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg )
-{
- if( m_bAwaitingReadyRestart && FStrEq( chatmsg, mp_ready_signal.GetString() ) )
- {
- if( !pPlayer->IsReady() )
- {
- pPlayer->SetReady( true );
- }
- }
-}
-
-void CHL2MPRules::CheckRestartGame( void )
-{
- // Restart the game if specified by the server
- int iRestartDelay = mp_restartgame.GetInt();
-
- if ( iRestartDelay > 0 )
- {
- if ( iRestartDelay > 60 )
- iRestartDelay = 60;
-
-
- // let the players know
- char strRestartDelay[64];
- Q_snprintf( strRestartDelay, sizeof( strRestartDelay ), "%d", iRestartDelay );
- UTIL_ClientPrintAll( HUD_PRINTCENTER, "Game will restart in %s1 %s2", strRestartDelay, iRestartDelay == 1 ? "SECOND" : "SECONDS" );
- UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "Game will restart in %s1 %s2", strRestartDelay, iRestartDelay == 1 ? "SECOND" : "SECONDS" );
-
- m_flRestartGameTime = gpGlobals->curtime + iRestartDelay;
- m_bCompleteReset = true;
- mp_restartgame.SetValue( 0 );
- }
-
- if( mp_readyrestart.GetBool() )
- {
- m_bAwaitingReadyRestart = true;
- m_bHeardAllPlayersReady = false;
-
-
- const char *pszReadyString = mp_ready_signal.GetString();
-
-
- // Don't let them put anything malicious in there
- if( pszReadyString == NULL || Q_strlen(pszReadyString) > 16 )
- {
- pszReadyString = "ready";
- }
-
- IGameEvent *event = gameeventmanager->CreateEvent( "hl2mp_ready_restart" );
- if ( event )
- gameeventmanager->FireEvent( event );
-
- mp_readyrestart.SetValue( 0 );
-
- // cancel any restart round in progress
- m_flRestartGameTime = -1;
- }
-}
-
-void CHL2MPRules::CheckAllPlayersReady( void )
-{
- for (int i = 1; i <= gpGlobals->maxClients; i++ )
- {
- CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
-
- if ( !pPlayer )
- continue;
- if ( !pPlayer->IsReady() )
- return;
- }
- m_bHeardAllPlayersReady = true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-const char *CHL2MPRules::GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer )
-{
- if ( !pPlayer ) // dedicated server output
- {
- return NULL;
- }
-
- const char *pszFormat = NULL;
-
- // team only
- if ( bTeamOnly == TRUE )
- {
- if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR )
- {
- pszFormat = "HL2MP_Chat_Spec";
- }
- else
- {
- const char *chatLocation = GetChatLocation( bTeamOnly, pPlayer );
- if ( chatLocation && *chatLocation )
- {
- pszFormat = "HL2MP_Chat_Team_Loc";
- }
- else
- {
- pszFormat = "HL2MP_Chat_Team";
- }
- }
- }
- // everyone
- else
- {
- if ( pPlayer->GetTeamNumber() != TEAM_SPECTATOR )
- {
- pszFormat = "HL2MP_Chat_All";
- }
- else
- {
- pszFormat = "HL2MP_Chat_AllSpec";
- }
- }
-
- return pszFormat;
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "hl2mp_gamerules.h"
+#include "viewport_panel_names.h"
+#include "gameeventdefs.h"
+#include <KeyValues.h>
+#include "ammodef.h"
+
+#ifdef CLIENT_DLL
+ #include "c_hl2mp_player.h"
+#else
+
+ #include "eventqueue.h"
+ #include "player.h"
+ #include "gamerules.h"
+ #include "game.h"
+ #include "items.h"
+ #include "entitylist.h"
+ #include "mapentities.h"
+ #include "in_buttons.h"
+ #include <ctype.h>
+ #include "voice_gamemgr.h"
+ #include "iscorer.h"
+ #include "hl2mp_player.h"
+ #include "weapon_hl2mpbasehlmpcombatweapon.h"
+ #include "team.h"
+ #include "voice_gamemgr.h"
+ #include "hl2mp_gameinterface.h"
+ #include "hl2mp_cvars.h"
+
+#ifdef DEBUG
+ #include "hl2mp_bot_temp.h"
+#endif
+
+extern void respawn(CBaseEntity *pEdict, bool fCopyCorpse);
+
+extern bool FindInList( const char **pStrings, const char *pToFind );
+
+ConVar sv_hl2mp_weapon_respawn_time( "sv_hl2mp_weapon_respawn_time", "20", FCVAR_GAMEDLL | FCVAR_NOTIFY );
+ConVar sv_hl2mp_item_respawn_time( "sv_hl2mp_item_respawn_time", "30", FCVAR_GAMEDLL | FCVAR_NOTIFY );
+ConVar sv_report_client_settings("sv_report_client_settings", "0", FCVAR_GAMEDLL | FCVAR_NOTIFY );
+
+extern ConVar mp_chattime;
+
+extern CBaseEntity *g_pLastCombineSpawn;
+extern CBaseEntity *g_pLastRebelSpawn;
+
+#define WEAPON_MAX_DISTANCE_FROM_SPAWN 64
+
+#endif
+
+
+REGISTER_GAMERULES_CLASS( CHL2MPRules );
+
+BEGIN_NETWORK_TABLE_NOBASE( CHL2MPRules, DT_HL2MPRules )
+
+ #ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bTeamPlayEnabled ) ),
+ #else
+ SendPropBool( SENDINFO( m_bTeamPlayEnabled ) ),
+ #endif
+
+END_NETWORK_TABLE()
+
+
+LINK_ENTITY_TO_CLASS( hl2mp_gamerules, CHL2MPGameRulesProxy );
+IMPLEMENT_NETWORKCLASS_ALIASED( HL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
+
+static HL2MPViewVectors g_HL2MPViewVectors(
+ Vector( 0, 0, 64 ), //VEC_VIEW (m_vView)
+
+ Vector(-16, -16, 0 ), //VEC_HULL_MIN (m_vHullMin)
+ Vector( 16, 16, 72 ), //VEC_HULL_MAX (m_vHullMax)
+
+ Vector(-16, -16, 0 ), //VEC_DUCK_HULL_MIN (m_vDuckHullMin)
+ Vector( 16, 16, 36 ), //VEC_DUCK_HULL_MAX (m_vDuckHullMax)
+ Vector( 0, 0, 28 ), //VEC_DUCK_VIEW (m_vDuckView)
+
+ Vector(-10, -10, -10 ), //VEC_OBS_HULL_MIN (m_vObsHullMin)
+ Vector( 10, 10, 10 ), //VEC_OBS_HULL_MAX (m_vObsHullMax)
+
+ Vector( 0, 0, 14 ), //VEC_DEAD_VIEWHEIGHT (m_vDeadViewHeight)
+
+ Vector(-16, -16, 0 ), //VEC_CROUCH_TRACE_MIN (m_vCrouchTraceMin)
+ Vector( 16, 16, 60 ) //VEC_CROUCH_TRACE_MAX (m_vCrouchTraceMax)
+);
+
+static const char *s_PreserveEnts[] =
+{
+ "ai_network",
+ "ai_hint",
+ "hl2mp_gamerules",
+ "team_manager",
+ "player_manager",
+ "env_soundscape",
+ "env_soundscape_proxy",
+ "env_soundscape_triggerable",
+ "env_sun",
+ "env_wind",
+ "env_fog_controller",
+ "func_brush",
+ "func_wall",
+ "func_buyzone",
+ "func_illusionary",
+ "infodecal",
+ "info_projecteddecal",
+ "info_node",
+ "info_target",
+ "info_node_hint",
+ "info_player_deathmatch",
+ "info_player_combine",
+ "info_player_rebel",
+ "info_map_parameters",
+ "keyframe_rope",
+ "move_rope",
+ "info_ladder",
+ "player",
+ "point_viewcontrol",
+ "scene_manager",
+ "shadow_control",
+ "sky_camera",
+ "soundent",
+ "trigger_soundscape",
+ "viewmodel",
+ "predicted_viewmodel",
+ "worldspawn",
+ "point_devshot_camera",
+ "", // END Marker
+};
+
+
+
+#ifdef CLIENT_DLL
+ void RecvProxy_HL2MPRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
+ {
+ CHL2MPRules *pRules = HL2MPRules();
+ Assert( pRules );
+ *pOut = pRules;
+ }
+
+ BEGIN_RECV_TABLE( CHL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
+ RecvPropDataTable( "hl2mp_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_HL2MPRules ), RecvProxy_HL2MPRules )
+ END_RECV_TABLE()
+#else
+ void* SendProxy_HL2MPRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
+ {
+ CHL2MPRules *pRules = HL2MPRules();
+ Assert( pRules );
+ return pRules;
+ }
+
+ BEGIN_SEND_TABLE( CHL2MPGameRulesProxy, DT_HL2MPGameRulesProxy )
+ SendPropDataTable( "hl2mp_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_HL2MPRules ), SendProxy_HL2MPRules )
+ END_SEND_TABLE()
+#endif
+
+#ifndef CLIENT_DLL
+
+ class CVoiceGameMgrHelper : public IVoiceGameMgrHelper
+ {
+ public:
+ virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker, bool &bProximity )
+ {
+ return ( pListener->GetTeamNumber() == pTalker->GetTeamNumber() );
+ }
+ };
+ CVoiceGameMgrHelper g_VoiceGameMgrHelper;
+ IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper;
+
+#endif
+
+// NOTE: the indices here must match TEAM_TERRORIST, TEAM_CT, TEAM_SPECTATOR, etc.
+char *sTeamNames[] =
+{
+ "Unassigned",
+ "Spectator",
+ "Combine",
+ "Rebels",
+};
+
+CHL2MPRules::CHL2MPRules()
+{
+#ifndef CLIENT_DLL
+ // Create the team managers
+ for ( int i = 0; i < ARRAYSIZE( sTeamNames ); i++ )
+ {
+ CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "team_manager" ));
+ pTeam->Init( sTeamNames[i], i );
+
+ g_Teams.AddToTail( pTeam );
+ }
+
+ m_bTeamPlayEnabled = teamplay.GetBool();
+ m_flIntermissionEndTime = 0.0f;
+ m_flGameStartTime = 0;
+
+ m_hRespawnableItemsAndWeapons.RemoveAll();
+ m_tmNextPeriodicThink = 0;
+ m_flRestartGameTime = 0;
+ m_bCompleteReset = false;
+ m_bHeardAllPlayersReady = false;
+ m_bAwaitingReadyRestart = false;
+ m_bChangelevelDone = false;
+
+#endif
+}
+
+const CViewVectors* CHL2MPRules::GetViewVectors()const
+{
+ return &g_HL2MPViewVectors;
+}
+
+const HL2MPViewVectors* CHL2MPRules::GetHL2MPViewVectors()const
+{
+ return &g_HL2MPViewVectors;
+}
+
+CHL2MPRules::~CHL2MPRules( void )
+{
+#ifndef CLIENT_DLL
+ // Note, don't delete each team since they are in the gEntList and will
+ // automatically be deleted from there, instead.
+ g_Teams.Purge();
+#endif
+}
+
+void CHL2MPRules::CreateStandardEntities( void )
+{
+
+#ifndef CLIENT_DLL
+ // Create the entity that will send our data to the client.
+
+ BaseClass::CreateStandardEntities();
+
+ g_pLastCombineSpawn = NULL;
+ g_pLastRebelSpawn = NULL;
+
+#ifdef DBGFLAG_ASSERT
+ CBaseEntity *pEnt =
+#endif
+ CBaseEntity::Create( "hl2mp_gamerules", vec3_origin, vec3_angle );
+ Assert( pEnt );
+#endif
+}
+
+//=========================================================
+// FlWeaponRespawnTime - what is the time in the future
+// at which this weapon may spawn?
+//=========================================================
+float CHL2MPRules::FlWeaponRespawnTime( CBaseCombatWeapon *pWeapon )
+{
+#ifndef CLIENT_DLL
+ if ( weaponstay.GetInt() > 0 )
+ {
+ // make sure it's only certain weapons
+ if ( !(pWeapon->GetWeaponFlags() & ITEM_FLAG_LIMITINWORLD) )
+ {
+ return 0; // weapon respawns almost instantly
+ }
+ }
+
+ return sv_hl2mp_weapon_respawn_time.GetFloat();
+#endif
+
+ return 0; // weapon respawns almost instantly
+}
+
+
+bool CHL2MPRules::IsIntermission( void )
+{
+#ifndef CLIENT_DLL
+ return m_flIntermissionEndTime > gpGlobals->curtime;
+#endif
+
+ return false;
+}
+
+void CHL2MPRules::PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info )
+{
+#ifndef CLIENT_DLL
+ if ( IsIntermission() )
+ return;
+ BaseClass::PlayerKilled( pVictim, info );
+#endif
+}
+
+
+void CHL2MPRules::Think( void )
+{
+
+#ifndef CLIENT_DLL
+
+ CGameRules::Think();
+
+ if ( g_fGameOver ) // someone else quit the game already
+ {
+ // check to see if we should change levels now
+ if ( m_flIntermissionEndTime < gpGlobals->curtime )
+ {
+ if ( !m_bChangelevelDone )
+ {
+ ChangeLevel(); // intermission is over
+ m_bChangelevelDone = true;
+ }
+ }
+
+ return;
+ }
+
+// float flTimeLimit = mp_timelimit.GetFloat() * 60;
+ float flFragLimit = fraglimit.GetFloat();
+
+ if ( GetMapRemainingTime() < 0 )
+ {
+ GoToIntermission();
+ return;
+ }
+
+ if ( flFragLimit )
+ {
+ if( IsTeamplay() == true )
+ {
+ CTeam *pCombine = g_Teams[TEAM_COMBINE];
+ CTeam *pRebels = g_Teams[TEAM_REBELS];
+
+ if ( pCombine->GetScore() >= flFragLimit || pRebels->GetScore() >= flFragLimit )
+ {
+ GoToIntermission();
+ return;
+ }
+ }
+ else
+ {
+ // check if any player is over the frag limit
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( pPlayer && pPlayer->FragCount() >= flFragLimit )
+ {
+ GoToIntermission();
+ return;
+ }
+ }
+ }
+ }
+
+ if ( gpGlobals->curtime > m_tmNextPeriodicThink )
+ {
+ CheckAllPlayersReady();
+ CheckRestartGame();
+ m_tmNextPeriodicThink = gpGlobals->curtime + 1.0;
+ }
+
+ if ( m_flRestartGameTime > 0.0f && m_flRestartGameTime <= gpGlobals->curtime )
+ {
+ RestartGame();
+ }
+
+ if( m_bAwaitingReadyRestart && m_bHeardAllPlayersReady )
+ {
+ UTIL_ClientPrintAll( HUD_PRINTCENTER, "All players ready. Game will restart in 5 seconds" );
+ UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "All players ready. Game will restart in 5 seconds" );
+
+ m_flRestartGameTime = gpGlobals->curtime + 5;
+ m_bAwaitingReadyRestart = false;
+ }
+
+ ManageObjectRelocation();
+
+#endif
+}
+
+void CHL2MPRules::GoToIntermission( void )
+{
+#ifndef CLIENT_DLL
+ if ( g_fGameOver )
+ return;
+
+ g_fGameOver = true;
+
+ m_flIntermissionEndTime = gpGlobals->curtime + mp_chattime.GetInt();
+
+ for ( int i = 0; i < MAX_PLAYERS; i++ )
+ {
+ CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer )
+ continue;
+
+ pPlayer->ShowViewPortPanel( PANEL_SCOREBOARD );
+ pPlayer->AddFlag( FL_FROZEN );
+ }
+#endif
+
+}
+
+bool CHL2MPRules::CheckGameOver()
+{
+#ifndef CLIENT_DLL
+ if ( g_fGameOver ) // someone else quit the game already
+ {
+ // check to see if we should change levels now
+ if ( m_flIntermissionEndTime < gpGlobals->curtime )
+ {
+ ChangeLevel(); // intermission is over
+ }
+
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+// when we are within this close to running out of entities, items
+// marked with the ITEM_FLAG_LIMITINWORLD will delay their respawn
+#define ENTITY_INTOLERANCE 100
+
+//=========================================================
+// FlWeaponRespawnTime - Returns 0 if the weapon can respawn
+// now, otherwise it returns the time at which it can try
+// to spawn again.
+//=========================================================
+float CHL2MPRules::FlWeaponTryRespawn( CBaseCombatWeapon *pWeapon )
+{
+#ifndef CLIENT_DLL
+ if ( pWeapon && (pWeapon->GetWeaponFlags() & ITEM_FLAG_LIMITINWORLD) )
+ {
+ if ( gEntList.NumberOfEntities() < (gpGlobals->maxEntities - ENTITY_INTOLERANCE) )
+ return 0;
+
+ // we're past the entity tolerance level, so delay the respawn
+ return FlWeaponRespawnTime( pWeapon );
+ }
+#endif
+ return 0;
+}
+
+//=========================================================
+// VecWeaponRespawnSpot - where should this weapon spawn?
+// Some game variations may choose to randomize spawn locations
+//=========================================================
+Vector CHL2MPRules::VecWeaponRespawnSpot( CBaseCombatWeapon *pWeapon )
+{
+#ifndef CLIENT_DLL
+ CWeaponHL2MPBase *pHL2Weapon = dynamic_cast< CWeaponHL2MPBase*>( pWeapon );
+
+ if ( pHL2Weapon )
+ {
+ return pHL2Weapon->GetOriginalSpawnOrigin();
+ }
+#endif
+
+ return pWeapon->GetAbsOrigin();
+}
+
+#ifndef CLIENT_DLL
+
+CItem* IsManagedObjectAnItem( CBaseEntity *pObject )
+{
+ return dynamic_cast< CItem*>( pObject );
+}
+
+CWeaponHL2MPBase* IsManagedObjectAWeapon( CBaseEntity *pObject )
+{
+ return dynamic_cast< CWeaponHL2MPBase*>( pObject );
+}
+
+bool GetObjectsOriginalParameters( CBaseEntity *pObject, Vector &vOriginalOrigin, QAngle &vOriginalAngles )
+{
+ if ( CItem *pItem = IsManagedObjectAnItem( pObject ) )
+ {
+ if ( pItem->m_flNextResetCheckTime > gpGlobals->curtime )
+ return false;
+
+ vOriginalOrigin = pItem->GetOriginalSpawnOrigin();
+ vOriginalAngles = pItem->GetOriginalSpawnAngles();
+
+ pItem->m_flNextResetCheckTime = gpGlobals->curtime + sv_hl2mp_item_respawn_time.GetFloat();
+ return true;
+ }
+ else if ( CWeaponHL2MPBase *pWeapon = IsManagedObjectAWeapon( pObject ))
+ {
+ if ( pWeapon->m_flNextResetCheckTime > gpGlobals->curtime )
+ return false;
+
+ vOriginalOrigin = pWeapon->GetOriginalSpawnOrigin();
+ vOriginalAngles = pWeapon->GetOriginalSpawnAngles();
+
+ pWeapon->m_flNextResetCheckTime = gpGlobals->curtime + sv_hl2mp_weapon_respawn_time.GetFloat();
+ return true;
+ }
+
+ return false;
+}
+
+void CHL2MPRules::ManageObjectRelocation( void )
+{
+ int iTotal = m_hRespawnableItemsAndWeapons.Count();
+
+ if ( iTotal > 0 )
+ {
+ for ( int i = 0; i < iTotal; i++ )
+ {
+ CBaseEntity *pObject = m_hRespawnableItemsAndWeapons[i].Get();
+
+ if ( pObject )
+ {
+ Vector vSpawOrigin;
+ QAngle vSpawnAngles;
+
+ if ( GetObjectsOriginalParameters( pObject, vSpawOrigin, vSpawnAngles ) == true )
+ {
+ float flDistanceFromSpawn = (pObject->GetAbsOrigin() - vSpawOrigin ).Length();
+
+ if ( flDistanceFromSpawn > WEAPON_MAX_DISTANCE_FROM_SPAWN )
+ {
+ bool shouldReset = false;
+ IPhysicsObject *pPhysics = pObject->VPhysicsGetObject();
+
+ if ( pPhysics )
+ {
+ shouldReset = pPhysics->IsAsleep();
+ }
+ else
+ {
+ shouldReset = (pObject->GetFlags() & FL_ONGROUND) ? true : false;
+ }
+
+ if ( shouldReset )
+ {
+ pObject->Teleport( &vSpawOrigin, &vSpawnAngles, NULL );
+ pObject->EmitSound( "AlyxEmp.Charge" );
+
+ IPhysicsObject *pPhys = pObject->VPhysicsGetObject();
+
+ if ( pPhys )
+ {
+ pPhys->Wake();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+//=========================================================
+//AddLevelDesignerPlacedWeapon
+//=========================================================
+void CHL2MPRules::AddLevelDesignerPlacedObject( CBaseEntity *pEntity )
+{
+ if ( m_hRespawnableItemsAndWeapons.Find( pEntity ) == -1 )
+ {
+ m_hRespawnableItemsAndWeapons.AddToTail( pEntity );
+ }
+}
+
+//=========================================================
+//RemoveLevelDesignerPlacedWeapon
+//=========================================================
+void CHL2MPRules::RemoveLevelDesignerPlacedObject( CBaseEntity *pEntity )
+{
+ if ( m_hRespawnableItemsAndWeapons.Find( pEntity ) != -1 )
+ {
+ m_hRespawnableItemsAndWeapons.FindAndRemove( pEntity );
+ }
+}
+
+//=========================================================
+// Where should this item respawn?
+// Some game variations may choose to randomize spawn locations
+//=========================================================
+Vector CHL2MPRules::VecItemRespawnSpot( CItem *pItem )
+{
+ return pItem->GetOriginalSpawnOrigin();
+}
+
+//=========================================================
+// What angles should this item use to respawn?
+//=========================================================
+QAngle CHL2MPRules::VecItemRespawnAngles( CItem *pItem )
+{
+ return pItem->GetOriginalSpawnAngles();
+}
+
+//=========================================================
+// At what time in the future may this Item respawn?
+//=========================================================
+float CHL2MPRules::FlItemRespawnTime( CItem *pItem )
+{
+ return sv_hl2mp_item_respawn_time.GetFloat();
+}
+
+
+//=========================================================
+// CanHaveWeapon - returns false if the player is not allowed
+// to pick up this weapon
+//=========================================================
+bool CHL2MPRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pItem )
+{
+ if ( weaponstay.GetInt() > 0 )
+ {
+ if ( pPlayer->Weapon_OwnsThisType( pItem->GetClassname(), pItem->GetSubType() ) )
+ return false;
+ }
+
+ return BaseClass::CanHavePlayerItem( pPlayer, pItem );
+}
+
+#endif
+
+//=========================================================
+// WeaponShouldRespawn - any conditions inhibiting the
+// respawning of this weapon?
+//=========================================================
+int CHL2MPRules::WeaponShouldRespawn( CBaseCombatWeapon *pWeapon )
+{
+#ifndef CLIENT_DLL
+ if ( pWeapon->HasSpawnFlags( SF_NORESPAWN ) )
+ {
+ return GR_WEAPON_RESPAWN_NO;
+ }
+#endif
+
+ return GR_WEAPON_RESPAWN_YES;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Player has just left the game
+//-----------------------------------------------------------------------------
+void CHL2MPRules::ClientDisconnected( edict_t *pClient )
+{
+#ifndef CLIENT_DLL
+ // Msg( "CLIENT DISCONNECTED, REMOVING FROM TEAM.\n" );
+
+ CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient );
+ if ( pPlayer )
+ {
+ // Remove the player from his team
+ if ( pPlayer->GetTeam() )
+ {
+ pPlayer->GetTeam()->RemovePlayer( pPlayer );
+ }
+ }
+
+ BaseClass::ClientDisconnected( pClient );
+
+#endif
+}
+
+
+//=========================================================
+// Deathnotice.
+//=========================================================
+void CHL2MPRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
+{
+#ifndef CLIENT_DLL
+ // Work out what killed the player, and send a message to all clients about it
+ const char *killer_weapon_name = "world"; // by default, the player is killed by the world
+ int killer_ID = 0;
+
+ // Find the killer & the scorer
+ CBaseEntity *pInflictor = info.GetInflictor();
+ CBaseEntity *pKiller = info.GetAttacker();
+ CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );
+
+ // Custom kill type?
+ if ( info.GetDamageCustom() )
+ {
+ killer_weapon_name = GetDamageCustomString( info );
+ if ( pScorer )
+ {
+ killer_ID = pScorer->GetUserID();
+ }
+ }
+ else
+ {
+ // Is the killer a client?
+ if ( pScorer )
+ {
+ killer_ID = pScorer->GetUserID();
+
+ if ( pInflictor )
+ {
+ if ( pInflictor == pScorer )
+ {
+ // If the inflictor is the killer, then it must be their current weapon doing the damage
+ if ( pScorer->GetActiveWeapon() )
+ {
+ killer_weapon_name = pScorer->GetActiveWeapon()->GetClassname();
+ }
+ }
+ else
+ {
+ killer_weapon_name = pInflictor->GetClassname(); // it's just that easy
+ }
+ }
+ }
+ else
+ {
+ killer_weapon_name = pInflictor->GetClassname();
+ }
+
+ // strip the NPC_* or weapon_* from the inflictor's classname
+ if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 )
+ {
+ killer_weapon_name += 7;
+ }
+ else if ( strncmp( killer_weapon_name, "npc_", 4 ) == 0 )
+ {
+ killer_weapon_name += 4;
+ }
+ else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 )
+ {
+ killer_weapon_name += 5;
+ }
+ else if ( strstr( killer_weapon_name, "physics" ) )
+ {
+ killer_weapon_name = "physics";
+ }
+
+ if ( strcmp( killer_weapon_name, "prop_combine_ball" ) == 0 )
+ {
+ killer_weapon_name = "combine_ball";
+ }
+ else if ( strcmp( killer_weapon_name, "grenade_ar2" ) == 0 )
+ {
+ killer_weapon_name = "smg1_grenade";
+ }
+ else if ( strcmp( killer_weapon_name, "satchel" ) == 0 || strcmp( killer_weapon_name, "tripmine" ) == 0)
+ {
+ killer_weapon_name = "slam";
+ }
+
+
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "player_death" );
+ if( event )
+ {
+ event->SetInt("userid", pVictim->GetUserID() );
+ event->SetInt("attacker", killer_ID );
+ event->SetString("weapon", killer_weapon_name );
+ event->SetInt( "priority", 7 );
+ gameeventmanager->FireEvent( event );
+ }
+#endif
+
+}
+
+void CHL2MPRules::ClientSettingsChanged( CBasePlayer *pPlayer )
+{
+#ifndef CLIENT_DLL
+
+ CHL2MP_Player *pHL2Player = ToHL2MPPlayer( pPlayer );
+
+ if ( pHL2Player == NULL )
+ return;
+
+ const char *pCurrentModel = modelinfo->GetModelName( pPlayer->GetModel() );
+ const char *szModelName = engine->GetClientConVarValue( engine->IndexOfEdict( pPlayer->edict() ), "cl_playermodel" );
+
+ //If we're different.
+ if ( stricmp( szModelName, pCurrentModel ) )
+ {
+ //Too soon, set the cvar back to what it was.
+ //Note: this will make this function be called again
+ //but since our models will match it'll just skip this whole dealio.
+ if ( pHL2Player->GetNextModelChangeTime() >= gpGlobals->curtime )
+ {
+ char szReturnString[512];
+
+ Q_snprintf( szReturnString, sizeof (szReturnString ), "cl_playermodel %s\n", pCurrentModel );
+ engine->ClientCommand ( pHL2Player->edict(), szReturnString );
+
+ Q_snprintf( szReturnString, sizeof( szReturnString ), "Please wait %d more seconds before trying to switch.\n", (int)(pHL2Player->GetNextModelChangeTime() - gpGlobals->curtime) );
+ ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
+ return;
+ }
+
+ if ( HL2MPRules()->IsTeamplay() == false )
+ {
+ pHL2Player->SetPlayerModel();
+
+ const char *pszCurrentModelName = modelinfo->GetModelName( pHL2Player->GetModel() );
+
+ char szReturnString[128];
+ Q_snprintf( szReturnString, sizeof( szReturnString ), "Your player model is: %s\n", pszCurrentModelName );
+
+ ClientPrint( pHL2Player, HUD_PRINTTALK, szReturnString );
+ }
+ else
+ {
+ if ( Q_stristr( szModelName, "models/human") )
+ {
+ pHL2Player->ChangeTeam( TEAM_REBELS );
+ }
+ else
+ {
+ pHL2Player->ChangeTeam( TEAM_COMBINE );
+ }
+ }
+ }
+ if ( sv_report_client_settings.GetInt() == 1 )
+ {
+ UTIL_LogPrintf( "\"%s\" cl_cmdrate = \"%s\"\n", pHL2Player->GetPlayerName(), engine->GetClientConVarValue( pHL2Player->entindex(), "cl_cmdrate" ));
+ }
+
+ BaseClass::ClientSettingsChanged( pPlayer );
+#endif
+
+}
+
+int CHL2MPRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget )
+{
+#ifndef CLIENT_DLL
+ // half life multiplay has a simple concept of Player Relationships.
+ // you are either on another player's team, or you are not.
+ if ( !pPlayer || !pTarget || !pTarget->IsPlayer() || IsTeamplay() == false )
+ return GR_NOTTEAMMATE;
+
+ if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) )
+ {
+ return GR_TEAMMATE;
+ }
+#endif
+
+ return GR_NOTTEAMMATE;
+}
+
+const char *CHL2MPRules::GetGameDescription( void )
+{
+ if ( IsTeamplay() )
+ return "Team Deathmatch";
+
+ return "Deathmatch";
+}
+
+bool CHL2MPRules::IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer )
+{
+ return true;
+}
+
+float CHL2MPRules::GetMapRemainingTime()
+{
+ // if timelimit is disabled, return 0
+ if ( mp_timelimit.GetInt() <= 0 )
+ return 0;
+
+ // timelimit is in minutes
+
+ float timeleft = (m_flGameStartTime + mp_timelimit.GetInt() * 60.0f ) - gpGlobals->curtime;
+
+ return timeleft;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHL2MPRules::Precache( void )
+{
+ CBaseEntity::PrecacheScriptSound( "AlyxEmp.Charge" );
+}
+
+bool CHL2MPRules::ShouldCollide( int collisionGroup0, int collisionGroup1 )
+{
+ if ( collisionGroup0 > collisionGroup1 )
+ {
+ // swap so that lowest is always first
+ V_swap(collisionGroup0,collisionGroup1);
+ }
+
+ if ( (collisionGroup0 == COLLISION_GROUP_PLAYER || collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT) &&
+ collisionGroup1 == COLLISION_GROUP_WEAPON )
+ {
+ return false;
+ }
+
+ return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 );
+
+}
+
+bool CHL2MPRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
+{
+#ifndef CLIENT_DLL
+ if( BaseClass::ClientCommand( pEdict, args ) )
+ return true;
+
+
+ CHL2MP_Player *pPlayer = (CHL2MP_Player *) pEdict;
+
+ if ( pPlayer->ClientCommand( args ) )
+ return true;
+#endif
+
+ return false;
+}
+
+// shared ammo definition
+// JAY: Trying to make a more physical bullet response
+#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f)
+#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains))
+
+// exaggerate all of the forces, but use real numbers to keep them consistent
+#define BULLET_IMPULSE_EXAGGERATION 3.5
+// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s
+#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION)
+
+
+CAmmoDef *GetAmmoDef()
+{
+ static CAmmoDef def;
+ static bool bInitted = false;
+
+ if ( !bInitted )
+ {
+ bInitted = true;
+
+ def.AddAmmoType("AR2", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 60, BULLET_IMPULSE(200, 1225), 0 );
+ def.AddAmmoType("AR2AltFire", DMG_DISSOLVE, TRACER_NONE, 0, 0, 3, 0, 0 );
+ def.AddAmmoType("Pistol", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 150, BULLET_IMPULSE(200, 1225), 0 );
+ def.AddAmmoType("SMG1", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 225, BULLET_IMPULSE(200, 1225), 0 );
+ def.AddAmmoType("357", DMG_BULLET, TRACER_LINE_AND_WHIZ, 0, 0, 12, BULLET_IMPULSE(800, 5000), 0 );
+ def.AddAmmoType("XBowBolt", DMG_BULLET, TRACER_LINE, 0, 0, 10, BULLET_IMPULSE(800, 8000), 0 );
+ def.AddAmmoType("Buckshot", DMG_BULLET | DMG_BUCKSHOT, TRACER_LINE, 0, 0, 30, BULLET_IMPULSE(400, 1200), 0 );
+ def.AddAmmoType("RPG_Round", DMG_BURN, TRACER_NONE, 0, 0, 3, 0, 0 );
+ def.AddAmmoType("SMG1_Grenade", DMG_BURN, TRACER_NONE, 0, 0, 3, 0, 0 );
+ def.AddAmmoType("Grenade", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0 );
+ def.AddAmmoType("slam", DMG_BURN, TRACER_NONE, 0, 0, 5, 0, 0 );
+ }
+
+ return &def;
+}
+
+#ifdef CLIENT_DLL
+
+ ConVar cl_autowepswitch(
+ "cl_autowepswitch",
+ "1",
+ FCVAR_ARCHIVE | FCVAR_USERINFO,
+ "Automatically switch to picked up weapons (if more powerful)" );
+
+#else
+
+#ifdef DEBUG
+
+ // Handler for the "bot" command.
+ void Bot_f()
+ {
+ // Look at -count.
+ int count = 1;
+ count = clamp( count, 1, 16 );
+
+ int iTeam = TEAM_COMBINE;
+
+ // Look at -frozen.
+ bool bFrozen = false;
+
+ // Ok, spawn all the bots.
+ while ( --count >= 0 )
+ {
+ BotPutInServer( bFrozen, iTeam );
+ }
+ }
+
+
+ ConCommand cc_Bot( "bot", Bot_f, "Add a bot.", FCVAR_CHEAT );
+
+#endif
+
+ bool CHL2MPRules::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon )
+ {
+ if ( pPlayer->GetActiveWeapon() && pPlayer->IsNetClient() )
+ {
+ // Player has an active item, so let's check cl_autowepswitch.
+ const char *cl_autowepswitch = engine->GetClientConVarValue( engine->IndexOfEdict( pPlayer->edict() ), "cl_autowepswitch" );
+ if ( cl_autowepswitch && atoi( cl_autowepswitch ) <= 0 )
+ {
+ return false;
+ }
+ }
+
+ return BaseClass::FShouldSwitchWeapon( pPlayer, pWeapon );
+ }
+
+#endif
+
+#ifndef CLIENT_DLL
+
+void CHL2MPRules::RestartGame()
+{
+ // bounds check
+ if ( mp_timelimit.GetInt() < 0 )
+ {
+ mp_timelimit.SetValue( 0 );
+ }
+ m_flGameStartTime = gpGlobals->curtime;
+ if ( !IsFinite( m_flGameStartTime.Get() ) )
+ {
+ Warning( "Trying to set a NaN game start time\n" );
+ m_flGameStartTime.GetForModify() = 0.0f;
+ }
+
+ CleanUpMap();
+
+ // now respawn all players
+ for (int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer )
+ continue;
+
+ if ( pPlayer->GetActiveWeapon() )
+ {
+ pPlayer->GetActiveWeapon()->Holster();
+ }
+ pPlayer->RemoveAllItems( true );
+ respawn( pPlayer, false );
+ pPlayer->Reset();
+ }
+
+ // Respawn entities (glass, doors, etc..)
+
+ CTeam *pRebels = GetGlobalTeam( TEAM_REBELS );
+ CTeam *pCombine = GetGlobalTeam( TEAM_COMBINE );
+
+ if ( pRebels )
+ {
+ pRebels->SetScore( 0 );
+ }
+
+ if ( pCombine )
+ {
+ pCombine->SetScore( 0 );
+ }
+
+ m_flIntermissionEndTime = 0;
+ m_flRestartGameTime = 0.0;
+ m_bCompleteReset = false;
+
+ IGameEvent * event = gameeventmanager->CreateEvent( "round_start" );
+ if ( event )
+ {
+ event->SetInt("fraglimit", 0 );
+ event->SetInt( "priority", 6 ); // HLTV event priority, not transmitted
+
+ event->SetString("objective","DEATHMATCH");
+
+ gameeventmanager->FireEvent( event );
+ }
+}
+
+void CHL2MPRules::CleanUpMap()
+{
+ // Recreate all the map entities from the map data (preserving their indices),
+ // then remove everything else except the players.
+
+ // Get rid of all entities except players.
+ CBaseEntity *pCur = gEntList.FirstEnt();
+ while ( pCur )
+ {
+ CBaseHL2MPCombatWeapon *pWeapon = dynamic_cast< CBaseHL2MPCombatWeapon* >( pCur );
+ // Weapons with owners don't want to be removed..
+ if ( pWeapon )
+ {
+ if ( !pWeapon->GetPlayerOwner() )
+ {
+ UTIL_Remove( pCur );
+ }
+ }
+ // remove entities that has to be restored on roundrestart (breakables etc)
+ else if ( !FindInList( s_PreserveEnts, pCur->GetClassname() ) )
+ {
+ UTIL_Remove( pCur );
+ }
+
+ pCur = gEntList.NextEnt( pCur );
+ }
+
+ // Really remove the entities so we can have access to their slots below.
+ gEntList.CleanupDeleteList();
+
+ // Cancel all queued events, in case a func_bomb_target fired some delayed outputs that
+ // could kill respawning CTs
+ g_EventQueue.Clear();
+
+ // Now reload the map entities.
+ class CHL2MPMapEntityFilter : public IMapEntityFilter
+ {
+ public:
+ virtual bool ShouldCreateEntity( const char *pClassname )
+ {
+ // Don't recreate the preserved entities.
+ if ( !FindInList( s_PreserveEnts, pClassname ) )
+ {
+ return true;
+ }
+ else
+ {
+ // Increment our iterator since it's not going to call CreateNextEntity for this ent.
+ if ( m_iIterator != g_MapEntityRefs.InvalidIndex() )
+ m_iIterator = g_MapEntityRefs.Next( m_iIterator );
+
+ return false;
+ }
+ }
+
+
+ virtual CBaseEntity* CreateNextEntity( const char *pClassname )
+ {
+ if ( m_iIterator == g_MapEntityRefs.InvalidIndex() )
+ {
+ // This shouldn't be possible. When we loaded the map, it should have used
+ // CCSMapLoadEntityFilter, which should have built the g_MapEntityRefs list
+ // with the same list of entities we're referring to here.
+ Assert( false );
+ return NULL;
+ }
+ else
+ {
+ CMapEntityRef &ref = g_MapEntityRefs[m_iIterator];
+ m_iIterator = g_MapEntityRefs.Next( m_iIterator ); // Seek to the next entity.
+
+ if ( ref.m_iEdict == -1 || engine->PEntityOfEntIndex( ref.m_iEdict ) )
+ {
+ // Doh! The entity was delete and its slot was reused.
+ // Just use any old edict slot. This case sucks because we lose the baseline.
+ return CreateEntityByName( pClassname );
+ }
+ else
+ {
+ // Cool, the slot where this entity was is free again (most likely, the entity was
+ // freed above). Now create an entity with this specific index.
+ return CreateEntityByName( pClassname, ref.m_iEdict );
+ }
+ }
+ }
+
+ public:
+ int m_iIterator; // Iterator into g_MapEntityRefs.
+ };
+ CHL2MPMapEntityFilter filter;
+ filter.m_iIterator = g_MapEntityRefs.Head();
+
+ // DO NOT CALL SPAWN ON info_node ENTITIES!
+
+ MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
+}
+
+void CHL2MPRules::CheckChatForReadySignal( CHL2MP_Player *pPlayer, const char *chatmsg )
+{
+ if( m_bAwaitingReadyRestart && FStrEq( chatmsg, mp_ready_signal.GetString() ) )
+ {
+ if( !pPlayer->IsReady() )
+ {
+ pPlayer->SetReady( true );
+ }
+ }
+}
+
+void CHL2MPRules::CheckRestartGame( void )
+{
+ // Restart the game if specified by the server
+ int iRestartDelay = mp_restartgame.GetInt();
+
+ if ( iRestartDelay > 0 )
+ {
+ if ( iRestartDelay > 60 )
+ iRestartDelay = 60;
+
+
+ // let the players know
+ char strRestartDelay[64];
+ Q_snprintf( strRestartDelay, sizeof( strRestartDelay ), "%d", iRestartDelay );
+ UTIL_ClientPrintAll( HUD_PRINTCENTER, "Game will restart in %s1 %s2", strRestartDelay, iRestartDelay == 1 ? "SECOND" : "SECONDS" );
+ UTIL_ClientPrintAll( HUD_PRINTCONSOLE, "Game will restart in %s1 %s2", strRestartDelay, iRestartDelay == 1 ? "SECOND" : "SECONDS" );
+
+ m_flRestartGameTime = gpGlobals->curtime + iRestartDelay;
+ m_bCompleteReset = true;
+ mp_restartgame.SetValue( 0 );
+ }
+
+ if( mp_readyrestart.GetBool() )
+ {
+ m_bAwaitingReadyRestart = true;
+ m_bHeardAllPlayersReady = false;
+
+
+ const char *pszReadyString = mp_ready_signal.GetString();
+
+
+ // Don't let them put anything malicious in there
+ if( pszReadyString == NULL || Q_strlen(pszReadyString) > 16 )
+ {
+ pszReadyString = "ready";
+ }
+
+ IGameEvent *event = gameeventmanager->CreateEvent( "hl2mp_ready_restart" );
+ if ( event )
+ gameeventmanager->FireEvent( event );
+
+ mp_readyrestart.SetValue( 0 );
+
+ // cancel any restart round in progress
+ m_flRestartGameTime = -1;
+ }
+}
+
+void CHL2MPRules::CheckAllPlayersReady( void )
+{
+ for (int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CHL2MP_Player *pPlayer = (CHL2MP_Player*) UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer )
+ continue;
+ if ( !pPlayer->IsReady() )
+ return;
+ }
+ m_bHeardAllPlayersReady = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CHL2MPRules::GetChatFormat( bool bTeamOnly, CBasePlayer *pPlayer )
+{
+ if ( !pPlayer ) // dedicated server output
+ {
+ return NULL;
+ }
+
+ const char *pszFormat = NULL;
+
+ // team only
+ if ( bTeamOnly == TRUE )
+ {
+ if ( pPlayer->GetTeamNumber() == TEAM_SPECTATOR )
+ {
+ pszFormat = "HL2MP_Chat_Spec";
+ }
+ else
+ {
+ const char *chatLocation = GetChatLocation( bTeamOnly, pPlayer );
+ if ( chatLocation && *chatLocation )
+ {
+ pszFormat = "HL2MP_Chat_Team_Loc";
+ }
+ else
+ {
+ pszFormat = "HL2MP_Chat_Team";
+ }
+ }
+ }
+ // everyone
+ else
+ {
+ if ( pPlayer->GetTeamNumber() != TEAM_SPECTATOR )
+ {
+ pszFormat = "HL2MP_Chat_All";
+ }
+ else
+ {
+ pszFormat = "HL2MP_Chat_AllSpec";
+ }
+ }
+
+ return pszFormat;
+}
+
#endif \ No newline at end of file