diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/server/client.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/server/client.cpp')
| -rw-r--r-- | mp/src/game/server/client.cpp | 1517 |
1 files changed, 1517 insertions, 0 deletions
diff --git a/mp/src/game/server/client.cpp b/mp/src/game/server/client.cpp new file mode 100644 index 00000000..2fd87cfe --- /dev/null +++ b/mp/src/game/server/client.cpp @@ -0,0 +1,1517 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+/*
+
+===== client.cpp ========================================================
+
+ client/server game specific stuff
+
+*/
+
+#include "cbase.h"
+#include "player.h"
+#include "client.h"
+#include "soundent.h"
+#include "gamerules.h"
+#include "game.h"
+#include "physics.h"
+#include "entitylist.h"
+#include "shake.h"
+#include "globalstate.h"
+#include "event_tempentity_tester.h"
+#include "ndebugoverlay.h"
+#include "engine/IEngineSound.h"
+#include <ctype.h>
+#include "tier1/strtools.h"
+#include "te_effect_dispatch.h"
+#include "globals.h"
+#include "nav_mesh.h"
+#include "team.h"
+#include "datacache/imdlcache.h"
+#include "basemultiplayerplayer.h"
+#include "voice_gamemgr.h"
+
+#ifdef TF_DLL
+#include "tf_player.h"
+#include "tf_gamerules.h"
+#endif
+
+#ifdef HL2_DLL
+#include "weapon_physcannon.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern int giPrecacheGrunt;
+
+// For not just using one big ai net
+extern CBaseEntity* FindPickerEntity( CBasePlayer* pPlayer );
+
+extern bool IsInCommentaryMode( void );
+
+ConVar *sv_cheats = NULL;
+
+void ClientKill( edict_t *pEdict, const Vector &vecForce, bool bExplode = false )
+{
+ CBasePlayer *pPlayer = static_cast<CBasePlayer*>( GetContainingEntity( pEdict ) );
+ pPlayer->CommitSuicide( vecForce, bExplode );
+}
+
+char * CheckChatText( CBasePlayer *pPlayer, char *text )
+{
+ char *p = text;
+
+ // invalid if NULL or empty
+ if ( !text || !text[0] )
+ return NULL;
+
+ int length = Q_strlen( text );
+
+ // remove quotes (leading & trailing) if present
+ if (*p == '"')
+ {
+ p++;
+ length -=2;
+ p[length] = 0;
+ }
+
+ // cut off after 127 chars
+ if ( length > 127 )
+ text[127] = 0;
+
+ GameRules()->CheckChatText( pPlayer, p );
+
+ return p;
+}
+
+//// HOST_SAY
+// String comes in as
+// say blah blah blah
+// or as
+// blah blah blah
+//
+void Host_Say( edict_t *pEdict, const CCommand &args, bool teamonly )
+{
+ CBasePlayer *client;
+ int j;
+ char *p;
+ char text[256];
+ char szTemp[256];
+ const char *cpSay = "say";
+ const char *cpSayTeam = "say_team";
+ const char *pcmd = args[0];
+ bool bSenderDead = false;
+
+ // We can get a raw string now, without the "say " prepended
+ if ( args.ArgC() == 0 )
+ return;
+
+ if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
+ {
+ if ( args.ArgC() >= 2 )
+ {
+ p = (char *)args.ArgS();
+ }
+ else
+ {
+ // say with a blank message, nothing to do
+ return;
+ }
+ }
+ else // Raw text, need to prepend argv[0]
+ {
+ if ( args.ArgC() >= 2 )
+ {
+ Q_snprintf( szTemp,sizeof(szTemp), "%s %s", ( char * )pcmd, (char *)args.ArgS() );
+ }
+ else
+ {
+ // Just a one word command, use the first word...sigh
+ Q_snprintf( szTemp,sizeof(szTemp), "%s", ( char * )pcmd );
+ }
+ p = szTemp;
+ }
+
+ CBasePlayer *pPlayer = NULL;
+ if ( pEdict )
+ {
+ pPlayer = ((CBasePlayer *)CBaseEntity::Instance( pEdict ));
+ Assert( pPlayer );
+
+ // make sure the text has valid content
+ p = CheckChatText( pPlayer, p );
+ }
+
+ if ( !p )
+ return;
+
+ if ( pEdict )
+ {
+ if ( !pPlayer->CanSpeak() )
+ return;
+
+ // See if the player wants to modify of check the text
+ pPlayer->CheckChatText( p, 127 ); // though the buffer szTemp that p points to is 256,
+ // chat text is capped to 127 in CheckChatText above
+
+ Assert( strlen( pPlayer->GetPlayerName() ) > 0 );
+
+ bSenderDead = ( pPlayer->m_lifeState != LIFE_ALIVE );
+ }
+ else
+ {
+ bSenderDead = false;
+ }
+
+ const char *pszFormat = NULL;
+ const char *pszPrefix = NULL;
+ const char *pszLocation = NULL;
+ if ( g_pGameRules )
+ {
+ pszFormat = g_pGameRules->GetChatFormat( teamonly, pPlayer );
+ pszPrefix = g_pGameRules->GetChatPrefix( teamonly, pPlayer );
+ pszLocation = g_pGameRules->GetChatLocation( teamonly, pPlayer );
+ }
+
+ const char *pszPlayerName = pPlayer ? pPlayer->GetPlayerName():"Console";
+
+ if ( pszPrefix && strlen( pszPrefix ) > 0 )
+ {
+ if ( pszLocation && strlen( pszLocation ) )
+ {
+ Q_snprintf( text, sizeof(text), "%s %s @ %s: ", pszPrefix, pszPlayerName, pszLocation );
+ }
+ else
+ {
+ Q_snprintf( text, sizeof(text), "%s %s: ", pszPrefix, pszPlayerName );
+ }
+ }
+ else
+ {
+ Q_snprintf( text, sizeof(text), "%s: ", pszPlayerName );
+ }
+
+ j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
+ if ( (int)strlen(p) > j )
+ p[j] = 0;
+
+ Q_strncat( text, p, sizeof( text ), COPY_ALL_CHARACTERS );
+ Q_strncat( text, "\n", sizeof( text ), COPY_ALL_CHARACTERS );
+
+ // loop through all players
+ // Start with the first player.
+ // This may return the world in single player if the client types something between levels or during spawn
+ // so check it, or it will infinite loop
+
+ client = NULL;
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ client = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
+ if ( !client || !client->edict() )
+ continue;
+
+ if ( client->edict() == pEdict )
+ continue;
+
+ if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
+ continue;
+
+ if ( teamonly && g_pGameRules->PlayerCanHearChat( client, pPlayer ) != GR_TEAMMATE )
+ continue;
+
+ if ( pPlayer && !client->CanHearAndReadChatFrom( pPlayer ) )
+ continue;
+
+ if ( pPlayer && GetVoiceGameMgr() && GetVoiceGameMgr()->IsPlayerIgnoringPlayer( pPlayer->entindex(), i ) )
+ continue;
+
+ CSingleUserRecipientFilter user( client );
+ user.MakeReliable();
+
+ if ( pszFormat )
+ {
+ UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
+ }
+ else
+ {
+ UTIL_SayTextFilter( user, text, pPlayer, true );
+ }
+ }
+
+ if ( pPlayer )
+ {
+ // print to the sending client
+ CSingleUserRecipientFilter user( pPlayer );
+ user.MakeReliable();
+
+ if ( pszFormat )
+ {
+ UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
+ }
+ else
+ {
+ UTIL_SayTextFilter( user, text, pPlayer, true );
+ }
+ }
+
+ // echo to server console
+ // Adrian: Only do this if we're running a dedicated server since we already print to console on the client.
+ if ( engine->IsDedicatedServer() )
+ Msg( "%s", text );
+
+ Assert( p );
+
+ int userid = 0;
+ const char *networkID = "Console";
+ const char *playerName = "Console";
+ const char *playerTeam = "Console";
+ if ( pPlayer )
+ {
+ userid = pPlayer->GetUserID();
+ networkID = pPlayer->GetNetworkIDString();
+ playerName = pPlayer->GetPlayerName();
+ CTeam *team = pPlayer->GetTeam();
+ if ( team )
+ {
+ playerTeam = team->GetName();
+ }
+ }
+
+ if ( teamonly )
+ UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say_team \"%s\"\n", playerName, userid, networkID, playerTeam, p );
+ else
+ UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say \"%s\"\n", playerName, userid, networkID, playerTeam, p );
+
+ IGameEvent * event = gameeventmanager->CreateEvent( "player_say", true );
+
+ if ( event )
+ {
+ event->SetInt("userid", userid );
+ event->SetString("text", p );
+ event->SetInt("priority", 1 ); // HLTV event priority, not transmitted
+ gameeventmanager->FireEvent( event, true );
+ }
+}
+
+
+void ClientPrecache( void )
+{
+ // Precache cable textures.
+ CBaseEntity::PrecacheModel( "cable/cable.vmt" );
+ CBaseEntity::PrecacheModel( "cable/cable_lit.vmt" );
+ CBaseEntity::PrecacheModel( "cable/chain.vmt" );
+ CBaseEntity::PrecacheModel( "cable/rope.vmt" );
+ CBaseEntity::PrecacheModel( "sprites/blueglow1.vmt" );
+ CBaseEntity::PrecacheModel( "sprites/purpleglow1.vmt" );
+ CBaseEntity::PrecacheModel( "sprites/purplelaser1.vmt" );
+
+#ifndef HL2MP
+ CBaseEntity::PrecacheScriptSound( "Hud.Hint" );
+#endif // HL2MP
+ CBaseEntity::PrecacheScriptSound( "Player.FallDamage" );
+ CBaseEntity::PrecacheScriptSound( "Player.Swim" );
+
+ // General HUD sounds
+ CBaseEntity::PrecacheScriptSound( "Player.PickupWeapon" );
+ CBaseEntity::PrecacheScriptSound( "Player.DenyWeaponSelection" );
+ CBaseEntity::PrecacheScriptSound( "Player.WeaponSelected" );
+ CBaseEntity::PrecacheScriptSound( "Player.WeaponSelectionClose" );
+ CBaseEntity::PrecacheScriptSound( "Player.WeaponSelectionMoveSlot" );
+
+ // General legacy temp ents sounds
+ CBaseEntity::PrecacheScriptSound( "Bounce.Glass" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Metal" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Flesh" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Wood" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Shrapnel" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.ShotgunShell" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Shell" );
+ CBaseEntity::PrecacheScriptSound( "Bounce.Concrete" );
+
+ ClientGamePrecache();
+}
+
+CON_COMMAND_F( cast_ray, "Tests collision detection", FCVAR_CHEAT )
+{
+ CBasePlayer *pPlayer = UTIL_GetCommandClient();
+
+ Vector forward;
+ trace_t tr;
+
+ pPlayer->EyeVectors( &forward );
+ Vector start = pPlayer->EyePosition();
+ UTIL_TraceLine(start, start + forward * MAX_COORD_RANGE, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.DidHit() )
+ {
+ DevMsg(1, "Hit %s\nposition %.2f, %.2f, %.2f\nangles %.2f, %.2f, %.2f\n", tr.m_pEnt->GetClassname(),
+ tr.m_pEnt->GetAbsOrigin().x, tr.m_pEnt->GetAbsOrigin().y, tr.m_pEnt->GetAbsOrigin().z,
+ tr.m_pEnt->GetAbsAngles().x, tr.m_pEnt->GetAbsAngles().y, tr.m_pEnt->GetAbsAngles().z );
+ DevMsg(1, "Hit: hitbox %d, hitgroup %d, physics bone %d, solid %d, surface %s, surfaceprop %s, contents %08x\n", tr.hitbox, tr.hitgroup, tr.physicsbone, tr.m_pEnt->GetSolid(), tr.surface.name, physprops->GetPropName( tr.surface.surfaceProps ), tr.contents );
+ NDebugOverlay::Line( start, tr.endpos, 0, 255, 0, false, 10 );
+ NDebugOverlay::Line( tr.endpos, tr.endpos + tr.plane.normal * 12, 255, 255, 0, false, 10 );
+ }
+}
+
+CON_COMMAND_F( cast_hull, "Tests hull collision detection", FCVAR_CHEAT )
+{
+ CBasePlayer *pPlayer = UTIL_GetCommandClient();
+
+ Vector forward;
+ trace_t tr;
+
+ Vector extents;
+ extents.Init(16,16,16);
+ pPlayer->EyeVectors( &forward );
+ Vector start = pPlayer->EyePosition();
+ UTIL_TraceHull(start, start + forward * MAX_COORD_RANGE, -extents, extents, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
+ if ( tr.DidHit() )
+ {
+ DevMsg(1, "Hit %s\nposition %.2f, %.2f, %.2f\nangles %.2f, %.2f, %.2f\n", tr.m_pEnt->GetClassname(),
+ tr.m_pEnt->GetAbsOrigin().x, tr.m_pEnt->GetAbsOrigin().y, tr.m_pEnt->GetAbsOrigin().z,
+ tr.m_pEnt->GetAbsAngles().x, tr.m_pEnt->GetAbsAngles().y, tr.m_pEnt->GetAbsAngles().z );
+ DevMsg(1, "Hit: hitbox %d, hitgroup %d, physics bone %d, solid %d, surface %s, surfaceprop %s\n", tr.hitbox, tr.hitgroup, tr.physicsbone, tr.m_pEnt->GetSolid(), tr.surface.name, physprops->GetPropName( tr.surface.surfaceProps ) );
+ NDebugOverlay::SweptBox( start, tr.endpos, -extents, extents, vec3_angle, 0, 0, 255, 0, 10 );
+ Vector end = tr.endpos;// - tr.plane.normal * DotProductAbs( tr.plane.normal, extents );
+ NDebugOverlay::Line( end, end + tr.plane.normal * 24, 255, 255, 64, false, 10 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Used to find targets for ent_* commands
+// Without a name, returns the entity under the player's crosshair.
+// With a name it finds entities via name/classname/index
+//-----------------------------------------------------------------------------
+CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent )
+{
+ if ( !pPlayer )
+ return NULL;
+
+ // If no name was given set bits based on the picked
+ if (FStrEq(name,""))
+ {
+ // If we've already found an entity, return NULL.
+ // Makes it easier to write code using this func.
+ if ( ent )
+ return NULL;
+
+ return FindPickerEntity( pPlayer );
+ }
+
+ int index = atoi( name );
+ if ( index )
+ {
+ // If we've already found an entity, return NULL.
+ // Makes it easier to write code using this func.
+ if ( ent )
+ return NULL;
+
+ return CBaseEntity::Instance( index );
+ }
+
+ // Loop through all entities matching, starting from the specified previous
+ while ( (ent = gEntList.NextEnt(ent)) != NULL )
+ {
+ if ( (ent->GetEntityName() != NULL_STRING && ent->NameMatches(name)) ||
+ (ent->m_iClassname != NULL_STRING && ent->ClassMatches(name)) )
+ {
+ return ent;
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called each time a player uses a "cmd" command
+// Input : pPlayer - the player who issued the command
+//-----------------------------------------------------------------------------
+void SetDebugBits( CBasePlayer* pPlayer, const char *name, int bit )
+{
+ if ( !pPlayer )
+ return;
+
+ CBaseEntity *pEntity = NULL;
+ while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL )
+ {
+ if (pEntity->m_debugOverlays & bit)
+ {
+ pEntity->m_debugOverlays &= ~bit;
+ }
+ else
+ {
+ pEntity->m_debugOverlays |= bit;
+
+#ifdef AI_MONITOR_FOR_OSCILLATION
+ if( pEntity->IsNPC() )
+ {
+ pEntity->MyNPCPointer()->m_ScheduleHistory.RemoveAll();
+ }
+#endif//AI_MONITOR_FOR_OSCILLATION
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pKillTargetName -
+//-----------------------------------------------------------------------------
+void KillTargets( const char *pKillTargetName )
+{
+ CBaseEntity *pentKillTarget = NULL;
+
+ DevMsg( 2, "KillTarget: %s\n", pKillTargetName );
+ pentKillTarget = gEntList.FindEntityByName( NULL, pKillTargetName );
+ while ( pentKillTarget )
+ {
+ UTIL_Remove( pentKillTarget );
+
+ DevMsg( 2, "killing %s\n", STRING( pentKillTarget->m_iClassname ) );
+ pentKillTarget = gEntList.FindEntityByName( pentKillTarget, pKillTargetName );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose:
+//------------------------------------------------------------------------------
+void ConsoleKillTarget( CBasePlayer *pPlayer, const char *name )
+{
+ // If no name was given use the picker
+ if (FStrEq(name,""))
+ {
+ CBaseEntity *pEntity = FindPickerEntity( pPlayer );
+ if ( pEntity )
+ {
+ UTIL_Remove( pEntity );
+ Msg( "killing %s\n", pEntity->GetDebugName() );
+ return;
+ }
+ }
+ // Otherwise use name or classname
+ KillTargets( name );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CPointClientCommand : public CPointEntity
+{
+public:
+ DECLARE_CLASS( CPointClientCommand, CPointEntity );
+ DECLARE_DATADESC();
+
+ void InputCommand( inputdata_t& inputdata );
+};
+
+void CPointClientCommand::InputCommand( inputdata_t& inputdata )
+{
+ if ( !inputdata.value.String()[0] )
+ return;
+
+ edict_t *pClient = NULL;
+ if ( gpGlobals->maxClients == 1 )
+ {
+ pClient = engine->PEntityOfEntIndex( 1 );
+ }
+ else
+ {
+ // In multiplayer, send it back to the activator
+ CBasePlayer *player = dynamic_cast< CBasePlayer * >( inputdata.pActivator );
+ if ( player )
+ {
+ pClient = player->edict();
+ }
+
+ if ( IsInCommentaryMode() && !pClient )
+ {
+ // Commentary is stuffing a command in. We'll pretend it came from the first player.
+ pClient = engine->PEntityOfEntIndex( 1 );
+ }
+ }
+
+ if ( !pClient || !pClient->GetUnknown() )
+ return;
+
+ engine->ClientCommand( pClient, "%s\n", inputdata.value.String() );
+}
+
+BEGIN_DATADESC( CPointClientCommand )
+ DEFINE_INPUTFUNC( FIELD_STRING, "Command", InputCommand ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( point_clientcommand, CPointClientCommand );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CPointServerCommand : public CPointEntity
+{
+public:
+ DECLARE_CLASS( CPointServerCommand, CPointEntity );
+ DECLARE_DATADESC();
+ void InputCommand( inputdata_t& inputdata );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : inputdata -
+//-----------------------------------------------------------------------------
+void CPointServerCommand::InputCommand( inputdata_t& inputdata )
+{
+ if ( !inputdata.value.String()[0] )
+ return;
+
+ engine->ServerCommand( UTIL_VarArgs( "%s\n", inputdata.value.String() ) );
+}
+
+BEGIN_DATADESC( CPointServerCommand )
+ DEFINE_INPUTFUNC( FIELD_STRING, "Command", InputCommand ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( point_servercommand, CPointServerCommand );
+
+//------------------------------------------------------------------------------
+// Purpose : Draw a line betwen two points. White if no world collisions, red if collisions
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CC_DrawLine( const CCommand &args )
+{
+ Vector startPos;
+ Vector endPos;
+
+ startPos.x = atof(args[1]);
+ startPos.y = atof(args[2]);
+ startPos.z = atof(args[3]);
+ endPos.x = atof(args[4]);
+ endPos.y = atof(args[5]);
+ endPos.z = atof(args[6]);
+
+ UTIL_AddDebugLine(startPos,endPos,true,true);
+}
+static ConCommand drawline("drawline", CC_DrawLine, "Draws line between two 3D Points.\n\tGreen if no collision\n\tRed is collides with something\n\tArguments: x1 y1 z1 x2 y2 z2", FCVAR_CHEAT);
+
+//------------------------------------------------------------------------------
+// Purpose : Draw a cross at a points.
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void CC_DrawCross( const CCommand &args )
+{
+ Vector vPosition;
+
+ vPosition.x = atof(args[1]);
+ vPosition.y = atof(args[2]);
+ vPosition.z = atof(args[3]);
+
+ // Offset since min and max z in not about center
+ Vector mins = Vector(-5,-5,-5);
+ Vector maxs = Vector(5,5,5);
+
+ Vector start = mins + vPosition;
+ Vector end = maxs + vPosition;
+ UTIL_AddDebugLine(start,end,true,true);
+
+ start.x += (maxs.x - mins.x);
+ end.x -= (maxs.x - mins.x);
+ UTIL_AddDebugLine(start,end,true,true);
+
+ start.y += (maxs.y - mins.y);
+ end.y -= (maxs.y - mins.y);
+ UTIL_AddDebugLine(start,end,true,true);
+
+ start.x -= (maxs.x - mins.x);
+ end.x += (maxs.x - mins.x);
+ UTIL_AddDebugLine(start,end,true,true);
+}
+static ConCommand drawcross("drawcross", CC_DrawCross, "Draws a cross at the given location\n\tArguments: x y z", FCVAR_CHEAT);
+
+
+//------------------------------------------------------------------------------
+// helper function for kill and explode
+//------------------------------------------------------------------------------
+void kill_helper( const CCommand &args, bool bExplode )
+{
+ if ( args.ArgC() > 1 && sv_cheats->GetBool() )
+ {
+ // Find the matching netname
+ for ( int i = 1; i <= gpGlobals->maxClients; i++ )
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_PlayerByIndex(i) );
+ if ( pPlayer )
+ {
+ if ( Q_strstr( pPlayer->GetPlayerName(), args[1] ) )
+ {
+ pPlayer->CommitSuicide( bExplode );
+ }
+ }
+ }
+ }
+ else
+ {
+ CBasePlayer *pPlayer = UTIL_GetCommandClient();
+ if ( pPlayer )
+ {
+ pPlayer->CommitSuicide( bExplode );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( kill, "Kills the player with generic damage" )
+{
+ kill_helper( args, false );
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( explode, "Kills the player with explosive damage" )
+{
+ kill_helper( args, true );
+}
+
+//------------------------------------------------------------------------------
+// helper function for killvector and explodevector
+//------------------------------------------------------------------------------
+void killvector_helper( const CCommand &args, bool bExplode )
+{
+ CBasePlayer *pPlayer = UTIL_GetCommandClient();
+ if ( pPlayer && args.ArgC() == 5 )
+ {
+ // Find the matching netname.
+ for ( int iClient = 1; iClient <= gpGlobals->maxClients; iClient++ )
+ {
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_PlayerByIndex( iClient ) );
+ if ( pPlayer )
+ {
+ if ( Q_strstr( pPlayer->GetPlayerName(), args[1] ) )
+ {
+ // Build world-space force vector.
+ Vector vecForce;
+ vecForce.x = atof( args[2] );
+ vecForce.y = atof( args[3] );
+ vecForce.z = atof( args[4] );
+
+ ClientKill( pPlayer->edict(), vecForce, bExplode );
+ }
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND_F( killvector, "Kills a player applying force. Usage: killvector <player> <x value> <y value> <z value>", FCVAR_CHEAT )
+{
+ killvector_helper( args, false );
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND_F( explodevector, "Kills a player applying an explosive force. Usage: explodevector <player> <x value> <y value> <z value>", FCVAR_CHEAT )
+{
+ killvector_helper( args, false );
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND_F( buddha, "Toggle. Player takes damage but won't die. (Shows red cross when health is zero)", FCVAR_CHEAT )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer )
+ {
+ if (pPlayer->m_debugOverlays & OVERLAY_BUDDHA_MODE)
+ {
+ pPlayer->m_debugOverlays &= ~OVERLAY_BUDDHA_MODE;
+ Msg("Buddha Mode off...\n");
+ }
+ else
+ {
+ pPlayer->m_debugOverlays |= OVERLAY_BUDDHA_MODE;
+ Msg("Buddha Mode on...\n");
+ }
+ }
+}
+
+
+#define TALK_INTERVAL 0.66 // min time between say commands from a client
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( say, "Display player message" )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer )
+ {
+ if (( pPlayer->LastTimePlayerTalked() + TALK_INTERVAL ) < gpGlobals->curtime)
+ {
+ Host_Say( pPlayer->edict(), args, 0 );
+ pPlayer->NotePlayerTalked();
+ }
+ }
+ // This will result in a "console" say. Ignore anything from
+ // an index greater than 0 when we don't have a player pointer,
+ // as would be the case when a client that's connecting generates
+ // text via a script. This can be exploited to flood everyone off.
+ else if ( UTIL_GetCommandClientIndex() == 0 )
+ {
+ Host_Say( NULL, args, 0 );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( say_team, "Display player message to team" )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if (pPlayer)
+ {
+ if (( pPlayer->LastTimePlayerTalked() + TALK_INTERVAL ) < gpGlobals->curtime)
+ {
+ Host_Say( pPlayer->edict(), args, 1 );
+ pPlayer->NotePlayerTalked();
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( give, "Give item to player.\n\tArguments: <item_name>" )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer
+ && (gpGlobals->maxClients == 1 || sv_cheats->GetBool())
+ && args.ArgC() >= 2 )
+ {
+ char item_to_give[ 256 ];
+ Q_strncpy( item_to_give, args[1], sizeof( item_to_give ) );
+ Q_strlower( item_to_give );
+
+ // Dirty hack to avoid suit playing it's pickup sound
+ if ( !Q_stricmp( item_to_give, "item_suit" ) )
+ {
+ pPlayer->EquipSuit( false );
+ return;
+ }
+
+ string_t iszItem = AllocPooledString( item_to_give ); // Make a copy of the classname
+ pPlayer->GiveNamedItem( STRING(iszItem) );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+CON_COMMAND( fov, "Change players FOV" )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer && sv_cheats->GetBool() )
+ {
+ if ( args.ArgC() > 1 )
+ {
+ int nFOV = atoi( args[1] );
+ pPlayer->SetDefaultFOV( nFOV );
+ }
+ else
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs( "\"fov\" is \"%d\"\n", pPlayer->GetFOV() ) );
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void CC_Player_SetModel( const CCommand &args )
+{
+ if ( gpGlobals->deathmatch )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer && args.ArgC() == 2)
+ {
+ static char szName[256];
+ Q_snprintf( szName, sizeof( szName ), "models/%s.mdl", args[1] );
+ pPlayer->SetModel( szName );
+ UTIL_SetSize(pPlayer, VEC_HULL_MIN, VEC_HULL_MAX);
+ }
+}
+static ConCommand setmodel("setmodel", CC_Player_SetModel, "Changes's player's model", FCVAR_CHEAT );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CC_Player_TestDispatchEffect( const CCommand &args )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer)
+ return;
+
+ if ( args.ArgC() < 2 )
+ {
+ Msg(" Usage: test_dispatcheffect <effect name> <distance away> <flags> <magnitude> <scale>\n " );
+ Msg(" defaults are: <distance 1024> <flags 0> <magnitude 0> <scale 0>\n" );
+ return;
+ }
+
+ // Optional distance
+ float flDistance = 1024;
+ if ( args.ArgC() >= 3 )
+ {
+ flDistance = atoi( args[ 2 ] );
+ }
+
+ // Optional flags
+ float flags = 0;
+ if ( args.ArgC() >= 4 )
+ {
+ flags = atoi( args[ 3 ] );
+ }
+
+ // Optional magnitude
+ float magnitude = 0;
+ if ( args.ArgC() >= 5 )
+ {
+ magnitude = atof( args[ 4 ] );
+ }
+
+ // Optional scale
+ float scale = 0;
+ if ( args.ArgC() >= 6 )
+ {
+ scale = atof( args[ 5 ] );
+ }
+
+ Vector vecForward;
+ QAngle vecAngles = pPlayer->EyeAngles();
+ AngleVectors( vecAngles, &vecForward );
+
+ // Trace forward
+ trace_t tr;
+ Vector vecSrc = pPlayer->EyePosition();
+ Vector vecEnd = vecSrc + (vecForward * flDistance);
+ UTIL_TraceLine( vecSrc, vecEnd, MASK_ALL, pPlayer, COLLISION_GROUP_NONE, &tr );
+
+ // Fill out the generic data
+ CEffectData data;
+ // If we hit something, use that data
+ if ( tr.fraction < 1.0 )
+ {
+ data.m_vOrigin = tr.endpos;
+ VectorAngles( tr.plane.normal, data.m_vAngles );
+ data.m_vNormal = tr.plane.normal;
+ }
+ else
+ {
+ data.m_vOrigin = vecEnd;
+ data.m_vAngles = vecAngles;
+ AngleVectors( vecAngles, &data.m_vNormal );
+ }
+ data.m_nEntIndex = pPlayer->entindex();
+ data.m_fFlags = flags;
+ data.m_flMagnitude = magnitude;
+ data.m_flScale = scale;
+ DispatchEffect( (char *)args[1], data );
+}
+
+static ConCommand test_dispatcheffect("test_dispatcheffect", CC_Player_TestDispatchEffect, "Test a clientside dispatch effect.\n\tUsage: test_dispatcheffect <effect name> <distance away> <flags> <magnitude> <scale>\n\tDefaults are: <distance 1024> <flags 0> <magnitude 0> <scale 0>\n", FCVAR_CHEAT);
+
+#ifdef HL2_DLL
+//-----------------------------------------------------------------------------
+// Purpose: Quickly switch to the physics cannon, or back to previous item
+//-----------------------------------------------------------------------------
+void CC_Player_PhysSwap( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+
+ if ( pPlayer )
+ {
+ CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
+
+ if ( pWeapon )
+ {
+ // Tell the client to stop selecting weapons
+ engine->ClientCommand( UTIL_GetCommandClient()->edict(), "cancelselect" );
+
+ const char *strWeaponName = pWeapon->GetName();
+
+ if ( !Q_stricmp( strWeaponName, "weapon_physcannon" ) )
+ {
+ PhysCannonForceDrop( pWeapon, NULL );
+ pPlayer->SelectLastItem();
+ }
+ else
+ {
+ pPlayer->SelectItem( "weapon_physcannon" );
+ }
+ }
+ }
+}
+static ConCommand physswap("phys_swap", CC_Player_PhysSwap, "Automatically swaps the current weapon for the physcannon and back again." );
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Quickly switch to the bug bait, or back to previous item
+//-----------------------------------------------------------------------------
+void CC_Player_BugBaitSwap( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+
+ if ( pPlayer )
+ {
+ CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
+
+ if ( pWeapon )
+ {
+ // Tell the client to stop selecting weapons
+ engine->ClientCommand( UTIL_GetCommandClient()->edict(), "cancelselect" );
+
+ const char *strWeaponName = pWeapon->GetName();
+
+ if ( !Q_stricmp( strWeaponName, "weapon_bugbait" ) )
+ {
+ pPlayer->SelectLastItem();
+ }
+ else
+ {
+ pPlayer->SelectItem( "weapon_bugbait" );
+ }
+ }
+ }
+}
+static ConCommand bugswap("bug_swap", CC_Player_BugBaitSwap, "Automatically swaps the current weapon for the bug bait and back again.", FCVAR_CHEAT );
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void CC_Player_Use( const CCommand &args )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( pPlayer)
+ {
+ pPlayer->SelectItem((char *)args[1]);
+ }
+}
+static ConCommand use("use", CC_Player_Use, "Use a particular weapon\t\nArguments: <weapon_name>");
+
+
+//------------------------------------------------------------------------------
+// A small wrapper around SV_Move that never clips against the supplied entity.
+//------------------------------------------------------------------------------
+static bool TestEntityPosition ( CBasePlayer *pPlayer )
+{
+ trace_t trace;
+ UTIL_TraceEntity( pPlayer, pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(), MASK_PLAYERSOLID, &trace );
+ return (trace.startsolid == 0);
+}
+
+
+//------------------------------------------------------------------------------
+// Searches along the direction ray in steps of "step" to see if
+// the entity position is passible.
+// Used for putting the player in valid space when toggling off noclip mode.
+//------------------------------------------------------------------------------
+static int FindPassableSpace( CBasePlayer *pPlayer, const Vector& direction, float step, Vector& oldorigin )
+{
+ int i;
+ for ( i = 0; i < 100; i++ )
+ {
+ Vector origin = pPlayer->GetAbsOrigin();
+ VectorMA( origin, step, direction, origin );
+ pPlayer->SetAbsOrigin( origin );
+ if ( TestEntityPosition( pPlayer ) )
+ {
+ VectorCopy( pPlayer->GetAbsOrigin(), oldorigin );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+// Noclip
+//------------------------------------------------------------------------------
+void EnableNoClip( CBasePlayer *pPlayer )
+{
+ // Disengage from hierarchy
+ pPlayer->SetParent( NULL );
+ pPlayer->SetMoveType( MOVETYPE_NOCLIP );
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "noclip ON\n");
+ pPlayer->AddEFlags( EFL_NOCLIP_ACTIVE );
+}
+
+void CC_Player_NoClip( void )
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ CPlayerState *pl = pPlayer->PlayerData();
+ Assert( pl );
+
+ if (pPlayer->GetMoveType() != MOVETYPE_NOCLIP)
+ {
+ EnableNoClip( pPlayer );
+ return;
+ }
+
+ pPlayer->RemoveEFlags( EFL_NOCLIP_ACTIVE );
+ pPlayer->SetMoveType( MOVETYPE_WALK );
+
+ Vector oldorigin = pPlayer->GetAbsOrigin();
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "noclip OFF\n");
+ if ( !TestEntityPosition( pPlayer ) )
+ {
+ Vector forward, right, up;
+
+ AngleVectors ( pl->v_angle, &forward, &right, &up);
+
+ // Try to move into the world
+ if ( !FindPassableSpace( pPlayer, forward, 1, oldorigin ) )
+ {
+ if ( !FindPassableSpace( pPlayer, right, 1, oldorigin ) )
+ {
+ if ( !FindPassableSpace( pPlayer, right, -1, oldorigin ) ) // left
+ {
+ if ( !FindPassableSpace( pPlayer, up, 1, oldorigin ) ) // up
+ {
+ if ( !FindPassableSpace( pPlayer, up, -1, oldorigin ) ) // down
+ {
+ if ( !FindPassableSpace( pPlayer, forward, -1, oldorigin ) ) // back
+ {
+ Msg( "Can't find the world\n" );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ pPlayer->SetAbsOrigin( oldorigin );
+ }
+}
+
+static ConCommand noclip("noclip", CC_Player_NoClip, "Toggle. Player becomes non-solid and flies.", FCVAR_CHEAT);
+
+
+//------------------------------------------------------------------------------
+// Sets client to godmode
+//------------------------------------------------------------------------------
+void CC_God_f (void)
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+#ifdef TF_DLL
+ if ( TFGameRules() && ( TFGameRules()->IsPVEModeActive() == false ) )
+ {
+ if ( gpGlobals->deathmatch )
+ return;
+ }
+#else
+ if ( gpGlobals->deathmatch )
+ return;
+#endif
+
+ pPlayer->ToggleFlag( FL_GODMODE );
+ if (!(pPlayer->GetFlags() & FL_GODMODE ) )
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "godmode OFF\n");
+ else
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "godmode ON\n");
+}
+
+static ConCommand god("god", CC_God_f, "Toggle. Player becomes invulnerable.", FCVAR_CHEAT );
+
+
+//------------------------------------------------------------------------------
+// Sets client to godmode
+//------------------------------------------------------------------------------
+CON_COMMAND_F( setpos, "Move player to specified origin (must have sv_cheats).", FCVAR_CHEAT )
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ if ( args.ArgC() < 3 )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setpos x y <z optional>\n");
+ return;
+ }
+
+ Vector oldorigin = pPlayer->GetAbsOrigin();
+
+ Vector newpos;
+ newpos.x = atof( args[1] );
+ newpos.y = atof( args[2] );
+ newpos.z = args.ArgC() == 4 ? atof( args[3] ) : oldorigin.z;
+
+ pPlayer->SetAbsOrigin( newpos );
+
+ if ( !TestEntityPosition( pPlayer ) )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "setpos into world, use noclip to unstick yourself!\n");
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Sets client to godmode
+//------------------------------------------------------------------------------
+void CC_setang_f (const CCommand &args)
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ if ( args.ArgC() < 3 )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setang pitch yaw <roll optional>\n");
+ return;
+ }
+
+ QAngle oldang = pPlayer->GetAbsAngles();
+
+ QAngle newang;
+ newang.x = atof( args[1] );
+ newang.y = atof( args[2] );
+ newang.z = args.ArgC() == 4 ? atof( args[3] ) : oldang.z;
+
+ pPlayer->SnapEyeAngles( newang );
+}
+
+static ConCommand setang("setang", CC_setang_f, "Snap player eyes to specified pitch yaw <roll:optional> (must have sv_cheats).", FCVAR_CHEAT );
+
+static float GetHexFloat( const char *pStr )
+{
+ if ( ( pStr[0] == '0' ) && ( pStr[1] == 'x' ) )
+ {
+ uint32 f = (uint32)V_atoi64( pStr );
+ return *reinterpret_cast< const float * >( &f );
+ }
+
+ return atof( pStr );
+}
+
+//------------------------------------------------------------------------------
+// Move position
+//------------------------------------------------------------------------------
+CON_COMMAND_F( setpos_exact, "Move player to an exact specified origin (must have sv_cheats).", FCVAR_CHEAT )
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ if ( args.ArgC() < 3 )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setpos_exact x y <z optional>\n");
+ return;
+ }
+
+ Vector oldorigin = pPlayer->GetAbsOrigin();
+
+ Vector newpos;
+ newpos.x = GetHexFloat( args[1] );
+ newpos.y = GetHexFloat( args[2] );
+ newpos.z = args.ArgC() == 4 ? GetHexFloat( args[3] ) : oldorigin.z;
+
+ pPlayer->Teleport( &newpos, NULL, NULL );
+
+ if ( !TestEntityPosition( pPlayer ) )
+ {
+ if ( pPlayer->GetMoveType() != MOVETYPE_NOCLIP )
+ {
+ EnableNoClip( pPlayer );
+ return;
+ }
+ }
+}
+
+CON_COMMAND_F( setang_exact, "Snap player eyes and orientation to specified pitch yaw <roll:optional> (must have sv_cheats).", FCVAR_CHEAT )
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ if ( args.ArgC() < 3 )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setang_exact pitch yaw <roll optional>\n");
+ return;
+ }
+
+ QAngle oldang = pPlayer->GetAbsAngles();
+
+ QAngle newang;
+ newang.x = GetHexFloat( args[1] );
+ newang.y = GetHexFloat( args[2] );
+ newang.z = args.ArgC() == 4 ? GetHexFloat( args[3] ) : oldang.z;
+
+ pPlayer->Teleport( NULL, &newang, NULL );
+ pPlayer->SnapEyeAngles( newang );
+
+#ifdef TF_DLL
+ static_cast<CTFPlayer*>( pPlayer )->DoAnimationEvent( PLAYERANIMEVENT_SNAP_YAW );
+#endif
+}
+
+
+//------------------------------------------------------------------------------
+// Sets client to notarget mode.
+//------------------------------------------------------------------------------
+void CC_Notarget_f (void)
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ if ( gpGlobals->deathmatch )
+ return;
+
+ pPlayer->ToggleFlag( FL_NOTARGET );
+ if ( !(pPlayer->GetFlags() & FL_NOTARGET ) )
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "notarget OFF\n");
+ else
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "notarget ON\n");
+}
+
+ConCommand notarget("notarget", CC_Notarget_f, "Toggle. Player becomes hidden to NPCs.", FCVAR_CHEAT);
+
+//------------------------------------------------------------------------------
+// Damage the client the specified amount
+//------------------------------------------------------------------------------
+void CC_HurtMe_f(const CCommand &args)
+{
+ if ( !sv_cheats->GetBool() )
+ return;
+
+ CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
+ if ( !pPlayer )
+ return;
+
+ int iDamage = 10;
+ if ( args.ArgC() >= 2 )
+ {
+ iDamage = atoi( args[ 1 ] );
+ }
+
+ pPlayer->TakeDamage( CTakeDamageInfo( pPlayer, pPlayer, iDamage, DMG_PREVENT_PHYSICS_FORCE ) );
+}
+
+static ConCommand hurtme("hurtme", CC_HurtMe_f, "Hurts the player.\n\tArguments: <health to lose>", FCVAR_CHEAT);
+
+static bool IsInGroundList( CBaseEntity *ent, CBaseEntity *ground )
+{
+ if ( !ground || !ent )
+ return false;
+
+ groundlink_t *root = ( groundlink_t * )ground->GetDataObject( GROUNDLINK );
+ if ( root )
+ {
+ groundlink_t *link = root->nextLink;
+ while ( link != root )
+ {
+ CBaseEntity *other = link->entity;
+ if ( other == ent )
+ return true;
+ link = link->nextLink;
+ }
+ }
+
+ return false;
+
+}
+
+static int DescribeGroundList( CBaseEntity *ent )
+{
+ if ( !ent )
+ return 0;
+
+ int c = 1;
+
+ Msg( "%i : %s (ground %i %s)\n", ent->entindex(), ent->GetClassname(),
+ ent->GetGroundEntity() ? ent->GetGroundEntity()->entindex() : -1,
+ ent->GetGroundEntity() ? ent->GetGroundEntity()->GetClassname() : "NULL" );
+ groundlink_t *root = ( groundlink_t * )ent->GetDataObject( GROUNDLINK );
+ if ( root )
+ {
+ groundlink_t *link = root->nextLink;
+ while ( link != root )
+ {
+ CBaseEntity *other = link->entity;
+ if ( other )
+ {
+ Msg( " %02i: %i %s\n", c++, other->entindex(), other->GetClassname() );
+
+ if ( other->GetGroundEntity() != ent )
+ {
+ Assert( 0 );
+ Msg( " mismatched!!!\n" );
+ }
+ }
+ else
+ {
+ Assert( 0 );
+ Msg( " %02i: NULL link\n", c++ );
+ }
+ link = link->nextLink;
+ }
+ }
+
+ if ( ent->GetGroundEntity() != NULL )
+ {
+ Assert( IsInGroundList( ent, ent->GetGroundEntity() ) );
+ }
+
+ return c - 1;
+}
+
+void CC_GroundList_f(const CCommand &args)
+{
+ if ( !UTIL_IsCommandIssuedByServerAdmin() )
+ return;
+
+ if ( args.ArgC() == 2 )
+ {
+ int idx = atoi( args[1] );
+
+ CBaseEntity *ground = CBaseEntity::Instance( idx );
+ if ( ground )
+ {
+ DescribeGroundList( ground );
+ }
+ }
+ else
+ {
+ CBaseEntity *ent = NULL;
+ int linkCount = 0;
+ while ( (ent = gEntList.NextEnt(ent)) != NULL )
+ {
+ linkCount += DescribeGroundList( ent );
+ }
+
+ extern int groundlinksallocated;
+ Assert( linkCount == groundlinksallocated );
+
+ Msg( "--- %i links\n", groundlinksallocated );
+ }
+}
+
+static ConCommand groundlist("groundlist", CC_GroundList_f, "Display ground entity list <index>" );
+
+//-----------------------------------------------------------------------------
+// Purpose: called each time a player uses a "cmd" command
+// Input : *pEdict - the player who issued the command
+//-----------------------------------------------------------------------------
+void ClientCommand( CBasePlayer *pPlayer, const CCommand &args )
+{
+ const char *pCmd = args[0];
+
+ // Is the client spawned yet?
+ if ( !pPlayer )
+ return;
+
+ MDLCACHE_CRITICAL_SECTION();
+
+ /*
+ const char *pstr;
+
+ if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd))
+ {
+ // Subtype may be specified
+ if ( args.ArgC() == 2 )
+ {
+ pPlayer->SelectItem( pcmd, atoi( args[1] ) );
+ }
+ else
+ {
+ pPlayer->SelectItem(pcmd);
+ }
+ }
+ */
+
+ if ( FStrEq( pCmd, "killtarget" ) )
+ {
+ if ( g_pDeveloper->GetBool() && sv_cheats->GetBool() && UTIL_IsCommandIssuedByServerAdmin() )
+ {
+ ConsoleKillTarget( pPlayer, args[1] );
+ }
+ }
+ else if ( FStrEq( pCmd, "demorestart" ) )
+ {
+ pPlayer->ForceClientDllUpdate();
+ }
+ else if ( FStrEq( pCmd, "fade" ) )
+ {
+ color32 black = {32,63,100,200};
+ UTIL_ScreenFade( pPlayer, black, 3, 3, FFADE_OUT );
+ }
+ else if ( FStrEq( pCmd, "te" ) )
+ {
+ if ( sv_cheats->GetBool() && UTIL_IsCommandIssuedByServerAdmin() )
+ {
+ if ( FStrEq( args[1], "stop" ) )
+ {
+ // Destroy it
+ //
+ CBaseEntity *ent = gEntList.FindEntityByClassname( NULL, "te_tester" );
+ while ( ent )
+ {
+ CBaseEntity *next = gEntList.FindEntityByClassname( ent, "te_tester" );
+ UTIL_Remove( ent );
+ ent = next;
+ }
+ }
+ else
+ {
+ CTempEntTester::Create( pPlayer->WorldSpaceCenter(), pPlayer->EyeAngles(), args[1], args[2] );
+ }
+ }
+ }
+ else
+ {
+ if ( !g_pGameRules->ClientCommand( pPlayer, args ) )
+ {
+ if ( Q_strlen( pCmd ) > 128 )
+ {
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Console command too long.\n" );
+ }
+ else
+ {
+ // tell the user they entered an unknown command
+ ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pCmd ) );
+ }
+ }
+ }
+}
|