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
637 lines
20 KiB
//========= 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
|
|
|