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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Create and display a win panel at the end of a round displaying interesting stats and info about the round.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "win_panel_round.h"
  9. #include "vgui_controls/AnimationController.h"
  10. #include "iclientmode.h"
  11. #include "c_playerresource.h"
  12. #include <vgui_controls/Label.h>
  13. #include <vgui/ILocalize.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/ISystem.h>
  16. #include "fmtstr.h"
  17. #include "cs_gamestats_shared.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. ConVar cl_round_win_fade_time( "cl_round_win_fade_time", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
  21. DECLARE_HUDELEMENT_DEPTH( WinPanel_Round, 1 ); // 1 is foreground
  22. extern const wchar_t *LocalizeFindSafe( const char *pTokenName );
  23. // helper function for converting wstrings to upper-case inline
  24. // NB: this returns a pointer to a static buffer
  25. wchar_t* UpperCaseWideString( const wchar_t* wszSource )
  26. {
  27. static wchar_t wszBuffer[256];
  28. V_wcsncpy(wszBuffer, wszSource, sizeof(wszBuffer));
  29. V_wcsupr(wszBuffer);
  30. return wszBuffer;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Constructor
  34. //-----------------------------------------------------------------------------
  35. WinPanel_Round::WinPanel_Round( const char *pElementName ) :
  36. BorderedPanel( NULL, pElementName ),
  37. CHudElement( pElementName ),
  38. m_bIsFading(false),
  39. m_fFadeBeginTime(0.0f)
  40. {
  41. SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
  42. SetParent(g_pClientMode->GetViewport());
  43. SetScheme( "ClientScheme" );
  44. RegisterForRenderGroup( "hide_for_scoreboard" );
  45. m_bShouldBeVisible = false;
  46. }
  47. WinPanel_Round::~WinPanel_Round()
  48. {
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. void WinPanel_Round::Reset()
  54. {
  55. Hide();
  56. }
  57. void WinPanel_Round::Init()
  58. {
  59. CHudElement::Init();
  60. // listen for events
  61. ListenForGameEvent( "round_end" );
  62. ListenForGameEvent( "round_start" );
  63. ListenForGameEvent( "cs_win_panel_round" );
  64. ListenForGameEvent( "cs_win_panel_match" );
  65. ListenForGameEvent( "round_mvp" );
  66. InitLayout();
  67. m_bShouldBeVisible = false;
  68. m_bShowTimerDefend = false;
  69. m_bShowTimerAttack = false;
  70. }
  71. void WinPanel_Round::InitLayout()
  72. {
  73. // reload control settings when resolution changes to force update of proportional layout
  74. LoadControlSettings("Resource/UI/Win_Round.res");
  75. CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
  76. pMVP_Avatar->SetDefaultAvatar(scheme()->GetImage( CSTRIKE_DEFAULT_AVATAR, true));
  77. pMVP_Avatar->SetShouldDrawFriendIcon(false);
  78. }
  79. void WinPanel_Round::VidInit()
  80. {
  81. }
  82. //=============================================================================
  83. // HPE_BEGIN:
  84. // [Forrest] Allow win panel to be turned off on client
  85. //=============================================================================
  86. ConVar cl_nowinpanel(
  87. "cl_nowinpanel",
  88. "0",
  89. FCVAR_ARCHIVE,
  90. "Turn on/off win panel on client"
  91. );
  92. //=============================================================================
  93. // HPE_END
  94. //=============================================================================
  95. void WinPanel_Round::FireGameEvent( IGameEvent* event )
  96. {
  97. const char *pEventName = event->GetName();
  98. if ( Q_strcmp( "round_end", pEventName ) == 0 )
  99. {
  100. }
  101. else if ( Q_strcmp( "round_start", pEventName ) == 0 )
  102. {
  103. Hide();
  104. }
  105. else if( Q_strcmp( "cs_win_panel_match", pEventName ) == 0 )
  106. {
  107. Hide();
  108. }
  109. else if( Q_strcmp( "round_mvp", pEventName ) == 0 )
  110. {
  111. C_BasePlayer *basePlayer = UTIL_PlayerByUserId( event->GetInt( "userid" ) );
  112. CSMvpReason_t mvpReason = (CSMvpReason_t)event->GetInt( "reason" );
  113. if( basePlayer )
  114. {
  115. SetMVP( ToCSPlayer( basePlayer ), mvpReason );
  116. }
  117. }
  118. else if ( Q_strcmp( "cs_win_panel_round", pEventName ) == 0 )
  119. {
  120. /*
  121. "show_timer_defend" "bool"
  122. "show_timer_attack" "bool"
  123. "timer_time" "int"
  124. "final_event" "byte" // 0 - no event, 1 - bomb exploded, 2 - flag capped, 3 - timer expired
  125. "funfact_type" "byte" //WINPANEL_FUNFACT in cs_shareddef.h
  126. "funfact_player" "byte"
  127. "funfact_data1" "long"
  128. "funfact_data2" "long"
  129. "funfact_data3" "long"
  130. */
  131. if ( !g_PR )
  132. return;
  133. //=============================================================================
  134. // HPE_BEGIN:
  135. // [Forrest] Check if win panel is disabled.
  136. //=============================================================================
  137. static ConVarRef sv_nowinpanel( "sv_nowinpanel" );
  138. if ( sv_nowinpanel.GetBool() || cl_nowinpanel.GetBool() )
  139. return;
  140. //=============================================================================
  141. // HPE_END
  142. //=============================================================================
  143. m_bShowTimerDefend = event->GetBool( "show_timer_defend" );
  144. m_bShowTimerAttack = event->GetBool( "show_timer_attack" );
  145. int iTimerTime = event->GetInt( "timer_time" );
  146. int minutes = clamp( iTimerTime / 60, 0, 99 );
  147. int seconds = clamp( iTimerTime % 60, 0, 59 );
  148. wchar_t time[8];
  149. _snwprintf( time, ARRAYSIZE( time ), L"%d:%02d", minutes, seconds );
  150. SetDialogVariable("TIMER_TEXT", time);
  151. // Final Fun Fact
  152. SetFunFactLabel( L"");
  153. int iFunFactPlayer = event->GetInt("funfact_player");
  154. const char* funfactToken = event->GetString("funfact_token", "");
  155. if (strlen(funfactToken) != 0)
  156. {
  157. wchar_t funFactText[256];
  158. wchar_t playerText[64];
  159. wchar_t dataText1[8], dataText2[8], dataText3[8];
  160. int param1 = event->GetInt("funfact_data1");
  161. int param2 = event->GetInt("funfact_data2");
  162. int param3 = event->GetInt("funfact_data3");
  163. if ( iFunFactPlayer >= 1 && iFunFactPlayer <= MAX_PLAYERS )
  164. {
  165. const char* playerName = g_PR->GetPlayerName( iFunFactPlayer );
  166. if( playerName && Q_strcmp( playerName, PLAYER_UNCONNECTED_NAME ) != 0 && Q_strcmp( playerName, PLAYER_ERROR_NAME ) != 0 )
  167. {
  168. V_strtowcs( g_PR->GetPlayerName( iFunFactPlayer ), 64, playerText, sizeof( playerText ) );
  169. }
  170. else
  171. {
  172. #ifdef WIN32
  173. _snwprintf( playerText, ARRAYSIZE( playerText ), L"%s", LocalizeFindSafe( "#winpanel_former_player" ) );
  174. #else
  175. _snwprintf( playerText, ARRAYSIZE( playerText ), L"%S", LocalizeFindSafe( "#winpanel_former_player" ) );
  176. #endif
  177. }
  178. }
  179. else
  180. {
  181. _snwprintf( playerText, ARRAYSIZE( playerText ), L"" );
  182. }
  183. _snwprintf( dataText1, ARRAYSIZE( dataText1 ), L"%i", param1 );
  184. _snwprintf( dataText2, ARRAYSIZE( dataText2 ), L"%i", param2 );
  185. _snwprintf( dataText3, ARRAYSIZE( dataText3 ), L"%i", param3 );
  186. g_pVGuiLocalize->ConstructString( funFactText, sizeof(funFactText), (wchar_t *)LocalizeFindSafe(funfactToken), 4,
  187. playerText, dataText1, dataText2, dataText3 );
  188. SetFunFactLabel(funFactText);
  189. }
  190. int iEndEvent = event->GetInt( "final_event" );
  191. //Map the round end events onto localized strings
  192. const char* endEventToString[RoundEndReason_Count];
  193. V_memset(endEventToString, 0, sizeof(endEventToString));
  194. //terrorist win events
  195. endEventToString[Target_Bombed] = "#winpanel_end_target_bombed";
  196. endEventToString[VIP_Assassinated] = "#winpanel_end_vip_assassinated";
  197. endEventToString[Terrorists_Escaped] = "#winpanel_end_terrorists_escaped";
  198. endEventToString[Terrorists_Win] = "#winpanel_end_terrorists__kill";
  199. endEventToString[Hostages_Not_Rescued] = "#winpanel_end_hostages_not_rescued";
  200. endEventToString[VIP_Not_Escaped] = "#winpanel_end_vip_not_escaped";
  201. //CT win events
  202. endEventToString[VIP_Escaped] = "#winpanel_end_vip_escaped";
  203. endEventToString[CTs_PreventEscape] = "#winpanel_end_cts_prevent_escape";
  204. endEventToString[Escaping_Terrorists_Neutralized] = "#winpanel_end_escaping_terrorists_neutralized";
  205. endEventToString[Bomb_Defused] = "#winpanel_end_bomb_defused";
  206. endEventToString[CTs_Win] = "#winpanel_end_cts_win";
  207. endEventToString[All_Hostages_Rescued] = "#winpanel_end_all_hostages_rescued";
  208. endEventToString[Target_Saved] = "#winpanel_end_target_saved";
  209. endEventToString[Terrorists_Not_Escaped] = "#winpanel_end_terrorists_not_escaped";
  210. //We don't show a round end panel for these
  211. endEventToString[Game_Commencing] = "";
  212. endEventToString[Round_Draw] = "";
  213. const wchar_t* wszEventMessage = NULL;
  214. if(iEndEvent >=0 && iEndEvent < RoundEndReason_Count)
  215. wszEventMessage = LocalizeFindSafe(endEventToString[iEndEvent]);
  216. if ( wszEventMessage != NULL )
  217. {
  218. SetDialogVariable("WIN_DESCRIPTION", UpperCaseWideString(wszEventMessage));
  219. }
  220. else
  221. {
  222. SetDialogVariable("WIN_DESCRIPTION", "");
  223. }
  224. Label* pWinLabel = dynamic_cast<Label*>(FindChildByName("WinLabel"));
  225. switch(iEndEvent)
  226. {
  227. case Target_Bombed:
  228. case VIP_Assassinated:
  229. case Terrorists_Escaped:
  230. case Terrorists_Win:
  231. case Hostages_Not_Rescued:
  232. case VIP_Not_Escaped:
  233. pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_t_win")));
  234. pWinLabel->SetFgColor(Color(184,0,0,255));
  235. break;
  236. case VIP_Escaped:
  237. case CTs_PreventEscape:
  238. case Escaping_Terrorists_Neutralized:
  239. case Bomb_Defused:
  240. case CTs_Win:
  241. case All_Hostages_Rescued:
  242. case Target_Saved:
  243. case Terrorists_Not_Escaped:
  244. pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_ct_win")));
  245. pWinLabel->SetFgColor(Color(71,152,237,255));
  246. break;
  247. case Round_Draw:
  248. pWinLabel->SetText(UpperCaseWideString(LocalizeFindSafe("#winpanel_draw")));
  249. pWinLabel->SetFgColor(Color(204,204,204,255));
  250. break;
  251. }
  252. //[tj] We set the icon to the generic one right before we show it.
  253. // The expected result is that we replace it immediately with
  254. // the round MVP. if there is none, we just use the generic.
  255. SetMVP( NULL, CSMVP_UNDEFINED );
  256. Show();
  257. }
  258. }
  259. void WinPanel_Round::SetMVP( C_CSPlayer* pPlayer, CSMvpReason_t reason )
  260. {
  261. CAvatarImagePanel* pMVP_Avatar = dynamic_cast<CAvatarImagePanel*>(FindChildByName("MVP_Avatar"));
  262. if ( pMVP_Avatar )
  263. {
  264. pMVP_Avatar->ClearAvatar();
  265. }
  266. //First set the text to the name of the player
  267. //=============================================================================
  268. // HPE_BEGIN:
  269. // [Forrest] Allow MVP to be turned off for a server
  270. //=============================================================================
  271. bool isThereAnMVP = ( pPlayer != NULL );
  272. if ( isThereAnMVP )
  273. //=============================================================================
  274. // HPE_END
  275. //=============================================================================
  276. {
  277. const char* mvpReasonToken = NULL;
  278. switch ( reason )
  279. {
  280. case CSMVP_ELIMINATION:
  281. mvpReasonToken = "winpanel_mvp_award_kills";
  282. break;
  283. case CSMVP_BOMBPLANT:
  284. mvpReasonToken = "winpanel_mvp_award_bombplant";
  285. break;
  286. case CSMVP_BOMBDEFUSE:
  287. mvpReasonToken = "winpanel_mvp_award_bombdefuse";
  288. break;
  289. case CSMVP_HOSTAGERESCUE:
  290. mvpReasonToken = "winpanel_mvp_award_rescue";
  291. break;
  292. default:
  293. mvpReasonToken = "winpanel_mvp_award";
  294. break;
  295. }
  296. wchar_t wszBuf[256], wszPlayerName[64];
  297. g_pVGuiLocalize->ConvertANSIToUnicode(UTIL_SafeName(pPlayer->GetPlayerName()), wszPlayerName, sizeof(wszPlayerName));
  298. wchar_t *pReason = (wchar_t *)LocalizeFindSafe( mvpReasonToken );
  299. if ( !pReason )
  300. {
  301. pReason = L"%s1";
  302. }
  303. g_pVGuiLocalize->ConstructString( wszBuf, sizeof( wszBuf ), pReason, 1, wszPlayerName );
  304. SetDialogVariable( "MVP_TEXT", wszBuf );
  305. player_info_t pi;
  306. if ( engine->GetPlayerInfo(pPlayer->entindex(), &pi) )
  307. {
  308. if ( pMVP_Avatar )
  309. {
  310. pMVP_Avatar->SetDefaultAvatar( GetDefaultAvatarImage( pPlayer ) );
  311. pMVP_Avatar->SetPlayer( pPlayer, k_EAvatarSize64x64 );
  312. }
  313. }
  314. }
  315. else
  316. {
  317. SetDialogVariable( "MVP_TEXT", "");
  318. }
  319. //=============================================================================
  320. // HPE_BEGIN:
  321. // [Forrest] Allow MVP to be turned off for a server
  322. //=============================================================================
  323. // The avatar image and its accompanying elements should be hidden if there is no MVP for the round.
  324. if ( pMVP_Avatar )
  325. {
  326. pMVP_Avatar->SetVisible( isThereAnMVP );
  327. }
  328. ImagePanel* pMVP_AvatarGlow = dynamic_cast<ImagePanel*>(FindChildByName("MVP_AvatarGlow"));
  329. if ( pMVP_AvatarGlow )
  330. {
  331. pMVP_AvatarGlow->SetVisible( isThereAnMVP );
  332. }
  333. ImagePanel* pMVP_Foreground_Star = dynamic_cast<ImagePanel*>(FindChildByName("MVP_Foreground_Star"));
  334. if ( pMVP_Foreground_Star )
  335. {
  336. pMVP_Foreground_Star->SetVisible( isThereAnMVP );
  337. }
  338. //=============================================================================
  339. // HPE_END
  340. //=============================================================================
  341. }
  342. void WinPanel_Round::SetFunFactLabel( const wchar *szFunFact )
  343. {
  344. SetDialogVariable( "FUNFACT", szFunFact );
  345. }
  346. void WinPanel_Round::Show( void )
  347. {
  348. int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
  349. if ( iRenderGroup >= 0)
  350. {
  351. gHUD.LockRenderGroup( iRenderGroup );
  352. }
  353. m_bShouldBeVisible = true;
  354. SetAlpha(255);
  355. m_bIsFading = false;
  356. }
  357. void WinPanel_Round::Hide( void )
  358. {
  359. if ( m_bShouldBeVisible && !m_bIsFading )
  360. {
  361. m_bIsFading = true;
  362. m_fFadeBeginTime = gpGlobals->realtime;
  363. }
  364. }
  365. void WinPanel_Round::OnThink()
  366. {
  367. if ( m_bShouldBeVisible && m_bIsFading )
  368. {
  369. float fAlpha = 1.0f - (gpGlobals->realtime - m_fFadeBeginTime) / cl_round_win_fade_time.GetFloat();
  370. if (fAlpha >= 0.0f)
  371. {
  372. SetAlpha(RoundFloatToInt(fAlpha * 255.0f));
  373. }
  374. else
  375. {
  376. int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "hide_for_round_panel" );
  377. if ( iRenderGroup >= 0 )
  378. {
  379. gHUD.UnlockRenderGroup( iRenderGroup );
  380. }
  381. m_bShouldBeVisible = false;
  382. SetAlpha(0);
  383. m_bIsFading = false;
  384. }
  385. }
  386. }
  387. void WinPanel_Round::ApplySchemeSettings( vgui::IScheme *pScheme )
  388. {
  389. BaseClass::ApplySchemeSettings( pScheme );
  390. SetFgColor(Color(251,176,59,255));
  391. SetBgColor(Color(0,0,0,212));
  392. }
  393. void WinPanel_Round::OnScreenSizeChanged( int nOldWide, int nOldTall )
  394. {
  395. BaseClass::OnScreenSizeChanged(nOldWide, nOldTall);
  396. InitLayout();
  397. }
  398. bool WinPanel_Round::ShouldDraw( void )
  399. {
  400. return ( m_bShouldBeVisible && CHudElement::ShouldDraw());
  401. }