//========= 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 #include #include #include #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(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(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(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(FindChildByName("MVP_AvatarGlow")); if ( pMVP_AvatarGlow ) { pMVP_AvatarGlow->SetVisible( isThereAnMVP ); } ImagePanel* pMVP_Foreground_Star = dynamic_cast(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()); }