11/* **
22*
33* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
4- *
5- * This product contains software technology licensed from Id
6- * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
4+ *
5+ * This product contains software technology licensed from Id
6+ * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
77* All Rights Reserved.
88*
99* Use, distribution, and modification of this source code and/or resulting
1717//
1818// generic menu handler
1919//
20+
2021#include " hud.h"
2122#include " utils.h"
2223#include " parsemsg.h"
24+ #include < string.h>
25+ #include < stdio.h>
2326
2427#define MAX_MENU_STRING 512
25-
2628char g_szMenuString[MAX_MENU_STRING];
2729char g_szPrelocalisedMenuString[MAX_MENU_STRING];
2830
29- DECLARE_MESSAGE ( m_Menu, ShowMenu );
31+ int KB_ConvertString ( char *in, char **ppout );
3032
31- int CHudMenu :: Init( void )
33+ DECLARE_MESSAGE (m_Menu, ShowMenu)
34+
35+ int CHudMenu::Init(void )
3236{
33- gHUD .AddHudElem ( this );
37+ gHUD .AddHudElem (this );
3438
35- HOOK_MESSAGE ( ShowMenu );
39+ HOOK_MESSAGE (ShowMenu);
3640
3741 InitHUDData ();
3842
3943 return 1 ;
4044}
4145
42- void CHudMenu :: InitHUDData( void )
46+ void CHudMenu:: InitHUDData (void )
4347{
4448 m_fMenuDisplayed = 0 ;
4549 m_bitsValidSlots = 0 ;
50+ m_iFlags &= ~HUD_ACTIVE;
4651 Reset ();
4752}
4853
49- void CHudMenu :: Reset( void )
54+ void CHudMenu:: Reset (void )
5055{
5156 g_szPrelocalisedMenuString[0 ] = 0 ;
5257 m_fWaitingForMore = FALSE ;
5358}
5459
55- int CHudMenu :: VidInit( void )
60+ int CHudMenu:: VidInit (void )
5661{
5762 return 1 ;
5863}
5964
60- int CHudMenu :: Draw( float flTime )
65+ /*
66+ =================================
67+ ParseEscapeToken
68+
69+ Interprets the given escape token (backslash followed by a letter). The
70+ first character of the token must be a backslash. The second character
71+ specifies the operation to perform:
72+
73+ \w : White text (this is the default)
74+ \d : Dim (gray) text
75+ \y : Yellow text
76+ \r : Red text
77+ \R : Right-align (just for the remainder of the current line)
78+ =================================
79+ */
80+
81+ static int menu_r, menu_g, menu_b, menu_x, menu_ralign;
82+
83+ static inline const char * ParseEscapeToken (const char * token)
84+ {
85+ if (*token != ' \\ ' )
86+ return token;
87+
88+ token++;
89+
90+ switch (*token)
91+ {
92+ case ' \0 ' :
93+ return token;
94+
95+ case ' w' :
96+ menu_r = 255 ;
97+ menu_g = 255 ;
98+ menu_b = 255 ;
99+ break ;
100+
101+ case ' d' :
102+ menu_r = 100 ;
103+ menu_g = 100 ;
104+ menu_b = 100 ;
105+ break ;
106+
107+ case ' y' :
108+ menu_r = 255 ;
109+ menu_g = 210 ;
110+ menu_b = 64 ;
111+ break ;
112+
113+ case ' r' :
114+ menu_r = 210 ;
115+ menu_g = 24 ;
116+ menu_b = 0 ;
117+ break ;
118+
119+ case ' R' :
120+ menu_x = ScreenWidth / 2 ;
121+ menu_ralign = TRUE ;
122+ break ;
123+ }
124+
125+ return ++token;
126+ }
127+
128+ int CHudMenu::Draw (float flTime)
61129{
62130 int i;
131+
63132 // check for if menu is set to disappear
64- if ( m_flShutoffTime > 0 )
133+ if ( m_flShutoffTime > 0 )
65134 {
66- if ( m_flShutoffTime <= gHUD .m_flTime )
135+ if ( m_flShutoffTime <= gHUD .m_flTime )
67136 {
68137 // times up, shutoff
69138 m_fMenuDisplayed = 0 ;
@@ -76,99 +145,119 @@ int CHudMenu :: Draw( float flTime )
76145 if ( gHUD .m_Scoreboard .m_iShowscoresHeld )
77146 return 1 ;
78147
79- // draw the menu, along the left-hand side of the screen
148+ SCREENINFO screenInfo;
149+
150+ screenInfo.iSize = sizeof (SCREENINFO);
151+ gEngfuncs .pfnGetScreenInfo (&screenInfo);
80152
153+ // draw the menu, along the left-hand side of the screen
81154 // count the number of newlines
82155 int nlc = 0 ;
83- for ( i = 0 ; i < MAX_MENU_STRING && g_szMenuString[i] != ' \0 ' ; i++ )
84- {
85- if ( g_szMenuString[i] == ' \n ' )
156+ for (i = 0 ; i < MAX_MENU_STRING && g_szMenuString[i] != ' \0 ' ; i++)
157+ if (g_szMenuString[i] == ' \n ' )
86158 nlc++;
87- }
159+
160+ int nFontHeight = Q_max (12 , screenInfo.iCharHeight );
88161
89162 // center it
90- int y = (ScreenHeight / 2 ) - ((nlc / 2 ) * 12 ) - 40 ; // make sure it is above the say text
91- int x = 20 ;
163+ int y = (ScreenHeight / 2 ) - ((nlc / 2 ) * nFontHeight) - (3 * nFontHeight + nFontHeight / 3 ); // make sure it is above the say text
92164
93- i = 0 ;
94- while ( i < MAX_MENU_STRING && g_szMenuString[i] != ' \0 ' )
95- {
96- gHUD . DrawHudString ( x, y, 320 , g_szMenuString + i, 255 , 255 , 255 ) ;
97- y += 12 ;
165+ menu_r = 255 ;
166+ menu_g = 255 ;
167+ menu_b = 255 ;
168+ menu_x = 20 ;
169+ menu_ralign = FALSE ;
98170
99- while ( i < MAX_MENU_STRING && g_szMenuString[i] != ' \0 ' && g_szMenuString[i] != ' \n ' )
100- i++;
171+ const char * sptr = g_szMenuString;
101172
102- if ( g_szMenuString[i] == ' \n ' )
103- i++;
173+ while (*sptr != ' \0 ' )
174+ {
175+ if (*sptr == ' \\ ' )
176+ sptr = ParseEscapeToken (sptr);
177+ else if (*sptr == ' \n ' )
178+ {
179+ menu_ralign = FALSE ;
180+ menu_x = 20 ;
181+ y += nFontHeight;
182+ sptr++;
183+ }
184+ else
185+ {
186+ char menubuf[80 ] = " " ;
187+ const char *ptr = sptr;
188+ while (*sptr != ' \0 ' && *sptr != ' \n ' && *sptr != ' \\ ' )
189+ sptr++;
190+ strlcpy (menubuf, ptr, Q_min ((sptr - ptr + 1 ), (int )sizeof (menubuf)));
191+ if (menu_ralign)
192+ // IMPORTANT: Right-to-left rendered text does not parse escape tokens!
193+ menu_x = gHUD .DrawHudStringReverse (menu_x, y, 0 , menubuf, menu_r, menu_g, menu_b);
194+ else menu_x = gHUD .DrawHudString (menu_x, y, 320 , menubuf, menu_r, menu_g, menu_b);
195+ }
104196 }
105-
197+
106198 return 1 ;
107199}
108200
109201// selects an item from the menu
110- void CHudMenu :: SelectMenuItem( int menu_item )
202+ void CHudMenu:: SelectMenuItem (int menu_item)
111203{
112204 // if menu_item is in a valid slot, send a menuselect command to the server
113- if (( menu_item > 0 ) && ( m_bitsValidSlots & (1 << ( menu_item - 1 ))))
205+ if (( menu_item > 0 ) && (m_bitsValidSlots & (1 << (menu_item - 1 ))))
114206 {
115207 char szbuf[32 ];
116- sprintf ( szbuf, " menuselect %d\n " , menu_item );
117- ClientCmd ( szbuf );
208+ sprintf (szbuf, " menuselect %d\n " , menu_item);
209+ ClientCmd (szbuf);
118210
119211 // remove the menu
120212 m_fMenuDisplayed = 0 ;
121213 m_iFlags &= ~HUD_ACTIVE;
122214 }
123215}
124216
125-
126217// Message handler for ShowMenu message
127218// takes four values:
128- // short: a bitfield of keys that are valid input
129- // char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
130- // byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string
131- // string: menu string to display
219+ // short: a bitfield of keys that are valid input
220+ // char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
221+ // byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string
222+ // string: menu string to display
132223// if this message is never received, then scores will simply be the combined totals of the players.
133- int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf )
224+ int CHudMenu:: MsgFunc_ShowMenu (const char *pszName, int iSize, void *pbuf)
134225{
135226 char *temp = NULL ;
136227
137- BEGIN_READ ( pszName, pbuf, iSize );
228+ BEGIN_READ (pszName, pbuf, iSize);
138229
139230 m_bitsValidSlots = READ_SHORT ();
140231 int DisplayTime = READ_CHAR ();
141232 int NeedMore = READ_BYTE ();
142233
143- if ( DisplayTime > 0 )
234+ if ( DisplayTime > 0 )
144235 m_flShutoffTime = DisplayTime + gHUD .m_flTime ;
145236 else
146237 m_flShutoffTime = -1 ;
147238
148- if ( m_bitsValidSlots )
239+ if ( m_bitsValidSlots)
149240 {
150- if ( !m_fWaitingForMore )
241+ if ( !m_fWaitingForMore) // this is the start of a new menu
151242 {
152- // this is the start of a new menu
153- Q_strncpy ( g_szPrelocalisedMenuString, READ_STRING (), MAX_MENU_STRING );
243+ strlcpy (g_szPrelocalisedMenuString, READ_STRING (), MAX_MENU_STRING);
154244 }
155245 else
156246 {
157247 // append to the current menu string
158- Q_strncat ( g_szPrelocalisedMenuString, READ_STRING (), MAX_MENU_STRING - Q_strlen ( g_szPrelocalisedMenuString ) );
248+ strlcat ( g_szPrelocalisedMenuString, READ_STRING (), MAX_MENU_STRING);
159249 }
160- g_szPrelocalisedMenuString[MAX_MENU_STRING-1 ] = 0 ; // ensure null termination (strncat/strncpy does not)
161250
162- if ( !NeedMore )
251+ if ( !NeedMore)
163252 {
164253 // we have the whole string, so we can localise it now
165- Q_strcpy ( g_szMenuString, gHUD .m_TextMessage .BufferedLocaliseTextString ( g_szPrelocalisedMenuString ) );
254+ strlcpy ( g_szMenuString, gHUD .m_TextMessage .BufferedLocaliseTextString (g_szPrelocalisedMenuString), MAX_MENU_STRING );
166255
167256 // Swap in characters
168- if ( KB_ConvertString ( g_szMenuString, &temp ))
257+ if ( KB_ConvertString (g_szMenuString, &temp))
169258 {
170- Q_strcpy ( g_szMenuString, temp );
171- free ( temp );
259+ strlcpy ( g_szMenuString, temp, MAX_MENU_STRING );
260+ free (temp);
172261 }
173262 }
174263
@@ -187,4 +276,3 @@ int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf )
187276
188277 return 1 ;
189278}
190-
0 commit comments