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.

637 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #ifdef GAME_DLL
  8. #include "gamestats.h"
  9. #else
  10. #include "tf_hud_statpanel.h"
  11. #endif
  12. #include "tf_gamestats_shared.h"
  13. #ifndef NO_STEAM
  14. #include "steamworks_gamestats.h"
  15. #endif
  16. int TF_Gamestats_RoundStats_t::m_iNumRounds = 0;
  17. time_t TF_Gamestats_RoundStats_t::m_iRoundStartTime = 0;
  18. //-----------------------------------------------------------------------------
  19. const char *s_pStatStrings[ TFSTAT_TOTAL ] =
  20. {
  21. "TFSTAT_UNDEFINED",
  22. "TFSTAT_SHOTS_HIT",
  23. "TFSTAT_SHOTS_FIRED",
  24. "TFSTAT_KILLS",
  25. "TFSTAT_DEATHS",
  26. "TFSTAT_DAMAGE",
  27. "TFSTAT_CAPTURES",
  28. "TFSTAT_DEFENSES",
  29. "TFSTAT_DOMINATIONS",
  30. "TFSTAT_REVENGE",
  31. "TFSTAT_POINTSSCORED",
  32. "TFSTAT_BUILDINGSDESTROYED",
  33. "TFSTAT_HEADSHOTS",
  34. "TFSTAT_PLAYTIME",
  35. "TFSTAT_HEALING",
  36. "TFSTAT_INVULNS",
  37. "TFSTAT_KILLASSISTS",
  38. "TFSTAT_BACKSTABS",
  39. "TFSTAT_HEALTHLEACHED",
  40. "TFSTAT_BUILDINGSBUILT",
  41. "TFSTAT_MAXSENTRYKILLS",
  42. "TFSTAT_TELEPORTS",
  43. "TFSTAT_FIREDAMAGE",
  44. "TFSTAT_BONUS_POINTS",
  45. "TFSTAT_BLASTDAMAGE",
  46. "TFSTAT_DAMAGETAKEN",
  47. "TFSTAT_HEALTHKITS",
  48. "TFSTAT_AMMOKITS",
  49. "TFSTAT_CLASSCHANGES",
  50. "TFSTAT_CRITS",
  51. "TFSTAT_SUICIDES",
  52. "TFSTAT_CURRENCY_COLLECTED",
  53. "TFSTAT_DAMAGE_ASSIST",
  54. "TFSTAT_HEALING_ASSIST",
  55. "TFSTAT_DAMAGE_BOSS",
  56. "TFSTAT_DAMAGE_BLOCKED",
  57. "TFSTAT_DAMAGE_RANGED",
  58. "TFSTAT_DAMAGE_RANGED_CRIT_RANDOM",
  59. "TFSTAT_DAMAGE_RANGED_CRIT_BOOSTED",
  60. "TFSTAT_REVIVED",
  61. };
  62. const char *s_pMapStatStrings[ TFMAPSTAT_TOTAL ] =
  63. {
  64. "TFSTAT_UNDEFINED",
  65. "TFSTAT_PLAYTIME",
  66. };
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Constructor
  69. // Input : -
  70. //-----------------------------------------------------------------------------
  71. TF_Gamestats_LevelStats_t::TF_Gamestats_LevelStats_t()
  72. {
  73. m_bInitialized = false;
  74. m_iRoundStartTime = 0;
  75. m_flRoundStartTime = 0;
  76. m_Header.m_iRoundsPlayed = 0;
  77. m_Header.m_iTotalTime = 0;
  78. m_Header.m_iBlueWins = 0;
  79. m_Header.m_iRedWins = 0;
  80. m_Header.m_iStalemates = 0;
  81. m_Header.m_iBlueSuddenDeathWins = 0;
  82. m_Header.m_iRedSuddenDeathWins = 0;
  83. Q_memset( m_aClassStats, 0, sizeof( m_aClassStats ) );
  84. Q_memset( m_aWeaponStats, 0, sizeof( m_aWeaponStats ) );
  85. Q_memset( m_iPeakPlayerCount, 0, sizeof( m_iPeakPlayerCount ) );
  86. for ( int i = 0; i <= MAX_CONTROL_POINTS; i++ )
  87. {
  88. m_Header.m_iLastCapChangedInRound[i] = 0;
  89. }
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: Destructor
  93. // Input : -
  94. //-----------------------------------------------------------------------------
  95. TF_Gamestats_LevelStats_t::~TF_Gamestats_LevelStats_t()
  96. {
  97. //m_aPlayerDeaths.Purge();
  98. //m_aPlayerDamage.Purge();
  99. m_bIsRealServer = false;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: Copy constructor
  103. // Input : -
  104. //-----------------------------------------------------------------------------
  105. TF_Gamestats_LevelStats_t::TF_Gamestats_LevelStats_t( const TF_Gamestats_LevelStats_t &stats )
  106. {
  107. m_bInitialized = stats.m_bInitialized;
  108. m_iRoundStartTime = stats.m_iRoundStartTime;
  109. m_flRoundStartTime = stats.m_flRoundStartTime;
  110. m_iMapStartTime = stats.m_iMapStartTime;
  111. m_Header = stats.m_Header;
  112. m_bIsRealServer = stats.m_bIsRealServer;
  113. //m_aPlayerDeaths = stats.m_aPlayerDeaths;
  114. //m_aPlayerDamage = stats.m_aPlayerDamage;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. // Input : *pszMapName -
  119. // nIPAddr -
  120. // nPort -
  121. // flStartTime -
  122. //-----------------------------------------------------------------------------
  123. void TF_Gamestats_LevelStats_t::Init( const char *pszMapName, int nMapRevision, int nIPAddr, short nPort, float flStartTime )
  124. {
  125. Q_memset( &m_Header, 0, sizeof( m_Header ) ); // TODO: This is correct for steamworks stats, but probably breaks old stats!!!
  126. V_FileBase( pszMapName, m_Header.m_szMapName, sizeof( m_Header.m_szMapName ) );
  127. m_Header.m_nMapRevision = nMapRevision;
  128. m_Header.m_nIPAddr = nIPAddr;
  129. m_Header.m_nPort = nPort;
  130. #ifndef NO_STEAM
  131. // Start the level timer.
  132. m_iMapStartTime = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
  133. m_iRoundStartTime = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
  134. m_flRoundStartTime = gpGlobals->curtime;
  135. #endif
  136. m_bIsRealServer = false;
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose:
  140. // Input : flEndTime -
  141. //-----------------------------------------------------------------------------
  142. void TF_Gamestats_LevelStats_t::Shutdown( float flEndTime )
  143. {
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose: Constructor
  147. // Input : -
  148. //-----------------------------------------------------------------------------
  149. TF_Gamestats_RoundStats_t::TF_Gamestats_RoundStats_t()
  150. {
  151. Reset();
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Destructor
  155. // Input : -
  156. //-----------------------------------------------------------------------------
  157. TF_Gamestats_RoundStats_t::~TF_Gamestats_RoundStats_t()
  158. {
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose: resets the state of stat tracking
  162. //-----------------------------------------------------------------------------
  163. void TF_Gamestats_RoundStats_t::Reset()
  164. {
  165. ResetSummary();
  166. m_iRoundStartTime = 0.f;
  167. }
  168. //-----------------------------------------------------------------------------
  169. // Purpose:
  170. //-----------------------------------------------------------------------------
  171. void TF_Gamestats_RoundStats_t::ResetSummary()
  172. {
  173. Q_memset( &m_Summary, 0, sizeof( m_Summary ) );
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose: Constructor
  177. // Input : -
  178. //-----------------------------------------------------------------------------
  179. TF_Gamestats_KillStats_t::TF_Gamestats_KillStats_t()
  180. {
  181. Reset();
  182. }
  183. //-----------------------------------------------------------------------------
  184. // Purpose: Destructor
  185. // Input : -
  186. //-----------------------------------------------------------------------------
  187. TF_Gamestats_KillStats_t::~TF_Gamestats_KillStats_t()
  188. {
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose: resets the state of stat tracking
  192. //-----------------------------------------------------------------------------
  193. void TF_Gamestats_KillStats_t::Reset()
  194. {
  195. // Q_memset( &m_Summary, 0, sizeof( m_Summary ) );
  196. // m_flRoundStartTime = 0.f;
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose: constructor
  200. //-----------------------------------------------------------------------------
  201. TFReportedStats_t::TFReportedStats_t()
  202. {
  203. Clear();
  204. m_bValidData = false;
  205. m_pCurrentGame = NULL;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: destructor
  209. //-----------------------------------------------------------------------------
  210. TFReportedStats_t::~TFReportedStats_t()
  211. {
  212. if ( m_pCurrentGame )
  213. {
  214. delete m_pCurrentGame;
  215. m_pCurrentGame = NULL;
  216. }
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: Clears data
  220. //-----------------------------------------------------------------------------
  221. void TFReportedStats_t::Clear()
  222. {
  223. m_pCurrentGame = NULL;
  224. m_dictMapStats.Purge();
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. // Input : *szMapName -
  229. // Output : TF_Gamestats_LevelStats_t
  230. //-----------------------------------------------------------------------------
  231. TF_Gamestats_LevelStats_t *TFReportedStats_t::FindOrAddMapStats( const char *szMapName )
  232. {
  233. int iMap = m_dictMapStats.Find( szMapName );
  234. if( iMap == m_dictMapStats.InvalidIndex() )
  235. {
  236. iMap = m_dictMapStats.Insert( szMapName );
  237. }
  238. return &m_dictMapStats[iMap];
  239. }
  240. #ifdef GAME_DLL
  241. //-----------------------------------------------------------------------------
  242. // Purpose: Saves data to buffer
  243. //-----------------------------------------------------------------------------
  244. void TFReportedStats_t::AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer )
  245. {
  246. // save a version lump at beginning of file
  247. TF_Gamestats_Version_t versionLump;
  248. versionLump.m_iMagic = TF_GAMESTATS_MAGIC;
  249. versionLump.m_iVersion = TF_GAMESTATS_FILE_VERSION;
  250. CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_VERSION, 1, sizeof( versionLump ), &versionLump );
  251. // Save data per map.
  252. for ( int iMap = m_dictMapStats.First(); iMap != m_dictMapStats.InvalidIndex(); iMap = m_dictMapStats.Next( iMap ) )
  253. {
  254. // Get the current map.
  255. TF_Gamestats_LevelStats_t *pCurrentMap = &m_dictMapStats[iMap];
  256. Assert( pCurrentMap );
  257. // Write out the lumps.
  258. CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_MAPHEADER, 1, sizeof( TF_Gamestats_LevelStats_t::LevelHeader_t ), static_cast<void*>( &pCurrentMap->m_Header ) );
  259. //CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_MAPDEATH, pCurrentMap->m_aPlayerDeaths.Count(), sizeof( TF_Gamestats_LevelStats_t::PlayerDeathsLump_t ), static_cast<void*>( pCurrentMap->m_aPlayerDeaths.Base() ) );
  260. //CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_MAPDAMAGE, pCurrentMap->m_aPlayerDamage.Count(), sizeof( TF_Gamestats_LevelStats_t::PlayerDamageLump_t ), static_cast<void*>( pCurrentMap->m_aPlayerDamage.Base() ) );
  261. CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_CLASS, ARRAYSIZE( pCurrentMap->m_aClassStats ), sizeof( pCurrentMap->m_aClassStats[0] ),
  262. static_cast<void*>( pCurrentMap->m_aClassStats ) );
  263. CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_WEAPON, ARRAYSIZE( pCurrentMap->m_aWeaponStats ), sizeof( pCurrentMap->m_aWeaponStats[0] ),
  264. static_cast<void*>( pCurrentMap->m_aWeaponStats ) );
  265. }
  266. // Append an end tag to verify we've reached end of file and data was sane. (Sometimes we receive stat files that start sane but become filled
  267. // with garbage partway through.)
  268. CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_ENDTAG, 1, sizeof( versionLump ), &versionLump );
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Purpose: Loads data from buffer
  272. //-----------------------------------------------------------------------------
  273. bool TFReportedStats_t::LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer )
  274. {
  275. // read the version lump of beginning of file and verify version
  276. bool bGotEndTag = false;
  277. unsigned short iLump = 0;
  278. unsigned short iLumpCount = 0;
  279. if ( !CBaseGameStats::GetLumpHeader( MAX_LUMP_COUNT, LoadBuffer, iLump, iLumpCount ) )
  280. return false;
  281. if ( iLump != TFSTATS_LUMP_VERSION )
  282. {
  283. Msg( "Didn't find version header. Expected lump type TFSTATS_LUMP_VERSION, got lump type %d. Skipping file.\n", iLump );
  284. return false;
  285. }
  286. TF_Gamestats_Version_t versionLump;
  287. CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( versionLump ), &versionLump );
  288. if ( versionLump.m_iMagic != TF_GAMESTATS_MAGIC )
  289. {
  290. Msg( "Incorrect magic # in version header. Expected %x, got %x. Skipping file.\n", TF_GAMESTATS_MAGIC, versionLump.m_iMagic );
  291. return false;
  292. }
  293. if ( versionLump.m_iVersion != TF_GAMESTATS_FILE_VERSION )
  294. {
  295. Msg( "Mismatched file version. Expected file version %d, got %d. Skipping file.\n", TF_GAMESTATS_FILE_VERSION, versionLump.m_iVersion );
  296. return false;
  297. }
  298. TF_Gamestats_LevelStats_t *pCurrentGame = NULL;
  299. // read all the lumps in the file
  300. while( CBaseGameStats::GetLumpHeader( MAX_LUMP_COUNT, LoadBuffer, iLump, iLumpCount ) )
  301. {
  302. switch ( iLump )
  303. {
  304. case TFSTATS_LUMP_MAPHEADER:
  305. {
  306. TF_Gamestats_LevelStats_t::LevelHeader_t header;
  307. CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::LevelHeader_t ), &header );
  308. // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
  309. if ( ( header.m_iRoundsPlayed < 0 ) || ( header.m_iTotalTime < 0 ) || ( header.m_iRoundsPlayed > 1000 ) )
  310. return false;
  311. // if there's no interesting data, skip this file. (Need to have server not send it in this case.)
  312. if ( header.m_iTotalTime == 0 )
  313. return false;
  314. pCurrentGame = FindOrAddMapStats( header.m_szMapName );
  315. if ( pCurrentGame )
  316. {
  317. pCurrentGame->m_Header = header;
  318. }
  319. break;
  320. }
  321. case TFSTATS_LUMP_MAPDEATH:
  322. {
  323. //CUtlVector<TF_Gamestats_LevelStats_t::PlayerDeathsLump_t> playerDeaths;
  324. //playerDeaths.SetCount( iLumpCount );
  325. //CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::PlayerDeathsLump_t ), static_cast<void*>( playerDeaths.Base() ) );
  326. //if ( pCurrentGame )
  327. //{
  328. // pCurrentGame->m_aPlayerDeaths = playerDeaths;
  329. //}
  330. break;
  331. }
  332. case TFSTATS_LUMP_MAPDAMAGE:
  333. {
  334. //CUtlVector<TF_Gamestats_LevelStats_t::PlayerDamageLump_t> playerDamage;
  335. //playerDamage.SetCount( iLumpCount );
  336. //CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::PlayerDamageLump_t ), static_cast<void*>( playerDamage.Base() ) );
  337. //if ( pCurrentGame )
  338. //{
  339. // pCurrentGame->m_aPlayerDamage = playerDamage;
  340. //}
  341. break;
  342. }
  343. case TFSTATS_LUMP_CLASS:
  344. {
  345. Assert( pCurrentGame );
  346. if ( !pCurrentGame )
  347. return false;
  348. Assert ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aClassStats ) );
  349. if ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aClassStats ) )
  350. {
  351. CBaseGameStats::LoadLump( LoadBuffer, ARRAYSIZE( pCurrentGame->m_aClassStats ), sizeof( pCurrentGame->m_aClassStats[0] ),
  352. pCurrentGame->m_aClassStats );
  353. // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
  354. for ( int i = 0; i < ARRAYSIZE( pCurrentGame->m_aClassStats ); i++ )
  355. {
  356. TF_Gamestats_ClassStats_t &classStats = pCurrentGame->m_aClassStats[i];
  357. if ( ( classStats.iSpawns < 0 ) || ( classStats.iSpawns > 10000 ) || ( classStats.iTotalTime < 0 ) || ( classStats.iTotalTime > 36000 * 20 ) ||
  358. ( classStats.iKills < 0 ) || ( classStats.iKills > 10000 ) )
  359. {
  360. return false;
  361. }
  362. }
  363. }
  364. else
  365. {
  366. // mismatched lump size, possibly from different build, don't know how it interpret it, just skip over it
  367. return false;
  368. }
  369. break;
  370. }
  371. case TFSTATS_LUMP_WEAPON:
  372. {
  373. Assert( pCurrentGame );
  374. if ( !pCurrentGame )
  375. return false;
  376. Assert ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aWeaponStats ) );
  377. if ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aWeaponStats ) )
  378. {
  379. CBaseGameStats::LoadLump( LoadBuffer, ARRAYSIZE( pCurrentGame->m_aWeaponStats ), sizeof( pCurrentGame->m_aWeaponStats[0] ),
  380. pCurrentGame->m_aWeaponStats );
  381. // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
  382. if ( ( pCurrentGame->m_aWeaponStats[TF_WEAPON_MEDIGUN].iShotsFired < 0 ) || ( pCurrentGame->m_aWeaponStats[TF_WEAPON_MEDIGUN].iShotsFired > 100000 )
  383. || ( pCurrentGame->m_aWeaponStats[TF_WEAPON_FLAMETHROWER_ROCKET].iShotsFired != 0 ) ) // check that unused weapon has 0 shots
  384. {
  385. return false;
  386. }
  387. }
  388. else
  389. {
  390. // mismatched lump size, possibly from different build, don't know how it interpret it, just skip over it
  391. return false;
  392. }
  393. break;
  394. }
  395. case TFSTATS_LUMP_ENDTAG:
  396. {
  397. // check that end tag is valid -- should be version lump again
  398. TF_Gamestats_Version_t versionLump;
  399. CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( versionLump ), &versionLump );
  400. if ( versionLump.m_iMagic != TF_GAMESTATS_MAGIC )
  401. {
  402. Msg( "Incorrect magic # in version header. Expected %x, got %x. Skipping file.\n", TF_GAMESTATS_MAGIC, versionLump.m_iMagic );
  403. return false;
  404. }
  405. if ( versionLump.m_iVersion != TF_GAMESTATS_FILE_VERSION )
  406. {
  407. Msg( "Mismatched file version. Expected file version %d, got %d. Skipping file.\n", TF_GAMESTATS_FILE_VERSION, versionLump.m_iVersion );
  408. return false;
  409. }
  410. bGotEndTag = true;
  411. break;
  412. }
  413. }
  414. }
  415. return bGotEndTag;
  416. }
  417. #endif
  418. //-----------------------------------------------------------------------------
  419. // TF2 Beta Maps
  420. // Robot Destruction
  421. //-----------------------------------------------------------------------------
  422. RobotDestructionStats_t::RobotDestructionStats_t()
  423. {
  424. Clear();
  425. }
  426. //-----------------------------------------------------------------------------
  427. void RobotDestructionStats_t::Clear()
  428. {
  429. V_memset( &iRobotInteraction, 0, sizeof( iRobotInteraction ) );
  430. V_memset( &iRobotCoreInteraction, 0, sizeof( iRobotCoreInteraction ) );
  431. V_memset( &iFlagInteraction, 0, sizeof( iFlagInteraction ) );
  432. V_memset( &iCoresCollectedByTeam, 0, sizeof( iCoresCollectedByTeam ) );
  433. V_memset( &iCoreCollectedByClass, 0, sizeof( iCoreCollectedByClass ) );
  434. V_memset( &iBlueRobotsKilledByType, 0, sizeof( iBlueRobotsKilledByType ) );
  435. V_memset( &iRedRobotsKilledByType, 0, sizeof( iRedRobotsKilledByType ) );
  436. V_memset( &iRobotsDamageFromClass, 0, sizeof( iRobotsDamageFromClass ) );
  437. }
  438. //-----------------------------------------------------------------------------
  439. int RobotDestructionStats_t::GetRobotInteractionCount()
  440. {
  441. int iCount = 0;
  442. for ( int i = 1; i < MAX_PLAYERS; ++i )
  443. {
  444. if ( iRobotInteraction[i] )
  445. {
  446. iCount++;
  447. }
  448. }
  449. return iCount;
  450. }
  451. //-----------------------------------------------------------------------------
  452. int RobotDestructionStats_t::GetRobotCoreInteractionCount()
  453. {
  454. int iCount = 0;
  455. for ( int i = 1; i < MAX_PLAYERS; ++i )
  456. {
  457. if ( iRobotCoreInteraction[i] )
  458. {
  459. iCount++;
  460. }
  461. }
  462. return iCount;
  463. }
  464. //-----------------------------------------------------------------------------
  465. int RobotDestructionStats_t::GetFlagInteractionCount()
  466. {
  467. int iCount = 0;
  468. for ( int i = 1; i < MAX_PLAYERS; ++i )
  469. {
  470. if ( iFlagInteraction[i] )
  471. {
  472. iCount++;
  473. }
  474. }
  475. return iCount;
  476. }
  477. //-----------------------------------------------------------------------------
  478. const char* g_aRoundEndReasons[] =
  479. {
  480. "round_end",
  481. "client_disconnect",
  482. "client_quit",
  483. "server_map_change",
  484. "server_shutdown",
  485. "time_limit_reached",
  486. "win_limit_reached",
  487. "win_diff_limit_reached",
  488. "round_limit_reached",
  489. "next_level_cvar",
  490. };
  491. // Get a string describing the current game type.
  492. const char* GetGameTypeID()
  493. {
  494. ConVarRef tf_gamemode_arena( "tf_gamemode_arena" );
  495. ConVarRef tf_gamemode_cp( "tf_gamemode_cp" );
  496. ConVarRef tf_gamemode_ctf( "tf_gamemode_ctf" );
  497. ConVarRef tf_gamemode_sd( "tf_gamemode_sd" );
  498. ConVarRef tf_gamemode_payload( "tf_gamemode_payload" );
  499. ConVarRef tf_gamemode_mvm( "tf_gamemode_mvm" );
  500. ConVarRef tf_powerup_mode( "tf_powerup_mode" );
  501. ConVarRef tf_gamemode_passtime( "tf_gamemode_passtime" );
  502. const char* pszGameTypeID = NULL;
  503. if ( tf_gamemode_arena.GetBool() )
  504. {
  505. pszGameTypeID = "arena";
  506. }
  507. else if ( tf_gamemode_cp.GetBool() )
  508. {
  509. pszGameTypeID = "cp";
  510. }
  511. else if ( tf_gamemode_ctf.GetBool() )
  512. {
  513. if ( tf_powerup_mode.GetBool() )
  514. {
  515. pszGameTypeID = "ctf_mannpower";
  516. }
  517. else
  518. {
  519. pszGameTypeID = "ctf";
  520. }
  521. }
  522. else if ( tf_gamemode_sd.GetBool() )
  523. {
  524. pszGameTypeID = "sd";
  525. }
  526. else if ( tf_gamemode_payload.GetBool() )
  527. {
  528. pszGameTypeID = "payload";
  529. }
  530. else if ( tf_gamemode_mvm.GetBool() )
  531. {
  532. pszGameTypeID = "mvm";
  533. }
  534. else if ( tf_gamemode_passtime.GetBool() )
  535. {
  536. pszGameTypeID = "pass"; // intentionally not "passtime"
  537. }
  538. else
  539. {
  540. pszGameTypeID = "custom";
  541. }
  542. return pszGameTypeID;
  543. }
  544. //-----------------------------------------------------------------------------
  545. // TF2 Beta Maps
  546. // Passtime
  547. //-----------------------------------------------------------------------------
  548. void PasstimeStats_t::Clear()
  549. {
  550. memset( &summary, 0, sizeof(summary) );
  551. memset( &classes, 0, sizeof(classes) );
  552. }
  553. //-----------------------------------------------------------------------------
  554. void PasstimeStats_t::AddBallFracSample( float f )
  555. {
  556. Assert( f >= 0 && f <= 1.0f );
  557. int iBin = (uint8) Floor2Int( f * 255 );
  558. summary.nBallFracHistSum += iBin;
  559. ++summary.arrBallFracHist[ iBin ];
  560. ++summary.nBallFracSampleCount;
  561. }
  562. //-----------------------------------------------------------------------------
  563. void PasstimeStats_t::AddPassTravelDistSample( float f )
  564. {
  565. if ( summary.nPassTravelDistSampleCount >= summary.k_nMaxPassTravelDistSamples )
  566. return;
  567. Assert( f >= 0 );
  568. summary.arrPassTravelDistSamples[ summary.nPassTravelDistSampleCount ] = (uint16) Float2Int( f );
  569. ++summary.nPassTravelDistSampleCount;
  570. }
  571. #ifdef CLIENT_DLL
  572. MapStats_t &GetMapStats( map_identifier_t iMapID )
  573. {
  574. return CTFStatPanel::GetMapStats( iMapID );
  575. }
  576. #endif