hl2_src-leak-2017/src/game/client/tf/tf_hud_mann_vs_machine_scor...

741 lines
26 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Scoreboard for MvM
//
// $NoKeywords: $
//=============================================================================
#include "cbase.h"
#include "tf_hud_mann_vs_machine_scoreboard.h"
#include <filesystem.h>
#include <time.h>
#include "tf_lobby_server.h"
using namespace vgui;
#ifdef STAGING_ONLY
ConVar cl_mvm_log_playerstats( "cl_mvm_log_playerstats", "0", FCVAR_ARCHIVE, "Internal dump of verbose player stats from mvm missions." );
#endif // STAGING_ONLY
extern ConVar tf_mvm_respec_credit_goal;
extern ConVar tf_mvm_respec_limit;
extern ConVar tf_scoreboard_alt_class_icons;
DECLARE_BUILD_FACTORY( CMvMScoreboardEnemyInfo );
//-----------------------------------------------------------------------------
CMvMScoreboardEnemyInfo::CMvMScoreboardEnemyInfo( Panel *parent, const char *pName ): vgui::EditablePanel( parent, pName )
{
}
//-----------------------------------------------------------------------------
void CMvMScoreboardEnemyInfo::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
// load control settings...
LoadControlSettings( "resource/UI/MvMScoreboardEnemyInfo.res" );
}
//-----------------------------------------------------------------------------
void CMvMScoreboardEnemyInfo::FireGameEvent( IGameEvent *event )
{
}
//-----------------------------------------------------------------------------
void CMvMScoreboardEnemyInfo::UpdateEntry( char* icon, bool bIsGiant )
{
const wchar_t *pwchHint = g_pVGuiLocalize->Find( VarArgs( "#TF_PVE_ROBOT_%s", icon ) );
if ( pwchHint && pwchHint[ 0 ] != L'\0' )
{
SetDialogVariable( "description", pwchHint );
}
else
{
SetDialogVariable( "description", VarArgs( "NYI: #TF_PVE_ROBOT_%s", icon ) );
}
CTFImagePanel *pImage = dynamic_cast< CTFImagePanel* >( FindChildByName( "EnemyIcon" ) );
if ( pImage )
{
pImage->SetImage( VarArgs( "../hud/leaderboard_class_%s", icon ) );
pImage->SetVisible( true );
}
Panel *pBGPanel = dynamic_cast< Panel* >( FindChildByName( "Background" ) );
if ( pBGPanel )
{
if ( bIsGiant )
{
pBGPanel->SetBgColor( m_clrMiniBoss );
}
else
{
pBGPanel->SetBgColor( m_clrNormal );
}
}
}
//-----------------------------------------------------------------------------
// CTFHudMannVsMachineScoreboard
//-----------------------------------------------------------------------------
DECLARE_BUILD_FACTORY( CTFHudMannVsMachineScoreboard );
CTFHudMannVsMachineScoreboard::CTFHudMannVsMachineScoreboard( Panel *parent, const char *pName ): vgui::EditablePanel( parent, pName )
{
m_pPlayerList = new SectionedListPanel( this, "MvMPlayerList" );
m_pImageList = NULL;
m_mapAvatarsToImageList.SetLessFunc( DefLessFunc( CSteamID ) );
m_mapAvatarsToImageList.RemoveAll();
m_pLocalPlayerStatsPanel = new vgui::EditablePanel( this, "LocalPlayerStatsPanel" );
m_pCreditStatsPanel = new vgui::EditablePanel( this, "CreditStatsContainer");
m_pDifficultyContainer = new vgui::EditablePanel( this, "DifficultyContainer");
m_iDisplayedWave = -1;
m_bInitialized = false;
m_iSquadSurplusTexture = 0;
Q_memset( m_iImageClass, NULL, sizeof( m_iImageClass ) );
Q_memset( m_iImageClassAlt, NULL, sizeof( m_iImageClassAlt ) );
ListenForGameEvent( "mvm_wave_complete" );
ListenForGameEvent( "mvm_reset_stats" );
ListenForGameEvent( "player_connect_client" );
}
//-----------------------------------------------------------------------------
CTFHudMannVsMachineScoreboard::~CTFHudMannVsMachineScoreboard()
{
if ( NULL != m_pImageList )
{
delete m_pImageList;
m_pImageList = NULL;
}
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::ApplySchemeSettings( IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
// load control settings...
LoadControlSettings( "resource/UI/MvMScoreboard.res" );
InitPlayerList( pScheme );
m_iDisplayedWave = -1;
if ( m_pCreditStatsPanel )
{
m_pPreviousWaveCreditsInfo = dynamic_cast<CCreditDisplayPanel*>( m_pCreditStatsPanel->FindChildByName("PreviousWaveCreditInfoPanel") );
m_pTotalCreditsInfo = dynamic_cast<CCreditDisplayPanel*>( m_pCreditStatsPanel->FindChildByName("TotalGameCreditInfoPanel") );
m_pPreviousWaveCreditsSpend = dynamic_cast<CCreditSpendPanel*>( m_pCreditStatsPanel->FindChildByName("PreviousWaveCreditSpendPanel") );
m_pTotalCreditsSpend = dynamic_cast<CCreditSpendPanel*>( m_pCreditStatsPanel->FindChildByName("TotalGameCreditSpendPanel") );
m_pRespecStatusLabel = dynamic_cast< CExLabel* >( m_pCreditStatsPanel->FindChildByName( "RespecStatusLabel" ) );
}
// Last
m_bInitialized = true;
m_popfile[0] = '\0'; // clear the popfile name so everything will be reset again in the UpdatePopFile() call in OnTick()
OnTick();
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::FireGameEvent( IGameEvent * event )
{
const char *pszEvent = event->GetName();
if ( !Q_strcmp( pszEvent, "mvm_wave_complete" ) )
{
if ( !g_TF_PR )
return;
#ifdef STAGING_ONLY
// Write our current state to a log file if we're configured to
if ( cl_mvm_log_playerstats.GetBool() )
{
WritePlayerScoreStats();
}
#endif // STAGING_ONLY
// Adds current stats to "prev" containers (i.e. current wave's stats added to total of all previous wave stats)
g_TF_PR->UpdatePlayerScoreStats();
}
else if ( !Q_strcmp( pszEvent, "mvm_reset_stats" ) )
{
if ( !g_TF_PR )
return;
g_TF_PR->ResetPlayerScoreStats();
}
else if ( !Q_strcmp( pszEvent, "player_connect_client" ) )
{
if ( !g_TF_PR )
return;
g_TF_PR->ResetPlayerScoreStats( event->GetInt( "index" ) + 1 );
}
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::OnTick ()
{
// Ensure the panels and everything else have been initialized
if (!m_bInitialized
|| !TFGameRules()
|| !TFGameRules()->IsMannVsMachineMode()
|| !TFObjectiveResource() )
{
return;
}
UpdatePlayerList();
UpdateCreditStats();
UpdatePopFile();
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::InitPlayerList ( IScheme *pScheme )
{
// Scoreboard
if ( m_pImageList )
{
delete m_pImageList;
}
m_pImageList = new ImageList( false );
m_mapAvatarsToImageList.RemoveAll();
m_pPlayerListBackground = dynamic_cast<vgui::ScalableImagePanel*>( FindChildByName("PlayerListBackground") );
m_iImageDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dead", true ) );
m_iSquadSurplusTexture = m_pImageList->AddImage( scheme()->GetImage( "pve/mvm_squad_surplus_small", true ) );
for(int i = 1 ; i < SCOREBOARD_CLASS_ICONS ; i++)
{
m_iImageClass[i] = m_pImageList->AddImage( scheme()->GetImage( g_pszClassIcons[i], true ) );
m_iImageClassAlt[i] = m_pImageList->AddImage( scheme()->GetImage( g_pszClassIconsAlt[i], true ) );
}
// resize the images to our resolution
for (int i = 1 ; i < m_pImageList->GetImageCount(); i++ )
{
int wide = 14, tall = 14;
m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(), wide ), scheme()->GetProportionalScaledValueEx( GetScheme(),tall ) );
}
m_pPlayerList->SetVerticalScrollbar( false );
m_pPlayerList->RemoveAll();
m_pPlayerList->RemoveAllSections();
m_pPlayerList->AddSection( 0, "Players" );
m_pPlayerList->SetSectionAlwaysVisible( 0, true );
m_pPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) );
m_pPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) );
m_pPlayerList->SetBorder( NULL );
m_hScoreFont = pScheme->GetFont( "ScoreboardVerySmall", true );
m_pPlayerList->AddColumnToSection( 0, "medal", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iMedalWidth );
m_pPlayerList->AddColumnToSection( 0, "spacer1", "", 0, m_iMedalSpacerWidth );
m_pPlayerList->AddColumnToSection( 0, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth );
m_pPlayerList->AddColumnToSection( 0, "spacer0", "", 0, m_iSpacerWidth );
m_pPlayerList->AddColumnToSection( 0, "name", "#TF_Scoreboard_Name", 0, m_iNameWidth );
m_pPlayerList->AddColumnToSection( 0, "class", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iClassWidth );
m_pPlayerList->AddColumnToSection( 0, "tour_no", "#TF_MvMScoreboard_Tour", SectionedListPanel::COLUMN_RIGHT, m_iClassWidth );
m_pPlayerList->AddColumnToSection( 0, "score", "#TF_Scoreboard_Score", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "damage", "#TF_MvMScoreboard_Damage", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "tank", "#TF_MvMScoreboard_Tank", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "healing", "#TF_MvMScoreboard_Healing", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "support", "#TF_MvMScoreboard_Support", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
// m_pPlayerList->AddColumnToSection( 0, "blocked", "Blocked", 0, m_iStatWidth );
// m_pPlayerList->AddColumnToSection( 0, "bonus", "Bonus", 0, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "credits", "#TF_MvMScoreboard_Money", SectionedListPanel::COLUMN_RIGHT, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "squad_surplus", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iStatWidth );
m_pPlayerList->AddColumnToSection( 0, "ping", "#TF_Scoreboard_Ping", SectionedListPanel::COLUMN_RIGHT, m_iPingWidth );
m_pPlayerList->SetImageList( m_pImageList, false );
m_pPlayerList->SetVisible( true );
}
//-----------------------------------------------------------------------------
char *ConvertScoreboardValueToString( int iValue )
{
static char szConversion[32];
szConversion[0] = '\0';
if ( iValue >= 1000000 )
{
V_sprintf_safe( szConversion, "%d%s%d%d%d%s%d%d%d", iValue / 1000000, ",", ( iValue % 1000000 ) / 100000, ( iValue % 100000 ) / 10000, ( iValue % 10000 ) / 1000, ",", ( iValue % 1000 ) / 100, ( iValue % 100 ) / 10, iValue % 10 );
}
else if ( iValue >= 1000 )
{
V_sprintf_safe( szConversion, "%d%s%d%d%d", iValue / 1000, ",", ( iValue % 1000 ) / 100, ( iValue % 100 ) / 10, iValue % 10 );
}
else if ( iValue >= 0 )
{
V_sprintf_safe( szConversion, "%d", iValue );
}
return szConversion;
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdatePlayerList ()
{
m_pPlayerList->ClearSelection();
m_pPlayerList->RemoveAll();
if ( !g_TF_PR )
return;
for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ )
{
if( !g_PR->IsConnected( playerIndex ) )
{
continue;
}
if ( g_PR->GetTeam( playerIndex ) != TF_TEAM_PVE_DEFENDERS )
{
continue;
}
const char *szName = g_TF_PR->GetPlayerName( playerIndex );
KeyValues *pKeyValues = new KeyValues( "data" );
pKeyValues->SetInt( "playerIndex", playerIndex );
pKeyValues->SetString( "name", szName );
bool bAlive = g_TF_PR->IsAlive( playerIndex );
if( g_PR->IsConnected( playerIndex ) )
{
int iClass = g_TF_PR->GetPlayerClass( playerIndex );
if ( GetLocalPlayerIndex() == playerIndex && !bAlive )
{
// If this is local player and he is dead, show desired class (which he will spawn as) rather than current class.
C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
int iDesiredClass = pPlayer->m_Shared.GetDesiredPlayerClassIndex();
// use desired class unless it's random -- if random, his future class is not decided until moment of spawn
if ( TF_CLASS_RANDOM != iDesiredClass )
{
iClass = iDesiredClass;
}
}
else
{
// for non-local players, show the current class
iClass = g_TF_PR->GetPlayerClass( playerIndex );
}
if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= TF_LAST_NORMAL_CLASS )
{
if ( bAlive )
{
pKeyValues->SetInt( "class", tf_scoreboard_alt_class_icons.GetBool() ? m_iImageClassAlt[iClass] : m_iImageClass[iClass] );
}
else
{
pKeyValues->SetInt( "class", tf_scoreboard_alt_class_icons.GetBool() ? m_iImageClassAlt[iClass + 9] : m_iImageClass[iClass + 9] ); // +9 is to jump ahead to the darker dead icons
}
}
else
{
pKeyValues->SetInt( "class", 0 );
}
}
// check for bots first, so malicious server operators can't fake a ping and stuff their server with bots that look like players
if ( g_PR->IsFakePlayer( playerIndex ) )
{
pKeyValues->SetString( "ping", "#TF_Scoreboard_Bot" );
}
else
{
if ( g_PR->GetPing( playerIndex ) < 1 )
{
pKeyValues->SetString( "ping", "" );
}
else
{
pKeyValues->SetString( "ping", ConvertScoreboardValueToString( g_PR->GetPing( playerIndex ) ) );
}
}
Color fgClr;
Color bgClr;
// change color based off alive or dead status. Also slightly different if its local player since the name is highlighted.
if ( bAlive )
{
UpdatePlayerAvatar( playerIndex, pKeyValues );
fgClr = g_PR->GetTeamColor( TF_TEAM_RED );
bgClr = Color( 0, 0, 0, 0 );
}
else
{
pKeyValues->SetInt( "avatar", m_iImageDead );
fgClr = Color( 117, 107, 94, 255 );
bgClr = Color( 78, 78, 78, 150 );
}
// the medal column is just a place holder for the images that are displayed later
pKeyValues->SetInt( "medal", 0 );
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
CTFGSLobby *pLobby = GTFGCClientSystem()->GetLobby();
if ( pLobby )
{
int nTourNo = 0;
int bSurplusEnabled = false;
const CTFLobbyMember *pMember = pLobby->GetMemberDetails( GetSteamIDForPlayerIndex( playerIndex ) );
if ( pMember )
{
bSurplusEnabled = pMember->squad_surplus();
nTourNo = pMember->badge_level();
}
if ( bSurplusEnabled )
{
pKeyValues->SetInt( "squad_surplus", m_iSquadSurplusTexture );
}
else
{
pKeyValues->SetInt( "squad_surplus", 0 );
}
if ( nTourNo > 0 )
{
pKeyValues->SetString( "tour_no", ConvertScoreboardValueToString( nTourNo ) );
}
else
{
pKeyValues->SetString( "tour_no", "" );
}
}
// int nTeam = g_PR->GetTeam( playerIndex );
// int nTeamDamage = g_TF_PR->GetTeamDamage( nTeam );
// int nTeamTankDamage = g_TF_PR->GetTeamDamageBoss( nTeam );
// int nTeamAssist = g_TF_PR->GetTeamDamageAssist( nTeam ) + g_TF_PR->GetTeamHealingAssist( nTeam );
// int nTeamHealing = g_TF_PR->GetTeamHealingAssist( nTeam );
// Note: Inflate bonus points when bucketing with healing and damage assist.
// We do this because each have different weights. Example: Every 250 points
// of healing or damage assist results in 1 point of Score. Bonus requires
// only 10. This makes it easier for players to evaluate their "support" value.
int nSupport = g_TF_PR->GetDamageAssist( playerIndex ) +
g_TF_PR->GetHealingAssist( playerIndex ) +
g_TF_PR->GetDamageBlocked( playerIndex ) +
( g_TF_PR->GetBonusPoints( playerIndex ) * 25 );
pKeyValues->SetString( "score", ConvertScoreboardValueToString( g_TF_PR->GetTotalScore( playerIndex ) ) );
pKeyValues->SetString( "damage", ConvertScoreboardValueToString( g_TF_PR->GetDamage( playerIndex ) ) );
pKeyValues->SetString( "tank", ConvertScoreboardValueToString( g_TF_PR->GetDamageBoss( playerIndex ) ) );
pKeyValues->SetString( "healing", ConvertScoreboardValueToString( g_TF_PR->GetHealing( playerIndex ) ) );
pKeyValues->SetString( "support", ConvertScoreboardValueToString( nSupport ) );
//pKeyValues->SetString( "blocked", ConvertScoreboardValueToString( g_TF_PR->GetDamageBlocked( playerIndex ) ) );
//pKeyValues->SetString( "bonus", ConvertScoreboardValueToString( g_TF_PR->GetBonusPoints( playerIndex ) ) );
pKeyValues->SetString( "credits", ConvertScoreboardValueToString( g_TF_PR->GetCurrencyCollected( playerIndex ) ) );
}
int itemID = m_pPlayerList->AddItem( 0, pKeyValues );
m_pPlayerList->SetItemFgColor( itemID, fgClr );
m_pPlayerList->SetItemBgColor( itemID, bgClr );
m_pPlayerList->SetItemFont( itemID, m_hScoreFont );
pKeyValues->deleteThis();
}
// force the list to PerformLayout() now so we can update our medal images after we return
m_pPlayerList->InvalidateLayout( true );
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdatePlayerAvatar( int playerIndex, KeyValues *kv )
{
// Update their avatar
if ( kv && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
{
player_info_t pi;
if ( engine->GetPlayerInfo( playerIndex, &pi ) )
{
if ( pi.friendsID )
{
CSteamID steamIDForPlayer( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
// See if we already have that avatar in our list
int iMapIndex = m_mapAvatarsToImageList.Find( steamIDForPlayer );
int iImageIndex;
if ( iMapIndex == m_mapAvatarsToImageList.InvalidIndex() )
{
CAvatarImage *pImage = new CAvatarImage();
pImage->SetAvatarSteamID( steamIDForPlayer );
pImage->SetAvatarSize( 32, 32 ); // Deliberately non scaling
pImage->SetDrawFriend( false );
iImageIndex = m_pImageList->AddImage( pImage );
m_mapAvatarsToImageList.Insert( steamIDForPlayer, iImageIndex );
}
else
{
iImageIndex = m_mapAvatarsToImageList[ iMapIndex ];
}
kv->SetInt( "avatar", iImageIndex );
CAvatarImage *pAvIm = (CAvatarImage *)m_pImageList->GetImage( iImageIndex );
pAvIm->UpdateFriendStatus();
}
}
}
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdateCreditStats()
{
int iWaveNumber = TFObjectiveResource()->GetMannVsMachineWaveCount() - 1;
if ( ( TFObjectiveResource()->GetMannVsMachineIsBetweenWaves() == true ) && ( iWaveNumber > 0 ) )
{
iWaveNumber--; // Examine Previous wave credits
}
if ( !m_pPreviousWaveCreditsInfo || !m_pTotalCreditsInfo )
{
return;
}
CMannVsMachineStats *pMVMStats = MannVsMachineStats_GetInstance();
if ( pMVMStats == NULL )
{
return;
}
// Previous or current
int nAcquired = pMVMStats->GetAcquiredCredits( iWaveNumber, false );
int nMissed = pMVMStats->GetMissedCredits( iWaveNumber );
int nBonus = pMVMStats->GetBonusCredits( iWaveNumber );
wchar_t wszWaveNumber[16];
_snwprintf( wszWaveNumber, ARRAYSIZE( wszWaveNumber ), L"%d", MAX( 1, iWaveNumber + 1 ) );
wchar_t wszLocalizedWave[512];
g_pVGuiLocalize->ConstructString_safe( wszLocalizedWave, g_pVGuiLocalize->Find( "#TF_PVE_WaveCount" ), 1, wszWaveNumber );
m_pPreviousWaveCreditsInfo->SetDialogVariable( "header", wszLocalizedWave );
UpdateCreditPanel( m_pPreviousWaveCreditsInfo, nAcquired, nMissed, nBonus );
// Total
nAcquired = pMVMStats->GetAcquiredCredits( -1, false );
nMissed = pMVMStats->GetMissedCredits( -1 );
nBonus = pMVMStats->GetBonusCredits( -1 );
m_pTotalCreditsInfo->SetDialogVariable( "header", g_pVGuiLocalize->Find( "#TF_PVE_GameTotal" ) );
UpdateCreditPanel( m_pTotalCreditsInfo, nAcquired, nMissed, nBonus );
// Credit Spend
if ( m_pPreviousWaveCreditsSpend )
{
m_pPreviousWaveCreditsSpend->SetDialogVariable( "header", "" );
}
CPlayerWaveSpendingStats *pWaveStats = pMVMStats->GetLocalSpending( iWaveNumber );
int nUpgradeSpending = pWaveStats ? pWaveStats->nCreditsSpentOnUpgrades : 0;
int nBuyBackSpending = pWaveStats ? pWaveStats->nCreditsSpentOnBuyBacks : 0;
int nBottleSpending = pWaveStats ? pWaveStats->nCreditsSpentOnBottles : 0;
UpdateCreditSpend( m_pPreviousWaveCreditsSpend, nUpgradeSpending, nBuyBackSpending, nBottleSpending );
if ( m_pTotalCreditsSpend )
{
m_pTotalCreditsSpend->SetDialogVariable( "header", "" );
}
// Get the current WaveStats, have to re-add 1 from above
if ( ( TFObjectiveResource()->GetMannVsMachineIsBetweenWaves() == true ) && ( TFObjectiveResource()->GetMannVsMachineWaveCount() > 1 ) )
{
pWaveStats = pMVMStats->GetLocalSpending( iWaveNumber + 1 );
}
else
{
pWaveStats = pMVMStats->GetLocalSpending( iWaveNumber );
}
nUpgradeSpending = pWaveStats ? pWaveStats->nCreditsSpentOnUpgrades : 0;
nBuyBackSpending = pWaveStats ? pWaveStats->nCreditsSpentOnBuyBacks : 0;
nBottleSpending = pWaveStats ? pWaveStats->nCreditsSpentOnBottles : 0;
pWaveStats = pMVMStats->GetLocalSpending( -1 );
nUpgradeSpending += pWaveStats ? pWaveStats->nCreditsSpentOnUpgrades : 0;
nBuyBackSpending += pWaveStats ? pWaveStats->nCreditsSpentOnBuyBacks : 0;
nBottleSpending += pWaveStats ? pWaveStats->nCreditsSpentOnBottles : 0;
UpdateCreditSpend( m_pTotalCreditsSpend, nUpgradeSpending, nBuyBackSpending, nBottleSpending );
if ( m_pRespecStatusLabel )
{
// Respec progress. Don't show if we aren't limiting respecs.
bool bShowRespec = TFGameRules() && TFGameRules()->IsMannVsMachineRespecEnabled() && tf_mvm_respec_limit.GetInt();
if ( m_pRespecStatusLabel->IsVisible() != bShowRespec )
{
m_pRespecStatusLabel->SetVisible( bShowRespec );
}
if ( bShowRespec )
{
int nCredits = pMVMStats->GetAcquiredCreditsForRespec();
int nCreditGoal = tf_mvm_respec_credit_goal.GetInt();
wchar_t wzRespecProg[256];
wchar_t wzCredits[32];
wchar_t wzGoal[32];
g_pVGuiLocalize->ConvertANSIToUnicode( CFmtStr( "%d", nCredits ), wzCredits, sizeof( wzCredits ) );
g_pVGuiLocalize->ConvertANSIToUnicode( CFmtStr( "%d", nCreditGoal ), wzGoal, sizeof( wzGoal ) );
g_pVGuiLocalize->ConstructString_safe( wzRespecProg, g_pVGuiLocalize->Find( "#TF_PVE_RespecsProgress" ), 2, wzCredits, wzGoal );
m_pRespecStatusLabel->SetText( wzRespecProg );
}
}
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdateCreditPanel( CCreditDisplayPanel *panel, int nAcquired, int nMissed, int nBonus )
{
panel->SetDialogVariable( "creditscollected", nAcquired );
panel->SetDialogVariable( "creditsmissed", nMissed );
panel->SetDialogVariable( "creditbonus", nBonus );
int nDropped = nAcquired + nMissed;
if ( ( TFGameRules() && TFGameRules()->State_Get() == GR_STATE_BETWEEN_RNDS && TFObjectiveResource()->GetMannVsMachineWaveCount() == 1 ) || nDropped == 0 )
{
panel->SetDialogVariable( "rating", "" );
panel->SetDialogVariable( "ratingshadow", "" );
return;
}
//calc a score
const char* pletterScore = "F";
float fPercent = (float)nAcquired / (float)nDropped;
if ( fPercent >= 1.0 )
{
pletterScore = "A+";
}
else if ( fPercent >= 0.9 )
{
pletterScore = "A";
}
else if ( fPercent >= 0.8 )
{
pletterScore = "B";
}
else if ( fPercent >= 0.7 )
{
pletterScore = "C";
}
else if ( fPercent >= 0.6 )
{
pletterScore = "D";
}
panel->SetDialogVariable( "rating", pletterScore );
panel->SetDialogVariable( "ratingshadow", pletterScore );
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdateCreditSpend ( CCreditSpendPanel *panel, int nUpgrades, int nBuybacks, int nBottles )
{
if ( panel )
{
panel->SetDialogVariable( "upgrades", nUpgrades );
panel->SetDialogVariable( "buybacks", nBuybacks );
panel->SetDialogVariable( "bottles", nBottles );
}
}
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::UpdatePopFile( void )
{
if ( TFObjectiveResource() )
{
if ( Q_strcmp( m_popfile, TFObjectiveResource()->GetMvMPopFileName() ) != 0 )
{
V_strcpy_safe( m_popfile, TFObjectiveResource()->GetMvMPopFileName() );
char szTempName[MAX_PATH];
V_FileBase( m_popfile, szTempName, sizeof( szTempName ) );
int iChallengeIndex = GetItemSchema()->FindMvmMissionByName( szTempName );
if ( GetItemSchema()->GetMvmMissions().IsValidIndex( iChallengeIndex ) )
{
const MvMMission_t &mission = GetItemSchema()->GetMvmMissions()[ iChallengeIndex ];
wchar_t wszChallengeName[ 256 ];
g_pVGuiLocalize->ConstructString_safe( wszChallengeName, L"%s1 (%s2)", 2,
g_pVGuiLocalize->Find( mission.m_sDisplayName.Get() ), g_pVGuiLocalize->Find( mission.m_sMode.Get() ) );
SetDialogVariable( "popfile", wszChallengeName );
m_pDifficultyContainer->SetVisible( true );
m_pDifficultyContainer->SetDialogVariable( "difficultyvalue", g_pVGuiLocalize->Find( GetMvMChallengeDifficultyLocName( mission.m_eDifficulty ) ) );
}
else
{
SetDialogVariable( "popfile", GetMapDisplayName(szTempName) );
// Hide Difficulty Panel since we dont know what it is
m_pDifficultyContainer->SetVisible( false );
}
}
}
}
#ifdef STAGING_ONLY
//-----------------------------------------------------------------------------
void CTFHudMannVsMachineScoreboard::WritePlayerScoreStats( void )
{
if ( g_TF_PR )
{
FileHandle_t hFile = g_pFullFileSystem->Open( "mvm_mission_stats.txt", "a" );
if ( hFile != FILESYSTEM_INVALID_HANDLE )
{
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
tm newtime;
VCRHook_LocalTime( &newtime );
buf.Printf( "%s - Wave %d - %s", TFObjectiveResource()->GetMvMPopFileName(), TFObjectiveResource()->GetMannVsMachineWaveCount(), asctime( &newtime ) );
buf.Printf( "----\n" );
// Player stats
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
C_TFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );
if ( !pPlayer )
continue;
if ( pPlayer->GetTeamNumber() != TF_TEAM_PVE_DEFENDERS )
continue;
const char *pszClassName = GetPlayerClassName( g_TF_PR->GetPlayerClass( i ) );
buf.Printf( "%10.10s %8.8s\tScore: %-6d Damage: %-6d DmgAssist: %-6d Tank: %-6d Healing: %-6d HealAssist: %-6d Blocked: %-6d Money: %-6d Bonus: %-6d\n",
pPlayer->GetPlayerName(),
pszClassName ? pszClassName : "Unknown",
g_TF_PR->GetTotalScore( i ),
g_TF_PR->GetDamage( i ),
g_TF_PR->GetDamageAssist( i ),
g_TF_PR->GetDamageBoss( i ),
g_TF_PR->GetHealing( i ),
g_TF_PR->GetHealingAssist( i ),
g_TF_PR->GetDamageBlocked( i ),
g_TF_PR->GetCurrencyCollected( i ),
// Bonus points come from special events and helping teammates, such as:
// Resetting the bomb, killing a fully charged medic, shooting down projectiles
// extinguishing a teammate, pushing enemy giants away with airblast,
// removing a sapper from someone else's building, dispensers giving ammo to the team,
// someone gaining health from your sandvich, bow headshots, stunning enemies with baseballs,
// scouts killing medics that were actively healing
g_TF_PR->GetBonusPoints( i ) );
}
buf.Printf( "----\n\n" );
g_pFullFileSystem->Write( buf.String(), buf.TellPut(), hFile );
buf.Clear();
g_pFullFileSystem->Close( hFile );
}
}
}
#endif // STAGING_ONLY