Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1605 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. /*
  9. ===== client.cpp ========================================================
  10. client/server game specific stuff
  11. */
  12. #include "cbase.h"
  13. #include "player.h"
  14. #include "client.h"
  15. #include "soundent.h"
  16. #include "gamerules.h"
  17. #include "game.h"
  18. #include "physics.h"
  19. #include "entitylist.h"
  20. #include "shake.h"
  21. #include "globalstate.h"
  22. #include "event_tempentity_tester.h"
  23. #include "ndebugoverlay.h"
  24. #include "engine/IEngineSound.h"
  25. #include <ctype.h>
  26. #include "tier1/strtools.h"
  27. #include "te_effect_dispatch.h"
  28. #include "globals.h"
  29. #include "nav_mesh.h"
  30. #include "team.h"
  31. #include "datacache/imdlcache.h"
  32. #include "basemultiplayerplayer.h"
  33. #include "voice_gamemgr.h"
  34. #ifdef TF_DLL
  35. #include "tf_player.h"
  36. #include "tf_gamerules.h"
  37. #endif
  38. #ifdef HL2_DLL
  39. #include "weapon_physcannon.h"
  40. #endif
  41. // memdbgon must be the last include file in a .cpp file!!!
  42. #include "tier0/memdbgon.h"
  43. extern int giPrecacheGrunt;
  44. // For not just using one big ai net
  45. extern CBaseEntity* FindPickerEntity( CBasePlayer* pPlayer );
  46. extern bool IsInCommentaryMode( void );
  47. ConVar *sv_cheats = NULL;
  48. enum eAllowPointServerCommand {
  49. eAllowNever,
  50. eAllowOfficial,
  51. eAllowAlways
  52. };
  53. #ifdef TF_DLL
  54. // The default value here should match the default of the convar
  55. eAllowPointServerCommand sAllowPointServerCommand = eAllowOfficial;
  56. #else
  57. eAllowPointServerCommand sAllowPointServerCommand = eAllowAlways;
  58. #endif // TF_DLL
  59. void sv_allow_point_servercommand_changed( IConVar *pConVar, const char *pOldString, float flOldValue )
  60. {
  61. ConVarRef var( pConVar );
  62. if ( !var.IsValid() )
  63. {
  64. return;
  65. }
  66. const char *pNewValue = var.GetString();
  67. if ( V_strcasecmp ( pNewValue, "always" ) == 0 )
  68. {
  69. sAllowPointServerCommand = eAllowAlways;
  70. }
  71. #ifdef TF_DLL
  72. else if ( V_strcasecmp ( pNewValue, "official" ) == 0 )
  73. {
  74. sAllowPointServerCommand = eAllowOfficial;
  75. }
  76. #endif // TF_DLL
  77. else
  78. {
  79. sAllowPointServerCommand = eAllowNever;
  80. }
  81. }
  82. ConVar sv_allow_point_servercommand ( "sv_allow_point_servercommand",
  83. #ifdef TF_DLL
  84. // The default value here should match the default of the convar
  85. "official",
  86. #else
  87. // Other games may use this in their official maps, and only TF exposes IsValveMap() currently
  88. "always",
  89. #endif // TF_DLL
  90. FCVAR_NONE,
  91. "Allow use of point_servercommand entities in map. Potentially dangerous for untrusted maps.\n"
  92. " disallow : Always disallow\n"
  93. #ifdef TF_DLL
  94. " official : Allowed for valve maps only\n"
  95. #endif // TF_DLL
  96. " always : Allow for all maps", sv_allow_point_servercommand_changed );
  97. void ClientKill( edict_t *pEdict, const Vector &vecForce, bool bExplode = false )
  98. {
  99. CBasePlayer *pPlayer = static_cast<CBasePlayer*>( GetContainingEntity( pEdict ) );
  100. pPlayer->CommitSuicide( vecForce, bExplode );
  101. }
  102. char * CheckChatText( CBasePlayer *pPlayer, char *text )
  103. {
  104. char *p = text;
  105. // invalid if NULL or empty
  106. if ( !text || !text[0] )
  107. return NULL;
  108. int length = Q_strlen( text );
  109. // remove quotes (leading & trailing) if present
  110. if (*p == '"')
  111. {
  112. p++;
  113. length -=2;
  114. p[length] = 0;
  115. }
  116. // cut off after 127 chars
  117. if ( length > 127 )
  118. text[127] = 0;
  119. GameRules()->CheckChatText( pPlayer, p );
  120. return p;
  121. }
  122. //// HOST_SAY
  123. // String comes in as
  124. // say blah blah blah
  125. // or as
  126. // blah blah blah
  127. //
  128. void Host_Say( edict_t *pEdict, const CCommand &args, bool teamonly )
  129. {
  130. CBasePlayer *client;
  131. int j;
  132. char *p;
  133. char text[256];
  134. char szTemp[256];
  135. const char *cpSay = "say";
  136. const char *cpSayTeam = "say_team";
  137. const char *pcmd = args[0];
  138. bool bSenderDead = false;
  139. // We can get a raw string now, without the "say " prepended
  140. if ( args.ArgC() == 0 )
  141. return;
  142. if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
  143. {
  144. if ( args.ArgC() >= 2 )
  145. {
  146. p = (char *)args.ArgS();
  147. }
  148. else
  149. {
  150. // say with a blank message, nothing to do
  151. return;
  152. }
  153. }
  154. else // Raw text, need to prepend argv[0]
  155. {
  156. if ( args.ArgC() >= 2 )
  157. {
  158. Q_snprintf( szTemp,sizeof(szTemp), "%s %s", ( char * )pcmd, (char *)args.ArgS() );
  159. }
  160. else
  161. {
  162. // Just a one word command, use the first word...sigh
  163. Q_snprintf( szTemp,sizeof(szTemp), "%s", ( char * )pcmd );
  164. }
  165. p = szTemp;
  166. }
  167. CBasePlayer *pPlayer = NULL;
  168. if ( pEdict )
  169. {
  170. pPlayer = ((CBasePlayer *)CBaseEntity::Instance( pEdict ));
  171. Assert( pPlayer );
  172. // make sure the text has valid content
  173. p = CheckChatText( pPlayer, p );
  174. }
  175. if ( !p )
  176. return;
  177. if ( pEdict )
  178. {
  179. if ( !pPlayer->CanSpeak() )
  180. return;
  181. // See if the player wants to modify of check the text
  182. pPlayer->CheckChatText( p, 127 ); // though the buffer szTemp that p points to is 256,
  183. // chat text is capped to 127 in CheckChatText above
  184. Assert( strlen( pPlayer->GetPlayerName() ) > 0 );
  185. bSenderDead = ( pPlayer->m_lifeState != LIFE_ALIVE );
  186. }
  187. else
  188. {
  189. bSenderDead = false;
  190. }
  191. const char *pszFormat = NULL;
  192. const char *pszPrefix = NULL;
  193. const char *pszLocation = NULL;
  194. if ( g_pGameRules )
  195. {
  196. pszFormat = g_pGameRules->GetChatFormat( teamonly, pPlayer );
  197. pszPrefix = g_pGameRules->GetChatPrefix( teamonly, pPlayer );
  198. pszLocation = g_pGameRules->GetChatLocation( teamonly, pPlayer );
  199. }
  200. const char *pszPlayerName = pPlayer ? pPlayer->GetPlayerName():"Console";
  201. if ( pszPrefix && strlen( pszPrefix ) > 0 )
  202. {
  203. if ( pszLocation && strlen( pszLocation ) )
  204. {
  205. Q_snprintf( text, sizeof(text), "%s %s @ %s: ", pszPrefix, pszPlayerName, pszLocation );
  206. }
  207. else
  208. {
  209. Q_snprintf( text, sizeof(text), "%s %s: ", pszPrefix, pszPlayerName );
  210. }
  211. }
  212. else
  213. {
  214. Q_snprintf( text, sizeof(text), "%s: ", pszPlayerName );
  215. }
  216. j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
  217. if ( (int)strlen(p) > j )
  218. p[j] = 0;
  219. Q_strncat( text, p, sizeof( text ), COPY_ALL_CHARACTERS );
  220. Q_strncat( text, "\n", sizeof( text ), COPY_ALL_CHARACTERS );
  221. // loop through all players
  222. // Start with the first player.
  223. // This may return the world in single player if the client types something between levels or during spawn
  224. // so check it, or it will infinite loop
  225. client = NULL;
  226. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  227. {
  228. client = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
  229. if ( !client || !client->edict() )
  230. continue;
  231. if ( client->edict() == pEdict )
  232. continue;
  233. if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
  234. continue;
  235. if ( teamonly && g_pGameRules->PlayerCanHearChat( client, pPlayer ) != GR_TEAMMATE )
  236. continue;
  237. if ( pPlayer && !client->CanHearAndReadChatFrom( pPlayer ) )
  238. continue;
  239. if ( pPlayer && GetVoiceGameMgr() && GetVoiceGameMgr()->IsPlayerIgnoringPlayer( pPlayer->entindex(), i ) )
  240. continue;
  241. CSingleUserRecipientFilter user( client );
  242. user.MakeReliable();
  243. if ( pszFormat )
  244. {
  245. UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
  246. }
  247. else
  248. {
  249. UTIL_SayTextFilter( user, text, pPlayer, true );
  250. }
  251. }
  252. if ( pPlayer )
  253. {
  254. // print to the sending client
  255. CSingleUserRecipientFilter user( pPlayer );
  256. user.MakeReliable();
  257. if ( pszFormat )
  258. {
  259. UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
  260. }
  261. else
  262. {
  263. UTIL_SayTextFilter( user, text, pPlayer, true );
  264. }
  265. }
  266. // echo to server console
  267. // Adrian: Only do this if we're running a dedicated server since we already print to console on the client.
  268. if ( engine->IsDedicatedServer() )
  269. Msg( "%s", text );
  270. Assert( p );
  271. int userid = 0;
  272. const char *networkID = "Console";
  273. const char *playerName = "Console";
  274. const char *playerTeam = "Console";
  275. if ( pPlayer )
  276. {
  277. userid = pPlayer->GetUserID();
  278. networkID = pPlayer->GetNetworkIDString();
  279. playerName = pPlayer->GetPlayerName();
  280. CTeam *team = pPlayer->GetTeam();
  281. if ( team )
  282. {
  283. playerTeam = team->GetName();
  284. }
  285. }
  286. if ( teamonly )
  287. UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say_team \"%s\"\n", playerName, userid, networkID, playerTeam, p );
  288. else
  289. UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say \"%s\"\n", playerName, userid, networkID, playerTeam, p );
  290. IGameEvent * event = gameeventmanager->CreateEvent( "player_say", true );
  291. if ( event )
  292. {
  293. event->SetInt("userid", userid );
  294. event->SetString("text", p );
  295. event->SetInt("priority", 1 ); // HLTV event priority, not transmitted
  296. gameeventmanager->FireEvent( event, true );
  297. }
  298. }
  299. void ClientPrecache( void )
  300. {
  301. // Precache cable textures.
  302. CBaseEntity::PrecacheModel( "cable/cable.vmt" );
  303. CBaseEntity::PrecacheModel( "cable/cable_lit.vmt" );
  304. CBaseEntity::PrecacheModel( "cable/chain.vmt" );
  305. CBaseEntity::PrecacheModel( "cable/rope.vmt" );
  306. CBaseEntity::PrecacheModel( "sprites/blueglow1.vmt" );
  307. CBaseEntity::PrecacheModel( "sprites/purpleglow1.vmt" );
  308. CBaseEntity::PrecacheModel( "sprites/purplelaser1.vmt" );
  309. #ifndef HL2MP
  310. CBaseEntity::PrecacheScriptSound( "Hud.Hint" );
  311. #endif // HL2MP
  312. CBaseEntity::PrecacheScriptSound( "Player.FallDamage" );
  313. CBaseEntity::PrecacheScriptSound( "Player.Swim" );
  314. // General HUD sounds
  315. CBaseEntity::PrecacheScriptSound( "Player.PickupWeapon" );
  316. CBaseEntity::PrecacheScriptSound( "Player.DenyWeaponSelection" );
  317. CBaseEntity::PrecacheScriptSound( "Player.WeaponSelected" );
  318. CBaseEntity::PrecacheScriptSound( "Player.WeaponSelectionClose" );
  319. CBaseEntity::PrecacheScriptSound( "Player.WeaponSelectionMoveSlot" );
  320. // General legacy temp ents sounds
  321. CBaseEntity::PrecacheScriptSound( "Bounce.Glass" );
  322. CBaseEntity::PrecacheScriptSound( "Bounce.Metal" );
  323. CBaseEntity::PrecacheScriptSound( "Bounce.Flesh" );
  324. CBaseEntity::PrecacheScriptSound( "Bounce.Wood" );
  325. CBaseEntity::PrecacheScriptSound( "Bounce.Shrapnel" );
  326. CBaseEntity::PrecacheScriptSound( "Bounce.ShotgunShell" );
  327. CBaseEntity::PrecacheScriptSound( "Bounce.Shell" );
  328. CBaseEntity::PrecacheScriptSound( "Bounce.Concrete" );
  329. ClientGamePrecache();
  330. }
  331. CON_COMMAND_F( cast_ray, "Tests collision detection", FCVAR_CHEAT )
  332. {
  333. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  334. Vector forward;
  335. trace_t tr;
  336. pPlayer->EyeVectors( &forward );
  337. Vector start = pPlayer->EyePosition();
  338. UTIL_TraceLine(start, start + forward * MAX_COORD_RANGE, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  339. if ( tr.DidHit() )
  340. {
  341. DevMsg(1, "Hit %s\nposition %.2f, %.2f, %.2f\nangles %.2f, %.2f, %.2f\n", tr.m_pEnt->GetClassname(),
  342. tr.m_pEnt->GetAbsOrigin().x, tr.m_pEnt->GetAbsOrigin().y, tr.m_pEnt->GetAbsOrigin().z,
  343. tr.m_pEnt->GetAbsAngles().x, tr.m_pEnt->GetAbsAngles().y, tr.m_pEnt->GetAbsAngles().z );
  344. 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 );
  345. NDebugOverlay::Line( start, tr.endpos, 0, 255, 0, false, 10 );
  346. NDebugOverlay::Line( tr.endpos, tr.endpos + tr.plane.normal * 12, 255, 255, 0, false, 10 );
  347. }
  348. }
  349. CON_COMMAND_F( cast_hull, "Tests hull collision detection", FCVAR_CHEAT )
  350. {
  351. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  352. Vector forward;
  353. trace_t tr;
  354. Vector extents;
  355. extents.Init(16,16,16);
  356. pPlayer->EyeVectors( &forward );
  357. Vector start = pPlayer->EyePosition();
  358. UTIL_TraceHull(start, start + forward * MAX_COORD_RANGE, -extents, extents, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &tr );
  359. if ( tr.DidHit() )
  360. {
  361. DevMsg(1, "Hit %s\nposition %.2f, %.2f, %.2f\nangles %.2f, %.2f, %.2f\n", tr.m_pEnt->GetClassname(),
  362. tr.m_pEnt->GetAbsOrigin().x, tr.m_pEnt->GetAbsOrigin().y, tr.m_pEnt->GetAbsOrigin().z,
  363. tr.m_pEnt->GetAbsAngles().x, tr.m_pEnt->GetAbsAngles().y, tr.m_pEnt->GetAbsAngles().z );
  364. 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 ) );
  365. NDebugOverlay::SweptBox( start, tr.endpos, -extents, extents, vec3_angle, 0, 0, 255, 0, 10 );
  366. Vector end = tr.endpos;// - tr.plane.normal * DotProductAbs( tr.plane.normal, extents );
  367. NDebugOverlay::Line( end, end + tr.plane.normal * 24, 255, 255, 64, false, 10 );
  368. }
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose: Used to find targets for ent_* commands
  372. // Without a name, returns the entity under the player's crosshair.
  373. // With a name it finds entities via name/classname/index
  374. //-----------------------------------------------------------------------------
  375. CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent )
  376. {
  377. if ( !pPlayer )
  378. return NULL;
  379. // If no name was given set bits based on the picked
  380. if (FStrEq(name,""))
  381. {
  382. // If we've already found an entity, return NULL.
  383. // Makes it easier to write code using this func.
  384. if ( ent )
  385. return NULL;
  386. return FindPickerEntity( pPlayer );
  387. }
  388. int index = atoi( name );
  389. if ( index )
  390. {
  391. // If we've already found an entity, return NULL.
  392. // Makes it easier to write code using this func.
  393. if ( ent )
  394. return NULL;
  395. return CBaseEntity::Instance( index );
  396. }
  397. // Loop through all entities matching, starting from the specified previous
  398. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  399. {
  400. if ( (ent->GetEntityName() != NULL_STRING && ent->NameMatches(name)) ||
  401. (ent->m_iClassname != NULL_STRING && ent->ClassMatches(name)) )
  402. {
  403. return ent;
  404. }
  405. }
  406. return NULL;
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose: called each time a player uses a "cmd" command
  410. // Input : pPlayer - the player who issued the command
  411. //-----------------------------------------------------------------------------
  412. void SetDebugBits( CBasePlayer* pPlayer, const char *name, int bit )
  413. {
  414. if ( !pPlayer )
  415. return;
  416. CBaseEntity *pEntity = NULL;
  417. while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL )
  418. {
  419. if (pEntity->m_debugOverlays & bit)
  420. {
  421. pEntity->m_debugOverlays &= ~bit;
  422. }
  423. else
  424. {
  425. pEntity->m_debugOverlays |= bit;
  426. #ifdef AI_MONITOR_FOR_OSCILLATION
  427. if( pEntity->IsNPC() )
  428. {
  429. pEntity->MyNPCPointer()->m_ScheduleHistory.RemoveAll();
  430. }
  431. #endif//AI_MONITOR_FOR_OSCILLATION
  432. }
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose:
  437. // Input : pKillTargetName -
  438. //-----------------------------------------------------------------------------
  439. void KillTargets( const char *pKillTargetName )
  440. {
  441. CBaseEntity *pentKillTarget = NULL;
  442. DevMsg( 2, "KillTarget: %s\n", pKillTargetName );
  443. pentKillTarget = gEntList.FindEntityByName( NULL, pKillTargetName );
  444. while ( pentKillTarget )
  445. {
  446. UTIL_Remove( pentKillTarget );
  447. DevMsg( 2, "killing %s\n", STRING( pentKillTarget->m_iClassname ) );
  448. pentKillTarget = gEntList.FindEntityByName( pentKillTarget, pKillTargetName );
  449. }
  450. }
  451. //------------------------------------------------------------------------------
  452. // Purpose:
  453. //------------------------------------------------------------------------------
  454. void ConsoleKillTarget( CBasePlayer *pPlayer, const char *name )
  455. {
  456. // If no name was given use the picker
  457. if (FStrEq(name,""))
  458. {
  459. CBaseEntity *pEntity = FindPickerEntity( pPlayer );
  460. if ( pEntity )
  461. {
  462. UTIL_Remove( pEntity );
  463. Msg( "killing %s\n", pEntity->GetDebugName() );
  464. return;
  465. }
  466. }
  467. // Otherwise use name or classname
  468. KillTargets( name );
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose:
  472. //-----------------------------------------------------------------------------
  473. class CPointClientCommand : public CPointEntity
  474. {
  475. public:
  476. DECLARE_CLASS( CPointClientCommand, CPointEntity );
  477. DECLARE_DATADESC();
  478. void InputCommand( inputdata_t& inputdata );
  479. };
  480. void CPointClientCommand::InputCommand( inputdata_t& inputdata )
  481. {
  482. if ( !inputdata.value.String()[0] )
  483. return;
  484. edict_t *pClient = NULL;
  485. if ( gpGlobals->maxClients == 1 )
  486. {
  487. pClient = engine->PEntityOfEntIndex( 1 );
  488. }
  489. else
  490. {
  491. // In multiplayer, send it back to the activator
  492. CBasePlayer *player = dynamic_cast< CBasePlayer * >( inputdata.pActivator );
  493. if ( player )
  494. {
  495. pClient = player->edict();
  496. }
  497. if ( IsInCommentaryMode() && !pClient )
  498. {
  499. // Commentary is stuffing a command in. We'll pretend it came from the first player.
  500. pClient = engine->PEntityOfEntIndex( 1 );
  501. }
  502. }
  503. if ( !pClient || !pClient->GetUnknown() )
  504. return;
  505. engine->ClientCommand( pClient, "%s\n", inputdata.value.String() );
  506. }
  507. BEGIN_DATADESC( CPointClientCommand )
  508. DEFINE_INPUTFUNC( FIELD_STRING, "Command", InputCommand ),
  509. END_DATADESC()
  510. LINK_ENTITY_TO_CLASS( point_clientcommand, CPointClientCommand );
  511. //-----------------------------------------------------------------------------
  512. // Purpose:
  513. //-----------------------------------------------------------------------------
  514. class CPointServerCommand : public CPointEntity
  515. {
  516. public:
  517. DECLARE_CLASS( CPointServerCommand, CPointEntity );
  518. DECLARE_DATADESC();
  519. void InputCommand( inputdata_t& inputdata );
  520. };
  521. //-----------------------------------------------------------------------------
  522. // Purpose:
  523. // Input : inputdata -
  524. //-----------------------------------------------------------------------------
  525. void CPointServerCommand::InputCommand( inputdata_t& inputdata )
  526. {
  527. if ( !inputdata.value.String()[0] )
  528. return;
  529. bool bAllowed = ( sAllowPointServerCommand == eAllowAlways );
  530. #ifdef TF_DLL
  531. if ( sAllowPointServerCommand == eAllowOfficial )
  532. {
  533. bAllowed = TFGameRules() && TFGameRules()->IsValveMap();
  534. }
  535. #endif // TF_DLL
  536. if ( bAllowed )
  537. {
  538. engine->ServerCommand( UTIL_VarArgs( "%s\n", inputdata.value.String() ) );
  539. }
  540. else
  541. {
  542. Warning( "point_servercommand usage blocked by sv_allow_point_servercommand setting\n" );
  543. }
  544. }
  545. BEGIN_DATADESC( CPointServerCommand )
  546. DEFINE_INPUTFUNC( FIELD_STRING, "Command", InputCommand ),
  547. END_DATADESC()
  548. LINK_ENTITY_TO_CLASS( point_servercommand, CPointServerCommand );
  549. //------------------------------------------------------------------------------
  550. // Purpose : Draw a line betwen two points. White if no world collisions, red if collisions
  551. // Input :
  552. // Output :
  553. //------------------------------------------------------------------------------
  554. void CC_DrawLine( const CCommand &args )
  555. {
  556. Vector startPos;
  557. Vector endPos;
  558. startPos.x = clamp( atof(args[1]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  559. startPos.y = clamp( atof(args[2]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  560. startPos.z = clamp( atof(args[3]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  561. endPos.x = clamp( atof(args[4]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  562. endPos.y = clamp( atof(args[5]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  563. endPos.z = clamp( atof(args[6]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  564. UTIL_AddDebugLine(startPos,endPos,true,true);
  565. }
  566. 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);
  567. //------------------------------------------------------------------------------
  568. // Purpose : Draw a cross at a points.
  569. // Input :
  570. // Output :
  571. //------------------------------------------------------------------------------
  572. void CC_DrawCross( const CCommand &args )
  573. {
  574. Vector vPosition;
  575. vPosition.x = clamp( atof(args[1]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  576. vPosition.y = clamp( atof(args[2]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  577. vPosition.z = clamp( atof(args[3]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  578. // Offset since min and max z in not about center
  579. Vector mins = Vector(-5,-5,-5);
  580. Vector maxs = Vector(5,5,5);
  581. Vector start = mins + vPosition;
  582. Vector end = maxs + vPosition;
  583. UTIL_AddDebugLine(start,end,true,true);
  584. start.x += (maxs.x - mins.x);
  585. end.x -= (maxs.x - mins.x);
  586. UTIL_AddDebugLine(start,end,true,true);
  587. start.y += (maxs.y - mins.y);
  588. end.y -= (maxs.y - mins.y);
  589. UTIL_AddDebugLine(start,end,true,true);
  590. start.x -= (maxs.x - mins.x);
  591. end.x += (maxs.x - mins.x);
  592. UTIL_AddDebugLine(start,end,true,true);
  593. }
  594. static ConCommand drawcross("drawcross", CC_DrawCross, "Draws a cross at the given location\n\tArguments: x y z", FCVAR_CHEAT);
  595. //------------------------------------------------------------------------------
  596. // helper function for kill and explode
  597. //------------------------------------------------------------------------------
  598. void kill_helper( const CCommand &args, bool bExplode )
  599. {
  600. if ( args.ArgC() > 1 && sv_cheats->GetBool() )
  601. {
  602. // Find the matching netname
  603. for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  604. {
  605. CBasePlayer *pPlayer = ToBasePlayer( UTIL_PlayerByIndex(i) );
  606. if ( pPlayer )
  607. {
  608. if ( Q_strstr( pPlayer->GetPlayerName(), args[1] ) )
  609. {
  610. pPlayer->CommitSuicide( bExplode );
  611. }
  612. }
  613. }
  614. }
  615. else
  616. {
  617. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  618. if ( pPlayer )
  619. {
  620. pPlayer->CommitSuicide( bExplode );
  621. }
  622. }
  623. }
  624. //------------------------------------------------------------------------------
  625. //------------------------------------------------------------------------------
  626. CON_COMMAND( kill, "Kills the player with generic damage" )
  627. {
  628. kill_helper( args, false );
  629. }
  630. //------------------------------------------------------------------------------
  631. //------------------------------------------------------------------------------
  632. CON_COMMAND( explode, "Kills the player with explosive damage" )
  633. {
  634. kill_helper( args, true );
  635. }
  636. //------------------------------------------------------------------------------
  637. // helper function for killvector and explodevector
  638. //------------------------------------------------------------------------------
  639. void killvector_helper( const CCommand &args, bool bExplode )
  640. {
  641. CBasePlayer *pPlayer = UTIL_GetCommandClient();
  642. if ( pPlayer && args.ArgC() == 5 )
  643. {
  644. // Find the matching netname.
  645. for ( int iClient = 1; iClient <= gpGlobals->maxClients; iClient++ )
  646. {
  647. CBasePlayer *pPlayer = ToBasePlayer( UTIL_PlayerByIndex( iClient ) );
  648. if ( pPlayer )
  649. {
  650. if ( Q_strstr( pPlayer->GetPlayerName(), args[1] ) )
  651. {
  652. // Build world-space force vector.
  653. Vector vecForce;
  654. vecForce.x = atof( args[2] );
  655. vecForce.y = atof( args[3] );
  656. vecForce.z = atof( args[4] );
  657. ClientKill( pPlayer->edict(), vecForce, bExplode );
  658. }
  659. }
  660. }
  661. }
  662. }
  663. //------------------------------------------------------------------------------
  664. //------------------------------------------------------------------------------
  665. CON_COMMAND_F( killvector, "Kills a player applying force. Usage: killvector <player> <x value> <y value> <z value>", FCVAR_CHEAT )
  666. {
  667. killvector_helper( args, false );
  668. }
  669. //------------------------------------------------------------------------------
  670. //------------------------------------------------------------------------------
  671. CON_COMMAND_F( explodevector, "Kills a player applying an explosive force. Usage: explodevector <player> <x value> <y value> <z value>", FCVAR_CHEAT )
  672. {
  673. killvector_helper( args, false );
  674. }
  675. //------------------------------------------------------------------------------
  676. //------------------------------------------------------------------------------
  677. CON_COMMAND_F( buddha, "Toggle. Player takes damage but won't die. (Shows red cross when health is zero)", FCVAR_CHEAT )
  678. {
  679. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  680. if ( pPlayer )
  681. {
  682. if (pPlayer->m_debugOverlays & OVERLAY_BUDDHA_MODE)
  683. {
  684. pPlayer->m_debugOverlays &= ~OVERLAY_BUDDHA_MODE;
  685. Msg("Buddha Mode off...\n");
  686. }
  687. else
  688. {
  689. pPlayer->m_debugOverlays |= OVERLAY_BUDDHA_MODE;
  690. Msg("Buddha Mode on...\n");
  691. }
  692. }
  693. }
  694. #define TALK_INTERVAL 0.66 // min time between say commands from a client
  695. //------------------------------------------------------------------------------
  696. //------------------------------------------------------------------------------
  697. CON_COMMAND( say, "Display player message" )
  698. {
  699. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  700. if ( pPlayer )
  701. {
  702. if (( pPlayer->LastTimePlayerTalked() + TALK_INTERVAL ) < gpGlobals->curtime)
  703. {
  704. Host_Say( pPlayer->edict(), args, 0 );
  705. pPlayer->NotePlayerTalked();
  706. }
  707. }
  708. // This will result in a "console" say. Ignore anything from
  709. // an index greater than 0 when we don't have a player pointer,
  710. // as would be the case when a client that's connecting generates
  711. // text via a script. This can be exploited to flood everyone off.
  712. else if ( UTIL_GetCommandClientIndex() == 0 )
  713. {
  714. Host_Say( NULL, args, 0 );
  715. }
  716. }
  717. //------------------------------------------------------------------------------
  718. //------------------------------------------------------------------------------
  719. CON_COMMAND( say_team, "Display player message to team" )
  720. {
  721. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  722. if (pPlayer)
  723. {
  724. if (( pPlayer->LastTimePlayerTalked() + TALK_INTERVAL ) < gpGlobals->curtime)
  725. {
  726. Host_Say( pPlayer->edict(), args, 1 );
  727. pPlayer->NotePlayerTalked();
  728. }
  729. }
  730. }
  731. //------------------------------------------------------------------------------
  732. //------------------------------------------------------------------------------
  733. CON_COMMAND( give, "Give item to player.\n\tArguments: <item_name>" )
  734. {
  735. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  736. if ( pPlayer
  737. && (gpGlobals->maxClients == 1 || sv_cheats->GetBool())
  738. && args.ArgC() >= 2 )
  739. {
  740. char item_to_give[ 256 ];
  741. Q_strncpy( item_to_give, args[1], sizeof( item_to_give ) );
  742. Q_strlower( item_to_give );
  743. // Don't allow regular users to create point_servercommand entities for the same reason as blocking ent_fire
  744. if ( !Q_stricmp( item_to_give, "point_servercommand" ) )
  745. {
  746. if ( engine->IsDedicatedServer() )
  747. {
  748. // We allow people with disabled autokick to do it, because they already have rcon.
  749. if ( pPlayer->IsAutoKickDisabled() == false )
  750. return;
  751. }
  752. else if ( gpGlobals->maxClients > 1 )
  753. {
  754. // On listen servers with more than 1 player, only allow the host to create point_servercommand.
  755. CBasePlayer *pHostPlayer = UTIL_GetListenServerHost();
  756. if ( pPlayer != pHostPlayer )
  757. return;
  758. }
  759. }
  760. // Dirty hack to avoid suit playing it's pickup sound
  761. if ( !Q_stricmp( item_to_give, "item_suit" ) )
  762. {
  763. pPlayer->EquipSuit( false );
  764. return;
  765. }
  766. string_t iszItem = AllocPooledString( item_to_give ); // Make a copy of the classname
  767. pPlayer->GiveNamedItem( STRING(iszItem) );
  768. }
  769. }
  770. //------------------------------------------------------------------------------
  771. //------------------------------------------------------------------------------
  772. CON_COMMAND( fov, "Change players FOV" )
  773. {
  774. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  775. if ( pPlayer && sv_cheats->GetBool() )
  776. {
  777. if ( args.ArgC() > 1 )
  778. {
  779. int nFOV = atoi( args[1] );
  780. pPlayer->SetDefaultFOV( nFOV );
  781. }
  782. else
  783. {
  784. ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs( "\"fov\" is \"%d\"\n", pPlayer->GetFOV() ) );
  785. }
  786. }
  787. }
  788. //------------------------------------------------------------------------------
  789. //------------------------------------------------------------------------------
  790. void CC_Player_SetModel( const CCommand &args )
  791. {
  792. if ( gpGlobals->deathmatch )
  793. return;
  794. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  795. if ( pPlayer && args.ArgC() == 2)
  796. {
  797. static char szName[256];
  798. Q_snprintf( szName, sizeof( szName ), "models/%s.mdl", args[1] );
  799. pPlayer->SetModel( szName );
  800. UTIL_SetSize(pPlayer, VEC_HULL_MIN, VEC_HULL_MAX);
  801. }
  802. }
  803. static ConCommand setmodel("setmodel", CC_Player_SetModel, "Changes's player's model", FCVAR_CHEAT );
  804. //-----------------------------------------------------------------------------
  805. // Purpose:
  806. //-----------------------------------------------------------------------------
  807. void CC_Player_TestDispatchEffect( const CCommand &args )
  808. {
  809. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  810. if ( !pPlayer)
  811. return;
  812. if ( args.ArgC() < 2 )
  813. {
  814. Msg(" Usage: test_dispatcheffect <effect name> <distance away> <flags> <magnitude> <scale>\n " );
  815. Msg(" defaults are: <distance 1024> <flags 0> <magnitude 0> <scale 0>\n" );
  816. return;
  817. }
  818. // Optional distance
  819. float flDistance = 1024;
  820. if ( args.ArgC() >= 3 )
  821. {
  822. flDistance = atoi( args[ 2 ] );
  823. }
  824. // Optional flags
  825. float flags = 0;
  826. if ( args.ArgC() >= 4 )
  827. {
  828. flags = atoi( args[ 3 ] );
  829. }
  830. // Optional magnitude
  831. float magnitude = 0;
  832. if ( args.ArgC() >= 5 )
  833. {
  834. magnitude = atof( args[ 4 ] );
  835. }
  836. // Optional scale
  837. float scale = 0;
  838. if ( args.ArgC() >= 6 )
  839. {
  840. scale = atof( args[ 5 ] );
  841. }
  842. Vector vecForward;
  843. QAngle vecAngles = pPlayer->EyeAngles();
  844. AngleVectors( vecAngles, &vecForward );
  845. // Trace forward
  846. trace_t tr;
  847. Vector vecSrc = pPlayer->EyePosition();
  848. Vector vecEnd = vecSrc + (vecForward * flDistance);
  849. UTIL_TraceLine( vecSrc, vecEnd, MASK_ALL, pPlayer, COLLISION_GROUP_NONE, &tr );
  850. // Fill out the generic data
  851. CEffectData data;
  852. // If we hit something, use that data
  853. if ( tr.fraction < 1.0 )
  854. {
  855. data.m_vOrigin = tr.endpos;
  856. VectorAngles( tr.plane.normal, data.m_vAngles );
  857. data.m_vNormal = tr.plane.normal;
  858. }
  859. else
  860. {
  861. data.m_vOrigin = vecEnd;
  862. data.m_vAngles = vecAngles;
  863. AngleVectors( vecAngles, &data.m_vNormal );
  864. }
  865. data.m_nEntIndex = pPlayer->entindex();
  866. data.m_fFlags = flags;
  867. data.m_flMagnitude = magnitude;
  868. data.m_flScale = scale;
  869. DispatchEffect( (char *)args[1], data );
  870. }
  871. 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);
  872. #ifdef HL2_DLL
  873. //-----------------------------------------------------------------------------
  874. // Purpose: Quickly switch to the physics cannon, or back to previous item
  875. //-----------------------------------------------------------------------------
  876. void CC_Player_PhysSwap( void )
  877. {
  878. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  879. if ( pPlayer )
  880. {
  881. CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
  882. if ( pWeapon )
  883. {
  884. // Tell the client to stop selecting weapons
  885. engine->ClientCommand( UTIL_GetCommandClient()->edict(), "cancelselect" );
  886. const char *strWeaponName = pWeapon->GetName();
  887. if ( !Q_stricmp( strWeaponName, "weapon_physcannon" ) )
  888. {
  889. PhysCannonForceDrop( pWeapon, NULL );
  890. pPlayer->SelectLastItem();
  891. }
  892. else
  893. {
  894. pPlayer->SelectItem( "weapon_physcannon" );
  895. }
  896. }
  897. }
  898. }
  899. static ConCommand physswap("phys_swap", CC_Player_PhysSwap, "Automatically swaps the current weapon for the physcannon and back again." );
  900. #endif
  901. //-----------------------------------------------------------------------------
  902. // Purpose: Quickly switch to the bug bait, or back to previous item
  903. //-----------------------------------------------------------------------------
  904. void CC_Player_BugBaitSwap( void )
  905. {
  906. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  907. if ( pPlayer )
  908. {
  909. CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
  910. if ( pWeapon )
  911. {
  912. // Tell the client to stop selecting weapons
  913. engine->ClientCommand( UTIL_GetCommandClient()->edict(), "cancelselect" );
  914. const char *strWeaponName = pWeapon->GetName();
  915. if ( !Q_stricmp( strWeaponName, "weapon_bugbait" ) )
  916. {
  917. pPlayer->SelectLastItem();
  918. }
  919. else
  920. {
  921. pPlayer->SelectItem( "weapon_bugbait" );
  922. }
  923. }
  924. }
  925. }
  926. static ConCommand bugswap("bug_swap", CC_Player_BugBaitSwap, "Automatically swaps the current weapon for the bug bait and back again.", FCVAR_CHEAT );
  927. //------------------------------------------------------------------------------
  928. //------------------------------------------------------------------------------
  929. void CC_Player_Use( const CCommand &args )
  930. {
  931. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  932. if ( pPlayer)
  933. {
  934. pPlayer->SelectItem((char *)args[1]);
  935. }
  936. }
  937. static ConCommand use("use", CC_Player_Use, "Use a particular weapon\t\nArguments: <weapon_name>");
  938. //------------------------------------------------------------------------------
  939. // A small wrapper around SV_Move that never clips against the supplied entity.
  940. //------------------------------------------------------------------------------
  941. static bool TestEntityPosition ( CBasePlayer *pPlayer )
  942. {
  943. trace_t trace;
  944. UTIL_TraceEntity( pPlayer, pPlayer->GetAbsOrigin(), pPlayer->GetAbsOrigin(), MASK_PLAYERSOLID, &trace );
  945. return (trace.startsolid == 0);
  946. }
  947. //------------------------------------------------------------------------------
  948. // Searches along the direction ray in steps of "step" to see if
  949. // the entity position is passible.
  950. // Used for putting the player in valid space when toggling off noclip mode.
  951. //------------------------------------------------------------------------------
  952. static int FindPassableSpace( CBasePlayer *pPlayer, const Vector& direction, float step, Vector& oldorigin )
  953. {
  954. int i;
  955. for ( i = 0; i < 100; i++ )
  956. {
  957. Vector origin = pPlayer->GetAbsOrigin();
  958. VectorMA( origin, step, direction, origin );
  959. pPlayer->SetAbsOrigin( origin );
  960. if ( TestEntityPosition( pPlayer ) )
  961. {
  962. VectorCopy( pPlayer->GetAbsOrigin(), oldorigin );
  963. return 1;
  964. }
  965. }
  966. return 0;
  967. }
  968. //------------------------------------------------------------------------------
  969. // Noclip
  970. //------------------------------------------------------------------------------
  971. void EnableNoClip( CBasePlayer *pPlayer )
  972. {
  973. // Disengage from hierarchy
  974. pPlayer->SetParent( NULL );
  975. pPlayer->SetMoveType( MOVETYPE_NOCLIP );
  976. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "noclip ON\n");
  977. pPlayer->AddEFlags( EFL_NOCLIP_ACTIVE );
  978. }
  979. void CC_Player_NoClip( void )
  980. {
  981. if ( !sv_cheats->GetBool() )
  982. return;
  983. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  984. if ( !pPlayer )
  985. return;
  986. CPlayerState *pl = pPlayer->PlayerData();
  987. Assert( pl );
  988. if (pPlayer->GetMoveType() != MOVETYPE_NOCLIP)
  989. {
  990. EnableNoClip( pPlayer );
  991. return;
  992. }
  993. pPlayer->RemoveEFlags( EFL_NOCLIP_ACTIVE );
  994. pPlayer->SetMoveType( MOVETYPE_WALK );
  995. Vector oldorigin = pPlayer->GetAbsOrigin();
  996. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "noclip OFF\n");
  997. if ( !TestEntityPosition( pPlayer ) )
  998. {
  999. Vector forward, right, up;
  1000. AngleVectors ( pl->v_angle, &forward, &right, &up);
  1001. // Try to move into the world
  1002. if ( !FindPassableSpace( pPlayer, forward, 1, oldorigin ) )
  1003. {
  1004. if ( !FindPassableSpace( pPlayer, right, 1, oldorigin ) )
  1005. {
  1006. if ( !FindPassableSpace( pPlayer, right, -1, oldorigin ) ) // left
  1007. {
  1008. if ( !FindPassableSpace( pPlayer, up, 1, oldorigin ) ) // up
  1009. {
  1010. if ( !FindPassableSpace( pPlayer, up, -1, oldorigin ) ) // down
  1011. {
  1012. if ( !FindPassableSpace( pPlayer, forward, -1, oldorigin ) ) // back
  1013. {
  1014. Msg( "Can't find the world\n" );
  1015. }
  1016. }
  1017. }
  1018. }
  1019. }
  1020. }
  1021. pPlayer->SetAbsOrigin( oldorigin );
  1022. }
  1023. }
  1024. static ConCommand noclip("noclip", CC_Player_NoClip, "Toggle. Player becomes non-solid and flies.", FCVAR_CHEAT);
  1025. //------------------------------------------------------------------------------
  1026. // Sets client to godmode
  1027. //------------------------------------------------------------------------------
  1028. void CC_God_f (void)
  1029. {
  1030. if ( !sv_cheats->GetBool() )
  1031. return;
  1032. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1033. if ( !pPlayer )
  1034. return;
  1035. #ifdef TF_DLL
  1036. if ( TFGameRules() && ( TFGameRules()->IsPVEModeActive() == false ) )
  1037. {
  1038. if ( gpGlobals->deathmatch )
  1039. return;
  1040. }
  1041. #else
  1042. if ( gpGlobals->deathmatch )
  1043. return;
  1044. #endif
  1045. pPlayer->ToggleFlag( FL_GODMODE );
  1046. if (!(pPlayer->GetFlags() & FL_GODMODE ) )
  1047. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "godmode OFF\n");
  1048. else
  1049. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "godmode ON\n");
  1050. }
  1051. static ConCommand god("god", CC_God_f, "Toggle. Player becomes invulnerable.", FCVAR_CHEAT );
  1052. //------------------------------------------------------------------------------
  1053. // Sets client to godmode
  1054. //------------------------------------------------------------------------------
  1055. CON_COMMAND_F( setpos, "Move player to specified origin (must have sv_cheats).", FCVAR_CHEAT )
  1056. {
  1057. if ( !sv_cheats->GetBool() )
  1058. return;
  1059. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1060. if ( !pPlayer )
  1061. return;
  1062. if ( args.ArgC() < 3 )
  1063. {
  1064. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setpos x y <z optional>\n");
  1065. return;
  1066. }
  1067. Vector oldorigin = pPlayer->GetAbsOrigin();
  1068. Vector newpos;
  1069. newpos.x = clamp( atof( args[1] ), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  1070. newpos.y = clamp( atof( args[2] ), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  1071. newpos.z = args.ArgC() == 4 ? clamp( atof( args[3] ), MIN_COORD_FLOAT, MAX_COORD_FLOAT ) : oldorigin.z;
  1072. pPlayer->SetAbsOrigin( newpos );
  1073. if ( !TestEntityPosition( pPlayer ) )
  1074. {
  1075. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "setpos into world, use noclip to unstick yourself!\n");
  1076. }
  1077. }
  1078. //------------------------------------------------------------------------------
  1079. // Sets client to godmode
  1080. //------------------------------------------------------------------------------
  1081. void CC_setang_f (const CCommand &args)
  1082. {
  1083. if ( !sv_cheats->GetBool() )
  1084. return;
  1085. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1086. if ( !pPlayer )
  1087. return;
  1088. if ( args.ArgC() < 3 )
  1089. {
  1090. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setang pitch yaw <roll optional>\n");
  1091. return;
  1092. }
  1093. QAngle oldang = pPlayer->GetAbsAngles();
  1094. QAngle newang;
  1095. newang.x = atof( args[1] );
  1096. newang.y = atof( args[2] );
  1097. newang.z = args.ArgC() == 4 ? atof( args[3] ) : oldang.z;
  1098. pPlayer->SnapEyeAngles( newang );
  1099. }
  1100. static ConCommand setang("setang", CC_setang_f, "Snap player eyes to specified pitch yaw <roll:optional> (must have sv_cheats).", FCVAR_CHEAT );
  1101. static float GetHexFloat( const char *pStr )
  1102. {
  1103. if ( ( pStr[0] == '0' ) && ( pStr[1] == 'x' ) )
  1104. {
  1105. uint32 f = (uint32)V_atoi64( pStr );
  1106. return *reinterpret_cast< const float * >( &f );
  1107. }
  1108. return atof( pStr );
  1109. }
  1110. //------------------------------------------------------------------------------
  1111. // Move position
  1112. //------------------------------------------------------------------------------
  1113. CON_COMMAND_F( setpos_exact, "Move player to an exact specified origin (must have sv_cheats).", FCVAR_CHEAT )
  1114. {
  1115. if ( !sv_cheats->GetBool() )
  1116. return;
  1117. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1118. if ( !pPlayer )
  1119. return;
  1120. if ( args.ArgC() < 3 )
  1121. {
  1122. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setpos_exact x y <z optional>\n");
  1123. return;
  1124. }
  1125. Vector oldorigin = pPlayer->GetAbsOrigin();
  1126. Vector newpos;
  1127. newpos.x = GetHexFloat( args[1] );
  1128. newpos.y = GetHexFloat( args[2] );
  1129. newpos.z = args.ArgC() == 4 ? GetHexFloat( args[3] ) : oldorigin.z;
  1130. pPlayer->Teleport( &newpos, NULL, NULL );
  1131. if ( !TestEntityPosition( pPlayer ) )
  1132. {
  1133. if ( pPlayer->GetMoveType() != MOVETYPE_NOCLIP )
  1134. {
  1135. EnableNoClip( pPlayer );
  1136. return;
  1137. }
  1138. }
  1139. }
  1140. CON_COMMAND_F( setang_exact, "Snap player eyes and orientation to specified pitch yaw <roll:optional> (must have sv_cheats).", FCVAR_CHEAT )
  1141. {
  1142. if ( !sv_cheats->GetBool() )
  1143. return;
  1144. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1145. if ( !pPlayer )
  1146. return;
  1147. if ( args.ArgC() < 3 )
  1148. {
  1149. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Usage: setang_exact pitch yaw <roll optional>\n");
  1150. return;
  1151. }
  1152. QAngle oldang = pPlayer->GetAbsAngles();
  1153. QAngle newang;
  1154. newang.x = GetHexFloat( args[1] );
  1155. newang.y = GetHexFloat( args[2] );
  1156. newang.z = args.ArgC() == 4 ? GetHexFloat( args[3] ) : oldang.z;
  1157. pPlayer->Teleport( NULL, &newang, NULL );
  1158. pPlayer->SnapEyeAngles( newang );
  1159. #ifdef TF_DLL
  1160. static_cast<CTFPlayer*>( pPlayer )->DoAnimationEvent( PLAYERANIMEVENT_SNAP_YAW );
  1161. #endif
  1162. }
  1163. //------------------------------------------------------------------------------
  1164. // Sets client to notarget mode.
  1165. //------------------------------------------------------------------------------
  1166. void CC_Notarget_f (void)
  1167. {
  1168. if ( !sv_cheats->GetBool() )
  1169. return;
  1170. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1171. if ( !pPlayer )
  1172. return;
  1173. if ( gpGlobals->deathmatch )
  1174. return;
  1175. pPlayer->ToggleFlag( FL_NOTARGET );
  1176. if ( !(pPlayer->GetFlags() & FL_NOTARGET ) )
  1177. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "notarget OFF\n");
  1178. else
  1179. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "notarget ON\n");
  1180. }
  1181. ConCommand notarget("notarget", CC_Notarget_f, "Toggle. Player becomes hidden to NPCs.", FCVAR_CHEAT);
  1182. //------------------------------------------------------------------------------
  1183. // Damage the client the specified amount
  1184. //------------------------------------------------------------------------------
  1185. void CC_HurtMe_f(const CCommand &args)
  1186. {
  1187. if ( !sv_cheats->GetBool() )
  1188. return;
  1189. CBasePlayer *pPlayer = ToBasePlayer( UTIL_GetCommandClient() );
  1190. if ( !pPlayer )
  1191. return;
  1192. int iDamage = 10;
  1193. if ( args.ArgC() >= 2 )
  1194. {
  1195. iDamage = atoi( args[ 1 ] );
  1196. }
  1197. pPlayer->TakeDamage( CTakeDamageInfo( pPlayer, pPlayer, iDamage, DMG_PREVENT_PHYSICS_FORCE ) );
  1198. }
  1199. static ConCommand hurtme("hurtme", CC_HurtMe_f, "Hurts the player.\n\tArguments: <health to lose>", FCVAR_CHEAT);
  1200. #ifdef DBGFLAG_ASSERT
  1201. static bool IsInGroundList( CBaseEntity *ent, CBaseEntity *ground )
  1202. {
  1203. if ( !ground || !ent )
  1204. return false;
  1205. groundlink_t *root = ( groundlink_t * )ground->GetDataObject( GROUNDLINK );
  1206. if ( root )
  1207. {
  1208. groundlink_t *link = root->nextLink;
  1209. while ( link != root )
  1210. {
  1211. CBaseEntity *other = link->entity;
  1212. if ( other == ent )
  1213. return true;
  1214. link = link->nextLink;
  1215. }
  1216. }
  1217. return false;
  1218. }
  1219. #endif
  1220. static int DescribeGroundList( CBaseEntity *ent )
  1221. {
  1222. if ( !ent )
  1223. return 0;
  1224. int c = 1;
  1225. Msg( "%i : %s (ground %i %s)\n", ent->entindex(), ent->GetClassname(),
  1226. ent->GetGroundEntity() ? ent->GetGroundEntity()->entindex() : -1,
  1227. ent->GetGroundEntity() ? ent->GetGroundEntity()->GetClassname() : "NULL" );
  1228. groundlink_t *root = ( groundlink_t * )ent->GetDataObject( GROUNDLINK );
  1229. if ( root )
  1230. {
  1231. groundlink_t *link = root->nextLink;
  1232. while ( link != root )
  1233. {
  1234. CBaseEntity *other = link->entity;
  1235. if ( other )
  1236. {
  1237. Msg( " %02i: %i %s\n", c++, other->entindex(), other->GetClassname() );
  1238. if ( other->GetGroundEntity() != ent )
  1239. {
  1240. Assert( 0 );
  1241. Msg( " mismatched!!!\n" );
  1242. }
  1243. }
  1244. else
  1245. {
  1246. Assert( 0 );
  1247. Msg( " %02i: NULL link\n", c++ );
  1248. }
  1249. link = link->nextLink;
  1250. }
  1251. }
  1252. if ( ent->GetGroundEntity() != NULL )
  1253. {
  1254. Assert( IsInGroundList( ent, ent->GetGroundEntity() ) );
  1255. }
  1256. return c - 1;
  1257. }
  1258. void CC_GroundList_f(const CCommand &args)
  1259. {
  1260. if ( !UTIL_IsCommandIssuedByServerAdmin() )
  1261. return;
  1262. if ( args.ArgC() == 2 )
  1263. {
  1264. int idx = atoi( args[1] );
  1265. CBaseEntity *ground = CBaseEntity::Instance( idx );
  1266. if ( ground )
  1267. {
  1268. DescribeGroundList( ground );
  1269. }
  1270. }
  1271. else
  1272. {
  1273. CBaseEntity *ent = NULL;
  1274. int linkCount = 0;
  1275. while ( (ent = gEntList.NextEnt(ent)) != NULL )
  1276. {
  1277. linkCount += DescribeGroundList( ent );
  1278. }
  1279. extern int groundlinksallocated;
  1280. Assert( linkCount == groundlinksallocated );
  1281. Msg( "--- %i links\n", groundlinksallocated );
  1282. }
  1283. }
  1284. static ConCommand groundlist("groundlist", CC_GroundList_f, "Display ground entity list <index>" );
  1285. //-----------------------------------------------------------------------------
  1286. // Purpose: called each time a player uses a "cmd" command
  1287. // Input : *pEdict - the player who issued the command
  1288. //-----------------------------------------------------------------------------
  1289. void ClientCommand( CBasePlayer *pPlayer, const CCommand &args )
  1290. {
  1291. const char *pCmd = args[0];
  1292. // Is the client spawned yet?
  1293. if ( !pPlayer )
  1294. return;
  1295. MDLCACHE_CRITICAL_SECTION();
  1296. /*
  1297. const char *pstr;
  1298. if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd))
  1299. {
  1300. // Subtype may be specified
  1301. if ( args.ArgC() == 2 )
  1302. {
  1303. pPlayer->SelectItem( pcmd, atoi( args[1] ) );
  1304. }
  1305. else
  1306. {
  1307. pPlayer->SelectItem(pcmd);
  1308. }
  1309. }
  1310. */
  1311. if ( FStrEq( pCmd, "killtarget" ) )
  1312. {
  1313. if ( g_pDeveloper->GetBool() && sv_cheats->GetBool() && UTIL_IsCommandIssuedByServerAdmin() )
  1314. {
  1315. ConsoleKillTarget( pPlayer, args[1] );
  1316. }
  1317. }
  1318. else if ( FStrEq( pCmd, "demorestart" ) )
  1319. {
  1320. pPlayer->ForceClientDllUpdate();
  1321. }
  1322. else if ( FStrEq( pCmd, "fade" ) )
  1323. {
  1324. color32 black = {32,63,100,200};
  1325. UTIL_ScreenFade( pPlayer, black, 3, 3, FFADE_OUT );
  1326. }
  1327. else if ( FStrEq( pCmd, "te" ) )
  1328. {
  1329. if ( sv_cheats->GetBool() && UTIL_IsCommandIssuedByServerAdmin() )
  1330. {
  1331. if ( FStrEq( args[1], "stop" ) )
  1332. {
  1333. // Destroy it
  1334. //
  1335. CBaseEntity *ent = gEntList.FindEntityByClassname( NULL, "te_tester" );
  1336. while ( ent )
  1337. {
  1338. CBaseEntity *next = gEntList.FindEntityByClassname( ent, "te_tester" );
  1339. UTIL_Remove( ent );
  1340. ent = next;
  1341. }
  1342. }
  1343. else
  1344. {
  1345. CTempEntTester::Create( pPlayer->WorldSpaceCenter(), pPlayer->EyeAngles(), args[1], args[2] );
  1346. }
  1347. }
  1348. }
  1349. else
  1350. {
  1351. if ( !g_pGameRules->ClientCommand( pPlayer, args ) )
  1352. {
  1353. if ( Q_strlen( pCmd ) > 128 )
  1354. {
  1355. ClientPrint( pPlayer, HUD_PRINTCONSOLE, "Console command too long.\n" );
  1356. }
  1357. else
  1358. {
  1359. // tell the user they entered an unknown command
  1360. ClientPrint( pPlayer, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pCmd ) );
  1361. }
  1362. }
  1363. }
  1364. }