summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_gamestats_shared.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_gamestats_shared.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf/tf_gamestats_shared.cpp')
-rw-r--r--game/shared/tf/tf_gamestats_shared.cpp637
1 files changed, 637 insertions, 0 deletions
diff --git a/game/shared/tf/tf_gamestats_shared.cpp b/game/shared/tf/tf_gamestats_shared.cpp
new file mode 100644
index 0000000..80dad37
--- /dev/null
+++ b/game/shared/tf/tf_gamestats_shared.cpp
@@ -0,0 +1,637 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#ifdef GAME_DLL
+ #include "gamestats.h"
+#else
+ #include "tf_hud_statpanel.h"
+#endif
+#include "tf_gamestats_shared.h"
+
+#ifndef NO_STEAM
+#include "steamworks_gamestats.h"
+#endif
+
+int TF_Gamestats_RoundStats_t::m_iNumRounds = 0;
+time_t TF_Gamestats_RoundStats_t::m_iRoundStartTime = 0;
+
+//-----------------------------------------------------------------------------
+
+const char *s_pStatStrings[ TFSTAT_TOTAL ] =
+{
+ "TFSTAT_UNDEFINED",
+ "TFSTAT_SHOTS_HIT",
+ "TFSTAT_SHOTS_FIRED",
+ "TFSTAT_KILLS",
+ "TFSTAT_DEATHS",
+ "TFSTAT_DAMAGE",
+ "TFSTAT_CAPTURES",
+ "TFSTAT_DEFENSES",
+ "TFSTAT_DOMINATIONS",
+ "TFSTAT_REVENGE",
+ "TFSTAT_POINTSSCORED",
+ "TFSTAT_BUILDINGSDESTROYED",
+ "TFSTAT_HEADSHOTS",
+ "TFSTAT_PLAYTIME",
+ "TFSTAT_HEALING",
+ "TFSTAT_INVULNS",
+ "TFSTAT_KILLASSISTS",
+ "TFSTAT_BACKSTABS",
+ "TFSTAT_HEALTHLEACHED",
+ "TFSTAT_BUILDINGSBUILT",
+ "TFSTAT_MAXSENTRYKILLS",
+ "TFSTAT_TELEPORTS",
+ "TFSTAT_FIREDAMAGE",
+ "TFSTAT_BONUS_POINTS",
+ "TFSTAT_BLASTDAMAGE",
+ "TFSTAT_DAMAGETAKEN",
+ "TFSTAT_HEALTHKITS",
+ "TFSTAT_AMMOKITS",
+ "TFSTAT_CLASSCHANGES",
+ "TFSTAT_CRITS",
+ "TFSTAT_SUICIDES",
+ "TFSTAT_CURRENCY_COLLECTED",
+ "TFSTAT_DAMAGE_ASSIST",
+ "TFSTAT_HEALING_ASSIST",
+ "TFSTAT_DAMAGE_BOSS",
+ "TFSTAT_DAMAGE_BLOCKED",
+ "TFSTAT_DAMAGE_RANGED",
+ "TFSTAT_DAMAGE_RANGED_CRIT_RANDOM",
+ "TFSTAT_DAMAGE_RANGED_CRIT_BOOSTED",
+ "TFSTAT_REVIVED",
+};
+
+const char *s_pMapStatStrings[ TFMAPSTAT_TOTAL ] =
+{
+ "TFSTAT_UNDEFINED",
+ "TFSTAT_PLAYTIME",
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_LevelStats_t::TF_Gamestats_LevelStats_t()
+{
+ m_bInitialized = false;
+ m_iRoundStartTime = 0;
+ m_flRoundStartTime = 0;
+ m_Header.m_iRoundsPlayed = 0;
+ m_Header.m_iTotalTime = 0;
+ m_Header.m_iBlueWins = 0;
+ m_Header.m_iRedWins = 0;
+ m_Header.m_iStalemates = 0;
+ m_Header.m_iBlueSuddenDeathWins = 0;
+ m_Header.m_iRedSuddenDeathWins = 0;
+ Q_memset( m_aClassStats, 0, sizeof( m_aClassStats ) );
+ Q_memset( m_aWeaponStats, 0, sizeof( m_aWeaponStats ) );
+ Q_memset( m_iPeakPlayerCount, 0, sizeof( m_iPeakPlayerCount ) );
+
+ for ( int i = 0; i <= MAX_CONTROL_POINTS; i++ )
+ {
+ m_Header.m_iLastCapChangedInRound[i] = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_LevelStats_t::~TF_Gamestats_LevelStats_t()
+{
+ //m_aPlayerDeaths.Purge();
+ //m_aPlayerDamage.Purge();
+ m_bIsRealServer = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Copy constructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_LevelStats_t::TF_Gamestats_LevelStats_t( const TF_Gamestats_LevelStats_t &stats )
+{
+ m_bInitialized = stats.m_bInitialized;
+ m_iRoundStartTime = stats.m_iRoundStartTime;
+ m_flRoundStartTime = stats.m_flRoundStartTime;
+ m_iMapStartTime = stats.m_iMapStartTime;
+ m_Header = stats.m_Header;
+ m_bIsRealServer = stats.m_bIsRealServer;
+ //m_aPlayerDeaths = stats.m_aPlayerDeaths;
+ //m_aPlayerDamage = stats.m_aPlayerDamage;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pszMapName -
+// nIPAddr -
+// nPort -
+// flStartTime -
+//-----------------------------------------------------------------------------
+void TF_Gamestats_LevelStats_t::Init( const char *pszMapName, int nMapRevision, int nIPAddr, short nPort, float flStartTime )
+{
+ Q_memset( &m_Header, 0, sizeof( m_Header ) ); // TODO: This is correct for steamworks stats, but probably breaks old stats!!!
+
+ V_FileBase( pszMapName, m_Header.m_szMapName, sizeof( m_Header.m_szMapName ) );
+
+ m_Header.m_nMapRevision = nMapRevision;
+ m_Header.m_nIPAddr = nIPAddr;
+ m_Header.m_nPort = nPort;
+
+#ifndef NO_STEAM
+ // Start the level timer.
+ m_iMapStartTime = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
+ m_iRoundStartTime = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
+ m_flRoundStartTime = gpGlobals->curtime;
+#endif
+
+ m_bIsRealServer = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flEndTime -
+//-----------------------------------------------------------------------------
+void TF_Gamestats_LevelStats_t::Shutdown( float flEndTime )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_RoundStats_t::TF_Gamestats_RoundStats_t()
+{
+ Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_RoundStats_t::~TF_Gamestats_RoundStats_t()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: resets the state of stat tracking
+//-----------------------------------------------------------------------------
+void TF_Gamestats_RoundStats_t::Reset()
+{
+ ResetSummary();
+ m_iRoundStartTime = 0.f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void TF_Gamestats_RoundStats_t::ResetSummary()
+{
+ Q_memset( &m_Summary, 0, sizeof( m_Summary ) );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_KillStats_t::TF_Gamestats_KillStats_t()
+{
+ Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+// Input : -
+//-----------------------------------------------------------------------------
+TF_Gamestats_KillStats_t::~TF_Gamestats_KillStats_t()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: resets the state of stat tracking
+//-----------------------------------------------------------------------------
+void TF_Gamestats_KillStats_t::Reset()
+{
+// Q_memset( &m_Summary, 0, sizeof( m_Summary ) );
+// m_flRoundStartTime = 0.f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+TFReportedStats_t::TFReportedStats_t()
+{
+ Clear();
+ m_bValidData = false;
+ m_pCurrentGame = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+TFReportedStats_t::~TFReportedStats_t()
+{
+ if ( m_pCurrentGame )
+ {
+ delete m_pCurrentGame;
+ m_pCurrentGame = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clears data
+//-----------------------------------------------------------------------------
+void TFReportedStats_t::Clear()
+{
+ m_pCurrentGame = NULL;
+ m_dictMapStats.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *szMapName -
+// Output : TF_Gamestats_LevelStats_t
+//-----------------------------------------------------------------------------
+TF_Gamestats_LevelStats_t *TFReportedStats_t::FindOrAddMapStats( const char *szMapName )
+{
+ int iMap = m_dictMapStats.Find( szMapName );
+ if( iMap == m_dictMapStats.InvalidIndex() )
+ {
+ iMap = m_dictMapStats.Insert( szMapName );
+ }
+
+ return &m_dictMapStats[iMap];
+}
+
+#ifdef GAME_DLL
+//-----------------------------------------------------------------------------
+// Purpose: Saves data to buffer
+//-----------------------------------------------------------------------------
+void TFReportedStats_t::AppendCustomDataToSaveBuffer( CUtlBuffer &SaveBuffer )
+{
+ // save a version lump at beginning of file
+ TF_Gamestats_Version_t versionLump;
+ versionLump.m_iMagic = TF_GAMESTATS_MAGIC;
+ versionLump.m_iVersion = TF_GAMESTATS_FILE_VERSION;
+ CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_VERSION, 1, sizeof( versionLump ), &versionLump );
+
+ // Save data per map.
+ for ( int iMap = m_dictMapStats.First(); iMap != m_dictMapStats.InvalidIndex(); iMap = m_dictMapStats.Next( iMap ) )
+ {
+ // Get the current map.
+ TF_Gamestats_LevelStats_t *pCurrentMap = &m_dictMapStats[iMap];
+ Assert( pCurrentMap );
+
+ // Write out the lumps.
+ CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_MAPHEADER, 1, sizeof( TF_Gamestats_LevelStats_t::LevelHeader_t ), static_cast<void*>( &pCurrentMap->m_Header ) );
+ //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() ) );
+ //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() ) );
+ CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_CLASS, ARRAYSIZE( pCurrentMap->m_aClassStats ), sizeof( pCurrentMap->m_aClassStats[0] ),
+ static_cast<void*>( pCurrentMap->m_aClassStats ) );
+ CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_WEAPON, ARRAYSIZE( pCurrentMap->m_aWeaponStats ), sizeof( pCurrentMap->m_aWeaponStats[0] ),
+ static_cast<void*>( pCurrentMap->m_aWeaponStats ) );
+ }
+
+ // 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
+ // with garbage partway through.)
+ CBaseGameStats::AppendLump( MAX_LUMP_COUNT, SaveBuffer, TFSTATS_LUMP_ENDTAG, 1, sizeof( versionLump ), &versionLump );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads data from buffer
+//-----------------------------------------------------------------------------
+bool TFReportedStats_t::LoadCustomDataFromBuffer( CUtlBuffer &LoadBuffer )
+{
+ // read the version lump of beginning of file and verify version
+ bool bGotEndTag = false;
+ unsigned short iLump = 0;
+ unsigned short iLumpCount = 0;
+ if ( !CBaseGameStats::GetLumpHeader( MAX_LUMP_COUNT, LoadBuffer, iLump, iLumpCount ) )
+ return false;
+ if ( iLump != TFSTATS_LUMP_VERSION )
+ {
+ Msg( "Didn't find version header. Expected lump type TFSTATS_LUMP_VERSION, got lump type %d. Skipping file.\n", iLump );
+ return false;
+ }
+ TF_Gamestats_Version_t versionLump;
+ CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( versionLump ), &versionLump );
+ if ( versionLump.m_iMagic != TF_GAMESTATS_MAGIC )
+ {
+ Msg( "Incorrect magic # in version header. Expected %x, got %x. Skipping file.\n", TF_GAMESTATS_MAGIC, versionLump.m_iMagic );
+ return false;
+ }
+ if ( versionLump.m_iVersion != TF_GAMESTATS_FILE_VERSION )
+ {
+ Msg( "Mismatched file version. Expected file version %d, got %d. Skipping file.\n", TF_GAMESTATS_FILE_VERSION, versionLump.m_iVersion );
+ return false;
+ }
+
+ TF_Gamestats_LevelStats_t *pCurrentGame = NULL;
+
+ // read all the lumps in the file
+ while( CBaseGameStats::GetLumpHeader( MAX_LUMP_COUNT, LoadBuffer, iLump, iLumpCount ) )
+ {
+ switch ( iLump )
+ {
+ case TFSTATS_LUMP_MAPHEADER:
+ {
+ TF_Gamestats_LevelStats_t::LevelHeader_t header;
+ CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::LevelHeader_t ), &header );
+
+ // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
+ if ( ( header.m_iRoundsPlayed < 0 ) || ( header.m_iTotalTime < 0 ) || ( header.m_iRoundsPlayed > 1000 ) )
+ return false;
+
+ // if there's no interesting data, skip this file. (Need to have server not send it in this case.)
+ if ( header.m_iTotalTime == 0 )
+ return false;
+
+ pCurrentGame = FindOrAddMapStats( header.m_szMapName );
+ if ( pCurrentGame )
+ {
+ pCurrentGame->m_Header = header;
+ }
+ break;
+ }
+ case TFSTATS_LUMP_MAPDEATH:
+ {
+ //CUtlVector<TF_Gamestats_LevelStats_t::PlayerDeathsLump_t> playerDeaths;
+
+ //playerDeaths.SetCount( iLumpCount );
+ //CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::PlayerDeathsLump_t ), static_cast<void*>( playerDeaths.Base() ) );
+ //if ( pCurrentGame )
+ //{
+ // pCurrentGame->m_aPlayerDeaths = playerDeaths;
+ //}
+ break;
+ }
+ case TFSTATS_LUMP_MAPDAMAGE:
+ {
+ //CUtlVector<TF_Gamestats_LevelStats_t::PlayerDamageLump_t> playerDamage;
+
+ //playerDamage.SetCount( iLumpCount );
+ //CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( TF_Gamestats_LevelStats_t::PlayerDamageLump_t ), static_cast<void*>( playerDamage.Base() ) );
+ //if ( pCurrentGame )
+ //{
+ // pCurrentGame->m_aPlayerDamage = playerDamage;
+ //}
+ break;
+ }
+ case TFSTATS_LUMP_CLASS:
+ {
+ Assert( pCurrentGame );
+ if ( !pCurrentGame )
+ return false;
+ Assert ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aClassStats ) );
+ if ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aClassStats ) )
+ {
+ CBaseGameStats::LoadLump( LoadBuffer, ARRAYSIZE( pCurrentGame->m_aClassStats ), sizeof( pCurrentGame->m_aClassStats[0] ),
+ pCurrentGame->m_aClassStats );
+
+ // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
+ for ( int i = 0; i < ARRAYSIZE( pCurrentGame->m_aClassStats ); i++ )
+ {
+ TF_Gamestats_ClassStats_t &classStats = pCurrentGame->m_aClassStats[i];
+ if ( ( classStats.iSpawns < 0 ) || ( classStats.iSpawns > 10000 ) || ( classStats.iTotalTime < 0 ) || ( classStats.iTotalTime > 36000 * 20 ) ||
+ ( classStats.iKills < 0 ) || ( classStats.iKills > 10000 ) )
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // mismatched lump size, possibly from different build, don't know how it interpret it, just skip over it
+ return false;
+ }
+ break;
+ }
+ case TFSTATS_LUMP_WEAPON:
+ {
+ Assert( pCurrentGame );
+ if ( !pCurrentGame )
+ return false;
+ Assert ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aWeaponStats ) );
+ if ( iLumpCount == ARRAYSIZE( pCurrentGame->m_aWeaponStats ) )
+ {
+ CBaseGameStats::LoadLump( LoadBuffer, ARRAYSIZE( pCurrentGame->m_aWeaponStats ), sizeof( pCurrentGame->m_aWeaponStats[0] ),
+ pCurrentGame->m_aWeaponStats );
+
+ // quick sanity check on some data -- we get some stat files that start out OK but are corrupted later in the file
+ if ( ( pCurrentGame->m_aWeaponStats[TF_WEAPON_MEDIGUN].iShotsFired < 0 ) || ( pCurrentGame->m_aWeaponStats[TF_WEAPON_MEDIGUN].iShotsFired > 100000 )
+ || ( pCurrentGame->m_aWeaponStats[TF_WEAPON_FLAMETHROWER_ROCKET].iShotsFired != 0 ) ) // check that unused weapon has 0 shots
+ {
+ return false;
+ }
+
+ }
+ else
+ {
+ // mismatched lump size, possibly from different build, don't know how it interpret it, just skip over it
+ return false;
+ }
+ break;
+ }
+ case TFSTATS_LUMP_ENDTAG:
+ {
+ // check that end tag is valid -- should be version lump again
+ TF_Gamestats_Version_t versionLump;
+ CBaseGameStats::LoadLump( LoadBuffer, iLumpCount, sizeof( versionLump ), &versionLump );
+ if ( versionLump.m_iMagic != TF_GAMESTATS_MAGIC )
+ {
+ Msg( "Incorrect magic # in version header. Expected %x, got %x. Skipping file.\n", TF_GAMESTATS_MAGIC, versionLump.m_iMagic );
+ return false;
+ }
+ if ( versionLump.m_iVersion != TF_GAMESTATS_FILE_VERSION )
+ {
+ Msg( "Mismatched file version. Expected file version %d, got %d. Skipping file.\n", TF_GAMESTATS_FILE_VERSION, versionLump.m_iVersion );
+ return false;
+ }
+ bGotEndTag = true;
+ break;
+ }
+
+ }
+ }
+
+ return bGotEndTag;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// TF2 Beta Maps
+// Robot Destruction
+//-----------------------------------------------------------------------------
+RobotDestructionStats_t::RobotDestructionStats_t()
+{
+ Clear();
+}
+
+//-----------------------------------------------------------------------------
+void RobotDestructionStats_t::Clear()
+{
+ V_memset( &iRobotInteraction, 0, sizeof( iRobotInteraction ) );
+ V_memset( &iRobotCoreInteraction, 0, sizeof( iRobotCoreInteraction ) );
+ V_memset( &iFlagInteraction, 0, sizeof( iFlagInteraction ) );
+
+ V_memset( &iCoresCollectedByTeam, 0, sizeof( iCoresCollectedByTeam ) );
+ V_memset( &iCoreCollectedByClass, 0, sizeof( iCoreCollectedByClass ) );
+
+ V_memset( &iBlueRobotsKilledByType, 0, sizeof( iBlueRobotsKilledByType ) );
+ V_memset( &iRedRobotsKilledByType, 0, sizeof( iRedRobotsKilledByType ) );
+ V_memset( &iRobotsDamageFromClass, 0, sizeof( iRobotsDamageFromClass ) );
+
+}
+
+//-----------------------------------------------------------------------------
+int RobotDestructionStats_t::GetRobotInteractionCount()
+{
+ int iCount = 0;
+ for ( int i = 1; i < MAX_PLAYERS; ++i )
+ {
+ if ( iRobotInteraction[i] )
+ {
+ iCount++;
+ }
+ }
+ return iCount;
+}
+//-----------------------------------------------------------------------------
+int RobotDestructionStats_t::GetRobotCoreInteractionCount()
+{
+ int iCount = 0;
+ for ( int i = 1; i < MAX_PLAYERS; ++i )
+ {
+ if ( iRobotCoreInteraction[i] )
+ {
+ iCount++;
+ }
+ }
+ return iCount;
+}
+//-----------------------------------------------------------------------------
+int RobotDestructionStats_t::GetFlagInteractionCount()
+{
+ int iCount = 0;
+ for ( int i = 1; i < MAX_PLAYERS; ++i )
+ {
+ if ( iFlagInteraction[i] )
+ {
+ iCount++;
+ }
+ }
+ return iCount;
+}
+
+//-----------------------------------------------------------------------------
+const char* g_aRoundEndReasons[] =
+{
+ "round_end",
+ "client_disconnect",
+ "client_quit",
+ "server_map_change",
+ "server_shutdown",
+ "time_limit_reached",
+ "win_limit_reached",
+ "win_diff_limit_reached",
+ "round_limit_reached",
+ "next_level_cvar",
+};
+
+// Get a string describing the current game type.
+const char* GetGameTypeID()
+{
+ ConVarRef tf_gamemode_arena( "tf_gamemode_arena" );
+ ConVarRef tf_gamemode_cp( "tf_gamemode_cp" );
+ ConVarRef tf_gamemode_ctf( "tf_gamemode_ctf" );
+ ConVarRef tf_gamemode_sd( "tf_gamemode_sd" );
+ ConVarRef tf_gamemode_payload( "tf_gamemode_payload" );
+ ConVarRef tf_gamemode_mvm( "tf_gamemode_mvm" );
+ ConVarRef tf_powerup_mode( "tf_powerup_mode" );
+ ConVarRef tf_gamemode_passtime( "tf_gamemode_passtime" );
+
+ const char* pszGameTypeID = NULL;
+ if ( tf_gamemode_arena.GetBool() )
+ {
+ pszGameTypeID = "arena";
+ }
+ else if ( tf_gamemode_cp.GetBool() )
+ {
+ pszGameTypeID = "cp";
+ }
+ else if ( tf_gamemode_ctf.GetBool() )
+ {
+ if ( tf_powerup_mode.GetBool() )
+ {
+ pszGameTypeID = "ctf_mannpower";
+ }
+ else
+ {
+ pszGameTypeID = "ctf";
+ }
+ }
+ else if ( tf_gamemode_sd.GetBool() )
+ {
+ pszGameTypeID = "sd";
+ }
+ else if ( tf_gamemode_payload.GetBool() )
+ {
+ pszGameTypeID = "payload";
+ }
+ else if ( tf_gamemode_mvm.GetBool() )
+ {
+ pszGameTypeID = "mvm";
+ }
+ else if ( tf_gamemode_passtime.GetBool() )
+ {
+ pszGameTypeID = "pass"; // intentionally not "passtime"
+ }
+ else
+ {
+ pszGameTypeID = "custom";
+ }
+
+ return pszGameTypeID;
+}
+
+//-----------------------------------------------------------------------------
+// TF2 Beta Maps
+// Passtime
+//-----------------------------------------------------------------------------
+void PasstimeStats_t::Clear()
+{
+ memset( &summary, 0, sizeof(summary) );
+ memset( &classes, 0, sizeof(classes) );
+}
+
+//-----------------------------------------------------------------------------
+void PasstimeStats_t::AddBallFracSample( float f )
+{
+ Assert( f >= 0 && f <= 1.0f );
+ int iBin = (uint8) Floor2Int( f * 255 );
+ summary.nBallFracHistSum += iBin;
+ ++summary.arrBallFracHist[ iBin ];
+ ++summary.nBallFracSampleCount;
+}
+
+//-----------------------------------------------------------------------------
+void PasstimeStats_t::AddPassTravelDistSample( float f )
+{
+ if ( summary.nPassTravelDistSampleCount >= summary.k_nMaxPassTravelDistSamples )
+ return;
+ Assert( f >= 0 );
+ summary.arrPassTravelDistSamples[ summary.nPassTravelDistSampleCount ] = (uint16) Float2Int( f );
+ ++summary.nPassTravelDistSampleCount;
+}
+
+#ifdef CLIENT_DLL
+MapStats_t &GetMapStats( map_identifier_t iMapID )
+{
+ return CTFStatPanel::GetMapStats( iMapID );
+}
+#endif