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
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());
|
|
}
|