2
0
mirror of https://github.com/FWGS/hlsdk-xash3d synced 2024-11-26 03:39:13 +01:00
hlsdk-xash3d/cl_dll/vgui_ClassMenu.cpp
Roman Chistokhodov ba2cab60df
Get VGUI back (optionally) (#194)
* Get VGUI back (optionally)

* Add some missing VGUI invocations

* Update CMakeLists.txt to build with vgui for Windows

* Move windows.h inclusions only to those places where it's really needed

* Try fix mingw build

* Update hud_spectator

* Merge nekonomicon's vgui branch

* Don't include vgui panel and app in cdll_int.cpp if vgui is real

* Deduplicate scoreboard global variables

* Add options to prefer non-vgui motd and scoreboard when vgui is enabled

* Add vgui-dev as a submodule. Add building vith vgui to CI

* Fix artifact uploading

* Don't use global variable when not necessary

* char* to const char* in CMenuHandler_StringCommand constructor

* Fix 'format string is not a literal string' warnings

* Fix 'always evaluate to true' warnings

* Team Fortress classes to const char*

* CreateCommandMenu accepts const char*

* Fix printf formats. Turn some unsigned longs into unsigned ints since they use only 32 bits anyway

* Explicit assignment result as condition

* Prevent memory leak on menu reading

* Localize button text

* Create FileInputStream on stack avoiding the leak

* Remove Servers Browser code

* Arrow file names to const char*

* Fix assignment to the wrong variable
2021-10-27 01:35:11 +00:00

437 lines
13 KiB
C++

//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: TFC Class Menu
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================
#include "VGUI_Font.h"
#include <VGUI_TextImage.h>
#include "hud.h"
#include "cl_util.h"
#include "camera.h"
#include "kbutton.h"
#include "cvardef.h"
#include "usercmd.h"
#include "const.h"
#include "camera.h"
#include "in_defs.h"
#include "parsemsg.h"
#include "vgui_int.h"
#include "vgui_TeamFortressViewport.h"
// Class Menu Dimensions
#define CLASSMENU_TITLE_X XRES(40)
#define CLASSMENU_TITLE_Y YRES(32)
#define CLASSMENU_TOPLEFT_BUTTON_X XRES(40)
#define CLASSMENU_TOPLEFT_BUTTON_Y YRES(80)
#define CLASSMENU_BUTTON_SIZE_X XRES(124)
#define CLASSMENU_BUTTON_SIZE_Y YRES(24)
#define CLASSMENU_BUTTON_SPACER_Y YRES(8)
#define CLASSMENU_WINDOW_X XRES(176)
#define CLASSMENU_WINDOW_Y YRES(80)
#define CLASSMENU_WINDOW_SIZE_X XRES(424)
#define CLASSMENU_WINDOW_SIZE_Y YRES(312)
#define CLASSMENU_WINDOW_TEXT_X XRES(150)
#define CLASSMENU_WINDOW_TEXT_Y YRES(80)
#define CLASSMENU_WINDOW_NAME_X XRES(150)
#define CLASSMENU_WINDOW_NAME_Y YRES(8)
#define CLASSMENU_WINDOW_PLAYERS_Y YRES(42)
// Creation
CClassMenuPanel::CClassMenuPanel( int iTrans, int iRemoveMe, int x, int y, int wide, int tall ) : CMenuPanel( iTrans, iRemoveMe, x, y, wide, tall )
{
// don't show class graphics at below 640x480 resolution
bool bShowClassGraphic = true;
if( ScreenWidth < 640 )
{
bShowClassGraphic = false;
}
memset( m_pClassImages, 0, sizeof(m_pClassImages) );
// Get the scheme used for the Titles
CSchemeManager *pSchemes = gViewPort->GetSchemeManager();
// schemes
SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" );
SchemeHandle_t hClassWindowText = pSchemes->getSchemeHandle( "Briefing Text" );
// color schemes
int r, g, b, a;
// Create the title
Label *pLabel = new Label( "", CLASSMENU_TITLE_X, CLASSMENU_TITLE_Y );
pLabel->setParent( this );
pLabel->setFont( pSchemes->getFont( hTitleScheme ) );
pSchemes->getFgColor( hTitleScheme, r, g, b, a );
pLabel->setFgColor( r, g, b, a );
pSchemes->getBgColor( hTitleScheme, r, g, b, a );
pLabel->setBgColor( r, g, b, a );
pLabel->setContentAlignment( vgui::Label::a_west );
pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString( "#Title_SelectYourClass" ) );
// Create the Scroll panel
m_pScrollPanel = new CTFScrollPanel( CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y );
m_pScrollPanel->setParent( this );
//force the scrollbars on, so after the validate clientClip will be smaller
m_pScrollPanel->setScrollBarAutoVisible( false, false );
m_pScrollPanel->setScrollBarVisible( true, true );
m_pScrollPanel->setBorder( new LineBorder( Color( 255 * 0.7, 170 * 0.7, 0, 0 ) ) );
m_pScrollPanel->validate();
int clientWide=m_pScrollPanel->getClient()->getWide();
//turn scrollpanel back into auto show scrollbar mode and validate
m_pScrollPanel->setScrollBarAutoVisible( false, true );
m_pScrollPanel->setScrollBarVisible( false, false );
m_pScrollPanel->validate();
// Create the Class buttons
#ifdef _TFC
for( int i = 0; i <= PC_RANDOM; i++ )
{
char sz[256];
int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y + ( ( CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y ) * i );
ActionSignal *pASignal = new CMenuHandler_StringCommandClassSelect( sTFClassSelection[i], true );
// Class button
sprintf( sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ) );
m_pButtons[i] = new ClassButton( i, sz, CLASSMENU_TOPLEFT_BUTTON_X, iYPos, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y, true );
// RandomPC uses '0'
if( i >= 1 && i <= 9 )
{
sprintf( sz, "%d", i );
}
else
{
strcpy( sz, "0" );
}
m_pButtons[i]->setBoundKey( sz[0] );
m_pButtons[i]->setContentAlignment( vgui::Label::a_west );
m_pButtons[i]->addActionSignal( pASignal );
m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) );
m_pButtons[i]->setParent( this );
// Create the Class Info Window
// m_pClassInfoPanel[i] = new CTransparentPanel( 255, CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y );
m_pClassInfoPanel[i] = new CTransparentPanel( 255, 0, 0, clientWide, CLASSMENU_WINDOW_SIZE_Y );
m_pClassInfoPanel[i]->setParent( m_pScrollPanel->getClient() );
// m_pClassInfoPanel[i]->setVisible( false );
// don't show class pic in lower resolutions
int textOffs = XRES( 8 );
if( bShowClassGraphic )
{
textOffs = CLASSMENU_WINDOW_NAME_X;
}
// Create the Class Name Label
sprintf( sz, "#Title_%s", sTFClassSelection[i] );
char *localName=CHudTextMessage::BufferedLocaliseTextString( sz );
Label *pNameLabel = new Label( "", textOffs, CLASSMENU_WINDOW_NAME_Y );
pNameLabel->setFont( pSchemes->getFont( hTitleScheme ) );
pNameLabel->setParent( m_pClassInfoPanel[i] );
pSchemes->getFgColor( hTitleScheme, r, g, b, a );
pNameLabel->setFgColor( r, g, b, a );
pSchemes->getBgColor( hTitleScheme, r, g, b, a );
pNameLabel->setBgColor( r, g, b, a );
pNameLabel->setContentAlignment( vgui::Label::a_west );
// pNameLabel->setBorder( new LineBorder() );
pNameLabel->setText( "%s", localName);
// Create the Class Image
if( bShowClassGraphic )
{
for( int team = 0; team < 2; team++ )
{
if( team == 1 )
{
sprintf( sz, "%sred", sTFClassSelection[i] );
}
else
{
sprintf( sz, "%sblue", sTFClassSelection[i] );
}
m_pClassImages[team][i] = new CImageLabel( sz, 0, 0, CLASSMENU_WINDOW_TEXT_X, CLASSMENU_WINDOW_TEXT_Y );
CImageLabel *pLabel = m_pClassImages[team][i];
pLabel->setParent( m_pClassInfoPanel[i] );
// pLabel->setBorder( new LineBorder() );
if( team != 1 )
{
pLabel->setVisible( false );
}
// Reposition it based upon it's size
int xOut, yOut;
pNameLabel->getTextSize( xOut, yOut );
pLabel->setPos( ( CLASSMENU_WINDOW_TEXT_X - pLabel->getWide() ) / 2, yOut / 2 );
}
}
// Create the Player count string
gHUD.m_TextMessage.LocaliseTextString( "#Title_CurrentlyOnYourTeam", m_sPlayersOnTeamString, STRLENMAX_PLAYERSONTEAM );
m_pPlayers[i] = new Label( "", textOffs, CLASSMENU_WINDOW_PLAYERS_Y );
m_pPlayers[i]->setParent( m_pClassInfoPanel[i] );
m_pPlayers[i]->setBgColor( 0, 0, 0, 255 );
m_pPlayers[i]->setContentAlignment( vgui::Label::a_west );
m_pPlayers[i]->setFont( pSchemes->getFont( hClassWindowText ) );
// Open up the Class Briefing File
sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]);
char *cText = "Class Description not available.";
char *pfile = (char *)gEngfuncs.COM_LoadFile( sz, 5, NULL );
if( pfile )
{
cText = pfile;
}
// Create the Text info window
TextPanel *pTextWindow = new TextPanel( cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, ( CLASSMENU_WINDOW_SIZE_X - textOffs ) - 5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y );
pTextWindow->setParent( m_pClassInfoPanel[i] );
pTextWindow->setFont( pSchemes->getFont( hClassWindowText ) );
pSchemes->getFgColor( hClassWindowText, r, g, b, a );
pTextWindow->setFgColor( r, g, b, a );
pSchemes->getBgColor( hClassWindowText, r, g, b, a );
pTextWindow->setBgColor( r, g, b, a );
// Resize the Info panel to fit it all
int wide,tall;
pTextWindow->getTextImage()->getTextSizeWrapped( wide, tall );
pTextWindow->setSize( wide, tall );
int xx, yy;
pTextWindow->getPos( xx, yy );
int maxX = xx + wide;
int maxY = yy + tall;
//check to see if the image goes lower than the text
//just use the red teams [0] images
if( m_pClassImages[0][i] != null )
{
m_pClassImages[0][i]->getPos( xx, yy );
if( ( yy + m_pClassImages[0][i]->getTall() ) > maxY )
{
maxY = yy + m_pClassImages[0][i]->getTall();
}
}
m_pClassInfoPanel[i]->setSize( maxX , maxY );
if( pfile )
gEngfuncs.COM_FreeFile( pfile );
// m_pClassInfoPanel[i]->setBorder( new LineBorder() );
}
#endif
// Create the Cancel button
m_pCancelButton = new CommandButton( gHUD.m_TextMessage.BufferedLocaliseTextString( "#Menu_Cancel" ), CLASSMENU_TOPLEFT_BUTTON_X, 0, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y );
m_pCancelButton->setParent( this );
m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow( HIDE_TEXTWINDOW ) );
m_iCurrentInfo = 0;
}
// Update
void CClassMenuPanel::Update()
{
// Don't allow the player to join a team if they're not in a team
if( !g_iTeamNumber )
return;
int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y;
// Cycle through the rest of the buttons
#ifdef _TFC
for( int i = 0; i <= PC_RANDOM; i++ )
{
bool bCivilian = ( gViewPort->GetValidClasses( g_iTeamNumber ) == -1 );
if( bCivilian )
{
// If this team can only be civilians, only the civilian button's visible
if( i == 0 )
{
m_pButtons[0]->setVisible( true );
SetActiveInfo( 0 );
iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y;
}
else
{
m_pButtons[i]->setVisible( false );
}
}
else
{
if( m_pButtons[i]->IsNotValid() || i == 0 )
{
m_pButtons[i]->setVisible( false );
}
else
{
m_pButtons[i]->setVisible( true );
m_pButtons[i]->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos );
iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y;
// Start with the first option up
if( !m_iCurrentInfo )
SetActiveInfo( i );
}
}
// Now count the number of teammembers of this class
int iTotal = 0;
for( int j = 1; j < MAX_PLAYERS; j++ )
{
if( g_PlayerInfoList[j].name == 0 )
continue; // empty player slot, skip
if( g_PlayerExtraInfo[j].teamname[0] == 0 )
continue; // skip over players who are not in a team
if( g_PlayerInfoList[j].thisplayer )
continue; // skip this player
if( g_PlayerExtraInfo[j].teamnumber != g_iTeamNumber )
continue; // skip over players in other teams
// If this team is forced to be civilians, just count the number of teammates
if( g_PlayerExtraInfo[j].playerclass != i && !bCivilian )
continue;
iTotal++;
}
char sz[256];
sprintf( sz, m_sPlayersOnTeamString, iTotal );
m_pPlayers[i]->setText( "%s", sz );
// Set the text color to the teamcolor
m_pPlayers[i]->setFgColor( iTeamColors[g_iTeamNumber % iNumberOfTeamColors][0],
iTeamColors[g_iTeamNumber % iNumberOfTeamColors][1],
iTeamColors[g_iTeamNumber % iNumberOfTeamColors][2],
0 );
// set the graphic to be the team pick
for( int team = 0; team < MAX_TEAMS; team++ )
{
// unset all the other images
if( m_pClassImages[team][i] )
{
m_pClassImages[team][i]->setVisible( false );
}
// set the current team image
if( m_pClassImages[g_iTeamNumber - 1][i] != 0 )
{
m_pClassImages[g_iTeamNumber - 1][i]->setVisible( true );
}
else if( m_pClassImages[0][i] )
{
m_pClassImages[0][i]->setVisible( true );
}
}
}
#endif
// If the player already has a class, make the cancel button visible
if( g_iPlayerClass )
{
m_pCancelButton->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos );
m_pCancelButton->setVisible( true );
}
else
{
m_pCancelButton->setVisible( false );
}
}
//======================================
// Key inputs for the Class Menu
bool CClassMenuPanel::SlotInput( int iSlot )
{
if( ( iSlot < 0 ) || ( iSlot > 9 ) )
return false;
if( !m_pButtons[iSlot] )
return false;
// Is the button pushable? (0 is special case)
if( iSlot == 0 )
{
// Selects Civilian and RandomPC
if( gViewPort->GetValidClasses( g_iTeamNumber ) == -1 )
{
m_pButtons[0]->fireActionSignal();
return true;
}
// Select RandomPC
iSlot = 10;
}
if( !( m_pButtons[iSlot]->IsNotValid() ) )
{
m_pButtons[iSlot]->fireActionSignal();
return true;
}
return false;
}
//======================================
// Update the Class menu before opening it
void CClassMenuPanel::Open( void )
{
Update();
CMenuPanel::Open();
}
//-----------------------------------------------------------------------------
// Purpose: Called each time a new level is started.
//-----------------------------------------------------------------------------
void CClassMenuPanel::Initialize( void )
{
setVisible( false );
m_pScrollPanel->setScrollValue( 0, 0 );
}
//======================================
// Mouse is over a class button, bring up the class info
void CClassMenuPanel::SetActiveInfo( int iInput )
{
// Remove all the Info panels and bring up the specified one
#ifdef _TFC
for( int i = 0; i <= PC_RANDOM; i++ )
{
m_pButtons[i]->setArmed( false );
m_pClassInfoPanel[i]->setVisible( false );
}
if( iInput > PC_RANDOM || iInput < 0 )
#endif
iInput = 0;
m_pButtons[iInput]->setArmed( true );
m_pClassInfoPanel[iInput]->setVisible( true );
m_iCurrentInfo = iInput;
m_pScrollPanel->setScrollValue( 0, 0 );
m_pScrollPanel->validate();
}