mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-22 05:25:44 +02:00
Quake 4 integrated with DoomRTX
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
//----------------------------------------------------------------
|
||||
// StatEvent.cpp
|
||||
//
|
||||
// Copyright 2002-2005 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../../Game_local.h"
|
||||
#include "StatManager.h"
|
||||
|
||||
|
||||
rvStatHit::rvStatHit( int t, int p, int v, int w, bool countForAccuracy ) : rvStat( t ) {
|
||||
playerClientNum = p;
|
||||
victimClientNum = v;
|
||||
weapon = w;
|
||||
trackAccuracy = countForAccuracy;
|
||||
type = ST_HIT;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatHit::RegisterInGame( rvPlayerStat* stats ) {
|
||||
if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS && weapon >= 0 && weapon < MAX_WEAPONS && trackAccuracy ) {
|
||||
stats[ playerClientNum ].weaponHits[ weapon ]++;
|
||||
}
|
||||
idPlayer* player = (idPlayer*)gameLocal.entities[ playerClientNum ];
|
||||
if( !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", weapon ) ), "weapon_railgun" ) ) {
|
||||
|
||||
// Apparently it does the rail hit event before the rail fired event, so this is backwards for a reason
|
||||
if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_ROCKET_HIT ) {
|
||||
rvStatManager::comboKillState[ playerClientNum ] = CKS_RAIL_HIT;
|
||||
}
|
||||
|
||||
if ( rvStatManager::lastRailShot[ playerClientNum ] < stats[ playerClientNum ].weaponShots[ weapon ] - 1 ) {
|
||||
rvStatManager::lastRailShot[ playerClientNum ] = stats[ playerClientNum ].weaponShots[ weapon ];
|
||||
} else {
|
||||
if ( rvStatManager::lastRailShot[ playerClientNum ] >= stats[ playerClientNum ].weaponShots[ weapon ] - 1 ) {
|
||||
if ( (rvStatManager::lastRailShotHits[ playerClientNum ] % 2) == 0 ) {
|
||||
statManager->GiveInGameAward( IGA_IMPRESSIVE, playerClientNum );
|
||||
}
|
||||
++rvStatManager::lastRailShotHits[ playerClientNum ];
|
||||
} else {
|
||||
rvStatManager::lastRailShot[ playerClientNum ] = stats[ playerClientNum ].weaponShots[ weapon ];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
rvStatHit* lastHits[ 2 ] = { NULL, NULL };
|
||||
statManager->GetLastClientStats( playerClientNum, ST_HIT, gameLocal.time - 8000, 2, (rvStat**)lastHits );
|
||||
if( lastHits[0] ) {
|
||||
if( !idStr::Icmp(player->spawnArgs.GetString( va( "def_weapon%d", ((rvStatHit*)lastHits[0])->weapon ) ), "weapon_railgun" ) ) {
|
||||
|
||||
//Check to make sure we don't chain impressive awards.
|
||||
if(lastHits[1]
|
||||
&& !idStr::Icmp(player->spawnArgs.GetString( va( "def_weapon%d", ((rvStatHit*)lastHits[1])->weapon ) ), "weapon_railgun" )
|
||||
&& (lastHits[1]->GetTimeStamp() - lastHits[0]->GetTimeStamp()) < 4000) {
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if(gameLocal.time - lastHits[0]->GetTimeStamp() < 4000){
|
||||
statManager->GiveInGameAward( IGA_IMPRESSIVE, playerClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
} else if( !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", weapon ) ), "weapon_rocketlauncher" ) ) {
|
||||
|
||||
if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_ROCKET_FIRED ) {
|
||||
rvStatManager::comboKillState[ playerClientNum ] = CKS_ROCKET_HIT;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
rvStatKill::rvStatKill( int t, int p, int v, bool g, int mod ) : rvStat( t ) {
|
||||
type = ST_KILL;
|
||||
playerClientNum = p;
|
||||
victimClientNum = v;
|
||||
gibbed = g;
|
||||
methodOfDeath = mod;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatKill::RegisterInGame( rvPlayerStat* stats ) {
|
||||
if( playerClientNum < 0 || playerClientNum >= MAX_CLIENTS || victimClientNum < 0 || victimClientNum >= MAX_CLIENTS ) {
|
||||
return;
|
||||
}
|
||||
|
||||
idPlayer* player = (idPlayer*)gameLocal.entities[ playerClientNum ];
|
||||
idPlayer* victim = (idPlayer*)gameLocal.entities[ victimClientNum ];
|
||||
|
||||
// no award processing for suicides
|
||||
if( victimClientNum == playerClientNum ) {
|
||||
stats[ playerClientNum ].suicides++;
|
||||
return;
|
||||
}
|
||||
|
||||
bool teamKill = false;
|
||||
|
||||
// don't track team kills
|
||||
if( !gameLocal.IsTeamGame() || player->team != victim->team ) {
|
||||
stats[ playerClientNum ].kills++;
|
||||
|
||||
if( methodOfDeath >= 0 && methodOfDeath < MAX_WEAPONS ) {
|
||||
stats[ playerClientNum ].weaponKills[ methodOfDeath ]++;
|
||||
}
|
||||
}
|
||||
|
||||
if( gameLocal.IsTeamGame() && player->team == victim->team ) {
|
||||
teamKill = true;
|
||||
}
|
||||
|
||||
|
||||
// check for humiliation award
|
||||
if( !teamKill && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", methodOfDeath ) ), "weapon_gauntlet" ) ) {
|
||||
statManager->GiveInGameAward( IGA_HUMILIATION, playerClientNum );
|
||||
}
|
||||
|
||||
rvStatKill* lastKills[ 2 ] = { NULL, NULL };
|
||||
|
||||
statManager->GetLastClientStats( playerClientNum, ST_KILL, gameLocal.time - 5000, 2, (rvStat**)lastKills );
|
||||
|
||||
// check for excellent award
|
||||
if( !teamKill && lastKills[ 0 ] && lastKills[ 0 ]->GetTimeStamp() >= (gameLocal.time - 2000) && lastKills[ 0 ]->victimClientNum != playerClientNum && victimClientNum != playerClientNum ) {
|
||||
statManager->GiveInGameAward( IGA_EXCELLENT, playerClientNum );
|
||||
}
|
||||
|
||||
// check for rampage award
|
||||
if( !teamKill && ( gibbed && victimClientNum != playerClientNum ) &&
|
||||
( lastKills[ 0 ] && lastKills[ 0 ]->gibbed && lastKills[ 0 ]->victimClientNum != playerClientNum ) &&
|
||||
( lastKills[ 1 ] && lastKills[ 1 ]->gibbed && lastKills[ 1 ]->victimClientNum != playerClientNum ) ) {
|
||||
statManager->GiveInGameAward( IGA_RAMPAGE, playerClientNum );
|
||||
}
|
||||
|
||||
|
||||
// check for combo kill award
|
||||
if( victimClientNum != playerClientNum && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", methodOfDeath ) ), "weapon_railgun" ) ) {
|
||||
// the rail killing shot is the last hit, so look for the one past that
|
||||
rvStatHit* lastHits[ 2 ] = { NULL, NULL };
|
||||
|
||||
statManager->GetLastClientStats( playerClientNum, ST_HIT, gameLocal.time - 3000, 2, (rvStat**)lastHits );
|
||||
|
||||
if( lastHits[ 1 ] && lastHits[ 1 ]->GetVictimClientNum() != playerClientNum && !idStr::Icmp( player->spawnArgs.GetString( va( "def_weapon%d", lastHits[ 1 ]->GetWeapon() ) ), "weapon_rocketlauncher" ) ) {
|
||||
if ( rvStatManager::comboKillState[ playerClientNum ] == CKS_RAIL_HIT ) {
|
||||
statManager->GiveInGameAward( IGA_COMBO_KILL, playerClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rvStatManager::comboKillState[ playerClientNum ] = CKS_NONE;
|
||||
|
||||
|
||||
// check for defense award
|
||||
if( gameLocal.IsFlagGameType() && player->team != victim->team && player != victim ) {
|
||||
// defense is given for two conditions
|
||||
// assert( gameLocal.mpGame.GetFlagEntity( TEAM_STROGG ) && gameLocal.mpGame.GetFlagEntity( TEAM_MARINE ) );
|
||||
assert( player->team >= 0 && player->team < TEAM_MAX );
|
||||
assert( gameLocal.mpGame.GetGameState()->IsType( rvCTFGameState::GetClassType() ) );
|
||||
|
||||
if ( gameLocal.mpGame.GetFlagEntity( player->team ) ) {
|
||||
// defending your flag
|
||||
if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( player->team ) == FS_AT_BASE || ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( player->team ) == FS_DROPPED ) {
|
||||
if( ( gameLocal.mpGame.GetFlagEntity( player->team )->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin() ).LengthSqr() < 250000 ) {
|
||||
// give award if you're close to flag and you kill an enemy
|
||||
statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum );
|
||||
} else if ( ( gameLocal.mpGame.GetFlagEntity( player->team )->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin() ).LengthSqr() < 250000 ) {
|
||||
// give award if enemy is close to flag and you kill them
|
||||
statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// defending your teammate carrying the enemy flag
|
||||
if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( gameLocal.mpGame.OpposingTeam( player->team ) ) == FS_TAKEN ) {
|
||||
int clientNum = ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagCarrier( gameLocal.mpGame.OpposingTeam( player->team ) );
|
||||
|
||||
idPlayer* flagCarrier = NULL;
|
||||
|
||||
if( clientNum >= 0 && clientNum < MAX_CLIENTS ) {
|
||||
flagCarrier = (idPlayer*)gameLocal.entities[ clientNum ];
|
||||
}
|
||||
|
||||
if( flagCarrier ) {
|
||||
if( (flagCarrier->GetPhysics()->GetOrigin() - player->GetPhysics()->GetOrigin()).LengthSqr() < 250000 ) {
|
||||
// killed enemy while close to the flag carrier
|
||||
statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum );
|
||||
} else if( (flagCarrier->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin()).LengthSqr() < 250000 ) {
|
||||
// killed an enemy who was close to teh flag carrier
|
||||
statManager->GiveInGameAward( IGA_DEFENSE, playerClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for holy shit award
|
||||
if( gameLocal.IsFlagGameType() && player->team != victim->team && player != victim ) {
|
||||
if( (player->team == TEAM_MARINE && victim->PowerUpActive( POWERUP_CTF_MARINEFLAG )) ||
|
||||
(player->team == TEAM_STROGG && victim->PowerUpActive( POWERUP_CTF_STROGGFLAG )) ) {
|
||||
if( ((rvCTFGameState*)gameLocal.mpGame.GetGameState())->GetFlagState( victim->team ) == FS_AT_BASE ) {
|
||||
|
||||
// fixme: something is broken with the mpgame state
|
||||
if ( gameLocal.mpGame.GetFlagEntity( victim->team ) ) {
|
||||
if( (gameLocal.mpGame.GetFlagEntity( victim->team )->GetPhysics()->GetOrigin() - victim->GetPhysics()->GetOrigin()).LengthSqr() < 40000 ) {
|
||||
statManager->GiveInGameAward( IGA_HOLY_SHIT, playerClientNum );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDeath
|
||||
|
||||
A player died
|
||||
================
|
||||
*/
|
||||
rvStatDeath::rvStatDeath( int t, int p, int mod ) : rvStat( t ) {
|
||||
type = ST_DEATH;
|
||||
playerClientNum = p;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatDeath::RegisterInGame( rvPlayerStat* stats ) {
|
||||
stats[ playerClientNum ].deaths++;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDamageDealt
|
||||
|
||||
A player damaged another player
|
||||
================
|
||||
*/
|
||||
rvStatDamageDealt::rvStatDamageDealt( int t, int p, int w, int d ) : rvStat( t ) {
|
||||
playerClientNum = p;
|
||||
weapon = w;
|
||||
damage = d;
|
||||
type = ST_DAMAGE_DEALT;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatDamageDealt::RegisterInGame( rvPlayerStat* stats ) {
|
||||
if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS ) {
|
||||
stats[ playerClientNum ].damageGiven += damage;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDamageTaken
|
||||
|
||||
A player took damage from another player
|
||||
================
|
||||
*/
|
||||
rvStatDamageTaken::rvStatDamageTaken( int t, int p, int w, int d ) : rvStat( t ) {
|
||||
playerClientNum = p;
|
||||
weapon = w;
|
||||
damage = d;
|
||||
type = ST_DAMAGE_TAKEN;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatDamageTaken::RegisterInGame( rvPlayerStat* stats ) {
|
||||
if( playerClientNum >= 0 && playerClientNum < MAX_CLIENTS ) {
|
||||
stats[ playerClientNum ].damageTaken += damage;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagDrop
|
||||
|
||||
A player dropped the flag (CTF)
|
||||
================
|
||||
*/
|
||||
rvStatFlagDrop::rvStatFlagDrop( int t, int p, int a, int tm ) : rvStatTeam( t, tm ) {
|
||||
playerClientNum = p;
|
||||
attacker = a;
|
||||
type = ST_CTF_FLAG_DROP;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagReturn
|
||||
|
||||
A player returned his teams flag
|
||||
================
|
||||
*/
|
||||
rvStatFlagReturn::rvStatFlagReturn( int t, int p, int tm ) : rvStatTeam( t, tm ) {
|
||||
playerClientNum = p;
|
||||
type = ST_CTF_FLAG_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagCapture
|
||||
|
||||
A player captured a flag (CTF)
|
||||
================
|
||||
*/
|
||||
rvStatFlagCapture::rvStatFlagCapture( int t, int p, int f, int tm ) : rvStatTeam( t, tm ) {
|
||||
playerClientNum = p;
|
||||
flagTeam = f;
|
||||
type = ST_CTF_FLAG_CAPTURE;
|
||||
RegisterInGame( statManager->GetPlayerStats() );
|
||||
}
|
||||
|
||||
void rvStatFlagCapture::RegisterInGame( rvPlayerStat* stats ) {
|
||||
statManager->GiveInGameAward( IGA_CAPTURE, playerClientNum );
|
||||
// figure out if we need to give an assist
|
||||
|
||||
// see if someone carried the flag a bit, lost it, but it was capped
|
||||
rvStatFlagDrop* flagDrop = (rvStatFlagDrop*)statManager->GetLastTeamStat( team, ST_CTF_FLAG_DROP, gameLocal.time - 10000 );
|
||||
if( flagDrop && flagDrop->GetTeam() == team ) {
|
||||
// only give the award if there was no flag return between the flag drop and the flag capture
|
||||
rvStatFlagReturn* flagReturn = (rvStatFlagReturn*)statManager->GetLastTeamStat( flagTeam, ST_CTF_FLAG_RETURN, gameLocal.time - 10000 );
|
||||
if( flagReturn == NULL ) {
|
||||
statManager->GiveInGameAward( IGA_ASSIST, flagDrop->GetPlayerClientNum() );
|
||||
}
|
||||
}
|
||||
|
||||
// see if someone returned the flag, allowing a cap
|
||||
rvStatFlagReturn* flagReturn = (rvStatFlagReturn*)statManager->GetLastTeamStat( team, ST_CTF_FLAG_RETURN, gameLocal.time - 10000 );
|
||||
if( flagReturn ) {
|
||||
statManager->GiveInGameAward( IGA_ASSIST, flagReturn->GetPlayerClientNum() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
//----------------------------------------------------------------
|
||||
// StatEvent.h
|
||||
//
|
||||
// Copyright 2002-2005 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __STATEVENT_H__
|
||||
#define __STATEVENT_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Multiplayer statistics events
|
||||
|
||||
This file contains statistic event definitions. rvStatManager exposes
|
||||
game-related functions (i.e. 'Kill', 'FlagCaptured') which create the
|
||||
appropriate statistic event and add it to the statQueue in rvStatManager.
|
||||
|
||||
The statQueue contains a complete picture of an MP game. It can be parsed to
|
||||
calculate accuracies, award end-game awards, etc.
|
||||
|
||||
Statistic events also have functionality to register in-game information for
|
||||
on-the-fly statistics.
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class rvPlayerStat;
|
||||
|
||||
/*
|
||||
================
|
||||
statType_t
|
||||
|
||||
Type identifiers for RTTI of stat events, rvStatTeam-derived events must go
|
||||
after ST_STAT_TEAM
|
||||
================
|
||||
*/
|
||||
enum statType_t {
|
||||
// not an actual event, undefined marker
|
||||
ST_NONE = 0,
|
||||
// rvStat derived
|
||||
ST_BEGIN_GAME,
|
||||
ST_END_GAME,
|
||||
ST_CLIENT_CONNECT,
|
||||
ST_HIT,
|
||||
ST_KILL,
|
||||
ST_DEATH,
|
||||
ST_DAMAGE_DEALT,
|
||||
ST_DAMAGE_TAKEN,
|
||||
// not an actual event, team marker
|
||||
ST_STAT_TEAM,
|
||||
// rvStatTeam derived
|
||||
ST_CTF_FLAG_CAPTURE,
|
||||
ST_CTF_FLAG_DROP,
|
||||
ST_CTF_FLAG_RETURN,
|
||||
|
||||
ST_COUNT
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStat
|
||||
|
||||
An individual event we want to know about for stats.
|
||||
================
|
||||
*/
|
||||
class rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
public:
|
||||
|
||||
statType_t GetType( void ) const { return type; };
|
||||
int GetTimeStamp( void ) const { return timeStamp; };
|
||||
byte GetPlayerClientNum( void ) const { return playerClientNum; };
|
||||
|
||||
protected:
|
||||
|
||||
// moved to protected to prevent allocating these on the normal heap.
|
||||
// these should only be allocatd by rvStatAllocator.
|
||||
rvStat( int t ) { timeStamp = t; playerClientNum = -1; type = ST_NONE; };
|
||||
virtual ~rvStat( void ) {};
|
||||
|
||||
virtual void RegisterInGame( rvPlayerStat* stats ) {};
|
||||
|
||||
// the entity number of the player associated with this statistic
|
||||
byte playerClientNum;
|
||||
|
||||
statType_t type;
|
||||
int timeStamp;
|
||||
|
||||
private:
|
||||
// because of the way memory is handled for these we want the compiler
|
||||
// on our side to find abuses. note that we aren't defining these.
|
||||
// this change is propagated to all derived classes.
|
||||
rvStat();
|
||||
rvStat( const rvStat &rhs );
|
||||
const rvStat &operator=( const rvStat &rhs );
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatTeam
|
||||
|
||||
A team-related rvStat
|
||||
================
|
||||
*/
|
||||
class rvStatTeam : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
public:
|
||||
virtual ~rvStatTeam( void ) {};
|
||||
|
||||
int GetTeam( void ) { return team; };
|
||||
protected:
|
||||
|
||||
// see comment in rvStat
|
||||
rvStatTeam( int t, int tm ) : rvStat( t ) { team = tm; };
|
||||
|
||||
byte team;
|
||||
|
||||
private:
|
||||
// see comment in rvStat
|
||||
rvStatTeam();
|
||||
rvStatTeam( const rvStatTeam &rhs );
|
||||
const rvStatTeam &operator=( const rvStat &rhs );
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
rvStat/rvStatTeam-derived classes
|
||||
|
||||
These are the individual events that get stored in the
|
||||
statManager's stat queue
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatBeginGame
|
||||
|
||||
A game has begun
|
||||
================
|
||||
*/
|
||||
class rvStatBeginGame : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatBeginGame( int t ) : rvStat( t ) { type = ST_BEGIN_GAME; };
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatEndGame
|
||||
|
||||
The current game has ended
|
||||
================
|
||||
*/
|
||||
class rvStatEndGame : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatEndGame( int t ) : rvStat( t ) { type = ST_END_GAME; };
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatClientConnect
|
||||
|
||||
A player has connected
|
||||
================
|
||||
*/
|
||||
class rvStatClientConnect : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatClientConnect( int t, int p ) : rvStat( t ) { type = ST_CLIENT_CONNECT; playerClientNum = p; };
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatHit
|
||||
|
||||
A player hit another player
|
||||
================
|
||||
*/
|
||||
class rvStatHit : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
public:
|
||||
int GetVictimClientNum() const { return victimClientNum; }
|
||||
int GetWeapon() const { return weapon; }
|
||||
|
||||
protected:
|
||||
rvStatHit( int t, int p, int v, int w, bool countForAccuracy );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte weapon;
|
||||
byte victimClientNum;
|
||||
bool trackAccuracy;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatKill
|
||||
|
||||
A player killed another player
|
||||
================
|
||||
*/
|
||||
class rvStatKill : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatKill( int t, int p, int v, bool g, int mod );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte methodOfDeath;
|
||||
byte victimClientNum;
|
||||
bool gibbed;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDeath
|
||||
|
||||
A player died
|
||||
================
|
||||
*/
|
||||
class rvStatDeath : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatDeath( int t, int p, int mod );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte methodOfDeath;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDamageDealt
|
||||
|
||||
A player damaged another player
|
||||
================
|
||||
*/
|
||||
class rvStatDamageDealt : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
public:
|
||||
int GetDamage() const { return damage; }
|
||||
|
||||
protected:
|
||||
rvStatDamageDealt( int t, int p, int w, int d );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte weapon;
|
||||
short damage;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatDamageTaken
|
||||
|
||||
A player took damage from another player
|
||||
================
|
||||
*/
|
||||
class rvStatDamageTaken : public rvStat {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
public:
|
||||
int GetDamage() const { return damage; }
|
||||
|
||||
protected:
|
||||
rvStatDamageTaken( int t, int p, int w, int d );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte weapon;
|
||||
short damage;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagDrop
|
||||
|
||||
A player dropped the flag (CTF)
|
||||
================
|
||||
*/
|
||||
class rvStatFlagDrop : public rvStatTeam {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatFlagDrop( int t, int p, int a, int tm );
|
||||
|
||||
byte attacker; // enemy who caused the flag drop
|
||||
|
||||
private:
|
||||
// see comment in rvStat
|
||||
rvStatFlagDrop();
|
||||
rvStatFlagDrop( const rvStatFlagDrop &rhs );
|
||||
const rvStatFlagDrop &operator=( const rvStatFlagDrop &rhs );
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagReturn
|
||||
|
||||
A player returned his teams flag
|
||||
================
|
||||
*/
|
||||
class rvStatFlagReturn : public rvStatTeam {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatFlagReturn( int t, int p, int tm );
|
||||
|
||||
private:
|
||||
// see comment in rvStat
|
||||
rvStatFlagReturn();
|
||||
rvStatFlagReturn( const rvStatFlagReturn &rhs );
|
||||
const rvStatFlagReturn &operator=( const rvStatFlagReturn &rhs );
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatFlagCapture
|
||||
|
||||
A player captured a flag (CTF)
|
||||
================
|
||||
*/
|
||||
class rvStatFlagCapture : public rvStatTeam {
|
||||
|
||||
friend class rvStatAllocator;
|
||||
|
||||
protected:
|
||||
rvStatFlagCapture( int t, int p, int f, int tm );
|
||||
virtual void RegisterInGame( rvPlayerStat* stats );
|
||||
|
||||
byte flagTeam; // team of flag was captured
|
||||
|
||||
private:
|
||||
// see comment in rvStat
|
||||
rvStatFlagCapture();
|
||||
rvStatFlagCapture( const rvStatFlagCapture &rhs );
|
||||
const rvStatFlagCapture &operator=( const rvStatFlagCapture &rhs );
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,349 @@
|
||||
//----------------------------------------------------------------
|
||||
// StatManager.h
|
||||
//
|
||||
// Copyright 2002-2004 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __STATMANAGER_H__
|
||||
#define __STATMANAGER_H__
|
||||
|
||||
#include "StatEvent.h"
|
||||
#include "StatWindow.h"
|
||||
|
||||
#ifndef ID_TRAFFICSTATS
|
||||
#define ID_TRAFFICSTATS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Multiplayer game statistics
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
endGameAward_t
|
||||
|
||||
End-game award IDs
|
||||
================
|
||||
*/
|
||||
enum endGameAward_t {
|
||||
EGA_INVALID = 0,
|
||||
EGA_LEMMING,
|
||||
EGA_RAIL_MASTER,
|
||||
EGA_ROCKET_SAUCE,
|
||||
EGA_BRAWLER,
|
||||
EGA_SNIPER,
|
||||
EGA_CRITICAL_FAILURE,
|
||||
EGA_TEAM_PLAYER,
|
||||
EGA_ACCURACY,
|
||||
EGA_FRAGS,
|
||||
EGA_PERFECT,
|
||||
EGA_NUM_AWARDS
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
endGameAwardInfo_t
|
||||
|
||||
end-game award info
|
||||
================
|
||||
*/
|
||||
struct endGameAwardInfo_t {
|
||||
char* name;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
inGameAward_t
|
||||
|
||||
in-game award IDs
|
||||
================
|
||||
*/
|
||||
enum inGameAward_t {
|
||||
IGA_INVALID = 0,
|
||||
IGA_CAPTURE,
|
||||
IGA_HUMILIATION,
|
||||
IGA_IMPRESSIVE,
|
||||
IGA_EXCELLENT,
|
||||
IGA_ASSIST,
|
||||
IGA_DEFENSE,
|
||||
IGA_COMBO_KILL,
|
||||
IGA_RAMPAGE,
|
||||
IGA_HOLY_SHIT,
|
||||
IGA_NUM_AWARDS
|
||||
};
|
||||
|
||||
enum comboKillState_t {
|
||||
CKS_NONE,
|
||||
CKS_ROCKET_FIRED,
|
||||
CKS_ROCKET_HIT,
|
||||
CKS_RAIL_FIRED,
|
||||
CKS_RAIL_HIT,
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
inGameAwardInfo_t
|
||||
|
||||
in-game award info
|
||||
================
|
||||
*/
|
||||
struct inGameAwardInfo_t {
|
||||
char* name;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatAllocator
|
||||
|
||||
A simple block allocator for different stat objects.
|
||||
Note: this isn't a real heap; it has no delete or tracking of free blocks.
|
||||
It matches the memory usage of the rvStatManager which dumps its entire
|
||||
memory all at once at very specific times. If that ever changes, this will
|
||||
need to change.
|
||||
================
|
||||
*/
|
||||
|
||||
const int BLOCK_SIZE = 1024;
|
||||
const int MAX_BLOCKS = 128;
|
||||
|
||||
class rvStatAllocator {
|
||||
protected:
|
||||
byte blocks[ BLOCK_SIZE * MAX_BLOCKS ];
|
||||
short currentBlock; // current block
|
||||
size_t placeInBlock; // current position, offset from start of block
|
||||
size_t totalBytesUsed; // total bytes handed out from the allocator
|
||||
size_t totalAllocations; // total blocks handed out from the allocator
|
||||
size_t totalBytesAllocated; // total bytes in all allocated blocks
|
||||
size_t allocationsByType[ST_COUNT]; // one spare at [0]; allocations per type of event
|
||||
|
||||
void *GetBlock( size_t blockSize, int* blockNumOut = NULL );
|
||||
|
||||
public:
|
||||
rvStatAllocator();
|
||||
void Report();
|
||||
void Reset();
|
||||
|
||||
// object allocators
|
||||
rvStatBeginGame *AllocStatBeginGame ( int t, int* blockNumOut = NULL );
|
||||
rvStatEndGame *AllocStatEndGame ( int t, int* blockNumOut = NULL );
|
||||
rvStatClientConnect *AllocStatClientConnect ( int t, int client, int* blockNumOut = NULL );
|
||||
rvStatHit *AllocStatHit ( int t, int p, int v, int w, bool countForAccuracy, int* blockNumOut = NULL );
|
||||
rvStatKill *AllocStatKill ( int t, int p, int v, bool g, int mod, int* blockNumOut = NULL );
|
||||
rvStatDeath *AllocStatDeath ( int t, int p, int mod, int* blockNumOut = NULL );
|
||||
rvStatDamageDealt *AllocStatDamageDealt ( int t, int p, int w, int d, int* blockNumOut = NULL );
|
||||
rvStatDamageTaken *AllocStatDamageTaken ( int t, int p, int w, int d, int* blockNumOut = NULL );
|
||||
rvStatFlagDrop *AllocStatFlagDrop ( int t, int p, int a, int tm, int* blockNumOut = NULL );
|
||||
rvStatFlagReturn *AllocStatFlagReturn ( int t, int p, int tm, int* blockNumOut = NULL );
|
||||
rvStatFlagCapture *AllocStatFlagCapture ( int t, int p, int f, int tm, int* blockNumOut = NULL );
|
||||
|
||||
// bookkeeping readers
|
||||
ID_INLINE size_t GetBytesLeftInBlock() const {
|
||||
assert( placeInBlock <= BLOCK_SIZE );
|
||||
return ( size_t )( BLOCK_SIZE - placeInBlock );
|
||||
}
|
||||
|
||||
ID_INLINE size_t GetPlaceInBlock() const {
|
||||
return placeInBlock;
|
||||
}
|
||||
|
||||
ID_INLINE size_t GetTotalBytesUsed() const {
|
||||
return totalBytesUsed;
|
||||
}
|
||||
|
||||
ID_INLINE size_t GetTotalAllocations() const {
|
||||
return totalAllocations;
|
||||
}
|
||||
|
||||
ID_INLINE size_t GetAllocationsByType( statType_t type ) const {
|
||||
return allocationsByType[ type ];
|
||||
}
|
||||
|
||||
ID_INLINE size_t GetTotalBytesAllocated() const {
|
||||
return totalBytesAllocated;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvPlayerStat
|
||||
|
||||
Stores one player's stat information.
|
||||
================
|
||||
*/
|
||||
class rvPlayerStat {
|
||||
public:
|
||||
rvPlayerStat();
|
||||
|
||||
void Clear( void );
|
||||
void CalculateStats( int p, const idList<rvStat*>& playerStats );
|
||||
|
||||
void PackStats( idBitMsg& msg );
|
||||
void UnpackStats( const idBitMsg& msg );
|
||||
|
||||
int weaponShots[ MAX_WEAPONS ];
|
||||
int weaponHits[ MAX_WEAPONS ];
|
||||
|
||||
int weaponKills[ MAX_WEAPONS ];
|
||||
|
||||
int kills;
|
||||
int deaths;
|
||||
int suicides;
|
||||
float damageRatio;
|
||||
|
||||
// asalmon: added for Xenon
|
||||
// ddynerman: also used on PC
|
||||
int damageGiven;
|
||||
int damageTaken;
|
||||
|
||||
idList<endGameAward_t> endGameAwards;
|
||||
// asalmon: changed this to just an array of counts
|
||||
int inGameAwards[IGA_NUM_AWARDS];
|
||||
|
||||
int lastUpdateTime;
|
||||
};
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatManager
|
||||
|
||||
The statistics management interface. This is the entrypoint into
|
||||
statistics from the game.
|
||||
|
||||
The game calls into rvStatManager at appropriate times (i.e. 'FlagCaptured')
|
||||
|
||||
rvStatManager creates stat events (see StatEvent.h) with the appropriate
|
||||
information and append them to the statQueue.
|
||||
|
||||
The statQueue is parsed at the end of a game to tabulate statistics, give
|
||||
end-game awards.
|
||||
|
||||
================
|
||||
*/
|
||||
class rvStatManager {
|
||||
public:
|
||||
rvStatManager();
|
||||
|
||||
void Init( void );
|
||||
void Shutdown( void );
|
||||
|
||||
// generic events
|
||||
void BeginGame( void );
|
||||
void EndGame( void );
|
||||
void ClientConnect( int clientNum );
|
||||
void ClientDisconnect( int clientNum );
|
||||
void WeaponFired( const idPlayer* player, int weapon, int num );
|
||||
void WeaponHit( const idActor* attacker, const idEntity* victim, int weapon, bool countForAccuracy = true );
|
||||
void Damage( const idEntity* attacker, const idEntity* victim, int weapon, int damage );
|
||||
|
||||
|
||||
// ctf-specific events
|
||||
void FlagCaptured( const idPlayer* player, int flagTeam );
|
||||
void FlagDropped( const idPlayer* player, const idEntity* attacker );
|
||||
void FlagReturned( const idPlayer* player );
|
||||
|
||||
|
||||
// shared events
|
||||
void Kill( const idPlayer* victim, const idEntity* killer, int methodOfDeath );
|
||||
|
||||
void DebugPrint( void );
|
||||
|
||||
rvPlayerStat* GetPlayerStats( void ) { return playerStats; };
|
||||
rvPlayerStat* GetPlayerStat( int clientNum );
|
||||
|
||||
void CalculateEndGameStats( void );
|
||||
|
||||
void GivePlayerCashForAward( idPlayer* player, inGameAward_t award );
|
||||
void GiveInGameAward( inGameAward_t award, int clientNum );
|
||||
|
||||
// network transmission
|
||||
void SendStat( int toClient, int statClient );
|
||||
void ReceiveStat( const idBitMsg& msg );
|
||||
|
||||
void SendInGameAward( inGameAward_t award, int clientNum );
|
||||
void ReceiveInGameAward( const idBitMsg& msg );
|
||||
void CheckAwardQueue();
|
||||
|
||||
void ClearStats( void );
|
||||
|
||||
int DamageGiven( int playerNum, int lowerBound = idMath::INT_MIN, int upperBound = idMath::INT_MAX );
|
||||
int DamageTaken( int playerNum, int lowerBound = idMath::INT_MIN, int upperBound = idMath::INT_MAX );
|
||||
|
||||
void UpdateInGameHud( idUserInterface* statHud, bool visible );
|
||||
void UpdateEndGameHud( idUserInterface* statHud, int clientNum );
|
||||
void SetupEndGameHud( idUserInterface* statHud );
|
||||
|
||||
rvStat* GetLastClientStat( int clientNum, statType_t type, int time );
|
||||
void GetLastClientStats( int clientNum, statType_t type, int time, int num, rvStat** results );
|
||||
rvStatTeam* GetLastTeamStat( int team, statType_t type, int time );
|
||||
rvStat* GetStat( int i );
|
||||
|
||||
void GetAccuracyLeaders( int accuracyLeaders[ MAX_WEAPONS ] );
|
||||
|
||||
void SetupStatWindow( idUserInterface* statHud );
|
||||
void SelectStatWindow( int selectionIndex, int selectionTeam );
|
||||
int GetSelectedClientNum( int* selectionIndexOut = NULL, int* selectionTeamOut = NULL );
|
||||
|
||||
//asalmon: Sends all stats to all clients. For Xenon periodic update of stats.
|
||||
void SendAllStats( int clientNum = -1, bool full = true );
|
||||
void ReceiveAllStats( const idBitMsg& msg );
|
||||
|
||||
void SetDamageGiven(int client, int damage) { playerStats[client].damageGiven = damage; }
|
||||
void SetDamageTaken(int client, int damage) { playerStats[client].damageTaken = damage; }
|
||||
|
||||
int FreeEvents( int blockNum );
|
||||
|
||||
static comboKillState_t comboKillState[ MAX_CLIENTS ];
|
||||
static int lastRailShot[ MAX_CLIENTS ];
|
||||
static int lastRailShotHits[ MAX_CLIENTS ];
|
||||
|
||||
private:
|
||||
idList<rvPair<rvStat*, int> > statQueue;
|
||||
idList<rvPair<int, bool> > awardQueue;
|
||||
// idList<rvStatInGame> inGameStats;
|
||||
// rvStatInGame previousInGameStats[ MAX_CLIENTS ];
|
||||
// rvStatInGame localClientInGameStats;
|
||||
|
||||
// local hud support
|
||||
int localInGameAwards[ IGA_NUM_AWARDS ];
|
||||
int inGameAwardHudTime;
|
||||
|
||||
rvPlayerStat playerStats[ MAX_CLIENTS ];
|
||||
|
||||
bool endGameSetup;
|
||||
|
||||
rvStatWindow statWindow;
|
||||
|
||||
// shouchard: stat allocator to avoid lots of little news
|
||||
rvStatAllocator statAllocator;
|
||||
|
||||
#ifdef _XENON
|
||||
int lastFullUpdate;
|
||||
#endif
|
||||
|
||||
#if ID_TRAFFICSTATS
|
||||
int startSent;
|
||||
int startPacketsSent;
|
||||
int startReceived;
|
||||
int startPacketsReceived;
|
||||
int startTime;
|
||||
#endif
|
||||
};
|
||||
|
||||
ID_INLINE rvStat* rvStatManager::GetStat( int i ) {
|
||||
if( i < 0 || i >= statQueue.Num() ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return statQueue[ i ].First();
|
||||
}
|
||||
|
||||
extern rvStatManager* statManager;
|
||||
extern inGameAwardInfo_t inGameAwardInfo[ IGA_NUM_AWARDS ];
|
||||
extern endGameAwardInfo_t endGameAwardInfo[ EGA_NUM_AWARDS ];
|
||||
|
||||
#endif /* !__STATMANAGER_H__ */
|
||||
@@ -0,0 +1,462 @@
|
||||
//----------------------------------------------------------------
|
||||
// StatWindow.cpp
|
||||
//
|
||||
// Copyright 2002-2005 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../../Game_local.h"
|
||||
|
||||
#include "StatWindow.h"
|
||||
#include "StatManager.h"
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::rvStatWindow()
|
||||
================
|
||||
*/
|
||||
rvStatWindow::rvStatWindow() {
|
||||
statHud = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::SetupStatWindow()
|
||||
|
||||
Sets up a selectable window of current stats
|
||||
================
|
||||
*/
|
||||
void rvStatWindow::SetupStatWindow( idUserInterface* hud, bool useSpectator ) {
|
||||
idPlayer* player = gameLocal.GetLocalPlayer();
|
||||
assert( player );
|
||||
if ( !player ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// mekberg: added
|
||||
idList<int> marineScores;
|
||||
idList<int> stroggScores;
|
||||
|
||||
int selectionIndex = -1;
|
||||
int selectionTeam = -1;
|
||||
|
||||
statHud = hud;
|
||||
|
||||
if( gameLocal.IsTeamGame() ) {
|
||||
if( gameLocal.IsFlagGameType() ) {
|
||||
statHud->SetStateInt( "ctf_awards", 1 );
|
||||
} else {
|
||||
statHud->SetStateInt( "ctf_awards", 0 );
|
||||
}
|
||||
|
||||
stroggPlayers.Clear();
|
||||
marinePlayers.Clear();
|
||||
|
||||
for( int i = 0; i < gameLocal.mpGame.GetNumRankedPlayers(); i++ ) {
|
||||
idPlayer* player = gameLocal.mpGame.GetRankedPlayer( i );
|
||||
|
||||
if( player->team == TEAM_MARINE ) {
|
||||
marinePlayers.Append( player );
|
||||
marineScores.Append( gameLocal.mpGame.GetRankedPlayerScore( i ) );
|
||||
} else if ( player->team == TEAM_STROGG ) {
|
||||
stroggPlayers.Append( player );
|
||||
stroggScores.Append( gameLocal.mpGame.GetRankedPlayerScore( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ ) {
|
||||
if( i < marinePlayers.Num() ) {
|
||||
statHud->SetStateString( va( "team_1_names_item_%d", i ),
|
||||
va( "%s\t%s\t%s\t%d\t", ( player->IsFriend( marinePlayers[ i ] ) ? I_FRIEND_ENABLED : I_FRIEND_DISABLED ),
|
||||
( player->IsPlayerMuted( marinePlayers[ i ] ) ? I_VOICE_DISABLED : I_VOICE_ENABLED ),
|
||||
marinePlayers[ i ]->GetUserInfo()->GetString( "ui_name"),
|
||||
marineScores[ i ] ) );
|
||||
|
||||
if( useSpectator ) {
|
||||
if( marinePlayers[ i ]->entityNumber == player->spectator ) {
|
||||
selectionTeam = TEAM_MARINE;
|
||||
selectionIndex = i;
|
||||
}
|
||||
} else {
|
||||
if( marinePlayers[ i ] == player ) {
|
||||
selectionTeam = TEAM_MARINE;
|
||||
selectionIndex = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statHud->SetStateString( va( "team_1_names_item_%d", i ), "" );
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ ) {
|
||||
if( i < stroggPlayers.Num() ) {
|
||||
statHud->SetStateString( va( "team_2_names_item_%d", i ),
|
||||
va( "%s\t%s\t%s\t%d\t", ( player->IsFriend( stroggPlayers[ i ] ) ? I_FRIEND_ENABLED : I_FRIEND_DISABLED ),
|
||||
( player->IsPlayerMuted( stroggPlayers[ i ] ) ? I_VOICE_DISABLED : I_VOICE_ENABLED ),
|
||||
stroggPlayers[ i ]->GetUserInfo()->GetString( "ui_name"),
|
||||
stroggScores[ i ] ) );
|
||||
if( useSpectator ) {
|
||||
if( stroggPlayers[ i ]->entityNumber == player->spectator ) {
|
||||
selectionTeam = TEAM_STROGG;
|
||||
selectionIndex = i;
|
||||
}
|
||||
} else {
|
||||
if( stroggPlayers[ i ] == player ) {
|
||||
selectionTeam = TEAM_STROGG;
|
||||
selectionIndex = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statHud->SetStateString( va( "team_2_names_item_%d", i ), "" );
|
||||
}
|
||||
}
|
||||
|
||||
statHud->SetStateInt ( "num_strogg_players", stroggPlayers.Num() );
|
||||
statHud->SetStateInt ( "num_marine_players", marinePlayers.Num() );
|
||||
} else {
|
||||
statHud->SetStateInt( "ctf_awards", 0 );
|
||||
|
||||
players.Clear();
|
||||
|
||||
for( int i = 0; i < gameLocal.mpGame.GetNumRankedPlayers(); i++ ) {
|
||||
players.Append( gameLocal.mpGame.GetRankedPlayer( i ) );
|
||||
}
|
||||
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ ) {
|
||||
if( i < players.Num() ) {
|
||||
statHud->SetStateString( va( "dm_names_item_%d", i ),
|
||||
va( "%s\t%s\t%s\t%d\t", ( player->IsFriend( players[ i ] ) ? I_FRIEND_ENABLED : I_FRIEND_DISABLED ),
|
||||
( player->IsPlayerMuted( players[ i ] ) ? I_VOICE_DISABLED : I_VOICE_ENABLED ),
|
||||
players[ i ]->GetUserInfo()->GetString( "ui_name"),
|
||||
|
||||
gameLocal.mpGame.GetScore( players[ i ] ) ) );
|
||||
if( useSpectator ) {
|
||||
if( players[ i ]->entityNumber == player->spectator ) {
|
||||
selectionTeam = 0;
|
||||
selectionIndex = i;
|
||||
}
|
||||
} else {
|
||||
if( players[ i ] == player ) {
|
||||
selectionTeam = 0;
|
||||
selectionIndex = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statHud->SetStateString( va( "dm_names_item_%d", i ), "" );
|
||||
}
|
||||
}
|
||||
statHud->SetStateInt ( "num_players", players.Num() );
|
||||
}
|
||||
|
||||
// spectators
|
||||
spectators.Clear();
|
||||
|
||||
for( int i = 0; i < gameLocal.mpGame.GetNumUnrankedPlayers(); i++ ) {
|
||||
spectators.Append( gameLocal.mpGame.GetUnrankedPlayer( i ) );
|
||||
}
|
||||
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ ) {
|
||||
if( i < spectators.Num() ) {
|
||||
statHud->SetStateString( va( "spec_names_item_%d", i ),
|
||||
va( "%s\t%s\t%s\t", ( player->IsFriend( spectators[ i ] ) ? I_FRIEND_ENABLED : I_FRIEND_DISABLED ),
|
||||
( player->IsPlayerMuted( spectators[ i ] ) ? I_VOICE_DISABLED : I_VOICE_ENABLED ),
|
||||
spectators[ i ]->GetUserInfo()->GetString( "ui_name") ) );
|
||||
|
||||
if( useSpectator ) {
|
||||
if( spectators[ i ]->entityNumber == player->spectator ) {
|
||||
selectionTeam = TEAM_MAX;
|
||||
selectionIndex = i;
|
||||
}
|
||||
} else {
|
||||
if( spectators[ i ] == player ) {
|
||||
selectionTeam = TEAM_MAX;
|
||||
selectionIndex = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
statHud->SetStateString( va( "spec_names_item_%d", i ), "" );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
statHud->SetStateInt( "gametype", gameLocal.gameType );
|
||||
statHud->SetStateInt( "playerteam", gameLocal.GetLocalPlayer()->team );
|
||||
|
||||
statHud->StateChanged ( gameLocal.time );
|
||||
statHud->Redraw( gameLocal.time );
|
||||
|
||||
// we shouldn't ever draw a hud unless we're in-game
|
||||
assert( selectionIndex >= 0 && selectionTeam >= 0 );
|
||||
|
||||
|
||||
statManager->SelectStatWindow( selectionIndex, selectionTeam );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::ClearWindow()
|
||||
|
||||
Clears the stat part of the stat window, but not the player lists boxes
|
||||
================
|
||||
*/
|
||||
void rvStatWindow::ClearWindow( void ) {
|
||||
for( int i = 0; i < MAX_WEAPONS; i++ ) {
|
||||
statHud->SetStateString( va( "stat_%d_pct", i ), "" );
|
||||
}
|
||||
|
||||
for( int i = 0; i < IGA_NUM_AWARDS; i++ ) {
|
||||
statHud->SetStateString( inGameAwardInfo[ i ].name, "" );
|
||||
}
|
||||
|
||||
// end-game awards
|
||||
for( int i = 0; i < EGA_NUM_AWARDS; i++ ) {
|
||||
statHud->SetStateInt( va( "eg_award%d", i ), 0 );
|
||||
statHud->SetStateString( va( "eg_award%d_text", i ), "" );
|
||||
}
|
||||
|
||||
// kills
|
||||
statHud->SetStateString( "stat_frags", "" );
|
||||
|
||||
// deaths
|
||||
statHud->SetStateString( "stat_deaths", "" );
|
||||
|
||||
// score
|
||||
statHud->SetStateString( "stat_score", "" );
|
||||
|
||||
statHud->StateChanged ( gameLocal.time );
|
||||
statHud->Redraw( gameLocal.time );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::SelectPlayer()
|
||||
|
||||
Selects the specified player
|
||||
================
|
||||
*/
|
||||
void rvStatWindow::SelectPlayer( int clientNum ) {
|
||||
if( statHud == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( clientNum < 0 || clientNum >= MAX_CLIENTS ) {
|
||||
ClearWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
assert( gameLocal.GetLocalPlayer() );
|
||||
|
||||
rvPlayerStat* clientStat = statManager->GetPlayerStat( clientNum );
|
||||
|
||||
if( gameLocal.isClient && ( clientStat == NULL || ( gameLocal.time - clientStat->lastUpdateTime ) > 5000 ) ) {
|
||||
// get new stats
|
||||
idBitMsg outMsg;
|
||||
byte msgBuf[ 128 ];
|
||||
|
||||
outMsg.Init( msgBuf, sizeof( msgBuf ) );
|
||||
outMsg.WriteByte( GAME_RELIABLE_MESSAGE_STAT );
|
||||
outMsg.WriteByte( clientNum );
|
||||
networkSystem->ClientSendReliableMessage( outMsg );
|
||||
return;
|
||||
}
|
||||
|
||||
// weapon accuracy
|
||||
for( int i = 0; i < MAX_WEAPONS; i++ ) {
|
||||
int weaponAccuracy = 0;
|
||||
if( clientStat->weaponShots[ i ] != 0 ) {
|
||||
weaponAccuracy = (int)(((float)clientStat->weaponHits[ i ] / (float)clientStat->weaponShots[ i ]) * 100.0f);
|
||||
}
|
||||
statHud->SetStateString( va( "stat_%d_pct", i ), va( "%d%%", weaponAccuracy ) );
|
||||
}
|
||||
|
||||
int igAwardCount[ IGA_NUM_AWARDS ];
|
||||
memset( igAwardCount, 0, sizeof( int ) * IGA_NUM_AWARDS );
|
||||
for( int i = 0; i < IGA_NUM_AWARDS; i++ ) {
|
||||
igAwardCount[i] = clientStat->inGameAwards[i];
|
||||
}
|
||||
|
||||
for( int i = 0; i < IGA_NUM_AWARDS; i++ ) {
|
||||
statHud->SetStateString( inGameAwardInfo[ i ].name, va( "%d", igAwardCount[ i ] ) );
|
||||
}
|
||||
|
||||
// end-game awards
|
||||
for( int i = 0; i < EGA_NUM_AWARDS; i++ ) {
|
||||
if( i < clientStat->endGameAwards.Num() ) {
|
||||
statHud->SetStateInt( va( "eg_award%d", i ), 1 );
|
||||
// RAVEN BEGIN
|
||||
// rhummer: Localized the award strings..
|
||||
statHud->SetStateString( va( "eg_award%d_text", i ), common->GetLocalizedString( endGameAwardInfo[ clientStat->endGameAwards[ i ] ].name ) );
|
||||
// RAVEN END
|
||||
} else {
|
||||
statHud->SetStateInt( va( "eg_award%d", i), 0 );
|
||||
}
|
||||
}
|
||||
|
||||
// kills
|
||||
statHud->SetStateString( "stat_frags", va( "%d", clientStat->kills ) );
|
||||
|
||||
// deaths
|
||||
statHud->SetStateString( "stat_deaths", va( "%d", clientStat->deaths ) );
|
||||
|
||||
// score
|
||||
int score = gameLocal.IsTeamGame() ? (gameLocal.mpGame.GetTeamScore( clientNum ) + gameLocal.mpGame.GetScore( clientNum )): gameLocal.mpGame.GetScore( clientNum );
|
||||
statHud->SetStateString( "stat_score", va( "%d", score ) );
|
||||
|
||||
if( gameLocal.GetLocalPlayer()->IsFriend( clientNum ) ) {
|
||||
// remove friend label
|
||||
statHud->SetStateString( "friend_button", common->GetLocalizedString( "#str_200249" ) );
|
||||
} else {
|
||||
// add friend label
|
||||
statHud->SetStateString( "friend_button", common->GetLocalizedString( "#str_200248" ) );
|
||||
}
|
||||
|
||||
if( gameLocal.GetLocalPlayer()->IsPlayerMuted( clientNum ) ) {
|
||||
// unmute label
|
||||
statHud->SetStateString( "mute_button", common->GetLocalizedString( "#str_200251" ) );
|
||||
} else {
|
||||
// mute label
|
||||
statHud->SetStateString( "mute_button", common->GetLocalizedString( "#str_200250" ) );
|
||||
}
|
||||
|
||||
statHud->StateChanged ( gameLocal.time );
|
||||
statHud->Redraw( gameLocal.time );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::ClientNumFromSelection()
|
||||
|
||||
Parses a selection index and team into a clientNum
|
||||
================
|
||||
*/
|
||||
int rvStatWindow::ClientNumFromSelection( int selectionIndex, int selectionTeam ) {
|
||||
int clientNum = -1;
|
||||
|
||||
if( gameLocal.IsTeamGame() ) {
|
||||
if( selectionTeam == TEAM_MARINE ) {
|
||||
if( selectionIndex < 0 || selectionIndex >= marinePlayers.Num() ) {
|
||||
gameLocal.Warning( "rvStatManager::SelectPlayerStats() - invalid selection '%d'\n", selectionIndex );
|
||||
return -1;
|
||||
}
|
||||
clientNum = marinePlayers[ selectionIndex ]->entityNumber;
|
||||
|
||||
// explicitly set the gui selection if we called in here not from a GUI
|
||||
statHud->SetStateInt( "team_1_names_sel_0", selectionIndex );
|
||||
statHud->SetStateString( "dm_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "spec_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_2_names_sel_0", "-1" );
|
||||
} else if( selectionTeam == TEAM_STROGG ) {
|
||||
if( selectionIndex < 0 || selectionIndex >= stroggPlayers.Num() ) {
|
||||
gameLocal.Warning( "rvStatManager::SelectPlayerStats() - invalid selection '%d'\n", selectionIndex );
|
||||
return -1;
|
||||
}
|
||||
clientNum = stroggPlayers[ selectionIndex ]->entityNumber;
|
||||
|
||||
// explicitly set the gui selection if we called in here not from a GUI
|
||||
statHud->SetStateInt( "team_2_names_sel_0", selectionIndex );
|
||||
statHud->SetStateString( "dm_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "spec_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_1_names_sel_0", "-1" );
|
||||
} else {
|
||||
if( selectionIndex < 0 || selectionIndex >= spectators.Num() ) {
|
||||
gameLocal.Warning( "rvStatManager::SelectPlayerStats() - invalid selection '%d'\n", selectionIndex );
|
||||
return -1;
|
||||
}
|
||||
clientNum = spectators[ selectionIndex ]->entityNumber;
|
||||
|
||||
// explicitly set the gui selection if we called in here not from a GUI
|
||||
statHud->SetStateInt( "spec_names_sel_0", selectionIndex );
|
||||
statHud->SetStateString( "dm_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_1_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_2_names_sel_0", "-1" );
|
||||
}
|
||||
} else {
|
||||
if( selectionTeam == TEAM_MAX ) {
|
||||
if( selectionIndex < 0 || selectionIndex >= spectators.Num() ) {
|
||||
gameLocal.Warning( "rvStatManager::SelectPlayerStats() - invalid selection '%d'\n", selectionIndex );
|
||||
return -1;
|
||||
}
|
||||
clientNum = spectators[ selectionIndex ]->entityNumber;
|
||||
|
||||
// explicitly set the gui selection if we called in here not from a GUI
|
||||
statHud->SetStateInt( "spec_names_sel_0", selectionIndex );
|
||||
statHud->SetStateString( "dm_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_1_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_2_names_sel_0", "-1" );
|
||||
} else {
|
||||
if( selectionIndex < 0 || selectionIndex >= players.Num() ) {
|
||||
gameLocal.Warning( "rvStatManager::SelectPlayerStats() - invalid selection '%d'\n", selectionIndex );
|
||||
return -1;
|
||||
}
|
||||
clientNum = players[ selectionIndex ]->entityNumber;
|
||||
|
||||
// explicitly set the gui selection if we called in here not from a GUI
|
||||
statHud->SetStateInt( "dm_names_sel_0", selectionIndex );
|
||||
statHud->SetStateString( "spec_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_1_names_sel_0", "-1" );
|
||||
statHud->SetStateString( "team_2_names_sel_0", "-1" );
|
||||
}
|
||||
}
|
||||
|
||||
return clientNum;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
rvStatWindow::GetSelectedClientNum()
|
||||
|
||||
Queries the gui dict to figure out the currently selected selectionIndex/selectionTeam.
|
||||
Uses the selectionIndex/selectionTeam to return the selected client num.
|
||||
================
|
||||
*/
|
||||
int rvStatWindow::GetSelectedClientNum( int* selectionIndexOut, int* selectionTeamOut ) {
|
||||
if( statHud == NULL ) {
|
||||
return -1;
|
||||
}
|
||||
int selectionIndex = -1;
|
||||
int selectionTeam = -1;
|
||||
|
||||
// StatWindow update code should assure that only one selection of all these listDefs is is valid
|
||||
// Find the valid one
|
||||
if( statHud->State().GetInt( "spec_names_sel_0", "-1" ) >= 0 ) {
|
||||
selectionIndex = statHud->State().GetInt( "spec_names_sel_0", "-1" );
|
||||
selectionTeam = TEAM_MAX;
|
||||
}
|
||||
|
||||
if ( statHud->State().GetInt( "dm_names_sel_0", "-1" ) >= 0 ) {
|
||||
// if this assert fails, more than one selection is valid
|
||||
assert( selectionIndex == -1 && selectionTeam == -1 );
|
||||
|
||||
selectionIndex = statHud->State().GetInt( "dm_names_sel_0", "-1" );
|
||||
selectionTeam = 0;
|
||||
}
|
||||
|
||||
if ( statHud->State().GetInt( "team_1_names_sel_0", "-1" ) >= 0 ) {
|
||||
// if this assert fails, more than one selection is valid
|
||||
assert( selectionIndex == -1 && selectionTeam == -1 );
|
||||
|
||||
selectionIndex = statHud->State().GetInt( "team_1_names_sel_0", "-1" );
|
||||
selectionTeam = TEAM_MARINE;
|
||||
}
|
||||
|
||||
if ( statHud->State().GetInt( "team_2_names_sel_0", "-1" ) >= 0 ) {
|
||||
// if this assert fails, more than one selection is valid
|
||||
assert( selectionIndex == -1 && selectionTeam == -1 );
|
||||
|
||||
selectionIndex = statHud->State().GetInt( "team_2_names_sel_0", "-1" );
|
||||
selectionTeam = TEAM_STROGG;
|
||||
}
|
||||
|
||||
// return the selection index & team
|
||||
if( selectionIndexOut ) {
|
||||
(*selectionIndexOut) = selectionIndex;
|
||||
}
|
||||
if( selectionTeamOut ) {
|
||||
(*selectionTeamOut) = selectionTeam;
|
||||
}
|
||||
|
||||
return ClientNumFromSelection( selectionIndex, selectionTeam );
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//----------------------------------------------------------------
|
||||
// StatWindow.h
|
||||
//
|
||||
// Copyright 2002-2005 Raven Software
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifndef __STATWINDOW_H__
|
||||
#define __STATWINDOW_H__
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
Stat selection window
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
class rvStatWindow {
|
||||
public:
|
||||
rvStatWindow();
|
||||
void SetupStatWindow( idUserInterface* statHud, bool useSpectator = false );
|
||||
void SelectPlayer( int clientNum );
|
||||
int ClientNumFromSelection( int selectionIndex, int selectionTeam );
|
||||
void ClearWindow( void );
|
||||
int GetSelectedClientNum( int* selectionIndexOut, int* selectionTeamOut );
|
||||
private:
|
||||
idList<idPlayer*> stroggPlayers;
|
||||
idList<idPlayer*> marinePlayers;
|
||||
idList<idPlayer*> players;
|
||||
idList<idPlayer*> spectators;
|
||||
|
||||
idUserInterface* statHud;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user