mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-06-06 10:52:13 +03:00
game_menu entity and associated CHudMenu changes
This commit is contained in:
parent
985ebc0dbb
commit
cdafc1278e
@ -37,6 +37,9 @@ char g_szPrelocalisedMenuString[MAX_MENU_STRING];
|
||||
|
||||
DECLARE_HUDELEMENT( CHudMenu );
|
||||
DECLARE_HUD_MESSAGE( CHudMenu, ShowMenu );
|
||||
#ifdef MAPBASE
|
||||
DECLARE_HUD_MESSAGE( CHudMenu, ShowMenuComplex );
|
||||
#endif
|
||||
|
||||
//
|
||||
//-----------------------------------------------------
|
||||
@ -71,6 +74,9 @@ CHudMenu::CHudMenu( const char *pElementName ) :
|
||||
void CHudMenu::Init( void )
|
||||
{
|
||||
HOOK_HUD_MESSAGE( CHudMenu, ShowMenu );
|
||||
#ifdef MAPBASE
|
||||
HOOK_HUD_MESSAGE( CHudMenu, ShowMenuComplex );
|
||||
#endif
|
||||
|
||||
m_bMenuTakesInput = false;
|
||||
m_bMenuDisplayed = false;
|
||||
@ -81,6 +87,24 @@ void CHudMenu::Init( void )
|
||||
Reset();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudMenu::LevelInit()
|
||||
{
|
||||
CHudElement::LevelInit();
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (m_bMapDefinedMenu)
|
||||
{
|
||||
// Fixes menu retaining on level change/reload
|
||||
// TODO: Would non-map menus benefit from this as well?
|
||||
m_bMenuTakesInput = false;
|
||||
m_bMenuDisplayed = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -114,7 +138,11 @@ void CHudMenu::OnThink()
|
||||
float flSelectionTimeout = MENU_SELECTION_TIMEOUT;
|
||||
|
||||
// If we've been open for a while without input, hide
|
||||
#ifdef MAPBASE
|
||||
if ( m_bMenuDisplayed && ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout && !m_bMapDefinedMenu ) )
|
||||
#else
|
||||
if ( m_bMenuDisplayed && ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout ) )
|
||||
#endif
|
||||
{
|
||||
m_bMenuDisplayed = false;
|
||||
}
|
||||
@ -130,11 +158,24 @@ bool CHudMenu::ShouldDraw( void )
|
||||
return false;
|
||||
|
||||
// check for if menu is set to disappear
|
||||
if ( m_flShutoffTime > 0 && m_flShutoffTime <= gpGlobals->realtime )
|
||||
if ( m_flShutoffTime > 0 )
|
||||
{
|
||||
// times up, shutoff
|
||||
m_bMenuDisplayed = false;
|
||||
return false;
|
||||
#ifdef MAPBASE
|
||||
if ( m_bMapDefinedMenu && !m_bPlayingFadeout && (m_flShutoffTime - m_flOpenCloseTime) <= GetMenuTime() )
|
||||
{
|
||||
// Begin closing the menu
|
||||
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "MenuClose" );
|
||||
m_bMenuTakesInput = false;
|
||||
m_bPlayingFadeout = true;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if ( m_flShutoffTime <= GetMenuTime() )
|
||||
{
|
||||
// times up, shutoff
|
||||
m_bMenuDisplayed = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return draw;
|
||||
@ -169,23 +210,21 @@ void CHudMenu::Paint()
|
||||
return;
|
||||
|
||||
// center it
|
||||
int x = 20;
|
||||
int x = m_nBorder;
|
||||
|
||||
Color menuColor = m_MenuColor;
|
||||
Color itemColor = m_ItemColor;
|
||||
|
||||
int c = m_Processed.Count();
|
||||
|
||||
int border = 20;
|
||||
|
||||
int wide = m_nMaxPixels + border;
|
||||
int tall = m_nHeight + border;
|
||||
int wide = m_nMaxPixels + m_nBorder;
|
||||
int tall = m_nHeight + m_nBorder;
|
||||
|
||||
int y = ( ScreenHeight() - tall ) * 0.5f;
|
||||
|
||||
DrawBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
|
||||
DrawBox( x - m_nBorder/2, y - m_nBorder/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
|
||||
|
||||
//DrawTexturedBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
|
||||
//DrawTexturedBox( x - m_nBorder/2, y - m_nBorder/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
|
||||
|
||||
menuColor[3] = menuColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
|
||||
itemColor[3] = itemColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
|
||||
@ -195,7 +234,18 @@ void CHudMenu::Paint()
|
||||
ProcessedLine *line = &m_Processed[ i ];
|
||||
Assert( line );
|
||||
|
||||
Color clr = line->menuitem != 0 ? itemColor : menuColor;
|
||||
#ifdef MAPBASE
|
||||
bool isItem = true;
|
||||
if (line->menuitem == 0 && line->startchar < (MAX_MENU_STRING-1) && g_szMenuString[ line->startchar ] != L'0' && g_szMenuString[ line->startchar+1 ] != L'.')
|
||||
{
|
||||
// Can't use 0 directly because it gets conflated with the cancel item
|
||||
isItem = false;
|
||||
}
|
||||
#else
|
||||
bool isItem = line->menuitem != 0;
|
||||
#endif
|
||||
|
||||
Color clr = isItem ? itemColor : menuColor;
|
||||
|
||||
bool canblur = false;
|
||||
if ( line->menuitem != 0 &&
|
||||
@ -208,15 +258,15 @@ void CHudMenu::Paint()
|
||||
vgui::surface()->DrawSetTextColor( clr );
|
||||
|
||||
int drawLen = line->length;
|
||||
if ( line->menuitem != 0 )
|
||||
if (isItem)
|
||||
{
|
||||
drawLen *= m_flTextScan;
|
||||
}
|
||||
|
||||
vgui::surface()->DrawSetTextFont( line->menuitem != 0 ? m_hItemFont : m_hTextFont );
|
||||
vgui::surface()->DrawSetTextFont( isItem ? m_hItemFont : m_hTextFont );
|
||||
|
||||
PaintString( &g_szMenuString[ line->startchar ], drawLen,
|
||||
line->menuitem != 0 ? m_hItemFont : m_hTextFont, x, y );
|
||||
isItem ? m_hItemFont : m_hTextFont, x, y );
|
||||
|
||||
if ( canblur )
|
||||
{
|
||||
@ -242,6 +292,20 @@ void CHudMenu::Paint()
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
inline float CHudMenu::GetMenuTime( void )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
// In singleplayer, use the curtime instead. This fixes issues with menus disappearing after pausing
|
||||
if (gpGlobals->maxClients <= 1)
|
||||
return gpGlobals->curtime;
|
||||
#endif
|
||||
|
||||
return gpGlobals->realtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: selects an item from the menu
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -260,7 +324,7 @@ void CHudMenu::SelectMenuItem( int menu_item )
|
||||
|
||||
// remove the menu quickly
|
||||
m_bMenuTakesInput = false;
|
||||
m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
|
||||
m_flShutoffTime = GetMenuTime() + m_flOpenCloseTime;
|
||||
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
|
||||
}
|
||||
}
|
||||
@ -339,9 +403,20 @@ void CHudMenu::ProcessText( void )
|
||||
{
|
||||
ProcessedLine *l = &m_Processed[ i ];
|
||||
Assert( l );
|
||||
|
||||
#ifdef MAPBASE
|
||||
bool isItem = true;
|
||||
if (l->menuitem == 0 && l->startchar < (MAX_MENU_STRING-1) && g_szMenuString[ l->startchar ] != L'0' && g_szMenuString[ l->startchar+1 ] != L'.')
|
||||
{
|
||||
// Can't use 0 directly because it gets conflated with the cancel item
|
||||
isItem = false;
|
||||
}
|
||||
#else
|
||||
bool isItem = l->menuitem != 0;
|
||||
#endif
|
||||
|
||||
int pixels = 0;
|
||||
vgui::HFont font = l->menuitem != 0 ? m_hItemFont : m_hTextFont;
|
||||
vgui::HFont font = isItem ? m_hItemFont : m_hTextFont;
|
||||
|
||||
for ( int ch = 0; ch < l->length; ch++ )
|
||||
{
|
||||
@ -364,7 +439,7 @@ void CHudMenu::ProcessText( void )
|
||||
void CHudMenu::HideMenu( void )
|
||||
{
|
||||
m_bMenuTakesInput = false;
|
||||
m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
|
||||
m_flShutoffTime = GetMenuTime() + m_flOpenCloseTime;
|
||||
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
|
||||
}
|
||||
|
||||
@ -381,6 +456,11 @@ void CHudMenu::ShowMenu( const char * menuName, int validSlots )
|
||||
m_flShutoffTime = -1;
|
||||
m_bitsValidSlots = validSlots;
|
||||
m_fWaitingForMore = 0;
|
||||
m_nBorder = 20;
|
||||
#ifdef MAPBASE
|
||||
m_bMapDefinedMenu = false;
|
||||
m_bPlayingFadeout = false;
|
||||
#endif
|
||||
|
||||
Q_strncpy( g_szPrelocalisedMenuString, menuName, sizeof( g_szPrelocalisedMenuString ) );
|
||||
|
||||
@ -408,6 +488,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
|
||||
m_flShutoffTime = -1;
|
||||
m_fWaitingForMore = 0;
|
||||
m_bitsValidSlots = 0;
|
||||
m_nBorder = 20;
|
||||
#ifdef MAPBASE
|
||||
m_bMapDefinedMenu = false;
|
||||
m_bPlayingFadeout = false;
|
||||
#endif
|
||||
|
||||
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpen");
|
||||
m_nSelectedItem = -1;
|
||||
@ -426,7 +511,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
|
||||
const char *pszItem = item->GetName();
|
||||
const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pszItem );
|
||||
|
||||
#ifdef MAPBASE
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"->%d. %ls\n", i+1, wLocalizedItem );
|
||||
#else
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"%d. %ls\n", i+1, wLocalizedItem );
|
||||
#endif
|
||||
nRemaining -= nCount;
|
||||
pWritePosition += nCount;
|
||||
|
||||
@ -436,7 +525,11 @@ void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
|
||||
// put a cancel on the end
|
||||
m_bitsValidSlots |= (1<<9);
|
||||
|
||||
#ifdef MAPBASE
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"->0. %ls\n", g_pVGuiLocalize->Find( "#Cancel" ) );
|
||||
#else
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"0. %ls\n", g_pVGuiLocalize->Find( "#Cancel" ) );
|
||||
#endif
|
||||
nRemaining -= nCount;
|
||||
pWritePosition += nCount;
|
||||
|
||||
@ -465,8 +558,7 @@ void CHudMenu::MsgFunc_ShowMenu( bf_read &msg)
|
||||
|
||||
if ( DisplayTime > 0 )
|
||||
{
|
||||
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + gpGlobals->realtime;
|
||||
|
||||
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + GetMenuTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -511,8 +603,131 @@ void CHudMenu::MsgFunc_ShowMenu( bf_read &msg)
|
||||
}
|
||||
|
||||
m_fWaitingForMore = NeedMore;
|
||||
m_nBorder = 20;
|
||||
#ifdef MAPBASE
|
||||
m_bMapDefinedMenu = false;
|
||||
m_bPlayingFadeout = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
ConVar hud_menu_complex_border( "hud_menu_complex_border", "30" );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Message handler for ShowMenu message with more options for game_menu
|
||||
// takes four values:
|
||||
// short : a bitfield of keys that are valid input
|
||||
// float : the duration, in seconds, the menu should stay up. -1 means it stays until something is chosen.
|
||||
// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, false if it's the last string
|
||||
// string: menu string to display
|
||||
// if this message is never received, then scores will simply be the combined totals of the players.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHudMenu::MsgFunc_ShowMenuComplex( bf_read &msg)
|
||||
{
|
||||
m_bitsValidSlots = (short)msg.ReadWord();
|
||||
float DisplayTime = msg.ReadFloat();
|
||||
int NeedMore = msg.ReadByte();
|
||||
|
||||
m_nBorder = hud_menu_complex_border.GetInt();
|
||||
m_bMapDefinedMenu = true;
|
||||
m_bPlayingFadeout = false;
|
||||
|
||||
if ( DisplayTime > 0 )
|
||||
{
|
||||
m_flShutoffTime = m_flOpenCloseTime + DisplayTime + GetMenuTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flShutoffTime = -1;
|
||||
}
|
||||
|
||||
if ( m_bitsValidSlots > -1 )
|
||||
{
|
||||
char szString[2048];
|
||||
msg.ReadString( szString, sizeof(szString) );
|
||||
|
||||
if ( !m_fWaitingForMore ) // this is the start of a new menu
|
||||
{
|
||||
Q_strncpy( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ) );
|
||||
}
|
||||
else
|
||||
{ // append to the current menu string
|
||||
Q_strncat( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
|
||||
if ( !NeedMore )
|
||||
{
|
||||
g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpenFlash");
|
||||
m_nSelectedItem = -1;
|
||||
|
||||
// we have the whole string, so we can localise it now
|
||||
wchar_t *pWritePosition = g_szMenuString;
|
||||
int nRemaining = sizeof( g_szMenuString ) / sizeof( wchar_t );
|
||||
int nCount;
|
||||
|
||||
char *pszToken = strtok( szString, "\n" );
|
||||
int nCurItem = 0;
|
||||
for (; pszToken != NULL; pszToken = strtok( NULL, "\n" ), nCurItem++)
|
||||
{
|
||||
if (!*pszToken || *pszToken == ' ')
|
||||
continue;
|
||||
|
||||
wchar_t wszMenuItem[128];
|
||||
|
||||
const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pszToken );
|
||||
if (wLocalizedItem)
|
||||
{
|
||||
V_wcsncpy( wszMenuItem, wLocalizedItem, sizeof( wszMenuItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pVGuiLocalize->ConvertANSIToUnicode( pszToken, wszMenuItem, sizeof( wszMenuItem ) );
|
||||
}
|
||||
|
||||
if (nCurItem == 0)
|
||||
{
|
||||
// First item is title
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"%ls\n", wszMenuItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this item isn't valid, skip until it is
|
||||
//while (!(m_bitsValidSlots & (1 << nCurItem)) && nCurItem < 10)
|
||||
//{
|
||||
// nCurItem++;
|
||||
//}
|
||||
|
||||
if (nCurItem == 10)
|
||||
nCurItem = 0;
|
||||
|
||||
nCount = _snwprintf( pWritePosition, nRemaining, L"->%d. %ls\n", nCurItem, wszMenuItem );
|
||||
}
|
||||
|
||||
nRemaining -= nCount;
|
||||
pWritePosition += nCount;
|
||||
}
|
||||
|
||||
ProcessText();
|
||||
}
|
||||
|
||||
m_bMenuDisplayed = true;
|
||||
|
||||
if (m_bitsValidSlots > 0)
|
||||
m_bMenuTakesInput = true;
|
||||
else
|
||||
m_bMenuTakesInput = false;
|
||||
|
||||
m_flSelectionTime = gpGlobals->curtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
HideMenu();
|
||||
}
|
||||
|
||||
m_fWaitingForMore = NeedMore;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: hud scheme settings
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -26,10 +26,14 @@ class CHudMenu : public CHudElement, public vgui::Panel
|
||||
public:
|
||||
CHudMenu( const char *pElementName );
|
||||
void Init( void );
|
||||
void LevelInit( void );
|
||||
void VidInit( void );
|
||||
void Reset( void );
|
||||
virtual bool ShouldDraw( void );
|
||||
void MsgFunc_ShowMenu( bf_read &msg );
|
||||
#ifdef MAPBASE
|
||||
void MsgFunc_ShowMenuComplex( bf_read &msg );
|
||||
#endif
|
||||
void HideMenu( void );
|
||||
void ShowMenu( const char * menuName, int keySlot );
|
||||
void ShowMenu_KeyValueItems( KeyValues *pKV );
|
||||
@ -42,6 +46,8 @@ private:
|
||||
virtual void Paint();
|
||||
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
|
||||
private:
|
||||
float GetMenuTime( void );
|
||||
|
||||
void ProcessText( void );
|
||||
|
||||
void PaintString( const wchar_t *text, int textlen, vgui::HFont& font, int x, int y );
|
||||
@ -59,6 +65,7 @@ private:
|
||||
|
||||
int m_nMaxPixels;
|
||||
int m_nHeight;
|
||||
int m_nBorder;
|
||||
|
||||
bool m_bMenuDisplayed;
|
||||
int m_bitsValidSlots;
|
||||
@ -69,6 +76,12 @@ private:
|
||||
|
||||
float m_flSelectionTime;
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Indicates this menu is defined by game_menu
|
||||
bool m_bMapDefinedMenu;
|
||||
bool m_bPlayingFadeout;
|
||||
#endif
|
||||
|
||||
CPanelAnimationVar( float, m_flOpenCloseTime, "OpenCloseTime", "1" );
|
||||
|
||||
CPanelAnimationVar( float, m_flBlur, "Blur", "0" );
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "entityoutput.h"
|
||||
#ifdef MAPBASE
|
||||
#include "eventqueue.h"
|
||||
#include "saverestore_utlvector.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
@ -825,3 +826,449 @@ void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TY
|
||||
}
|
||||
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Displays a custom number menu for player(s)
|
||||
//-----------------------------------------------------------------------------
|
||||
LINK_ENTITY_TO_CLASS( game_menu, CGameMenu );
|
||||
|
||||
BEGIN_DATADESC( CGameMenu )
|
||||
|
||||
DEFINE_UTLVECTOR( m_ActivePlayers, FIELD_EHANDLE ),
|
||||
DEFINE_UTLVECTOR( m_ActivePlayerTimes, FIELD_TIME ),
|
||||
|
||||
DEFINE_KEYFIELD( m_flDisplayTime, FIELD_FLOAT, "holdtime" ),
|
||||
|
||||
DEFINE_KEYFIELD( m_iszTitle, FIELD_STRING, "Title" ),
|
||||
|
||||
DEFINE_KEYFIELD( m_iszOption[0], FIELD_STRING, "Case01" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[1], FIELD_STRING, "Case02" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[2], FIELD_STRING, "Case03" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[3], FIELD_STRING, "Case04" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[4], FIELD_STRING, "Case05" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[5], FIELD_STRING, "Case06" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[6], FIELD_STRING, "Case07" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[7], FIELD_STRING, "Case08" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[8], FIELD_STRING, "Case09" ),
|
||||
DEFINE_KEYFIELD( m_iszOption[9], FIELD_STRING, "Case10" ),
|
||||
|
||||
// Inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ShowMenu", InputShowMenu ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "HideMenu", InputHideMenu ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "__DoRestore", InputDoRestore ),
|
||||
|
||||
// Outputs
|
||||
DEFINE_OUTPUT( m_OnCase[0], "OnCase01" ),
|
||||
DEFINE_OUTPUT( m_OnCase[1], "OnCase02" ),
|
||||
DEFINE_OUTPUT( m_OnCase[2], "OnCase03" ),
|
||||
DEFINE_OUTPUT( m_OnCase[3], "OnCase04" ),
|
||||
DEFINE_OUTPUT( m_OnCase[4], "OnCase05" ),
|
||||
DEFINE_OUTPUT( m_OnCase[5], "OnCase06" ),
|
||||
DEFINE_OUTPUT( m_OnCase[6], "OnCase07" ),
|
||||
DEFINE_OUTPUT( m_OnCase[7], "OnCase08" ),
|
||||
DEFINE_OUTPUT( m_OnCase[8], "OnCase09" ),
|
||||
DEFINE_OUTPUT( m_OnCase[9], "OnCase10" ),
|
||||
DEFINE_OUTPUT( m_OutValue, "OutValue" ),
|
||||
DEFINE_OUTPUT( m_OnTimeout, "OnTimeout" ),
|
||||
|
||||
DEFINE_THINKFUNC( TimeoutThink ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_AUTO_LIST( IGameMenuAutoList );
|
||||
|
||||
static const char *s_pTimeoutContext = "TimeoutContext";
|
||||
|
||||
#define MENU_INFINITE_TIME -1.0f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CGameMenu::CGameMenu()
|
||||
{
|
||||
m_flDisplayTime = 5.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::OnRestore()
|
||||
{
|
||||
BaseClass::OnRestore();
|
||||
|
||||
// Do this a bit after we restore since the HUD might not be ready yet
|
||||
g_EventQueue.AddEvent( this, "__DoRestore", 0.4f, this, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::InputDoRestore( inputdata_t &inputdata )
|
||||
{
|
||||
// Check if we should restore the menu on anyone
|
||||
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get())
|
||||
{
|
||||
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
|
||||
{
|
||||
CRecipientFilter filter;
|
||||
filter.AddRecipient( static_cast<CBasePlayer*>( m_ActivePlayers[i].Get() ) );
|
||||
|
||||
ShowMenu( filter, m_ActivePlayerTimes[i] - gpGlobals->curtime );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove this player since it's no longer valid
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::TimeoutThink()
|
||||
{
|
||||
float flNextLowestTime = FLT_MAX;
|
||||
FOR_EACH_VEC( m_ActivePlayerTimes, i )
|
||||
{
|
||||
// If the player is still in our list, then they must not have selected an option
|
||||
if (m_ActivePlayerTimes[i] != MENU_INFINITE_TIME)
|
||||
{
|
||||
if (m_ActivePlayerTimes[i] <= gpGlobals->curtime)
|
||||
{
|
||||
m_OnTimeout.FireOutput( m_ActivePlayers[i], this );
|
||||
|
||||
// Remove this player since it's no longer valid
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
break;
|
||||
}
|
||||
else if (m_ActivePlayerTimes[i] < flNextLowestTime)
|
||||
{
|
||||
flNextLowestTime = m_ActivePlayerTimes[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flNextLowestTime < FLT_MAX)
|
||||
{
|
||||
SetNextThink( flNextLowestTime, s_pTimeoutContext );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetContextThink( NULL, TICK_NEVER_THINK, s_pTimeoutContext );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::ShowMenu( CRecipientFilter &filter, float flDisplayTime )
|
||||
{
|
||||
// Before showing the menu, check each menu to see if there's already one being shown to one of our recipients
|
||||
for ( int i = 0; i < IGameMenuAutoList::AutoList().Count(); i++ )
|
||||
{
|
||||
CGameMenu *pMenu = static_cast<CGameMenu*>( IGameMenuAutoList::AutoList()[i] );
|
||||
if ( pMenu != this && pMenu->IsActive() )
|
||||
{
|
||||
for ( int j = 0; j < filter.GetRecipientCount(); j++ )
|
||||
{
|
||||
CBaseEntity *ent = CBaseEntity::Instance( filter.GetRecipientIndex( j ) );
|
||||
if ( pMenu->IsActiveOnTarget( ent ) )
|
||||
{
|
||||
Msg( "%s overriding menu %s for player %i\n", GetDebugName(), pMenu->GetDebugName(), j );
|
||||
pMenu->RemoveTarget( ent );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flDisplayTime == 0.0f)
|
||||
{
|
||||
flDisplayTime = m_flDisplayTime;
|
||||
}
|
||||
|
||||
char szString[512] = { 0 };
|
||||
int nBitsValidSlots = 0;
|
||||
|
||||
if (m_iszTitle != NULL_STRING)
|
||||
{
|
||||
V_strncat( szString, STRING( m_iszTitle ), sizeof( szString ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert space to tell menu code to skip
|
||||
V_strncat( szString, " ", sizeof( szString ) );
|
||||
}
|
||||
|
||||
// Insert newline even if there's no string
|
||||
V_strncat( szString, "\n", sizeof( szString ) );
|
||||
|
||||
// Populate the options
|
||||
for (int i = 0; i < MAX_MENU_OPTIONS; i++)
|
||||
{
|
||||
if (m_iszOption[i] != NULL_STRING)
|
||||
{
|
||||
nBitsValidSlots |= (1 << i);
|
||||
|
||||
V_strncat( szString, STRING( m_iszOption[i] ), sizeof( szString ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert space to tell menu code to skip
|
||||
V_strncat( szString, " ", sizeof( szString ) );
|
||||
}
|
||||
|
||||
// Insert newline even if there's no string
|
||||
V_strncat( szString, "\n", sizeof( szString ) );
|
||||
}
|
||||
|
||||
if (nBitsValidSlots <= 0 && m_iszTitle == NULL_STRING)
|
||||
{
|
||||
Warning( "%s ShowMenu: Can't show menu with no options or title\n", GetDebugName() );
|
||||
return;
|
||||
}
|
||||
|
||||
UserMessageBegin( filter, "ShowMenuComplex" );
|
||||
WRITE_WORD( nBitsValidSlots );
|
||||
WRITE_FLOAT( flDisplayTime );
|
||||
WRITE_BYTE( 0 );
|
||||
WRITE_STRING( szString );
|
||||
MessageEnd();
|
||||
|
||||
float flMenuTime;
|
||||
if (flDisplayTime <= 0.0f)
|
||||
{
|
||||
flMenuTime = MENU_INFINITE_TIME;
|
||||
}
|
||||
else
|
||||
{
|
||||
flMenuTime = gpGlobals->curtime + flDisplayTime;
|
||||
}
|
||||
|
||||
for ( int j = 0; j < filter.GetRecipientCount(); j++ )
|
||||
{
|
||||
CBaseEntity *ent = CBaseEntity::Instance( filter.GetRecipientIndex( j ) );
|
||||
|
||||
// Check if we already track this player. If not, make a new one
|
||||
bool bFound = false;
|
||||
FOR_EACH_VEC( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get() == ent)
|
||||
{
|
||||
m_ActivePlayerTimes[i] = flMenuTime;
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFound)
|
||||
{
|
||||
m_ActivePlayers.AddToTail( ent );
|
||||
m_ActivePlayerTimes.AddToTail( flMenuTime );
|
||||
}
|
||||
}
|
||||
|
||||
if (GetNextThink( s_pTimeoutContext ) == TICK_NEVER_THINK)
|
||||
{
|
||||
SetContextThink( &CGameMenu::TimeoutThink, gpGlobals->curtime + flDisplayTime, s_pTimeoutContext );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::HideMenu( CRecipientFilter &filter )
|
||||
{
|
||||
UserMessageBegin( filter, "ShowMenuComplex" );
|
||||
WRITE_WORD( -1 );
|
||||
WRITE_FLOAT( 0.0f );
|
||||
WRITE_BYTE( 0 );
|
||||
WRITE_STRING( "" );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::MenuSelected( int nSlot, CBaseEntity *pActivator )
|
||||
{
|
||||
if (nSlot <= 0 || nSlot > MAX_MENU_OPTIONS)
|
||||
{
|
||||
Warning( "%s: Invalid slot %i\n", GetDebugName(), nSlot );
|
||||
return;
|
||||
}
|
||||
|
||||
m_OnCase[nSlot-1].FireOutput( pActivator, this );
|
||||
m_OutValue.Set( nSlot, pActivator, this );
|
||||
|
||||
RemoveTarget( pActivator );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CGameMenu::IsActive()
|
||||
{
|
||||
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get())
|
||||
{
|
||||
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove this player since it's no longer valid
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CGameMenu::IsActiveOnTarget( CBaseEntity *pPlayer )
|
||||
{
|
||||
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get() == pPlayer)
|
||||
{
|
||||
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
|
||||
return true;
|
||||
|
||||
// Remove this player since it's no longer valid
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::RemoveTarget( CBaseEntity *pPlayer )
|
||||
{
|
||||
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get() == pPlayer)
|
||||
{
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::InputShowMenu( inputdata_t &inputdata )
|
||||
{
|
||||
if (HasSpawnFlags( SF_GAMEMENU_ALLPLAYERS ))
|
||||
{
|
||||
CRecipientFilter filter;
|
||||
filter.AddAllPlayers();
|
||||
|
||||
ShowMenu( filter );
|
||||
}
|
||||
else
|
||||
{
|
||||
CBasePlayer *pPlayer = NULL;
|
||||
|
||||
// If we're in singleplayer, show the message to the player.
|
||||
if ( gpGlobals->maxClients == 1 )
|
||||
{
|
||||
pPlayer = UTIL_GetLocalPlayer();
|
||||
}
|
||||
// Otherwise show the message to the player that triggered us.
|
||||
else if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
|
||||
{
|
||||
pPlayer = ToBasePlayer( inputdata.pActivator );
|
||||
}
|
||||
|
||||
if (pPlayer)
|
||||
{
|
||||
CRecipientFilter filter;
|
||||
filter.AddRecipient( pPlayer );
|
||||
|
||||
ShowMenu( filter );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CGameMenu::InputHideMenu( inputdata_t &inputdata )
|
||||
{
|
||||
if (HasSpawnFlags( SF_GAMEMENU_ALLPLAYERS ))
|
||||
{
|
||||
CRecipientFilter filter;
|
||||
|
||||
FOR_EACH_VEC_BACK( m_ActivePlayers, i )
|
||||
{
|
||||
// Select all players in our list who are still active, and remove them
|
||||
if (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME)
|
||||
{
|
||||
filter.AddRecipient( static_cast<CBasePlayer*>(m_ActivePlayers[i].Get()) );
|
||||
}
|
||||
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
}
|
||||
|
||||
if (filter.GetRecipientCount() <= 0)
|
||||
return;
|
||||
|
||||
HideMenu( filter );
|
||||
}
|
||||
else
|
||||
{
|
||||
CBasePlayer *pPlayer = NULL;
|
||||
|
||||
// If we're in singleplayer, show the message to the player.
|
||||
if ( gpGlobals->maxClients == 1 )
|
||||
{
|
||||
pPlayer = UTIL_GetLocalPlayer();
|
||||
}
|
||||
// Otherwise show the message to the player that triggered us.
|
||||
else if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
|
||||
{
|
||||
pPlayer = ToBasePlayer( inputdata.pActivator );
|
||||
}
|
||||
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
// Verify that this player is in our list
|
||||
CRecipientFilter filter;
|
||||
FOR_EACH_VEC( m_ActivePlayers, i )
|
||||
{
|
||||
if (m_ActivePlayers[i].Get() == pPlayer && (m_ActivePlayerTimes[i] > gpGlobals->curtime || m_ActivePlayerTimes[i] == MENU_INFINITE_TIME))
|
||||
{
|
||||
filter.AddRecipient( pPlayer );
|
||||
|
||||
// Remove since the player won't have the menu anymore
|
||||
m_ActivePlayers.Remove( i );
|
||||
m_ActivePlayerTimes.Remove( i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter.GetRecipientCount() <= 0)
|
||||
return;
|
||||
|
||||
HideMenu( filter );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -9,7 +9,55 @@
|
||||
#ifndef MAPRULES_H
|
||||
#define MAPRULES_H
|
||||
|
||||
#ifdef MAPBASE
|
||||
#define MAX_MENU_OPTIONS 10
|
||||
|
||||
#define SF_GAMEMENU_ALLPLAYERS 0x0001
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Displays a custom number menu for player(s)
|
||||
//-----------------------------------------------------------------------------
|
||||
DECLARE_AUTO_LIST( IGameMenuAutoList );
|
||||
class CGameMenu : public CLogicalEntity, public IGameMenuAutoList
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CGameMenu, CLogicalEntity );
|
||||
DECLARE_DATADESC();
|
||||
CGameMenu();
|
||||
|
||||
void OnRestore();
|
||||
void InputDoRestore( inputdata_t &inputdata );
|
||||
|
||||
void TimeoutThink();
|
||||
|
||||
void ShowMenu( CRecipientFilter &filter, float flDisplayTime = 0.0f );
|
||||
void HideMenu( CRecipientFilter &filter );
|
||||
void MenuSelected( int nSlot, CBaseEntity *pActivator );
|
||||
|
||||
bool IsActive();
|
||||
bool IsActiveOnTarget( CBaseEntity *pPlayer );
|
||||
void RemoveTarget( CBaseEntity *pPlayer );
|
||||
|
||||
// Inputs
|
||||
void InputShowMenu( inputdata_t &inputdata );
|
||||
void InputHideMenu( inputdata_t &inputdata );
|
||||
|
||||
private:
|
||||
|
||||
CUtlVector<EHANDLE> m_ActivePlayers;
|
||||
CUtlVector<float> m_ActivePlayerTimes;
|
||||
|
||||
float m_flDisplayTime;
|
||||
|
||||
string_t m_iszTitle;
|
||||
string_t m_iszOption[MAX_MENU_OPTIONS];
|
||||
|
||||
// Outputs
|
||||
COutputEvent m_OnCase[MAX_MENU_OPTIONS]; // Fired for the option chosen
|
||||
COutputInt m_OutValue; // Outputs the option chosen
|
||||
COutputEvent m_OnTimeout; // Fires when no option was chosen in time
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // MAPRULES_H
|
||||
|
||||
|
@ -27,6 +27,9 @@
|
||||
#include "player_resource.h"
|
||||
#include "tactical_mission.h"
|
||||
#include "gamestats.h"
|
||||
#ifdef MAPBASE
|
||||
#include "maprules.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -619,6 +622,27 @@ bool CGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
|
||||
{
|
||||
if( GetVoiceGameMgr()->ClientCommand( static_cast<CBasePlayer*>(pEdict), args ) )
|
||||
return true;
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( FStrEq( args[0], "menuselect" ) )
|
||||
{
|
||||
if ( args.ArgC() >= 2 )
|
||||
{
|
||||
int slot = atoi( args[1] );
|
||||
|
||||
// See if this is from a game_menu
|
||||
for ( int i = 0; i < IGameMenuAutoList::AutoList().Count(); i++ )
|
||||
{
|
||||
CGameMenu *pMenu = static_cast<CGameMenu*>( IGameMenuAutoList::AutoList()[i] );
|
||||
if ( pMenu->IsActiveOnTarget( pEdict ) )
|
||||
{
|
||||
pMenu->MenuSelected( slot, pEdict );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -20,6 +20,8 @@ void HookMapbaseUserMessages( void )
|
||||
{
|
||||
// VScript
|
||||
//HOOK_MESSAGE( ScriptMsg ); // Hooked in CNetMsgScriptHelper
|
||||
|
||||
//HOOK_MESSAGE( ShowMenuComplex ); // Hooked in CHudMenu
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -28,6 +30,8 @@ void RegisterMapbaseUserMessages( void )
|
||||
// VScript
|
||||
usermessages->Register( "ScriptMsg", -1 ); // CNetMsgScriptHelper
|
||||
|
||||
usermessages->Register( "ShowMenuComplex", -1 ); // CHudMenu
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
// TODO: Better placement?
|
||||
HookMapbaseUserMessages();
|
||||
|
Loading…
x
Reference in New Issue
Block a user