Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

470 lines
14 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Create and display a win panel at the end of a round displaying interesting stats and info about the round.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "win_panel_round.h"
#include "vgui_controls/AnimationController.h"
#include "iclientmode.h"
#include "c_playerresource.h"
#include <vgui_controls/Label.h>
#include <vgui/ILocalize.h>
#include <vgui/ISurface.h>
#include <vgui/ISystem.h>
#include "fmtstr.h"
#include "cs_gamestats_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar cl_round_win_fade_time( "cl_round_win_fade_time", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
DECLARE_HUDELEMENT_DEPTH( WinPanel_Round, 1 ); // 1 is foreground
extern const wchar_t *LocalizeFindSafe( const char *pTokenName );
// helper function for converting wstrings to upper-case inline
// NB: this returns a pointer to a static buffer
wchar_t* UpperCaseWideString( const wchar_t* wszSource )
{
static wchar_t wszBuffer[256];
V_wcsncpy(wszBuffer, wszSource, sizeof(wszBuffer));
V_wcsupr(wszBuffer);
return wszBuffer;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
WinPanel_Round::WinPanel_Round( const char *pElementName ) :
BorderedPanel( NULL, pElementName ),
CHudElement( pElementName ),
m_bIsFading(false),
m_fFadeBeginTime(0.0f)
{
SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
SetParent(g_pClientMode->GetViewport());
SetScheme( "ClientScheme" );
RegisterForRenderGroup( "hide_for_scoreboard" );
m_bShouldBeVisible = false;
}
WinPanel_Round::~WinPanel_Round()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void WinPanel_Round::Reset()
{
Hide();
}
void WinPanel_Round::Init()
{
CHudElement::Init();
// listen for events
ListenForGameEvent( "round_end" );
ListenForGameEvent( "round_start" );
ListenForGameEvent( "cs_win_panel_round" );
ListenForGameEvent( "cs_win_panel_match" );
ListenForGameEvent( "round_mvp" );
InitLayout();
m_bShouldBeVisible = false;
m_bShowTimerDefend = false;
m_bShowTimerAttack = false;
}
void WinPanel_Round::InitLayout()
{
// reload control settings when resolution changes to force update of proportional layout
LoadControlSettings("Resource/UI/Win_Round.res");
CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
pMVP_Avatar->SetDefaultAvatar(scheme()->GetImage( CSTRIKE_DEFAULT_AVATAR, true));
pMVP_Avatar->SetShouldDrawFriendIcon(false);
}
void WinPanel_Round::VidInit()
{
}
//=============================================================================
// HPE_BEGIN:
// [Forrest] Allow win panel to be turned off on client
//=============================================================================
ConVar cl_nowinpanel(
"cl_nowinpanel",
"0",
FCVAR_ARCHIVE,
"Turn on/off win panel on client"
);
//=============================================================================
// HPE_END
//=============================================================================
void WinPanel_Round::FireGameEvent( IGameEvent* event )
{
const char *pEventName = event->GetName();
if ( Q_strcmp( "round_end", pEventName ) == 0 )
{
}
else if ( Q_strcmp( "round_start", pEventName ) == 0 )
{
Hide();
}
else if( Q_strcmp( "cs_win_panel_match", pEventName ) == 0 )
{
Hide();
}
else if( Q_strcmp( "round_mvp", pEventName ) == 0 )
{
C_BasePlayer *basePlayer = UTIL_PlayerByUserId( event->GetInt( "userid" ) );
CSMvpReason_t mvpReason = (CSMvpReason_t)event->GetInt( "reason" );
if( basePlayer )
{
SetMVP( ToCSPlayer( basePlayer ), mvpReason );
}
}
else if ( Q_strcmp( "cs_win_panel_round", pEventName ) == 0 )
{
/*
"show_timer_defend" "bool"
"show_timer_attack" "bool"
"timer_time" "int"
"final_event" "byte" // 0 - no event, 1 - bomb exploded, 2 - flag capped, 3 - timer expired
"funfact_type" "byte" //WINPANEL_FUNFACT in cs_shareddef.h
"funfact_player" "byte"
"funfact_data1" "long"
"funfact_data2" "long"
"funfact_data3" "long"
*/
if ( !g_PR )
return;
//=============================================================================
// HPE_BEGIN:
// [Forrest] Check if win panel is disabled.
//=============================================================================
static ConVarRef sv_nowinpanel( "sv_nowinpanel" );
if ( sv_nowinpanel.GetBool() || cl_nowinpanel.GetBool() )
return;
//=============================================================================
// HPE_END
//=============================================================================
m_bShowTimerDefend = event->GetBool( "show_timer_defend" );
m_bShowTimerAttack = event->GetBool( "show_timer_attack" );
int iTimerTime = event->GetInt( "timer_time" );
int minutes = clamp( iTimerTime / 60, 0, 99 );
int seconds = clamp( iTimerTime % 60, 0, 59 );
wchar_t time[8];
_snwprintf( time, ARRAYSIZE( time ), L"%d:%02d", minutes, seconds );
SetDialogVariable("TIMER_TEXT", time);
// Final Fun Fact
SetFunFactLabel( L"");
int iFunFactPlayer = event->GetInt("funfact_player");
const char* funfactToken = event->GetString("funfact_token", "");
if (strlen(funfactToken) != 0)
{
wchar_t funFactText[256];
wchar_t playerText[64];
wchar_t dataText1[8], dataText2[8], dataText3[8];
int param1 = event->GetInt("funfact_data1");
int param2 = event->GetInt("funfact_data2");
int param3 = event->GetInt("funfact_data3");
if ( iFunFactPlayer >= 1 && iFunFactPlayer <= MAX_PLAYERS )
{
const char* playerName = g_PR->GetPlayerName( iFunFactPlayer );
if( playerName && Q_strcmp( playerName, PLAYER_UNCONNECTED_NAME ) != 0 && Q_strcmp( playerName, PLAYER_ERROR_NAME ) != 0 )
{
V_strtowcs( g_PR->GetPlayerName( iFunFactPlayer ), 64, playerText, sizeof( playerText ) );
}
else
{
#ifdef WIN32
_snwprintf( playerText, ARRAYSIZE( playerText ), L"%s", LocalizeFindSafe( "#winpanel_former_player" ) );
#else
_snwprintf( playerText, ARRAYSIZE( playerText ), L"%S", LocalizeFindSafe( "#winpanel_former_player" ) );
#endif
}
}
else
{
_snwprintf( playerText, ARRAYSIZE( playerText ), L"" );
}
_snwprintf( dataText1, ARRAYSIZE( dataText1 ), L"%i", param1 );
_snwprintf( dataText2, ARRAYSIZE( dataText2 ), L"%i", param2 );
_snwprintf( dataText3, ARRAYSIZE( dataText3 ), L"%i", param3 );
g_pVGuiLocalize->ConstructString( funFactText, sizeof(funFactText), (wchar_t *)LocalizeFindSafe(funfactToken), 4,
playerText, dataText1, dataText2, dataText3 );
SetFunFactLabel(funFactText);
}
int iEndEvent = event->GetInt( "final_event" );
//Map the round end events onto localized strings
const char* endEventToString[RoundEndReason_Count];
V_memset(endEventToString, 0, sizeof(endEventToString));
//terrorist win events
endEventToString[Target_Bombed] = "#winpanel_end_target_bombed";
endEventToString[VIP_Assassinated] = "#winpanel_end_vip_assassinated";
endEventToString[Terrorists_Escaped] = "#winpanel_end_terrorists_escaped";
endEventToString[Terrorists_Win] = "#winpanel_end_terrorists__kill";
endEventToString[Hostages_Not_Rescued] = "#winpanel_end_hostages_not_rescued";
endEventToString[VIP_Not_Escaped] = "#winpanel_end_vip_not_escaped";
//CT win events
endEventToString[VIP_Escaped] = "#winpanel_end_vip_escaped";
endEventToString[CTs_PreventEscape] = "#winpanel_end_cts_prevent_escape";
endEventToString[Escaping_Terrorists_Neutralized] = "#winpanel_end_escaping_terrorists_neutralized";
endEventToString[Bomb_Defused] = "#winpanel_end_bomb_defused";
endEventToString[CTs_Win] = "#winpanel_end_cts_win";
endEventToString[All_Hostages_Rescued] = "#winpanel_end_all_hostages_rescued";
endEventToString[Target_Saved] = "#winpanel_end_target_saved";
endEventToString[Terrorists_Not_Escaped] = "#winpanel_end_terrorists_not_escaped";
//We don't show a round end panel for these
endEventToString[Game_Commencing] = "";
endEventToString[Round_Draw] = "";
const wchar_t* wszEventMessage = NULL;
if(iEndEvent >=0 && iEndEvent < RoundEndReason_Count)
wszEventMessage = LocalizeFindSafe(endEventToString[iEndEvent]);
if ( wszEventMessage != NULL )
{
SetDialogVariable("WIN_DESCRIPTION", UpperCaseWideString(wszEventMessage));
}
else
{
SetDialogVariable("WIN_DESCRIPTION", "");
}
Label* pWinLabel = dynamic_cast<Label*>(FindChildByName("WinLabel"));
switch(iEndEvent)
{
case Target_Bombed:
case VIP_Assassinated:
case Terrorists_Escaped:
case Terrorists_Win:
case Hostages_Not_Rescued:
case VIP_Not_Escaped:
pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_t_win")));
pWinLabel->SetFgColor(Color(184,0,0,255));
break;
case VIP_Escaped:
case CTs_PreventEscape:
case Escaping_Terrorists_Neutralized:
case Bomb_Defused:
case CTs_Win:
case All_Hostages_Rescued:
case Target_Saved:
case Terrorists_Not_Escaped:
pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_ct_win")));
pWinLabel->SetFgColor(Color(71,152,237,255));
break;
case Round_Draw:
pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_draw")));
pWinLabel->SetFgColor(Color(204,204,204,255));
break;
}
//[tj] We set the icon to the generic one right before we show it.
// The expected result is that we replace it immediately with
// the round MVP. if there is none, we just use the generic.
SetMVP( NULL, CSMVP_UNDEFINED );
Show();
}
}
void WinPanel_Round::SetMVP( C_CSPlayer* pPlayer, CSMvpReason_t reason )
{
CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
if ( pMVP_Avatar )
{
pMVP_Avatar->ClearAvatar();
}
//First set the text to the name of the player
//=============================================================================
// HPE_BEGIN:
// [Forrest] Allow MVP to be turned off for a server
//=============================================================================
bool isThereAnMVP = ( pPlayer != NULL );
if ( isThereAnMVP )
//=============================================================================
// HPE_END
//=============================================================================
{
const char* mvpReasonToken = NULL;
switch ( reason )
{
case CSMVP_ELIMINATION:
mvpReasonToken = "winpanel_mvp_award_kills";
break;
case CSMVP_BOMBPLANT:
mvpReasonToken = "winpanel_mvp_award_bombplant";
break;
case CSMVP_BOMBDEFUSE:
mvpReasonToken = "winpanel_mvp_award_bombdefuse";
break;
case CSMVP_HOSTAGERESCUE:
mvpReasonToken = "winpanel_mvp_award_rescue";
break;
default:
mvpReasonToken = "winpanel_mvp_award";
break;
}
wchar_t wszBuf[256], wszPlayerName[64];
g_pVGuiLocalize->ConvertANSIToUnicode(UTIL_SafeName(pPlayer->GetPlayerName()), wszPlayerName, sizeof(wszPlayerName));
wchar_t *pReason = (wchar_t *)LocalizeFindSafe( mvpReasonToken );
if ( !pReason )
{
pReason = L"%s1";
}
g_pVGuiLocalize->ConstructString( wszBuf, sizeof( wszBuf ), pReason, 1, wszPlayerName );
SetDialogVariable( "MVP_TEXT", wszBuf );
player_info_t pi;
if ( engine->GetPlayerInfo(pPlayer->entindex(), &pi) )
{
if ( pMVP_Avatar )
{
pMVP_Avatar->SetDefaultAvatar( GetDefaultAvatarImage( pPlayer ) );
pMVP_Avatar->SetPlayer( pPlayer, k_EAvatarSize64x64 );
}
}
}
else
{
SetDialogVariable( "MVP_TEXT", "");
}
//=============================================================================
// HPE_BEGIN:
// [Forrest] Allow MVP to be turned off for a server
//=============================================================================
// The avatar image and its accompanying elements should be hidden if there is no MVP for the round.
if ( pMVP_Avatar )
{
pMVP_Avatar->SetVisible( isThereAnMVP );
}
ImagePanel* pMVP_AvatarGlow = dynamic_cast<ImagePanel*>(FindChildByName("MVP_AvatarGlow"));
if ( pMVP_AvatarGlow )
{
pMVP_AvatarGlow->SetVisible( isThereAnMVP );
}
ImagePanel* pMVP_Foreground_Star = dynamic_cast<ImagePanel*>(FindChildByName("MVP_Foreground_Star"));
if ( pMVP_Foreground_Star )
{
pMVP_Foreground_Star->SetVisible( isThereAnMVP );
}
//=============================================================================
// HPE_END
//=============================================================================
}
void WinPanel_Round::SetFunFactLabel( const wchar *szFunFact )
{
SetDialogVariable( "FUNFACT", szFunFact );
}
void WinPanel_Round::Show( void )
{
int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
if ( iRenderGroup >= 0)
{
gHUD.LockRenderGroup( iRenderGroup );
}
m_bShouldBeVisible = true;
SetAlpha(255);
m_bIsFading = false;
}
void WinPanel_Round::Hide( void )
{
if ( m_bShouldBeVisible && !m_bIsFading )
{
m_bIsFading = true;
m_fFadeBeginTime = gpGlobals->realtime;
}
}
void WinPanel_Round::OnThink()
{
if ( m_bShouldBeVisible && m_bIsFading )
{
float fAlpha = 1.0f - (gpGlobals->realtime - m_fFadeBeginTime) / cl_round_win_fade_time.GetFloat();
if (fAlpha >= 0.0f)
{
SetAlpha(RoundFloatToInt(fAlpha * 255.0f));
}
else
{
int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
if ( iRenderGroup >= 0 )
{
gHUD.UnlockRenderGroup( iRenderGroup );
}
m_bShouldBeVisible = false;
SetAlpha(0);
m_bIsFading = false;
}
}
}
void WinPanel_Round::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetFgColor(Color(251,176,59,255));
SetBgColor(Color(0,0,0,212));
}
void WinPanel_Round::OnScreenSizeChanged( int nOldWide, int nOldTall )
{
BaseClass::OnScreenSizeChanged(nOldWide, nOldTall);
InitLayout();
}
bool WinPanel_Round::ShouldDraw( void )
{
return ( m_bShouldBeVisible && CHudElement::ShouldDraw());
}