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.
293 lines
8.6 KiB
293 lines
8.6 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
|
|
#include "cbase.h" |
|
#include "tf_matchmaking_dashboard.h" |
|
#include "tf_gamerules.h" |
|
#include "tf_gc_client.h" |
|
#include "clientmode_tf.h" |
|
#include <vgui_controls/AnimationController.h> |
|
#include <vgui_controls/CircularProgressBar.h> |
|
|
|
using namespace vgui; |
|
using namespace GCSDK; |
|
|
|
extern ConVar tf_mm_next_map_vote_time; |
|
|
|
#ifdef STAGING_ONLY |
|
extern ConVar tf_mm_popup_state_override; |
|
#endif |
|
|
|
#ifdef STAGING_ONLY |
|
CON_COMMAND( test_next_map_vote, "Fakes a player voting" ) |
|
{ |
|
IGameEvent *event = gameeventmanager->CreateEvent( "player_next_map_vote_change" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "map_index", RandomInt( 0, 2 ) ); |
|
// Client-side once it's actually happened |
|
gameeventmanager->FireEventClientSide( event ); |
|
} |
|
} |
|
#endif |
|
|
|
class CNextMapVotingDashboardState : public CTFMatchmakingPopup |
|
{ |
|
public: |
|
CNextMapVotingDashboardState( const char* pszName, const char* pszResFile ) |
|
: CTFMatchmakingPopup( pszName, pszResFile ) |
|
, m_pTimerProgressBar( NULL ) |
|
{ |
|
memset( m_arMapPanels, 0, sizeof( m_arMapPanels ) ); |
|
ListenForGameEvent( "player_next_map_vote_change" ); |
|
ListenForGameEvent( "vote_maps_changed" ); |
|
} |
|
|
|
virtual void ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
CTFMatchmakingPopup::ApplySchemeSettings( pScheme ); |
|
|
|
m_pTimerProgressBar = FindControl< CircularProgressBar >( "TimeRemainingProgressBar", true ); |
|
if ( m_pTimerProgressBar ) |
|
{ |
|
m_pTimerProgressBar->SetProgressDirection( CircularProgressBar::PROGRESS_CCW ); |
|
m_pTimerProgressBar->SetFgImage( GetLocalPlayerTeam() == TF_TEAM_RED ? "progress_bar_red" : "progress_bar_blu" ); |
|
} |
|
|
|
for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i ) |
|
{ |
|
EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true ); |
|
if ( pMapChoice ) |
|
{ |
|
pMapChoice->LoadControlSettings( "resource/UI/MatchMakingDashboardPopup_MapVotePanel.res" ); |
|
} |
|
} |
|
} |
|
|
|
virtual void PerformLayout() OVERRIDE |
|
{ |
|
CTFMatchmakingPopup::PerformLayout(); |
|
|
|
SetMapChoiceSettings(); |
|
UpdateVoteCounts(); |
|
} |
|
|
|
virtual void OnUpdate() OVERRIDE |
|
{ |
|
CTFMatchmakingPopup::OnUpdate(); |
|
|
|
// Default to looping 30 sec cycle for debugging |
|
float flVoteEndTime = ( 30 + ( ( int( Plat_FloatTime() ) / 30 ) * 30 ) - Plat_FloatTime() ) / 30.f; |
|
|
|
if ( TFGameRules() ) |
|
{ |
|
// Get the actual countdown if we have gamerules |
|
flVoteEndTime = ( tf_mm_next_map_vote_time.GetInt() - ( gpGlobals->curtime - TFGameRules()->GetLastRoundStateChangeTime() ) ) / tf_mm_next_map_vote_time.GetFloat(); |
|
} |
|
|
|
if ( m_pTimerProgressBar ) |
|
{ |
|
m_pTimerProgressBar->SetProgress( flVoteEndTime ); |
|
} |
|
} |
|
|
|
virtual bool ShouldBeActve() const OVERRIDE |
|
{ |
|
#ifdef STAGING_ONLY |
|
if ( FStrEq( const_cast<CNextMapVotingDashboardState*>(this)->GetName(), tf_mm_popup_state_override.GetString() ) ) |
|
return true; |
|
#endif |
|
|
|
if ( BInEndOfMatch() && |
|
TFGameRules() && |
|
TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE && |
|
GTFGCClientSystem()->BConnectedToMatchServer( false ) ) |
|
{ |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
virtual void OnCommand( const char *pszCommand ) |
|
{ |
|
if ( Q_strnicmp( pszCommand, "choice", 6 ) == 0 && |
|
GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED ) |
|
{ |
|
int nIndex = atoi( pszCommand + 6 ); |
|
Assert( nIndex >= 0 && nIndex <= 2 ); |
|
if ( nIndex < 0 || nIndex > 2 ) |
|
return; |
|
|
|
engine->ClientCmd( CFmtStr( "next_map_vote %d", nIndex ) ); |
|
} |
|
} |
|
|
|
virtual void FireGameEvent( IGameEvent *pEvent ) |
|
{ |
|
if ( FStrEq( pEvent->GetName(), "player_next_map_vote_change" ) && |
|
TFGameRules()->GetCurrentNextMapVotingState() == CTFGameRules::NEXT_MAP_VOTE_STATE_WAITING_FOR_USERS_TO_VOTE ) |
|
{ |
|
ShowVoteByOtherPlayer( pEvent->GetInt( "map_index" ) ); |
|
InvalidateLayout(); |
|
surface()->PlaySound( UTIL_GetRandomSoundFromEntry( "Vote.Cast.Yes" ) ); |
|
|
|
return; |
|
} |
|
else if ( FStrEq( pEvent->GetName(), "vote_maps_changed" ) ) |
|
{ |
|
InvalidateLayout( false, true ); |
|
} |
|
} |
|
|
|
virtual void OnEnter() OVERRIDE |
|
{ |
|
// To get the voting options setup how they're supposed to be |
|
InvalidateLayout( true, false); |
|
|
|
CTFMatchmakingPopup::OnEnter(); |
|
} |
|
|
|
private: |
|
|
|
void SetMapChoiceSettings() |
|
{ |
|
for ( int nIndex = 0; nIndex < NEXT_MAP_VOTE_OPTIONS; ++nIndex ) |
|
{ |
|
const MapDef_t* pMapDef = NULL; |
|
|
|
if ( TFGameRules() ) |
|
{ |
|
pMapDef = GetItemSchema()->GetMasterMapDefByIndex( TFGameRules()->GetNextMapVoteOption( nIndex ) ); |
|
} |
|
else |
|
{ |
|
pMapDef = GetItemSchema()->GetMasterMapDefByIndex( RandomInt( 1, GetItemSchema()->GetMapCount() - 1 ) ); |
|
} |
|
|
|
Assert( pMapDef ); |
|
if ( !pMapDef ) |
|
return; |
|
|
|
EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true ); |
|
if ( pMapChoice ) |
|
{ |
|
ScalableImagePanel* pMapImage = pMapChoice->FindControl< ScalableImagePanel >( "MapImage", true ); |
|
|
|
// The image |
|
if ( pMapImage ) |
|
{ |
|
m_arMapPanels[ nIndex ].pMapImage = pMapImage; |
|
char imagename[ 512 ]; |
|
Q_snprintf( imagename, sizeof( imagename ), "..\\vgui\\maps\\menu_thumb_%s", pMapDef->pszMapName ); |
|
pMapImage->SetImage( imagename ); |
|
} |
|
|
|
// Label text |
|
pMapChoice->SetDialogVariable( "mapname", g_pVGuiLocalize->Find( pMapDef->pszMapNameLocKey ) ); |
|
m_arMapPanels[ nIndex ].pMapNameLabel = pMapChoice->FindControl< Label >( "NameLabel" ); |
|
|
|
// Fixup the button |
|
Button* pButton = pMapChoice->FindControl< Button >( "SelectButton" ); |
|
if ( pButton ) |
|
{ |
|
m_arMapPanels[ nIndex ].pChooseButton = pButton; |
|
pButton->SetCommand( CFmtStr( "choice%d", nIndex ) ); |
|
// Dont let people click anymore if the've already voted |
|
pButton->SetEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED ); |
|
pButton->SetMouseInputEnabled( GetPlayerVoteState() == CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED ); |
|
|
|
// Give the one the user selected a green border |
|
if ( GetPlayerVoteState() == nIndex ) |
|
{ |
|
pButton->SetArmed( true ); |
|
pButton->MakeReadyForUse(); |
|
pButton->SetArmedColor( pButton->GetButtonArmedFgColor(), scheme()->GetIScheme( GetScheme() )->GetColor( "CreditsGreen", Color( 94, 150, 49, 255 ) ) ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void ShowVoteByOtherPlayer( int nIndex ) |
|
{ |
|
EditablePanel* pMapChoice = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", nIndex ), true ); |
|
if ( pMapChoice ) |
|
{ |
|
// Play animation on the map that got voted on |
|
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoice, "MapVoted" ); |
|
} |
|
} |
|
|
|
void UpdateVoteCounts() |
|
{ |
|
int nVotes[ CTFGameRules::EUserNextMapVote::NUM_VOTE_STATES ]; |
|
memset( nVotes, 0, sizeof( nVotes ) ); |
|
int nTotalVotes = 0; |
|
|
|
CTFGameRules::EUserNextMapVote eWinningVote = CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED; |
|
if ( TFGameRules() ) |
|
{ |
|
TFGameRules()->GetWinningVote( nVotes ); |
|
} |
|
else |
|
{ |
|
// For testing on the main menu |
|
for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i ) |
|
{ |
|
nVotes[ i ] += RandomInt( 0, 10 ); |
|
eWinningVote = (CTFGameRules::EUserNextMapVote)( nVotes[ i ] >= nVotes[ eWinningVote ] ? i : eWinningVote ); |
|
} |
|
} |
|
|
|
// Calculate the total so we can do a % breakdown |
|
for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i ) |
|
{ |
|
nTotalVotes += nVotes[ i ]; |
|
} |
|
|
|
for ( int i=0; i < NEXT_MAP_VOTE_OPTIONS; ++i ) |
|
{ |
|
float flPercent = nTotalVotes ? (float)nVotes[ i ] / nTotalVotes * 100.f : 0.f; |
|
EditablePanel* pMapChoicePanel = FindControl< EditablePanel >( CFmtStr( "MapChoice%d", i ), true ); |
|
if ( pMapChoicePanel ) |
|
{ |
|
// Update the label with the % total |
|
pMapChoicePanel->SetDialogVariable( "votes", CFmtStr( "%3.0f%%", flPercent ) ); |
|
// Do a color change animation |
|
if ( g_pClientMode && g_pClientMode->GetViewport() ) |
|
{ |
|
g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( pMapChoicePanel, i == eWinningVote ? "LosingNextMapVote" : "WinningNextMapVote" ); |
|
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pMapChoicePanel, i == eWinningVote ? "WinningNextMapVote" : "LosingNextMapVote" ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
CTFGameRules::EUserNextMapVote GetPlayerVoteState() |
|
{ |
|
if ( TFGameRules() ) |
|
{ |
|
int nPlayerIndex = GetLocalPlayerIndex(); |
|
return TFGameRules()->PlayerNextMapVoteState( nPlayerIndex ); |
|
} |
|
|
|
return CTFGameRules::USER_NEXT_MAP_VOTE_UNDECIDED; |
|
} |
|
|
|
CircularProgressBar* m_pTimerProgressBar; |
|
|
|
struct MapChoice_t |
|
{ |
|
ScalableImagePanel* pMapImage; |
|
Label* pMapNameLabel; |
|
Button* pChooseButton; |
|
}; |
|
MapChoice_t m_arMapPanels[3]; |
|
}; |
|
|
|
REG_MM_POPUP_FACTORY( CNextMapVotingDashboardState, "NextMapVoting", "resource/UI/MatchMakingDashboardPopup_NextMapVoting.res" ) |