Counter Strike : Global Offensive Source Code
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.

1454 lines
37 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include <stdarg.h>
  10. #include "hud.h"
  11. #include "itextmessage.h"
  12. #include "materialsystem/imaterial.h"
  13. #include "materialsystem/itexture.h"
  14. #include "materialsystem/imaterialsystem.h"
  15. #include "imovehelper.h"
  16. #include "checksum_crc.h"
  17. #include "decals.h"
  18. #include "iefx.h"
  19. #include "view_scene.h"
  20. #include "filesystem.h"
  21. #include "model_types.h"
  22. #include "engine/IEngineTrace.h"
  23. #include "engine/ivmodelinfo.h"
  24. #include "c_te_effect_dispatch.h"
  25. #include <vgui_controls/Controls.h>
  26. #include <vgui/ISurface.h>
  27. #include <vgui/ILocalize.h>
  28. #include "view.h"
  29. #include "ixboxsystem.h"
  30. #include <ctype.h>
  31. #include <vgui_controls/EditablePanel.h>
  32. #include "vgui_int.h"
  33. #include "cdll_client_int.h"
  34. #include "c_cs_playerresource.h"
  35. #include "c_cs_player.h"
  36. #include "cs_gamerules.h"
  37. #include "weapon_c4.h"
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40. //-----------------------------------------------------------------------------
  41. // ConVars
  42. //-----------------------------------------------------------------------------
  43. #ifdef _DEBUG
  44. ConVar r_FadeProps( "r_FadeProps", "1" );
  45. #endif
  46. bool g_MakingDevShots = false;
  47. extern ConVar cl_leveloverview;
  48. //-----------------------------------------------------------------------------
  49. // Purpose: Performs a var args printf into a static return buffer
  50. // Input : *format -
  51. // ... -
  52. // Output : char
  53. //-----------------------------------------------------------------------------
  54. char *VarArgs( const char *format, ... )
  55. {
  56. va_list argptr;
  57. static char string[1024];
  58. va_start (argptr, format);
  59. Q_vsnprintf (string, sizeof( string ), format,argptr);
  60. va_end (argptr);
  61. return string;
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose: Returns true if the entity index corresponds to a player slot
  65. // Input : index -
  66. // Output : bool
  67. //-----------------------------------------------------------------------------
  68. bool IsPlayerIndex( int index )
  69. {
  70. return ( index >= 1 && index <= gpGlobals->maxClients ) ? true : false;
  71. }
  72. int GetLocalPlayerIndex( void )
  73. {
  74. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  75. if ( player )
  76. return player->entindex();
  77. else
  78. return 0; // game not started yet
  79. }
  80. bool IsLocalPlayerSpectator( void )
  81. {
  82. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  83. if ( player )
  84. return player->IsObserver();
  85. else
  86. return false; // game not started yet
  87. }
  88. int GetSpectatorMode( void )
  89. {
  90. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  91. if ( player )
  92. return player->GetObserverMode();
  93. else
  94. return OBS_MODE_NONE; // game not started yet
  95. }
  96. int GetSpectatorTarget( void )
  97. {
  98. C_BasePlayer * player = C_BasePlayer::GetLocalPlayer();
  99. if ( player )
  100. {
  101. CBaseEntity * target = player->GetObserverTarget();
  102. if ( target )
  103. return target->entindex();
  104. else
  105. return 0;
  106. }
  107. else
  108. {
  109. return 0; // game not started yet
  110. }
  111. }
  112. // this is meant to be called on a bot character
  113. // note: This is quite similar to CCSPlayer::CanControlBot. This is here since calling into the CCSPlayer was unrealistic in some code paths
  114. // TODO: Fix this so it ACTUALLY calls CanControlBot, there are bugs otherwise (and will be more) do to them being different functions
  115. bool CanControlSpectatedTarget( void )
  116. {
  117. C_CSPlayer * player = ( C_CSPlayer* )C_BasePlayer::GetLocalPlayer();
  118. if ( !player || ( player->GetPendingTeamNumber() != player->GetTeamNumber() ) )
  119. return false;
  120. C_CSPlayer * target = dynamic_cast<C_CSPlayer*>(player->GetObserverTarget());
  121. if ( !target )
  122. return false;
  123. if ( !target->IsAlive() )
  124. return false;
  125. if ( !target->IsOtherSameTeam( GetLocalPlayerTeam() ) || target->IsOtherEnemy( player ) )
  126. return false;
  127. C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
  128. int entIndex = target->entindex();
  129. bool targetIsFakePlayer = pCSPR->IsFakePlayer( entIndex );
  130. if ( !targetIsFakePlayer )
  131. return false;
  132. AssertMsg(pCSPR, "Expected PlayerResources to exsist");
  133. AssertMsg(entIndex > 0 && entIndex <= MAX_PLAYERS, "Bad entity index for player");
  134. // need to duplicate some of the checks that CanControlBot already does so they match up....
  135. // Can't control a bot that is setting a bomb
  136. const CC4 *pC4 = dynamic_cast<CC4*>( target->GetActiveWeapon() );
  137. if ( pC4 && pC4->m_bStartedArming )
  138. return false;
  139. if ( CSGameRules() && CSGameRules()->IsRoundOver() )
  140. return false;
  141. if ( CSGameRules() && CSGameRules()->IsFreezePeriod() )
  142. return false;
  143. return true;
  144. }
  145. bool CanSeeSpectatorOnlyTools( void )
  146. {
  147. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  148. if ( !pPlayer )
  149. return false;
  150. if ( pPlayer->IsHLTV() )
  151. return true;
  152. if ( pPlayer->IsSpectator() )
  153. {
  154. if ( sv_competitive_official_5v5.GetBool() )
  155. return true;
  156. if ( CSGameRules() && CSGameRules()->IsQueuedMatchmaking() )
  157. return true;
  158. }
  159. return false;
  160. }
  161. bool CanToggleXRayView( void )
  162. {
  163. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  164. if ( !pPlayer )
  165. return false;
  166. if ( CanSeeSpectatorOnlyTools() )
  167. return true;
  168. return false;
  169. }
  170. int GetLocalPlayerTeam( void )
  171. {
  172. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  173. if ( pPlayer )
  174. return pPlayer->GetTeamNumber();
  175. else
  176. return TEAM_UNASSIGNED;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose: Convert angles to -180 t 180 range
  180. // Input : angles -
  181. //-----------------------------------------------------------------------------
  182. void NormalizeAngles( QAngle& angles )
  183. {
  184. int i;
  185. // Normalize angles to -180 to 180 range
  186. for ( i = 0; i < 3; i++ )
  187. {
  188. if ( angles[i] > 180.0 )
  189. {
  190. angles[i] -= 360.0;
  191. }
  192. else if ( angles[i] < -180.0 )
  193. {
  194. angles[i] += 360.0;
  195. }
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose: Interpolate Euler angles using quaternions to avoid singularities
  200. // Input : start -
  201. // end -
  202. // output -
  203. // frac -
  204. //-----------------------------------------------------------------------------
  205. void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac )
  206. {
  207. Quaternion src, dest;
  208. // Convert to quaternions
  209. AngleQuaternion( start, src );
  210. AngleQuaternion( end, dest );
  211. Quaternion result;
  212. // Slerp
  213. QuaternionSlerp( src, dest, frac, result );
  214. // Convert to euler
  215. QuaternionAngles( result, output );
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose: Simple linear interpolation
  219. // Input : frac -
  220. // src -
  221. // dest -
  222. // output -
  223. //-----------------------------------------------------------------------------
  224. void InterpolateVector( float frac, const Vector& src, const Vector& dest, Vector& output )
  225. {
  226. int i;
  227. for ( i = 0; i < 3; i++ )
  228. {
  229. output[ i ] = src[ i ] + frac * ( dest[ i ] - src[ i ] );
  230. }
  231. }
  232. client_textmessage_t *TextMessageGet( const char *pName )
  233. {
  234. return engine->TextMessageGet( pName );
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: ScreenHeight returns the height of the screen, in pixels
  238. // Output : int
  239. //-----------------------------------------------------------------------------
  240. int ScreenHeight( void )
  241. {
  242. int w, h;
  243. GetHudSize( w, h );
  244. return h;
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: ScreenWidth returns the width of the screen, in pixels
  248. // Output : int
  249. //-----------------------------------------------------------------------------
  250. int ScreenWidth( void )
  251. {
  252. int w, h;
  253. GetHudSize( w, h );
  254. return w;
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose: Return the difference between two angles
  258. // Input : destAngle -
  259. // srcAngle -
  260. // Output : float
  261. //-----------------------------------------------------------------------------
  262. float UTIL_AngleDiff( float destAngle, float srcAngle )
  263. {
  264. float delta;
  265. delta = destAngle - srcAngle;
  266. if ( destAngle > srcAngle )
  267. {
  268. while ( delta >= 180 )
  269. delta -= 360;
  270. }
  271. else
  272. {
  273. while ( delta <= -180 )
  274. delta += 360;
  275. }
  276. return delta;
  277. }
  278. void UTIL_Bubbles( const Vector& mins, const Vector& maxs, int count )
  279. {
  280. Vector mid = (mins + maxs) * 0.5;
  281. float flHeight = UTIL_WaterLevel( mid, mid.z, mid.z + 1024 );
  282. flHeight = flHeight - mins.z;
  283. CPASFilter filter( mid );
  284. int bubbles = modelinfo->GetModelIndex( "sprites/bubble.vmt" );
  285. te->Bubbles( filter, 0.0,
  286. &mins, &maxs, flHeight, bubbles, count, 8.0 );
  287. }
  288. void UTIL_ScreenShake( const Vector &center, float amplitude, float frequency, float duration, float radius, ShakeCommand_t eCommand, bool bAirShake )
  289. {
  290. // Nothing for now
  291. }
  292. char TEXTURETYPE_Find( trace_t *ptr )
  293. {
  294. surfacedata_t *psurfaceData = physprops->GetSurfaceData( ptr->surface.surfaceProps );
  295. return psurfaceData->game.material;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose: Make a tracer effect
  299. //-----------------------------------------------------------------------------
  300. void UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex, int iAttachment, float flVelocity, bool bWhiz, char *pCustomTracerName )
  301. {
  302. CEffectData data;
  303. data.m_vStart = vecStart;
  304. data.m_vOrigin = vecEnd;
  305. data.m_hEntity = ClientEntityList().EntIndexToHandle( iEntIndex );
  306. data.m_flScale = flVelocity;
  307. // Flags
  308. if ( bWhiz )
  309. {
  310. data.m_fFlags |= TRACER_FLAG_WHIZ;
  311. }
  312. if ( iAttachment != TRACER_DONT_USE_ATTACHMENT )
  313. {
  314. data.m_fFlags |= TRACER_FLAG_USEATTACHMENT;
  315. // Stomp the start, since it's not going to be used anyway
  316. data.m_vStart[0] = iAttachment;
  317. }
  318. // Fire it off
  319. if ( pCustomTracerName )
  320. {
  321. DispatchEffect( pCustomTracerName, data );
  322. }
  323. else
  324. {
  325. DispatchEffect( "Tracer", data );
  326. }
  327. }
  328. // Tried to include this in the actual trace function, but ran into
  329. // linker issues. Just dropped it here instead. Michael Dorgan
  330. static bool HasValidDirection(trace_t *pTrace)
  331. {
  332. if(pTrace->fraction <= 0.0001f)
  333. {
  334. // Ok, there is a very, very strong chance our vectors are out of wack
  335. // Add a direct check against the actual start and end points to be sure.
  336. if( VectorsAreEqual( pTrace->startpos, pTrace->endpos, 0.0001f ) )
  337. {
  338. return false;
  339. }
  340. }
  341. return true;
  342. }
  343. //------------------------------------------------------------------------------
  344. // Purpose : Creates both an decal and any associated impact effects (such
  345. // as flecks) for the given iDamageType and the trace's end position
  346. // Input :
  347. // Output :
  348. //------------------------------------------------------------------------------
  349. void UTIL_ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName )
  350. {
  351. C_BaseEntity *pEntity = pTrace->m_pEnt;
  352. // Is the entity valid, is the surface sky?
  353. if ( !pEntity || (pTrace->surface.flags & SURF_SKY) )
  354. return;
  355. if (pTrace->fraction >= 1.0f)
  356. return;
  357. // Very, very, very close range shots cause all sorts of issues with normal and correct
  358. // decal orientation. Just skip them to prevent heartache.
  359. if ( !HasValidDirection(pTrace) )
  360. return;
  361. // don't decal nodraw surfaces
  362. if ( pTrace->surface.flags & SURF_NODRAW )
  363. return;
  364. pEntity->ImpactTrace( pTrace, iDamageType, pCustomImpactName );
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose:
  368. //-----------------------------------------------------------------------------
  369. int UTIL_PrecacheDecal( const char *name, bool preload )
  370. {
  371. return effects->Draw_DecalIndexFromName( (char*)name );
  372. }
  373. extern int g_sModelIndexSmoke;
  374. void UTIL_Smoke( const Vector &origin, const float scale, const float framerate )
  375. {
  376. CPVSFilter filter( origin );
  377. te->Smoke( filter, 0.0f, &origin, g_sModelIndexSmoke, scale, framerate );
  378. }
  379. void UTIL_SetOrigin( C_BaseEntity *entity, const Vector &vecOrigin )
  380. {
  381. entity->SetLocalOrigin( vecOrigin );
  382. }
  383. //#define PRECACHE_OTHER_ONCE
  384. // UNDONE: Do we need this to avoid doing too much of this? Measure startup times and see
  385. #if PRECACHE_OTHER_ONCE
  386. #include "utlsymbol.h"
  387. class CPrecacheOtherList : public CAutoServerSystem
  388. {
  389. public:
  390. virtual void LevelInitPreEntity();
  391. virtual void LevelShutdownPostEntity();
  392. bool AddOrMarkPrecached( const char *pClassname );
  393. private:
  394. CUtlSymbolTable m_list;
  395. };
  396. void CPrecacheOtherList::LevelInitPreEntity()
  397. {
  398. m_list.RemoveAll();
  399. }
  400. void CPrecacheOtherList::LevelShutdownPostEntity()
  401. {
  402. m_list.RemoveAll();
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Purpose: mark or add
  406. // Input : *pEntity -
  407. // Output : Returns true on success, false on failure.
  408. //-----------------------------------------------------------------------------
  409. bool CPrecacheOtherList::AddOrMarkPrecached( const char *pClassname )
  410. {
  411. CUtlSymbol sym = m_list.Find( pClassname );
  412. if ( sym.IsValid() )
  413. return false;
  414. m_list.AddString( pClassname );
  415. return true;
  416. }
  417. CPrecacheOtherList g_PrecacheOtherList;
  418. #endif
  419. void UTIL_PrecacheOther( const char *szClassname )
  420. {
  421. #if PRECACHE_OTHER_ONCE
  422. // already done this one?, if not, mark as done
  423. if ( !g_PrecacheOtherList.AddOrMarkPrecached( szClassname ) )
  424. return;
  425. #endif
  426. // Client should only do this once entities are coming down from server!!!
  427. // Assert( engine->IsConnected() );
  428. C_BaseEntity *pEntity = CreateEntityByName( szClassname );
  429. if ( !pEntity )
  430. {
  431. Warning( "NULL Ent in UTIL_PrecacheOther\n" );
  432. return;
  433. }
  434. if (pEntity)
  435. {
  436. pEntity->Precache( );
  437. }
  438. // Bye bye
  439. UTIL_Remove( pEntity );
  440. }
  441. static csurface_t g_NullSurface = { "**empty**", 0 };
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. void UTIL_SetTrace(trace_t& trace, const Ray_t& ray, C_BaseEntity *ent, float fraction, int hitgroup, unsigned int contents, const Vector& normal, float intercept )
  446. {
  447. trace.startsolid = (fraction == 0.0f);
  448. trace.fraction = fraction;
  449. VectorCopy( ray.m_Start, trace.startpos );
  450. VectorMA( ray.m_Start, fraction, ray.m_Delta, trace.endpos );
  451. VectorCopy( normal, trace.plane.normal );
  452. trace.plane.dist = intercept;
  453. trace.m_pEnt = C_BaseEntity::Instance( ent );
  454. trace.hitgroup = hitgroup;
  455. trace.surface = g_NullSurface;
  456. trace.contents = contents;
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose: Get the x & y positions of a world position in screenspace
  460. // Returns true if it's onscreen
  461. //-----------------------------------------------------------------------------
  462. bool GetVectorInScreenSpace( Vector pos, int& iX, int& iY, Vector *vecOffset )
  463. {
  464. Vector screen;
  465. // Apply the offset, if one was specified
  466. if ( vecOffset != NULL )
  467. pos += *vecOffset;
  468. // Transform to screen space
  469. int x, y, screenWidth, screenHeight;
  470. int insetX, insetY;
  471. VGui_GetEngineRenderBounds( GET_ACTIVE_SPLITSCREEN_SLOT(), x, y, screenWidth, screenHeight, insetX, insetY );
  472. // Transform to screen space
  473. int iFacing = ScreenTransform( pos, screen );
  474. iX = 0.5 * screen[0] * screenWidth;
  475. iY = -0.5 * screen[1] * screenHeight;
  476. iX += 0.5 * screenWidth;
  477. iY += 0.5 * screenHeight;
  478. iX += insetX;
  479. iY += insetY;
  480. // Make sure the player's facing it
  481. if ( iFacing )
  482. {
  483. // We're actually facing away from the Target. Stomp the screen position.
  484. iX = -640;
  485. iY = -640;
  486. return false;
  487. }
  488. return true;
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Purpose: Get the x & y positions of an entity in screenspace
  492. // Returns true if it's onscreen
  493. //-----------------------------------------------------------------------------
  494. bool GetTargetInScreenSpace( C_BaseEntity *pTargetEntity, int& iX, int& iY, Vector *vecOffset )
  495. {
  496. return GetVectorInScreenSpace( pTargetEntity->WorldSpaceCenter(), iX, iY, vecOffset );
  497. }
  498. //-----------------------------------------------------------------------------
  499. // Purpose:
  500. // Input : *player -
  501. // msg_dest -
  502. // *msg_name -
  503. // *param1 -
  504. // *param2 -
  505. // *param3 -
  506. // *param4 -
  507. //-----------------------------------------------------------------------------
  508. void ClientPrint( C_BasePlayer *player, int msg_dest, const char *msg_name, const char *param1 /*= NULL*/, const char *param2 /*= NULL*/, const char *param3 /*= NULL*/, const char *param4 /*= NULL*/ )
  509. {
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted
  513. // Input : **pList -
  514. // listMax -
  515. // &mins -
  516. // &maxs -
  517. // flagMask -
  518. // Output : int
  519. //-----------------------------------------------------------------------------
  520. int UTIL_EntitiesInBox( C_BaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask, int partitionMask )
  521. {
  522. CFlaggedEntitiesEnum boxEnum( pList, listMax, flagMask );
  523. ::partition->EnumerateElementsInBox( partitionMask, mins, maxs, false, &boxEnum );
  524. return boxEnum.GetCount();
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose: Pass in an array of pointers and an array size, it fills the array and returns the number inserted
  528. // Input : **pList -
  529. // listMax -
  530. // &center -
  531. // radius -
  532. // flagMask -
  533. // Output : int
  534. //-----------------------------------------------------------------------------
  535. int UTIL_EntitiesInSphere( C_BaseEntity **pList, int listMax, const Vector &center, float radius, int flagMask, int partitionMask )
  536. {
  537. CFlaggedEntitiesEnum sphereEnum( pList, listMax, flagMask );
  538. ::partition->EnumerateElementsInSphere( partitionMask, center, radius, false, &sphereEnum );
  539. return sphereEnum.GetCount();
  540. }
  541. int UTIL_RenderablesInBox( C_BaseEntity** pList, int listMax, const Vector &mins, const Vector &maxs )
  542. {
  543. return g_pClientLeafSystem->GetEntitiesInBox( pList, listMax, mins, maxs );
  544. }
  545. CEntitySphereQuery::CEntitySphereQuery( const Vector &center, float radius, int flagMask, int partitionMask )
  546. {
  547. m_listIndex = 0;
  548. m_listCount = UTIL_EntitiesInSphere( m_pList, ARRAYSIZE(m_pList), center, radius, flagMask, partitionMask );
  549. }
  550. CBaseEntity *CEntitySphereQuery::GetCurrentEntity()
  551. {
  552. if ( m_listIndex < m_listCount )
  553. return m_pList[m_listIndex];
  554. return NULL;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose:
  558. // Input : font -
  559. // *str -
  560. // Output : int
  561. //-----------------------------------------------------------------------------
  562. int UTIL_ComputeStringWidth( vgui::HFont& font, const char *str )
  563. {
  564. float pixels = 0;
  565. char *p = (char *)str;
  566. char *pAfter = p + 1;
  567. char *pBefore = "\0";
  568. while ( *p )
  569. {
  570. #ifdef OSX
  571. float wide, abcA, abcC;
  572. vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA, abcC );
  573. pixels += wide;
  574. #else
  575. pixels += vgui::surface()->GetCharacterWidth( font, *p );
  576. #endif
  577. pBefore = p;
  578. p++;
  579. if ( *p )
  580. pAfter = p + 1;
  581. else
  582. pAfter = "\0";
  583. }
  584. return (int)ceil(pixels);
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Purpose:
  588. // Input : font -
  589. // *str -
  590. // Output : int
  591. //-----------------------------------------------------------------------------
  592. int UTIL_ComputeStringWidth( vgui::HFont& font, const wchar_t *str )
  593. {
  594. float pixels = 0;
  595. wchar_t *p = (wchar_t *)str;
  596. wchar_t *pAfter = p + 1;
  597. wchar_t *pBefore = L"\0";
  598. while ( *p )
  599. {
  600. #ifdef OSX
  601. float wide, abcA, abcC;
  602. vgui::surface()->GetKernedCharWidth( font, *p, *pBefore, *pAfter, wide, abcA, abcC );
  603. pixels += wide;
  604. #else
  605. pixels += vgui::surface()->GetCharacterWidth( font, *p );
  606. #endif
  607. pBefore = p;
  608. p++;
  609. if ( *p )
  610. pAfter = p + 1;
  611. else
  612. pAfter = L"\0";
  613. }
  614. return (int)ceil(pixels);
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Purpose: Scans player names
  618. //Passes the player name to be checked in a KeyValues pointer
  619. //with the keyname "name"
  620. // - replaces '&' with '&&' so they will draw in the scoreboard
  621. // - replaces '#' at the start of the name with '*'
  622. //-----------------------------------------------------------------------------
  623. void UTIL_MakeSafeName( const char *oldName, char *newName, int newNameBufSize )
  624. {
  625. int newpos = 0;
  626. for( const char *p=oldName; *p != 0 && newpos < newNameBufSize-1; p++ )
  627. {
  628. //check for a '#' char at the beginning
  629. if( p == oldName && *p == '#' )
  630. {
  631. newName[newpos] = '*';
  632. newpos++;
  633. }
  634. else if( *p == '%' )
  635. {
  636. // remove % chars
  637. newName[newpos] = '*';
  638. newpos++;
  639. }
  640. else if( *p == '&' )
  641. {
  642. //insert another & after this one
  643. if ( newpos+2 < newNameBufSize )
  644. {
  645. newName[newpos] = '&';
  646. newName[newpos+1] = '&';
  647. newpos+=2;
  648. }
  649. }
  650. else
  651. {
  652. newName[newpos] = *p;
  653. newpos++;
  654. }
  655. }
  656. newName[newpos] = 0;
  657. }
  658. //-----------------------------------------------------------------------------
  659. // Purpose: Scans player names and replaces characters that vgui won't
  660. // display properly
  661. // Input : *oldName - player name to be fixed up
  662. // Output : *char - static buffer with the safe name
  663. //-----------------------------------------------------------------------------
  664. const char * UTIL_SafeName( const char *oldName )
  665. {
  666. static char safeName[ MAX_PLAYER_NAME_LENGTH * 2 + 1 ];
  667. UTIL_MakeSafeName( oldName, safeName, sizeof( safeName ) );
  668. return safeName;
  669. }
  670. //-----------------------------------------------------------------------------
  671. // Purpose: Looks up key bindings for commands and replaces them in string.
  672. // %<commandname>% will get replaced with its bound control, e.g. %attack2%
  673. // Input buffer sizes are in bytes rather than unicode character count
  674. // for consistency with other APIs. If inbufsizebytes is 0 a NULL-terminated
  675. // input buffer is assumed, or you can pass the size of the input buffer if
  676. // not NULL-terminated.
  677. //-----------------------------------------------------------------------------
  678. void UTIL_ReplaceKeyBindings( const wchar_t *inbuf, int inbufsizebytes, wchar_t *outbuf, int outbufsizebytes )
  679. {
  680. if ( !inbuf || !inbuf[0] )
  681. return;
  682. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  683. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  684. // copy to a new buf if there are vars
  685. outbuf[0]=0;
  686. int pos = 0;
  687. const wchar_t *inbufend = NULL;
  688. if ( inbufsizebytes > 0 )
  689. {
  690. inbufend = inbuf + ( inbufsizebytes / 2 );
  691. }
  692. while( inbuf != inbufend && *inbuf != 0 )
  693. {
  694. // check for variables
  695. if ( *inbuf == '%' )
  696. {
  697. ++inbuf;
  698. const wchar_t *end = wcschr( inbuf, '%' );
  699. if ( end && ( end != inbuf ) ) // make sure we handle %% in the string, which should be treated in the output as %
  700. {
  701. wchar_t token[64];
  702. wcsncpy( token, inbuf, end - inbuf );
  703. token[end - inbuf] = 0;
  704. inbuf += end - inbuf;
  705. // lookup key names
  706. char binding[64];
  707. g_pVGuiLocalize->ConvertUnicodeToANSI( token, binding, sizeof(binding) );
  708. const char *key = engine->Key_LookupBindingEx( *binding == '+' ? binding + 1 : binding, nSlot );
  709. //!! change some key names into better names
  710. char friendlyName[64];
  711. bool bAddBrackets = false;
  712. if ( IsGameConsole() )
  713. {
  714. if ( !key || !key[0] )
  715. {
  716. Q_snprintf( friendlyName, sizeof(friendlyName), "%s", binding );
  717. bAddBrackets = true;
  718. }
  719. else
  720. {
  721. Q_snprintf( friendlyName, sizeof(friendlyName), "#GameUI_KeyNames_%s", key );
  722. Q_strupr( friendlyName );
  723. }
  724. }
  725. else
  726. {
  727. if ( !key || !key[0] )
  728. {
  729. Q_snprintf( friendlyName, sizeof(friendlyName), "%s", binding );
  730. }
  731. else
  732. {
  733. Q_snprintf( friendlyName, sizeof(friendlyName), "%s", key );
  734. Q_strupr( friendlyName );
  735. }
  736. }
  737. wchar_t *locName = g_pVGuiLocalize->Find( friendlyName );
  738. if ( !locName || wcslen(locName) <= 0)
  739. {
  740. g_pVGuiLocalize->ConvertANSIToUnicode( friendlyName, token, sizeof(token) );
  741. outbuf[pos] = '\0';
  742. wcscat( outbuf, token );
  743. pos += wcslen(token);
  744. }
  745. else
  746. {
  747. outbuf[pos] = '\0';
  748. if ( bAddBrackets )
  749. {
  750. wcscat( outbuf, L"[" );
  751. pos += 1;
  752. }
  753. wcscat( outbuf, locName );
  754. pos += wcslen(locName);
  755. if ( bAddBrackets )
  756. {
  757. wcscat( outbuf, L"]" );
  758. pos += 1;
  759. }
  760. }
  761. }
  762. else
  763. {
  764. outbuf[pos] = *inbuf;
  765. ++pos;
  766. }
  767. }
  768. else
  769. {
  770. outbuf[pos] = *inbuf;
  771. ++pos;
  772. }
  773. ++inbuf;
  774. }
  775. outbuf[pos] = '\0';
  776. }
  777. //-----------------------------------------------------------------------------
  778. // Purpose:
  779. //-----------------------------------------------------------------------------
  780. void UTIL_SetControlStringWithKeybindings( vgui::EditablePanel *panel, const char *controlName, const char *str )
  781. {
  782. if ( !panel || !controlName || !str )
  783. return;
  784. const wchar_t *unicodeStr = g_pVGuiLocalize->Find( str );
  785. if ( unicodeStr )
  786. {
  787. wchar_t buf[512];
  788. UTIL_ReplaceKeyBindings( unicodeStr, 0, buf, sizeof( buf ) );
  789. panel->SetControlString( controlName, buf );
  790. }
  791. else
  792. {
  793. panel->SetControlString( controlName, str );
  794. }
  795. }
  796. //-----------------------------------------------------------------------------
  797. // Purpose:
  798. // Input : *filename -
  799. // *pLength -
  800. // Output : byte
  801. //-----------------------------------------------------------------------------
  802. byte *UTIL_LoadFileForMe( const char *filename, int *pLength )
  803. {
  804. byte *buffer;
  805. FileHandle_t file;
  806. file = filesystem->Open( filename, "rb", "GAME" );
  807. if ( FILESYSTEM_INVALID_HANDLE == file )
  808. {
  809. if ( pLength ) *pLength = 0;
  810. return NULL;
  811. }
  812. int size = filesystem->Size( file );
  813. buffer = new byte[ size + 1 ];
  814. if ( !buffer )
  815. {
  816. Warning( "UTIL_LoadFileForMe: Couldn't allocate buffer of size %i for file %s\n", size + 1, filename );
  817. filesystem->Close( file );
  818. return NULL;
  819. }
  820. filesystem->Read( buffer, size, file );
  821. filesystem->Close( file );
  822. // Ensure null terminator
  823. buffer[ size ] =0;
  824. if ( pLength )
  825. {
  826. *pLength = size;
  827. }
  828. return buffer;
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose:
  832. // Input : *buffer -
  833. //-----------------------------------------------------------------------------
  834. void UTIL_FreeFile( byte *buffer )
  835. {
  836. delete[] buffer;
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Compute distance fade
  840. //-----------------------------------------------------------------------------
  841. static unsigned char ComputeDistanceFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist )
  842. {
  843. if ((flMinDist <= 0) && (flMaxDist <= 0))
  844. return 255;
  845. if( flMinDist > flMaxDist )
  846. {
  847. V_swap( flMinDist, flMaxDist );
  848. }
  849. // If a negative value is provided for the min fade distance, then base it off the max.
  850. if( flMinDist < 0 )
  851. {
  852. flMinDist = flMaxDist - 400;
  853. if( flMinDist < 0 )
  854. {
  855. flMinDist = 0;
  856. }
  857. }
  858. flMinDist *= flMinDist;
  859. flMaxDist *= flMaxDist;
  860. float flCurrentDistanceSq = CurrentViewOrigin().DistToSqr( pEntity->WorldSpaceCenter() );
  861. C_BasePlayer *pLocal = C_BasePlayer::GetLocalPlayer();
  862. if ( pLocal )
  863. {
  864. float flDistFactor = pLocal->GetFOVDistanceAdjustFactor();
  865. flCurrentDistanceSq *= flDistFactor * flDistFactor;
  866. }
  867. // If I'm inside the minimum range than don't resort to alpha trickery
  868. if ( flCurrentDistanceSq <= flMinDist )
  869. return 255;
  870. if ( flCurrentDistanceSq >= flMaxDist )
  871. return 0;
  872. // NOTE: Because of the if-checks above, flMinDist != flMinDist here
  873. float flFalloffFactor = 255.0f / (flMaxDist - flMinDist);
  874. int nAlpha = flFalloffFactor * (flMaxDist - flCurrentDistanceSq);
  875. return clamp( nAlpha, 0, 255 );
  876. }
  877. //-----------------------------------------------------------------------------
  878. // Compute fade amount
  879. //-----------------------------------------------------------------------------
  880. unsigned char UTIL_ComputeEntityFade( C_BaseEntity *pEntity, float flMinDist, float flMaxDist, float flFadeScale )
  881. {
  882. unsigned char nAlpha = 255;
  883. // If we're taking devshots, don't fade props at all
  884. if ( g_MakingDevShots || cl_leveloverview.GetInt() != 0 || input->CAM_IsThirdPersonOverview() )
  885. return 255;
  886. #ifdef _DEBUG
  887. if ( r_FadeProps.GetBool() )
  888. #endif
  889. {
  890. nAlpha = ComputeDistanceFade( pEntity, flMinDist, flMaxDist );
  891. // NOTE: This computation for the center + radius is invalid!
  892. // The center of the sphere is at the center of the OBB, which is not necessarily
  893. // at the render origin. But it should be close enough.
  894. Vector vecMins, vecMaxs;
  895. pEntity->GetRenderBounds( vecMins, vecMaxs );
  896. float flRadius = vecMins.DistTo( vecMaxs ) * 0.5f;
  897. Vector vecAbsCenter;
  898. if ( modelinfo->GetModelType( pEntity->GetModel() ) == mod_brush )
  899. {
  900. Vector vecRenderMins, vecRenderMaxs;
  901. pEntity->GetRenderBoundsWorldspace( vecRenderMins, vecRenderMaxs );
  902. VectorAdd( vecRenderMins, vecRenderMaxs, vecAbsCenter );
  903. vecAbsCenter *= 0.5f;
  904. }
  905. else
  906. {
  907. vecAbsCenter = pEntity->GetRenderOrigin();
  908. }
  909. unsigned char nGlobalAlpha = modelinfo->ComputeLevelScreenFade( vecAbsCenter, flRadius, flFadeScale );
  910. unsigned char nDistAlpha;
  911. if ( !engine->IsLevelMainMenuBackground() )
  912. {
  913. nDistAlpha = modelinfo->ComputeViewScreenFade( vecAbsCenter, flRadius, flFadeScale );
  914. }
  915. else
  916. {
  917. nDistAlpha = 255;
  918. }
  919. if ( nDistAlpha < nGlobalAlpha )
  920. {
  921. nGlobalAlpha = nDistAlpha;
  922. }
  923. if ( nGlobalAlpha < nAlpha )
  924. {
  925. nAlpha = nGlobalAlpha;
  926. }
  927. }
  928. return nAlpha;
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Purpose: Given a vector, clamps the scalar axes to MAX_COORD_FLOAT ranges from worldsize.h
  932. // Input : *pVecPos -
  933. //-----------------------------------------------------------------------------
  934. void UTIL_BoundToWorldSize( Vector *pVecPos )
  935. {
  936. Assert( pVecPos );
  937. for ( int i = 0; i < 3; ++i )
  938. {
  939. (*pVecPos)[ i ] = clamp( (*pVecPos)[ i ], MIN_COORD_FLOAT, MAX_COORD_FLOAT );
  940. }
  941. }
  942. #ifdef _GAMECONSOLE
  943. #define MAP_KEY_FILE_DIR "cfg"
  944. #else
  945. #define MAP_KEY_FILE_DIR "media"
  946. #endif
  947. //-----------------------------------------------------------------------------
  948. // Purpose:
  949. //-----------------------------------------------------------------------------
  950. C_BasePlayer* UTIL_PlayerByUserId( int userID )
  951. {
  952. for (int i = 1; i<=gpGlobals->maxClients; i++ )
  953. {
  954. C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  955. if ( !pPlayer )
  956. continue;
  957. if ( pPlayer->GetUserID() == userID )
  958. {
  959. return pPlayer;
  960. }
  961. }
  962. return NULL;
  963. }
  964. C_BaseEntity* UTIL_EntityFromUserMessageEHandle( long nEncodedEHandle )
  965. {
  966. int nEntity, nSerialNum;
  967. if( nEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE )
  968. return NULL;
  969. nEntity = nEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1);
  970. nSerialNum = nEncodedEHandle >> MAX_EDICT_BITS;
  971. EHANDLE hEntity( nEntity, nSerialNum );
  972. return hEntity.Get();
  973. }
  974. //-----------------------------------------------------------------------------
  975. //
  976. //-----------------------------------------------------------------------------
  977. void UTIL_ApproachTarget( float target, float increaseSpeed, float decreaseSpeed, float *val )
  978. {
  979. if ( *val < target )
  980. {
  981. *val += gpGlobals->frametime*increaseSpeed;
  982. *val = MIN( *val, target );
  983. }
  984. else if ( *val > target )
  985. {
  986. *val -= gpGlobals->frametime*decreaseSpeed;
  987. *val = MAX( *val, target );
  988. }
  989. }
  990. //-----------------------------------------------------------------------------
  991. //
  992. //-----------------------------------------------------------------------------
  993. void UTIL_ApproachTarget( const Vector &target, float increaseSpeed, float decreaseSpeed, Vector *val )
  994. {
  995. UTIL_ApproachTarget( target.x, increaseSpeed, decreaseSpeed, &val->x );
  996. UTIL_ApproachTarget( target.y, increaseSpeed, decreaseSpeed, &val->y );
  997. UTIL_ApproachTarget( target.z, increaseSpeed, decreaseSpeed, &val->z );
  998. }
  999. //-----------------------------------------------------------------------------
  1000. // Purpose: Returns the filename to count map loads in
  1001. //-----------------------------------------------------------------------------
  1002. bool UTIL_GetMapLoadCountFileName( int iController, const char *pszFilePrependName, char *pszBuffer, int iBuflen )
  1003. {
  1004. if ( IsX360() )
  1005. {
  1006. #ifdef _X360
  1007. if ( iController < 0 || iController >= XUSER_MAX_COUNT )
  1008. return false;
  1009. int iSlot = -1;
  1010. for ( unsigned int k = 0; k < XBX_GetNumGameUsers(); ++ k )
  1011. {
  1012. if ( XBX_GetUserId( k ) == iController )
  1013. {
  1014. iSlot = k;
  1015. if ( XBX_GetUserIsGuest( k ) )
  1016. return false;
  1017. }
  1018. }
  1019. if ( iSlot < 0 )
  1020. return false;
  1021. DWORD nStorageDevice = XBX_GetStorageDeviceId( iController );
  1022. if ( !XBX_DescribeStorageDevice( nStorageDevice ) )
  1023. return false;
  1024. #endif
  1025. }
  1026. #ifdef _X360
  1027. if ( IsX360() )
  1028. {
  1029. XBX_MakeStorageContainerRoot( iController, XBX_USER_SETTINGS_CONTAINER_DRIVE, pszBuffer, iBuflen );
  1030. int nLen = strlen( pszBuffer );
  1031. Q_snprintf( pszBuffer + nLen, iBuflen - nLen, ":/%s", pszFilePrependName );
  1032. }
  1033. else
  1034. #endif
  1035. {
  1036. Q_snprintf( pszBuffer, iBuflen, "%s/%s", MAP_KEY_FILE_DIR, pszFilePrependName );
  1037. }
  1038. return true;
  1039. }
  1040. #ifdef TF_CLIENT_DLL
  1041. #define MAP_KEY_FILE "viewed.res"
  1042. #else
  1043. #define MAP_KEY_FILE "mapkeys.res"
  1044. #endif
  1045. void UTIL_IncrementMapKey( const char *pszCustomKey )
  1046. {
  1047. #ifdef _X360
  1048. // TODO: controller-specific code required
  1049. return;
  1050. #endif
  1051. int iController = -1;
  1052. if ( !pszCustomKey )
  1053. return;
  1054. char szFilename[ _MAX_PATH ];
  1055. if ( !UTIL_GetMapLoadCountFileName( iController, MAP_KEY_FILE, szFilename, _MAX_PATH ) )
  1056. return;
  1057. int iCount = 1;
  1058. KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE );
  1059. if ( kvMapLoadFile )
  1060. {
  1061. kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" );
  1062. char mapname[MAX_MAP_NAME];
  1063. Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) );
  1064. Q_strlower( mapname );
  1065. // Increment existing, or add a new one
  1066. KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname );
  1067. if ( pMapKey )
  1068. {
  1069. iCount = pMapKey->GetInt( pszCustomKey, 0 ) + 1;
  1070. pMapKey->SetInt( pszCustomKey, iCount );
  1071. }
  1072. else
  1073. {
  1074. KeyValues *pNewKey = new KeyValues( mapname );
  1075. if ( pNewKey )
  1076. {
  1077. pNewKey->SetString( pszCustomKey, "1" );
  1078. kvMapLoadFile->AddSubKey( pNewKey );
  1079. }
  1080. }
  1081. // Write it out
  1082. // force create this directory incase it doesn't exist
  1083. filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD");
  1084. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1085. kvMapLoadFile->RecursiveSaveToFile( buf, 0 );
  1086. g_pFullFileSystem->WriteFile( szFilename, "MOD", buf );
  1087. kvMapLoadFile->deleteThis();
  1088. }
  1089. #ifdef _X360
  1090. if ( xboxsystem )
  1091. {
  1092. xboxsystem->FinishContainerWrites( iController );
  1093. }
  1094. #endif
  1095. }
  1096. int UTIL_GetMapKeyCount( const char *pszCustomKey )
  1097. {
  1098. #ifdef _X360
  1099. // TODO: controller-specific code required
  1100. return 0;
  1101. #endif
  1102. int iController = -1;
  1103. if ( !pszCustomKey )
  1104. return 0;
  1105. char szFilename[ _MAX_PATH ];
  1106. if ( !UTIL_GetMapLoadCountFileName( iController, MAP_KEY_FILE, szFilename, _MAX_PATH ) )
  1107. return 0;
  1108. int iCount = 0;
  1109. KeyValues *kvMapLoadFile = new KeyValues( MAP_KEY_FILE );
  1110. if ( kvMapLoadFile )
  1111. {
  1112. // create an empty file if none exists
  1113. if ( !g_pFullFileSystem->FileExists( szFilename, "MOD" ) )
  1114. {
  1115. // force create this directory incase it doesn't exist
  1116. filesystem->CreateDirHierarchy( MAP_KEY_FILE_DIR, "MOD");
  1117. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1118. g_pFullFileSystem->WriteFile( szFilename, "MOD", buf );
  1119. }
  1120. kvMapLoadFile->LoadFromFile( g_pFullFileSystem, szFilename, "MOD" );
  1121. char mapname[MAX_MAP_NAME];
  1122. Q_FileBase( engine->GetLevelName(), mapname, sizeof( mapname) );
  1123. Q_strlower( mapname );
  1124. KeyValues *pMapKey = kvMapLoadFile->FindKey( mapname );
  1125. if ( pMapKey )
  1126. {
  1127. iCount = pMapKey->GetInt( pszCustomKey );
  1128. }
  1129. kvMapLoadFile->deleteThis();
  1130. }
  1131. return iCount;
  1132. }
  1133. bool UTIL_HasLoadedAnyMap()
  1134. {
  1135. #ifdef _X360
  1136. // TODO: controller-specific code required
  1137. return 0;
  1138. #endif
  1139. int iController = -1;
  1140. char szFilename[ _MAX_PATH ];
  1141. if ( !UTIL_GetMapLoadCountFileName( iController, MAP_KEY_FILE, szFilename, _MAX_PATH ) )
  1142. return false;
  1143. return g_pFullFileSystem->FileExists( szFilename, "MOD" );
  1144. }
  1145. wchar_t *UTIL_GetLocalizedKeyString( const char *command, const char *fmt, const wchar_t *arg1, const wchar_t *arg2, const wchar_t *arg3 )
  1146. {
  1147. static wchar_t useString[4][256];
  1148. static int index = 0;
  1149. index = index + 1;
  1150. if ( index > 3 )
  1151. index = 0;
  1152. const char *lowercaseKey = engine->Key_LookupBinding( command );
  1153. if ( !lowercaseKey )
  1154. {
  1155. lowercaseKey = "<NOT BOUND>";
  1156. }
  1157. char szKey[64];
  1158. V_strncpy( szKey, lowercaseKey, sizeof( szKey ) );
  1159. for ( char *tmp = szKey; *tmp; ++tmp )
  1160. {
  1161. *tmp = toupper( *tmp );
  1162. }
  1163. wchar_t wszKey[64];
  1164. g_pVGuiLocalize->ConvertANSIToUnicode( szKey, wszKey, sizeof(wszKey) );
  1165. int argCount = 1;
  1166. if ( arg1 )
  1167. {
  1168. ++argCount;
  1169. if ( arg2 )
  1170. {
  1171. ++argCount;
  1172. if ( arg3 )
  1173. {
  1174. ++argCount;
  1175. }
  1176. }
  1177. }
  1178. g_pVGuiLocalize->ConstructString( useString[index], sizeof( useString[index] ), g_pVGuiLocalize->Find( fmt ), argCount, wszKey, arg1, arg2, arg3 );
  1179. return useString[index];
  1180. }
  1181. void UTIL_GetClientStatusText( char *buffer, int nSize )
  1182. {
  1183. if ( !buffer || nSize==0 ) {return;}
  1184. buffer[0] = 0;
  1185. #if defined ( CSTRIKE15 )
  1186. extern float g_flReadyToCheckForPCBootInvite;
  1187. bool bStartupFinished = g_flReadyToCheckForPCBootInvite && ( ( Plat_FloatTime() - g_flReadyToCheckForPCBootInvite ) > 1.5f );
  1188. if ( bStartupFinished )
  1189. Q_snprintf( buffer, nSize, "+" );
  1190. if ( nSize <= 2 )
  1191. return;
  1192. C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
  1193. if (pCSPR)
  1194. {
  1195. Q_snprintf( buffer, nSize, "%sPlayers: ", ( bStartupFinished ? "+" : "" ) );
  1196. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  1197. {
  1198. if ( pCSPR->IsConnected(i) )
  1199. {
  1200. const char *name = pCSPR->GetPlayerName(i);
  1201. if (name && name[0])
  1202. {
  1203. V_strncat( buffer, name, nSize );
  1204. V_strncat( buffer, ", ", nSize );
  1205. }
  1206. }
  1207. }
  1208. buffer[nSize-1]=0;
  1209. }
  1210. #endif
  1211. }
  1212. void UTIL_ClearTrace( trace_t &trace )
  1213. {
  1214. memset( &trace, 0, sizeof(trace));
  1215. trace.fraction = 1.f;
  1216. trace.fractionleftsolid = 0;
  1217. trace.surface = g_NullSurface;
  1218. }
  1219. //-----------------------------------------------------------------------------
  1220. // Also in cdll so linked libs can extern it
  1221. //-----------------------------------------------------------------------------
  1222. bool UTIL_IsDedicatedServer( void )
  1223. {
  1224. return false;
  1225. }