Joe Ludwig beaae8ac45 Updated the SDK with the latest code from the TF and HL2 branches
* Adds support for Visual Studio 2012 and 2013
* VR Mode:
. Switches from headtrack.dll to sourcevr.dll
. Improved readability of the UI in VR
. Removed the IPD calibration tool. TF2 will now obey the Oculus
configuration file. Use the Oculus calibration tool in your SDK or
install and run "OpenVR" under Tools in Steam to calibrate your IPD.
. Added dropdown to enable VR mode in the Video options. Removed the -vr
command line option.
. Added the ability to switch in and out of VR mode without quitting the
game
. By default VR mode will run full screen. To switch back to a
borderless window set the vr_force_windowed convar.
. Added support for VR mode on Linux
* Many assorted bug fixes and other changes from Team Fortress in
various shared files
2013-12-03 08:54:16 -08:00

1726 lines
53 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
//===========================================================================//
#include "cbase.h"
#include "hud.h"
#include "hudelement.h"
#include "hud_macros.h"
#include "hud_numericdisplay.h"
#include "iclientmode.h"
#include "clientmode_shared.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterialvar.h"
#include "con_nprint.h"
#include "hud_vote.h"
#include "menu.h"
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
#include <vgui/ILocalize.h>
#include <KeyValues.h>
#include <vgui_controls/AnimationController.h>
#include <vgui_controls/EditablePanel.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/ComboBox.h>
#include <vgui_controls/ImageList.h>
#include "vgui_avatarimage.h"
#ifdef TF_CLIENT_DLL
#include "ienginevgui.h"
#include "tf_gcmessages.h"
#include "c_tf_player.h"
#include "econ_notifications.h"
#include "confirm_dialog.h"
#include "gc_clientsystem.h"
#include "tf_gamerules.h"
#include "c_playerresource.h"
#include "c_tf_objective_resource.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar cl_vote_ui_active_after_voting( "cl_vote_ui_active_after_voting", "0" );
ConVar cl_vote_ui_show_notification( "cl_vote_ui_show_notification", "0" );
#ifdef TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CTFVoteNotification : public CEconNotification
{
public:
CTFVoteNotification( const char *pPlayerName ) : CEconNotification()
{
g_pVGuiLocalize->ConvertANSIToUnicode( pPlayerName, m_wszPlayerName, sizeof(m_wszPlayerName) );
SetLifetime( 7 );
SetText( "#Vote_notification_text" );
AddStringToken( "initiator", m_wszPlayerName );
}
virtual bool CanBeTriggered()
{
return true;
}
virtual void Trigger()
{
CTFGenericConfirmDialog *pDialog = ShowConfirmDialog( "#Vote_notification_title", "#Vote_notification_text", "#Vote_notification_view", "#cancel", &ConfirmShowVoteSetup );
pDialog->SetContext( this );
pDialog->AddStringToken( "initiator", m_wszPlayerName );
// so we aren't deleted
SetIsInUse( true );
}
virtual bool CanBeAcceptedOrDeclined()
{
return true;
}
virtual void Accept()
{
ConfirmShowVoteSetup( true, this );
}
virtual void Decline()
{
ConfirmShowVoteSetup( false, this );
}
static void ConfirmShowVoteSetup( bool bConfirmed, void *pContext )
{
CTFVoteNotification *pNotification = (CTFVoteNotification*)pContext;
if ( bConfirmed )
{
// Show vote
CHudVote *pHudVote = GET_HUDELEMENT( CHudVote );
if ( pHudVote )
{
pHudVote->ShowVoteUI();
}
}
pNotification->SetIsInUse( false );
pNotification->MarkForDeletion();
}
public:
wchar_t m_wszPlayerName[MAX_PLAYER_NAME_LENGTH];
};
#endif // TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
VoteBarPanel::VoteBarPanel( vgui::Panel *parent, const char *panelName ) : vgui::Panel( parent, panelName )
{
for( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
{
m_nVoteOptionCount[index] = 0;
}
m_nPotentialVotes = 0;
ListenForGameEvent( "vote_changed" );
}
void VoteBarPanel::Paint( void )
{
int wide, tall;
GetSize( wide, tall );
int x = 0;
// driller: this shouldn't ship - temp UI solution for playtesting
for ( int i = 0; i < 2; i++ )
{
// Draw an outlined box
vgui::surface()->DrawSetColor( 128, 128, 128, 128 );
vgui::surface()->DrawFilledRect( x, 0, x + m_iBoxSize, m_iBoxSize );
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawFilledRect( x + m_iBoxInset, m_iBoxInset, x + m_iBoxSize - m_iBoxInset, m_iBoxSize - m_iBoxInset );
vgui::surface()->DrawSetColor( Color(255, 255, 255, 255) );
x += ( m_iBoxSize + 64 );
}
x = 0;
int iImageInset = 2 * m_iBoxInset;
// Yes image
vgui::surface()->DrawSetTexture( m_nYesTextureId );
vgui::surface()->DrawTexturedRect( x + iImageInset, iImageInset, x + m_iBoxSize - iImageInset, m_iBoxSize - iImageInset );
x += ( m_iBoxSize + 64 );
// No image
vgui::surface()->DrawSetTexture( m_nNoTextureId );
vgui::surface()->DrawTexturedRect( x + iImageInset, iImageInset, x + m_iBoxSize - iImageInset, m_iBoxSize - iImageInset );
}
void VoteBarPanel::FireGameEvent( IGameEvent *event )
{
const char *eventName = event->GetName();
if ( !eventName )
return;
if( FStrEq( eventName, "vote_changed" ) )
{
for ( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
{
char szOption[2];
Q_snprintf( szOption, sizeof( szOption ), "%i", index + 1 );
char szVoteOption[13] = "vote_option";
Q_strncat( szVoteOption, szOption, sizeof( szVoteOption ), COPY_ALL_CHARACTERS );
m_nVoteOptionCount[index] = event->GetInt( szVoteOption );
}
m_nPotentialVotes = event->GetInt( "potentialVotes" );
}
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CVoteSetupDialog::CVoteSetupDialog( vgui::Panel *parent ) : BaseClass( parent, "VoteSetupDialog" )
{
SetMoveable( false );
SetSizeable( false );
m_pVoteSetupList = new SectionedListPanel( this, "VoteSetupList" );
m_pVoteParameterList = new SectionedListPanel( this, "VoteParameterList" );
m_pCallVoteButton = new Button( this, "CallVoteButton", "CallVote", this, "CallVote" );
m_pComboBox = new ComboBox( this, "ComboBox", 5, false );
m_pImageList = NULL;
#ifdef TF_CLIENT_DLL
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
SetScheme(scheme);
#else
SetScheme( "ClientScheme" );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CVoteSetupDialog::~CVoteSetupDialog()
{
if ( m_pImageList )
{
delete m_pImageList;
m_pImageList = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetProportional( true );
LoadControlSettings( "Resource/UI/VoteHud.res" );
m_pComboBox->GetComboButton()->SetFgColor( Color( 117,107,94,255 ) );
m_pComboBox->GetComboButton()->SetDefaultColor( Color( 117,107,94,255), Color( 0,0,0,0) );
m_pComboBox->GetComboButton()->SetArmedColor( Color( 117,107,94,255), Color( 0,0,0,0) );
m_pComboBox->GetComboButton()->SetDepressedColor( Color( 117,107,94,255), Color( 0,0,0,0) );
if ( m_pImageList )
{
delete m_pImageList;
}
m_pImageList = new ImageList( false );
}
//-----------------------------------------------------------------------------
// Purpose: Does dialog-specific customization after applying scheme settings.
//-----------------------------------------------------------------------------
void CVoteSetupDialog::PostApplySchemeSettings( vgui::IScheme *pScheme )
{
// resize the images to our resolution
for ( int i = 0; i < m_pImageList->GetImageCount(); i++ )
{
int wide, tall;
m_pImageList->GetImage( i )->GetSize( wide, tall );
m_pImageList->GetImage( i )->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(), wide ), scheme()->GetProportionalScaledValueEx( GetScheme(), tall ) );
}
m_pVoteParameterList->SetImageList( m_pImageList, false );
m_pVoteParameterList->SetVisible( true );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::ApplySettings(KeyValues *inResourceData)
{
BaseClass::ApplySettings( inResourceData );
IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
m_hIssueFont = INVALID_FONT;
const char *pszFont = inResourceData->GetString( "issue_font", NULL );
if ( pszFont && pszFont[0] )
{
m_hIssueFont = pScheme->GetFont( pszFont, true );
}
m_hHeaderFont = INVALID_FONT;
pszFont = inResourceData->GetString( "header_font", NULL );
if ( pszFont && pszFont[0] )
{
m_hHeaderFont = pScheme->GetFont( pszFont, true );
}
const char *pszColor = inResourceData->GetString( "issue_fgcolor", "Label.TextColor" );
m_IssueFGColor = pScheme->GetColor( pszColor, Color( 255, 255, 255, 255 ) );
pszColor = inResourceData->GetString( "issue_fgcolor_disabled", "Label.TextColor" );
m_IssueFGColorDisabled = pScheme->GetColor( pszColor, Color( 255, 255, 255, 255 ) );
pszColor = inResourceData->GetString( "header_fgcolor", "Label.TextColor" );
m_HeaderFGColor = pScheme->GetColor( pszColor, Color( 255, 255, 255, 255 ) );
}
//-----------------------------------------------------------------------------
// Purpose: Keep track of the current map
//-----------------------------------------------------------------------------
void CVoteSetupDialog::UpdateCurrentMap( void )
{
Q_FileBase( engine->GetLevelName(), m_szCurrentMap, sizeof(m_szCurrentMap) );
Q_strlower( m_szCurrentMap );
}
//-----------------------------------------------------------------------------
// Purpose: Feeds Issues from the server to this Dialog
//-----------------------------------------------------------------------------
void CVoteSetupDialog::AddVoteIssues( CUtlStringList &m_VoteSetupIssues )
{
m_VoteIssues.RemoveAll();
for ( int index = 0; index < m_VoteSetupIssues.Count(); index++ )
{
m_VoteIssues.AddToTail( m_VoteSetupIssues[index] );
}
}
//-----------------------------------------------------------------------------
// Purpose: Feeds the server's MapCycle to the parameters dialog
//-----------------------------------------------------------------------------
void CVoteSetupDialog::AddVoteIssueParams_MapCycle( CUtlStringList &m_VoteSetupMapCycle )
{
m_VoteIssuesMapCycle.RemoveAll();
for ( int index = 0; index < m_VoteSetupMapCycle.Count(); index++ )
{
m_VoteIssuesMapCycle.AddToTail( m_VoteSetupMapCycle[index] );
}
}
#ifdef TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Feeds the server's PopFiles to the parameters dialog
//-----------------------------------------------------------------------------
void CVoteSetupDialog::AddVoteIssueParams_PopFiles( CUtlStringList &m_VoteSetupPopFiles )
{
m_VoteIssuesPopFiles.RemoveAll();
for ( int index = 0; index < m_VoteSetupPopFiles.Count(); index++ )
{
m_VoteIssuesPopFiles.AddToTail( m_VoteSetupPopFiles[index] );
}
}
#endif // TF_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::Activate()
{
InvalidateLayout( true, true );
BaseClass::Activate();
ResetData();
m_pVoteSetupList->SetVerticalScrollbar( true );
m_pVoteSetupList->RemoveAll();
m_pVoteSetupList->RemoveAllSections();
m_pVoteSetupList->AddSection( 0, "Issue" );
m_pVoteSetupList->SetSectionAlwaysVisible( 0, true );
m_pVoteSetupList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) );
m_pVoteSetupList->SetBgColor( Color( 0, 0, 0, 0 ) );
m_pVoteSetupList->SetBorder( NULL );
m_pVoteSetupList->AddColumnToSection( 0, "Issue", "#TF_Vote_Column_Issue", SectionedListPanel::COLUMN_CENTER, m_iIssueWidth );
if ( m_hHeaderFont != INVALID_FONT )
{
m_pVoteSetupList->SetFontSection( 0, m_hHeaderFont );
m_pVoteSetupList->SetSectionFgColor( 0, m_HeaderFGColor );
}
m_pVoteParameterList->SetVerticalScrollbar( true );
m_pVoteParameterList->RemoveAll();
m_pVoteParameterList->RemoveAllSections();
m_pVoteParameterList->AddSection( 0, "Name" );
m_pVoteParameterList->SetSectionAlwaysVisible( 0, true );
m_pVoteParameterList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) );
m_pVoteParameterList->SetBgColor( Color( 0, 0, 0, 0 ) );
m_pVoteParameterList->SetBorder( NULL );
m_pVoteParameterList->AddColumnToSection( 0, "Avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, 55 );
m_pVoteParameterList->AddColumnToSection( 0, "", "", 0, 10 ); // Spacer
m_pVoteParameterList->AddColumnToSection( 0, "Name", "#TF_Vote_Column_Name", 0, m_iParameterWidth * 0.6 );
m_pVoteParameterList->AddColumnToSection( 0, "Properties", "#TF_Vote_Column_Properties", SectionedListPanel::COLUMN_CENTER, m_iParameterWidth * 0.3 );
if ( m_hHeaderFont != INVALID_FONT )
{
m_pVoteParameterList->SetFontSection( 0, m_hHeaderFont );
m_pVoteParameterList->SetSectionFgColor( 0, m_HeaderFGColor );
m_pVoteParameterList->SetFontSection( 1, m_hHeaderFont );
m_pVoteParameterList->SetSectionFgColor( 1, m_HeaderFGColor );
}
// Populate the Issue list
for ( int index = 0; index < m_VoteIssues.Count(); index++ )
{
const char *pszIssue = m_VoteIssues[index];
if ( !pszIssue || !pszIssue[0] )
continue;
KeyValues *pKeyValues = new KeyValues( "Issue" );
pKeyValues->SetString( "Issue", pszIssue );
int iId = m_pVoteSetupList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
// Setup the list entry style
if ( m_hIssueFont != INVALID_FONT )
{
m_pVoteSetupList->SetItemFont( iId, m_hIssueFont );
bool bDisabled = V_stristr( pszIssue, "(Disabled on Server)" ); // driller: need to localize
Color colFG = bDisabled ? m_IssueFGColorDisabled : m_IssueFGColor;
m_pVoteSetupList->SetItemFgColor( iId, colFG );
}
}
// Select the first item by default
if ( m_pVoteSetupList->GetItemCount() > 0 )
{
m_pVoteSetupList->SetSelectedItem( 0 );
}
UpdateCurrentMap();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::OnClose()
{
ResetData();
BaseClass::OnClose();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::OnCommand(const char *command)
{
// We should have enough data to issue a CallVote command
if ( V_stricmp( command, "CallVote" ) == 0 )
{
int iSelectedItem = m_pVoteSetupList->GetSelectedItem();
if ( iSelectedItem >= 0 )
{
char szVoteCommand[128];
KeyValues *pIssueKeyValues = m_pVoteSetupList->GetItemData( iSelectedItem );
const char *szIssue = pIssueKeyValues->GetString( "Issue" );
if ( V_stricmp( "changelevel", szIssue ) == 0 || V_stricmp( "nextlevel", szIssue ) == 0 )
{
int nSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( nSelectedParam >= 0 )
{
// Get selected Map
int iSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( iSelectedParam >= 0 )
{
KeyValues *pParameterKeyValues = m_pVoteParameterList->GetItemData( iSelectedParam );
if ( pParameterKeyValues )
{
// Which Map?
const char *szMapName = pParameterKeyValues->GetString( "Name" );
Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssue, szMapName );
engine->ClientCmd( szVoteCommand );
}
}
}
}
else if ( V_stricmp( "kick", szIssue ) == 0 )
{
// Get selected Player
int iSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( iSelectedParam >= 0 )
{
KeyValues *pKeyValues = m_pVoteParameterList->GetItemData( iSelectedParam );
if ( pKeyValues )
{
// Is Player valid?
int playerIndex = pKeyValues->GetInt( "index" );
const char *pReasonString = m_pComboBox->GetActiveItemUserData() ? m_pComboBox->GetActiveItemUserData()->GetName() : "other";
player_info_t playerInfo;
if ( engine->GetPlayerInfo( playerIndex, &playerInfo ) )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( playerIndex );
Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s \"%d %s\"\n;", szIssue, pPlayer->GetUserID(), pReasonString );
engine->ClientCmd( szVoteCommand );
#ifdef TF_CLIENT_DLL
CSteamID steamID;
CTFPlayer* pSubject = ToTFPlayer( pPlayer );
if ( pSubject && pSubject->GetSteamID( &steamID ) && steamID.GetAccountID() != 0 )
{
GCSDK::CProtoBufMsg<CMsgTFVoteKickBanPlayer> msg( k_EMsgGCVoteKickBanPlayer );
uint32 reason = GetKickBanPlayerReason( pReasonString );
msg.Body().set_account_id_subject( steamID.GetAccountID() );
msg.Body().set_kick_reason( reason );
GCClientSystem()->BSendMessage( msg );
}
#endif
}
}
}
}
#ifdef TF_CLIENT_DLL
else if ( V_stricmp( "ChangeMission", szIssue ) == 0 )
{
int nSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( nSelectedParam >= 0 )
{
// Get selected Challenge
int iSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( iSelectedParam >= 0 )
{
KeyValues *pParameterKeyValues = m_pVoteParameterList->GetItemData( iSelectedParam );
if ( pParameterKeyValues )
{
// Which Pop File?
const char *szPopFile = pParameterKeyValues->GetString( "Name" );
Q_snprintf( szVoteCommand, sizeof( szVoteCommand ), "callvote %s %s\n;", szIssue, szPopFile );
engine->ClientCmd( szVoteCommand );
}
}
}
}
#endif // TF_CLIENT_DLL
else
{
// Non-parameter vote. i.e. callvote scrambleteams
Q_snprintf( szVoteCommand, sizeof(szVoteCommand), "callvote %s\n;", szIssue );
engine->ClientCmd( szVoteCommand );
}
Close();
}
}
else
{
BaseClass::OnCommand( command );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::OnItemSelected( vgui::Panel *panel )
{
if ( panel == m_pVoteSetupList )
{
m_pComboBox->RemoveAll();
m_pComboBox->SetVisible( false );
SetDialogVariable( "combo_label", "" );
// Which Issue did we select?
int iSelectedItem = m_pVoteSetupList->GetSelectedItem();
if ( iSelectedItem >= 0 )
{
KeyValues *pIssueKeyValues = m_pVoteSetupList->GetItemData( iSelectedItem );
if ( !pIssueKeyValues )
return;
// We're rebuilding, so clear state
m_bVoteButtonEnabled = false;
m_pVoteParameterList->ClearSelection();
m_pVoteParameterList->RemoveAll();
const char *szName = pIssueKeyValues->GetString( "Issue" );
if ( V_stricmp( "Voting disabled on this Server", szName ) == 0 )
{
m_bVoteButtonEnabled = false;
}
else if ( V_stristr( szName, "(Disabled on Server)" ) ) // driller: need to localize
{
m_bVoteButtonEnabled = false;
}
// CHANGELEVEL / NEXTLEVEL
else if ( V_stricmp( "changelevel", szName ) == 0 || V_stricmp( "nextlevel", szName ) == 0 )
{
// Feed the mapcycle to the parameters list
for ( int index = 0; index < m_VoteIssuesMapCycle.Count(); index++ )
{
// Don't show the current map
if ( V_strncmp( m_VoteIssuesMapCycle[index], m_szCurrentMap, ( V_strlen( m_VoteIssuesMapCycle[index] ) - 1 ) ) == 0 )
continue;
KeyValues *pKeyValues = new KeyValues( "Name" );
pKeyValues->SetString( "Name", m_VoteIssuesMapCycle[index] );
pKeyValues->SetInt( "index", index );
int iId = m_pVoteParameterList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
if ( m_hIssueFont != INVALID_FONT )
{
m_pVoteParameterList->SetItemFont( iId, m_hIssueFont );
m_pVoteParameterList->SetItemFgColor( iId, m_IssueFGColor );
}
}
if ( m_pVoteParameterList->GetItemCount() == 0 )
{
KeyValues *pKeyValues = new KeyValues( "Name" );
pKeyValues->SetString( "Name", "#TF_vote_no_maps" );
pKeyValues->SetInt( "index", 1 );
m_pVoteParameterList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
}
}
// KICK
else if ( V_stricmp( "kick", szName ) == 0 )
{
// Feed the player list to the parameters list
int nMaxClients = engine->GetMaxClients();
for ( int playerIndex = 1; playerIndex <= nMaxClients; playerIndex++ )
{
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( playerIndex );
if ( !pPlayer )
continue;
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
continue;
if ( pPlayer == pLocalPlayer )
continue;
bool bAllowKickUnassigned = false;
#ifdef TF_CLIENT_DLL
// Allow kicking team unassigned in MvM
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && g_PR->IsConnected( playerIndex ) && pPlayer->GetTeamNumber() == TEAM_UNASSIGNED )
{
bAllowKickUnassigned = true;
}
#endif // TF_CLIENT_DLL
// Can't kick people on the other team, so don't list them
if ( pPlayer->GetTeam() != pLocalPlayer->GetTeam() && !bAllowKickUnassigned )
continue;
char szPlayerIndex[32];
Q_snprintf( szPlayerIndex, sizeof( szPlayerIndex ), "%d", playerIndex );
KeyValues *pKeyValues = new KeyValues( szPlayerIndex );
pKeyValues->SetString( "Name", pPlayer->GetPlayerName() );
pKeyValues->SetInt( "index", playerIndex );
int iId = m_pVoteParameterList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
if ( m_hIssueFont != INVALID_FONT )
{
m_pVoteParameterList->SetItemFont( iId, m_hIssueFont );
m_pVoteParameterList->SetItemFgColor( iId, m_IssueFGColor );
}
}
#ifdef TF_CLIENT_DLL
SetDialogVariable( "combo_label", g_pVGuiLocalize->Find( "#TF_VoteKickReason" ) );
m_pComboBox->AddItem( g_pVGuiLocalize->Find( "TF_VoteKickReason_Other" ), new KeyValues( "other" ) );
m_pComboBox->AddItem( g_pVGuiLocalize->Find( "TF_VoteKickReason_Cheating" ), new KeyValues( "cheating" ) );
m_pComboBox->AddItem( g_pVGuiLocalize->Find( "TF_VoteKickReason_Idle" ), new KeyValues( "idle" ) );
m_pComboBox->AddItem( g_pVGuiLocalize->Find( "TF_VoteKickReason_Scamming" ), new KeyValues( "scamming" ) );
m_pComboBox->SilentActivateItemByRow( 0 );
m_pComboBox->SetVisible( true );
#endif
}
#ifdef TF_CLIENT_DLL
// CHANGE POP FILE
else if ( V_stricmp( "ChangeMission", szName ) == 0 )
{
// Feed the popfiles to the parameters list
for ( int index = 0; index < m_VoteIssuesPopFiles.Count(); index++ )
{
// Don't show the current pop file
if ( TFObjectiveResource()->GetMvMPopFileName() == '\0' )
{
// Use the map name
char szShortMapName[ MAX_MAP_NAME ];
V_strncpy( szShortMapName, engine->GetLevelName(), sizeof( szShortMapName ) );
V_StripExtension( szShortMapName, szShortMapName, sizeof( szShortMapName ) );
if ( V_strncmp( m_VoteIssuesPopFiles[index], V_GetFileName( szShortMapName ), ( V_strlen( m_VoteIssuesPopFiles[index] ) - 1 ) ) == 0 )
continue;
}
else
{
// Use the specified pop file
if ( V_strncmp( m_VoteIssuesPopFiles[index], TFObjectiveResource()->GetMvMPopFileName(), ( V_strlen( m_VoteIssuesPopFiles[index] ) - 1 ) ) == 0 )
continue;
}
KeyValues *pKeyValues = new KeyValues( "Name" );
pKeyValues->SetString( "Name", m_VoteIssuesPopFiles[index] );
pKeyValues->SetInt( "index", index );
int iId = m_pVoteParameterList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
if ( m_hIssueFont != INVALID_FONT )
{
m_pVoteParameterList->SetItemFont( iId, m_hIssueFont );
m_pVoteParameterList->SetItemFgColor( iId, m_IssueFGColor );
}
}
if ( m_pVoteParameterList->GetItemCount() == 0 )
{
KeyValues *pKeyValues = new KeyValues( "Name" );
pKeyValues->SetString( "Name", "#TF_vote_no_challenges" );
pKeyValues->SetInt( "index", 1 );
m_pVoteParameterList->AddItem( 0, pKeyValues );
pKeyValues->deleteThis();
}
}
#endif // TF_CLIENT_DLL
else
{
// User selected an issue that doesn't require a parameter - Scrambleteams, Restartgame, etc
m_bVoteButtonEnabled = true;
}
}
}
else if ( panel == m_pVoteParameterList )
{
// If this issue requires a parameter, make sure we have one selected before enabling the CallVote button
int iSelectedParam = m_pVoteParameterList->GetSelectedItem();
if ( iSelectedParam >= 0 )
{
KeyValues *pParameterKeyValues = m_pVoteParameterList->GetItemData( iSelectedParam );
if ( pParameterKeyValues )
{
const char *szParameterName = pParameterKeyValues->GetString( "Name" );
if ( szParameterName )
{
m_bVoteButtonEnabled = true;
}
}
}
}
m_pCallVoteButton->SetEnabled( m_bVoteButtonEnabled );
RefreshIssueParameters();
}
//-----------------------------------------------------------------------------
// Purpose: Updates any additional data/info on Vote issue parameters
//-----------------------------------------------------------------------------
void CVoteSetupDialog::RefreshIssueParameters()
{
// In the case of the KICK issue, we list players and show additional properties (Bot, Disconnected)
int iSelectedItem = m_pVoteSetupList->GetSelectedItem();
if ( iSelectedItem >= 0 )
{
KeyValues *pIssueKeyValues = m_pVoteSetupList->GetItemData( iSelectedItem );
const char *szName = pIssueKeyValues->GetString( "Issue" );
if ( V_stricmp( "kick", szName ) == 0 )
{
if ( m_pVoteParameterList->GetItemCount() > 0 )
{
for ( int index = 0; index < m_pVoteParameterList->GetItemCount(); index++ )
{
KeyValues *pKeyValues = m_pVoteParameterList->GetItemData( index );
if ( !pKeyValues )
continue;
int playerIndex = pKeyValues->GetInt( "index" );
player_info_t playerInfo;
if ( !engine->GetPlayerInfo( playerIndex, &playerInfo ) )
{
pKeyValues->SetString( "Properties", "Offline" );
continue;
}
pKeyValues->SetString( "Name", playerInfo.name );
if ( playerInfo.fakeplayer )
{
pKeyValues->SetString( "Properties", "Bot" );
}
else
{
pKeyValues->SetString( "Properties", "" );
}
CSteamID steamID;
C_BasePlayer* pPlayer = UTIL_PlayerByIndex( playerIndex );
if ( pPlayer && pPlayer->GetSteamID( &steamID ) && steamID.GetAccountID() != 0 )
{
CAvatarImage *pAvatar = new CAvatarImage();
pAvatar->SetAvatarSteamID( steamID );
pAvatar->SetAvatarSize( 32, 32 );
int iImageIndex = m_pImageList->AddImage( pAvatar );
pKeyValues->SetInt( "Avatar", iImageIndex );
}
m_pVoteParameterList->InvalidateItem( index );
}
m_pVoteParameterList->SetImageList( m_pImageList, false );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CVoteSetupDialog::ResetData()
{
m_bVoteButtonEnabled = false;
m_pVoteSetupList->DeleteAllItems();
m_pVoteParameterList->DeleteAllItems();
m_pComboBox->DeleteAllItems();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
DECLARE_HUDELEMENT( CHudVote );
DECLARE_HUD_MESSAGE( CHudVote, CallVoteFailed );
DECLARE_HUD_MESSAGE( CHudVote, VoteStart );
DECLARE_HUD_MESSAGE( CHudVote, VotePass );
DECLARE_HUD_MESSAGE( CHudVote, VoteFailed );
DECLARE_HUD_MESSAGE( CHudVote, VoteSetup );
//-----------------------------------------------------------------------------
// Purpose: Handles all UI for Voting
//-----------------------------------------------------------------------------
CHudVote::CHudVote( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "CHudVote" )
{
vgui::Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
#ifdef TF_CLIENT_DLL
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
SetScheme(scheme);
#endif
SetHiddenBits( 0 );
for( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
{
m_nVoteOptionCount[index] = 0;
}
m_pVoteActive = new EditablePanel( this, "VoteActive" );
m_voteBar = new VoteBarPanel( m_pVoteActive, "VoteBar" );
m_pVoteFailed = new EditablePanel( this, "VoteFailed" );
m_pVotePassed = new EditablePanel( this, "VotePassed" );
m_pCallVoteFailed = new EditablePanel( this, "CallVoteFailed" );
m_pVoteSetupDialog = new CVoteSetupDialog( pParent );
RegisterForRenderGroup( "mid" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetProportional( true );
LoadControlSettings( "Resource/UI/VoteHud.res" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::Init( void )
{
ListenForGameEvent( "vote_changed" );
ListenForGameEvent( "vote_options" );
ListenForGameEvent( "vote_cast" );
SetVoteActive( false );
m_flVoteResultCycleTime = -1;
m_flHideTime = -1;
m_bIsYesNoVote = true;
m_bPlayerVoted = false;
m_nVoteChoicesCount = 2; // Yes/No is the default
m_bShowVoteActivePanel = false;
m_iVoteCallerIdx = -1;
HOOK_HUD_MESSAGE( CHudVote, CallVoteFailed );
HOOK_HUD_MESSAGE( CHudVote, VoteStart );
HOOK_HUD_MESSAGE( CHudVote, VotePass );
HOOK_HUD_MESSAGE( CHudVote, VoteFailed );
HOOK_HUD_MESSAGE( CHudVote, VoteSetup );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::LevelInit( void )
{
SetVoteActive( false );
m_flVoteResultCycleTime = -1;
m_flHideTime = -1;
m_flPostVotedHideTime = -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CHudVote::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
if ( !IsVisible() )
return 1;
if ( !down )
return 1;
if ( !m_bVoteActive )
return 1;
if ( m_bPlayerVoted )
return 1;
if ( !m_bShowVoteActivePanel )
return 1;
int nSlot = 999;
if ( down && keynum == KEY_F1 )
{
nSlot = 1;
}
else if ( down && keynum == KEY_F2 )
{
nSlot = 2;
}
else if ( down && keynum == KEY_F3 )
{
nSlot = 3;
}
else if ( down && keynum == KEY_F4 )
{
nSlot = 4;
}
else if ( down && keynum == KEY_F5 )
{
nSlot = 5;
}
else
{
return 1;
}
// Limit key checking to the number of options
if ( nSlot > m_nVoteChoicesCount )
return 1;
char szNumber[2];
Q_snprintf( szNumber, sizeof( szNumber ), "%i", nSlot );
char szOptionName[13] = "vote option";
Q_strncat( szOptionName, szNumber, sizeof( szOptionName ), COPY_ALL_CHARACTERS );
engine->ClientCmd( szOptionName );
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Sent only to the caller
//-----------------------------------------------------------------------------
void CHudVote::MsgFunc_CallVoteFailed( bf_read &msg )
{
if ( IsPlayingDemo() )
return;
vote_create_failed_t nReason = (vote_create_failed_t)msg.ReadByte();
int nTime = msg.ReadShort();
// if we're already drawing a vote, do nothing
if ( ShouldDraw() )
return;
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
pLocalPlayer->EmitSound("Vote.Failed");
m_pVoteActive->SetVisible( false );
m_pVoteFailed->SetVisible( false );
m_pVotePassed->SetVisible( false );
m_pCallVoteFailed->SetVisible( true );
m_pVoteSetupDialog->SetVisible( false );
m_flHideTime = gpGlobals->curtime + 4.0;
char szTime[256];
wchar_t wszTime[256];
Q_snprintf( szTime, sizeof ( szTime), "%i", nTime );
g_pVGuiLocalize->ConvertANSIToUnicode( szTime, wszTime, sizeof( wszTime ) );
wchar_t wszHeaderString[512];
wchar_t *pwszHeaderString;
switch( nReason )
{
case VOTE_FAILED_GENERIC:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed" );
break;
case VOTE_FAILED_TRANSITIONING_PLAYERS:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_transition_vote" );
break;
case VOTE_FAILED_RATE_EXCEEDED:
g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_failed_vote_spam" ), 1, wszTime );
pwszHeaderString = wszHeaderString;
m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString );
break;
case VOTE_FAILED_ISSUE_DISABLED:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_disabled_issue" );
break;
case VOTE_FAILED_MAP_NOT_FOUND:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_map_not_found" );
break;
case VOTE_FAILED_MAP_NOT_VALID:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_map_not_valid" );
break;
case VOTE_FAILED_MAP_NAME_REQUIRED:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_map_name_required" );
break;
case VOTE_FAILED_FAILED_RECENTLY:
g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_failed_recently" ), 1, wszTime );
pwszHeaderString = wszHeaderString;
m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString );
break;
case VOTE_FAILED_TEAM_CANT_CALL:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_team_cant_call" );
break;
case VOTE_FAILED_WAITINGFORPLAYERS:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_waitingforplayers" );
break;
case VOTE_FAILED_CANNOT_KICK_ADMIN:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_cannot_kick_admin" );
break;
case VOTE_FAILED_SCRAMBLE_IN_PROGRESS:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_scramble_in_prog" );
break;
case VOTE_FAILED_SPECTATOR:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_spectator" );
break;
case VOTE_FAILED_NEXTLEVEL_SET:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_nextlevel_set" );
break;
case VOTE_FAILED_CANNOT_KICK_FOR_TIME:
g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_failed_cannot_kick_for_time" ), 1, wszTime );
pwszHeaderString = wszHeaderString;
m_pCallVoteFailed->SetDialogVariable( "FailedReason", pwszHeaderString );
break;
case VOTE_FAILED_CANNOT_KICK_DURING_ROUND:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_round_active" );
break;
case VOTE_FAILED_MODIFICATION_ALREADY_ACTIVE:
m_pCallVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_event_already_active" );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose: Sent to everyone
//-----------------------------------------------------------------------------
void CHudVote::MsgFunc_VoteFailed( bf_read &msg )
{
if ( IsPlayingDemo() )
return;
int iTeam = msg.ReadByte();
vote_create_failed_t nReason = (vote_create_failed_t)msg.ReadByte();
// Visibility of this error is handled by OnThink()
SetVoteActive( false );
m_bVotePassed = false;
m_flVoteResultCycleTime = gpGlobals->curtime + 2;
m_flHideTime = gpGlobals->curtime + 5;
switch ( nReason )
{
case VOTE_FAILED_GENERIC:
m_pVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed" );
break;
case VOTE_FAILED_YES_MUST_EXCEED_NO:
m_pVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_yesno" );
break;
case VOTE_FAILED_QUORUM_FAILURE:
m_pVoteFailed->SetControlString( "FailedReason", "#GameUI_vote_failed_quorum" );
break;
}
// driller: this event has no listeners - will eventually hook into stats
IGameEvent *event = gameeventmanager->CreateEvent( "vote_failed" );
if ( event )
{
event->SetInt( "team", iTeam );
gameeventmanager->FireEventClientSide( event );
}
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
pLocalPlayer->EmitSound("Vote.Failed");
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::MsgFunc_VoteStart( bf_read &msg )
{
if ( IsPlayingDemo() )
return;
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
// Is this a team-only vote?
int iTeam = msg.ReadByte();
uint8 invalidTeam = (uint8)TEAM_INVALID;
if ( iTeam != invalidTeam && iTeam != pLocalPlayer->GetTeamNumber() )
return;
// Entity calling the vote
bool bShowNotif = cl_vote_ui_show_notification.GetBool();
const char *pszCallerName = "Server";
m_iVoteCallerIdx = msg.ReadByte();
if ( m_iVoteCallerIdx != DEDICATED_SERVER )
{
C_BasePlayer *pVoteCaller = UTIL_PlayerByIndex( m_iVoteCallerIdx );
if ( pVoteCaller )
{
pszCallerName = pVoteCaller->GetPlayerName();
// Don't show a notification to the caller
if ( pVoteCaller == pLocalPlayer )
{
bShowNotif = false;
}
}
else
{
// Caller invalid for some reason
pszCallerName = "Player";
}
}
// DisplayString
char szIssue[256];
szIssue[0] = 0;
msg.ReadString( szIssue, sizeof(szIssue) );
// DetailString
char szParam1[256];
szParam1[0] = 0;
msg.ReadString( szParam1, sizeof(szParam1) );
m_bIsYesNoVote = msg.ReadByte();
SetVoteActive( true );
m_pVoteFailed->SetVisible( false );
m_pVotePassed->SetVisible( false );
m_pCallVoteFailed->SetVisible( false );
m_pVoteSetupDialog->SetVisible( false );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "HideVoteBackgrounds" );
m_voteBar->SetVisible( m_bIsYesNoVote );
// There will always be at least two choices...
m_pVoteActive->SetControlVisible( "LabelOption1", true );
m_pVoteActive->SetControlVisible( "LabelOption2", true );
// ...sometimes more
m_pVoteActive->SetControlVisible( "LabelOption3", m_VoteSetupChoices.Count() > 2 ? true : false );
m_pVoteActive->SetControlVisible( "Option3Background_Selected", m_VoteSetupChoices.Count() > 2 ? true : false );
m_pVoteActive->SetControlVisible( "LabelOption4", m_VoteSetupChoices.Count() > 3 ? true : false );
m_pVoteActive->SetControlVisible( "Option4Background_Selected", m_VoteSetupChoices.Count() > 3 ? true : false );
m_pVoteActive->SetControlVisible( "LabelOption5", m_VoteSetupChoices.Count() > 4 ? true : false );
m_pVoteActive->SetControlVisible( "Option5Background_Selected", m_VoteSetupChoices.Count() > 4 ? true : false );
m_pVoteActive->SetControlVisible( "VoteCountLabel", m_bIsYesNoVote );
m_pVoteActive->SetControlVisible( "Option1CountLabel", m_bIsYesNoVote );
m_pVoteActive->SetControlVisible( "Option2CountLabel", m_bIsYesNoVote );
m_pVoteActive->SetControlVisible( "Divider1", m_bIsYesNoVote );
m_pVoteActive->SetControlVisible( "Divider2", m_bIsYesNoVote );
// Display vote caller's name
wchar_t wszCallerName[MAX_PLAYER_NAME_LENGTH];
wchar_t wszHeaderString[512];
wchar_t *pwszHeaderString;
// Player
g_pVGuiLocalize->ConvertANSIToUnicode( pszCallerName, wszCallerName, sizeof( wszCallerName ) );
// String
g_pVGuiLocalize->ConstructString( wszHeaderString, sizeof(wszHeaderString), g_pVGuiLocalize->Find( "#GameUI_vote_header" ), 1, wszCallerName );
pwszHeaderString = wszHeaderString;
// Final
m_pVoteActive->SetDialogVariable( "header", pwszHeaderString );
// Display the Issue
wchar_t *pwcParam;
wchar_t wcParam[128];
wchar_t *pwcIssue;
wchar_t wcIssue[512];
if ( Q_strlen( szParam1 ) > 0 )
{
if ( szParam1[0] == '#' )
{
// localize it
pwcParam = g_pVGuiLocalize->Find( szParam1 );
}
else
{
// convert to wchar
g_pVGuiLocalize->ConvertANSIToUnicode( szParam1, wcParam, sizeof( wcParam ) );
pwcParam = wcParam;
}
g_pVGuiLocalize->ConstructString( wcIssue, sizeof(wcIssue), g_pVGuiLocalize->Find( szIssue ), 1, pwcParam );
pwcIssue = wcIssue;
}
else
{
// no param, just localize the issue
pwcIssue = g_pVGuiLocalize->Find( szIssue );
}
m_pVoteActive->SetDialogVariable( "voteissue", pwcIssue );
// Figure out which UI
if ( m_bIsYesNoVote )
{
// YES / NO UI
wchar_t wzFinal[512] = L"";
wchar_t *pszText = g_pVGuiLocalize->Find( "#GameUI_vote_yes_pc_instruction" );
if ( pszText )
{
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) );
if ( m_pVoteActive )
m_pVoteActive->SetControlString( "LabelOption1", wzFinal );
}
pszText = g_pVGuiLocalize->Find( "#GameUI_vote_no_pc_instruction" );
if ( pszText )
{
UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) );
if ( m_pVoteActive )
m_pVoteActive->SetControlString( "LabelOption2", wzFinal );
}
}
else
{
// GENERAL UI
if ( m_VoteSetupChoices.Count() )
{
// Clear the labels to prevent previous options from being displayed,
// such as when there are fewer options this vote than the previous
for ( int iIndex = 0; iIndex < MAX_VOTE_OPTIONS; iIndex++ )
{
// Construct Label name
char szOptionNum[2];
Q_snprintf( szOptionNum, sizeof( szOptionNum ), "%i", iIndex + 1 );
char szVoteOptionCount[13] = "LabelOption";
Q_strncat( szVoteOptionCount, szOptionNum, sizeof( szVoteOptionCount ), COPY_ALL_CHARACTERS );
m_pVoteActive->SetControlString( szVoteOptionCount, "" );
}
// Set us up the vote
for ( int iIndex = 0; iIndex < m_nVoteChoicesCount; iIndex++ )
{
// Construct Option name
const char *pszChoiceName = m_VoteSetupChoices[iIndex];
char szOptionName[256];
Q_snprintf( szOptionName, sizeof( szOptionName ), "F%i. ", iIndex + 1 );
Q_strncat( szOptionName, pszChoiceName, sizeof( szOptionName ), COPY_ALL_CHARACTERS );
// Construct Label name
char szOptionNum[2];
Q_snprintf( szOptionNum, sizeof( szOptionNum ), "%i", iIndex + 1 );
char szVoteOptionCount[13] = "LabelOption";
Q_strncat( szVoteOptionCount, szOptionNum, sizeof( szVoteOptionCount ), COPY_ALL_CHARACTERS );
// Set Label string
if ( m_pVoteActive )
{
m_pVoteActive->SetControlString( szVoteOptionCount, szOptionName );
}
}
}
}
IGameEvent *event = gameeventmanager->CreateEvent( "vote_started" );
if ( event )
{
event->SetString( "issue", szIssue );
event->SetString( "param1", szParam1 );
event->SetInt( "team", iTeam );
event->SetInt( "initiator", m_iVoteCallerIdx );
gameeventmanager->FireEventClientSide( event );
}
#ifdef TF_CLIENT_DLL
if ( bShowNotif )
{
NotificationQueue_Add( new CTFVoteNotification( pszCallerName ) );
}
else
{
ShowVoteUI();
}
#else
ShowVoteUI();
#endif // TF_CLIENT_DLL
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::MsgFunc_VotePass( bf_read &msg )
{
if ( IsPlayingDemo() )
return;
int iTeam = msg.ReadByte();
// Passed string
char szResult[256];
szResult[0] = 0;
msg.ReadString( szResult, sizeof(szResult) );
// Detail string
char szParam1[256];
szParam1[0] = 0;
msg.ReadString( szParam1, sizeof(szParam1) );
// Localize
wchar_t *pwcParam;
wchar_t wcParam[128];
wchar_t *pwcIssue;
wchar_t wcIssue[512];
if ( Q_strlen( szParam1 ) > 0 )
{
if ( szParam1[0] == '#' )
{
pwcParam = g_pVGuiLocalize->Find( szParam1 );
}
else
{
// Convert to wchar
g_pVGuiLocalize->ConvertANSIToUnicode( szParam1, wcParam, sizeof( wcParam ) );
pwcParam = wcParam;
}
g_pVGuiLocalize->ConstructString( wcIssue, sizeof(wcIssue), g_pVGuiLocalize->Find( szResult ), 1, pwcParam );
pwcIssue = wcIssue;
}
else
{
// No param, just localize the result
pwcIssue = g_pVGuiLocalize->Find( szResult );
}
m_pVotePassed->SetDialogVariable( "passedresult", pwcIssue );
SetVoteActive( false );
m_bVotePassed = true;
m_flVoteResultCycleTime = gpGlobals->curtime + 2;
m_flHideTime = gpGlobals->curtime + 5;
// driller: this event has no listeners - will eventually hook into stats
IGameEvent *event = gameeventmanager->CreateEvent( "vote_passed" );
if ( event )
{
event->SetString( "details", szResult );
event->SetString( "param1", szParam1 );
event->SetInt( "team", iTeam );
gameeventmanager->FireEventClientSide( event );
}
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
pLocalPlayer->EmitSound( "Vote.Passed" );
}
//-----------------------------------------------------------------------------
// Purpose: Creates a UI for Vote Issue selection
//-----------------------------------------------------------------------------
void CHudVote::MsgFunc_VoteSetup( bf_read &msg )
{
if ( IsPlayingDemo() )
return;
m_pVoteActive->SetVisible( false );
m_pVoteFailed->SetVisible( false );
m_pVotePassed->SetVisible( false );
m_pCallVoteFailed->SetVisible( false );
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
// Load up the list of Vote Issues
m_VoteSetupIssues.RemoveAll();
int nIssueCount = msg.ReadByte();
if ( nIssueCount )
{
for ( int index = 0; index < nIssueCount; index++ )
{
char szIssue[256];
msg.ReadString( szIssue, sizeof(szIssue) );
if ( !m_VoteSetupIssues.HasElement( szIssue ) )
{
// Send it over to the listpanel
m_VoteSetupIssues.CopyAndAddToTail( szIssue );
}
}
}
else
{
m_VoteSetupIssues.CopyAndAddToTail( "Voting disabled on this Server" );
}
m_pVoteSetupDialog->AddVoteIssues( m_VoteSetupIssues );
// Load up the list of Vote Issue Parameters
m_VoteSetupMapCycle.RemoveAll();
// Use the appropriate stringtable for maps based on gamemode
bool bMvM = false;
INetworkStringTable *pStringTable = g_pStringTableServerMapCycle;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
bMvM = true;
pStringTable = g_pStringTableServerMapCycleMvM;
}
#endif // TF_CLIENT_DLL
if ( pStringTable )
{
int index = bMvM ? pStringTable->FindStringIndex( "ServerMapCycleMvM" ) : pStringTable->FindStringIndex( "ServerMapCycle" );
if ( index != ::INVALID_STRING_INDEX )
{
int nLength = 0;
const char *pszMapCycle = (const char *)pStringTable->GetStringUserData( index, &nLength );
if ( pszMapCycle && pszMapCycle[0] )
{
if ( pszMapCycle && nLength )
{
V_SplitString( pszMapCycle, "\n", m_VoteSetupMapCycle );
}
// Alphabetize
if ( m_VoteSetupMapCycle.Count() )
{
m_VoteSetupMapCycle.Sort( m_VoteSetupMapCycle.SortFunc );
}
}
}
}
#ifdef TF_CLIENT_DLL
m_VoteSetupPopFiles.RemoveAll();
if ( g_pStringTableServerPopFiles )
{
int index = g_pStringTableServerPopFiles->FindStringIndex( "ServerPopFiles" );
if ( index != ::INVALID_STRING_INDEX )
{
int nLength = 0;
const char *pszPopFiles = (const char *)g_pStringTableServerPopFiles->GetStringUserData( index, &nLength );
if ( pszPopFiles && pszPopFiles[0] )
{
if ( pszPopFiles && nLength )
{
V_SplitString( pszPopFiles, "\n", m_VoteSetupPopFiles );
}
// Alphabetize
if ( m_VoteSetupPopFiles.Count() )
{
m_VoteSetupPopFiles.Sort( m_VoteSetupPopFiles.SortFunc );
}
}
}
}
#endif // TF_CLIENT_DLL
// Now send any data we gathered over to the listpanel
PropagateOptionParameters();
m_pVoteSetupDialog->Activate();
m_pVoteSetupDialog->SetVisible( true );
}
//-----------------------------------------------------------------------------
// Purpose: Propagate vote option parameters to the Issue Parameters list
//-----------------------------------------------------------------------------
void CHudVote::PropagateOptionParameters( void )
{
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
m_pVoteSetupDialog->AddVoteIssueParams_MapCycle( m_VoteSetupMapCycle );
#ifdef TF_CLIENT_DLL
m_pVoteSetupDialog->AddVoteIssueParams_PopFiles( m_VoteSetupPopFiles );
#endif // TF_CLIENT_DLL
// Insert future issue param data containers here
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::FireGameEvent( IGameEvent *event )
{
const char *eventName = event->GetName();
if ( !eventName )
return;
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pLocalPlayer )
return;
if( FStrEq( eventName, "vote_changed" ) )
{
for ( int index = 0; index < MAX_VOTE_OPTIONS; index++ )
{
char szOption[2];
Q_snprintf( szOption, sizeof( szOption ), "%i", index + 1 );
char szVoteOptionCount[13] = "vote_option";
Q_strncat( szVoteOptionCount, szOption, sizeof( szVoteOptionCount ), COPY_ALL_CHARACTERS );
m_nVoteOptionCount[index] = event->GetInt( szVoteOptionCount );
}
m_nPotentialVotes = event->GetInt( "potentialVotes" );
}
else if ( FStrEq( eventName, "vote_options" ) )
{
m_VoteSetupChoices.RemoveAll();
m_nVoteChoicesCount = event->GetInt( "count" );
for ( int iIndex = 0; iIndex < m_nVoteChoicesCount; iIndex++ )
{
char szNumber[2];
Q_snprintf( szNumber, sizeof( szNumber ), "%i", iIndex + 1 );
char szOptionName[8] = "option";
Q_strncat( szOptionName, szNumber, sizeof( szOptionName ), COPY_ALL_CHARACTERS );
const char *pszOptionName = event->GetString( szOptionName );
m_VoteSetupChoices.CopyAndAddToTail( pszOptionName );
}
}
else if ( FStrEq( eventName, "vote_cast" ) )
{
int iPlayer = event->GetInt( "entityid" );
C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayer );
if ( pPlayer != pLocalPlayer )
return;
int vote_option = event->GetInt( "vote_option", TEAM_UNASSIGNED );
if( vote_option == VOTE_OPTION1 )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "PulseOption1" );
}
else if( vote_option == VOTE_OPTION2 )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "PulseOption2" );
}
else if( vote_option == VOTE_OPTION3 )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "PulseOption3" );
}
else if( vote_option == VOTE_OPTION4 )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "PulseOption4" );
}
else if( vote_option == VOTE_OPTION5 )
{
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "PulseOption5" );
}
m_bPlayerVoted = true;
bool bForceActive = false;
#ifdef TF_CLIENT_DLL
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
if ( m_iVoteCallerIdx == GetLocalPlayerIndex() )
{
bForceActive = true;
}
}
#endif // TF_CLIENT_DLL
if ( !cl_vote_ui_active_after_voting.GetBool() && !bForceActive )
{
m_flPostVotedHideTime = gpGlobals->curtime + 1.5f;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::OnThink()
{
// We delay hiding the menu after we cast a vote
if ( m_bPlayerVoted && m_flPostVotedHideTime > 0 && m_flPostVotedHideTime < gpGlobals->curtime )
{
m_pVoteActive->SetVisible( false );
m_bShowVoteActivePanel = false;
m_flPostVotedHideTime = -1;
}
if ( m_flVoteResultCycleTime > 0 && m_flVoteResultCycleTime < gpGlobals->curtime )
{
m_pVoteActive->SetVisible( false );
m_pVoteFailed->SetVisible( !m_bVotePassed );
m_pVotePassed->SetVisible( m_bVotePassed );
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pVoteActive, "HideVoteBackgrounds" );
m_flVoteResultCycleTime = -1;
m_bPlayerVoted = false;
m_bVoteActive = false;
m_bShowVoteActivePanel = false;
m_iVoteCallerIdx = -1;
}
if ( m_bVoteActive )
{
// driller: Need to rewrite this to handle all vote types (Yes/No and General)
if ( m_bIsYesNoVote && m_pVoteActive )
{
char szYesCount[512] = "";
Q_snprintf( szYesCount, 512, "%d", m_nVoteOptionCount[0] );
char szNoCount[512] = "";
Q_snprintf( szNoCount, 512, "%d", m_nVoteOptionCount[1] );
m_pVoteActive->SetControlString( "Option1CountLabel", szYesCount );
m_pVoteActive->SetControlString( "Option2CountLabel", szNoCount );
}
if ( !m_pVoteActive->IsVisible() && m_bShowVoteActivePanel )
{
m_pVoteActive->SetVisible( true );
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
if ( pLocalPlayer )
{
pLocalPlayer->EmitSound("Vote.Created");
}
}
}
BaseClass::OnThink();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudVote::ShouldDraw( void )
{
return ( m_bVoteActive || m_flHideTime > gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudVote::IsPlayingDemo() const
{
return engine->IsPlayingDemo();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::SetVoteActive( bool bActive )
{
m_bVoteActive = bActive;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudVote::ShowVoteUI( void )
{
m_bShowVoteActivePanel = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CHudVote::IsVoteUIActive( void )
{
return m_bShowVoteActivePanel;
}