diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_gamestats_shared.cpp | |
| download | archived-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.cpp | 637 |
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 |