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.
341 lines
10 KiB
341 lines
10 KiB
![]()
4 years ago
|
//========= 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
|