quake4-sdk/source/game/mp/stats/StatWindow.cpp

463 lines
14 KiB
C++

//----------------------------------------------------------------
// StatWindow.cpp
//
// Copyright 2002-2005 Raven Software
//----------------------------------------------------------------
#include "../../../idlib/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 );
}