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.

292 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_matchmaking_dashboard.h"
  8. #include "tf_gamerules.h"
  9. #include "tf_gc_client.h"
  10. #include "clientmode_tf.h"
  11. #include <vgui_controls/AnimationController.h>
  12. #include <vgui_controls/CircularProgressBar.h>
  13. using namespace vgui;
  14. using namespace GCSDK;
  15. extern ConVar tf_mm_next_map_vote_time;
  16. #ifdef STAGING_ONLY
  17. extern ConVar tf_mm_popup_state_override;
  18. #endif
  19. #ifdef STAGING_ONLY
  20. CON_COMMAND( test_next_map_vote, "Fakes a player voting" )
  21. {
  22. IGameEvent *event = gameeventmanager->CreateEvent( "player_next_map_vote_change" );
  23. if ( event )
  24. {
  25. event->SetInt( "map_index", RandomInt( 0, 2 ) );
  26. // Client-side once it's actually happened
  27. gameeventmanager->FireEventClientSide( event );
  28. }
  29. }
  30. #endif
  31. class CNextMapVotingDashboardState : public CTFMatchmakingPopup
  32. {
  33. public:
  34. CNextMapVotingDashboardState( const char* pszName, const char* pszResFile )
  35. : CTFMatchmakingPopup( pszName, pszResFile )
  36. , m_pTimerProgressBar( NULL )
  37. {
  38. memset( m_arMapPanels, 0, sizeof( m_arMapPanels ) );
  39. ListenForGameEvent( "player_next_map_vote_change" );
  40. ListenForGameEvent( "vote_maps_changed" );
  41. }
  42. virtual void ApplySchemeSettings( IScheme *pScheme )
  43. {
  44. CTFMatchmakingPopup::ApplySchemeSettings( pScheme );
  45. m_pTimerProgressBar = FindControl< CircularProgressBar >( "TimeRemainingProgressBar", true );
  46. if ( m_pTimerProgressBar )
  47. {
  48. m_pTimerProgressBar->SetProgressDirection( CircularProgressBar::PROGRESS_CCW );
  49. m_pTimerProgressBar->SetFgImage( GetLocalPlayerTeam() == TF_TEAM_RED ? "progress_bar_red" : "progress_bar_blu" );
  50. }
  51. for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
  52. {
  53. EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true );
  54. if ( pMapChoice )
  55. {
  56. pMapChoice->LoadControlSettings( "resource/UI/MatchMakingDashboardPopup_MapVotePanel.res" );
  57. }
  58. }
  59. }
  60. virtual void PerformLayout() OVERRIDE
  61. {
  62. CTFMatchmakingPopup::PerformLayout();
  63. SetMapChoiceSettings();
  64. UpdateVoteCounts();
  65. }
  66. virtual void OnUpdate() OVERRIDE
  67. {
  68. CTFMatchmakingPopup::OnUpdate();
  69. // Default to looping 30 sec cycle for debugging
  70. float flVoteEndTime = ( 30 + ( ( int( Plat_FloatTime() ) / 30 ) * 30 ) - Plat_FloatTime() ) / 30.f;
  71. if ( TFGameRules() )
  72. {
  73. // Get the actual countdown if we have gamerules
  74. flVoteEndTime = ( tf_mm_next_map_vote_time.GetInt() - ( gpGlobals->curtime - TFGameRules()->GetLastRoundStateChangeTime() ) ) / tf_mm_next_map_vote_time.GetFloat();
  75. }
  76. if ( m_pTimerProgressBar )
  77. {
  78. m_pTimerProgressBar->SetProgress( flVoteEndTime );
  79. }
  80. }
  81. virtual bool ShouldBeActve() const OVERRIDE
  82. {
  83. #ifdef STAGING_ONLY
  84. if ( FStrEq( const_cast<CNextMapVotingDashboardState*>(this)->GetName(), tf_mm_popup_state_override.GetString() ) )
  85. return true;
  86. #endif
  87. if ( BInEndOfMatch() &&
  88. TFGameRules() &&
  89. TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE &&
  90. GTFGCClientSystem()->BConnectedToMatchServer( false ) )
  91. {
  92. return true;
  93. }
  94. return false;
  95. }
  96. virtual void OnCommand( const char *pszCommand )
  97. {
  98. if ( Q_strnicmp( pszCommand, "choice", 6 ) == 0 &&
  99. GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED )
  100. {
  101. int nIndex = atoi( pszCommand + 6 );
  102. Assert( nIndex >= 0 && nIndex <= 2 );
  103. if ( nIndex < 0 || nIndex > 2 )
  104. return;
  105. engine->ClientCmd( CFmtStr( "next_map_vote %d", nIndex ) );
  106. }
  107. }
  108. virtual void FireGameEvent( IGameEvent *pEvent )
  109. {
  110. if ( FStrEq( pEvent->GetName(), "player_next_map_vote_change" ) &&
  111. TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE )
  112. {
  113. ShowVoteByOtherPlayer( pEvent->GetInt( "map_index" ) );
  114. InvalidateLayout();
  115. surface()->PlaySound( UTIL_GetRandomSoundFromEntry( "Vote.Cast.Yes" ) );
  116. return;
  117. }
  118. else if ( FStrEq( pEvent->GetName(), "vote_maps_changed" ) )
  119. {
  120. InvalidateLayout( false, true );
  121. }
  122. }
  123. virtual void OnEnter() OVERRIDE
  124. {
  125. // To get the voting options setup how they're supposed to be
  126. InvalidateLayout( true, false);
  127. CTFMatchmakingPopup::OnEnter();
  128. }
  129. private:
  130. void SetMapChoiceSettings()
  131. {
  132. for ( int nIndex = 0; nIndex < NEXT_MAP_VOTE_OPTIONS; ++nIndex )
  133. {
  134. const MapDef_t* pMapDef = NULL;
  135. if ( TFGameRules() )
  136. {
  137. pMapDef = GetItemSchema()->GetMasterMapDefByIndex( TFGameRules()->GetNextMapVoteOption( nIndex ) );
  138. }
  139. else
  140. {
  141. pMapDef = GetItemSchema()->GetMasterMapDefByIndex( RandomInt( 1, GetItemSchema()->GetMapCount() - 1 ) );
  142. }
  143. Assert( pMapDef );
  144. if ( !pMapDef )
  145. return;
  146. EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true );
  147. if ( pMapChoice )
  148. {
  149. ScalableImagePanel* pMapImage = pMapChoice->FindControl< ScalableImagePanel >( "MapImage", true );
  150. // The image
  151. if ( pMapImage )
  152. {
  153. m_arMapPanels[ nIndex ].pMapImage = pMapImage;
  154. char imagename[ 512 ];
  155. Q_snprintf( imagename, sizeof( imagename ), "..\\vgui\\maps\\menu_thumb_%s", pMapDef->pszMapName );
  156. pMapImage->SetImage( imagename );
  157. }
  158. // Label text
  159. pMapChoice->SetDialogVariable( "mapname", g_pVGuiLocalize->Find( pMapDef->pszMapNameLocKey ) );
  160. m_arMapPanels[ nIndex ].pMapNameLabel = pMapChoice->FindControl< Label >( "NameLabel" );
  161. // Fixup the button
  162. Button* pButton = pMapChoice->FindControl< Button >( "SelectButton" );
  163. if ( pButton )
  164. {
  165. m_arMapPanels[ nIndex ].pChooseButton = pButton;
  166. pButton->SetCommand( CFmtStr( "choice%d", nIndex ) );
  167. // Dont let people click anymore if the've already voted
  168. pButton->SetEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED );
  169. pButton->SetMouseInputEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED );
  170. // Give the one the user selected a green border
  171. if ( GetPlayerVoteState() == nIndex )
  172. {
  173. pButton->SetArmed( true );
  174. pButton->MakeReadyForUse();
  175. pButton->SetArmedColor( pButton->GetButtonArmedFgColor(), scheme()->GetIScheme( GetScheme() )->GetColor( "CreditsGreen", Color( 94, 150, 49, 255 ) ) );
  176. }
  177. }
  178. }
  179. }
  180. }
  181. void ShowVoteByOtherPlayer( int nIndex )
  182. {
  183. EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true );
  184. if ( pMapChoice )
  185. {
  186. // Play animation on the map that got voted on
  187. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoice, "MapVoted" );
  188. }
  189. }
  190. void UpdateVoteCounts()
  191. {
  192. int nVotes[ CTFGameRules::EUserNextMapVote::NUM_VOTE_STATES ];
  193. memset( nVotes, 0, sizeof( nVotes ) );
  194. int nTotalVotes = 0;
  195. CTFGameRules::EUserNextMapVote eWinningVote = CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED;
  196. if ( TFGameRules() )
  197. {
  198. TFGameRules()->GetWinningVote( nVotes );
  199. }
  200. else
  201. {
  202. // For testing on the main menu
  203. for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
  204. {
  205. nVotes[ i ] += RandomInt( 0, 10 );
  206. eWinningVote = (CTFGameRules::EUserNextMapVote)( nVotes[ i ] >= nVotes[ eWinningVote ] ? i : eWinningVote );
  207. }
  208. }
  209. // Calculate the total so we can do a % breakdown
  210. for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
  211. {
  212. nTotalVotes += nVotes[ i ];
  213. }
  214. for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i )
  215. {
  216. float flPercent = nTotalVotes ? (float)nVotes[ i ] / nTotalVotes * 100.f : 0.f;
  217. EditablePanel* pMapChoicePanel = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true );
  218. if ( pMapChoicePanel )
  219. {
  220. // Update the label with the % total
  221. pMapChoicePanel->SetDialogVariable( "votes", CFmtStr( "%3.0f%%", flPercent ) );
  222. // Do a color change animation
  223. if ( g_pClientMode && g_pClientMode->GetViewport() )
  224. {
  225. g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( pMapChoicePanel, i == eWinningVote ? "LosingNextMapVote" : "WinningNextMapVote" );
  226. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoicePanel, i == eWinningVote ? "WinningNextMapVote" : "LosingNextMapVote" );
  227. }
  228. }
  229. }
  230. }
  231. CTFGameRules::EUserNextMapVote GetPlayerVoteState()
  232. {
  233. if ( TFGameRules() )
  234. {
  235. int nPlayerIndex = GetLocalPlayerIndex();
  236. return TFGameRules()->PlayerNextMapVoteState( nPlayerIndex );
  237. }
  238. return CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED;
  239. }
  240. CircularProgressBar* m_pTimerProgressBar;
  241. struct MapChoice_t
  242. {
  243. ScalableImagePanel* pMapImage;
  244. Label* pMapNameLabel;
  245. Button* pChooseButton;
  246. };
  247. MapChoice_t m_arMapPanels[3];
  248. };
  249. REG_MM_POPUP_FACTORY( CNextMapVotingDashboardState, "NextMapVoting", "resource/UI/MatchMakingDashboardPopup_NextMapVoting.res" )