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.
340 lines
10 KiB
340 lines
10 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: The CS game stats header |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#ifndef CS_GAMESTATS_H |
|
#define CS_GAMESTATS_H |
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include "cs_blackmarket.h" |
|
#include "gamestats.h" |
|
#include "cs_gamestats_shared.h" |
|
#include "GameEventListener.h" |
|
#include "steamworks_gamestats.h" |
|
#include "weapon_csbase.h" |
|
|
|
// forward declares |
|
class CBreakableProp; |
|
|
|
#define CS_STATS_BLOB_VERSION 3 |
|
|
|
const float cDisseminationTimeHigh = 0.25f; // Time interval for high priority stats sent to the player |
|
const float cDisseminationTimeLow = 2.5f; // Time interval for medium priority stats sent to the player |
|
|
|
int GetCSLevelIndex( const char *pLevelName ); |
|
|
|
typedef struct |
|
{ |
|
char szGameName[8]; |
|
byte iVersion; |
|
char szMapName[32]; |
|
char ipAddr[4]; |
|
short port; |
|
int serverid; |
|
} gamestats_header_t; |
|
|
|
typedef struct |
|
{ |
|
gamestats_header_t header; |
|
short iMinutesPlayed; |
|
|
|
short iTerroristVictories[CS_NUM_LEVELS]; |
|
short iCounterTVictories[CS_NUM_LEVELS]; |
|
short iBlackMarketPurchases[WEAPON_MAX]; |
|
|
|
short iAutoBuyPurchases; |
|
short iReBuyPurchases; |
|
short iAutoBuyM4A1Purchases; |
|
short iAutoBuyAK47Purchases; |
|
short iAutoBuyFamasPurchases; |
|
short iAutoBuyGalilPurchases; |
|
short iAutoBuyVestHelmPurchases; |
|
short iAutoBuyVestPurchases; |
|
|
|
} cs_gamestats_t; |
|
|
|
extern short g_iWeaponPurchases[WEAPON_MAX]; |
|
extern float g_flGameStatsUpdateTime; |
|
extern short g_iTerroristVictories[CS_NUM_LEVELS]; |
|
extern short g_iCounterTVictories[CS_NUM_LEVELS]; |
|
extern short g_iWeaponPurchases[WEAPON_MAX]; |
|
|
|
extern short g_iAutoBuyPurchases; |
|
extern short g_iReBuyPurchases; |
|
extern short g_iAutoBuyM4A1Purchases; |
|
extern short g_iAutoBuyAK47Purchases; |
|
extern short g_iAutoBuyFamasPurchases; |
|
extern short g_iAutoBuyGalilPurchases; |
|
extern short g_iAutoBuyVestHelmPurchases; |
|
extern short g_iAutoBuyVestPurchases; |
|
|
|
|
|
struct sHappyCamperSnipePosition |
|
{ |
|
sHappyCamperSnipePosition( int userid, Vector pos ) : m_iUserID(userid), m_vPos(pos) {} |
|
|
|
int m_iUserID; |
|
Vector m_vPos; |
|
}; |
|
|
|
struct SMarketPurchases : public BaseStatData |
|
{ |
|
SMarketPurchases( uint64 ulPlayerID, int iPrice, const char *pName ) : m_nPlayerID(ulPlayerID), ItemCost(iPrice) |
|
{ |
|
if ( pName ) |
|
{ |
|
Q_strncpy( ItemID, pName, ARRAYSIZE(ItemID) ); |
|
} |
|
else |
|
{ |
|
Q_strncpy( ItemID, "unknown", ARRAYSIZE(ItemID) ); |
|
} |
|
} |
|
uint64 m_nPlayerID; |
|
int ItemCost; |
|
char ItemID[64]; |
|
|
|
BEGIN_STAT_TABLE( "CSSMarketPurchase" ) |
|
REGISTER_STAT( m_nPlayerID ) |
|
REGISTER_STAT( ItemCost ) |
|
REGISTER_STAT_STRING( ItemID ) |
|
END_STAT_TABLE() |
|
}; |
|
typedef CUtlVector< SMarketPurchases* > VectorMarketPurchaseData; |
|
|
|
struct WeaponStats |
|
{ |
|
int shots; |
|
int hits; |
|
int kills; |
|
int damage; |
|
}; |
|
|
|
struct SCSSWeaponData : public BaseStatData |
|
{ |
|
SCSSWeaponData( const char *pWeaponName, const WeaponStats &wpnData ) |
|
{ |
|
if ( pWeaponName ) |
|
{ |
|
Q_strncpy( WeaponID, pWeaponName, ARRAYSIZE(WeaponID) ); |
|
} |
|
else |
|
{ |
|
Q_strncpy( WeaponID, "unknown", ARRAYSIZE(WeaponID) ); |
|
} |
|
|
|
Shots = wpnData.shots; |
|
Hits = wpnData.hits; |
|
Kills = wpnData.kills; |
|
Damage = wpnData.damage; |
|
} |
|
|
|
char WeaponID[64]; |
|
int Shots; |
|
int Hits; |
|
int Kills; |
|
int Damage; |
|
|
|
BEGIN_STAT_TABLE( "CSSWeaponData" ) |
|
REGISTER_STAT_STRING( WeaponID ) |
|
REGISTER_STAT( Shots ) |
|
REGISTER_STAT( Hits ) |
|
REGISTER_STAT( Kills ) |
|
REGISTER_STAT( Damage ) |
|
END_STAT_TABLE() |
|
}; |
|
typedef CUtlVector< SCSSWeaponData* > CSSWeaponData; |
|
|
|
struct SCSSDeathData : public BaseStatData |
|
{ |
|
SCSSDeathData( CBasePlayer *pVictim, const CTakeDamageInfo &info ) |
|
{ |
|
m_bUseGlobalData = false; |
|
|
|
m_DeathPos = info.GetDamagePosition(); |
|
m_iVictimTeam = pVictim->GetTeamNumber(); |
|
|
|
CCSPlayer *pCSPlayer = ToCSPlayer( info.GetAttacker() ); |
|
if ( pCSPlayer ) |
|
{ |
|
m_iKillerTeam = pCSPlayer->GetTeamNumber(); |
|
} |
|
else |
|
{ |
|
m_iKillerTeam = -1; |
|
} |
|
|
|
const char *pszWeaponName = info.GetInflictor() ? info.GetInflictor()->GetClassname() : "unknown"; |
|
|
|
if ( pszWeaponName ) |
|
{ |
|
if ( V_strcmp(pszWeaponName, "player") == 0 ) |
|
{ |
|
// get the player's weapon |
|
if ( pCSPlayer && pCSPlayer->GetActiveCSWeapon() ) |
|
{ |
|
pszWeaponName = pCSPlayer->GetActiveCSWeapon()->GetClassname(); |
|
} |
|
} |
|
} |
|
|
|
|
|
m_uiDeathParam = WEAPON_NONE; |
|
if ( (m_uiDeathParam = AliasToWeaponID( pszWeaponName )) == WEAPON_NONE ) |
|
{ |
|
m_uiDeathParam = AliasToWeaponID( pszWeaponName ); |
|
} |
|
|
|
const char *pszMapName = gpGlobals->mapname.ToCStr() ? gpGlobals->mapname.ToCStr() : "unknown"; |
|
Q_strncpy( m_szMapName, pszMapName, ARRAYSIZE(m_szMapName) ); |
|
} |
|
Vector m_DeathPos; |
|
int m_iVictimTeam; |
|
int m_iKillerTeam; |
|
int m_iDamageType; |
|
uint64 m_uiDeathParam; |
|
char m_szMapName[64]; |
|
|
|
BEGIN_STAT_TABLE( "Deaths" ) |
|
REGISTER_STAT_NAMED( m_DeathPos.x, "XCoord" ) |
|
REGISTER_STAT_NAMED( m_DeathPos.y, "YCoord" ) |
|
REGISTER_STAT_NAMED( m_DeathPos.z, "ZCoord" ) |
|
REGISTER_STAT_NAMED( m_iVictimTeam, "Team" ) |
|
REGISTER_STAT_NAMED( m_iKillerTeam, "DeathCause" ) |
|
REGISTER_STAT_NAMED( m_uiDeathParam, "DeathParam" ) |
|
REGISTER_STAT_NAMED( m_szMapName, "DeathMap" ) |
|
END_STAT_TABLE() |
|
}; |
|
typedef CUtlVector< SCSSDeathData* > CSSDeathData; |
|
|
|
//============================================================================= |
|
// |
|
// CS Game Stats Class |
|
// |
|
class CCSGameStats : public CBaseGameStats, public CGameEventListener, public CAutoGameSystemPerFrame, public IGameStatTracker |
|
{ |
|
public: |
|
|
|
// Constructor/Destructor. |
|
CCSGameStats( void ); |
|
~CCSGameStats( void ); |
|
|
|
virtual void Clear( void ); |
|
virtual bool Init(); |
|
virtual void PreClientUpdate(); |
|
virtual void PostInit(); |
|
virtual void LevelShutdownPreClearSteamAPIContext(); |
|
|
|
void UploadRoundStats( void ); |
|
// Overridden events |
|
virtual void Event_LevelInit( void ); |
|
virtual void Event_LevelShutdown( float flElapsed ); |
|
virtual void Event_ShotFired( CBasePlayer *pPlayer, CBaseCombatWeapon* pWeapon ); |
|
virtual void Event_ShotHit( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); |
|
virtual void Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); |
|
virtual void Event_PlayerKilled_PreWeaponDrop( CBasePlayer *pPlayer, const CTakeDamageInfo &info ); |
|
void UpdatePlayerRoundStats(int winner); |
|
virtual void Event_PlayerConnected( CBasePlayer *pPlayer ); |
|
virtual void Event_PlayerDisconnected( CBasePlayer *pPlayer ); |
|
virtual void Event_WindowShattered( CBasePlayer *pPlayer ); |
|
virtual void Event_PlayerKilledOther( CBasePlayer *pAttacker, CBaseEntity *pVictim, const CTakeDamageInfo &info ); |
|
|
|
|
|
// CSS specific events |
|
void Event_BombPlanted( CCSPlayer *pPlayer ); |
|
void Event_BombDefused( CCSPlayer *pPlayer ); |
|
void Event_PlayerDamage( CBasePlayer *pBasePlayer, const CTakeDamageInfo &info ); |
|
void Event_BombExploded( CCSPlayer *pPlayer ); |
|
void Event_MoneyEarned( CCSPlayer *pPlayer, int moneyEarned ); |
|
void Event_MoneySpent( CCSPlayer *pPlayer, int moneySpent, const char *pItemName ); |
|
void Event_HostageRescued( CCSPlayer *pPlayer ); |
|
void Event_PlayerSprayedDecal( CCSPlayer*pPlayer ); |
|
void Event_AllHostagesRescued(); |
|
void Event_BreakProp( CCSPlayer *pPlayer, CBreakableProp *pProp ); |
|
void Event_PlayerDonatedWeapon (CCSPlayer* pPlayer); |
|
void Event_PlayerDominatedOther( CCSPlayer* pAttacker, CCSPlayer* pVictim); |
|
void Event_PlayerRevenge( CCSPlayer* pAttacker ); |
|
void Event_PlayerAvengedTeammate( CCSPlayer* pAttacker, CCSPlayer* pAvengedPlayer ); |
|
void Event_MVPEarned( CCSPlayer* pPlayer ); |
|
void Event_KnifeUse( CCSPlayer* pPlayer, bool bStab, int iDamage ); |
|
|
|
virtual void FireGameEvent( IGameEvent *event ); |
|
|
|
void DumpMatchWeaponMetrics(); |
|
|
|
const PlayerStats_t& FindPlayerStats( CBasePlayer *pPlayer ) const; |
|
void ResetPlayerStats( CBasePlayer *pPlayer ); |
|
void ResetKillHistory( CBasePlayer *pPlayer ); |
|
void ResetRoundStats(); |
|
void ResetPlayerClassMatchStats(); |
|
|
|
const StatsCollection_t& GetTeamStats( int iTeamIndex ) const; |
|
void ResetAllTeamStats(); |
|
void ResetAllStats(); |
|
void ResetWeaponStats(); |
|
void IncrementTeamStat( int iTeamIndex, int iStatIndex, int iAmount ); |
|
void CalcDominationAndRevenge( CCSPlayer *pAttacker, CCSPlayer *pVictim, int *piDeathFlags ); |
|
void CalculateOverkill( CCSPlayer* pAttacker, CCSPlayer* pVictim ); |
|
void PlayerKilled( CBasePlayer *pVictim, const CTakeDamageInfo &info ); |
|
|
|
void IncrementStat( CCSPlayer* pPlayer, CSStatType_t statId, int iValue, bool bPlayerOnly = false ); |
|
// Steamworks Gamestats |
|
virtual void SubmitGameStats( KeyValues *pKV ); |
|
|
|
virtual StatContainerList_t* GetStatContainerList( void ) |
|
{ |
|
return s_StatLists; |
|
} |
|
|
|
protected: |
|
void SetStat( CCSPlayer *pPlayer, CSStatType_t statId, int iValue ); |
|
void TrackKillStats( CCSPlayer *pAttacker, CCSPlayer *pVictim ); |
|
void ComputeRollingStatAverages(); |
|
void ComputeDirectStatAverages(); |
|
void SendRollingStatsAveragesToAllPlayers(); |
|
void SendDirectStatsAveragesToAllPlayers(); |
|
void SendStatsToPlayer( CCSPlayer * pPlayer, int iMinStatPriority ); |
|
|
|
private: |
|
PlayerStats_t m_aPlayerStats[MAX_PLAYERS+1]; // List of stats for each player for current life - reset after each death |
|
StatsCollection_t m_aTeamStats[TEAM_MAXCOUNT - FIRST_GAME_TEAM]; |
|
|
|
RoundStatsRollingAverage_t m_rollingCTStatAverages; |
|
RoundStatsRollingAverage_t m_rollingTStatAverages; |
|
RoundStatsRollingAverage_t m_rollingPlayerStatAverages; |
|
|
|
RoundStatsDirectAverage_t m_directCTStatAverages; |
|
RoundStatsDirectAverage_t m_directTStatAverages; |
|
RoundStatsDirectAverage_t m_directPlayerStatAverages; |
|
|
|
float m_fDisseminationTimerLow; // how long since last medium priority stat update |
|
float m_fDisseminationTimerHigh; // how long since last high priority stat update |
|
|
|
int m_numberOfRoundsForDirectAverages; |
|
int m_numberOfTerroristEntriesForDirectAverages; |
|
int m_numberOfCounterTerroristEntriesForDirectAverages; |
|
|
|
CUtlDict< CSStatType_t, short > m_PropStatTable; |
|
|
|
CUtlLinkedList<sHappyCamperSnipePosition, int> m_PlayerSnipedPosition; |
|
WeaponStats m_weaponStats[WEAPON_MAX][2]; |
|
|
|
// Steamworks Gamestats |
|
VectorMarketPurchaseData m_MarketPurchases; |
|
CSSWeaponData m_WeaponData; |
|
CSSDeathData m_DeathData; |
|
|
|
// A static list of all the stat containers, one for each data structure being tracked |
|
static StatContainerList_t * s_StatLists; |
|
|
|
bool m_bInRound; |
|
}; |
|
|
|
extern CCSGameStats CCS_GameStats; |
|
|
|
#endif // CS_GAMESTATS_H
|
|
|