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.

739 lines
27 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tf_hud_winpanel.h"
  9. #include "tf_hud_statpanel.h"
  10. #include "tf_spectatorgui.h"
  11. #include "vgui_controls/AnimationController.h"
  12. #include "iclientmode.h"
  13. #include "engine/IEngineSound.h"
  14. #include "c_tf_playerresource.h"
  15. #include "c_team.h"
  16. #include "tf_clientscoreboard.h"
  17. #include <vgui_controls/Label.h>
  18. #include <vgui_controls/ImagePanel.h>
  19. #include <vgui/ILocalize.h>
  20. #include <vgui/ISurface.h>
  21. #include "vgui_avatarimage.h"
  22. #include "fmtstr.h"
  23. #include "teamplayroundbased_gamerules.h"
  24. #include "tf_gamerules.h"
  25. #include "tf_logic_halloween_2014.h"
  26. #include "c_tf_team.h"
  27. #include "tf_badge_panel.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. DECLARE_HUDELEMENT_DEPTH( CTFWinPanel, 1 );
  31. //-----------------------------------------------------------------------------
  32. // Purpose: Constructor
  33. //-----------------------------------------------------------------------------
  34. CTFWinPanel::CTFWinPanel( const char *pElementName ) : EditablePanel( NULL, "WinPanel" ), CHudElement( pElementName )
  35. {
  36. vgui::Panel *pParent = g_pClientMode->GetViewport();
  37. SetParent( pParent );
  38. m_bShouldBeVisible = false;
  39. SetAlpha( 0 );
  40. SetScheme( "ClientScheme" );
  41. m_pTeamScorePanel = new EditablePanel( this, "TeamScoresPanel" );
  42. m_pRedTeamName = new CExLabel( m_pTeamScorePanel, "RedTeamLabel", "" );
  43. m_pBlueTeamName = new CExLabel( m_pTeamScorePanel, "BlueTeamLabel", "" );
  44. m_pRedLeaderAvatarImage = new CAvatarImagePanel( m_pTeamScorePanel, "RedLeaderAvatar" );
  45. m_pBlueLeaderAvatarImage = new CAvatarImagePanel( m_pTeamScorePanel, "BlueLeaderAvatar" );
  46. m_pRedLeaderAvatarBG = new EditablePanel( m_pTeamScorePanel, "RedLeaderAvatarBG" );
  47. m_pBlueLeaderAvatarBG = new EditablePanel( m_pTeamScorePanel, "BlueLeaderAvatarBG" );
  48. m_flTimeUpdateTeamScore = 0;
  49. m_iBlueTeamScore = 0;
  50. m_iRedTeamScore = 0;
  51. RegisterForRenderGroup( "mid" );
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. void CTFWinPanel::ApplySettings( KeyValues *inResourceData )
  57. {
  58. BaseClass::ApplySettings( inResourceData );
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose:
  62. //-----------------------------------------------------------------------------
  63. void CTFWinPanel::Reset()
  64. {
  65. m_bShouldBeVisible = false;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void CTFWinPanel::Init()
  71. {
  72. // listen for events
  73. ListenForGameEvent( "teamplay_win_panel" );
  74. ListenForGameEvent( "teamplay_round_start" );
  75. ListenForGameEvent( "teamplay_game_over" );
  76. ListenForGameEvent( "tf_game_over" );
  77. ListenForGameEvent( "training_complete" );
  78. ListenForGameEvent( "show_match_summary" );
  79. m_bShouldBeVisible = false;
  80. CHudElement::Init();
  81. }
  82. void CTFWinPanel::SetVisible( bool state )
  83. {
  84. if ( state == IsVisible() )
  85. return;
  86. if ( state )
  87. {
  88. HideLowerPriorityHudElementsInGroup( "mid" );
  89. }
  90. else
  91. {
  92. UnhideLowerPriorityHudElementsInGroup( "mid" );
  93. }
  94. BaseClass::SetVisible( state );
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. //-----------------------------------------------------------------------------
  99. void CTFWinPanel::FireGameEvent( IGameEvent * event )
  100. {
  101. const char *pEventName = event->GetName();
  102. if ( FStrEq( "teamplay_round_start", pEventName ) ||
  103. FStrEq( "teamplay_game_over", pEventName ) ||
  104. FStrEq( "tf_game_over", pEventName ) ||
  105. FStrEq( "training_complete", pEventName ) ||
  106. FStrEq( "show_match_summary", pEventName ) )
  107. {
  108. m_bShouldBeVisible = false;
  109. }
  110. else if ( Q_strcmp( "teamplay_win_panel", pEventName ) == 0 )
  111. {
  112. if ( !g_PR )
  113. return;
  114. vgui::IScheme* pScheme = scheme()->GetIScheme( GetScheme() );
  115. int iWinningTeam = event->GetInt( "winning_team" );
  116. int iWinReason = event->GetInt( "winreason" );
  117. int iFlagCapLimit = event->GetInt( "flagcaplimit" );
  118. bool bRoundComplete = (bool) event->GetInt( "round_complete" );
  119. int iRoundsRemaining = event->GetInt( "rounds_remaining" );
  120. bool bGameOver = event->GetBool( "game_over", false );
  121. bool bUseMoreOpaqueBorder = false;
  122. if ( TFGameRules() && bGameOver )
  123. {
  124. if ( TFGameRules()->IsMatchTypeCompetitive() )
  125. {
  126. bUseMoreOpaqueBorder = true;
  127. }
  128. }
  129. // non-final rounds of stopwatch mode should say something different
  130. CTeamRoundTimer *pTimer = NULL;
  131. if ( TFGameRules() && TFGameRules()->IsInTournamentMode() && TFGameRules()->IsInStopWatch() )
  132. {
  133. int iActiveTimer = ObjectiveResource()->GetStopWatchTimer();
  134. pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( iActiveTimer ) );
  135. if ( pTimer )
  136. {
  137. if ( pTimer->IsWatchingTimeStamps() )
  138. {
  139. iWinningTeam = TEAM_INVALID;
  140. iWinReason = bRoundComplete ? WINREASON_STOPWATCH_WATCHING_FINAL_ROUND : WINREASON_STOPWATCH_WATCHING_ROUNDS;
  141. }
  142. else
  143. {
  144. if ( !TFGameRules()->HaveStopWatchWinner() && !bRoundComplete )
  145. {
  146. iWinningTeam = TEAM_INVALID;
  147. iWinReason = WINREASON_STOPWATCH_PLAYING_ROUNDS;
  148. }
  149. }
  150. }
  151. }
  152. LoadControlSettings( "resource/UI/WinPanel.res" );
  153. InvalidateLayout( false, true );
  154. SetDialogVariable( "WinningTeamLabel", "" );
  155. SetDialogVariable( "AdvancingTeamLabel", "" );
  156. SetDialogVariable( "WinReasonLabel", "" );
  157. SetDialogVariable( "DetailsLabel", "" );
  158. EditablePanel *pBGPanel = dynamic_cast<EditablePanel *>( FindChildByName("WinPanelBGBorder") );
  159. Assert( pBGPanel );
  160. if ( !pBGPanel )
  161. return;
  162. EditablePanel *pBlueBGPanel = FindControl< EditablePanel >( "BlueScoreBG", true );
  163. Assert( pBlueBGPanel );
  164. EditablePanel *pRedBGPanel = FindControl< EditablePanel >( "RedScoreBG", true );
  165. Assert( pRedBGPanel );
  166. if( !pBlueBGPanel || !pRedBGPanel )
  167. return;
  168. pBlueBGPanel->SetBorder( pScheme->GetBorder( bUseMoreOpaqueBorder ? "TFFatLineBorderBlueBGMoreOpaque" : "TFFatLineBorderBlueBG" ) );
  169. pRedBGPanel->SetBorder( pScheme->GetBorder( bUseMoreOpaqueBorder ? "TFFatLineBorderRedBGMoreOpaque" : "TFFatLineBorderRedBG" ) ) ;
  170. // we want to suppress the winreason for sd_doomsday_event and plr_hightower_event
  171. if ( TFGameRules() )
  172. {
  173. if ( ( TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_DOOMSDAY ) && CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() ) ||
  174. ( TFGameRules()->IsHalloweenScenario( CTFGameRules::HALLOWEEN_SCENARIO_HIGHTOWER ) ) )
  175. {
  176. iWinReason = WINREASON_NONE;
  177. }
  178. }
  179. // this is an area defense, but not a round win, if this was a successful defend until time limit but not a complete round
  180. bool bIsAreaDefense = ( ( WINREASON_DEFEND_UNTIL_TIME_LIMIT == iWinReason ) && !bRoundComplete );
  181. // set the appropriate background image and label text
  182. const wchar_t *pTeamLabel = L"";
  183. const wchar_t *pTopPlayersLabel = L"";
  184. const wchar_t *pLocalizedTeamName = L"";
  185. const char *pWinTeamLabel = ( bRoundComplete ? "#Winpanel_TeamWins" : ( bIsAreaDefense ? "#Winpanel_TeamDefends" : "#Winpanel_TeamAdvances" ) );
  186. C_TFTeam *pBlueTeam = GetGlobalTFTeam( TF_TEAM_BLUE );
  187. const wchar_t *pBlueTeamName = pBlueTeam ? pBlueTeam->Get_Localized_Name() : L"BLU";
  188. C_TFTeam *pRedTeam = GetGlobalTFTeam( TF_TEAM_RED );
  189. const wchar_t *pRedTeamName = pRedTeam ? pRedTeam->Get_Localized_Name() : L"RED";
  190. if ( TFGameRules() && TFGameRules()->IsInTournamentMode() )
  191. {
  192. pWinTeamLabel = ( bRoundComplete ? "#Winpanel_TournamentTeamWins" : ( bIsAreaDefense ? "#Winpanel_TournamentTeamDefends" : "#Winpanel_TournamentTeamAdvances" ) );
  193. }
  194. wchar_t wzTeamWin[256] = L"";
  195. switch ( iWinningTeam )
  196. {
  197. case TF_TEAM_BLUE:
  198. pBGPanel->SetBorder( pScheme->GetBorder( bUseMoreOpaqueBorder ? "TFFatLineBorderBlueBGMoreOpaque" : "TFFatLineBorderBlueBG" ) );
  199. pTopPlayersLabel = g_pVGuiLocalize->Find( "#Winpanel_BlueMVPs" );
  200. pLocalizedTeamName = pBlueTeamName;
  201. g_pVGuiLocalize->ConstructString_safe( wzTeamWin, g_pVGuiLocalize->Find( pWinTeamLabel ), 2, pLocalizedTeamName, g_pVGuiLocalize->Find( "#Winpanel_Team1" ) );
  202. pTeamLabel = wzTeamWin;
  203. break;
  204. case TF_TEAM_RED:
  205. pBGPanel->SetBorder( pScheme->GetBorder( bUseMoreOpaqueBorder ? "TFFatLineBorderRedBGMoreOpaque" : "TFFatLineBorderRedBG" ) );
  206. pTopPlayersLabel = g_pVGuiLocalize->Find( "#Winpanel_RedMVPs" );
  207. pLocalizedTeamName = pRedTeamName;
  208. break;
  209. case TEAM_UNASSIGNED: // stalemate
  210. pBGPanel->SetBorder( pScheme->GetBorder( "TFFatLineBorder" ) );
  211. pTeamLabel = g_pVGuiLocalize->Find( "#Winpanel_Stalemate" );
  212. pTopPlayersLabel = g_pVGuiLocalize->Find( "#Winpanel_TopPlayers" );
  213. break;
  214. case TEAM_INVALID: // used for stopwatch mode when it's not the final victory yet
  215. pBGPanel->SetBorder( pScheme->GetBorder( "TFFatLineBorder" ) );
  216. pTopPlayersLabel = g_pVGuiLocalize->Find( "#Winpanel_TopPlayers" );
  217. pTeamLabel = L"";
  218. if ( pBlueTeam && pBlueTeamName && pRedTeamName )
  219. {
  220. if ( bRoundComplete )
  221. {
  222. pTeamLabel = g_pVGuiLocalize->Find( "#WinPanel_StopWatch_Watching_RoundFinal" );
  223. }
  224. else
  225. {
  226. bool bBlueAttackers = ( pBlueTeam->GetRole() == TEAM_ROLE_ATTACKERS );
  227. g_pVGuiLocalize->ConstructString_safe( wzTeamWin,
  228. g_pVGuiLocalize->Find( "#WinPanel_StopWatch_Round_Complete" ),
  229. 1,
  230. bBlueAttackers ? pBlueTeamName : pRedTeamName );
  231. pTeamLabel = wzTeamWin;
  232. }
  233. }
  234. break;
  235. default:
  236. Assert( false );
  237. break;
  238. }
  239. SetDialogVariable( "TopPlayersLabel", pTopPlayersLabel );
  240. if ( TFGameRules() && TFGameRules()->IsInTournamentMode() && !TFGameRules()->IsInStopWatch() )
  241. {
  242. g_pVGuiLocalize->ConstructString_safe( wzTeamWin, g_pVGuiLocalize->Find( pWinTeamLabel ), 1, pLocalizedTeamName );
  243. wchar_t wzTeamMPVs[256];
  244. g_pVGuiLocalize->ConstructString_safe( wzTeamMPVs, g_pVGuiLocalize->Find( "#Winpanel_TournamentMVPs" ), 1, pLocalizedTeamName );
  245. if ( iWinningTeam != TEAM_UNASSIGNED )
  246. {
  247. SetDialogVariable( "TopPlayersLabel", wzTeamMPVs );
  248. }
  249. }
  250. else if ( ( iWinningTeam != TEAM_UNASSIGNED ) && ( iWinningTeam != TEAM_INVALID ) )
  251. {
  252. g_pVGuiLocalize->ConstructString_safe( wzTeamWin, g_pVGuiLocalize->Find( pWinTeamLabel ), 2, pLocalizedTeamName, g_pVGuiLocalize->Find( "#Winpanel_Team1" ) );
  253. }
  254. if ( ( iWinningTeam != TEAM_UNASSIGNED ) && ( iWinningTeam != TEAM_INVALID ) )
  255. {
  256. pTeamLabel = wzTeamWin;
  257. }
  258. SetDialogVariable( bRoundComplete ? "WinningTeamLabel" : "AdvancingTeamLabel", pTeamLabel );
  259. wchar_t wzWinReason[256] = L"";
  260. switch ( iWinReason )
  261. {
  262. case WINREASON_ALL_POINTS_CAPTURED:
  263. {
  264. if ( TFGameRules() && ( TFGameRules()->GetGameType() == TF_GAMETYPE_ESCORT ) && ( TFGameRules()->HasMultipleTrains() == true ) && ( iRoundsRemaining == 0 ) )
  265. {
  266. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_PayloadRace" ), 1, pLocalizedTeamName );
  267. }
  268. else
  269. {
  270. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_AllPointsCaptured" ), 1, pLocalizedTeamName );
  271. }
  272. }
  273. break;
  274. case WINREASON_FLAG_CAPTURE_LIMIT:
  275. {
  276. wchar_t wzFlagCaptureLimit[16];
  277. _snwprintf( wzFlagCaptureLimit, ARRAYSIZE( wzFlagCaptureLimit), L"%i", iFlagCapLimit );
  278. const wchar_t *wpszFormatString = NULL;
  279. if ( iFlagCapLimit == 1 )
  280. {
  281. wpszFormatString = g_pVGuiLocalize->Find( "#Winreason_FlagCaptureLimit_One" );
  282. }
  283. if ( !wpszFormatString )
  284. {
  285. wpszFormatString = g_pVGuiLocalize->Find( "#Winreason_FlagCaptureLimit" );
  286. }
  287. g_pVGuiLocalize->ConstructString_safe( wzWinReason, wpszFormatString, 2,
  288. pLocalizedTeamName, wzFlagCaptureLimit );
  289. }
  290. break;
  291. case WINREASON_OPPONENTS_DEAD:
  292. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_OpponentsDead" ), 1, pLocalizedTeamName );
  293. break;
  294. case WINREASON_DEFEND_UNTIL_TIME_LIMIT:
  295. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_DefendedUntilTimeLimit" ), 1, pLocalizedTeamName );
  296. break;
  297. case WINREASON_STALEMATE:
  298. if ( !TFGameRules() || !TFGameRules()->IsCompetitiveMode() )
  299. {
  300. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_Stalemate" ), 0 );
  301. }
  302. break;
  303. case WINREASON_TIMELIMIT:
  304. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_TimeLimit" ), 1, pLocalizedTeamName );
  305. break;
  306. case WINREASON_WINLIMIT:
  307. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_WinLimit" ), 1, pLocalizedTeamName );
  308. break;
  309. case WINREASON_WINDIFFLIMIT:
  310. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_WinDiffLimit" ), 1, pLocalizedTeamName );
  311. break;
  312. case WINREASON_RD_REACTOR_CAPTURED:
  313. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_ReactorCaptured" ), 1, pLocalizedTeamName );
  314. break;
  315. case WINREASON_RD_CORES_COLLECTED:
  316. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_CoresCollected" ), 1, pLocalizedTeamName );
  317. break;
  318. case WINREASON_RD_REACTOR_RETURNED:
  319. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_ReactorReturned" ), 1, pLocalizedTeamName );
  320. break;
  321. case WINREASON_PD_POINTS:
  322. g_pVGuiLocalize->ConstructString_safe( wzWinReason, g_pVGuiLocalize->Find( "#Winreason_PlayerDestructionPoints" ), 1, pLocalizedTeamName );
  323. break;
  324. case WINREASON_SCORED:
  325. {
  326. wchar_t wzScoreLimit[16];
  327. _snwprintf( wzScoreLimit, ARRAYSIZE( wzScoreLimit ), L"%i", iFlagCapLimit );
  328. const wchar_t *wpszFormatString = NULL;
  329. if ( iFlagCapLimit == 1 )
  330. {
  331. wpszFormatString = g_pVGuiLocalize->Find( "#Winreason_ScoreLimit_One" );
  332. }
  333. if ( !wpszFormatString )
  334. {
  335. wpszFormatString = g_pVGuiLocalize->Find( "#Winreason_ScoreLimit" );
  336. }
  337. g_pVGuiLocalize->ConstructString_safe( wzWinReason, wpszFormatString, 2,
  338. pLocalizedTeamName, wzScoreLimit );
  339. }
  340. break;
  341. case WINREASON_STOPWATCH_WATCHING_ROUNDS:
  342. if ( pBlueTeam && pBlueTeamName && pRedTeamName )
  343. {
  344. bool bBlueAttackers = ( pBlueTeam->GetRole() == TEAM_ROLE_ATTACKERS );
  345. g_pVGuiLocalize->ConstructString_safe( wzWinReason,
  346. g_pVGuiLocalize->Find( "#Winreason_Stopwatch_Watching_Rounds" ),
  347. 2,
  348. bBlueAttackers ? pBlueTeamName : pRedTeamName,
  349. bBlueAttackers ? pRedTeamName : pBlueTeamName );
  350. }
  351. break;
  352. case WINREASON_STOPWATCH_WATCHING_FINAL_ROUND:
  353. if ( pBlueTeam && pBlueTeamName && pRedTeamName )
  354. {
  355. bool bBlueAttackers = ( pBlueTeam->GetRole() == TEAM_ROLE_ATTACKERS );
  356. g_pVGuiLocalize->ConstructString_safe( wzWinReason,
  357. g_pVGuiLocalize->Find( "#Winreason_Stopwatch_SwitchSides" ),
  358. 2,
  359. bBlueAttackers ? pRedTeamName : pBlueTeamName,
  360. bBlueAttackers ? pBlueTeamName : pRedTeamName );
  361. }
  362. break;
  363. case WINREASON_STOPWATCH_PLAYING_ROUNDS:
  364. if ( pBlueTeam && pBlueTeamName && pRedTeamName )
  365. {
  366. bool bBlueAttackers = ( pBlueTeam->GetRole() == TEAM_ROLE_ATTACKERS );
  367. g_pVGuiLocalize->ConstructString_safe( wzWinReason,
  368. g_pVGuiLocalize->Find( "#Winreason_Stopwatch_Playing_Rounds" ),
  369. 2,
  370. bBlueAttackers ? pBlueTeamName : pRedTeamName,
  371. bBlueAttackers ? pRedTeamName : pBlueTeamName );
  372. }
  373. break;
  374. default:
  375. // This happens at the end of the Soldier training mission, FYI
  376. Assert( false );
  377. break;
  378. }
  379. SetDialogVariable( "WinReasonLabel", wzWinReason );
  380. if ( !bRoundComplete && ( WINREASON_STALEMATE != iWinReason ) && ( WINREASON_STOPWATCH_WATCHING_ROUNDS != iWinReason ) && ( WINREASON_STOPWATCH_WATCHING_FINAL_ROUND != iWinReason ) && ( WINREASON_STOPWATCH_PLAYING_ROUNDS != iWinReason ) )
  381. {
  382. // if this was a mini-round, show # of capture points remaining
  383. wchar_t wzNumCapturesRemaining[16];
  384. wchar_t wzCapturesRemainingMsg[256]=L"";
  385. _snwprintf( wzNumCapturesRemaining, ARRAYSIZE( wzNumCapturesRemaining ), L"%i", iRoundsRemaining );
  386. g_pVGuiLocalize->ConstructString_safe( wzCapturesRemainingMsg,
  387. g_pVGuiLocalize->Find( 1 == iRoundsRemaining ? "#Winpanel_CapturePointRemaining" : "Winpanel_CapturePointsRemaining" ),
  388. 1, wzNumCapturesRemaining );
  389. SetDialogVariable( "DetailsLabel", wzCapturesRemainingMsg );
  390. }
  391. else if ( ( WINREASON_ALL_POINTS_CAPTURED == iWinReason ) || ( WINREASON_FLAG_CAPTURE_LIMIT == iWinReason ) )
  392. {
  393. // if this was a full round that ended with point capture or flag capture, show the winning cappers
  394. const char *pCappers = event->GetString( "cappers" );
  395. int iCappers = Q_strlen( pCappers );
  396. if ( iCappers > 0 )
  397. {
  398. char szPlayerNames[256]="";
  399. wchar_t wzPlayerNames[256]=L"";
  400. wchar_t wzCapMsg[512]=L"";
  401. for ( int i = 0; i < iCappers; i++ )
  402. {
  403. Q_strncat( szPlayerNames, g_PR->GetPlayerName( (int) pCappers[i] ), ARRAYSIZE( szPlayerNames ) );
  404. if ( i < iCappers - 1 )
  405. {
  406. Q_strncat( szPlayerNames, ", ", ARRAYSIZE( szPlayerNames ) );
  407. }
  408. }
  409. g_pVGuiLocalize->ConvertANSIToUnicode( szPlayerNames, wzPlayerNames, sizeof( wzPlayerNames ) );
  410. g_pVGuiLocalize->ConstructString_safe( wzCapMsg, g_pVGuiLocalize->Find( "#Winpanel_WinningCapture" ), 1, wzPlayerNames );
  411. SetDialogVariable( "DetailsLabel", wzCapMsg );
  412. }
  413. }
  414. // get the current & previous team scores
  415. int iBlueTeamPrevScore = event->GetInt( "blue_score_prev", 0 );
  416. int iRedTeamPrevScore = event->GetInt( "red_score_prev", 0 );
  417. m_iBlueTeamScore = event->GetInt( "blue_score", 0 );
  418. m_iRedTeamScore = event->GetInt( "red_score", 0 );
  419. if ( m_pTeamScorePanel )
  420. {
  421. m_pTeamScorePanel->SetDialogVariable( "blueteamname", pBlueTeamName );
  422. m_pTeamScorePanel->SetDialogVariable( "redteamname", pRedTeamName );
  423. if ( bRoundComplete )
  424. {
  425. // set the previous team scores in scoreboard
  426. m_pTeamScorePanel->SetDialogVariable( "blueteamscore", iBlueTeamPrevScore );
  427. m_pTeamScorePanel->SetDialogVariable( "redteamscore", iRedTeamPrevScore );
  428. if ( ( m_iBlueTeamScore != iBlueTeamPrevScore ) || ( m_iRedTeamScore != iRedTeamPrevScore ) )
  429. {
  430. // if the new scores are different, set ourselves to update the scoreboard to the new values after a short delay, so players
  431. // see the scores tick up
  432. m_flTimeUpdateTeamScore = gpGlobals->curtime + 2.0f;
  433. }
  434. }
  435. // only show team scores if round is complete
  436. m_pTeamScorePanel->SetVisible( bRoundComplete );
  437. }
  438. if ( !g_TF_PR )
  439. return;
  440. // look for the top 3 players sent in the event
  441. for ( int i = 1; i <= 3; i++ )
  442. {
  443. bool bShow = false;
  444. char szPlayerIndexVal[64]="", szPlayerScoreVal[64]="";
  445. // get player index and round points from the event
  446. Q_snprintf( szPlayerIndexVal, ARRAYSIZE( szPlayerIndexVal ), "player_%d", i );
  447. Q_snprintf( szPlayerScoreVal, ARRAYSIZE( szPlayerScoreVal ), "player_%d_points", i );
  448. int iPlayerIndex = event->GetInt( szPlayerIndexVal, 0 );
  449. int iRoundScore = event->GetInt( szPlayerScoreVal, 0 );
  450. // round score of 0 means no player to show for that position (not enough players, or didn't score any points that round)
  451. if ( iRoundScore > 0 )
  452. bShow = true;
  453. CAvatarImagePanel *pPlayerAvatar = dynamic_cast<CAvatarImagePanel *>( FindChildByName( CFmtStr( "Player%dAvatar", i ) ) );
  454. if ( pPlayerAvatar )
  455. {
  456. pPlayerAvatar->SetShouldScaleImage( true );
  457. pPlayerAvatar->SetShouldDrawFriendIcon( false );
  458. if ( bShow )
  459. {
  460. CBasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  461. pPlayerAvatar->SetPlayer( pPlayer );
  462. }
  463. pPlayerAvatar->SetVisible( bShow );
  464. }
  465. CTFBadgePanel *pBadgePanel = dynamic_cast<CTFBadgePanel *>( FindChildByName( CFmtStr( "Player%dBadge", i ) ) );
  466. if ( pBadgePanel )
  467. {
  468. const IMatchGroupDescription *pMatchDesc = TFGameRules() ? GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() ) : NULL;
  469. const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL;
  470. bool bVisible = ( pMatchDesc && pProgressionDesc );
  471. if ( bVisible )
  472. {
  473. if ( !bGameOver && TFGameRules()->IsMatchTypeCompetitive() )
  474. {
  475. bVisible = false;
  476. }
  477. }
  478. if ( bVisible )
  479. {
  480. const CSteamID steamID = GetSteamIDForPlayerIndex( iPlayerIndex );
  481. if ( steamID.IsValid() )
  482. {
  483. pBadgePanel->SetupBadge( pProgressionDesc, steamID );
  484. }
  485. else
  486. {
  487. bVisible = false;
  488. }
  489. }
  490. if ( pBadgePanel->IsVisible() != bVisible )
  491. {
  492. pBadgePanel->SetVisible( bVisible );
  493. }
  494. }
  495. vgui::Label *pPlayerName = dynamic_cast<Label *>( FindChildByName( CFmtStr( "Player%dName", i ) ) );
  496. vgui::Label *pPlayerClass = dynamic_cast<Label *>( FindChildByName( CFmtStr( "Player%dClass", i ) ) );
  497. vgui::Label *pPlayerScore = dynamic_cast<Label *>( FindChildByName( CFmtStr( "Player%dScore", i ) ) );
  498. if ( !pPlayerName || !pPlayerClass || !pPlayerScore )
  499. return;
  500. if ( bShow )
  501. {
  502. // set the player labels to team color
  503. Color clr = g_PR->GetTeamColor( g_PR->GetTeam( iPlayerIndex ) );
  504. pPlayerName->SetFgColor( clr );
  505. pPlayerClass->SetFgColor( clr );
  506. pPlayerScore->SetFgColor( clr );
  507. // set label contents
  508. pPlayerName->SetText( g_PR->GetPlayerName( iPlayerIndex ) );
  509. pPlayerClass->SetText( g_aPlayerClassNames[g_TF_PR->GetPlayerClass( iPlayerIndex )] );
  510. pPlayerScore->SetText( CFmtStr( "%d", iRoundScore ) );
  511. // send an achievement event
  512. IGameEvent *pEvent = gameeventmanager->CreateEvent( "player_mvp" );
  513. if ( pEvent )
  514. {
  515. pEvent->SetInt( "player", iPlayerIndex );
  516. gameeventmanager->FireEventClientSide( pEvent );
  517. }
  518. }
  519. // show or hide labels for this player position
  520. pPlayerName->SetVisible( bShow );
  521. pPlayerClass->SetVisible( bShow );
  522. pPlayerScore->SetVisible( bShow );
  523. }
  524. // Top killstreak
  525. const int nMaxKillStreaks = 1;
  526. for ( int i = 1; i <= nMaxKillStreaks; ++i )
  527. {
  528. char szPlayerIndexVal[64]="", szPlayerScoreVal[64]="";
  529. Q_snprintf( szPlayerIndexVal, ARRAYSIZE( szPlayerIndexVal ), "killstreak_player_%d", i );
  530. Q_snprintf( szPlayerScoreVal, ARRAYSIZE( szPlayerScoreVal ), "killstreak_player_%d_count", i );
  531. int iPlayerIndex = event->GetInt( szPlayerIndexVal, 0 );
  532. int iCount = event->GetInt( szPlayerScoreVal, 0 );
  533. vgui::Label *pKillStreakPlayerName = dynamic_cast<Label *>( FindChildByName( CFmtStr( "KillStreakPlayer%dName", i ) ) );
  534. vgui::Label *pKillStreakPlayerClass = dynamic_cast<Label *>( FindChildByName( CFmtStr( "KillStreakPlayer%dClass", i ) ) );
  535. vgui::Label *pKillStreakPlayerScore = dynamic_cast<Label *>( FindChildByName( CFmtStr( "KillStreakPlayer%dScore", i ) ) );
  536. if ( !pKillStreakPlayerName || !pKillStreakPlayerClass || !pKillStreakPlayerScore )
  537. continue;
  538. bool bShow = iCount > 0;
  539. if ( bShow )
  540. {
  541. CAvatarImagePanel *pPlayerAvatar = dynamic_cast<CAvatarImagePanel *>( FindChildByName( CFmtStr( "KillStreakPlayer%dAvatar", i ) ) );
  542. if ( pPlayerAvatar )
  543. {
  544. pPlayerAvatar->SetShouldScaleImage( true );
  545. pPlayerAvatar->SetShouldDrawFriendIcon( false );
  546. CBasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
  547. pPlayerAvatar->SetPlayer( pPlayer );
  548. pPlayerAvatar->SetVisible( true );
  549. }
  550. // set the player labels to team color
  551. Color clr = g_PR->GetTeamColor( g_PR->GetTeam( iPlayerIndex ) );
  552. pKillStreakPlayerName->SetFgColor( clr );
  553. pKillStreakPlayerClass->SetFgColor( clr );
  554. pKillStreakPlayerScore->SetFgColor( clr );
  555. // set label contents
  556. pKillStreakPlayerName->SetText( g_PR->GetPlayerName( iPlayerIndex ) );
  557. pKillStreakPlayerClass->SetText( g_aPlayerClassNames[g_TF_PR->GetPlayerClass( iPlayerIndex )] );
  558. pKillStreakPlayerScore->SetText( CFmtStr( "%d", iCount ) );
  559. }
  560. CTFBadgePanel *pBadgePanel = dynamic_cast<CTFBadgePanel *>( FindChildByName( CFmtStr( "KillStreakPlayer%dBadge", i ) ) );
  561. if ( pBadgePanel )
  562. {
  563. const IMatchGroupDescription *pMatchDesc = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() );
  564. const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL;
  565. bool bVisible = ( bShow && pMatchDesc && pProgressionDesc );
  566. if ( bVisible )
  567. {
  568. const CSteamID steamID = GetSteamIDForPlayerIndex( iPlayerIndex );
  569. if ( steamID.IsValid() )
  570. {
  571. pBadgePanel->SetupBadge( pProgressionDesc, steamID );
  572. }
  573. else
  574. {
  575. bVisible = false;
  576. }
  577. }
  578. if ( pBadgePanel->IsVisible() != bVisible )
  579. {
  580. pBadgePanel->SetVisible( bVisible );
  581. }
  582. }
  583. // show or hide labels for this player position
  584. pKillStreakPlayerName->SetVisible( bShow );
  585. pKillStreakPlayerClass->SetVisible( bShow );
  586. pKillStreakPlayerScore->SetVisible( bShow );
  587. }
  588. UpdateTeamInfo();
  589. m_bShouldBeVisible = true;
  590. MoveToFront();
  591. }
  592. }
  593. //-----------------------------------------------------------------------------
  594. // Purpose:
  595. //-----------------------------------------------------------------------------
  596. void CTFWinPanel::UpdateTeamInfo()
  597. {
  598. bool bShowAvatars = g_TF_PR && g_TF_PR->HasPremadeParties();
  599. if ( bShowAvatars )
  600. {
  601. m_pRedLeaderAvatarImage->SetPlayer( GetSteamIDForPlayerIndex( g_TF_PR->GetPartyLeaderRedTeamIndex() ), k_EAvatarSize64x64 );
  602. m_pRedLeaderAvatarImage->SetShouldDrawFriendIcon( false );
  603. m_pBlueLeaderAvatarImage->SetPlayer( GetSteamIDForPlayerIndex( g_TF_PR->GetPartyLeaderBlueTeamIndex() ), k_EAvatarSize64x64 );
  604. m_pBlueLeaderAvatarImage->SetShouldDrawFriendIcon( false );
  605. }
  606. m_pRedLeaderAvatarImage->SetVisible( bShowAvatars );
  607. m_pRedLeaderAvatarBG->SetVisible( bShowAvatars );
  608. m_pRedTeamName->SetVisible( !bShowAvatars );
  609. m_pBlueLeaderAvatarImage->SetVisible( bShowAvatars );
  610. m_pBlueLeaderAvatarBG->SetVisible( bShowAvatars );
  611. m_pBlueTeamName->SetVisible( !bShowAvatars );
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose: Applies scheme settings
  615. //-----------------------------------------------------------------------------
  616. void CTFWinPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  617. {
  618. BaseClass::ApplySchemeSettings( pScheme );
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Purpose: returns whether panel should be drawn
  622. //-----------------------------------------------------------------------------
  623. bool CTFWinPanel::ShouldDraw()
  624. {
  625. if ( !m_bShouldBeVisible )
  626. return false;
  627. return CHudElement::ShouldDraw();
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose: panel think method
  631. //-----------------------------------------------------------------------------
  632. void CTFWinPanel::OnThink()
  633. {
  634. // if we've scheduled ourselves to update the team scores, handle it now
  635. if ( m_flTimeUpdateTeamScore > 0 && ( gpGlobals->curtime > m_flTimeUpdateTeamScore ) && m_pTeamScorePanel )
  636. {
  637. IGameEvent *event = gameeventmanager->CreateEvent( "winpanel_show_scores" );
  638. if ( event )
  639. {
  640. gameeventmanager->FireEventClientSide( event );
  641. }
  642. // play a sound
  643. CLocalPlayerFilter filter;
  644. C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Hud.EndRoundScored" );
  645. // update the team scores
  646. if ( m_pTeamScorePanel )
  647. {
  648. m_pTeamScorePanel->SetDialogVariable( "blueteamscore", m_iBlueTeamScore );
  649. m_pTeamScorePanel->SetDialogVariable( "redteamscore", m_iRedTeamScore );
  650. }
  651. m_flTimeUpdateTeamScore = 0;
  652. }
  653. }