1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
//========= 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
|