diff options
Diffstat (limited to 'game/client/dod/VGUI/dodclientscoreboard.cpp')
| -rw-r--r-- | game/client/dod/VGUI/dodclientscoreboard.cpp | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/game/client/dod/VGUI/dodclientscoreboard.cpp b/game/client/dod/VGUI/dodclientscoreboard.cpp new file mode 100644 index 0000000..d26351d --- /dev/null +++ b/game/client/dod/VGUI/dodclientscoreboard.cpp @@ -0,0 +1,621 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "hud.h" +#include "dodclientscoreboard.h" +#include "c_team.h" +#include "c_dod_team.h" +#include "c_dod_playerresource.h" +#include "c_dod_player.h" +#include "dod_gamerules.h" +#include "backgroundpanel.h" + +#include <KeyValues.h> + +#include <vgui/IScheme.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include <vgui_controls/SectionedListPanel.h> +#include <vgui_controls/ImageList.h> + +#include "voice_status.h" + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CDODClientScoreBoardDialog::CDODClientScoreBoardDialog( IViewPort *pViewPort ):CClientScoreBoardDialog( pViewPort ) +{ + m_pPlayerListAllies = new SectionedListPanel( this, "PlayerListAllies" ); + m_pPlayerListAxis = new SectionedListPanel( this, "PlayerListAxis" ); + + m_iImageDead = 0; + m_iImageDominated = 0; + m_iImageNemesis = 0; + + m_pAllies_PlayerCount = new Label( this, "Allies_PlayerCount", "" ); + m_pAllies_Score = new Label( this, "Allies_Score", "" ); + m_pAllies_Kills = new Label( this, "Allies_Kills", "" ); + m_pAllies_Deaths = new Label( this, "Allies_Deaths", "" ); + m_pAllies_Ping = new Label( this, "Allies_Ping", "" ); + + m_pAxis_PlayerCount = new Label( this, "Axis_PlayerCount", "" ); + m_pAxis_Score = new Label( this, "Axis_Score", "" ); + m_pAxis_Kills = new Label( this, "Axis_Kills", "" ); + m_pAxis_Deaths = new Label( this, "Axis_Deaths", "" ); + m_pAxis_Ping = new Label( this, "Axis_Ping", "" ); + + ListenForGameEvent( "server_spawn" ); + SetDialogVariable( "server", "" ); + SetVisible( false ); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CDODClientScoreBoardDialog::~CDODClientScoreBoardDialog() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Paint background for rounded corners +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::PaintBackground() +{ + int wide, tall; + GetSize( wide, tall ); + + DrawRoundedBackground( m_bgColor, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Paint border for rounded corners +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::PaintBorder() +{ + int wide, tall; + GetSize( wide, tall ); + + DrawRoundedBorder( m_borderColor, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Apply scheme settings +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "Resource/UI/scoreboard.res" ); + + m_bgColor = GetSchemeColor( "SectionedListPanel.BgColor", GetBgColor(), pScheme ); + m_borderColor = pScheme->GetColor( "Yellow", Color( 251, 206, 60, 255 ) ); + + SetBgColor( Color( 0, 0, 0, 0 ) ); + SetBorder( pScheme->GetBorder( "BaseBorder" ) ); + + if ( m_pImageList ) + { + m_iImageDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dead", true ) ); + m_iImageDominated = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dominated", true ) ); + m_iImageNemesis = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_nemesis", true ) ); + + // resize the images to our resolution + for (int i = 1; i < m_pImageList->GetImageCount(); i++ ) + { + int wide = 13, tall = 13; + m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(), wide ), scheme()->GetProportionalScaledValueEx( GetScheme(),tall ) ); + } + } + + if ( m_pPlayerListAllies ) + { + m_pPlayerListAllies->SetImageList( m_pImageList, false ); + m_pPlayerListAllies->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pPlayerListAllies->SetBorder( NULL ); + m_pPlayerListAllies->SetVisible( true ); + } + + if ( m_pPlayerListAxis ) + { + m_pPlayerListAxis->SetImageList( m_pImageList, false ); + m_pPlayerListAxis->SetBgColor( Color( 0, 0, 0, 0 ) ); + m_pPlayerListAxis->SetBorder( NULL ); + m_pPlayerListAxis->SetVisible( true ); + } + + // turn off the default player list since we have our own + if ( m_pPlayerList ) + { + m_pPlayerList->SetVisible( false ); + } + + if ( m_pAllies_PlayerCount && m_pAllies_Score && m_pAllies_Kills && m_pAllies_Deaths && m_pAllies_Ping ) + { + m_pAllies_PlayerCount->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Score->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Kills->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Deaths->SetFgColor( COLOR_DOD_GREEN ); + m_pAllies_Ping->SetFgColor( COLOR_DOD_GREEN ); + } + + if ( m_pAxis_PlayerCount && m_pAxis_Score && m_pAxis_Kills && m_pAxis_Deaths && m_pAxis_Ping ) + { + m_pAxis_PlayerCount->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Score->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Kills->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Deaths->SetFgColor( COLOR_DOD_RED ); + m_pAxis_Ping->SetFgColor( COLOR_DOD_RED ); + } + + SetVisible( false ); + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: Resets the scoreboard panel +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::Reset() +{ + InitPlayerList( m_pPlayerListAllies, TEAM_ALLIES ); + InitPlayerList( m_pPlayerListAxis, TEAM_AXIS ); +} + +//----------------------------------------------------------------------------- +// Purpose: Sorts players +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::DODPlayerSortFunc( vgui::SectionedListPanel *list, int itemID1, int itemID2 ) +{ + KeyValues *it1 = list->GetItemData( itemID1 ); + KeyValues *it2 = list->GetItemData( itemID2 ); + Assert( it1 && it2 ); + + // first compare score + int v1 = it1->GetInt( "score" ); + int v2 = it2->GetInt( "score" ); + if ( v1 > v2 ) + return true; + else if ( v1 < v2 ) + return false; + + // then compare frags + v1 = it1->GetInt( "frags" ); + v2 = it2->GetInt( "frags" ); + if ( v1 > v2 ) + return true; + else if ( v1 < v2 ) + return false; + + // next compare deaths + v1 = it1->GetInt( "deaths" ); + v2 = it2->GetInt( "deaths" ); + if ( v1 > v2 ) + return false; + else if ( v1 < v2 ) + return true; + + // if score and deaths are the same, use player index to get deterministic sort + int iPlayerIndex1 = it1->GetInt( "playerIndex" ); + int iPlayerIndex2 = it2->GetInt( "playerIndex" ); + return ( iPlayerIndex1 > iPlayerIndex2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Inits the player list in a list panel +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::InitPlayerList( SectionedListPanel *pPlayerList, int teamNumber ) +{ + pPlayerList->SetVerticalScrollbar( false ); + pPlayerList->RemoveAll(); + pPlayerList->RemoveAllSections(); + pPlayerList->AddSection( 0, "Players", DODPlayerSortFunc ); + pPlayerList->SetSectionAlwaysVisible( 0, true ); + pPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) ); + pPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) ); + pPlayerList->SetBorder( NULL ); + + // set the section to have the team color + if ( teamNumber && GameResources() ) + { + pPlayerList->SetSectionFgColor( 0, GameResources()->GetTeamColor( teamNumber ) ); + } + + // Avatars are always displayed at 32x32 regardless of resolution + pPlayerList->AddColumnToSection( 0, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iProportionalAvatarWidth ); + pPlayerList->AddColumnToSection( 0, "name", "", 0, m_iNameWidth ); + pPlayerList->AddColumnToSection( 0, "status", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iStatusWidth ); + pPlayerList->AddColumnToSection( 0, "class", "", 0, m_iClassWidth ); + pPlayerList->AddColumnToSection( 0, "score", "", SectionedListPanel::COLUMN_RIGHT, m_iScoreWidth ); + pPlayerList->AddColumnToSection( 0, "frags", "", SectionedListPanel::COLUMN_RIGHT, m_iFragsWidth ); + pPlayerList->AddColumnToSection( 0, "deaths", "", SectionedListPanel::COLUMN_RIGHT, m_iDeathWidth ); + pPlayerList->AddColumnToSection( 0, "ping", "", SectionedListPanel::COLUMN_RIGHT, m_iPingWidth ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the dialog +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::Update() +{ + UpdateTeamInfo(); + UpdatePlayerList(); + UpdateSpectatorList(); + MoveToCenterOfScreen(); + + // update every second + m_fNextUpdateTime = gpGlobals->curtime + 1.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Updates information about teams +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdateTeamInfo() +{ + // update the team sections in the scoreboard + for ( int teamIndex = TEAM_ALLIES; teamIndex <= TEAM_AXIS; teamIndex++ ) + { + wchar_t *teamName = NULL;; + C_DODTeam *team = dynamic_cast<C_DODTeam *>( GetGlobalTeam(teamIndex) ); + if ( team ) + { + // choose dialog variables to set depending on team + const char *pDialogVarTeamScore = NULL; + const char *pDialogVarTeamPlayerCount = NULL; + const char *pDialogVarTeamPing = NULL; + const char *pDialogVarTeamDeaths = NULL; + const char *pDialogVarTeamFrags = NULL; + switch ( teamIndex ) + { + case TEAM_ALLIES: + teamName = g_pVGuiLocalize->Find( "#Teamname_Allies" ); + pDialogVarTeamScore = "allies_teamscore"; + pDialogVarTeamPlayerCount = "allies_teamplayercount"; + pDialogVarTeamPing = "allies_teamping"; + pDialogVarTeamDeaths = "allies_teamdeaths"; + pDialogVarTeamFrags = "allies_teamfrags"; + break; + case TEAM_AXIS: + teamName = g_pVGuiLocalize->Find( "#Teamname_Axis" ); + pDialogVarTeamScore = "axis_teamscore"; + pDialogVarTeamPlayerCount = "axis_teamplayercount"; + pDialogVarTeamPing = "axis_teamping"; + pDialogVarTeamDeaths = "axis_teamdeaths"; + pDialogVarTeamFrags = "axis_teamfrags"; + break; + default: + Assert( false ); + break; + } + + // update team name + wchar_t name[64]; + wchar_t string1[1024]; + wchar_t wNumPlayers[6]; + _snwprintf( wNumPlayers, ARRAYSIZE( wNumPlayers ), L"%i", team->Get_Number_Players() ); + if ( !teamName && team ) + { + g_pVGuiLocalize->ConvertANSIToUnicode( team->Get_Name(), name, sizeof( name ) ); + teamName = name; + } + if ( team->Get_Number_Players() == 1 ) + { + g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find( "#scoreboard_Player" ), 2, teamName, wNumPlayers ); + } + else + { + g_pVGuiLocalize->ConstructString( string1, sizeof(string1), g_pVGuiLocalize->Find( "#scoreboard_Players" ), 2, teamName, wNumPlayers ); + } + + // set # of players for team in dialog + SetDialogVariable( pDialogVarTeamPlayerCount, string1 ); + + // Rounds won ( + tick ) + wchar_t wTeamScore[128]; + wchar_t wRoundsWon[8]; + wchar_t wTickScore[8]; + _snwprintf( wRoundsWon, ARRAYSIZE( wRoundsWon ), L"%i", team->GetRoundsWon() ); + _snwprintf( wTickScore, ARRAYSIZE( wTickScore ), L"%i", team->Get_Score() ); + g_pVGuiLocalize->ConstructString( wTeamScore, sizeof(wTeamScore), g_pVGuiLocalize->Find( "#scoreboard_teamscore" ), 2, wRoundsWon, wTickScore ); + + // set team score in dialog + SetDialogVariable( pDialogVarTeamScore, wTeamScore ); + + int kills = 0; + int deaths = 0; + int pingsum = 0; + int numcounted = 0; + int ping; + + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if( g_PR->IsConnected( playerIndex ) && g_PR->GetTeam( playerIndex ) == teamIndex ) + { + ping = g_PR->GetPing( playerIndex ); + kills += g_PR->GetPlayerScore( playerIndex ); + deaths += g_PR->GetDeaths( playerIndex ); + + if ( ping >= 1 ) + { + pingsum += ping; + numcounted++; + } + } + } + + if ( numcounted > 0 ) + { + int ping = (int)( (float)pingsum / (float)numcounted ); + SetDialogVariable( pDialogVarTeamPing, ping ); + } + else + { + SetDialogVariable( pDialogVarTeamPing, "" ); + } + + SetDialogVariable( pDialogVarTeamFrags, kills ); + SetDialogVariable( pDialogVarTeamDeaths, deaths ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the player list +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdatePlayerList() +{ + m_pPlayerListAllies->RemoveAll(); + m_pPlayerListAxis->RemoveAll(); + + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return; + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pLocalPlayer ) + return; + + int iLocalPlayerIndex = GetLocalPlayerIndex(); + + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if( g_PR->IsConnected( playerIndex ) ) + { + SectionedListPanel *pPlayerList = NULL; + switch ( g_PR->GetTeam( playerIndex ) ) + { + case TEAM_ALLIES: + pPlayerList = m_pPlayerListAllies; + break; + case TEAM_AXIS: + pPlayerList = m_pPlayerListAxis; + break; + } + + if ( pPlayerList == NULL ) + { + continue; + } + + KeyValues *pKeyValues = new KeyValues( "data" ); + GetPlayerScoreInfo( playerIndex, pKeyValues ); + + if ( pLocalPlayer->m_Shared.IsPlayerDominatingMe( playerIndex ) ) + { + // if local player is dominated by this player, show a nemesis icon + pKeyValues->SetString( "class", "#Scoreboard_Nemesis" ); + pKeyValues->SetInt( "status", m_iImageNemesis ); + } + else if ( pLocalPlayer->m_Shared.IsPlayerDominated( playerIndex) ) + { + // if this player is dominated by the local player, show the domination icon + pKeyValues->SetString( "class", "#Scoreboard_Dominated" ); + pKeyValues->SetInt( "status", m_iImageDominated ); + } + + int itemID = pPlayerList->AddItem( 0, pKeyValues ); + Color clr = g_PR->GetTeamColor( g_PR->GetTeam( playerIndex ) ); + pPlayerList->SetItemFgColor( itemID, clr ); + + if ( playerIndex == iLocalPlayerIndex ) + { + pPlayerList->SetSelectedItem( itemID ); + } + + pKeyValues->deleteThis(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the spectator list +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::UpdateSpectatorList() +{ + char szSpectatorList[512] = "" ; + int nSpectators = 0; + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( ShouldShowAsSpectator( playerIndex ) ) + { + if ( nSpectators > 0 ) + { + Q_strncat( szSpectatorList, ", ", ARRAYSIZE( szSpectatorList ) ); + } + + Q_strncat( szSpectatorList, g_PR->GetPlayerName( playerIndex ), ARRAYSIZE( szSpectatorList ) ); + nSpectators++; + } + } + + wchar_t wzSpectators[512] = L""; + if ( nSpectators > 0 ) + { + const char *pchFormat = ( 1 == nSpectators ? "#ScoreBoard_Spectator" : "#ScoreBoard_Spectators" ); + + wchar_t wzSpectatorCount[16]; + wchar_t wzSpectatorList[1024]; + _snwprintf( wzSpectatorCount, ARRAYSIZE( wzSpectatorCount ), L"%i", nSpectators ); + g_pVGuiLocalize->ConvertANSIToUnicode( szSpectatorList, wzSpectatorList, sizeof( wzSpectatorList ) ); + g_pVGuiLocalize->ConstructString( wzSpectators, sizeof(wzSpectators), g_pVGuiLocalize->Find( pchFormat), 2, wzSpectatorCount, wzSpectatorList ); + } + + SetDialogVariable( "spectators", wzSpectators ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether the specified player index is a spectator +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::ShouldShowAsSpectator( int iPlayerIndex ) +{ + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return false; + + // see if player is connected + if ( dod_PR->IsConnected( iPlayerIndex ) ) + { + // either spectator or unassigned team should show in spectator list + int iTeam = dod_PR->GetTeam( iPlayerIndex ); + if ( TEAM_SPECTATOR == iTeam || TEAM_UNASSIGNED == iTeam ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Event handler +//----------------------------------------------------------------------------- +void CDODClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) +{ + const char *type = event->GetName(); + + if ( 0 == Q_strcmp( type, "server_spawn" ) ) + { + // set server name in scoreboard + const char *hostname = event->GetString( "hostname" ); + wchar_t wzHostName[256]; + wchar_t wzServerLabel[256]; + g_pVGuiLocalize->ConvertANSIToUnicode( hostname, wzHostName, sizeof( wzHostName ) ); + g_pVGuiLocalize->ConstructString( wzServerLabel, sizeof(wzServerLabel), g_pVGuiLocalize->Find( "#Scoreboard_Server" ), 1, wzHostName ); + SetDialogVariable( "server", wzServerLabel ); + } + + if( IsVisible() ) + { + Update(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Adds a new row to the scoreboard, from the playerinfo structure +//----------------------------------------------------------------------------- +bool CDODClientScoreBoardDialog::GetPlayerScoreInfo( int playerIndex, KeyValues *kv ) +{ + C_DOD_PlayerResource *dod_PR = dynamic_cast<C_DOD_PlayerResource *>( g_PR ); + if ( !dod_PR ) + return true; + + // Clean up the player name + const char *oldName = g_PR->GetPlayerName( playerIndex ); + int bufsize = strlen( oldName ) * 2 + 1; + char *newName = (char *)_alloca( bufsize ); + UTIL_MakeSafeName( oldName, newName, bufsize ); + kv->SetString( "name", newName ); + + kv->SetInt( "playerIndex", playerIndex ); + kv->SetInt( "score", dod_PR->GetScore( playerIndex ) ); + kv->SetInt( "frags", g_PR->GetPlayerScore( playerIndex ) ); + kv->SetInt( "deaths", g_PR->GetDeaths( playerIndex ) ); + kv->SetString( "class", "" ); + + UpdatePlayerAvatar( playerIndex, kv ); + + if ( g_PR->GetPing( playerIndex ) < 1 ) + { + if ( g_PR->IsFakePlayer( playerIndex ) ) + { + kv->SetString( "ping", "BOT" ); + } + else + { + kv->SetString( "ping", "" ); + } + } + else + { + kv->SetInt( "ping", g_PR->GetPing( playerIndex ) ); + } + + C_DODPlayer *pLocalPlayer = C_DODPlayer::GetLocalDODPlayer(); + if ( !pLocalPlayer ) + return true; + + int team = g_PR->GetTeam( playerIndex ); + int localteam = pLocalPlayer->GetTeamNumber(); + + // If we are on a team that shows class/status, and the local player is allowed to see this information + if( ( localteam == TEAM_SPECTATOR || localteam == TEAM_UNASSIGNED || team == localteam ) ) + { + // class name + if( g_PR->IsConnected( playerIndex ) ) + { + C_DODTeam *pTeam = dynamic_cast<C_DODTeam *>( GetGlobalTeam( team ) ); + + Assert( pTeam ); + + int cls = dod_PR->GetPlayerClass( playerIndex ); + + char szClassName[64]; + szClassName[0] = '\0'; + + if( cls != PLAYERCLASS_UNDEFINED ) + { + const CDODPlayerClassInfo &info = pTeam->GetPlayerClassInfo( cls ); + + g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( info.m_szPrintName ), szClassName, sizeof(szClassName) ); + } + + kv->SetString( "class", szClassName ); + } + else + { + Assert(0); + } + + // status + // display whether player is alive or dead (all players see this for all other players on both teams) + kv->SetInt( "status", g_PR->IsAlive( playerIndex ) ? 0 : m_iImageDead ); + } + + if ( g_PR->IsHLTV( playerIndex ) ) + { + // show #spectators in class field, it's transmitted as player's score + char numspecs[32]; + Q_snprintf( numspecs, sizeof( numspecs ), "%i Spectators", m_HLTVSpectators ); + kv->SetString( "class", numspecs ); + } + + return true; +} + +void CDODClientScoreBoardDialog::ShowPanel( bool bShow ) +{ + BaseClass::ShowPanel( bShow ); + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "global" ); + + if ( bShow ) + { + gHUD.LockRenderGroup( iRenderGroup ); + } + else + { + gHUD.UnlockRenderGroup( iRenderGroup ); + } +}
\ No newline at end of file |