1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 
31 
32 
33 /*
34 =======================================================================
35 
36 USER INTERFACE MAIN
37 
38 =======================================================================
39 */
40 
41 #include "ui_local.h"
42 
43 // NERVE - SMF
44 #define AXIS_TEAM       0
45 #define ALLIES_TEAM     1
46 #define SPECT_TEAM      2
47 // -NERVE - SMF
48 
49 extern qboolean g_waitingForKey;
50 extern qboolean g_editingField;
51 extern itemDef_t *g_editItem;
52 
53 uiInfo_t uiInfo;
54 
55 static const char *MonthAbbrev[] = {
56 	"Jan","Feb","Mar",
57 	"Apr","May","Jun",
58 	"Jul","Aug","Sep",
59 	"Oct","Nov","Dec"
60 };
61 
62 
63 static const char *skillLevels[] = {
64 	"I Can Win",
65 	"Bring It On",
66 	"Hurt Me Plenty",
67 	"Hardcore",
68 	"Nightmare"
69 };
70 
71 static const int numSkillLevels = ARRAY_LEN( skillLevels );
72 
73 
74 #define UIAS_LOCAL			0
75 #define UIAS_GLOBAL0			1
76 #define UIAS_GLOBAL1			2
77 #define UIAS_GLOBAL2			3
78 #define UIAS_GLOBAL3			4
79 #define UIAS_GLOBAL4			5
80 #define UIAS_GLOBAL5			6
81 #define UIAS_FAVORITES			7
82 
83 static const char *netSources[] = {
84 	"Local",
85 	"Internet",
86 	"Master1",
87 	"Master2",
88 	"Master3",
89 	"Master4",
90 	"Master5",
91 	"Favorites"
92 };
93 static const int numNetSources = ARRAY_LEN( netSources );
94 
95 static const serverFilter_t serverFilters[] = {
96 	{"All", "" }
97 //	{"Quake 3 Arena", "" },
98 //	{"Team Arena", "missionpack" },
99 //	{"Rocket Arena", "arena" },
100 //	{"Alliance", "alliance" },
101 };
102 
103 static const int numServerFilters = ARRAY_LEN( serverFilters );
104 
105 static const char *teamArenaGameTypes[] = {
106 	"FFA",
107 	"TOURNAMENT",
108 	"SP",
109 	"TEAM DM",
110 	"CTF",
111 	"WOLF MP",               // NERVE - SMF
112 	"WOLF SW",               // NERVE - SMF
113 	"WOLF CP"               // NERVE - SMF
114 };
115 
116 static int const numTeamArenaGameTypes = ARRAY_LEN( teamArenaGameTypes );
117 
118 static char* netnames[] = {
119 	"???",
120 	"IP4",
121 	"IP6"
122 };
123 
124 //static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files"; // TTimo: unused
125 
126 static int gamecodetoui[] = {4,2,3,0,5,1,6};
127 static int uitogamecode[] = {4,6,2,3,1,5,7};
128 
129 
130 // NERVE - SMF - enabled for multiplayer
131 static void UI_StartServerRefresh( qboolean full, qboolean force );
132 static void UI_StopServerRefresh( void );
133 static void UI_DoServerRefresh( void );
134 static void UI_FeederSelection( float feederID, int index );
135 static void UI_BuildServerDisplayList( int force );
136 static void UI_BuildServerStatus( qboolean force );
137 static void UI_BuildFindPlayerList( qboolean force );
138 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
139 static int UI_MapCountByGameType( qboolean singlePlayer );
140 static const char *UI_SelectedMap( int index, int *actual );
141 static int UI_GetIndexFromSelection( int actual );
142 
143 qboolean    UI_CheckExecKey( int key );
144 // -NERVE - SMF - enabled for multiplayer
145 
146 static void UI_ParseGameInfo( const char *teamFile );
147 //static void UI_ParseTeamInfo(const char *teamFile); // TTimo: unused
148 
149 //int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
150 
151 itemDef_t *Menu_FindItemByName( menuDef_t *menu, const char *p );
152 void Menu_ShowItemByName( menuDef_t *menu, const char *p, qboolean bShow );
153 
154 #define ITEM_GRENADES       1
155 #define ITEM_MEDKIT         2
156 
157 #define ITEM_PISTOL         1
158 
159 #define DEFAULT_PISTOL
160 
161 #define PT_KNIFE            ( 1 )
162 #define PT_PISTOL           ( 1 << 2 )
163 #define PT_RIFLE            ( 1 << 3 )
164 #define PT_LIGHTONLY        ( 1 << 4 )
165 #define PT_GRENADES         ( 1 << 5 )
166 #define PT_EXPLOSIVES       ( 1 << 6 )
167 #define PT_MEDKIT           ( 1 << 7 )
168 
169 typedef struct {
170 	const char  *name;
171 	int items;
172 } playerType_t;
173 
174 static playerType_t playerTypes[] = {
175 	{ "player_window_soldier",       PT_KNIFE | PT_PISTOL | PT_RIFLE | PT_GRENADES },
176 	{ "player_window_medic",     PT_KNIFE | PT_PISTOL | PT_MEDKIT },
177 	{ "player_window_engineer",      PT_KNIFE | PT_PISTOL | PT_LIGHTONLY | PT_EXPLOSIVES | PT_GRENADES },
178 	{ "player_window_lieutenant",    PT_KNIFE | PT_PISTOL | PT_RIFLE | PT_EXPLOSIVES }
179 };
180 
181 // TTimo
182 static char translated_yes[4], translated_no[4];
183 
184 typedef struct {
185 	int weapindex;
186 
187 	const char  *desc;
188 	int flags;
189 	const char  *cvar;
190 	int value;
191 	const char  *name;
192 
193 	const char  *torso_anim;
194 	const char  *legs_anim;
195 
196 	const char  *large_shader;
197 } weaponType_t;
198 
199 // NERVE - SMF - this is the weapon info list [what can and can't be used by character classes]
200 //   - This list is seperate from the actual text names in the listboxes for localization purposes.
201 //   - The list boxes look up this list by the cvar value.
202 static weaponType_t weaponTypes[] = {
203 	{ 0, "NULL", 0, "none", 0, "none", "", "", "" },
204 
205 	{ WP_COLT,  "1911 pistol",   PT_PISTOL,  "mp_weapon", 0, "ui_mp/assets/weapon_colt1911.tga",       "firing_pistolB_1",      "stand_pistolB", "" },
206 	{ WP_LUGER, "Luger pistol",  PT_PISTOL,  "mp_weapon", 1, "ui_mp/assets/weapon_luger.tga",          "firing_pistolB_1",      "stand_pistolB", "" },
207 
208 	{ WP_MP40,              "MP 40",                 PT_LIGHTONLY | PT_RIFLE,    "mp_weapon", 3, "ui_mp/assets/weapon_mp40.tga",           "relaxed_idle_2h_1", "relaxed_idle_2h_1", "limbo_mp40" },
209 	{ WP_THOMPSON,          "Thompson",                  PT_LIGHTONLY | PT_RIFLE,    "mp_weapon", 4, "ui_mp/assets/weapon_thompson.tga",       "relaxed_idle_2h_1", "relaxed_idle_2h_1", "limbo_thompson" },
210 	{ WP_STEN,              "Sten",                      PT_LIGHTONLY | PT_RIFLE,    "mp_weapon", 5, "ui_mp/assets/weapon_sten.tga",           "relaxed_idle_2h_1", "relaxed_idle_2h_1", "limbo_sten" },
211 
212 	{ WP_MAUSER,            "Mauser",                    PT_RIFLE,                   "mp_weapon", 6, "ui_mp/assets/weapon_mauser.tga",     "stand_rifle",           "stand_rifle", "limbo_mauser" },
213 	{ WP_PANZERFAUST,       "Panzerfaust",               PT_RIFLE,                   "mp_weapon", 8, "ui_mp/assets/weapon_panzerfaust.tga",    "stand_panzer",          "stand_panzer", "limbo_panzer" },
214 	{ WP_VENOM,             "Venom",                 PT_RIFLE,                   "mp_weapon", 9, "ui_mp/assets/weapon_venom.tga",      "stand_machinegun",      "stand_machinegun", "limbo_venom" },
215 	{ WP_FLAMETHROWER,      "Flamethrower",              PT_RIFLE,                   "mp_weapon", 10, "ui_mp/assets/weapon_flamethrower.tga","stand_machinegun",        "stand_machinegun", "limbo_flame" },
216 
217 	{ WP_GRENADE_PINEAPPLE, "Pineapple grenade",     PT_GRENADES,                "mp_item1",      11, "ui_mp/assets/weapon_grenade.tga",       "firing_pistolB_1",      "stand_pistolB", "" },
218 	{ WP_GRENADE_LAUNCHER,  "Stick grenade",         PT_GRENADES,                "mp_item1",      12, "ui_mp/assets/weapon_grenade_ger.tga",   "firing_pistolB_1",      "stand_pistolB", "" },
219 
220 	{ WP_DYNAMITE,          "Explosives",                PT_EXPLOSIVES,              "mp_item2",      13, "ui_mp/assets/weapon_dynamite.tga",  "firing_pistolB_1",      "stand_pistolB", "" },
221 
222 	{ 0, NULL, 0, NULL, 0, NULL, NULL, NULL }
223 };
224 
225 typedef struct {
226 	char        *name;
227 	int flags;
228 	char        *shader;
229 } uiitemType_t;
230 
231 #define UI_KNIFE_PIC    "window_knife_pic"
232 #define UI_PISTOL_PIC   "window_pistol_pic"
233 #define UI_WEAPON_PIC   "window_weapon_pic"
234 #define UI_ITEM1_PIC    "window_item1_pic"
235 #define UI_ITEM2_PIC    "window_item2_pic"
236 
237 static uiitemType_t itemTypes[] = {
238 	{ UI_KNIFE_PIC,     PT_KNIFE,       "ui_mp/assets/weapon_knife.tga" },
239 	{ UI_PISTOL_PIC,    PT_PISTOL,      "ui_mp/assets/weapon_colt1911.tga" },
240 
241 	{ UI_WEAPON_PIC,    PT_RIFLE,       "ui_mp/assets/weapon_mauser.tga" },
242 
243 	{ UI_ITEM1_PIC,     PT_MEDKIT,      "ui_mp/assets/item_medkit.tga" },
244 
245 	{ UI_ITEM1_PIC,     PT_GRENADES,    "ui_mp/assets/weapon_grenade.tga" },
246 	{ UI_ITEM2_PIC,     PT_EXPLOSIVES,  "ui_mp/assets/weapon_dynamite.tga" },
247 
248 	{ NULL, 0, NULL }
249 };
250 
251 extern displayContextDef_t *DC;
252 
253 /*
254 ================
255 vmMain
256 
257 This is the only way control passes into the module.
258 This must be the very first function compiled into the .qvm file
259 ================
260 */
261 vmCvar_t ui_new;
262 vmCvar_t ui_debug;
263 vmCvar_t ui_initialized;
264 vmCvar_t ui_teamArenaFirstRun;
265 
266 void _UI_Init( qboolean );
267 void _UI_Shutdown( void );
268 void _UI_KeyEvent( int key, qboolean down );
269 void _UI_MouseEvent( int dx, int dy );
270 void _UI_Refresh( int realtime );
271 qboolean _UI_IsFullscreen( void );
272 
vmMain(intptr_t command,intptr_t arg0,intptr_t arg1,intptr_t arg2,intptr_t arg3,intptr_t arg4,intptr_t arg5,intptr_t arg6,intptr_t arg7,intptr_t arg8,intptr_t arg9,intptr_t arg10,intptr_t arg11)273 Q_EXPORT intptr_t vmMain( intptr_t command, intptr_t arg0, intptr_t arg1, intptr_t arg2, intptr_t arg3, intptr_t arg4, intptr_t arg5, intptr_t arg6, intptr_t arg7, intptr_t arg8, intptr_t arg9, intptr_t arg10, intptr_t arg11  ) {
274 	switch ( command ) {
275 	case UI_GETAPIVERSION:
276 		return UI_API_VERSION;
277 
278 	case UI_INIT:
279 		_UI_Init( arg0 );
280 		return 0;
281 
282 	case UI_SHUTDOWN:
283 		_UI_Shutdown();
284 		return 0;
285 
286 	case UI_KEY_EVENT:
287 		_UI_KeyEvent( arg0, arg1 );
288 		return 0;
289 
290 	case UI_MOUSE_EVENT:
291 		_UI_MouseEvent( arg0, arg1 );
292 		return 0;
293 
294 	case UI_REFRESH:
295 		_UI_Refresh( arg0 );
296 		return 0;
297 
298 	case UI_IS_FULLSCREEN:
299 		return _UI_IsFullscreen();
300 
301 	case UI_SET_ACTIVE_MENU:
302 		_UI_SetActiveMenu( arg0 );
303 		return 0;
304 
305 	case UI_GET_ACTIVE_MENU:
306 		return _UI_GetActiveMenu();
307 
308 	case UI_CONSOLE_COMMAND:
309 		return UI_ConsoleCommand( arg0 );
310 
311 	case UI_DRAW_CONNECT_SCREEN:
312 		UI_DrawConnectScreen( arg0 );
313 		return 0;
314 	case UI_HASUNIQUECDKEY:             // mod authors need to observe this
315 		return qtrue;
316 		// NERVE - SMF
317 	case UI_CHECKEXECKEY:
318 		return UI_CheckExecKey( arg0 );
319 	}
320 
321 	return -1;
322 }
323 
324 #define MAX_VA_STRING       32000
UI_TranslateString(const char * string)325 char* UI_TranslateString( const char *string ) {
326 	static char staticbuf[2][MAX_VA_STRING];
327 	static int bufcount = 0;
328 	char *buf;
329 
330 	buf = staticbuf[bufcount++ % 2];
331 
332 	trap_TranslateString( string, buf );
333 
334 	return buf;
335 }
336 
337 
AssetCache(void)338 void AssetCache( void ) {
339 	int n;
340 	//if (Assets.textFont == NULL) {
341 	//}
342 	//Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
343 	//Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
344 	uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
345 	uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
346 	uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
347 	uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
348 	uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
349 	uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
350 	uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
351 	uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
352 	uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
353 	uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
354 	uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
355 	uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
356 	uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
357 	uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
358 	uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
359 	uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
360 	uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
361 
362 	for ( n = 0; n < NUM_CROSSHAIRS; n++ ) {
363 		uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va( "gfx/2d/crosshair%c", 'a' + n ) );
364 	}
365 
366 	//uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav");
367 
368 	// NERVE - SMF - WolfMP cache
369 	trap_R_RegisterShaderNoMip( "multi_axisflag" );
370 	trap_R_RegisterShaderNoMip( "multi_alliedflag" );
371 
372 	trap_R_RegisterShaderNoMip( "axis_soldier" );
373 	trap_R_RegisterShaderNoMip( "axis_medic" );
374 	trap_R_RegisterShaderNoMip( "axis_eng" );
375 	trap_R_RegisterShaderNoMip( "axis_lt" );
376 
377 	trap_R_RegisterShaderNoMip( "allied_soldier" );
378 	trap_R_RegisterShaderNoMip( "allied_medic" );
379 	trap_R_RegisterShaderNoMip( "allied_eng" );
380 	trap_R_RegisterShaderNoMip( "allied_lt" );
381 
382 	trap_R_RegisterShaderNoMip( "multi_spectator" );
383 
384 	trap_R_RegisterShaderNoMip( "ui_mp/assets/button_click.tga" );
385 	trap_R_RegisterShaderNoMip( "ui_mp/assets/button.tga" );
386 
387 	trap_R_RegisterShaderNoMip( "ui_mp/assets/ger_flag.tga" );
388 	trap_R_RegisterShaderNoMip( "ui_mp/assets/usa_flag.tga" );
389 
390 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_syringe.tga" );
391 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_medheal.tga" );
392 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_pliers.tga" );
393 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_dynamite.tga" );
394 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_smokegrenade.tga" );
395 	trap_R_RegisterShaderNoMip( "ui_mp/assets/weapon_ammo.tga" );
396 
397 	for ( n = 1; weaponTypes[n].name; n++ ) {
398 		if ( weaponTypes[n].name ) {
399 			trap_R_RegisterShaderNoMip( weaponTypes[n].name );
400 		}
401 	}
402 	// -NERVE - SMF
403 }
404 
_UI_DrawSides(float x,float y,float w,float h,float size)405 void _UI_DrawSides( float x, float y, float w, float h, float size ) {
406 	UI_AdjustFrom640( &x, &y, &w, &h );
407 	size *= uiInfo.uiDC.xscale;
408 	trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
409 	trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
410 }
411 
_UI_DrawTopBottom(float x,float y,float w,float h,float size)412 void _UI_DrawTopBottom( float x, float y, float w, float h, float size ) {
413 	UI_AdjustFrom640( &x, &y, &w, &h );
414 	size *= uiInfo.uiDC.yscale;
415 	trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
416 	trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
417 }
418 /*
419 ================
420 UI_DrawRect
421 
422 Coordinates are 640*480 virtual values
423 =================
424 */
_UI_DrawRect(float x,float y,float width,float height,float size,const float * color)425 void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
426 	trap_R_SetColor( color );
427 
428 	_UI_DrawTopBottom( x, y, width, height, size );
429 	_UI_DrawSides( x, y, width, height, size );
430 
431 	trap_R_SetColor( NULL );
432 }
433 
434 
435 
436 // NERVE - SMF
Text_SetActiveFont(int font)437 void Text_SetActiveFont( int font ) {
438 	uiInfo.activeFont = font;
439 }
440 
441 
Text_Width(const char * text,float scale,int limit)442 int Text_Width( const char *text, float scale, int limit ) {
443 	int count,len;
444 	float out;
445 	glyphInfo_t *glyph;
446 	float useScale;
447 	const char *s = text;
448 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
449 
450 	// NERVE - SMF
451 	if ( uiInfo.activeFont == UI_FONT_DEFAULT ) {
452 		if ( scale <= ui_smallFont.value ) {
453 			font = &uiInfo.uiDC.Assets.smallFont;
454 		} else if ( scale >= ui_bigFont.value ) {
455 			font = &uiInfo.uiDC.Assets.bigFont;
456 		}
457 	} else {
458 		switch ( uiInfo.activeFont ) {
459 		case UI_FONT_NORMAL:
460 			font = &uiInfo.uiDC.Assets.textFont;
461 			break;
462 		case UI_FONT_BIG:
463 			font = &uiInfo.uiDC.Assets.bigFont;
464 			break;
465 		case UI_FONT_SMALL:
466 			font = &uiInfo.uiDC.Assets.smallFont;
467 			break;
468 		default:
469 			font = &uiInfo.uiDC.Assets.textFont;
470 		}
471 	}
472 	useScale = scale * font->glyphScale;
473 	// -NERVE - SMF
474 
475 	out = 0;
476 	if ( text ) {
477 		len = strlen( text );
478 		if ( limit > 0 && len > limit ) {
479 			len = limit;
480 		}
481 		count = 0;
482 		while ( s && *s && count < len ) {
483 			if ( Q_IsColorString( s ) ) {
484 				s += 2;
485 				continue;
486 			} else {
487 				glyph = &font->glyphs[*s & 255];
488 				out += glyph->xSkip;
489 				s++;
490 				count++;
491 			}
492 		}
493 	}
494 	return out * useScale;
495 }
496 
Text_Height(const char * text,float scale,int limit)497 int Text_Height( const char *text, float scale, int limit ) {
498 	int len, count;
499 	float max;
500 	glyphInfo_t *glyph;
501 	float useScale;
502 	const char *s = text;
503 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
504 	if ( scale <= ui_smallFont.value ) {
505 		font = &uiInfo.uiDC.Assets.smallFont;
506 	} else if ( scale >= ui_bigFont.value ) {
507 		font = &uiInfo.uiDC.Assets.bigFont;
508 	}
509 	useScale = scale * font->glyphScale;
510 	max = 0;
511 	if ( text ) {
512 		len = strlen( text );
513 		if ( limit > 0 && len > limit ) {
514 			len = limit;
515 		}
516 		count = 0;
517 		while ( s && *s && count < len ) {
518 			if ( Q_IsColorString( s ) ) {
519 				s += 2;
520 				continue;
521 			} else {
522 				glyph = &font->glyphs[*s & 255];
523 				if ( max < glyph->height ) {
524 					max = glyph->height;
525 				}
526 				s++;
527 				count++;
528 			}
529 		}
530 	}
531 	return max * useScale;
532 }
533 
Text_PaintChar(float x,float y,float width,float height,float scale,float s,float t,float s2,float t2,qhandle_t hShader)534 void Text_PaintChar( float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader ) {
535 	float w, h;
536 	w = width * scale;
537 	h = height * scale;
538 	UI_AdjustFrom640( &x, &y, &w, &h );
539 	trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
540 }
541 
Text_Paint(float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit,int style)542 void Text_Paint( float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style ) {
543 	int len, count;
544 	vec4_t newColor;
545 	glyphInfo_t *glyph;
546 	float useScale;
547 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
548 	int index;
549 
550 	// NERVE - SMF
551 	if ( uiInfo.activeFont == UI_FONT_DEFAULT ) {
552 		if ( scale <= ui_smallFont.value ) {
553 			font = &uiInfo.uiDC.Assets.smallFont;
554 		} else if ( scale >= ui_bigFont.value ) {
555 			font = &uiInfo.uiDC.Assets.bigFont;
556 		}
557 	} else {
558 		switch ( uiInfo.activeFont ) {
559 		case UI_FONT_NORMAL:
560 			font = &uiInfo.uiDC.Assets.textFont;
561 			break;
562 		case UI_FONT_BIG:
563 			font = &uiInfo.uiDC.Assets.bigFont;
564 			break;
565 		case UI_FONT_SMALL:
566 			font = &uiInfo.uiDC.Assets.smallFont;
567 			break;
568 		default:
569 			font = &uiInfo.uiDC.Assets.textFont;
570 		}
571 	}
572 	useScale = scale * font->glyphScale;
573 	// -NERVE - SMF
574 
575 	if ( text ) {
576 		const char *s = text;
577 		trap_R_SetColor( color );
578 		memcpy( &newColor[0], &color[0], sizeof( vec4_t ) );
579 		len = strlen( text );
580 		if ( limit > 0 && len > limit ) {
581 			len = limit;
582 		}
583 		count = 0;
584 		while ( s && *s && count < len ) {
585 			index = *s;
586 
587 			// NERVE - SMF - don't draw tabs and newlines
588 			if ( index < 20 ) {
589 				s++;
590 				count++;
591 				continue;
592 			}
593 
594 			glyph = &font->glyphs[index & 255];
595 			if ( Q_IsColorString( s ) ) {
596 				memcpy( newColor, g_color_table[ColorIndex( *( s + 1 ) )], sizeof( newColor ) );
597 				newColor[3] = color[3];
598 				trap_R_SetColor( newColor );
599 				s += 2;
600 				continue;
601 			} else {
602 				float yadj = useScale * glyph->top;
603 				if ( style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE ) {
604 					int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
605 					colorBlack[3] = newColor[3];
606 					trap_R_SetColor( colorBlack );
607 					Text_PaintChar( x + ofs, y - yadj + ofs,
608 									glyph->imageWidth,
609 									glyph->imageHeight,
610 									useScale,
611 									glyph->s,
612 									glyph->t,
613 									glyph->s2,
614 									glyph->t2,
615 									glyph->glyph );
616 					trap_R_SetColor( newColor );
617 					colorBlack[3] = 1.0;
618 				}
619 				Text_PaintChar( x, y - yadj,
620 								glyph->imageWidth,
621 								glyph->imageHeight,
622 								useScale,
623 								glyph->s,
624 								glyph->t,
625 								glyph->s2,
626 								glyph->t2,
627 								glyph->glyph );
628 
629 				x += ( glyph->xSkip * useScale ) + adjust;
630 				s++;
631 				count++;
632 			}
633 		}
634 		trap_R_SetColor( NULL );
635 	}
636 }
637 
638 // copied over from Text_Paint
639 // we use the bulk of Text_Paint to determine were we will hit the max width
640 // can be used for actual text printing, or dummy run to get the number of lines
641 // returns the next char to be printed after wrap, or the ending \0 of the string
642 // NOTE: this is clearly non-optimal implementation, see Item_Text_AutoWrap_Paint for one
643 // if color_save != NULL, use to keep track of the current color between wraps
Text_AutoWrap_Paint_Chunk(float x,float y,int width,float scale,vec4_t color,char * text,float adjust,int limit,int style,qboolean dummy,vec4_t color_save)644 char* Text_AutoWrap_Paint_Chunk( float x, float y, int width, float scale, vec4_t color, char *text, float adjust, int limit, int style, qboolean dummy, vec4_t color_save ) {
645 	int len = 0, count;
646 	vec4_t newColor;
647 	glyphInfo_t *glyph;
648 	float useScale;
649 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
650 	int index;
651 	char *wrap_point = NULL;
652 
653 	float wrap_x = x + width;
654 
655 	// NERVE - SMF
656 	if ( uiInfo.activeFont == UI_FONT_DEFAULT ) {
657 		if ( scale <= ui_smallFont.value ) {
658 			font = &uiInfo.uiDC.Assets.smallFont;
659 		} else if ( scale >= ui_bigFont.value ) {
660 			font = &uiInfo.uiDC.Assets.bigFont;
661 		}
662 	} else {
663 		switch ( uiInfo.activeFont ) {
664 		case UI_FONT_NORMAL:
665 			font = &uiInfo.uiDC.Assets.textFont;
666 			break;
667 		case UI_FONT_BIG:
668 			font = &uiInfo.uiDC.Assets.bigFont;
669 			break;
670 		case UI_FONT_SMALL:
671 			font = &uiInfo.uiDC.Assets.smallFont;
672 			break;
673 		default:
674 			font = &uiInfo.uiDC.Assets.textFont;
675 		}
676 	}
677 	useScale = scale * font->glyphScale;
678 	// -NERVE - SMF
679 
680 	if ( text ) {
681 		char *s = text;
682 		trap_R_SetColor( color );
683 		memcpy( &newColor[0], &color[0], sizeof( vec4_t ) );
684 		len = strlen( text );
685 		if ( limit > 0 && len > limit ) {
686 			len = limit;
687 		}
688 		count = 0;
689 		while ( s && *s && count < len ) {
690 			index = *s;
691 			if ( *s == ' ' || *s == '\t' || *s == '\n' ) {
692 				wrap_point = s;
693 			}
694 
695 			// NERVE - SMF - don't draw tabs and newlines
696 			if ( index < 20 ) {
697 				s++;
698 				count++;
699 				continue;
700 			}
701 
702 			glyph = &font->glyphs[index & 255];
703 			if ( Q_IsColorString( s ) ) {
704 				memcpy( newColor, g_color_table[ColorIndex( *( s + 1 ) )], sizeof( newColor ) );
705 				newColor[3] = color[3];
706 				if ( !dummy ) {
707 					trap_R_SetColor( newColor );
708 				}
709 				if ( color_save ) {
710 					memcpy( &color_save[0], &newColor[0], sizeof( vec4_t ) );
711 				}
712 				s += 2;
713 				continue;
714 			} else {
715 				float yadj = useScale * glyph->top;
716 
717 				if ( x + ( glyph->xSkip * useScale ) + adjust > wrap_x ) {
718 					if ( wrap_point ) {
719 						return wrap_point + 1; // the next char to be printed after line wrap
720 					}
721 					// we haven't found the wrap point .. cut
722 					return s;
723 				}
724 
725 				if ( !dummy ) {
726 					if ( style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE ) {
727 						int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
728 						colorBlack[3] = newColor[3];
729 						trap_R_SetColor( colorBlack );
730 						Text_PaintChar( x + ofs, y - yadj + ofs,
731 										glyph->imageWidth,
732 										glyph->imageHeight,
733 										useScale,
734 										glyph->s,
735 										glyph->t,
736 										glyph->s2,
737 										glyph->t2,
738 										glyph->glyph );
739 						trap_R_SetColor( newColor );
740 						colorBlack[3] = 1.0;
741 					}
742 					Text_PaintChar( x, y - yadj,
743 									glyph->imageWidth,
744 									glyph->imageHeight,
745 									useScale,
746 									glyph->s,
747 									glyph->t,
748 									glyph->s2,
749 									glyph->t2,
750 									glyph->glyph );
751 				}
752 
753 				x += ( glyph->xSkip * useScale ) + adjust;
754 				s++;
755 				count++;
756 			}
757 		}
758 		if ( !dummy ) {
759 			trap_R_SetColor( NULL );
760 		}
761 	}
762 	return text + len;
763 }
764 
765 // count the lines that we will need to have to print with the given wrap parameters
Count_Text_AutoWrap_Paint(float x,float y,int width,float scale,vec4_t color,const char * text,float adjust,int style)766 int Count_Text_AutoWrap_Paint( float x, float y, int width, float scale, vec4_t color, const char *text, float adjust, int style ) {
767 	const char *ret, *end;
768 	int i = 0;
769 
770 	ret = text;
771 	end = text + strlen( text );
772 
773 	do
774 	{
775 		ret = Text_AutoWrap_Paint_Chunk( x, y, width, scale, color, (char *)ret, adjust, 0, style, qtrue, NULL );
776 		i++;
777 	} while ( ret < end );
778 
779 	return i;
780 }
781 
Text_AutoWrap_Paint(float x,float y,int width,int height,float scale,vec4_t color,const char * l_text,float adjust,int style)782 void Text_AutoWrap_Paint( float x, float y, int width, int height, float scale, vec4_t color, const char *l_text, float adjust, int style ) {
783 	char text[1024];
784 	char *ret, *end, *next;
785 	char s;
786 	vec4_t aux_color, next_color;
787 
788 	Q_strncpyz( text, l_text, sizeof( text ) - 1 );
789 	ret = text;
790 	end = text + strlen( text );
791 	memcpy( &aux_color[0], &color[0], sizeof( vec4_t ) );
792 
793 	do
794 	{
795 		// one run to get the word wrap
796 		next = Text_AutoWrap_Paint_Chunk( x, y, width, scale, aux_color, ret, adjust, 0, style, qtrue, next_color );
797 		// now print - hack around a bit to avoid the word wrapped chars
798 		s = *next; *next = '\0';
799 		Text_Paint( x, y, scale, aux_color, ret, adjust, 0, style );
800 		*next = s;
801 		ret = next;
802 		memcpy( &aux_color[0], &next_color[0], sizeof( vec4_t ) );
803 		y += height;
804 	} while ( ret < end );
805 }
806 
Text_PaintWithCursor(float x,float y,float scale,vec4_t color,const char * text,int cursorPos,char cursor,int limit,int style)807 void Text_PaintWithCursor( float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style ) {
808 	int len, count;
809 	vec4_t newColor;
810 	glyphInfo_t *glyph, *glyph2;
811 	float yadj;
812 	float useScale;
813 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
814 
815 	// NERVE - SMF
816 	if ( uiInfo.activeFont == UI_FONT_DEFAULT ) {
817 		if ( scale <= ui_smallFont.value ) {
818 			font = &uiInfo.uiDC.Assets.smallFont;
819 		} else if ( scale >= ui_bigFont.value ) {
820 			font = &uiInfo.uiDC.Assets.bigFont;
821 		}
822 	} else {
823 		switch ( uiInfo.activeFont ) {
824 		case UI_FONT_NORMAL:
825 			font = &uiInfo.uiDC.Assets.textFont;
826 			break;
827 		case UI_FONT_BIG:
828 			font = &uiInfo.uiDC.Assets.bigFont;
829 			break;
830 		case UI_FONT_SMALL:
831 			font = &uiInfo.uiDC.Assets.smallFont;
832 			break;
833 		default:
834 			font = &uiInfo.uiDC.Assets.textFont;
835 		}
836 	}
837 	useScale = scale * font->glyphScale;
838 	// -NERVE - SMF
839 
840 	if ( text ) {
841 		const char *s = text;
842 		trap_R_SetColor( color );
843 		memcpy( &newColor[0], &color[0], sizeof( vec4_t ) );
844 		len = strlen( text );
845 		if ( limit > 0 && len > limit ) {
846 			len = limit;
847 		}
848 		count = 0;
849 		glyph2 = &font->glyphs[cursor & 255];
850 		while ( s && *s && count < len ) {
851 			glyph = &font->glyphs[*s & 255];
852 			//int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
853 			//float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
854 			if ( Q_IsColorString( s ) ) {
855 				memcpy( newColor, g_color_table[ColorIndex( *( s + 1 ) )], sizeof( newColor ) );
856 				newColor[3] = color[3];
857 				trap_R_SetColor( newColor );
858 				s += 2;
859 				continue;
860 			} else {
861 				yadj = useScale * glyph->top;
862 				if ( style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE ) {
863 					int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
864 					colorBlack[3] = newColor[3];
865 					trap_R_SetColor( colorBlack );
866 					Text_PaintChar( x + ofs, y - yadj + ofs,
867 									glyph->imageWidth,
868 									glyph->imageHeight,
869 									useScale,
870 									glyph->s,
871 									glyph->t,
872 									glyph->s2,
873 									glyph->t2,
874 									glyph->glyph );
875 					colorBlack[3] = 1.0;
876 					trap_R_SetColor( newColor );
877 				}
878 				Text_PaintChar( x, y - yadj,
879 								glyph->imageWidth,
880 								glyph->imageHeight,
881 								useScale,
882 								glyph->s,
883 								glyph->t,
884 								glyph->s2,
885 								glyph->t2,
886 								glyph->glyph );
887 
888 				// CG_DrawPic(x, y - yadj, scale * uiDC.Assets.textFont.glyphs[text[i]].imageWidth, scale * uiDC.Assets.textFont.glyphs[text[i]].imageHeight, uiDC.Assets.textFont.glyphs[text[i]].glyph);
889 				yadj = useScale * glyph2->top;
890 				if ( count == cursorPos && !( ( uiInfo.uiDC.realTime / BLINK_DIVISOR ) & 1 ) ) {
891 					Text_PaintChar( x, y - yadj,
892 									glyph2->imageWidth,
893 									glyph2->imageHeight,
894 									useScale,
895 									glyph2->s,
896 									glyph2->t,
897 									glyph2->s2,
898 									glyph2->t2,
899 									glyph2->glyph );
900 				}
901 
902 				x += ( glyph->xSkip * useScale );
903 				s++;
904 				count++;
905 			}
906 		}
907 		// need to paint cursor at end of text
908 		if ( cursorPos == len && !( ( uiInfo.uiDC.realTime / BLINK_DIVISOR ) & 1 ) ) {
909 			yadj = useScale * glyph2->top;
910 			Text_PaintChar( x, y - yadj,
911 							glyph2->imageWidth,
912 							glyph2->imageHeight,
913 							useScale,
914 							glyph2->s,
915 							glyph2->t,
916 							glyph2->s2,
917 							glyph2->t2,
918 							glyph2->glyph );
919 
920 		}
921 
922 
923 		trap_R_SetColor( NULL );
924 	}
925 }
926 
927 
Text_Paint_Limit(float * maxX,float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit)928 static void Text_Paint_Limit( float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit ) {
929 	int len, count;
930 	vec4_t newColor;
931 	glyphInfo_t *glyph;
932 	if ( text ) {
933 		const char *s = text;
934 		float max = *maxX;
935 		float useScale;
936 		fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
937 
938 		// NERVE - SMF
939 		if ( uiInfo.activeFont == UI_FONT_DEFAULT ) {
940 			if ( scale <= ui_smallFont.value ) {
941 				font = &uiInfo.uiDC.Assets.smallFont;
942 			} else if ( scale >= ui_bigFont.value ) {
943 				font = &uiInfo.uiDC.Assets.bigFont;
944 			}
945 		} else {
946 			switch ( uiInfo.activeFont ) {
947 			case UI_FONT_NORMAL:
948 				font = &uiInfo.uiDC.Assets.textFont;
949 				break;
950 			case UI_FONT_BIG:
951 				font = &uiInfo.uiDC.Assets.bigFont;
952 				break;
953 			case UI_FONT_SMALL:
954 				font = &uiInfo.uiDC.Assets.smallFont;
955 				break;
956 			default:
957 				font = &uiInfo.uiDC.Assets.textFont;
958 			}
959 		}
960 		useScale = scale * font->glyphScale;
961 		// -NERVE - SMF
962 
963 		trap_R_SetColor( color );
964 		len = strlen( text );
965 		if ( limit > 0 && len > limit ) {
966 			len = limit;
967 		}
968 		count = 0;
969 		while ( s && *s && count < len ) {
970 			glyph = &font->glyphs[*s & 255];
971 			if ( Q_IsColorString( s ) ) {
972 				memcpy( newColor, g_color_table[ColorIndex( *( s + 1 ) )], sizeof( newColor ) );
973 				newColor[3] = color[3];
974 				trap_R_SetColor( newColor );
975 				s += 2;
976 				continue;
977 			} else {
978 				float yadj = useScale * glyph->top;
979 				if ( Text_Width( s, scale, 1 ) + x > max ) {
980 					*maxX = 0;
981 					break;
982 				}
983 				Text_PaintChar( x, y - yadj,
984 								glyph->imageWidth,
985 								glyph->imageHeight,
986 								useScale,
987 								glyph->s,
988 								glyph->t,
989 								glyph->s2,
990 								glyph->t2,
991 								glyph->glyph );
992 				x += ( glyph->xSkip * useScale ) + adjust;
993 				*maxX = x;
994 				count++;
995 				s++;
996 			}
997 		}
998 		trap_R_SetColor( NULL );
999 	}
1000 
1001 }
1002 
1003 
UI_ShowPostGame(qboolean newHigh)1004 void UI_ShowPostGame( qboolean newHigh ) {
1005 	trap_Cvar_Set( "cg_cameraOrbit", "0" );
1006 	trap_Cvar_Set( "cg_thirdPerson", "0" );
1007 	uiInfo.soundHighScore = newHigh;
1008 	_UI_SetActiveMenu( UIMENU_POSTGAME );
1009 }
1010 /*
1011 =================
1012 _UI_Refresh
1013 =================
1014 */
1015 
UI_DrawCenteredPic(qhandle_t image,int w,int h)1016 void UI_DrawCenteredPic( qhandle_t image, int w, int h ) {
1017 	int x, y;
1018 	x = ( SCREEN_WIDTH - w ) / 2;
1019 	y = ( SCREEN_HEIGHT - h ) / 2;
1020 	UI_DrawHandlePic( x, y, w, h, image );
1021 }
1022 
1023 int frameCount = 0;
1024 int startTime;
1025 
1026 #define UI_FPS_FRAMES   4
_UI_Refresh(int realtime)1027 void _UI_Refresh( int realtime ) {
1028 	static int index;
1029 	static int previousTimes[UI_FPS_FRAMES];
1030 
1031 	//if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
1032 	//	return;
1033 	//}
1034 
1035 	uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
1036 	uiInfo.uiDC.realTime = realtime;
1037 
1038 	previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
1039 	index++;
1040 	if ( index > UI_FPS_FRAMES ) {
1041 		int i, total;
1042 		// average multiple frames together to smooth changes out a bit
1043 		total = 0;
1044 		for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
1045 			total += previousTimes[i];
1046 		}
1047 		if ( !total ) {
1048 			total = 1;
1049 		}
1050 		uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
1051 	}
1052 
1053 
1054 
1055 	UI_UpdateCvars();
1056 
1057 	if ( Menu_Count() > 0 ) {
1058 		// paint all the menus
1059 		Menu_PaintAll();
1060 		// refresh server browser list
1061 		UI_DoServerRefresh();
1062 		// refresh server status
1063 		UI_BuildServerStatus( qfalse );
1064 		// refresh find player list
1065 		UI_BuildFindPlayerList( qfalse );
1066 	}
1067 
1068 	// draw cursor
1069 	UI_SetColor( NULL );
1070 	if (Menu_Count() > 0 && (trap_Key_GetCatcher() & KEYCATCH_UI)) {
1071 		UI_DrawHandlePic( uiInfo.uiDC.cursorx - 16, uiInfo.uiDC.cursory - 16, 32, 32, uiInfo.uiDC.Assets.cursor );
1072 	}
1073 
1074 #ifndef NDEBUG
1075 	if ( uiInfo.uiDC.debug ) {
1076 		// cursor coordinates
1077 		//FIXME
1078 		//UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
1079 	}
1080 #endif
1081 
1082 }
1083 
1084 /*
1085 =================
1086 _UI_Shutdown
1087 =================
1088 */
_UI_Shutdown(void)1089 void _UI_Shutdown( void ) {
1090 	trap_LAN_SaveCachedServers();
1091 }
1092 
1093 char *defaultMenu = NULL;
1094 
GetMenuBuffer(const char * filename)1095 char *GetMenuBuffer( const char *filename ) {
1096 	int len;
1097 	fileHandle_t f;
1098 	static char buf[MAX_MENUFILE];
1099 
1100 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
1101 	if ( !f ) {
1102 		trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
1103 		return defaultMenu;
1104 	}
1105 	if ( len >= MAX_MENUFILE ) {
1106 		trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
1107 		trap_FS_FCloseFile( f );
1108 		return defaultMenu;
1109 	}
1110 
1111 	trap_FS_Read( buf, len, f );
1112 	buf[len] = 0;
1113 	trap_FS_FCloseFile( f );
1114 	//COM_Compress(buf);
1115 	return buf;
1116 
1117 }
1118 
Asset_Parse(int handle)1119 qboolean Asset_Parse( int handle ) {
1120 	pc_token_t token;
1121 	const char *tempStr;
1122 
1123 	if ( !trap_PC_ReadToken( handle, &token ) ) {
1124 		return qfalse;
1125 	}
1126 	if ( Q_stricmp( token.string, "{" ) != 0 ) {
1127 		return qfalse;
1128 	}
1129 
1130 	while ( 1 ) {
1131 
1132 		memset( &token, 0, sizeof( pc_token_t ) );
1133 
1134 		if ( !trap_PC_ReadToken( handle, &token ) ) {
1135 			return qfalse;
1136 		}
1137 
1138 		if ( Q_stricmp( token.string, "}" ) == 0 ) {
1139 			return qtrue;
1140 		}
1141 
1142 		// font
1143 		if ( Q_stricmp( token.string, "font" ) == 0 ) {
1144 			int pointSize;
1145 			if ( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle,&pointSize ) ) {
1146 				return qfalse;
1147 			}
1148 			trap_R_RegisterFont( tempStr, pointSize, &uiInfo.uiDC.Assets.textFont );
1149 			uiInfo.uiDC.Assets.fontRegistered = qtrue;
1150 			continue;
1151 		}
1152 
1153 		if ( Q_stricmp( token.string, "smallFont" ) == 0 ) {
1154 			int pointSize;
1155 			if ( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle,&pointSize ) ) {
1156 				return qfalse;
1157 			}
1158 			trap_R_RegisterFont( tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont );
1159 			continue;
1160 		}
1161 
1162 		if ( Q_stricmp( token.string, "bigFont" ) == 0 ) {
1163 			int pointSize;
1164 			if ( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle,&pointSize ) ) {
1165 				return qfalse;
1166 			}
1167 			trap_R_RegisterFont( tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont );
1168 			continue;
1169 		}
1170 
1171 
1172 		// gradientbar
1173 		if ( Q_stricmp( token.string, "gradientbar" ) == 0 ) {
1174 			if ( !PC_String_Parse( handle, &tempStr ) ) {
1175 				return qfalse;
1176 			}
1177 			uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( tempStr );
1178 			continue;
1179 		}
1180 
1181 		// enterMenuSound
1182 		if ( Q_stricmp( token.string, "menuEnterSound" ) == 0 ) {
1183 			if ( !PC_String_Parse( handle, &tempStr ) ) {
1184 				return qfalse;
1185 			}
1186 			uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr );
1187 			continue;
1188 		}
1189 
1190 		// exitMenuSound
1191 		if ( Q_stricmp( token.string, "menuExitSound" ) == 0 ) {
1192 			if ( !PC_String_Parse( handle, &tempStr ) ) {
1193 				return qfalse;
1194 			}
1195 			uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr );
1196 			continue;
1197 		}
1198 
1199 		// itemFocusSound
1200 		if ( Q_stricmp( token.string, "itemFocusSound" ) == 0 ) {
1201 			if ( !PC_String_Parse( handle, &tempStr ) ) {
1202 				return qfalse;
1203 			}
1204 			uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr );
1205 			continue;
1206 		}
1207 
1208 		// menuBuzzSound
1209 		if ( Q_stricmp( token.string, "menuBuzzSound" ) == 0 ) {
1210 			if ( !PC_String_Parse( handle, &tempStr ) ) {
1211 				return qfalse;
1212 			}
1213 			uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr );
1214 			continue;
1215 		}
1216 
1217 		if ( Q_stricmp( token.string, "cursor" ) == 0 ) {
1218 			if ( !PC_String_Parse( handle, &uiInfo.uiDC.Assets.cursorStr ) ) {
1219 				return qfalse;
1220 			}
1221 			uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr );
1222 			continue;
1223 		}
1224 
1225 		if ( Q_stricmp( token.string, "fadeClamp" ) == 0 ) {
1226 			if ( !PC_Float_Parse( handle, &uiInfo.uiDC.Assets.fadeClamp ) ) {
1227 				return qfalse;
1228 			}
1229 			continue;
1230 		}
1231 
1232 		if ( Q_stricmp( token.string, "fadeCycle" ) == 0 ) {
1233 			if ( !PC_Int_Parse( handle, &uiInfo.uiDC.Assets.fadeCycle ) ) {
1234 				return qfalse;
1235 			}
1236 			continue;
1237 		}
1238 
1239 		if ( Q_stricmp( token.string, "fadeAmount" ) == 0 ) {
1240 			if ( !PC_Float_Parse( handle, &uiInfo.uiDC.Assets.fadeAmount ) ) {
1241 				return qfalse;
1242 			}
1243 			continue;
1244 		}
1245 
1246 		if ( Q_stricmp( token.string, "shadowX" ) == 0 ) {
1247 			if ( !PC_Float_Parse( handle, &uiInfo.uiDC.Assets.shadowX ) ) {
1248 				return qfalse;
1249 			}
1250 			continue;
1251 		}
1252 
1253 		if ( Q_stricmp( token.string, "shadowY" ) == 0 ) {
1254 			if ( !PC_Float_Parse( handle, &uiInfo.uiDC.Assets.shadowY ) ) {
1255 				return qfalse;
1256 			}
1257 			continue;
1258 		}
1259 
1260 		if ( Q_stricmp( token.string, "shadowColor" ) == 0 ) {
1261 			if ( !PC_Color_Parse( handle, &uiInfo.uiDC.Assets.shadowColor ) ) {
1262 				return qfalse;
1263 			}
1264 			uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
1265 			continue;
1266 		}
1267 
1268 	}
1269 	return qfalse;
1270 }
1271 
Font_Report(void)1272 void Font_Report( void ) {
1273 	int i;
1274 	Com_Printf( "Font Info\n" );
1275 	Com_Printf( "=========\n" );
1276 	for ( i = 32; i < 96; i++ ) {
1277 		Com_Printf( "Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph );
1278 	}
1279 }
1280 
UI_Report(void)1281 void UI_Report( void ) {
1282 	String_Report();
1283 	//Font_Report();
1284 
1285 }
1286 
1287 void QDECL Com_DPrintf( const char *fmt, ... ) __attribute__ ( ( format ( printf, 1, 2 ) ) );
UI_ParseMenu(const char * menuFile)1288 qboolean UI_ParseMenu( const char *menuFile ) {
1289 	int handle;
1290 	pc_token_t token;
1291 
1292 	Com_DPrintf( "Parsing menu file: %s\n", menuFile );
1293 
1294 	handle = trap_PC_LoadSource( menuFile );
1295 	if ( !handle ) {
1296 		return qfalse;
1297 	}
1298 
1299 	while ( 1 ) {
1300 		memset( &token, 0, sizeof( pc_token_t ) );
1301 		if ( !trap_PC_ReadToken( handle, &token ) ) {
1302 			break;
1303 		}
1304 
1305 		//if ( Q_stricmp( token, "{" ) ) {
1306 		//	Com_Printf( "Missing { in menu file\n" );
1307 		//	break;
1308 		//}
1309 
1310 		//if ( menuCount == MAX_MENUS ) {
1311 		//	Com_Printf( "Too many menus!\n" );
1312 		//	break;
1313 		//}
1314 
1315 		if ( token.string[0] == '}' ) {
1316 			break;
1317 		}
1318 
1319 		if ( Q_stricmp( token.string, "assetGlobalDef" ) == 0 ) {
1320 			if ( Asset_Parse( handle ) ) {
1321 				continue;
1322 			} else {
1323 				break;
1324 			}
1325 		}
1326 
1327 		if ( Q_stricmp( token.string, "menudef" ) == 0 ) {
1328 			// start a new menu
1329 			Menu_New( handle );
1330 		}
1331 	}
1332 	trap_PC_FreeSource( handle );
1333 	return qtrue;
1334 }
1335 
Load_Menu(int handle)1336 qboolean Load_Menu( int handle ) {
1337 	pc_token_t token;
1338 	int cl_language;    // NERVE - SMF
1339 
1340 	if ( !trap_PC_ReadToken( handle, &token ) ) {
1341 		return qfalse;
1342 	}
1343 	if ( token.string[0] != '{' ) {
1344 		return qfalse;
1345 	}
1346 
1347 	while ( 1 ) {
1348 
1349 		if ( !trap_PC_ReadToken( handle, &token ) ) {
1350 			return qfalse;
1351 		}
1352 
1353 		if ( token.string[0] == 0 ) {
1354 			return qfalse;
1355 		}
1356 
1357 		if ( token.string[0] == '}' ) {
1358 			return qtrue;
1359 		}
1360 
1361 		// NERVE - SMF - localization crap
1362 		cl_language = atoi( UI_Cvar_VariableString( "cl_language" ) );
1363 
1364 		if ( cl_language ) {
1365 			const char *s = NULL; // TTimo: init
1366 			const char *filename;
1367 			char out[256];
1368 //			char filename[256];
1369 
1370 			COM_StripFilename( token.string, out );
1371 
1372 			filename = COM_SkipPath( token.string );
1373 
1374 			if ( cl_language == 1 ) {
1375 				s = va( "%s%s", out, "french/" );
1376 			} else if ( cl_language == 2 ) {
1377 				s = va( "%s%s", out, "german/" );
1378 			} else if ( cl_language == 3 ) {
1379 				s = va( "%s%s", out, "italian/" );
1380 			} else if ( cl_language == 4 ) {
1381 				s = va( "%s%s", out, "spanish/" );
1382 			}
1383 
1384 			if ( UI_ParseMenu( va( "%s%s", s, filename ) ) ) {
1385 				continue;
1386 			}
1387 		}
1388 		// -NERVE
1389 
1390 		UI_ParseMenu( token.string );
1391 	}
1392 	return qfalse;
1393 }
1394 
UI_LoadMenus(const char * menuFile,qboolean reset)1395 void UI_LoadMenus( const char *menuFile, qboolean reset ) {
1396 	pc_token_t token;
1397 	int handle;
1398 	int start;
1399 
1400 	start = trap_Milliseconds();
1401 
1402 	handle = trap_PC_LoadSource( menuFile );
1403 	if ( !handle ) {
1404 		Com_Printf( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile );
1405 		handle = trap_PC_LoadSource( "ui_mp/menus.txt" );
1406 		if ( !handle ) {
1407 			trap_Error( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!" );
1408 		}
1409 	}
1410 
1411 	ui_new.integer = 1;
1412 
1413 	if ( reset ) {
1414 		Menu_Reset();
1415 	}
1416 
1417 	while ( 1 ) {
1418 		if ( !trap_PC_ReadToken( handle, &token ) ) {
1419 			break;
1420 		}
1421 		if ( token.string[0] == 0 || token.string[0] == '}' ) {
1422 			break;
1423 		}
1424 
1425 		if ( token.string[0] == '}' ) {
1426 			break;
1427 		}
1428 
1429 		if ( Q_stricmp( token.string, "loadmenu" ) == 0 ) {
1430 			if ( Load_Menu( handle ) ) {
1431 				continue;
1432 			} else {
1433 				break;
1434 			}
1435 		}
1436 	}
1437 
1438 	Com_DPrintf( "UI menu load time = %d milli seconds\n", trap_Milliseconds() - start );
1439 
1440 	trap_PC_FreeSource( handle );
1441 }
1442 
UI_Load(void)1443 void UI_Load( void ) {
1444 	char lastName[1024];
1445 	menuDef_t *menu = Menu_GetFocused();
1446 	char *menuSet = UI_Cvar_VariableString( "ui_menuFiles" );
1447 	if ( menu && menu->window.name ) {
1448 		Q_strncpyz(lastName, menu->window.name, sizeof(lastName));
1449 	}
1450 	if ( menuSet == NULL || menuSet[0] == '\0' ) {
1451 		menuSet = "ui_mp/menus.txt";
1452 	}
1453 
1454 	String_Init();
1455 
1456 	UI_ParseGameInfo( "gameinfo.txt" );
1457 	UI_LoadArenas();
1458 
1459 	UI_LoadMenus( menuSet, qtrue );
1460 	Menus_CloseAll();
1461 	Menus_ActivateByName( lastName, qtrue );
1462 
1463 }
1464 
1465 // Convert ui's net source to AS_* used by trap calls.
UI_SourceForLAN(void)1466 int UI_SourceForLAN(void) {
1467 	switch (ui_netSource.integer) {
1468 		default:
1469 		case UIAS_LOCAL:
1470 			return AS_LOCAL;
1471 		case UIAS_GLOBAL0:
1472 		case UIAS_GLOBAL1:
1473 		case UIAS_GLOBAL2:
1474 		case UIAS_GLOBAL3:
1475 		case UIAS_GLOBAL4:
1476 		case UIAS_GLOBAL5:
1477 			return AS_GLOBAL;
1478 		case UIAS_FAVORITES:
1479 			return AS_FAVORITES;
1480 	}
1481 }
1482 
1483 static const char *handicapValues[] = {"None","95","90","85","80","75","70","65","60","55","50","45","40","35","30","25","20","15","10","5",NULL};
1484 //static int numHandicaps = ARRAY_LEN(handicapValues);
1485 
UI_DrawHandicap(rectDef_t * rect,float scale,vec4_t color,int textStyle)1486 static void UI_DrawHandicap( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1487 	int i, h;
1488 
1489 	h = Com_Clamp( 5, 100, trap_Cvar_VariableValue( "handicap" ) );
1490 	i = 20 - h / 5;
1491 
1492 	Text_Paint( rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle );
1493 }
1494 
UI_DrawClanName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1495 static void UI_DrawClanName( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1496 	Text_Paint( rect->x, rect->y, scale, color, UI_Cvar_VariableString( "ui_teamName" ), 0, 0, textStyle );
1497 }
1498 
1499 
UI_SetCapFragLimits(qboolean uiVars)1500 static void UI_SetCapFragLimits( qboolean uiVars ) {
1501 	//int cap = 5; // TTimo:unused
1502 	//int frag = 10; // TTimo: unused
1503 #ifdef MISSIONPACK
1504 	if ( uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK ) {
1505 		cap = 4;
1506 	} else if ( uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER ) {
1507 		cap = 15;
1508 	}
1509 	if ( uiVars ) {
1510 		trap_Cvar_Set( "ui_captureLimit", va( "%d", cap ) );
1511 		trap_Cvar_Set( "ui_fragLimit", va( "%d", frag ) );
1512 	} else {
1513 		trap_Cvar_Set( "capturelimit", va( "%d", cap ) );
1514 		trap_Cvar_Set( "fraglimit", va( "%d", frag ) );
1515 	}
1516 #endif  // #ifdef MISSIONPACK
1517 }
1518 // ui_gameType assumes gametype 0 is -1 ALL and will not show
UI_DrawGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1519 static void UI_DrawGameType( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1520 	Text_Paint( rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle );
1521 }
1522 
UI_DrawNetGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1523 static void UI_DrawNetGameType( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1524 	if ( ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes ) {
1525 		trap_Cvar_Set( "ui_netGameType", "0" );
1526 		trap_Cvar_Set( "ui_actualNetGameType", "0" );
1527 	}
1528 	Text_Paint( rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType, 0, 0, textStyle );
1529 }
1530 
UI_DrawJoinGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1531 static void UI_DrawJoinGameType( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1532 	if ( ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes ) {
1533 		trap_Cvar_Set( "ui_joinGameType", "0" );
1534 	}
1535 	Text_Paint( rect->x, rect->y, scale, color, UI_TranslateString( uiInfo.joinGameTypes[ui_joinGameType.integer].gameType ), 0, 0, textStyle );
1536 }
1537 
1538 
1539 
UI_TeamIndexFromName(const char * name)1540 static int UI_TeamIndexFromName( const char *name ) {
1541 	int i;
1542 
1543 	if ( name && *name ) {
1544 		for ( i = 0; i < uiInfo.teamCount; i++ ) {
1545 			if ( Q_stricmp( name, uiInfo.teamList[i].teamName ) == 0 ) {
1546 				return i;
1547 			}
1548 		}
1549 	}
1550 
1551 	return 0;
1552 
1553 }
1554 
1555 
1556 /*
1557 ==============
1558 UI_DrawSaveGameShot
1559 ==============
1560 */
UI_DrawSaveGameShot(rectDef_t * rect,float scale,vec4_t color)1561 static void UI_DrawSaveGameShot( rectDef_t *rect, float scale, vec4_t color ) {
1562 	trap_R_SetColor( color );
1563 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.savegameList[uiInfo.savegameIndex].sshotImage );
1564 	trap_R_SetColor( NULL );
1565 }
1566 
1567 
1568 /*
1569 ==============
1570 UI_DrawClanLogo
1571 ==============
1572 */
UI_DrawClanLogo(rectDef_t * rect,float scale,vec4_t color)1573 static void UI_DrawClanLogo( rectDef_t *rect, float scale, vec4_t color ) {
1574 	int i;
1575 	i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
1576 	if ( i >= 0 && i < uiInfo.teamCount ) {
1577 		trap_R_SetColor( color );
1578 
1579 		if ( uiInfo.teamList[i].teamIcon == -1 ) {
1580 			uiInfo.teamList[i].teamIcon         = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
1581 			uiInfo.teamList[i].teamIcon_Metal   = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
1582 			uiInfo.teamList[i].teamIcon_Name    = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
1583 		}
1584 
1585 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1586 		trap_R_SetColor( NULL );
1587 	}
1588 }
1589 
1590 /*
1591 ==============
1592 UI_DrawClanCinematic
1593 ==============
1594 */
UI_DrawClanCinematic(rectDef_t * rect,float scale,vec4_t color)1595 static void UI_DrawClanCinematic( rectDef_t *rect, float scale, vec4_t color ) {
1596 	int i;
1597 	i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
1598 	if ( i >= 0 && i < uiInfo.teamCount ) {
1599 
1600 		if ( uiInfo.teamList[i].cinematic >= -2 ) {
1601 			if ( uiInfo.teamList[i].cinematic == -1 ) {
1602 				uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic( va( "%s.roq", uiInfo.teamList[i].imageName ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
1603 			}
1604 			if ( uiInfo.teamList[i].cinematic >= 0 ) {
1605 				trap_CIN_RunCinematic( uiInfo.teamList[i].cinematic );
1606 
1607 				if ( ui_fixedAspect.integer ) {
1608 					if ( DC->glconfig.vidWidth * 480.0 > DC->glconfig.vidHeight * 640.0 ) {
1609 						float scaledx = rect->x * ( 480.0 / 640.0 ) + ( DC->xBias / DC->xscaleStretch);
1610 						float scaledw = rect->w * ( 480.0 / 640.0 );
1611 
1612 						trap_CIN_SetExtents( uiInfo.teamList[i].cinematic, scaledx, rect->y, scaledw, rect->h );
1613 					} else if ( DC->glconfig.vidWidth * 480.0 < DC->glconfig.vidHeight * 640.0 ) {
1614 						float scaledy = rect->y * ( 480.0 / 640.0 ) + ( DC->yBias / DC->yscaleStretch);
1615 						float scaledh = rect->h * ( 480.0 / 640.0 );
1616 
1617 						trap_CIN_SetExtents( uiInfo.teamList[i].cinematic, rect->x, scaledy, rect->w, scaledh );
1618 					} else {
1619 						trap_CIN_SetExtents( uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h );
1620 					}
1621 				} else {
1622 					trap_CIN_SetExtents( uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h );
1623 				}
1624 
1625 				trap_CIN_DrawCinematic( uiInfo.teamList[i].cinematic );
1626 			} else {
1627 				uiInfo.teamList[i].cinematic = -2;
1628 			}
1629 		} else {
1630 			trap_R_SetColor( color );
1631 			UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1632 			trap_R_SetColor( NULL );
1633 		}
1634 	}
1635 
1636 }
1637 
UI_DrawPreviewCinematic(rectDef_t * rect,float scale,vec4_t color)1638 static void UI_DrawPreviewCinematic( rectDef_t *rect, float scale, vec4_t color ) {
1639 	if ( uiInfo.previewMovie > -2 ) {
1640 		uiInfo.previewMovie = trap_CIN_PlayCinematic( va( "%s.roq", uiInfo.movieList[uiInfo.movieIndex] ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
1641 		if ( uiInfo.previewMovie >= 0 ) {
1642 			trap_CIN_RunCinematic( uiInfo.previewMovie );
1643 
1644 			if ( ui_fixedAspect.integer ) {
1645 				if ( DC->glconfig.vidWidth * 480.0 > DC->glconfig.vidHeight * 640.0 ) {
1646 					float scaledx = rect->x * ( 480.0 / 640.0 ) + ( DC->xBias / DC->xscaleStretch);
1647 					float scaledw = rect->w * ( 480.0 / 640.0 );
1648 
1649 					trap_CIN_SetExtents( uiInfo.previewMovie, scaledx, rect->y, scaledw, rect->h );
1650 				} else if ( DC->glconfig.vidWidth * 480.0 < DC->glconfig.vidHeight * 640.0 ) {
1651 					float scaledy = rect->y * ( 480.0 / 640.0 ) + ( DC->yBias / DC->yscaleStretch);
1652 					float scaledh = rect->h * ( 480.0 / 640.0 );
1653 
1654 					trap_CIN_SetExtents( uiInfo.previewMovie, rect->x, scaledy, rect->w, scaledh );
1655 				} else {
1656 					trap_CIN_SetExtents( uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h );
1657 				}
1658 			} else {
1659 				trap_CIN_SetExtents( uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h );
1660 			}
1661 
1662 			trap_CIN_DrawCinematic( uiInfo.previewMovie );
1663 		} else {
1664 			uiInfo.previewMovie = -2;
1665 		}
1666 	}
1667 
1668 }
1669 
1670 
1671 
UI_DrawSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)1672 static void UI_DrawSkill( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1673 	int i;
1674 	i = trap_Cvar_VariableValue( "g_spSkill" );
1675 	if ( i < 1 || i > numSkillLevels ) {
1676 		i = 1;
1677 	}
1678 	Text_Paint( rect->x, rect->y, scale, color, skillLevels[i - 1],0, 0, textStyle );
1679 }
1680 
1681 
UI_DrawTeamName(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int textStyle)1682 static void UI_DrawTeamName( rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle ) {
1683 	int i;
1684 	i = UI_TeamIndexFromName( UI_Cvar_VariableString( ( blue ) ? "ui_blueTeam" : "ui_redTeam" ) );
1685 	if ( i >= 0 && i < uiInfo.teamCount ) {
1686 		Text_Paint( rect->x, rect->y, scale, color, va( "%s: %s", ( blue ) ? "Blue" : "Red", uiInfo.teamList[i].teamName ),0, 0, textStyle );
1687 	}
1688 }
1689 
UI_DrawTeamMember(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int num,int textStyle)1690 static void UI_DrawTeamMember( rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle ) {
1691 #ifdef MISSIONPACK
1692 	// 0 - None
1693 	// 1 - Human
1694 	// 2..NumCharacters - Bot
1695 	int value = trap_Cvar_VariableValue( va( blue ? "ui_blueteam%i" : "ui_redteam%i", num ) );
1696 	const char *text;
1697 	if ( value <= 0 ) {
1698 		text = "Closed";
1699 	} else if ( value == 1 ) {
1700 		text = "Human";
1701 	} else {
1702 		value -= 2;
1703 
1704 		if ( ui_actualNetGameType.integer >= GT_TEAM ) {
1705 			if ( value >= uiInfo.characterCount ) {
1706 				value = 0;
1707 			}
1708 			text = uiInfo.characterList[value].name;
1709 		} else {
1710 			if ( value >= UI_GetNumBots() ) {
1711 				value = 0;
1712 			}
1713 			text = UI_GetBotNameByNumber( value );
1714 		}
1715 	}
1716 	Text_Paint( rect->x, rect->y, scale, color, text, 0, 0, textStyle );
1717 #endif  // #ifdef MISSIONPACK
1718 }
1719 
UI_DrawEffects(rectDef_t * rect,float scale,vec4_t color)1720 static void UI_DrawEffects( rectDef_t *rect, float scale, vec4_t color ) {
1721 	UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
1722 	UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
1723 }
1724 
UI_DrawMapPreview(rectDef_t * rect,float scale,vec4_t color,qboolean net)1725 static void UI_DrawMapPreview( rectDef_t *rect, float scale, vec4_t color, qboolean net ) {
1726 	int map = ( net ) ? ui_currentNetMap.integer : ui_currentMap.integer;
1727 	if ( map < 0 || map > uiInfo.mapCount ) {
1728 		if ( net ) {
1729 			ui_currentNetMap.integer = 0;
1730 			trap_Cvar_Set( "ui_currentNetMap", "0" );
1731 		} else {
1732 			ui_currentMap.integer = 0;
1733 			trap_Cvar_Set( "ui_currentMap", "0" );
1734 		}
1735 		map = 0;
1736 	}
1737 
1738 	if ( uiInfo.mapList[map].levelShot == -1 ) {
1739 		uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip( uiInfo.mapList[map].imageName );
1740 	}
1741 
1742 	if ( uiInfo.mapList[map].levelShot > 0 ) {
1743 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot );
1744 	} else {
1745 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip( "menu/art/unknownmap" ) );
1746 	}
1747 }
1748 
1749 
UI_DrawMapTimeToBeat(rectDef_t * rect,float scale,vec4_t color,int textStyle)1750 static void UI_DrawMapTimeToBeat( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1751 	int minutes, seconds, time;
1752 	if ( ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount ) {
1753 		ui_currentMap.integer = 0;
1754 		trap_Cvar_Set( "ui_currentMap", "0" );
1755 	}
1756 
1757 	time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
1758 
1759 	minutes = time / 60;
1760 	seconds = time % 60;
1761 
1762 	Text_Paint( rect->x, rect->y, scale, color, va( "%02i:%02i", minutes, seconds ), 0, 0, textStyle );
1763 }
1764 
1765 
1766 
UI_DrawMapCinematic(rectDef_t * rect,float scale,vec4_t color,qboolean net)1767 static void UI_DrawMapCinematic( rectDef_t *rect, float scale, vec4_t color, qboolean net ) {
1768 
1769 	int map = ( net ) ? ui_currentNetMap.integer : ui_currentMap.integer;
1770 	if ( map < 0 || map > uiInfo.mapCount ) {
1771 		if ( net ) {
1772 			ui_currentNetMap.integer = 0;
1773 			trap_Cvar_Set( "ui_currentNetMap", "0" );
1774 		} else {
1775 			ui_currentMap.integer = 0;
1776 			trap_Cvar_Set( "ui_currentMap", "0" );
1777 		}
1778 		map = 0;
1779 	}
1780 
1781 	if ( uiInfo.mapList[map].cinematic >= -1 ) {
1782 		if ( uiInfo.mapList[map].cinematic == -1 ) {
1783 			uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic( va( "%s.roq", uiInfo.mapList[map].mapLoadName ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
1784 		}
1785 		if ( uiInfo.mapList[map].cinematic >= 0 ) {
1786 			trap_CIN_RunCinematic( uiInfo.mapList[map].cinematic );
1787 
1788 			if ( ui_fixedAspect.integer ) {
1789 				if ( DC->glconfig.vidWidth * 480.0 > DC->glconfig.vidHeight * 640.0 ) {
1790 					float scaledx = rect->x * ( 480.0 / 640.0 ) + ( DC->xBias / DC->xscaleStretch);
1791 					float scaledw = rect->w * ( 480.0 / 640.0 );
1792 
1793 					trap_CIN_SetExtents( uiInfo.mapList[map].cinematic, scaledx, rect->y, scaledw, rect->h );
1794 				} else if ( DC->glconfig.vidWidth * 480.0 < DC->glconfig.vidHeight * 640.0 ) {
1795 					float scaledy = rect->y * ( 480.0 / 640.0 ) + ( DC->yBias / DC->yscaleStretch);
1796 					float scaledh = rect->h * ( 480.0 / 640.0 );
1797 
1798 					trap_CIN_SetExtents( uiInfo.mapList[map].cinematic, rect->x, scaledy, rect->w, scaledh );
1799 				} else {
1800 					trap_CIN_SetExtents( uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h );
1801 				}
1802 			} else {
1803 				trap_CIN_SetExtents( uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h );
1804 			}
1805 
1806 			trap_CIN_DrawCinematic( uiInfo.mapList[map].cinematic );
1807 		} else {
1808 			uiInfo.mapList[map].cinematic = -2;
1809 		}
1810 	} else {
1811 		UI_DrawMapPreview( rect, scale, color, net );
1812 	}
1813 }
1814 
1815 
1816 
1817 static qboolean updateModel = qtrue;
1818 static qboolean q3Model = qfalse;
1819 
UI_DrawPlayerModel(rectDef_t * rect)1820 static void UI_DrawPlayerModel( rectDef_t *rect ) {
1821 	static playerInfo_t info;
1822 	char model[MAX_QPATH];
1823 	char team[256];
1824 	char head[256];
1825 	vec3_t viewangles;
1826 	static vec3_t moveangles = { 0, 0, 0 };
1827 
1828 	if ( trap_Cvar_VariableValue( "ui_Q3Model" ) ) {
1829 		// NERVE - SMF
1830 		int teamval;
1831 		teamval = trap_Cvar_VariableValue( "mp_team" );
1832 
1833 		if ( teamval == ALLIES_TEAM ) {
1834 			strcpy( model, "multi" );
1835 		} else {
1836 			strcpy( model, "multi_axis" );
1837 		}
1838 		// -NERVE - SMF
1839 
1840 		Q_strncpyz(head, UI_Cvar_VariableString("headmodel"), sizeof(head));
1841 		if ( !q3Model ) {
1842 			q3Model = qtrue;
1843 			updateModel = qtrue;
1844 		}
1845 		team[0] = '\0';
1846 	} else {
1847 		Q_strncpyz(model, UI_Cvar_VariableString("team_model"), sizeof(model));
1848 		Q_strncpyz(head, UI_Cvar_VariableString("team_headmodel"), sizeof(head));
1849 		Q_strncpyz(team, UI_Cvar_VariableString("ui_teamName"), sizeof(team));
1850 		if ( q3Model ) {
1851 			q3Model = qfalse;
1852 			updateModel = qtrue;
1853 		}
1854 	}
1855 
1856 	moveangles[YAW] += 1;       // NERVE - SMF - TEMPORARY
1857 
1858 	// compare new cvars to old cvars and see if we need to update
1859 	{
1860 		int v1, v2;
1861 
1862 		v1 = trap_Cvar_VariableValue( "mp_team" );
1863 		v2 = trap_Cvar_VariableValue( "ui_prevTeam" );
1864 		if ( v1 != v2 ) {
1865 			trap_Cvar_Set( "ui_prevTeam", va( "%i", v1 ) );
1866 			updateModel = qtrue;
1867 		}
1868 
1869 		v1 = trap_Cvar_VariableValue( "mp_playerType" );
1870 		v2 = trap_Cvar_VariableValue( "ui_prevClass" );
1871 		if ( v1 != v2 ) {
1872 			trap_Cvar_Set( "ui_prevClass", va( "%i", v1 ) );
1873 			updateModel = qtrue;
1874 		}
1875 
1876 		v1 = trap_Cvar_VariableValue( "mp_weapon" );
1877 		v2 = trap_Cvar_VariableValue( "ui_prevWeapon" );
1878 		if ( v1 != v2 ) {
1879 			trap_Cvar_Set( "ui_prevWeapon", va( "%i", v1 ) );
1880 			updateModel = qtrue;
1881 		}
1882 	}
1883 
1884 	if ( updateModel ) {    // NERVE - SMF - TEMPORARY
1885 		memset( &info, 0, sizeof( playerInfo_t ) );
1886 		viewangles[YAW]   = 180 - 10;
1887 		viewangles[PITCH] = 0;
1888 		viewangles[ROLL]  = 0;
1889 //      VectorClear( moveangles );
1890 #ifdef MISSIONPACK
1891 		UI_PlayerInfo_SetModel( &info, model, head, team );
1892 #else
1893 		UI_PlayerInfo_SetModel( &info, model );
1894 #endif  // MISSIONPACK
1895 		UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, -1, qfalse );
1896 //		UI_RegisterClientModelname( &info, model, head, team);
1897 		updateModel = qfalse;
1898 	} else {
1899 		VectorCopy( moveangles, info.moveAngles );
1900 	}
1901 
1902 //	info.moveAngles[YAW] += 1;
1903 //   UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, moveangles, WP_MP40, qfalse );
1904 	UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2 );
1905 
1906 }
1907 
UI_DrawNetSource(rectDef_t * rect,float scale,vec4_t color,int textStyle)1908 static void UI_DrawNetSource( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1909 	if ( ui_netSource.integer < 0 || ui_netSource.integer >= numNetSources /*uiInfo.numGameTypes*/ ) {        // NERVE - SMF - possible bug
1910 		ui_netSource.integer = 0;
1911 	}
1912 	Text_Paint( rect->x, rect->y, scale, color, UI_TranslateString( va( "Source: %s", netSources[ui_netSource.integer] ) ), 0, 0, textStyle );
1913 }
1914 
UI_DrawNetMapPreview(rectDef_t * rect,float scale,vec4_t color)1915 static void UI_DrawNetMapPreview( rectDef_t *rect, float scale, vec4_t color ) {
1916 
1917 	if ( uiInfo.serverStatus.currentServerPreview > 0 ) {
1918 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview );
1919 	} else {
1920 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip( "menu/art/unknownmap" ) );
1921 	}
1922 }
1923 
UI_DrawNetMapCinematic(rectDef_t * rect,float scale,vec4_t color)1924 static void UI_DrawNetMapCinematic( rectDef_t *rect, float scale, vec4_t color ) {
1925 	if ( ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount ) {
1926 		ui_currentNetMap.integer = 0;
1927 		trap_Cvar_Set( "ui_currentNetMap", "0" );
1928 	}
1929 
1930 	if ( uiInfo.serverStatus.currentServerCinematic >= 0 ) {
1931 		trap_CIN_RunCinematic( uiInfo.serverStatus.currentServerCinematic );
1932 
1933 		if ( ui_fixedAspect.integer ) {
1934 			if ( DC->glconfig.vidWidth * 480.0 > DC->glconfig.vidHeight * 640.0 ) {
1935 				float scaledx = rect->x * ( 480.0 / 640.0 ) + ( DC->xBias / DC->xscaleStretch);
1936 				float scaledw = rect->w * ( 480.0 / 640.0 );
1937 
1938 				trap_CIN_SetExtents( uiInfo.serverStatus.currentServerCinematic, scaledx, rect->y, scaledw, rect->h );
1939 			} else if ( DC->glconfig.vidWidth * 480.0 < DC->glconfig.vidHeight * 640.0 ) {
1940 				float scaledy = rect->y * ( 480.0 / 640.0 ) + ( DC->yBias / DC->yscaleStretch);
1941 				float scaledh = rect->h * ( 480.0 / 640.0 );
1942 
1943 				trap_CIN_SetExtents( uiInfo.serverStatus.currentServerCinematic, rect->x, scaledy, rect->w, scaledh );
1944 			} else {
1945 				trap_CIN_SetExtents( uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h );
1946 			}
1947 		} else {
1948 			trap_CIN_SetExtents( uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h );
1949 		}
1950 
1951 		trap_CIN_DrawCinematic( uiInfo.serverStatus.currentServerCinematic );
1952 	} else {
1953 		UI_DrawNetMapPreview( rect, scale, color );
1954 	}
1955 }
1956 
1957 
1958 
UI_DrawNetFilter(rectDef_t * rect,float scale,vec4_t color,int textStyle)1959 static void UI_DrawNetFilter( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1960 	if ( ui_serverFilterType.integer < 0 || ui_serverFilterType.integer >= numServerFilters ) {
1961 		ui_serverFilterType.integer = 0;
1962 	}
1963 	Text_Paint( rect->x, rect->y, scale, color, va( "Filter: %s", serverFilters[ui_serverFilterType.integer].description ), 0, 0, textStyle );
1964 }
1965 
1966 
UI_DrawTier(rectDef_t * rect,float scale,vec4_t color,int textStyle)1967 static void UI_DrawTier( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
1968 	int i;
1969 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1970 	if ( i < 0 || i >= uiInfo.tierCount ) {
1971 		i = 0;
1972 	}
1973 	Text_Paint( rect->x, rect->y, scale, color, va( "Tier: %s", uiInfo.tierList[i].tierName ),0, 0, textStyle );
1974 }
1975 
UI_DrawTierMap(rectDef_t * rect,int index)1976 static void UI_DrawTierMap( rectDef_t *rect, int index ) {
1977 	int i;
1978 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1979 	if ( i < 0 || i >= uiInfo.tierCount ) {
1980 		i = 0;
1981 	}
1982 
1983 	if ( uiInfo.tierList[i].mapHandles[index] == -1 ) {
1984 		uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip( va( "levelshots/%s", uiInfo.tierList[i].maps[index] ) );
1985 	}
1986 
1987 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index] );
1988 }
1989 
UI_EnglishMapName(const char * map)1990 static const char *UI_EnglishMapName( const char *map ) {
1991 	int i;
1992 	for ( i = 0; i < uiInfo.mapCount; i++ ) {
1993 		if ( Q_stricmp( map, uiInfo.mapList[i].mapLoadName ) == 0 ) {
1994 			return uiInfo.mapList[i].mapName;
1995 		}
1996 	}
1997 	return "";
1998 }
1999 
UI_DrawTierMapName(rectDef_t * rect,float scale,vec4_t color,int textStyle)2000 static void UI_DrawTierMapName( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2001 	int i, j;
2002 	i = trap_Cvar_VariableValue( "ui_currentTier" );
2003 	if ( i < 0 || i >= uiInfo.tierCount ) {
2004 		i = 0;
2005 	}
2006 	j = trap_Cvar_VariableValue( "ui_currentMap" );
2007 	if ( j < 0 || j >= MAPS_PER_TIER ) {
2008 		j = 0;
2009 	}
2010 
2011 	Text_Paint( rect->x, rect->y, scale, color, UI_EnglishMapName( uiInfo.tierList[i].maps[j] ), 0, 0, textStyle );
2012 }
2013 
UI_DrawTierGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)2014 static void UI_DrawTierGameType( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2015 	int i, j;
2016 	i = trap_Cvar_VariableValue( "ui_currentTier" );
2017 	if ( i < 0 || i >= uiInfo.tierCount ) {
2018 		i = 0;
2019 	}
2020 	j = trap_Cvar_VariableValue( "ui_currentMap" );
2021 	if ( j < 0 || j >= MAPS_PER_TIER ) {
2022 		j = 0;
2023 	}
2024 
2025 	Text_Paint( rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType, 0, 0, textStyle );
2026 }
2027 
2028 /*
2029 // TTimo: unused
2030 static const char *UI_OpponentLeaderName(void) {
2031   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2032 	return uiInfo.teamList[i].teamMembers[0];
2033 }
2034 */
2035 
2036 /*
2037 // TTimo: unused
2038 static const char *UI_AIFromName(const char *name) {
2039 	int j;
2040 	for (j = 0; j < uiInfo.aliasCount; j++) {
2041 		if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
2042 			return uiInfo.aliasList[j].ai;
2043 		}
2044 	}
2045 	return "James";
2046 }
2047 */
2048 
2049 /*
2050 // TTimo: unused
2051 static const int UI_AIIndex(const char *name) {
2052 	int j;
2053 	for (j = 0; j < uiInfo.characterCount; j++) {
2054 		if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
2055 			return j;
2056 		}
2057 	}
2058 	return 0;
2059 }
2060 */
2061 
2062 /*
2063 // TTimo: unused
2064 static const int UI_AIIndexFromName(const char *name) {
2065 	int j;
2066 	for (j = 0; j < uiInfo.aliasCount; j++) {
2067 		if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
2068 			return UI_AIIndex(uiInfo.aliasList[j].ai);
2069 		}
2070 	}
2071 	return 0;
2072 }
2073 */
2074 
2075 /*
2076 // TTimo: unused
2077 static const char *UI_OpponentLeaderHead(void) {
2078 	const char *leader = UI_OpponentLeaderName();
2079 	return UI_AIFromName(leader);
2080 }
2081 */
2082 
2083 /*
2084 // TTimo: unused
2085 static const char *UI_OpponentLeaderModel(void) {
2086 	int i;
2087 	const char *head = UI_OpponentLeaderHead();
2088 	for (i = 0; i < uiInfo.characterCount; i++) {
2089 		if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
2090 			if (uiInfo.characterList[i].female) {
2091 				return "Janet";
2092 			} else {
2093 				return "James";
2094 			}
2095 		}
2096 	}
2097 	return "James";
2098 }
2099 */
2100 
2101 static qboolean updateOpponentModel = qtrue;
UI_DrawOpponent(rectDef_t * rect)2102 static void UI_DrawOpponent( rectDef_t *rect ) {
2103 	static playerInfo_t info2;
2104 	char model[MAX_QPATH];
2105 	char headmodel[MAX_QPATH];
2106 	vec3_t viewangles;
2107 	vec3_t moveangles;
2108 
2109 	if ( updateOpponentModel ) {
2110 
2111 		Q_strncpyz(model, UI_Cvar_VariableString("ui_opponentModel"), sizeof(model));
2112 		Q_strncpyz(headmodel, UI_Cvar_VariableString("ui_opponentModel"), sizeof(headmodel));
2113 
2114 		memset( &info2, 0, sizeof( playerInfo_t ) );
2115 		viewangles[YAW]   = 180 - 10;
2116 		viewangles[PITCH] = 0;
2117 		viewangles[ROLL]  = 0;
2118 		VectorClear( moveangles );
2119 #ifdef MISSIONPACK
2120 		UI_PlayerInfo_SetModel( &info2, model, headmodel, "" );
2121 #else
2122 		UI_PlayerInfo_SetModel( &info2, model );
2123 #endif  // #ifdef MISSIONPACK
2124 		UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MP40, qfalse );
2125 #ifdef MISSIONPACK
2126 		UI_RegisterClientModelname( &info2, model, headmodel, team );
2127 #else
2128 		UI_RegisterClientModelname( &info2, model );
2129 #endif  // #ifdef MISSIONPACK
2130 		updateOpponentModel = qfalse;
2131 	}
2132 
2133 	UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2 );
2134 
2135 }
2136 
UI_NextOpponent(void)2137 static void UI_NextOpponent( void ) {
2138 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
2139 	int j = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
2140 	i++;
2141 	if ( i >= uiInfo.teamCount ) {
2142 		i = 0;
2143 	}
2144 	if ( i == j ) {
2145 		i++;
2146 		if ( i >= uiInfo.teamCount ) {
2147 			i = 0;
2148 		}
2149 	}
2150 	trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
2151 }
2152 
UI_PriorOpponent(void)2153 static void UI_PriorOpponent( void ) {
2154 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
2155 	int j = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
2156 	i--;
2157 	if ( i < 0 ) {
2158 		i = uiInfo.teamCount - 1;
2159 	}
2160 	if ( i == j ) {
2161 		i--;
2162 		if ( i < 0 ) {
2163 			i = uiInfo.teamCount - 1;
2164 		}
2165 	}
2166 	trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
2167 }
2168 
UI_DrawPlayerLogo(rectDef_t * rect,vec3_t color)2169 static void UI_DrawPlayerLogo( rectDef_t *rect, vec3_t color ) {
2170 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
2171 
2172 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2173 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2174 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2175 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2176 	}
2177 
2178 	trap_R_SetColor( color );
2179 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
2180 	trap_R_SetColor( NULL );
2181 }
2182 
UI_DrawPlayerLogoMetal(rectDef_t * rect,vec3_t color)2183 static void UI_DrawPlayerLogoMetal( rectDef_t *rect, vec3_t color ) {
2184 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
2185 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2186 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2187 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2188 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2189 	}
2190 
2191 	trap_R_SetColor( color );
2192 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
2193 	trap_R_SetColor( NULL );
2194 }
2195 
UI_DrawPlayerLogoName(rectDef_t * rect,vec3_t color)2196 static void UI_DrawPlayerLogoName( rectDef_t *rect, vec3_t color ) {
2197 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
2198 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2199 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2200 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2201 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2202 	}
2203 
2204 	trap_R_SetColor( color );
2205 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
2206 	trap_R_SetColor( NULL );
2207 }
2208 
UI_DrawOpponentLogo(rectDef_t * rect,vec3_t color)2209 static void UI_DrawOpponentLogo( rectDef_t *rect, vec3_t color ) {
2210 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
2211 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2212 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2213 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2214 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2215 	}
2216 
2217 	trap_R_SetColor( color );
2218 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
2219 	trap_R_SetColor( NULL );
2220 }
2221 
UI_DrawOpponentLogoMetal(rectDef_t * rect,vec3_t color)2222 static void UI_DrawOpponentLogoMetal( rectDef_t *rect, vec3_t color ) {
2223 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
2224 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2225 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2226 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2227 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2228 	}
2229 
2230 	trap_R_SetColor( color );
2231 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
2232 	trap_R_SetColor( NULL );
2233 }
2234 
UI_DrawOpponentLogoName(rectDef_t * rect,vec3_t color)2235 static void UI_DrawOpponentLogoName( rectDef_t *rect, vec3_t color ) {
2236 	int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
2237 	if ( uiInfo.teamList[i].teamIcon == -1 ) {
2238 		uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip( uiInfo.teamList[i].imageName );
2239 		uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip( va( "%s_metal",uiInfo.teamList[i].imageName ) );
2240 		uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip( va( "%s_name", uiInfo.teamList[i].imageName ) );
2241 	}
2242 
2243 	trap_R_SetColor( color );
2244 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
2245 	trap_R_SetColor( NULL );
2246 }
2247 
UI_DrawAllMapsSelection(rectDef_t * rect,float scale,vec4_t color,int textStyle,qboolean net)2248 static void UI_DrawAllMapsSelection( rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net ) {
2249 #ifdef MISSIONPACK
2250 	int map = ( net ) ? ui_currentNetMap.integer : ui_currentMap.integer;
2251 	if ( map >= 0 && map < uiInfo.mapCount ) {
2252 		Text_Paint( rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle );
2253 	}
2254 #endif  // #ifdef MISSIONPACK
2255 }
2256 
UI_DrawOpponentName(rectDef_t * rect,float scale,vec4_t color,int textStyle)2257 static void UI_DrawOpponentName( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2258 	Text_Paint( rect->x, rect->y, scale, color, UI_Cvar_VariableString( "ui_opponentName" ), 0, 0, textStyle );
2259 }
2260 
2261 
UI_OwnerDrawWidth(int ownerDraw,float scale)2262 static int UI_OwnerDrawWidth( int ownerDraw, float scale ) {
2263 	int i, h, value;
2264 	const char *text;
2265 	const char *s = NULL;
2266 
2267 	switch ( ownerDraw ) {
2268 	case UI_HANDICAP:
2269 		h = Com_Clamp( 5, 100, trap_Cvar_VariableValue( "handicap" ) );
2270 		i = 20 - h / 5;
2271 		s = handicapValues[i];
2272 		break;
2273 	case UI_CLANNAME:
2274 		s = UI_Cvar_VariableString( "ui_teamName" );
2275 		break;
2276 	case UI_GAMETYPE:
2277 		s = uiInfo.gameTypes[ui_gameType.integer].gameType;
2278 		break;
2279 	case UI_SKILL:
2280 		i = trap_Cvar_VariableValue( "g_spSkill" );
2281 		if ( i < 1 || i > numSkillLevels ) {
2282 			i = 1;
2283 		}
2284 		s = skillLevels[i - 1];
2285 		break;
2286 	case UI_BLUETEAMNAME:
2287 		i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_blueTeam" ) );
2288 		if ( i >= 0 && i < uiInfo.teamCount ) {
2289 			s = va( "%s: %s", "Blue", uiInfo.teamList[i].teamName );
2290 		}
2291 		break;
2292 	case UI_REDTEAMNAME:
2293 		i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_redTeam" ) );
2294 		if ( i >= 0 && i < uiInfo.teamCount ) {
2295 			s = va( "%s: %s", "Red", uiInfo.teamList[i].teamName );
2296 		}
2297 		break;
2298 	case UI_BLUETEAM1:
2299 	case UI_BLUETEAM2:
2300 	case UI_BLUETEAM3:
2301 	case UI_BLUETEAM4:
2302 	case UI_BLUETEAM5:
2303 		value = trap_Cvar_VariableValue( va( "ui_blueteam%i", ownerDraw - UI_BLUETEAM1 + 1 ) );
2304 		if ( value <= 0 ) {
2305 			text = "Closed";
2306 		} else if ( value == 1 ) {
2307 			text = "Human";
2308 		} else {
2309 			value -= 2;
2310 			if ( value >= uiInfo.aliasCount ) {
2311 				value = 0;
2312 			}
2313 			text = uiInfo.aliasList[value].name;
2314 		}
2315 		s = va( "%i. %s", ownerDraw - UI_BLUETEAM1 + 1, text );
2316 		break;
2317 	case UI_REDTEAM1:
2318 	case UI_REDTEAM2:
2319 	case UI_REDTEAM3:
2320 	case UI_REDTEAM4:
2321 	case UI_REDTEAM5:
2322 		value = trap_Cvar_VariableValue( va( "ui_redteam%i", ownerDraw - UI_REDTEAM1 + 1 ) );
2323 		if ( value <= 0 ) {
2324 			text = "Closed";
2325 		} else if ( value == 1 ) {
2326 			text = "Human";
2327 		} else {
2328 			value -= 2;
2329 			if ( value >= uiInfo.aliasCount ) {
2330 				value = 0;
2331 			}
2332 			text = uiInfo.aliasList[value].name;
2333 		}
2334 		s = va( "%i. %s", ownerDraw - UI_REDTEAM1 + 1, text );
2335 		break;
2336 	case UI_NETSOURCE:
2337 		if (ui_netSource.integer < 0 || ui_netSource.integer >= numNetSources) {
2338 			ui_netSource.integer = 0;
2339 		}
2340 		s = va( "Source: %s", netSources[ui_netSource.integer] );
2341 		break;
2342 	case UI_NETFILTER:
2343 		if ( ui_serverFilterType.integer < 0 || ui_serverFilterType.integer >= numServerFilters ) {
2344 			ui_serverFilterType.integer = 0;
2345 		}
2346 		s = va( "Filter: %s", serverFilters[ui_serverFilterType.integer].description );
2347 		break;
2348 	case UI_TIER:
2349 		break;
2350 	case UI_TIER_MAPNAME:
2351 		break;
2352 	case UI_TIER_GAMETYPE:
2353 		break;
2354 	case UI_ALLMAPS_SELECTION:
2355 		break;
2356 	case UI_OPPONENT_NAME:
2357 		break;
2358 	case UI_KEYBINDSTATUS:
2359 		if ( Display_KeyBindPending() ) {
2360 			s = UI_TranslateString( "Waiting for new key... Press ESCAPE to cancel" );
2361 		} else {
2362 			s = UI_TranslateString( "Press ENTER or CLICK to change, Press BACKSPACE to clear" );
2363 		}
2364 		break;
2365 	case UI_SERVERREFRESHDATE:
2366 		s = UI_Cvar_VariableString( va( "ui_lastServerRefresh_%i", ui_netSource.integer ) );
2367 		break;
2368 	default:
2369 		break;
2370 	}
2371 
2372 	if ( s ) {
2373 		return Text_Width( s, scale, 0 );
2374 	}
2375 	return 0;
2376 }
2377 
UI_DrawBotName(rectDef_t * rect,float scale,vec4_t color,int textStyle)2378 static void UI_DrawBotName( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2379 #ifdef MISSIONPACK
2380 	int value = uiInfo.botIndex;
2381 	int game = trap_Cvar_VariableValue( "g_gametype" );
2382 	const char *text;
2383 	if ( game >= GT_TEAM ) {
2384 		text = uiInfo.characterList[value].name;
2385 	} else {
2386 		text = UI_GetBotNameByNumber( value );
2387 	}
2388 	Text_Paint( rect->x, rect->y, scale, color, text, 0, 0, textStyle );
2389 #endif  // #ifdef MISSIONPACK
2390 }
2391 
UI_DrawBotSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)2392 static void UI_DrawBotSkill( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2393 	if ( uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels ) {
2394 		Text_Paint( rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle );
2395 	}
2396 }
2397 
UI_DrawRedBlue(rectDef_t * rect,float scale,vec4_t color,int textStyle)2398 static void UI_DrawRedBlue( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2399 	Text_Paint( rect->x, rect->y, scale, color, ( uiInfo.redBlue == 0 ) ? "Red" : "Blue", 0, 0, textStyle );
2400 }
2401 
UI_DrawCrosshair(rectDef_t * rect,float scale,vec4_t color)2402 static void UI_DrawCrosshair( rectDef_t *rect, float scale, vec4_t color ) {
2403 	trap_R_SetColor( color );
2404 	if ( uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS ) {
2405 		uiInfo.currentCrosshair = 0;
2406 	}
2407 	UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair] );
2408 	trap_R_SetColor( NULL );
2409 }
2410 
2411 /*
2412 ===============
2413 UI_BuildPlayerList
2414 ===============
2415 */
UI_BuildPlayerList(void)2416 static void UI_BuildPlayerList( void ) {
2417 	uiClientState_t cs;
2418 	int n, count, team, team2, playerTeamNumber;
2419 	char info[MAX_INFO_STRING];
2420 
2421 	trap_GetClientState( &cs );
2422 	trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
2423 	uiInfo.playerNumber = cs.clientNum;
2424 	uiInfo.teamLeader = atoi( Info_ValueForKey( info, "tl" ) );
2425 	team = atoi( Info_ValueForKey( info, "t" ) );
2426 	trap_GetConfigString( CS_SERVERINFO, info, sizeof( info ) );
2427 	count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
2428 	uiInfo.playerCount = 0;
2429 	uiInfo.myTeamCount = 0;
2430 	playerTeamNumber = 0;
2431 	for ( n = 0; n < count; n++ ) {
2432 		trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
2433 
2434 		if ( info[0] ) {
2435 			Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
2436 			Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
2437 			uiInfo.playerCount++;
2438 			team2 = atoi( Info_ValueForKey( info, "t" ) );
2439 			if ( team2 == team ) {
2440 				Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
2441 				Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
2442 				uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
2443 				if ( uiInfo.playerNumber == n ) {
2444 					playerTeamNumber = uiInfo.myTeamCount;
2445 				}
2446 				uiInfo.myTeamCount++;
2447 			}
2448 		}
2449 	}
2450 
2451 	if ( !uiInfo.teamLeader ) {
2452 		trap_Cvar_Set( "cg_selectedPlayer", va( "%d", playerTeamNumber ) );
2453 	}
2454 
2455 	n = trap_Cvar_VariableValue( "cg_selectedPlayer" );
2456 	if ( n < 0 || n > uiInfo.myTeamCount ) {
2457 		n = 0;
2458 	}
2459 	if ( n < uiInfo.myTeamCount ) {
2460 		trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[n] );
2461 	}
2462 }
2463 
2464 
UI_DrawSelectedPlayer(rectDef_t * rect,float scale,vec4_t color,int textStyle)2465 static void UI_DrawSelectedPlayer( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2466 	if ( uiInfo.uiDC.realTime > uiInfo.playerRefresh ) {
2467 		uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
2468 		UI_BuildPlayerList();
2469 	}
2470 	Text_Paint( rect->x, rect->y, scale, color, ( uiInfo.teamLeader ) ? UI_Cvar_VariableString( "cg_selectedPlayerName" ) : UI_Cvar_VariableString( "name" ), 0, 0, textStyle );
2471 }
2472 
UI_DrawServerRefreshDate(rectDef_t * rect,float scale,vec4_t color,int textStyle)2473 static void UI_DrawServerRefreshDate( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2474 	int serverCount;            // NERVE - SMF
2475 //#ifdef MISSIONPACK
2476 	if ( uiInfo.serverStatus.refreshActive ) {
2477 		vec4_t lowLight, newColor;
2478 		lowLight[0] = 0.8 * color[0];
2479 		lowLight[1] = 0.8 * color[1];
2480 		lowLight[2] = 0.8 * color[2];
2481 		lowLight[3] = 0.8 * color[3];
2482 		LerpColor( color,lowLight,newColor,0.5 + 0.5 * sin( uiInfo.uiDC.realTime / PULSE_DIVISOR ) );
2483 		// NERVE - SMF
2484 		serverCount = trap_LAN_GetServerCount( UI_SourceForLAN() );
2485 		if ( serverCount >= 0 ) {
2486 			Text_Paint( rect->x, rect->y, scale, newColor, va( UI_TranslateString( "Getting info for %d servers (ESC to cancel)" ), serverCount ), 0, 0, textStyle );
2487 		} else {
2488 			Text_Paint( rect->x, rect->y, scale, newColor, UI_TranslateString( "Waiting for response from Master Server" ), 0, 0, textStyle );
2489 		}
2490 	} else {
2491 		char buff[64];
2492 		Q_strncpyz( buff, UI_Cvar_VariableString( va( "ui_lastServerRefresh_%i", ui_netSource.integer ) ), 64 );
2493 		Text_Paint( rect->x, rect->y, scale, color, va( UI_TranslateString( "Refresh Time: %s" ), buff ), 0, 0, textStyle );
2494 	}
2495 //#endif	// #ifdef MISSIONPACK
2496 }
2497 
UI_DrawServerMOTD(rectDef_t * rect,float scale,vec4_t color)2498 static void UI_DrawServerMOTD( rectDef_t *rect, float scale, vec4_t color ) {
2499 //#ifdef MISSIONPACK
2500 	if ( uiInfo.serverStatus.motdLen ) {
2501 		float maxX;
2502 
2503 		if ( uiInfo.serverStatus.motdWidth == -1 ) {
2504 			uiInfo.serverStatus.motdWidth = 0;
2505 			uiInfo.serverStatus.motdPaintX = rect->x + 1;
2506 			uiInfo.serverStatus.motdPaintX2 = -1;
2507 		}
2508 
2509 		if ( uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen ) {
2510 			uiInfo.serverStatus.motdOffset = 0;
2511 			uiInfo.serverStatus.motdPaintX = rect->x + 1;
2512 			uiInfo.serverStatus.motdPaintX2 = -1;
2513 		}
2514 
2515 		if ( uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime ) {
2516 			uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
2517 			if ( uiInfo.serverStatus.motdPaintX <= rect->x + 2 ) {
2518 				if ( uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen ) {
2519 					uiInfo.serverStatus.motdPaintX += Text_Width( &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1 ) - 1;
2520 					uiInfo.serverStatus.motdOffset++;
2521 				} else {
2522 					uiInfo.serverStatus.motdOffset = 0;
2523 					if ( uiInfo.serverStatus.motdPaintX2 >= 0 ) {
2524 						uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
2525 					} else {
2526 						uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
2527 					}
2528 					uiInfo.serverStatus.motdPaintX2 = -1;
2529 				}
2530 			} else {
2531 				//serverStatus.motdPaintX--;
2532 				uiInfo.serverStatus.motdPaintX -= 2;
2533 				if ( uiInfo.serverStatus.motdPaintX2 >= 0 ) {
2534 					//serverStatus.motdPaintX2--;
2535 					uiInfo.serverStatus.motdPaintX2 -= 2;
2536 				}
2537 			}
2538 		}
2539 
2540 		maxX = rect->x + rect->w - 2;
2541 		Text_Paint_Limit( &maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0 );
2542 		if ( uiInfo.serverStatus.motdPaintX2 >= 0 ) {
2543 			float maxX2 = rect->x + rect->w - 2;
2544 			Text_Paint_Limit( &maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset );
2545 		}
2546 		if ( uiInfo.serverStatus.motdOffset && maxX > 0 ) {
2547 			// if we have an offset ( we are skipping the first part of the string ) and we fit the string
2548 			if ( uiInfo.serverStatus.motdPaintX2 == -1 ) {
2549 				uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
2550 			}
2551 		} else {
2552 			uiInfo.serverStatus.motdPaintX2 = -1;
2553 		}
2554 
2555 	}
2556 //#endif	// #ifdef MISSIONPACK
2557 }
2558 
UI_DrawKeyBindStatus(rectDef_t * rect,float scale,vec4_t color,int textStyle)2559 static void UI_DrawKeyBindStatus( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2560 	//int ofs = 0; // TTimo: unused
2561 	if ( Display_KeyBindPending() ) {
2562 		Text_Paint( rect->x, rect->y, scale, color, UI_TranslateString( "Waiting for new key... Press ESCAPE to cancel" ), 0, 0, textStyle );
2563 	} else {
2564 		Text_Paint( rect->x, rect->y, scale, color, UI_TranslateString( "Press ENTER or CLICK to change, Press BACKSPACE to clear" ), 0, 0, textStyle );
2565 	}
2566 }
2567 
UI_DrawGLInfo(rectDef_t * rect,float scale,vec4_t color,int textStyle)2568 static void UI_DrawGLInfo( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2569 	char * eptr;
2570 	char buff[4096];
2571 	const char *lines[64];
2572 	int y, numLines, i;
2573 
2574 	Text_Paint( rect->x + 2, rect->y, scale, color, va( "VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string ), 0, 30, textStyle );
2575 	Text_Paint( rect->x + 2, rect->y + 15, scale, color, va( "VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string ), 0, 30, textStyle );
2576 	Text_Paint( rect->x + 2, rect->y + 30, scale, color, va( "PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits ), 0, 30, textStyle );
2577 
2578 	// build null terminated extension strings
2579 	Q_strncpyz( buff, uiInfo.uiDC.glconfig.extensions_string, 4096 );
2580 	eptr = buff;
2581 	y = rect->y + 45;
2582 	numLines = 0;
2583 	while ( y < rect->y + rect->h && *eptr )
2584 	{
2585 		while ( *eptr && *eptr == ' ' )
2586 			*eptr++ = '\0';
2587 
2588 		// TTimo - don't overflow the line buffer, don't go above 46, as it goes out of the screen anyway
2589 		if ( numLines == 46 )
2590 			break;
2591 
2592 		// track start of valid string
2593 		if ( *eptr && *eptr != ' ' ) {
2594 			lines[numLines++] = eptr;
2595 		}
2596 
2597 		while ( *eptr && *eptr != ' ' )
2598 			eptr++;
2599 	}
2600 
2601 	i = 0;
2602 	while ( i < numLines ) {
2603 		Text_Paint( rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle );
2604 		if ( i < numLines ) {
2605 			Text_Paint( rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle );
2606 		}
2607 		y += 10;
2608 		if ( y > rect->y + rect->h - 11 ) {
2609 			break;
2610 		}
2611 	}
2612 
2613 
2614 }
2615 
2616 // NERVE - SMF
2617 // TTimo - make the messages wrap and print in the right order (IRC-style)
UI_DrawLimboChat(rectDef_t * rect,float scale,vec4_t color,int textStyle)2618 static void UI_DrawLimboChat( rectDef_t *rect, float scale, vec4_t color, int textStyle ) {
2619 	int i, j, count;
2620 	char buf[140];
2621 	float x, y;
2622 
2623 	memset( buf, 0, 140 );
2624 
2625 	// first count strings
2626 	for ( i = 0, count = 0; ; i++, count++ ) {
2627 		if ( !trap_GetLimboString( i, buf ) ) {
2628 			break;
2629 		}
2630 	}
2631 
2632 	i = 0; j = 0;
2633 	do
2634 	{
2635 		trap_GetLimboString( i, buf );
2636 		x = rect->x;
2637 		j += Count_Text_AutoWrap_Paint( x, 0, 410, scale, color, buf, 0, textStyle );
2638 		y = rect->y + 9 * ( count - j );
2639 		if ( j < count ) {
2640 			// 410 is the hardcoded UI limbo chat max width
2641 			Text_AutoWrap_Paint( x, y, 410, 9, scale, color, buf, 0, textStyle );
2642 		}
2643 		i++;
2644 	} while ( j < count );
2645 }
2646 // -NERVE - SMF
2647 
2648 // FIXME: table drive
2649 //
UI_OwnerDraw(float x,float y,float w,float h,float text_x,float text_y,int ownerDraw,int ownerDrawFlags,int align,float special,float scale,vec4_t color,qhandle_t shader,int textStyle)2650 static void UI_OwnerDraw( float x, float y, float w, float h, float text_x, float text_y, int ownerDraw, int ownerDrawFlags, int align, float special, float scale, vec4_t color, qhandle_t shader, int textStyle ) {
2651 	rectDef_t rect;
2652 
2653 	rect.x = x + text_x;
2654 	rect.y = y + text_y;
2655 	rect.w = w;
2656 	rect.h = h;
2657 
2658 	switch ( ownerDraw ) {
2659 	case UI_HANDICAP:
2660 		UI_DrawHandicap( &rect, scale, color, textStyle );
2661 		break;
2662 	case UI_EFFECTS:
2663 		UI_DrawEffects( &rect, scale, color );
2664 		break;
2665 	case UI_PLAYERMODEL:
2666 		UI_DrawPlayerModel( &rect );
2667 		break;
2668 	case UI_CLANNAME:
2669 		UI_DrawClanName( &rect, scale, color, textStyle );
2670 		break;
2671 
2672 	case UI_SAVEGAME_SHOT:      // (SA)
2673 		UI_DrawSaveGameShot( &rect, scale, color );
2674 		break;
2675 
2676 	case UI_CLANLOGO:
2677 		UI_DrawClanLogo( &rect, scale, color );
2678 		break;
2679 	case UI_CLANCINEMATIC:
2680 		UI_DrawClanCinematic( &rect, scale, color );
2681 		break;
2682 	case UI_PREVIEWCINEMATIC:
2683 		UI_DrawPreviewCinematic( &rect, scale, color );
2684 		break;
2685 	case UI_GAMETYPE:
2686 		UI_DrawGameType( &rect, scale, color, textStyle );
2687 		break;
2688 	case UI_NETGAMETYPE:
2689 		UI_DrawNetGameType( &rect, scale, color, textStyle );
2690 		break;
2691 	case UI_JOINGAMETYPE:
2692 		UI_DrawJoinGameType( &rect, scale, color, textStyle );
2693 		break;
2694 	case UI_MAPPREVIEW:
2695 		UI_DrawMapPreview( &rect, scale, color, qtrue );
2696 		break;
2697 	case UI_MAP_TIMETOBEAT:
2698 		UI_DrawMapTimeToBeat( &rect, scale, color, textStyle );
2699 		break;
2700 	case UI_MAPCINEMATIC:
2701 		UI_DrawMapCinematic( &rect, scale, color, qfalse );
2702 		break;
2703 	case UI_STARTMAPCINEMATIC:
2704 		UI_DrawMapCinematic( &rect, scale, color, qtrue );
2705 		break;
2706 	case UI_SKILL:
2707 		UI_DrawSkill( &rect, scale, color, textStyle );
2708 		break;
2709 	case UI_BLUETEAMNAME:
2710 		UI_DrawTeamName( &rect, scale, color, qtrue, textStyle );
2711 		break;
2712 	case UI_REDTEAMNAME:
2713 		UI_DrawTeamName( &rect, scale, color, qfalse, textStyle );
2714 		break;
2715 	case UI_BLUETEAM1:
2716 	case UI_BLUETEAM2:
2717 	case UI_BLUETEAM3:
2718 	case UI_BLUETEAM4:
2719 	case UI_BLUETEAM5:
2720 		UI_DrawTeamMember( &rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle );
2721 		break;
2722 	case UI_REDTEAM1:
2723 	case UI_REDTEAM2:
2724 	case UI_REDTEAM3:
2725 	case UI_REDTEAM4:
2726 	case UI_REDTEAM5:
2727 		UI_DrawTeamMember( &rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle );
2728 		break;
2729 	case UI_NETSOURCE:
2730 		UI_DrawNetSource( &rect, scale, color, textStyle );
2731 		break;
2732 	case UI_NETMAPPREVIEW:
2733 		UI_DrawNetMapPreview( &rect, scale, color );
2734 		break;
2735 	case UI_NETMAPCINEMATIC:
2736 		UI_DrawNetMapCinematic( &rect, scale, color );
2737 		break;
2738 	case UI_NETFILTER:
2739 		UI_DrawNetFilter( &rect, scale, color, textStyle );
2740 		break;
2741 	case UI_TIER:
2742 		UI_DrawTier( &rect, scale, color, textStyle );
2743 		break;
2744 	case UI_OPPONENTMODEL:
2745 		UI_DrawOpponent( &rect );
2746 		break;
2747 	case UI_TIERMAP1:
2748 		UI_DrawTierMap( &rect, 0 );
2749 		break;
2750 	case UI_TIERMAP2:
2751 		UI_DrawTierMap( &rect, 1 );
2752 		break;
2753 	case UI_TIERMAP3:
2754 		UI_DrawTierMap( &rect, 2 );
2755 		break;
2756 	case UI_PLAYERLOGO:
2757 		UI_DrawPlayerLogo( &rect, color );
2758 		break;
2759 	case UI_PLAYERLOGO_METAL:
2760 		UI_DrawPlayerLogoMetal( &rect, color );
2761 		break;
2762 	case UI_PLAYERLOGO_NAME:
2763 		UI_DrawPlayerLogoName( &rect, color );
2764 		break;
2765 	case UI_OPPONENTLOGO:
2766 		UI_DrawOpponentLogo( &rect, color );
2767 		break;
2768 	case UI_OPPONENTLOGO_METAL:
2769 		UI_DrawOpponentLogoMetal( &rect, color );
2770 		break;
2771 	case UI_OPPONENTLOGO_NAME:
2772 		UI_DrawOpponentLogoName( &rect, color );
2773 		break;
2774 	case UI_TIER_MAPNAME:
2775 		UI_DrawTierMapName( &rect, scale, color, textStyle );
2776 		break;
2777 	case UI_TIER_GAMETYPE:
2778 		UI_DrawTierGameType( &rect, scale, color, textStyle );
2779 		break;
2780 	case UI_ALLMAPS_SELECTION:
2781 		UI_DrawAllMapsSelection( &rect, scale, color, textStyle, qtrue );
2782 		break;
2783 	case UI_MAPS_SELECTION:
2784 		UI_DrawAllMapsSelection( &rect, scale, color, textStyle, qfalse );
2785 		break;
2786 	case UI_OPPONENT_NAME:
2787 		UI_DrawOpponentName( &rect, scale, color, textStyle );
2788 		break;
2789 	case UI_BOTNAME:
2790 		UI_DrawBotName( &rect, scale, color, textStyle );
2791 		break;
2792 	case UI_BOTSKILL:
2793 		UI_DrawBotSkill( &rect, scale, color, textStyle );
2794 		break;
2795 	case UI_REDBLUE:
2796 		UI_DrawRedBlue( &rect, scale, color, textStyle );
2797 		break;
2798 	case UI_CROSSHAIR:
2799 		UI_DrawCrosshair( &rect, scale, color );
2800 		break;
2801 	case UI_SELECTEDPLAYER:
2802 		UI_DrawSelectedPlayer( &rect, scale, color, textStyle );
2803 		break;
2804 	case UI_SERVERREFRESHDATE:
2805 		UI_DrawServerRefreshDate( &rect, scale, color, textStyle );
2806 		break;
2807 	case UI_SERVERMOTD:
2808 		UI_DrawServerMOTD( &rect, scale, color );
2809 		break;
2810 	case UI_GLINFO:
2811 		UI_DrawGLInfo( &rect,scale, color, textStyle );
2812 		break;
2813 	case UI_KEYBINDSTATUS:
2814 		UI_DrawKeyBindStatus( &rect,scale, color, textStyle );
2815 		break;
2816 		// NERVE - SMF
2817 	case UI_LIMBOCHAT:
2818 		UI_DrawLimboChat( &rect,scale, color, textStyle );
2819 		break;
2820 		// -NERVE - SMF
2821 	default:
2822 		break;
2823 	}
2824 }
2825 
UI_OwnerDrawVisible(int flags)2826 static qboolean UI_OwnerDrawVisible( int flags ) {
2827 	qboolean vis = qtrue;
2828 
2829 	while ( flags ) {
2830 
2831 		if ( flags & UI_SHOW_FFA ) {
2832 			if ( trap_Cvar_VariableValue( "g_gametype" ) != GT_FFA ) {
2833 				vis = qfalse;
2834 			}
2835 			flags &= ~UI_SHOW_FFA;
2836 		}
2837 
2838 		if ( flags & UI_SHOW_NOTFFA ) {
2839 			if ( trap_Cvar_VariableValue( "g_gametype" ) == GT_FFA ) {
2840 				vis = qfalse;
2841 			}
2842 			flags &= ~UI_SHOW_NOTFFA;
2843 		}
2844 
2845 		if ( flags & UI_SHOW_LEADER ) {
2846 			// these need to show when this client can give orders to a player or a group
2847 			if ( !uiInfo.teamLeader ) {
2848 				vis = qfalse;
2849 			} else {
2850 				// if showing yourself
2851 				if ( ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber ) {
2852 					vis = qfalse;
2853 				}
2854 			}
2855 			flags &= ~UI_SHOW_LEADER;
2856 		}
2857 		if ( flags & UI_SHOW_NOTLEADER ) {
2858 			// these need to show when this client is assigning their own status or they are NOT the leader
2859 			if ( uiInfo.teamLeader ) {
2860 				// if not showing yourself
2861 				if ( !( ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber ) ) {
2862 					vis = qfalse;
2863 				}
2864 			}
2865 			flags &= ~UI_SHOW_NOTLEADER;
2866 		}
2867 		if ( flags & UI_SHOW_FAVORITESERVERS ) {
2868 			// this assumes you only put this type of display flag on something showing in the proper context
2869 			if ( ui_netSource.integer != UIAS_FAVORITES ) {
2870 				vis = qfalse;
2871 			}
2872 			flags &= ~UI_SHOW_FAVORITESERVERS;
2873 		}
2874 		if ( flags & UI_SHOW_NOTFAVORITESERVERS ) {
2875 			// this assumes you only put this type of display flag on something showing in the proper context
2876 			if ( ui_netSource.integer == UIAS_FAVORITES ) {
2877 				vis = qfalse;
2878 			}
2879 			flags &= ~UI_SHOW_NOTFAVORITESERVERS;
2880 		}
2881 		if ( flags & UI_SHOW_ANYTEAMGAME ) {
2882 			if ( uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM ) {
2883 				vis = qfalse;
2884 			}
2885 			flags &= ~UI_SHOW_ANYTEAMGAME;
2886 		}
2887 		if ( flags & UI_SHOW_ANYNONTEAMGAME ) {
2888 			if ( uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM ) {
2889 				vis = qfalse;
2890 			}
2891 			flags &= ~UI_SHOW_ANYNONTEAMGAME;
2892 		}
2893 		if ( flags & UI_SHOW_NETANYTEAMGAME ) {
2894 			if ( uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM ) {
2895 				vis = qfalse;
2896 			}
2897 			flags &= ~UI_SHOW_NETANYTEAMGAME;
2898 		}
2899 		if ( flags & UI_SHOW_NETANYNONTEAMGAME ) {
2900 			if ( uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM ) {
2901 				vis = qfalse;
2902 			}
2903 			flags &= ~UI_SHOW_NETANYNONTEAMGAME;
2904 		}
2905 		if ( flags & UI_SHOW_NEWHIGHSCORE ) {
2906 			if ( uiInfo.newHighScoreTime < uiInfo.uiDC.realTime ) {
2907 				vis = qfalse;
2908 			} else {
2909 				if ( uiInfo.soundHighScore ) {
2910 					if ( trap_Cvar_VariableValue( "sv_killserver" ) == 0 ) {
2911 						// wait on server to go down before playing sound
2912 						trap_S_StartLocalSound( uiInfo.newHighScoreSound, CHAN_ANNOUNCER );
2913 						uiInfo.soundHighScore = qfalse;
2914 					}
2915 				}
2916 			}
2917 			flags &= ~UI_SHOW_NEWHIGHSCORE;
2918 		}
2919 		if ( flags & UI_SHOW_NEWBESTTIME ) {
2920 			if ( uiInfo.newBestTime < uiInfo.uiDC.realTime ) {
2921 				vis = qfalse;
2922 			}
2923 			flags &= ~UI_SHOW_NEWBESTTIME;
2924 		}
2925 		if ( flags & UI_SHOW_DEMOAVAILABLE ) {
2926 			if ( !uiInfo.demoAvailable ) {
2927 				vis = qfalse;
2928 			}
2929 			flags &= ~UI_SHOW_DEMOAVAILABLE;
2930 		} else {
2931 			flags = 0;
2932 		}
2933 	}
2934 	return vis;
2935 }
2936 
UI_Handicap_HandleKey(int flags,float * special,int key)2937 static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
2938 	int select = UI_SelectForKey(key);
2939 	if (select != 0) {
2940 		int h;
2941 
2942 		h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
2943 		h += 5 * select;
2944 
2945 		if (h > 100) {
2946 			h = 5;
2947 		} else if (h < 5) {
2948 			h = 100;
2949 		}
2950 
2951 		trap_Cvar_SetValue( "handicap", h );
2952 		return qtrue;
2953 	}
2954 	return qfalse;
2955 }
2956 
UI_Effects_HandleKey(int flags,float * special,int key)2957 static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
2958 	int select = UI_SelectForKey(key);
2959 	if (select != 0) {
2960 		uiInfo.effectsColor += select;
2961 
2962 		if( uiInfo.effectsColor > 6 ) {
2963 			uiInfo.effectsColor = 0;
2964 		} else if (uiInfo.effectsColor < 0) {
2965 			uiInfo.effectsColor = 6;
2966 		}
2967 
2968 		trap_Cvar_SetValue( "color", uitogamecode[uiInfo.effectsColor] );
2969 		return qtrue;
2970 	}
2971 	return qfalse;
2972 }
2973 
UI_ClanName_HandleKey(int flags,float * special,int key)2974 static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
2975 	int select = UI_SelectForKey(key);
2976 	if (select != 0) {
2977 		int i;
2978 
2979 		i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2980 
2981 		if (uiInfo.teamList[i].cinematic >= 0) {
2982 			trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
2983 			uiInfo.teamList[i].cinematic = -1;
2984 		}
2985 
2986 		i += select;
2987 
2988 		if (i >= uiInfo.teamCount) {
2989 			i = 0;
2990 		} else if (i < 0) {
2991 			i = uiInfo.teamCount - 1;
2992 		}
2993 
2994 		trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
2995 		updateModel = qtrue;
2996 		return qtrue;
2997 	}
2998 	return qfalse;
2999 }
3000 
UI_GameType_HandleKey(int flags,float * special,int key,qboolean resetMap)3001 static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
3002 //#ifdef MISSIONPACK
3003 	int select = UI_SelectForKey(key);
3004 	if (select != 0) {
3005 		int oldCount = UI_MapCountByGameType(qtrue);
3006 
3007 		// hard coded mess here
3008 		if (select < 0) {
3009 			ui_gameType.integer--;
3010 			if (ui_gameType.integer == 2) {
3011 				ui_gameType.integer = 1;
3012 			} else if (ui_gameType.integer < 2) {
3013 				ui_gameType.integer = uiInfo.numGameTypes - 1;
3014 			}
3015 		} else {
3016 			ui_gameType.integer++;
3017 			if (ui_gameType.integer >= uiInfo.numGameTypes) {
3018 				ui_gameType.integer = 1;
3019 			} else if (ui_gameType.integer == 2) {
3020 				ui_gameType.integer = 3;
3021 			}
3022 		}
3023 
3024 		if (uiInfo.gameTypes[ui_gameType.integer].gtEnum < GT_TEAM) {
3025 			trap_Cvar_SetValue( "ui_Q3Model", 1 );
3026 		} else {
3027 			trap_Cvar_SetValue( "ui_Q3Model", 0 );
3028 		}
3029 
3030 		trap_Cvar_SetValue("ui_gameType", ui_gameType.integer);
3031 		UI_SetCapFragLimits(qtrue);
3032 		UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
3033 		if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
3034 			trap_Cvar_SetValue( "ui_currentMap", 0);
3035 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
3036 		}
3037 		return qtrue;
3038 	}
3039 //#endif	// #ifdef MISSIONPACK
3040 	return qfalse;
3041 }
3042 
UI_NetGameType_HandleKey(int flags,float * special,int key)3043 static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
3044 //#ifdef MISSIONPACK
3045 	int select = UI_SelectForKey(key);
3046 	if (select != 0) {
3047 		ui_netGameType.integer += select;
3048 
3049 		if (ui_netGameType.integer < 0) {
3050 			ui_netGameType.integer = uiInfo.numGameTypes - 1;
3051 		} else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
3052 			ui_netGameType.integer = 0;
3053 		}
3054 
3055 		trap_Cvar_SetValue( "ui_netGameType", ui_netGameType.integer);
3056 		trap_Cvar_SetValue( "ui_actualnetGameType", uiInfo.gameTypes[ui_netGameType.integer].gtEnum);
3057 		trap_Cvar_SetValue( "ui_currentNetMap", 0);
3058 		UI_MapCountByGameType(qfalse);
3059 		Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
3060 		return qtrue;
3061 	}
3062 //#endif	// #ifdef MISSIONPACK
3063 	return qfalse;
3064 }
3065 
UI_JoinGameType_HandleKey(int flags,float * special,int key)3066 static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
3067 //#ifdef MISSIONPACK
3068 	int select = UI_SelectForKey(key);
3069 	if (select != 0) {
3070 		ui_joinGameType.integer += select;
3071 
3072 		if (ui_joinGameType.integer < 0) {
3073 			ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
3074 		} else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
3075 			ui_joinGameType.integer = 0;
3076 		}
3077 
3078 		trap_Cvar_SetValue( "ui_joinGameType", ui_joinGameType.integer);
3079 		UI_BuildServerDisplayList(qtrue);
3080 		return qtrue;
3081 	}
3082 //#endif	// #ifdef MISSIONPACK
3083 	return qfalse;
3084 }
3085 
3086 
3087 
UI_Skill_HandleKey(int flags,float * special,int key)3088 static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
3089 	int select = UI_SelectForKey(key);
3090 	if (select != 0) {
3091 		int i = trap_Cvar_VariableValue( "g_spSkill" );
3092 
3093 		i += select;
3094 
3095 		if (i < 1) {
3096 			i = numSkillLevels;
3097 		} else if (i > numSkillLevels) {
3098 			i = 1;
3099 		}
3100 
3101 		trap_Cvar_SetValue("g_spSkill", i);
3102 		return qtrue;
3103 	}
3104 	return qfalse;
3105 }
3106 
UI_TeamName_HandleKey(int flags,float * special,int key,qboolean blue)3107 static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
3108 	int select = UI_SelectForKey(key);
3109 	if (select != 0) {
3110 		int i;
3111 
3112 		i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
3113 		i += select;
3114 
3115 		if (i >= uiInfo.teamCount) {
3116 			i = 0;
3117 		} else if (i < 0) {
3118 			i = uiInfo.teamCount - 1;
3119 		}
3120 
3121 		trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
3122 		return qtrue;
3123 	}
3124 	return qfalse;
3125 }
3126 
UI_TeamMember_HandleKey(int flags,float * special,int key,qboolean blue,int num)3127 static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
3128 	int select = UI_SelectForKey(key);
3129 	if (select != 0) {
3130 		// 0 - None
3131 		// 1 - Human
3132 		// 2..NumCharacters - Bot
3133 		char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
3134 		int value = trap_Cvar_VariableValue(cvar);
3135 
3136 		value += select;
3137 
3138 		if (ui_actualNetGameType.integer >= GT_TEAM) {
3139 			if (value >= uiInfo.characterCount + 2) {
3140 				value = 0;
3141 			} else if (value < 0) {
3142 				value = uiInfo.characterCount + 2 - 1;
3143 			}
3144 		} else {
3145 			if (value >= UI_GetNumBots() + 2) {
3146 				value = 0;
3147 			} else if (value < 0) {
3148 				value = UI_GetNumBots() + 2 - 1;
3149 			}
3150 		}
3151 
3152 		trap_Cvar_SetValue(cvar, value);
3153 		return qtrue;
3154 	}
3155 	return qfalse;
3156 }
3157 
UI_NetSource_HandleKey(int flags,float * special,int key)3158 static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
3159 //#ifdef MISSIONPACK
3160 	int select = UI_SelectForKey(key);
3161 	if (select != 0) {
3162 		ui_netSource.integer += select;
3163 
3164 		if(ui_netSource.integer >= UIAS_GLOBAL1 && ui_netSource.integer <= UIAS_GLOBAL5)
3165 		{
3166 			char masterstr[2], cvarname[sizeof("sv_master1")];
3167 
3168 			while(ui_netSource.integer >= UIAS_GLOBAL1 && ui_netSource.integer <= UIAS_GLOBAL5)
3169 			{
3170 				Com_sprintf(cvarname, sizeof(cvarname), "sv_master%d", ui_netSource.integer - UIAS_GLOBAL0);
3171 				trap_Cvar_VariableStringBuffer(cvarname, masterstr, sizeof(masterstr));
3172 				if(*masterstr)
3173 					break;
3174 
3175 				ui_netSource.integer += select;
3176 			}
3177 		}
3178 
3179 		if (ui_netSource.integer >= numNetSources) {
3180 			ui_netSource.integer = 0;
3181 		} else if (ui_netSource.integer < 0) {
3182 			ui_netSource.integer = numNetSources - 1;
3183 		}
3184 
3185 		UI_BuildServerDisplayList(qtrue);
3186 		UI_StartServerRefresh(qtrue, qfalse);
3187 		trap_Cvar_SetValue( "ui_netSource", ui_netSource.integer);
3188 		return qtrue;
3189 	}
3190 //#endif	// #ifdef MISSIONPACK
3191 	return qfalse;
3192 }
3193 
UI_NetFilter_HandleKey(int flags,float * special,int key)3194 static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
3195 //#ifdef MISSIONPACK
3196 	int select = UI_SelectForKey(key);
3197 	if (select != 0) {
3198 		ui_serverFilterType.integer += select;
3199 
3200 		if (ui_serverFilterType.integer >= numServerFilters) {
3201 			ui_serverFilterType.integer = 0;
3202 		} else if (ui_serverFilterType.integer < 0) {
3203 			ui_serverFilterType.integer = numServerFilters - 1;
3204 		}
3205 		UI_BuildServerDisplayList(qtrue);
3206 		return qtrue;
3207 	}
3208 //#endif	// #ifdef MISSIONPACK
3209 	return qfalse;
3210 }
3211 
UI_OpponentName_HandleKey(int flags,float * special,int key)3212 static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
3213 	int select = UI_SelectForKey(key);
3214 	if (select != 0) {
3215 		if (select < 0) {
3216 			UI_PriorOpponent();
3217 		} else {
3218 			UI_NextOpponent();
3219 		}
3220 		return qtrue;
3221 	}
3222 	return qfalse;
3223 }
3224 
UI_BotName_HandleKey(int flags,float * special,int key)3225 static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
3226 	int select = UI_SelectForKey(key);
3227 	if (select != 0) {
3228 		int game = trap_Cvar_VariableValue("g_gametype");
3229 		int value = uiInfo.botIndex;
3230 
3231 		value += select;
3232 
3233 		if (game >= GT_TEAM) {
3234 			if (value >= uiInfo.characterCount) {
3235 				value = 0;
3236 			} else if (value < 0) {
3237 				value = uiInfo.characterCount - 1;
3238 			}
3239 		} else {
3240 			if (value >= UI_GetNumBots()) {
3241 				value = 0;
3242 			} else if (value < 0) {
3243 				value = UI_GetNumBots() - 1;
3244 			}
3245 		}
3246 		uiInfo.botIndex = value;
3247 		return qtrue;
3248 	}
3249 	return qfalse;
3250 }
3251 
UI_BotSkill_HandleKey(int flags,float * special,int key)3252 static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
3253 	int select = UI_SelectForKey(key);
3254 	if (select != 0) {
3255 		uiInfo.skillIndex += select;
3256 
3257 		if (uiInfo.skillIndex >= numSkillLevels) {
3258 			uiInfo.skillIndex = 0;
3259 		} else if (uiInfo.skillIndex < 0) {
3260 			uiInfo.skillIndex = numSkillLevels-1;
3261 		}
3262 		return qtrue;
3263 	}
3264 	return qfalse;
3265 }
3266 
UI_RedBlue_HandleKey(int flags,float * special,int key)3267 static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
3268 	int select = UI_SelectForKey(key);
3269 	if (select != 0) {
3270 		uiInfo.redBlue ^= 1;
3271 		return qtrue;
3272 	}
3273 	return qfalse;
3274 }
3275 
UI_Crosshair_HandleKey(int flags,float * special,int key)3276 static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
3277 	int select = UI_SelectForKey(key);
3278 	if (select != 0) {
3279 		uiInfo.currentCrosshair += select;
3280 
3281 		if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
3282 			uiInfo.currentCrosshair = 0;
3283 		} else if (uiInfo.currentCrosshair < 0) {
3284 			uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
3285 		}
3286 		trap_Cvar_SetValue("cg_drawCrosshair", uiInfo.currentCrosshair);
3287 		return qtrue;
3288 	}
3289 	return qfalse;
3290 }
3291 
3292 
3293 
UI_SelectedPlayer_HandleKey(int flags,float * special,int key)3294 static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
3295 	int select = UI_SelectForKey(key);
3296 	if (select != 0) {
3297 		int selected;
3298 
3299 		UI_BuildPlayerList();
3300 		if (!uiInfo.teamLeader) {
3301 			return qfalse;
3302 		}
3303 		selected = trap_Cvar_VariableValue("cg_selectedPlayer");
3304 
3305 		selected += select;
3306 
3307 		if (selected > uiInfo.myTeamCount) {
3308 			selected = 0;
3309 		} else if (selected < 0) {
3310 			selected = uiInfo.myTeamCount;
3311 		}
3312 
3313 		if (selected == uiInfo.myTeamCount) {
3314 			trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
3315 		} else {
3316 			trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
3317 		}
3318 		trap_Cvar_SetValue( "cg_selectedPlayer", selected);
3319 	}
3320 	return qfalse;
3321 }
3322 
3323 
UI_OwnerDrawHandleKey(int ownerDraw,int flags,float * special,int key)3324 static qboolean UI_OwnerDrawHandleKey( int ownerDraw, int flags, float *special, int key ) {
3325 	switch ( ownerDraw ) {
3326 	case UI_HANDICAP:
3327 		return UI_Handicap_HandleKey( flags, special, key );
3328 		break;
3329 	case UI_EFFECTS:
3330 		return UI_Effects_HandleKey( flags, special, key );
3331 		break;
3332 	case UI_CLANNAME:
3333 		return UI_ClanName_HandleKey( flags, special, key );
3334 		break;
3335 	case UI_GAMETYPE:
3336 		return UI_GameType_HandleKey( flags, special, key, qtrue );
3337 		break;
3338 	case UI_NETGAMETYPE:
3339 		return UI_NetGameType_HandleKey( flags, special, key );
3340 		break;
3341 	case UI_JOINGAMETYPE:
3342 		return UI_JoinGameType_HandleKey( flags, special, key );
3343 		break;
3344 	case UI_SKILL:
3345 		return UI_Skill_HandleKey( flags, special, key );
3346 		break;
3347 	case UI_BLUETEAMNAME:
3348 		return UI_TeamName_HandleKey( flags, special, key, qtrue );
3349 		break;
3350 	case UI_REDTEAMNAME:
3351 		return UI_TeamName_HandleKey( flags, special, key, qfalse );
3352 		break;
3353 	case UI_BLUETEAM1:
3354 	case UI_BLUETEAM2:
3355 	case UI_BLUETEAM3:
3356 	case UI_BLUETEAM4:
3357 	case UI_BLUETEAM5:
3358 		UI_TeamMember_HandleKey( flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1 );
3359 		break;
3360 	case UI_REDTEAM1:
3361 	case UI_REDTEAM2:
3362 	case UI_REDTEAM3:
3363 	case UI_REDTEAM4:
3364 	case UI_REDTEAM5:
3365 		UI_TeamMember_HandleKey( flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1 );
3366 		break;
3367 	case UI_NETSOURCE:
3368 		UI_NetSource_HandleKey( flags, special, key );
3369 		break;
3370 	case UI_NETFILTER:
3371 		UI_NetFilter_HandleKey( flags, special, key );
3372 		break;
3373 	case UI_OPPONENT_NAME:
3374 		UI_OpponentName_HandleKey( flags, special, key );
3375 		break;
3376 	case UI_BOTNAME:
3377 		return UI_BotName_HandleKey( flags, special, key );
3378 		break;
3379 	case UI_BOTSKILL:
3380 		return UI_BotSkill_HandleKey( flags, special, key );
3381 		break;
3382 	case UI_REDBLUE:
3383 		UI_RedBlue_HandleKey( flags, special, key );
3384 		break;
3385 	case UI_CROSSHAIR:
3386 		UI_Crosshair_HandleKey( flags, special, key );
3387 		break;
3388 	case UI_SELECTEDPLAYER:
3389 		UI_SelectedPlayer_HandleKey( flags, special, key );
3390 		break;
3391 	default:
3392 		break;
3393 	}
3394 
3395 	return qfalse;
3396 }
3397 
3398 
UI_GetValue(int ownerDraw,int type)3399 static float UI_GetValue( int ownerDraw, int type ) {
3400 	return 0;
3401 }
3402 
3403 /*
3404 =================
3405 UI_ServersQsortCompare
3406 =================
3407 */
UI_ServersQsortCompare(const void * arg1,const void * arg2)3408 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
3409 //#ifdef MISSIONPACK
3410 	return trap_LAN_CompareServers( UI_SourceForLAN(), uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
3411 //#else
3412 //	return qfalse;
3413 //#endif	// #ifdef MISSIONPACK
3414 }
3415 
3416 
3417 /*
3418 =================
3419 UI_ServersSort
3420 =================
3421 */
UI_ServersSort(int column,qboolean force)3422 void UI_ServersSort( int column, qboolean force ) {
3423 
3424 	if ( !force ) {
3425 		if ( uiInfo.serverStatus.sortKey == column ) {
3426 			return;
3427 		}
3428 	}
3429 
3430 	uiInfo.serverStatus.sortKey = column;
3431 	qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof( int ), UI_ServersQsortCompare );
3432 
3433 	// update displayed levelshot
3434 	UI_FeederSelection( FEEDER_SERVERS, uiInfo.serverStatus.currentServer );
3435 }
3436 
3437 
3438 
3439 /*
3440 ===============
3441 UI_LoadMods
3442 ===============
3443 */
UI_LoadMods(void)3444 static void UI_LoadMods( void ) {
3445 	int numdirs;
3446 	char dirlist[2048];
3447 	char    *dirptr;
3448 	char  *descptr;
3449 	int i;
3450 	int dirlen;
3451 
3452 	uiInfo.modCount = 0;
3453 	numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof( dirlist ) );
3454 	dirptr  = dirlist;
3455 	for ( i = 0; i < numdirs; i++ ) {
3456 		dirlen = strlen( dirptr ) + 1;
3457 		descptr = dirptr + dirlen;
3458 		uiInfo.modList[uiInfo.modCount].modName = String_Alloc( dirptr );
3459 		uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc( descptr );
3460 		dirptr += dirlen + strlen( descptr ) + 1;
3461 		uiInfo.modCount++;
3462 		if ( uiInfo.modCount >= MAX_MODS ) {
3463 			break;
3464 		}
3465 	}
3466 
3467 }
3468 
3469 
3470 /*
3471 ===============
3472 UI_LoadTeams
3473 ===============
3474 */
3475 /*
3476 // TTimo: unused
3477 static void UI_LoadTeams( void ) {
3478 	char	teamList[4096];
3479 	char	*teamName;
3480 	int		i, len, count;
3481 
3482 	count = trap_FS_GetFileList( "", "team", teamList, 4096 );
3483 
3484 	if (count) {
3485 		teamName = teamList;
3486 		for ( i = 0; i < count; i++ ) {
3487 			len = strlen( teamName );
3488 			UI_ParseTeamInfo(teamName);
3489 			teamName += len + 1;
3490 		}
3491 	}
3492 }
3493 */
3494 
3495 /*
3496 ==============
3497 UI_DelSavegame
3498 ==============
3499 */
UI_DelSavegame(void)3500 static void UI_DelSavegame( void ) {
3501 
3502 	int ret;
3503 
3504 	ret = trap_FS_Delete( va( "save/%s.svg", uiInfo.savegameList[uiInfo.savegameIndex].name ) );
3505 	trap_FS_Delete( va( "save/images/%s.tga", uiInfo.savegameList[uiInfo.savegameIndex].name ) );
3506 
3507 	if ( ret ) {
3508 		Com_Printf( "Deleted savegame: %s.svg\n", uiInfo.savegameList[uiInfo.savegameIndex].name );
3509 	} else {
3510 		Com_Printf( "Unable to delete savegame: %s.svg\n", uiInfo.savegameList[uiInfo.savegameIndex].name );
3511 	}
3512 }
3513 
3514 /*
3515 ==============
3516 UI_LoadSavegames
3517 ==============
3518 */
UI_LoadSavegames(void)3519 static void UI_LoadSavegames( void ) {
3520 	char sglist[4096];
3521 	char    *sgname;
3522 	int i, len;
3523 
3524 	uiInfo.savegameCount = trap_FS_GetFileList( "save", "svg", sglist, 4096 );
3525 
3526 	if ( uiInfo.savegameCount ) {
3527 		if ( uiInfo.savegameCount > MAX_SAVEGAMES ) {
3528 			uiInfo.savegameCount = MAX_SAVEGAMES;
3529 		}
3530 		sgname = sglist;
3531 		for ( i = 0; i < uiInfo.savegameCount; i++ ) {
3532 
3533 			len = strlen( sgname );
3534 
3535 			if ( !Q_strncmp( sgname, "current", 7 ) ) {   // ignore current.svg since it has special uses and shouldn't be loaded directly
3536 				i--;
3537 				uiInfo.savegameCount -= 1;
3538 				sgname += len + 1;
3539 				continue;
3540 			}
3541 
3542 			if ( !Q_stricmp( sgname +  len - 4,".svg" ) ) {
3543 				sgname[len - 4] = '\0';
3544 			}
3545 			Q_strupr( sgname );
3546 			uiInfo.savegameList[i].name = String_Alloc( sgname );
3547 			uiInfo.savegameList[i].sshotImage = trap_R_RegisterShaderNoMip( va( "save/images/%s.tga",uiInfo.savegameList[i].name ) );
3548 			sgname += len + 1;
3549 		}
3550 	}
3551 }
3552 
3553 
3554 /*
3555 ===============
3556 UI_LoadMovies
3557 ===============
3558 */
UI_LoadMovies(void)3559 static void UI_LoadMovies( void ) {
3560 	char movielist[4096];
3561 	char    *moviename;
3562 	int i, len;
3563 
3564 	uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
3565 
3566 	if ( uiInfo.movieCount ) {
3567 		if ( uiInfo.movieCount > MAX_MOVIES ) {
3568 			uiInfo.movieCount = MAX_MOVIES;
3569 		}
3570 		moviename = movielist;
3571 		for ( i = 0; i < uiInfo.movieCount; i++ ) {
3572 			len = strlen( moviename );
3573 			if ( !Q_stricmp( moviename +  len - 4,".roq" ) ) {
3574 				moviename[len - 4] = '\0';
3575 			}
3576 			Q_strupr( moviename );
3577 			uiInfo.movieList[i] = String_Alloc( moviename );
3578 			moviename += len + 1;
3579 		}
3580 	}
3581 
3582 }
3583 
3584 #define NAMEBUFSIZE (MAX_DEMOS * 32)
3585 
3586 /*
3587 ===============
3588 UI_LoadDemos
3589 ===============
3590 */
UI_LoadDemos(void)3591 static void UI_LoadDemos( void ) {
3592 	char	demolist[NAMEBUFSIZE];
3593 	char	demoExt[32];
3594 	char    *demoname;
3595 	int i, j, len;
3596 	int	protocol, protocolLegacy;
3597 
3598 	protocolLegacy = trap_Cvar_VariableValue("com_legacyprotocol");
3599 	protocol = trap_Cvar_VariableValue("com_protocol");
3600 
3601 	if(!protocol)
3602 		protocol = trap_Cvar_VariableValue("protocol");
3603 	if(protocolLegacy == protocol)
3604 		protocolLegacy = 0;
3605 
3606 	Com_sprintf(demoExt, sizeof(demoExt), ".%s%d", DEMOEXT, protocol);
3607 	uiInfo.demoCount = trap_FS_GetFileList("demos", demoExt, demolist, ARRAY_LEN(demolist));
3608 
3609 	demoname = demolist;
3610 	i = 0;
3611 
3612 	for(j = 0; j < 2; j++)
3613 	{
3614 		if(uiInfo.demoCount > MAX_DEMOS)
3615 			uiInfo.demoCount = MAX_DEMOS;
3616 
3617 		for(; i < uiInfo.demoCount; i++)
3618 		{
3619 			len = strlen(demoname);
3620 			uiInfo.demoList[i] = String_Alloc( demoname );
3621 			demoname += len + 1;
3622 		}
3623 
3624 		if(!j)
3625 		{
3626 		        if(protocolLegacy > 0 && uiInfo.demoCount < MAX_DEMOS)
3627 		        {
3628                         	Com_sprintf(demoExt, sizeof(demoExt), ".%s%d", DEMOEXT, protocolLegacy);
3629                         	uiInfo.demoCount += trap_FS_GetFileList("demos", demoExt, demolist, ARRAY_LEN(demolist));
3630                         	demoname = demolist;
3631                         }
3632                         else
3633                                 break;
3634 		}
3635 	}
3636 
3637 }
3638 
3639 
3640 /*
3641 ==============
3642 UI_SetNextMap
3643 ==============
3644 */
3645 /*
3646 // TTimo: unused
3647 static qboolean UI_SetNextMap(int actual, int index) {
3648 	int i;
3649 	for (i = actual + 1; i < uiInfo.mapCount; i++) {
3650 		if (uiInfo.mapList[i].active) {
3651 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
3652 			return qtrue;
3653 		}
3654 	}
3655 	return qfalse;
3656 }
3657 */
3658 
3659 /*
3660 ==============
3661 UI_StartSkirmish
3662 ==============
3663 */
UI_StartSkirmish(qboolean next)3664 static void UI_StartSkirmish( qboolean next ) {
3665 #ifdef MISSIONPACK
3666 	int i, k, g, delay, temp;
3667 	float skill;
3668 	char buff[MAX_STRING_CHARS];
3669 
3670 	if ( next ) {
3671 		int actual;
3672 		int index = trap_Cvar_VariableValue( "ui_mapIndex" );
3673 		UI_MapCountByGameType( qtrue );
3674 		UI_SelectedMap( index, &actual );
3675 		if ( UI_SetNextMap( actual, index ) ) {
3676 		} else {
3677 			UI_GameType_HandleKey( 0, NULL, K_MOUSE1, qfalse );
3678 			UI_MapCountByGameType( qtrue );
3679 			Menu_SetFeederSelection( NULL, FEEDER_MAPS, 0, "skirmish" );
3680 		}
3681 	}
3682 
3683 	g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
3684 	trap_Cvar_SetValue( "g_gametype", g );
3685 	trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName ) );
3686 	skill = trap_Cvar_VariableValue( "g_spSkill" );
3687 	trap_Cvar_Set( "ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName );
3688 
3689 	k = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_opponentName" ) );
3690 
3691 	trap_Cvar_Set( "ui_singlePlayerActive", "1" );
3692 
3693 	// set up sp overrides, will be replaced on postgame
3694 	temp = trap_Cvar_VariableValue( "capturelimit" );
3695 	trap_Cvar_Set( "ui_saveCaptureLimit", va( "%i", temp ) );
3696 	temp = trap_Cvar_VariableValue( "fraglimit" );
3697 	trap_Cvar_Set( "ui_saveFragLimit", va( "%i", temp ) );
3698 
3699 	UI_SetCapFragLimits( qfalse );
3700 
3701 	temp = trap_Cvar_VariableValue( "cg_drawTimer" );
3702 	trap_Cvar_Set( "ui_drawTimer", va( "%i", temp ) );
3703 	temp = trap_Cvar_VariableValue( "g_doWarmup" );
3704 	trap_Cvar_Set( "ui_doWarmup", va( "%i", temp ) );
3705 	temp = trap_Cvar_VariableValue( "g_friendlyFire" );
3706 	trap_Cvar_Set( "ui_friendlyFire", va( "%i", temp ) );
3707 	temp = trap_Cvar_VariableValue( "sv_maxClients" );
3708 	trap_Cvar_Set( "ui_maxClients", va( "%i", temp ) );
3709 	temp = trap_Cvar_VariableValue( "g_warmup" );
3710 	trap_Cvar_Set( "ui_Warmup", va( "%i", temp ) );
3711 	temp = trap_Cvar_VariableValue( "sv_pure" );
3712 	trap_Cvar_Set( "ui_pure", va( "%i", temp ) );
3713 
3714 	trap_Cvar_Set( "cg_cameraOrbit", "0" );
3715 	trap_Cvar_Set( "cg_thirdPerson", "0" );
3716 	trap_Cvar_Set( "cg_drawTimer", "1" );
3717 	trap_Cvar_Set( "g_doWarmup", "1" );
3718 	trap_Cvar_Set( "g_warmup", "15" );
3719 	trap_Cvar_Set( "sv_pure", "0" );
3720 	trap_Cvar_Set( "g_friendlyFire", "0" );
3721 	trap_Cvar_Set( "g_redTeam", UI_Cvar_VariableString( "ui_teamName" ) );
3722 	trap_Cvar_Set( "g_blueTeam", UI_Cvar_VariableString( "ui_opponentName" ) );
3723 
3724 	if ( trap_Cvar_VariableValue( "ui_recordSPDemo" ) ) {
3725 		Com_sprintf( buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g );
3726 		trap_Cvar_Set( "ui_recordSPDemoName", buff );
3727 	}
3728 
3729 	delay = 500;
3730 
3731 	if ( g == GT_TOURNAMENT ) {
3732 		trap_Cvar_Set( "sv_maxClients", "2" );
3733 		Com_sprintf( buff, sizeof( buff ), "wait ; addbot %s %f " ", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay );
3734 		trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3735 	} else {
3736 		temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
3737 		trap_Cvar_Set( "sv_maxClients", va( "%d", temp ) );
3738 		for ( i = 0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++ ) {
3739 			Com_sprintf( buff, sizeof( buff ), "addbot %s %f %s %i %s\n", UI_AIFromName( uiInfo.teamList[k].teamMembers[i] ), skill, ( g == GT_FFA ) ? "" : "Blue", delay, uiInfo.teamList[k].teamMembers[i] );
3740 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3741 			delay += 500;
3742 		}
3743 		k = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
3744 		for ( i = 0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers - 1; i++ ) {
3745 			Com_sprintf( buff, sizeof( buff ), "addbot %s %f %s %i %s\n", UI_AIFromName( uiInfo.teamList[k].teamMembers[i] ), skill, ( g == GT_FFA ) ? "" : "Red", delay, uiInfo.teamList[k].teamMembers[i] );
3746 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3747 			delay += 500;
3748 		}
3749 	}
3750 	if ( g >= GT_TEAM ) {
3751 		// send team command for vanilla q3 game qvm
3752 		trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
3753 
3754 		// set g_localTeamPref for ioq3 game qvm
3755 		trap_Cvar_Set( "g_localTeamPref", "Red" );
3756 	}
3757 #endif  // #ifdef MISSIONPACK
3758 }
3759 
3760 // NERVE - SMF
3761 /*
3762 ==============
3763 WM_ChangePlayerType
3764 ==============
3765 */
3766 
WM_getWeaponIndex(void)3767 int WM_getWeaponIndex( void ) {
3768 	int lookupIndex, i;
3769 
3770 	lookupIndex = trap_Cvar_VariableValue( "mp_weapon" );
3771 
3772 	for ( i = 1; weaponTypes[i].name; i++ ) {
3773 		if ( weaponTypes[i].value == lookupIndex ) {
3774 			return weaponTypes[i].weapindex;
3775 		}
3776 	}
3777 
3778 	return 0;
3779 }
3780 
WM_getWeaponAnim(const char ** torso_anim,const char ** legs_anim)3781 void WM_getWeaponAnim( const char **torso_anim, const char **legs_anim ) {
3782 	int lookupIndex, i;
3783 
3784 	lookupIndex = trap_Cvar_VariableValue( "mp_weapon" );
3785 
3786 	for ( i = 1; weaponTypes[i].name; i++ ) {
3787 		if ( weaponTypes[i].value == lookupIndex ) {
3788 			*torso_anim = weaponTypes[i].torso_anim;
3789 			*legs_anim = weaponTypes[i].legs_anim;
3790 			return;
3791 		}
3792 	}
3793 }
3794 
WM_setItemPic(char * name,const char * shader)3795 void WM_setItemPic( char *name, const char *shader ) {
3796 	menuDef_t *menu = Menu_GetFocused();
3797 	itemDef_t *item;
3798 
3799 	item = Menu_FindItemByName( menu, name );
3800 	if ( item ) {
3801 		item->window.background = DC->registerShaderNoMip( shader );
3802 	}
3803 }
3804 
WM_setVisibility(char * name,qboolean show)3805 void WM_setVisibility( char *name, qboolean show ) {
3806 	menuDef_t *menu = Menu_GetFocused();
3807 	itemDef_t *item;
3808 
3809 	item = Menu_FindItemByName( menu, name );
3810 	if ( item ) {
3811 		if ( show ) {
3812 			item->window.flags |= WINDOW_VISIBLE;
3813 		} else {
3814 			item->window.flags &= ~WINDOW_VISIBLE;
3815 		}
3816 	}
3817 }
3818 
WM_setWeaponPics(void)3819 void WM_setWeaponPics( void ) {
3820 	itemDef_t *knifeDef, *pistolDef, *weaponDef, *grenadeDef, *item1Def, *item2Def;
3821 	menuDef_t *menu = Menu_GetFocused();
3822 	int playerType, team, weapon, i;
3823 	const char *gunShader, *grenadeShader;
3824 
3825 	knifeDef = Menu_FindItemByName( menu, "window_knife_pic" );
3826 	pistolDef = Menu_FindItemByName( menu, "window_pistol_pic" );
3827 	weaponDef = Menu_FindItemByName( menu, "window_weapon_pic" );
3828 	grenadeDef = Menu_FindItemByName( menu, "window_grenade_pic" );
3829 	item1Def = Menu_FindItemByName( menu, "window_item1_pic" );
3830 	item2Def = Menu_FindItemByName( menu, "window_item2_pic" );
3831 
3832 	if ( !knifeDef ) {
3833 		return;
3834 	}
3835 
3836 	team = trap_Cvar_VariableValue( "mp_team" );
3837 	playerType = trap_Cvar_VariableValue( "mp_playerType" );
3838 	weapon = trap_Cvar_VariableValue( "mp_weapon" );
3839 
3840 	knifeDef->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_knife.tga" );
3841 
3842 	if ( team == 0 ) {
3843 		pistolDef->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_luger.tga" );
3844 		gunShader = "ui_mp/assets/weapon_mp40.tga";
3845 		grenadeShader = "ui_mp/assets/weapon_grenade_ger.tga";
3846 	} else {
3847 		pistolDef->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_colt1911.tga" );
3848 		gunShader = "ui_mp/assets/weapon_thompson.tga";
3849 		grenadeShader = "ui_mp/assets/weapon_grenade.tga";
3850 	}
3851 
3852 	weaponDef->window.background = DC->registerShaderNoMip( gunShader );
3853 	grenadeDef->window.background = DC->registerShaderNoMip( grenadeShader );
3854 
3855 	if ( playerType == 0 ) {        // soldier
3856 		item1Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/item_none.tga" );
3857 		item2Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/item_none.tga" );
3858 
3859 		if ( weapon ) {
3860 			for ( i = 0; weaponTypes[i].name; i++ )
3861 				if ( weaponTypes[i].value == weapon ) {
3862 					weaponDef->window.background = DC->registerShaderNoMip( weaponTypes[i].name );
3863 					break;
3864 				}
3865 		}
3866 	} else if ( playerType == 1 )   { // medic
3867 		item1Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_syringe.tga" );
3868 		item2Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_medheal.tga" );
3869 	} else if ( playerType == 2 )   { // engineer
3870 		item1Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_pliers.tga" );
3871 		item2Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_dynamite.tga" );
3872 	} else if ( playerType == 3 )   { // lieut
3873 		item1Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_smokegrenade.tga" );
3874 		item2Def->window.background = DC->registerShaderNoMip( "ui_mp/assets/weapon_ammo.tga" );
3875 
3876 		if ( weapon ) {
3877 			for ( i = 0; weaponTypes[i].name; i++ )
3878 				if ( weaponTypes[i].value == weapon ) {
3879 					weaponDef->window.background = DC->registerShaderNoMip( weaponTypes[i].name );
3880 					break;
3881 				}
3882 		}
3883 	}
3884 
3885 	// set button states
3886 	WM_setItemPic( "window_axisTeamButton", "ui_mp/assets/button.tga" );
3887 	WM_setItemPic( "window_alliedTeamButton", "ui_mp/assets/button.tga" );
3888 	WM_setItemPic( "window_specTeamButton", "ui_mp/assets/button.tga" );
3889 	WM_setItemPic( "window_classSoldierButton", "ui_mp/assets/button.tga" );
3890 	WM_setItemPic( "window_classMedicButton", "ui_mp/assets/button.tga" );
3891 	WM_setItemPic( "window_classEngrButton", "ui_mp/assets/button.tga" );
3892 	WM_setItemPic( "window_classLieutButton", "ui_mp/assets/button.tga" );
3893 
3894 	if ( team == 0 ) {
3895 		WM_setItemPic( "window_axisTeamButton", "ui_mp/assets/button_click.tga" );
3896 	} else if ( team == 1 ) {
3897 		WM_setItemPic( "window_alliedTeamButton", "ui_mp/assets/button_click.tga" );
3898 	} else {
3899 		WM_setItemPic( "window_specTeamButton", "ui_mp/assets/button_click.tga" );
3900 	}
3901 
3902 	if ( playerType == 0 ) {
3903 		WM_setItemPic( "window_classSoldierButton", "ui_mp/assets/button_click.tga" );
3904 	} else if ( playerType == 1 ) {
3905 		WM_setItemPic( "window_classMedicButton", "ui_mp/assets/button_click.tga" );
3906 	} else if ( playerType == 2 ) {
3907 		WM_setItemPic( "window_classEngrButton", "ui_mp/assets/button_click.tga" );
3908 	} else {
3909 		WM_setItemPic( "window_classLieutButton", "ui_mp/assets/button_click.tga" );
3910 	}
3911 
3912 	// set objective states
3913 	WM_setItemPic( "window_objectiveButton0", "ui_mp/assets/button.tga" );
3914 	WM_setItemPic( "window_objectiveButton1", "ui_mp/assets/button.tga" );
3915 	WM_setItemPic( "window_objectiveButton2", "ui_mp/assets/button.tga" );
3916 	WM_setItemPic( "window_objectiveButton3", "ui_mp/assets/button.tga" );
3917 	WM_setItemPic( "window_objectiveButton4", "ui_mp/assets/button.tga" );
3918 	WM_setItemPic( "window_objectiveButton5", "ui_mp/assets/button.tga" );
3919 	WM_setItemPic( "window_objectiveButton6", "ui_mp/assets/button.tga" );
3920 
3921 	WM_setItemPic( va( "window_objectiveButton%d", uiInfo.selectedObjective ), "ui_mp/assets/button_click.tga" );
3922 
3923 	// set player backgrounds
3924 	{
3925 		int val;
3926 		char *team_str = NULL; // TTimo: init
3927 		qboolean skip = qfalse;
3928 
3929 		// set team background
3930 		val = trap_Cvar_VariableValue( "mp_team" );
3931 
3932 		if ( val == SPECT_TEAM ) {
3933 			WM_setItemPic( "modelselection_flag", "multi_spectator" );
3934 			WM_setItemPic( "modelselection_model", "multi_spectator" );
3935 			skip = qtrue;
3936 		} else if ( val == AXIS_TEAM )   {
3937 			WM_setItemPic( "modelselection_flag", "multi_axisflag" );
3938 			team_str = "axis";
3939 		} else {
3940 			WM_setItemPic( "modelselection_flag", "multi_alliedflag" );
3941 			team_str = "allied";
3942 		}
3943 
3944 		if ( !skip ) {
3945 			// set player type
3946 			val = trap_Cvar_VariableValue( "mp_playerType" );
3947 
3948 			if ( val == 0 ) {
3949 				WM_setItemPic( "modelselection_model", va( "%s_soldier", team_str ) );
3950 			} else if ( val == 1 ) {
3951 				WM_setItemPic( "modelselection_model", va( "%s_medic", team_str ) );
3952 			} else if ( val == 2 ) {
3953 				WM_setItemPic( "modelselection_model", va( "%s_eng", team_str ) );
3954 			} else {
3955 				WM_setItemPic( "modelselection_model", va( "%s_lt", team_str ) );
3956 			}
3957 
3958 			// set weapon pics
3959 			if ( weapon ) {
3960 				for ( i = 0; weaponTypes[i].name; i++ )
3961 					if ( weaponTypes[i].value == weapon ) {
3962 						WM_setItemPic( "modelselection_weap", weaponTypes[i].large_shader );
3963 						break;
3964 					}
3965 			}
3966 		}
3967 	}
3968 
3969 	// set feeder visibility
3970 	if ( playerType == 0 ) {
3971 		WM_setVisibility( "window_feeder_soldierweap", qtrue );
3972 	} else {
3973 		WM_setVisibility( "window_feeder_soldierweap", qfalse );
3974 	}
3975 
3976 	if ( playerType == 3 ) {
3977 		WM_setVisibility( "window_feeder_lieutweap", qtrue );
3978 	} else {
3979 		WM_setVisibility( "window_feeder_lieutweap", qfalse );
3980 	}
3981 
3982 	// don't allow spectators to cycle through menus
3983 	if ( team == 2 ) {
3984 		WM_setVisibility( "window_pickTeamNext", qfalse );
3985 		WM_setVisibility( "window_pickTeamNextCmd", qfalse );
3986 		WM_setVisibility( "window_pickTeamNextDisabled", qtrue );
3987 
3988 		if ( ui_limboOptions.integer == 1 || ui_limboOptions.integer == 2 ) {
3989 			trap_Cvar_Set( "ui_limboOptions", "0" );
3990 		}
3991 	} else {
3992 		WM_setVisibility( "window_pickTeamNext", qtrue );
3993 		WM_setVisibility( "window_pickTeamNextCmd", qtrue );
3994 		WM_setVisibility( "window_pickTeamNextDisabled", qfalse );
3995 	}
3996 }
3997 
WM_ChangePlayerType(void)3998 static void WM_ChangePlayerType( void ) {
3999 	int i, j, playerType;
4000 	menuDef_t *menu = Menu_GetFocused();
4001 	itemDef_t *itemdef, *itemdef2;
4002 
4003 	playerType = trap_Cvar_VariableValue( "mp_playerType" );
4004 
4005 	for ( i = 0; i < 4; i++ ) {
4006 		itemdef = Menu_FindItemByName( menu, playerTypes[i].name );
4007 		if ( !itemdef ) {
4008 			continue;
4009 		}
4010 
4011 		if ( i == playerType ) {
4012 			Menu_ShowItemByName( itemdef->parent, playerTypes[i].name, qtrue );
4013 		} else {
4014 			Menu_ShowItemByName( itemdef->parent, playerTypes[i].name, qfalse );
4015 		}
4016 
4017 		// selected only settings
4018 		if ( i != playerType ) {
4019 			continue;
4020 		}
4021 
4022 		// force all to none first
4023 		for ( j = 0; itemTypes[j].name; j++ ) {
4024 			itemdef2 = Menu_FindItemByName( menu, itemTypes[j].name );
4025 			if ( itemdef2 ) {
4026 				itemdef2->window.background = DC->registerShaderNoMip( "ui_mp/assets/item_none.tga" );
4027 			}
4028 		}
4029 
4030 		// set values
4031 		for ( j = 0; itemTypes[j].name; j++ ) {
4032 			itemdef2 = Menu_FindItemByName( menu, itemTypes[j].name );
4033 			if ( itemdef2 && ( playerTypes[i].items & itemTypes[j].flags ) ) {
4034 				itemdef2->window.background = DC->registerShaderNoMip( itemTypes[j].shader );
4035 			}
4036 		}
4037 	}
4038 }
4039 
WM_GetSpawnPoints(void)4040 void WM_GetSpawnPoints( void ) {
4041 	char cs[MAX_STRING_CHARS];
4042 	const char *s;
4043 	int i;
4044 
4045 	trap_GetConfigString( CS_MULTI_INFO, cs, sizeof( cs ) );
4046 	s = Info_ValueForKey( cs, "numspawntargets" );
4047 
4048 	if ( !s || !strlen( s ) ) {
4049 		return;
4050 	}
4051 
4052 	// first index is for autopicking
4053 	Q_strncpyz( uiInfo.spawnPoints[0], UI_TranslateString( "Auto Pick" ), MAX_SPAWNDESC );
4054 
4055 	uiInfo.spawnCount = atoi( s ) + 1;
4056 
4057 	for ( i = 1; i < uiInfo.spawnCount; i++ ) {
4058 		trap_GetConfigString( CS_MULTI_SPAWNTARGETS + i - 1, cs, sizeof( cs ) );
4059 
4060 		s = Info_ValueForKey( cs, "spawn_targ" );
4061 		if ( !s || !strlen( s ) ) {
4062 			return;
4063 		}
4064 
4065 		Q_strncpyz( uiInfo.spawnPoints[i], UI_TranslateString( s ), MAX_SPAWNDESC );
4066 	}
4067 }
4068 
WM_SetObjective(int objectiveIndex)4069 void WM_SetObjective( int objectiveIndex ) {
4070 	char cs[MAX_STRING_CHARS], overviewImage[MAX_STRING_CHARS], desc[MAX_STRING_CHARS];
4071 	itemDef_t *def_pic, *def_desc, *def_button;
4072 	menuDef_t *menu = Menu_GetFocused();
4073 	int team, numobjectives, i;
4074 	char *s, *teamStr;
4075 	qboolean playRoq = qfalse;
4076 
4077 	uiInfo.selectedObjective = objectiveIndex;
4078 	objectiveIndex--;
4079 
4080 	// get item defs
4081 	def_pic = Menu_FindItemByName( menu, "window_objectivePic" );
4082 	def_desc = Menu_FindItemByName( menu, "window_objectiveDesc" );
4083 	if ( !def_pic || !def_desc ) {
4084 		return;
4085 	}
4086 
4087 	// set proper team
4088 	team = trap_Cvar_VariableValue( "mp_team" );
4089 
4090 	if ( team == AXIS_TEAM ) {
4091 		teamStr = "axis_desc";
4092 	} else {
4093 		teamStr = "allied_desc";
4094 	}
4095 
4096 	// get config strings
4097 	trap_GetConfigString( CS_MULTI_INFO, cs, sizeof( cs ) );
4098 	s = Info_ValueForKey( cs, "numobjectives" );
4099 	if ( !s || !strlen( s ) ) {
4100 		return;
4101 	}
4102 	numobjectives = atoi( s );
4103 
4104 	// get map overview
4105 	s = Info_ValueForKey( cs, "overviewimage" );
4106 	if ( s && strlen( s ) ) {
4107 		Q_strncpyz( overviewImage, s, MAX_STRING_CHARS );
4108 	} else {
4109 		Q_strncpyz( overviewImage, "menu/art/unknownmap", MAX_STRING_CHARS );
4110 	}
4111 
4112 	// enable/disable buttons
4113 	for ( i = 0; i < 6; i++ ) {
4114 		def_button = Menu_FindItemByName( menu, va( "window_objectiveButton%d", i + 1 ) );
4115 
4116 		if ( !def_button ) {
4117 			continue;
4118 		}
4119 
4120 		if ( i < numobjectives ) {
4121 			def_button->window.flags |= WINDOW_VISIBLE;
4122 		} else {
4123 			def_button->window.flags &= ~WINDOW_VISIBLE;
4124 		}
4125 	}
4126 
4127 	if ( numobjectives < objectiveIndex ) {
4128 		return;
4129 	}
4130 
4131 	// see if we want to play a roq instead
4132 	if ( strstr( overviewImage, ".roq" ) ) {
4133 		playRoq = qtrue;
4134 	}
4135 
4136 	// we want overview info
4137 	if ( objectiveIndex == -1 ) {
4138 		trap_GetConfigString( CS_MULTI_MAPDESC, cs, sizeof( cs ) );
4139 		trap_Cvar_Set( "ui_objective", UI_TranslateString( cs ) );
4140 
4141 		def_pic->window.flags |= WINDOW_VISIBLE;
4142 
4143 		if ( playRoq ) {
4144 			if ( !atoi( UI_Cvar_VariableString( "r_inGameVideo" ) ) ) {
4145 				def_pic->window.style = WINDOW_STYLE_SHADER;
4146 				def_pic->window.background = DC->registerShaderNoMip( "menu/art/unknownmap" );
4147 			} else {
4148 				def_pic->window.style = WINDOW_STYLE_CINEMATIC;
4149 				def_pic->window.cinematic = -1;
4150 				def_pic->window.cinematicName = String_Alloc( overviewImage );
4151 			}
4152 		} else {
4153 			def_pic->window.style = WINDOW_STYLE_SHADER;
4154 			def_pic->window.background = DC->registerShaderNoMip( overviewImage );
4155 		}
4156 		WM_setWeaponPics();
4157 		return;
4158 	}
4159 
4160 	trap_GetConfigString( CS_MULTI_OBJECTIVE1 + objectiveIndex, cs, sizeof( cs ) );
4161 	s = Info_ValueForKey( cs, teamStr );
4162 
4163 	if ( s && strlen( s ) ) {
4164 		s = UI_TranslateString( s );
4165 
4166 		// NERVE - SMF - get around config strings not having \n by using '*'
4167 		for ( i = 0; s[i] != '\0'; i++ ) {
4168 			if ( s[i] == '*' ) {
4169 				desc[i] = '\n';
4170 			} else {
4171 				desc[i] = s[i];
4172 			}
4173 		}
4174 		desc[i] = '\0';
4175 
4176 		trap_Cvar_Set( "ui_objective", desc );
4177 	}
4178 
4179 	// set proper shader
4180 	s = Info_ValueForKey( cs, "image" );
4181 
4182 	if ( s && strlen( s ) ) {
4183 		def_pic->window.flags |= WINDOW_VISIBLE;
4184 		def_pic->window.style = WINDOW_STYLE_SHADER;
4185 		def_pic->window.background = DC->registerShaderNoMip( s );
4186 	} else {
4187 		def_pic->window.style = WINDOW_STYLE_SHADER;
4188 		def_pic->window.background = DC->registerShaderNoMip( overviewImage );
4189 	}
4190 
4191 	WM_setWeaponPics();
4192 }
WM_SetDefaultWeapon(void)4193 void WM_SetDefaultWeapon( void ) {
4194 	menuDef_t *menu = Menu_GetFocused();
4195 	itemDef_t *item;
4196 	int startPos, index = 0;
4197 
4198 	if ( trap_Cvar_VariableValue( "mp_team" ) == AXIS_TEAM ) {
4199 		index = WM_WEAPON_MP40;
4200 		trap_Cvar_Set( "mp_weapon", va( "%i", index ) );
4201 		startPos = 0;
4202 	} else {
4203 		index = WM_WEAPON_THOMPSON;
4204 		trap_Cvar_Set( "mp_weapon", va( "%i", index ) );
4205 		startPos = 1;
4206 	}
4207 
4208 	item = Menu_FindItemByName( menu, "window_feeder_soldierweap" );
4209 	if ( item ) {
4210 		listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
4211 		if ( listPtr ) {
4212 			listPtr->startPos = 0;
4213 		}
4214 
4215 		item->cursorPos = startPos;
4216 		UI_FeederSelection( FEEDER_SOLDIERWEAP, item->cursorPos );
4217 	}
4218 
4219 	item = Menu_FindItemByName( menu, "window_feeder_lieutweap" );
4220 	if ( item ) {
4221 		listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
4222 		if ( listPtr ) {
4223 			listPtr->startPos = 0;
4224 		}
4225 
4226 		item->cursorPos = startPos;
4227 		UI_FeederSelection( FEEDER_LIEUTWEAP, item->cursorPos );
4228 	}
4229 
4230 	trap_Cvar_Set( weaponTypes[index].cvar, va( "%i", weaponTypes[index].value ) );
4231 	trap_Cvar_Set( "ui_weapon", UI_TranslateString( weaponTypes[index].desc ) );
4232 
4233 	WM_setWeaponPics();
4234 }
4235 
WM_PickItem(int selectionType,int itemIndex)4236 void WM_PickItem( int selectionType, int itemIndex ) {
4237 	//menuDef_t *menu = Menu_GetFocused(); // TTimo: unused
4238 	int oldclass, newclass;
4239 
4240 	if ( selectionType == WM_SELECT_TEAM ) {
4241 		switch ( itemIndex ) {
4242 		case WM_AXIS:
4243 			trap_Cvar_Set( "mp_team", "0" );
4244 			trap_Cvar_Set( "ui_team", "Axis" );
4245 			WM_SetDefaultWeapon();
4246 			break;
4247 		case WM_ALLIES:
4248 			trap_Cvar_Set( "mp_team", "1" );
4249 			trap_Cvar_Set( "ui_team", "Allies" );
4250 			WM_SetDefaultWeapon();
4251 			break;
4252 		case WM_SPECTATOR:
4253 			trap_Cvar_Set( "mp_team", "2" );
4254 			trap_Cvar_Set( "ui_team", "Spectator" );
4255 			WM_SetDefaultWeapon();
4256 			break;
4257 		}
4258 	} else if ( selectionType == WM_SELECT_CLASS )   {
4259 		switch ( itemIndex ) {
4260 		case WM_START_SELECT:
4261 			break;
4262 		case WM_SOLDIER:
4263 			oldclass = trap_Cvar_VariableValue( "mp_playerType" );
4264 			newclass = 0;
4265 
4266 			trap_Cvar_Set( "mp_playerType", "0" );
4267 			trap_Cvar_Set( "ui_class", "Soldier" );
4268 
4269 			if ( oldclass != newclass ) {
4270 				WM_SetDefaultWeapon();
4271 			}
4272 			break;
4273 		case WM_MEDIC:
4274 			trap_Cvar_Set( "mp_playerType", "1" );
4275 			trap_Cvar_Set( "ui_class", "Medic" );
4276 			WM_SetDefaultWeapon();
4277 			break;
4278 		case WM_ENGINEER:
4279 			trap_Cvar_Set( "mp_playerType", "2" );
4280 			trap_Cvar_Set( "ui_class", "Engineer" );
4281 			WM_SetDefaultWeapon();
4282 			break;
4283 		case WM_LIEUTENANT:
4284 			oldclass = trap_Cvar_VariableValue( "mp_playerType" );
4285 			newclass = 3;
4286 
4287 			trap_Cvar_Set( "mp_playerType", "3" );
4288 			trap_Cvar_Set( "ui_class", "Lieutenant" );
4289 
4290 			if ( oldclass != newclass ) {
4291 				WM_SetDefaultWeapon();
4292 			}
4293 			break;
4294 		}
4295 	} else if ( selectionType == WM_SELECT_WEAPON )   {
4296 		if ( itemIndex == WM_START_SELECT ) {
4297 		} else {
4298 			trap_Cvar_Set( weaponTypes[itemIndex].cvar, va( "%i", weaponTypes[itemIndex].value ) );
4299 			trap_Cvar_Set( "ui_weapon", UI_TranslateString( weaponTypes[itemIndex].desc ) );
4300 		}
4301 	}
4302 
4303 	WM_setWeaponPics();
4304 }
4305 
WM_LimboChat(void)4306 void WM_LimboChat( void ) {
4307 	char buf[200];
4308 
4309 	trap_Cvar_VariableStringBuffer( "ui_cmd", buf, 200 );
4310 
4311 	if ( strlen( buf ) ) {
4312 		trap_Cmd_ExecuteText( EXEC_APPEND, va( "say %s\n", buf ) );
4313 	}
4314 
4315 	trap_Cvar_Set( "ui_cmd", "" );
4316 }
4317 
4318 
UI_CheckExecKey(int key)4319 qboolean UI_CheckExecKey( int key ) {
4320 	menuDef_t *menu = Menu_GetFocused();
4321 
4322 	if ( g_editingField ) {
4323 		return qtrue;
4324 	}
4325 
4326 	if ( key > 256 ) {
4327 		return qfalse;
4328 	}
4329 
4330 	if ( !menu ) {
4331 		if ( !trap_Cvar_VariableValue( "cl_bypassMouseInput" ) ) {
4332 			trap_Cvar_Set( "cl_bypassMouseInput", "0" );
4333 		}
4334 		return qfalse;
4335 	}
4336 
4337 	if ( menu->onKey[key] ) {
4338 		return qtrue;
4339 	}
4340 
4341 	return qfalse;
4342 }
4343 
WM_ActivateLimboChat(void)4344 void WM_ActivateLimboChat( void ) {
4345 	menuDef_t *menu;
4346 	itemDef_t *itemdef;
4347 
4348 	Menu_GetFocused();
4349 	menu = Menus_ActivateByName( "wm_limboChat", qtrue );
4350 
4351 	if ( !menu || g_editItem ) {
4352 		return;
4353 	}
4354 
4355 	itemdef = Menu_FindItemByName( menu, "window_limbo_chat" );
4356 
4357 	if ( itemdef ) {
4358 		itemdef->cursorPos = 0;
4359 		g_editingField = qtrue;
4360 		g_editItem = itemdef;
4361 		DC->setOverstrikeMode( qtrue );
4362 	}
4363 }
4364 // -NERVE - SMF
4365 
4366 /*
4367 ==============
4368 UI_Update
4369 ==============
4370 */
UI_Update(const char * name)4371 static void UI_Update( const char *name ) {
4372 	int val = trap_Cvar_VariableValue( name );
4373 
4374 	if ( Q_stricmp( name, "ui_SetName" ) == 0 ) {
4375 		trap_Cvar_Set( "name", UI_Cvar_VariableString( "ui_Name" ) );
4376 	} else if ( Q_stricmp( name, "ui_setRate" ) == 0 ) {
4377 		float rate = trap_Cvar_VariableValue( "rate" );
4378 		if ( rate >= 5000 ) {
4379 			trap_Cvar_Set( "cl_maxpackets", "30" );
4380 			trap_Cvar_Set( "cl_packetdup", "1" );
4381 		} else if ( rate >= 4000 ) {
4382 			trap_Cvar_Set( "cl_maxpackets", "15" );
4383 			trap_Cvar_Set( "cl_packetdup", "2" );       // favor less prediction errors when there's packet loss
4384 		} else {
4385 			trap_Cvar_Set( "cl_maxpackets", "15" );
4386 			trap_Cvar_Set( "cl_packetdup", "1" );       // favor lower bandwidth
4387 		}
4388 	} else if ( Q_stricmp( name, "ui_GetName" ) == 0 ) {
4389 		trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString( "name" ) );
4390 	} else if ( Q_stricmp( name, "r_colorbits" ) == 0 ) {
4391 		switch ( val ) {
4392 		case 0:
4393 			trap_Cvar_SetValue( "r_depthbits", 0 );
4394 			trap_Cvar_SetValue( "r_stencilbits", 0 );
4395 			break;
4396 		case 16:
4397 			trap_Cvar_SetValue( "r_depthbits", 16 );
4398 			trap_Cvar_SetValue( "r_stencilbits", 0 );
4399 			break;
4400 		case 32:
4401 			trap_Cvar_SetValue( "r_depthbits", 24 );
4402 			trap_Cvar_SetValue( "r_stencilbits", 8 );
4403 			break;
4404 		}
4405 	} else if ( Q_stricmp( name, "r_lodbias" ) == 0 ) {
4406 		switch ( val ) {
4407 		case 0:
4408 			trap_Cvar_SetValue( "r_subdivisions", 4 );
4409 			break;
4410 		case 1:
4411 			trap_Cvar_SetValue( "r_subdivisions", 12 );
4412 			break;
4413 		case 2:
4414 			trap_Cvar_SetValue( "r_subdivisions", 20 );
4415 			break;
4416 		}
4417 	} else if ( Q_stricmp( name, "ui_glCustom" ) == 0 ) {
4418 		switch ( val ) {
4419 		case 0:     // high quality
4420 			trap_Cvar_SetValue( "r_subdivisions", 4 );
4421 			trap_Cvar_SetValue( "r_vertexlight", 0 );
4422 			trap_Cvar_SetValue( "r_lodbias", 0 );
4423 			trap_Cvar_SetValue( "r_colorbits", 32 );
4424 			trap_Cvar_SetValue( "r_depthbits", 24 );
4425 			trap_Cvar_SetValue( "r_stencilbits", 8 );
4426 			trap_Cvar_SetValue( "r_picmip", 0 );
4427 			trap_Cvar_SetValue( "r_texturebits", 32 );
4428 			trap_Cvar_SetValue( "r_fastSky", 0 );
4429 			trap_Cvar_SetValue( "r_dynamiclight", 1 );
4430 			trap_Cvar_SetValue( "r_inGameVideo", 1 );
4431 			trap_Cvar_SetValue( "cg_shadows", 1 );
4432 			trap_Cvar_SetValue( "cg_brassTime", 2500 );
4433 			trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
4434 			trap_Cvar_SetValue( "r_ext_compressed_textures", 0 );
4435 			trap_Cvar_SetValue( "r_overBrightBits", 0 );
4436 			trap_Cvar_Set( "cl_renderer", "rend2" );
4437 			trap_Cvar_SetValue( "r_hdr", 1 );
4438 			trap_Cvar_SetValue( "r_postProcess", 1 );
4439 			trap_Cvar_SetValue( "r_toneMap", 1 );
4440 			trap_Cvar_SetValue( "r_autoExposure", 1 );
4441 			trap_Cvar_SetValue( "r_normalMapping", 1 );
4442 			trap_Cvar_SetValue( "r_specularMapping", 1 );
4443 			trap_Cvar_SetValue( "r_deluxeMapping", 1 );
4444 			trap_Cvar_SetValue( "r_forceSun", 1 );
4445 			trap_Cvar_SetValue( "r_drawSunRays", 1 );
4446 			trap_Cvar_SetValue( "r_sunShadows", 1 );
4447 			trap_Cvar_SetValue( "r_shadowFilter", 1 );
4448 #ifdef USE_BLOOM
4449 			trap_Cvar_SetValue( "r_bloom", 1 );
4450 #endif
4451 			break;
4452 		case 1:     // normal
4453 			trap_Cvar_SetValue( "r_subdivisions", 4 );
4454 			trap_Cvar_SetValue( "r_vertexlight", 0 );
4455 			trap_Cvar_SetValue( "r_lodbias", 0 );
4456 			trap_Cvar_SetValue( "r_colorbits", 0 );
4457 			trap_Cvar_SetValue( "r_depthbits", 0 );
4458 			trap_Cvar_SetValue( "r_stencilbits", 0 );
4459 			trap_Cvar_SetValue( "r_picmip", 0 );
4460 			trap_Cvar_SetValue( "r_texturebits", 0 );
4461 			trap_Cvar_SetValue( "r_fastSky", 0 );
4462 			trap_Cvar_SetValue( "r_dynamiclight", 1 );
4463 			trap_Cvar_SetValue( "r_inGameVideo", 1 );
4464 			trap_Cvar_SetValue( "cg_shadows", 1 );
4465 			trap_Cvar_SetValue( "cg_brassTime", 2500 );
4466 			trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
4467 			trap_Cvar_SetValue( "r_ext_compressed_textures", 0 );
4468 			trap_Cvar_SetValue( "r_overBrightBits", 0 );
4469 			trap_Cvar_Set( "cl_renderer", "opengl1" );
4470 #ifdef USE_BLOOM
4471 			trap_Cvar_SetValue( "r_bloom", 1 );
4472 #endif
4473 			break;
4474 		case 2:     // fast
4475 			trap_Cvar_SetValue( "r_subdivisions", 12 );
4476 			trap_Cvar_SetValue( "r_vertexlight", 0 );
4477 			trap_Cvar_SetValue( "r_lodbias", 1 );
4478 			trap_Cvar_SetValue( "r_colorbits", 0 );
4479 			trap_Cvar_SetValue( "r_depthbits", 0 );
4480 			trap_Cvar_SetValue( "r_stencilbits", 0 );
4481 			trap_Cvar_SetValue( "r_picmip", 1 );
4482 			trap_Cvar_SetValue( "r_texturebits", 0 );
4483 			trap_Cvar_SetValue( "cg_shadows", 0 );
4484 			trap_Cvar_SetValue( "r_fastSky", 1 );
4485 			trap_Cvar_SetValue( "r_dynamiclight", 0 );
4486 			trap_Cvar_SetValue( "r_inGameVideo", 0 );
4487 			trap_Cvar_SetValue( "cg_brassTime", 0 );
4488 			trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
4489 			trap_Cvar_SetValue( "r_ext_compressed_textures", 1 );
4490 			trap_Cvar_SetValue( "r_overBrightBits", 0 );
4491 			trap_Cvar_Set( "cl_renderer", "opengl1" );
4492 #ifdef USE_BLOOM
4493 			trap_Cvar_SetValue( "r_bloom", 0 );
4494 #endif
4495 			break;
4496 		case 3:     // fastest
4497 			trap_Cvar_SetValue( "r_subdivisions", 20 );
4498 			trap_Cvar_SetValue( "r_vertexlight", 1 );
4499 			trap_Cvar_SetValue( "r_lodbias", 2 );
4500 			trap_Cvar_SetValue( "r_colorbits", 0 );
4501 			trap_Cvar_SetValue( "r_depthbits", 0 );
4502 			trap_Cvar_SetValue( "r_stencilbits", 0 );
4503 			trap_Cvar_SetValue( "r_picmip", 2 );
4504 			trap_Cvar_SetValue( "r_texturebits", 0 );
4505 			trap_Cvar_SetValue( "cg_shadows", 0 );
4506 			trap_Cvar_SetValue( "cg_brassTime", 0 );
4507 			trap_Cvar_SetValue( "r_fastSky", 1 );
4508 			trap_Cvar_SetValue( "r_dynamiclight", 0 );
4509 			trap_Cvar_SetValue( "r_inGameVideo", 0 );
4510 			trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
4511 			trap_Cvar_SetValue( "r_ext_compressed_textures", 1 );
4512 			trap_Cvar_SetValue( "r_overBrightBits", 0 );
4513 			trap_Cvar_Set( "cl_renderer", "opengl1" );
4514 #ifdef USE_BLOOM
4515 			trap_Cvar_SetValue( "r_bloom", 0 );
4516 #endif
4517 			break;
4518 		}
4519 	} else if ( Q_stricmp( name, "ui_mousePitch" ) == 0 ) {
4520 		if ( val == 0 ) {
4521 			trap_Cvar_SetValue( "m_pitch", 0.022f );
4522 		} else {
4523 			trap_Cvar_SetValue( "m_pitch", -0.022f );
4524 		}
4525 	}
4526 }
4527 
4528 /*
4529 ==============
4530 UI_UpdateVoteFlags
4531 NOTE TTimo: VOTEFLAGS_RESTART for map_restart vote is present and can be used, but doesn't have any UI binding
4532 ==============
4533 */
UI_UpdateVoteFlags(qboolean open)4534 static void UI_UpdateVoteFlags( qboolean open ) {
4535 	int flags;
4536 	if ( open ) {
4537 		flags = trap_Cvar_VariableValue( "g_voteFlags" );
4538 		trap_Cvar_SetValue( "ui_voteRestart", flags & VOTEFLAGS_RESTART );
4539 		trap_Cvar_SetValue( "ui_voteResetMatch", flags & VOTEFLAGS_RESETMATCH );
4540 		trap_Cvar_SetValue( "ui_voteStartMatch", flags & VOTEFLAGS_STARTMATCH );
4541 		trap_Cvar_SetValue( "ui_voteNextMap", flags & VOTEFLAGS_NEXTMAP );
4542 		trap_Cvar_SetValue( "ui_voteSwap", flags & VOTEFLAGS_SWAP );
4543 		trap_Cvar_SetValue( "ui_voteType", flags & VOTEFLAGS_TYPE );
4544 		trap_Cvar_SetValue( "ui_voteKick", flags & VOTEFLAGS_KICK );
4545 		trap_Cvar_SetValue( "ui_voteMap", flags & VOTEFLAGS_MAP );
4546 	} else {
4547 		flags = 0;
4548 		flags |= trap_Cvar_VariableValue( "ui_voteRestart" ) ? VOTEFLAGS_RESTART : 0;
4549 		flags |= trap_Cvar_VariableValue( "ui_voteResetMatch" ) ? VOTEFLAGS_RESETMATCH : 0;
4550 		flags |= trap_Cvar_VariableValue( "ui_voteStartMatch" ) ? VOTEFLAGS_STARTMATCH : 0;
4551 		flags |= trap_Cvar_VariableValue( "ui_voteNextMap" ) ? VOTEFLAGS_NEXTMAP : 0;
4552 		flags |= trap_Cvar_VariableValue( "ui_voteSwap" ) ? VOTEFLAGS_SWAP : 0;
4553 		flags |= trap_Cvar_VariableValue( "ui_voteType" ) ? VOTEFLAGS_TYPE : 0;
4554 		flags |= trap_Cvar_VariableValue( "ui_voteKick" ) ? VOTEFLAGS_KICK : 0;
4555 		flags |= trap_Cvar_VariableValue( "ui_voteMap" ) ? VOTEFLAGS_MAP : 0;
4556 		trap_Cvar_SetValue( "g_voteFlags", flags );
4557 		// maintain consistency, if we turned one option back on, set the global on
4558 		if ( flags != 0 ) {
4559 			trap_Cvar_SetValue( "g_allowVote", 1 );
4560 		}
4561 	}
4562 }
4563 
4564 /*
4565 ==============
4566 UI_RunMenuScript
4567 ==============
4568 */
UI_RunMenuScript(char ** args)4569 static void UI_RunMenuScript( char **args ) {
4570 	const char *name, *name2;
4571 	char *s;
4572 	char buff[1024];
4573 	int val;                // NERVE - SMF
4574 	menuDef_t *menu;
4575 
4576 	if ( String_Parse( args, &name ) ) {
4577 
4578 		if ( Q_stricmp( name, "StartServer" ) == 0 ) {
4579 			int pb_sv, pb_cl;
4580 
4581 			// DHM - Nerve
4582 			if ( !ui_dedicated.integer ) {
4583 				pb_sv = (int)trap_Cvar_VariableValue( "sv_punkbuster" );
4584 				pb_cl = (int)trap_Cvar_VariableValue( "cl_punkbuster" );
4585 
4586 				if ( pb_sv && !pb_cl ) {
4587 					trap_Cvar_Set( "com_errorMessage", "You must either disable PunkBuster on the Server, or enable PunkBuster on the Client before starting a non-dedicated server." );
4588 					return;
4589 				}
4590 			}
4591 			// dhm - Nerve
4592 
4593 			trap_Cvar_Set( "cg_thirdPerson", "0" );
4594 			trap_Cvar_Set( "cg_cameraOrbit", "0" );
4595 			trap_Cvar_Set( "ui_singlePlayerActive", "0" );
4596 			trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
4597 			trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
4598 
4599 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
4600 
4601 			// NERVE - SMF - set user cvars here
4602 			// set timelimit
4603 			val = trap_Cvar_VariableValue( "ui_userTimelimit" );
4604 
4605 			if ( val != uiInfo.mapList[ui_mapIndex.integer].Timelimit ) {
4606 				trap_Cvar_Set( "g_userTimelimit", va( "%i", val ) );
4607 			} else {
4608 				trap_Cvar_Set( "g_userTimelimit", "0" );
4609 			}
4610 
4611 			// set axis respawn time
4612 			val = trap_Cvar_VariableValue( "ui_userAxisRespawnTime" );
4613 
4614 			if ( val != uiInfo.mapList[ui_mapIndex.integer].AxisRespawnTime ) {
4615 				trap_Cvar_Set( "g_userAxisRespawnTime", va( "%i", val ) );
4616 			} else {
4617 				trap_Cvar_Set( "g_userAxisRespawnTime", "0" );
4618 			}
4619 
4620 			// set allied respawn time
4621 			val = trap_Cvar_VariableValue( "ui_userAlliedRespawnTime" );
4622 
4623 			if ( val != uiInfo.mapList[ui_mapIndex.integer].AlliedRespawnTime ) {
4624 				trap_Cvar_Set( "g_userAlliedRespawnTime", va( "%i", val ) );
4625 			} else {
4626 				trap_Cvar_Set( "g_userAlliedRespawnTime", "0" );
4627 			}
4628 			// -NERVE - SMF
4629 
4630 		} else if ( Q_stricmp( name, "updateSPMenu" ) == 0 ) {
4631 			UI_SetCapFragLimits( qtrue );
4632 			UI_MapCountByGameType( qtrue );
4633 			ui_mapIndex.integer = UI_GetIndexFromSelection( ui_currentMap.integer );
4634 			trap_Cvar_Set( "ui_mapIndex", va( "%d", ui_mapIndex.integer ) );
4635 			Menu_SetFeederSelection( NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish" );
4636 			UI_GameType_HandleKey( 0, NULL, K_MOUSE1, qfalse );
4637 			UI_GameType_HandleKey( 0, NULL, K_MOUSE2, qfalse );
4638 		} else if ( Q_stricmp( name, "resetDefaults" ) == 0 ) {
4639 			trap_Cmd_ExecuteText( EXEC_NOW, "cvar_restart\n" );            // NERVE - SMF - changed order
4640 			trap_Cmd_ExecuteText( EXEC_NOW, "exec default.cfg\n" );
4641 			trap_Cmd_ExecuteText( EXEC_NOW, "exec language.cfg\n" );       // NERVE - SMF
4642 			trap_Cmd_ExecuteText( EXEC_NOW, "setRecommended\n" );     // NERVE - SMF
4643 			Controls_SetDefaults();
4644 #ifdef CINEMATICS_INTRO
4645 			trap_Cvar_Set( "com_introPlayed", "1" );
4646 #endif
4647 			trap_Cvar_Set( "com_recommendedSet", "1" );                   // NERVE - SMF
4648 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
4649 		} else if ( Q_stricmp( name, "getCDKey" ) == 0 ) {
4650 			char out[17];
4651 			trap_GetCDKey( buff, 17 );
4652 			trap_Cvar_Set( "cdkey1", "" );
4653 			trap_Cvar_Set( "cdkey2", "" );
4654 			trap_Cvar_Set( "cdkey3", "" );
4655 			trap_Cvar_Set( "cdkey4", "" );
4656 			trap_Cvar_Set( "cdkeychecksum", "" );
4657 			if ( buff[0] != 32 && strlen( buff ) == CDKEY_LEN ) {
4658 				Q_strncpyz( out, buff, 5 );
4659 				trap_Cvar_Set( "cdkey1", out );
4660 				Q_strncpyz( out, buff + 4, 5 );
4661 				trap_Cvar_Set( "cdkey2", out );
4662 				Q_strncpyz( out, buff + 8, 5 );
4663 				trap_Cvar_Set( "cdkey3", out );
4664 				Q_strncpyz( out, buff + 12, 5 );
4665 				trap_Cvar_Set( "cdkey4", out );
4666 			}
4667 
4668 		} else if ( Q_stricmp( name, "verifyCDKey" ) == 0 ) {
4669 			buff[0] = '\0';
4670 			Q_strcat( buff, 1024, UI_Cvar_VariableString( "cdkey1" ) );
4671 			Q_strcat( buff, 1024, UI_Cvar_VariableString( "cdkey2" ) );
4672 			Q_strcat( buff, 1024, UI_Cvar_VariableString( "cdkey3" ) );
4673 			Q_strcat( buff, 1024, UI_Cvar_VariableString( "cdkey4" ) );
4674 			trap_Cvar_Set( "cdkey", buff );
4675 			if ( trap_VerifyCDKey( buff, UI_Cvar_VariableString( "cdkeychecksum" ) ) ) {
4676 				trap_Cvar_Set( "ui_cdkeyvalid", UI_TranslateString( "CD key appears to be valid." ) );
4677 				trap_SetCDKey( buff );
4678 			} else {
4679 				trap_Cvar_Set( "ui_cdkeyvalid", UI_TranslateString( "CD key does not appear to be valid." ) );
4680 			}
4681 		} else if ( Q_stricmp( name, "loadArenas" ) == 0 ) {
4682 			UI_LoadArenasIntoMapList();
4683 			UI_MapCountByGameType( qfalse );
4684 			Menu_SetFeederSelection( NULL, FEEDER_ALLMAPS, 0, NULL );
4685 		} else if ( Q_stricmp( name, "saveControls" ) == 0 ) {
4686 			Controls_SetConfig( qtrue );
4687 		} else if ( Q_stricmp( name, "loadControls" ) == 0 ) {
4688 			Controls_GetConfig();
4689 		} else if ( Q_stricmp( name, "clearError" ) == 0 ) {
4690 			trap_Cvar_Set( "com_errorMessage", "" );
4691 			trap_Cvar_Set( "com_errorDiagnoseIP", "" );
4692 			trap_Cvar_Set( "com_missingFiles", "" );
4693 		} else if ( Q_stricmp( name, "loadGameInfo" ) == 0 ) {
4694 			UI_ParseGameInfo( "gameinfo.txt" );
4695 			UI_LoadBestScores( uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum );
4696 		} else if ( Q_stricmp( name, "resetScores" ) == 0 ) {
4697 			UI_ClearScores();
4698 		} else if ( Q_stricmp( name, "RefreshServers" ) == 0 ) {
4699 			UI_StartServerRefresh( qtrue, qtrue );
4700 			UI_BuildServerDisplayList( qtrue );
4701 		} else if ( Q_stricmp( name, "RefreshFilter" ) == 0 ) {
4702 			UI_StartServerRefresh( qfalse, qtrue );
4703 			UI_BuildServerDisplayList( qtrue );
4704 		} else if ( Q_stricmp( name, "RunSPDemo" ) == 0 ) {
4705 			if ( uiInfo.demoAvailable ) {
4706 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "demo %s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum ) );
4707 			}
4708 		} else if ( Q_stricmp( name, "LoadDemos" ) == 0 ) {
4709 			UI_LoadDemos();
4710 		} else if ( Q_stricmp( name, "LoadMovies" ) == 0 ) {
4711 			UI_LoadMovies();
4712 
4713 //----(SA)	added
4714 		} else if ( Q_stricmp( name, "LoadSaveGames" ) == 0 ) {  // get the list
4715 			UI_LoadSavegames();
4716 		} else if ( Q_stricmp( name, "Loadgame" ) == 0 ) {
4717 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "loadgame %s\n", uiInfo.savegameList[uiInfo.savegameIndex].name ) );
4718 		} else if ( Q_stricmp( name, "Savegame" ) == 0 ) {
4719 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "savegame %s\n", UI_Cvar_VariableString( "ui_savegame" ) ) );
4720 		} else if ( Q_stricmp( name, "DelSavegame" ) == 0 ) {
4721 			UI_DelSavegame();
4722 //----(SA)	end
4723 
4724 		} else if ( Q_stricmp( name, "LoadMods" ) == 0 ) {
4725 			UI_LoadMods();
4726 		} else if ( Q_stricmp( name, "playMovie" ) == 0 ) {
4727 			if ( uiInfo.previewMovie >= 0 ) {
4728 				trap_CIN_StopCinematic( uiInfo.previewMovie );
4729 			}
4730 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex] ) );
4731 		} else if ( Q_stricmp( name, "RunMod" ) == 0 ) {
4732 			trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName );
4733 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
4734 		} else if ( Q_stricmp( name, "RunDemo" ) == 0 ) {
4735 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "demo %s\n", uiInfo.demoList[uiInfo.demoIndex] ) );
4736 		} else if ( Q_stricmp( name, "Quake3" ) == 0 ) {
4737 			trap_Cvar_Set( "fs_game", "" );
4738 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
4739 		} else if ( Q_stricmp( name, "closeJoin" ) == 0 ) {
4740 			if ( uiInfo.serverStatus.refreshActive ) {
4741 				UI_StopServerRefresh();
4742 				uiInfo.serverStatus.nextDisplayRefresh = 0;
4743 				uiInfo.nextServerStatusRefresh = 0;
4744 				uiInfo.nextFindPlayerRefresh = 0;
4745 				UI_BuildServerDisplayList( qtrue );
4746 			} else {
4747 				Menus_CloseByName( "joinserver" );
4748 				Menus_OpenByName( "main" );
4749 			}
4750 		} else if ( Q_stricmp( name, "StopRefresh" ) == 0 ) {
4751 			UI_StopServerRefresh();
4752 			uiInfo.serverStatus.nextDisplayRefresh = 0;
4753 			uiInfo.nextServerStatusRefresh = 0;
4754 			uiInfo.nextFindPlayerRefresh = 0;
4755 		} else if ( Q_stricmp( name, "UpdateFilter" ) == 0 ) {
4756 			// UpdateFilter is called when server broser menu is opened and when a favorite server is deleted.
4757 			UI_StartServerRefresh(qtrue, qfalse);
4758 			UI_BuildServerDisplayList( qtrue );
4759 			UI_FeederSelection( FEEDER_SERVERS, 0 );
4760 		} else if ( Q_stricmp( name, "check_ServerStatus" ) == 0 ) {
4761 			s = UI_Cvar_VariableString( "com_errorDiagnoseIP" );
4762 			menu = Menus_FindByName( "ingame_options" );
4763 			if ( strlen( s ) && strcmp( s, "localhost" ) ) {
4764 				if ( menu ) {
4765 					Menu_ShowItemByName( menu, "ctr_serverinfo", qtrue );
4766 				}
4767 			} else
4768 			{
4769 				if ( menu ) {
4770 					Menu_ShowItemByName( menu, "ctr_serverinfo", qfalse );
4771 				}
4772 			}
4773 		} else if ( Q_stricmp( name, "ServerStatus" ) == 0 ) {
4774 			// the server info dialog has been turned into a modal thing
4775 			// it can be called in several situations
4776 			if ( trap_Cvar_VariableValue( "ui_serverBrowser" ) == 1 ) {
4777 				// legacy, from the server browser
4778 				trap_LAN_GetServerAddressString(UI_SourceForLAN(), uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
4779 				UI_BuildServerStatus( qtrue );
4780 			} else
4781 			{
4782 				// use com_errorDiagnoseIP otherwise
4783 				s = UI_Cvar_VariableString( "com_errorDiagnoseIP" );
4784 				if ( strlen( s ) && strcmp( s, "localhost" ) ) {
4785 					trap_Cvar_VariableStringBuffer( "com_errorDiagnoseIP", uiInfo.serverStatusAddress, sizeof( uiInfo.serverStatusAddress ) );
4786 					uiInfo.serverStatus.numDisplayServers   = 1; // this is ugly, have to force a non zero display server count to emit the query
4787 					UI_BuildServerStatus( qtrue );
4788 				} else
4789 				{
4790 					// we can't close the menu from here, it's not open yet .. (that's the onOpen script)
4791 					Com_Printf( "Can't show Server Info (not found, or local server)\n" );
4792 				}
4793 			}
4794 		} else if ( Q_stricmp( name, "ServerStatus_diagnose" ) == 0 ) {
4795 			// query server and display the URL buttons if the error happened during a server connection situation
4796 			s = UI_Cvar_VariableString( "com_errorDiagnoseIP" );
4797 			menu = Menus_FindByName( "error_popmenu_diagnose" );
4798 			if ( strlen( s ) && strcmp( s, "localhost" ) ) {
4799 				trap_Cvar_VariableStringBuffer( "com_errorDiagnoseIP", uiInfo.serverStatusAddress, sizeof( uiInfo.serverStatusAddress ) );
4800 				uiInfo.serverStatus.numDisplayServers   = 1; // this is ugly, have to force a non zero display server count to emit the query
4801 				// toggle the "Server Info" button
4802 				if ( menu ) {
4803 					Menu_ShowItemByName( menu, "serverinfo", qtrue );
4804 				}
4805 				UI_BuildServerStatus( qtrue );
4806 			} else
4807 			{
4808 				// don't send getinfo packet, hide "Server Info" button
4809 				if ( menu ) {
4810 					Menu_ShowItemByName( menu, "serverinfo", qfalse );
4811 				}
4812 			}
4813 		} else if ( Q_stricmp( name, "FoundPlayerServerStatus" ) == 0 ) {
4814 			Q_strncpyz( uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof( uiInfo.serverStatusAddress ) );
4815 			UI_BuildServerStatus( qtrue );
4816 			Menu_SetFeederSelection( NULL, FEEDER_FINDPLAYER, 0, NULL );
4817 		} else if ( Q_stricmp( name, "FindPlayer" ) == 0 ) {
4818 			UI_BuildFindPlayerList( qtrue );
4819 			// clear the displayed server status info
4820 			uiInfo.serverStatusInfo.numLines = 0;
4821 			Menu_SetFeederSelection( NULL, FEEDER_FINDPLAYER, 0, NULL );
4822 		} else if ( Q_stricmp( name, "JoinServer" ) == 0 ) {
4823 			trap_Cvar_Set( "cg_thirdPerson", "0" );
4824 			trap_Cvar_Set( "cg_cameraOrbit", "0" );
4825 			trap_Cvar_Set( "ui_singlePlayerActive", "0" );
4826 			if ( uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers ) {
4827 				trap_LAN_GetServerAddressString(UI_SourceForLAN(), uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
4828 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
4829 			}
4830 		} else if ( Q_stricmp( name, "FoundPlayerJoinServer" ) == 0 ) {
4831 			trap_Cvar_Set( "ui_singlePlayerActive", "0" );
4832 			if ( uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers ) {
4833 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
4834 			}
4835 		} else if ( Q_stricmp( name, "Quit" ) == 0 ) {
4836 			trap_Cvar_Set( "ui_singlePlayerActive", "0" );
4837 			trap_Cmd_ExecuteText( EXEC_NOW, "quit" );
4838 		} else if ( Q_stricmp( name, "Controls" ) == 0 ) {
4839 			trap_Cvar_Set( "cl_paused", "1" );
4840 			trap_Key_SetCatcher( KEYCATCH_UI );
4841 			Menus_CloseAll();
4842 			Menus_ActivateByName( "setup_menu2", qtrue );
4843 		} else if ( Q_stricmp( name, "Leave" ) == 0 ) {
4844 			// ATVI Wolfenstein Misc #460
4845 			// if we are running a local server, make sure we kill it cleanly for other clients
4846 			if ( trap_Cvar_VariableValue( "sv_running" ) ) {
4847 				trap_Cvar_Set( "sv_killserver", "1" );
4848 			} else
4849 			{
4850 				trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
4851 				trap_Key_SetCatcher( KEYCATCH_UI );
4852 				Menus_CloseAll();
4853 				Menus_ActivateByName( "main", qtrue );
4854 			}
4855 		} else if ( Q_stricmp( name, "ServerSort" ) == 0 ) {
4856 			int sortColumn;
4857 			if ( Int_Parse( args, &sortColumn ) ) {
4858 				// if same column we're already sorting on then flip the direction
4859 				if ( sortColumn == uiInfo.serverStatus.sortKey ) {
4860 					uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
4861 				}
4862 				// make sure we sort again
4863 				UI_ServersSort( sortColumn, qtrue );
4864 			}
4865 		} else if ( Q_stricmp( name, "nextSkirmish" ) == 0 ) {
4866 			UI_StartSkirmish( qtrue );
4867 		} else if ( Q_stricmp( name, "SkirmishStart" ) == 0 ) {
4868 			UI_StartSkirmish( qfalse );
4869 		} else if ( Q_stricmp( name, "closeingame" ) == 0 ) {
4870 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4871 			trap_Key_ClearStates();
4872 			trap_Cvar_Set( "cl_paused", "0" );
4873 			Menus_CloseAll();
4874 		} else if ( Q_stricmp( name, "voteMap" ) == 0 ) {
4875 			if ( ui_currentNetMap.integer >= 0 && ui_currentNetMap.integer < uiInfo.mapCount ) {
4876 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
4877 			}
4878 		} else if ( Q_stricmp( name, "voteKick" ) == 0 ) {
4879 			if ( uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount ) {
4880 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote kick \"%s\"\n",uiInfo.playerNames[uiInfo.playerIndex] ) );
4881 			}
4882 		} else if ( Q_stricmp( name, "voteGame" ) == 0 ) {
4883 			if ( ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes ) {
4884 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
4885 			}
4886 		} else if ( Q_stricmp( name, "voteLeader" ) == 0 ) {
4887 			if ( uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount ) {
4888 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex] ) );
4889 			}
4890 		} else if ( Q_stricmp( name, "addBot" ) == 0 ) {
4891 			if ( trap_Cvar_VariableValue( "g_gametype" ) >= GT_TEAM ) {
4892 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex + 1, ( uiInfo.redBlue == 0 ) ? "Red" : "Blue" ) );
4893 			} else {
4894 				// NERVE - SMF - no bots in wolf multiplayer
4895 //				trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
4896 			}
4897 		} else if ( Q_stricmp( name, "addFavorite" ) == 0 ) {
4898 			if ( ui_netSource.integer != UIAS_FAVORITES ) {
4899 				char name[MAX_NAME_LENGTH];
4900 				char addr[MAX_ADDRESSLENGTH];
4901 				int res;
4902 
4903 				trap_LAN_GetServerInfo(UI_SourceForLAN(), uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
4904 				name[0] = addr[0] = '\0';
4905 				Q_strncpyz( name,    Info_ValueForKey( buff, "hostname" ), sizeof ( name ) );
4906 				Q_strncpyz( addr,    Info_ValueForKey( buff, "addr" ), sizeof ( addr ) );
4907 				if ( strlen( name ) > 0 && strlen( addr ) > 0 ) {
4908 					res = trap_LAN_AddServer( AS_FAVORITES, name, addr );
4909 					if ( res == 0 ) {
4910 						// server already in the list
4911 						Com_Printf( "%s", UI_TranslateString( "Favorite already in list\n" ) );
4912 					} else if ( res == -1 )     {
4913 						// list full
4914 						Com_Printf( "%s", UI_TranslateString( "Favorite list full\n" ) );
4915 					} else {
4916 						// successfully added
4917 						Com_Printf( UI_TranslateString( "Added favorite server %s\n" ), addr );
4918 					}
4919 				}
4920 			}
4921 		} else if ( Q_stricmp( name, "deleteFavorite" ) == 0 ) {
4922 			if ( ui_netSource.integer == UIAS_FAVORITES ) {
4923 				char addr[MAX_ADDRESSLENGTH];
4924 				trap_LAN_GetServerInfo( AS_FAVORITES, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS );
4925 				addr[0] = '\0';
4926 				Q_strncpyz( addr,    Info_ValueForKey( buff, "addr" ), sizeof ( addr ) );
4927 				if ( strlen( addr ) > 0 ) {
4928 					trap_LAN_RemoveServer( AS_FAVORITES, addr );
4929 				}
4930 			}
4931 		} else if ( Q_stricmp( name, "createFavorite" ) == 0 ) {
4932 			char name[MAX_NAME_LENGTH];
4933 			char addr[MAX_ADDRESSLENGTH];
4934 			int res;
4935 
4936 			name[0] = addr[0] = '\0';
4937 			Q_strncpyz( name,    UI_Cvar_VariableString( "ui_favoriteName" ), sizeof ( name ) );
4938 			Q_strncpyz( addr,    UI_Cvar_VariableString( "ui_favoriteAddress" ), sizeof ( addr ) );
4939 			if ( strlen( name ) > 0 && strlen( addr ) > 0 ) {
4940 				res = trap_LAN_AddServer( AS_FAVORITES, name, addr );
4941 				if ( res == 0 ) {
4942 					// server already in the list
4943 					Com_Printf( "%s", UI_TranslateString( "Favorite already in list\n" ) );
4944 				} else if ( res == -1 )     {
4945 					// list full
4946 					Com_Printf( "%s", UI_TranslateString( "Favorite list full\n" ) );
4947 				} else {
4948 					// successfully added
4949 					Com_Printf( UI_TranslateString( "Added favorite server %s\n" ), addr );
4950 				}
4951 			}
4952 		} else if ( Q_stricmp( name, "orders" ) == 0 ) {
4953 			const char *orders;
4954 			if ( String_Parse( args, &orders ) ) {
4955 				int selectedPlayer = trap_Cvar_VariableValue( "cg_selectedPlayer" );
4956 				if ( selectedPlayer < uiInfo.myTeamCount ) {
4957 					Com_sprintf( buff, sizeof( buff ), orders, uiInfo.teamClientNums[selectedPlayer] );
4958 					trap_Cmd_ExecuteText( EXEC_APPEND, buff );
4959 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
4960 				} else {
4961 					int i;
4962 					for ( i = 0; i < uiInfo.myTeamCount; i++ ) {
4963 						if (uiInfo.playerNumber == uiInfo.teamClientNums[i]) {
4964 							continue;
4965 						}
4966 						Com_sprintf( buff, sizeof( buff ), orders, uiInfo.teamClientNums[i] );
4967 						trap_Cmd_ExecuteText( EXEC_APPEND, buff );
4968 						trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
4969 					}
4970 				}
4971 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4972 				trap_Key_ClearStates();
4973 				trap_Cvar_Set( "cl_paused", "0" );
4974 				Menus_CloseAll();
4975 			}
4976 		} else if ( Q_stricmp( name, "voiceOrdersTeam" ) == 0 ) {
4977 			const char *orders;
4978 			if ( String_Parse( args, &orders ) ) {
4979 				int selectedPlayer = trap_Cvar_VariableValue( "cg_selectedPlayer" );
4980 				if ( selectedPlayer == uiInfo.myTeamCount ) {
4981 					trap_Cmd_ExecuteText( EXEC_APPEND, orders );
4982 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
4983 				}
4984 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4985 				trap_Key_ClearStates();
4986 				trap_Cvar_Set( "cl_paused", "0" );
4987 				Menus_CloseAll();
4988 			}
4989 		} else if ( Q_stricmp( name, "voiceOrders" ) == 0 ) {
4990 			const char *orders;
4991 			if ( String_Parse( args, &orders ) ) {
4992 				int selectedPlayer = trap_Cvar_VariableValue( "cg_selectedPlayer" );
4993 				if ( selectedPlayer < uiInfo.myTeamCount ) {
4994 					Com_sprintf( buff, sizeof( buff ), orders, uiInfo.teamClientNums[selectedPlayer] );
4995 					trap_Cmd_ExecuteText( EXEC_APPEND, buff );
4996 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
4997 				}
4998 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4999 				trap_Key_ClearStates();
5000 				trap_Cvar_Set( "cl_paused", "0" );
5001 				Menus_CloseAll();
5002 			}
5003 		} else if ( Q_stricmp( name, "glCustom" ) == 0 ) {
5004 			trap_Cvar_Set( "ui_glCustom", "4" );
5005 		} else if ( Q_stricmp( name, "update" ) == 0 ) {
5006 			if ( String_Parse( args, &name2 ) ) {
5007 				UI_Update( name2 );
5008 			}
5009 			// NERVE - SMF
5010 		} else if ( Q_stricmp( name, "startSingleplayer" ) == 0 ) {
5011 			trap_Cmd_ExecuteText( EXEC_APPEND, "startSingleplayer\n" );
5012 		} else if ( Q_stricmp( name, "wm_showPickPlayer" ) == 0 ) {
5013 			Menus_CloseAll();
5014 			Menus_OpenByName( "wm_pickplayer" );
5015 		} else if ( Q_stricmp( name, "wm_showPickTeam" ) == 0 ) {
5016 			Menus_CloseAll();
5017 			Menus_OpenByName( "wm_pickteam" );
5018 		} else if ( Q_stricmp( name, "changePlayerType" ) == 0 ) {
5019 			WM_ChangePlayerType();
5020 		} else if ( Q_stricmp( name, "setWeaponPics" ) == 0 ) {
5021 			WM_setWeaponPics();
5022 		} else if ( Q_stricmp( name, "getSpawnPoints" ) == 0 ) {
5023 			WM_GetSpawnPoints();
5024 		} else if ( Q_stricmp( name, "showSpecScores" ) == 0 ) {
5025 			if ( atoi( UI_Cvar_VariableString( "ui_isSpectator" ) ) ) {
5026 				trap_Cmd_ExecuteText( EXEC_APPEND, "+scores\n" );
5027 			}
5028 		} else if ( Q_stricmp( name, "wm_sayPlayerClass" ) == 0 ) {
5029 			int playerType;
5030 			const char *s;
5031 
5032 			playerType = trap_Cvar_VariableValue( "mp_currentPlayerType" );
5033 
5034 			if ( playerType == 1 ) {
5035 				s = "IamMedic";
5036 			} else if ( playerType == 2 ) {
5037 				s = "IamEngineer";
5038 			} else if ( playerType == 3 ) {
5039 				s = "IamLieutenant";
5040 			} else {
5041 				s = "IamSoldier";
5042 			}
5043 
5044 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "VoiceTeamChat %s\n", s ) );
5045 
5046 		} else if ( Q_stricmp( name, "showObjectiveView" ) == 0 ) {
5047 			menuDef_t *menu = Menu_GetFocused();
5048 			itemDef_t *item;
5049 
5050 			if ( trap_Cvar_VariableValue( "ui_isSpectator" ) ) {
5051 				item = Menu_FindItemByName( menu, "window_tab2" );
5052 				if ( item ) {
5053 					item->window.flags &= ~WINDOW_VISIBLE;
5054 				}
5055 
5056 				item = Menu_FindItemByName( menu, "window_tab1" );
5057 				if ( item ) {
5058 					item->window.flags |= WINDOW_VISIBLE;
5059 				}
5060 
5061 				trap_Cvar_Set( "ui_limboObjective", "1" );
5062 			} else {
5063 				item = Menu_FindItemByName( menu, "window_tab2" );
5064 				if ( item ) {
5065 					item->window.flags |= WINDOW_VISIBLE;
5066 				}
5067 
5068 				item = Menu_FindItemByName( menu, "window_tab1" );
5069 				if ( item ) {
5070 					item->window.flags &= ~WINDOW_VISIBLE;
5071 				}
5072 
5073 				trap_Cvar_Set( "ui_limboObjective", "0" );
5074 			}
5075 
5076 		} else if ( Q_stricmp( name, "wm_pickitem2" ) == 0 ) {
5077 			const char *param, *param2;
5078 			int selectType = 0, itemIndex = 0;
5079 
5080 			if ( String_Parse( args, &param ) &&  String_Parse( args, &param2 ) ) {
5081 				selectType = atoi( param );
5082 				itemIndex = atoi( param2 );
5083 				WM_PickItem( selectType, itemIndex );
5084 			}
5085 		} else if ( Q_stricmp( name, "setLimboOptionMenu" ) == 0 ) {
5086 			int indexNum;
5087 
5088 			if ( String_Parse( args, &name ) ) {
5089 				indexNum = atoi( name );
5090 				trap_Cvar_Set( "ui_limboOptions", va( "%i", indexNum ) );
5091 			}
5092 		} else if ( Q_stricmp( name, "showSpawnWindow" ) == 0 ) {
5093 			int indexNum;
5094 
5095 			if ( String_Parse( args, &name ) ) {
5096 				int options, current;
5097 
5098 				current = trap_Cvar_VariableValue( "ui_limboOptions" );
5099 				indexNum = atoi( name );
5100 
5101 				if ( indexNum && current != 3 ) {
5102 					options = current;
5103 
5104 					trap_Cvar_Set( "ui_limboOptions", "3" );
5105 					trap_Cvar_Set( "ui_limboPrevOptions", va( "%i", options ) );
5106 				} else if ( !indexNum && current == 3 )   {
5107 					options = trap_Cvar_VariableValue( "ui_limboPrevOptions" );
5108 
5109 					trap_Cvar_Set( "ui_limboOptions", va( "%i", options ) );
5110 				}
5111 			}
5112 		} else if ( Q_stricmp( name, "startMultiplayer" ) == 0 ) {
5113 			int team, oldteam, playerType, weapon, pistol, item1, i;
5114 			const char *teamStr, *classStr, *weapStr;
5115 
5116 			// get cvars
5117 			team = trap_Cvar_VariableValue( "mp_team" );
5118 			oldteam = trap_Cvar_VariableValue( "mp_currentTeam" );
5119 			playerType = trap_Cvar_VariableValue( "mp_playerType" );
5120 			weapon = trap_Cvar_VariableValue( "mp_weapon" );
5121 			pistol = trap_Cvar_VariableValue( "mp_pistol" );
5122 			item1 = trap_Cvar_VariableValue( "mp_item1" );
5123 
5124 			// print center message
5125 			if ( team == AXIS_TEAM ) {
5126 				teamStr = "Axis";
5127 			} else if ( team == ALLIES_TEAM ) {
5128 				teamStr = "Allied";
5129 			} else {
5130 				teamStr = "Spectator";
5131 			}
5132 
5133 			if ( playerType == 0 ) {
5134 				classStr = "soldier";
5135 			} else if ( playerType == 1 ) {
5136 				classStr = "medic";
5137 			} else if ( playerType == 2 ) {
5138 				classStr = "engineer";
5139 			} else {
5140 				classStr = "lieutenant";
5141 			}
5142 
5143 			weapStr = "";
5144 			for ( i = 0; weaponTypes[i].name; i++ ) {
5145 				if ( weaponTypes[i].value == weapon ) {
5146 					weapStr = weaponTypes[i].desc;
5147 				}
5148 			}
5149 
5150 			if ( team != 2 ) {
5151 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "limbomessage \"%s\" \"%s\" \"%s\"\n", teamStr, classStr, weapStr ) );
5152 			}
5153 
5154 			if ( team != oldteam ) {
5155 				// join team
5156 				if ( team == 0 ) {
5157 					trap_Cmd_ExecuteText( EXEC_APPEND, va( "team %s %i %i %i %i 1\n", "red", playerType, weapon, pistol, item1 ) );
5158 				} else if ( team == 1 ) {
5159 					trap_Cmd_ExecuteText( EXEC_APPEND, va( "team %s %i %i %i %i 1\n", "blue", playerType, weapon, pistol, item1 ) );
5160 				} else {
5161 					trap_Cmd_ExecuteText( EXEC_APPEND, va( "team %s %i %i %i %i 1\n", "s", playerType, weapon, pistol, item1 ) );
5162 				}
5163 			}
5164 
5165 			// either close menu or bring up zoomed window
5166 			Menus_CloseAll();
5167 		} else if ( Q_stricmp( name, "limboChat" ) == 0 ) {
5168 			WM_LimboChat();
5169 		} else if ( Q_stricmp( name, "activateLimboChat" ) == 0 ) {
5170 			WM_ActivateLimboChat();
5171 		} else if ( Q_stricmp( name, "setObjective" ) == 0 ) {
5172 			int objectiveIndex;
5173 
5174 			if ( Int_Parse( args, &objectiveIndex ) ) {
5175 				WM_SetObjective( objectiveIndex );
5176 			}
5177 			// -NERVE - SMF
5178 			// DHM - Nerve :: PunkBuster
5179 		} else if ( Q_stricmp( name, "setPbClStatus" ) == 0 ) {
5180 			int stat;
5181 
5182 			if ( Int_Parse( args, &stat ) ) {
5183 				trap_SetPbClStatus( stat );
5184 			}
5185 			// DHM - Nerve
5186 			// TTimo
5187 		} else if ( Q_stricmp( name, "togglePbSvStatus" ) == 0 ) {
5188 			int sv_pb = trap_Cvar_VariableValue( "sv_punkbuster" );
5189 			if ( sv_pb ) {
5190 				trap_SetPbSvStatus( 0 );
5191 			} else {
5192 				trap_SetPbSvStatus( 1 );
5193 			}
5194 		} else if ( Q_stricmp( name, "openModURL" ) == 0 ) {
5195 			trap_Cvar_Set( "ui_finalURL", UI_Cvar_VariableString( "ui_modURL" ) );
5196 		} else if ( Q_stricmp( name, "openServerURL" ) == 0 ) {
5197 			trap_Cvar_Set( "ui_finalURL", UI_Cvar_VariableString( "ui_URL" ) );
5198 		} else if ( Q_stricmp( name, "validate_openURL" ) == 0 ) {
5199 			// this is the only one that effectively triggers the URL, after the disclaimers are done with
5200 			// we use ui_finalURL as an auxiliary variable to gather URLs from various sources
5201 			trap_openURL( UI_Cvar_VariableString( "ui_finalURL" ) );
5202 		} else if ( Q_stricmp( name, "update_voteFlags" ) == 0 ) {
5203 			// update g_voteFlags according to g_allowVote value change
5204 			if ( trap_Cvar_VariableValue( "g_allowVote" ) != 0 ) {
5205 				trap_Cvar_SetValue( "g_voteFlags", 255 );
5206 			} else {
5207 				trap_Cvar_SetValue( "g_voteFlags", 0 );
5208 			}
5209 			UI_UpdateVoteFlags( qtrue );
5210 		} else if ( Q_stricmp( name, "voteFlags" ) == 0 ) {
5211 			// createserver.menu, settings allowed / not allowed votes
5212 			if ( String_Parse( args, &name ) ) {
5213 				if ( Q_stricmp( name, "open" ) == 0 ) {
5214 					UI_UpdateVoteFlags( qtrue );
5215 				} else {
5216 					UI_UpdateVoteFlags( qfalse );
5217 				}
5218 			}
5219 		} else if ( Q_stricmp( name, "clientShowVote" ) == 0 ) {
5220 			// client side: only show the available votes
5221 			int flags;
5222 			menu = Menus_FindByName( "ingame_callvote" );
5223 			flags = trap_Cvar_VariableValue( "cg_ui_voteFlags" );
5224 			Menu_ShowItemByName( menu, "misc_resetmatch", flags & VOTEFLAGS_RESETMATCH );
5225 			Menu_ShowItemByName( menu, "misc_startmatch", flags & VOTEFLAGS_STARTMATCH );
5226 			Menu_ShowItemByName( menu, "misc_nextmap", flags & VOTEFLAGS_NEXTMAP );
5227 			Menu_ShowItemByName( menu, "misc_swap", flags & VOTEFLAGS_SWAP );
5228 			Menu_ShowItemByName( menu, "ctr_gametype", flags & VOTEFLAGS_TYPE );
5229 			Menu_ShowItemByName( menu, "ctr_kickplayer", flags & VOTEFLAGS_KICK );
5230 			Menu_ShowItemByName( menu, "ctr_changemap", flags & VOTEFLAGS_MAP );
5231 		} else if ( Q_stricmp( name, "clientCheckVote" ) == 0 ) {
5232 			int flags;
5233 			flags = trap_Cvar_VariableValue( "cg_ui_voteFlags" );
5234 			if ( ( flags | VOTEFLAGS_RESTART ) == VOTEFLAGS_RESTART ) {
5235 				trap_Cvar_SetValue( "cg_ui_novote", 1 );
5236 			} else {
5237 				trap_Cvar_SetValue( "cg_ui_novote", 0 );
5238 			}
5239 		} else if ( Q_stricmp( name, "reconnect" ) == 0 ) {
5240 			// TODO: if dumped because of cl_allowdownload problem, toggle on first (we don't have appropriate support for this yet)
5241 			trap_Cmd_ExecuteText( EXEC_APPEND, "reconnect" );
5242 		} else {
5243 			Com_Printf( "unknown UI script %s\n", name );
5244 		}
5245 	}
5246 }
5247 
UI_GetTeamColor(vec4_t * color)5248 static void UI_GetTeamColor( vec4_t *color ) {
5249 }
5250 
5251 /*
5252 ==================
5253 UI_MapCountByGameType
5254 ==================
5255 */
UI_MapCountByGameType(qboolean singlePlayer)5256 static int UI_MapCountByGameType( qboolean singlePlayer ) {
5257 	int i, c, game;
5258 	c = 0;
5259 	game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
5260 	if ( game == GT_SINGLE_PLAYER ) {
5261 		game++;
5262 	}
5263 	if ( game == GT_TEAM ) {
5264 		game = GT_FFA;
5265 	}
5266 
5267 	for ( i = 0; i < uiInfo.mapCount; i++ ) {
5268 		uiInfo.mapList[i].active = qfalse;
5269 		if ( uiInfo.mapList[i].typeBits & ( 1 << game ) ) {
5270 			if ( singlePlayer ) {
5271 				if ( !( uiInfo.mapList[i].typeBits & ( 1 << GT_SINGLE_PLAYER ) ) ) {
5272 					continue;
5273 				}
5274 			}
5275 			c++;
5276 			uiInfo.mapList[i].active = qtrue;
5277 		}
5278 	}
5279 	return c;
5280 }
5281 
5282 /*
5283 ==================
5284 UI_InsertServerIntoDisplayList
5285 ==================
5286 */
UI_InsertServerIntoDisplayList(int num,int position)5287 static void UI_InsertServerIntoDisplayList( int num, int position ) {
5288 	int i;
5289 
5290 	if ( position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
5291 		return;
5292 	}
5293 	//
5294 	uiInfo.serverStatus.numDisplayServers++;
5295 	for ( i = uiInfo.serverStatus.numDisplayServers; i > position; i-- ) {
5296 		uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i - 1];
5297 	}
5298 	uiInfo.serverStatus.displayServers[position] = num;
5299 
5300 	// update displayed levelshot
5301 	if ( position == uiInfo.serverStatus.currentServer ) {
5302 		UI_FeederSelection( FEEDER_SERVERS, uiInfo.serverStatus.currentServer );
5303 	}
5304 }
5305 
5306 /*
5307 ==================
5308 UI_RemoveServerFromDisplayList
5309 ==================
5310 */
UI_RemoveServerFromDisplayList(int num)5311 static void UI_RemoveServerFromDisplayList( int num ) {
5312 	int i, j;
5313 
5314 	for ( i = 0; i < uiInfo.serverStatus.numDisplayServers; i++ ) {
5315 		if ( uiInfo.serverStatus.displayServers[i] == num ) {
5316 			uiInfo.serverStatus.numDisplayServers--;
5317 			for ( j = i; j < uiInfo.serverStatus.numDisplayServers; j++ ) {
5318 				uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j + 1];
5319 			}
5320 			return;
5321 		}
5322 	}
5323 }
5324 
5325 /*
5326 ==================
5327 UI_BinaryServerInsertion
5328 ==================
5329 */
UI_BinaryServerInsertion(int num)5330 static void UI_BinaryServerInsertion( int num ) {
5331 	int mid, offset, res, len;
5332 
5333 	// use binary search to insert server
5334 	len = uiInfo.serverStatus.numDisplayServers;
5335 	mid = len;
5336 	offset = 0;
5337 	res = 0;
5338 	while ( mid > 0 ) {
5339 		mid = len >> 1;
5340 		//
5341 		res = trap_LAN_CompareServers( UI_SourceForLAN(), uiInfo.serverStatus.sortKey,
5342 									   uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset + mid] );
5343 		// if equal
5344 		if ( res == 0 ) {
5345 			UI_InsertServerIntoDisplayList( num, offset + mid );
5346 			return;
5347 		}
5348 		// if larger
5349 		else if ( res == 1 ) {
5350 			offset += mid;
5351 			len -= mid;
5352 		}
5353 		// if smaller
5354 		else {
5355 			len -= mid;
5356 		}
5357 	}
5358 	if ( res == 1 ) {
5359 		offset++;
5360 	}
5361 	UI_InsertServerIntoDisplayList( num, offset );
5362 }
5363 
5364 /*
5365 ==================
5366 UI_BuildServerDisplayList
5367 ==================
5368 */
UI_BuildServerDisplayList(int force)5369 static void UI_BuildServerDisplayList( int force ) {
5370 	int i, count, clients, maxClients, ping, game = 0, len, visible, friendlyFire, tourney, maxlives, punkbuster, antilag;
5371 	char info[MAX_STRING_CHARS];
5372 	//qboolean startRefresh = qtrue; // TTimo: unused
5373 	static int numinvisible;
5374 	int	lanSource;
5375 
5376 	if ( !( force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh ) ) {
5377 		return;
5378 	}
5379 	// if we shouldn't reset
5380 	if ( force == 2 ) {
5381 		force = 0;
5382 	}
5383 
5384 	// do motd updates here too
5385 	trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof( uiInfo.serverStatus.motd ) );
5386 	len = strlen( uiInfo.serverStatus.motd );
5387 	if ( len == 0 ) {
5388 		strcpy( uiInfo.serverStatus.motd, va( "Wolf Multiplayer - Version: %s", Q3_VERSION ) );
5389 		len = strlen( uiInfo.serverStatus.motd );
5390 	}
5391 	if ( len != uiInfo.serverStatus.motdLen ) {
5392 		uiInfo.serverStatus.motdLen = len;
5393 		uiInfo.serverStatus.motdWidth = -1;
5394 	}
5395 
5396 	lanSource = UI_SourceForLAN();
5397 
5398 	if ( force ) {
5399 		numinvisible = 0;
5400 		// clear number of displayed servers
5401 		uiInfo.serverStatus.numDisplayServers = 0;
5402 		uiInfo.serverStatus.numPlayersOnServers = 0;
5403 		// set list box index to zero
5404 		Menu_SetFeederSelection( NULL, FEEDER_SERVERS, 0, NULL );
5405 		// mark all servers as visible so we store ping updates for them
5406 		trap_LAN_MarkServerVisible(lanSource, -1, qtrue);
5407 	}
5408 
5409 	// get the server count (comes from the master)
5410 	count = trap_LAN_GetServerCount(lanSource);
5411 	if (count == -1 || (ui_netSource.integer == UIAS_LOCAL && count == 0) ) {
5412 		// still waiting on a response from the master
5413 		uiInfo.serverStatus.numDisplayServers = 0;
5414 		uiInfo.serverStatus.numPlayersOnServers = 0;
5415 		uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
5416 		return;
5417 	}
5418 
5419 	visible = qfalse;
5420 	for ( i = 0; i < count; i++ ) {
5421 		// if we already got info for this server
5422 		if (!trap_LAN_ServerIsVisible(lanSource, i)) {
5423 			continue;
5424 		}
5425 		visible = qtrue;
5426 		// get the ping for this server
5427 		ping = trap_LAN_GetServerPing(lanSource, i);
5428 		if (ping > 0 || ui_netSource.integer == UIAS_FAVORITES) {
5429 			// Remove favorite servers so they do not appear multiple times
5430 			// or appear when the cached server info was not filtered out
5431 			// but the new server info is filtered out.
5432 			if (ui_netSource.integer == UIAS_FAVORITES) {
5433 				UI_RemoveServerFromDisplayList(i);
5434 			}
5435 
5436 			trap_LAN_GetServerInfo(lanSource, i, info, MAX_STRING_CHARS);
5437 
5438 			clients = atoi( Info_ValueForKey( info, "clients" ) );
5439 
5440 			if ( ui_browserShowEmpty.integer == 0 ) {
5441 				if ( clients == 0 ) {
5442 					if (ping > 0) {
5443 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5444 					}
5445 					continue;
5446 				}
5447 			}
5448 
5449 			if ( ui_browserShowFull.integer == 0 ) {
5450 				maxClients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
5451 				if ( clients == maxClients ) {
5452 					if (ping > 0) {
5453 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5454 					}
5455 					continue;
5456 				}
5457 			}
5458 
5459 			// NERVE - SMF - friendly fire parsing
5460 			if ( ui_browserShowFriendlyFire.integer ) {
5461 				friendlyFire = atoi( Info_ValueForKey( info, "friendlyFire" ) );
5462 
5463 				if ( friendlyFire && ui_browserShowFriendlyFire.integer == 2 ) {
5464 					if (ping > 0) {
5465 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5466 					}
5467 					continue;
5468 				} else if ( !friendlyFire && ui_browserShowFriendlyFire.integer == 1 ) {
5469 					if (ping > 0) {
5470 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5471 					}
5472 					continue;
5473 				}
5474 			}
5475 
5476 			// NERVE - SMF - maxlives parsing
5477 			if ( ui_browserShowMaxlives.integer == 0 ) {
5478 				maxlives = atoi( Info_ValueForKey( info, "maxlives" ) );
5479 				if ( maxlives ) {
5480 					if (ping > 0) {
5481 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5482 					}
5483 					continue;
5484 				}
5485 			}
5486 
5487 			// NERVE - SMF - tourney parsing
5488 			if ( ui_browserShowTourney.integer == 0 ) {
5489 				tourney = atoi( Info_ValueForKey( info, "tourney" ) );
5490 				if ( tourney ) {
5491 					if (ping > 0) {
5492 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5493 					}
5494 					continue;
5495 				}
5496 			}
5497 
5498 			// DHM - Nerve - PunkBuster parsing
5499 			if ( ui_browserShowPunkBuster.integer ) {
5500 				punkbuster = atoi( Info_ValueForKey( info, "punkbuster" ) );
5501 
5502 				if ( punkbuster && ui_browserShowPunkBuster.integer == 2 ) {
5503 					if (ping > 0) {
5504 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5505 					}
5506 					continue;
5507 				} else if ( !punkbuster && ui_browserShowPunkBuster.integer == 1 ) {
5508 					if (ping > 0) {
5509 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5510 					}
5511 					continue;
5512 				}
5513 			}
5514 
5515 			if ( ui_browserShowAntilag.integer ) {
5516 				antilag = atoi( Info_ValueForKey( info, "g_antilag" ) );
5517 
5518 				if ( antilag && ui_browserShowAntilag.integer == 2 ) {
5519 					if (ping > 0) {
5520 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5521 					}
5522 					continue;
5523 				} else if ( !antilag && ui_browserShowAntilag.integer == 1 ) {
5524 					if (ping > 0) {
5525 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5526 					}
5527 					continue;
5528 				}
5529 			}
5530 
5531 			if ( uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1 ) {
5532 				game = atoi( Info_ValueForKey( info, "gametype" ) );
5533 				if ( game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum ) {
5534 					if (ping > 0) {
5535 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5536 					}
5537 					continue;
5538 				}
5539 			}
5540 
5541 			if ( ui_serverFilterType.integer > 0 ) {
5542 				if ( Q_stricmp( Info_ValueForKey( info, "game" ), serverFilters[ui_serverFilterType.integer].basedir ) != 0 ) {
5543 					if (ping > 0) {
5544 						trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5545 					}
5546 					continue;
5547 				}
5548 			}
5549 			// insert the server into the list
5550 			UI_BinaryServerInsertion( i );
5551 			// done with this server
5552 			if ( ping > 0 ) {
5553 				trap_LAN_MarkServerVisible(lanSource, i, qfalse);
5554 				uiInfo.serverStatus.numPlayersOnServers += clients;
5555 				numinvisible++;
5556 			}
5557 		}
5558 	}
5559 
5560 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
5561 
5562 	// if there were no servers visible for ping updates
5563 	if ( !visible ) {
5564 //		UI_StopServerRefresh();
5565 //		uiInfo.serverStatus.nextDisplayRefresh = 0;
5566 	}
5567 }
5568 
5569 typedef struct
5570 {
5571 	char *name, *altName;
5572 } serverStatusCvar_t;
5573 
5574 serverStatusCvar_t serverStatusCvars[] = {
5575 	{"sv_hostname", "Name"},
5576 	{"Address", ""},
5577 	{"gamename", "Game name"},
5578 	{"g_gametype", "Game type"},
5579 	{"mapname", "Map"},
5580 	{"version", ""},
5581 	{"protocol", ""},
5582 	{"timelimit", ""},
5583 	{"fraglimit", ""},
5584 	{NULL, NULL}
5585 };
5586 
5587 /*
5588 ==================
5589 UI_SortServerStatusInfo
5590 ==================
5591 */
UI_SortServerStatusInfo(serverStatusInfo_t * info)5592 static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
5593 	int i, j, index;
5594 	char *tmp1, *tmp2;
5595 
5596 	// FIXME: if "gamename" == "baseq3" or "missionpack" then
5597 	// replace the gametype number by FFA, CTF etc.
5598 	//
5599 	index = 0;
5600 	for ( i = 0; serverStatusCvars[i].name; i++ ) {
5601 		for ( j = 0; j < info->numLines; j++ ) {
5602 			if ( !info->lines[j][1] || info->lines[j][1][0] ) {
5603 				continue;
5604 			}
5605 			if ( !Q_stricmp( serverStatusCvars[i].name, info->lines[j][0] ) ) {
5606 				// swap lines
5607 				tmp1 = info->lines[index][0];
5608 				tmp2 = info->lines[index][3];
5609 				info->lines[index][0] = info->lines[j][0];
5610 				info->lines[index][3] = info->lines[j][3];
5611 				info->lines[j][0] = tmp1;
5612 				info->lines[j][3] = tmp2;
5613 				//
5614 				if ( strlen( serverStatusCvars[i].altName ) ) {
5615 					info->lines[index][0] = serverStatusCvars[i].altName;
5616 				}
5617 				index++;
5618 			}
5619 		}
5620 	}
5621 }
5622 
5623 /*
5624 ==================
5625 UI_GetServerStatusInfo
5626 ==================
5627 */
UI_GetServerStatusInfo(const char * serverAddress,serverStatusInfo_t * info)5628 static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
5629 	char *p, *score, *ping, *name, *p_val = NULL, *p_name = NULL;
5630 	menuDef_t *menu, *menu2; // we use the URL buttons in several menus
5631 	int i, len;
5632 
5633 	if (info) {
5634 		memset(info, 0, sizeof(*info));
5635 	}
5636 
5637 	// ignore initial unset addresses
5638 	if (serverAddress && *serverAddress == '\0') {
5639 		return qfalse;
5640 	}
5641 
5642 	// reset server status request for this address
5643 	if ( !info ) {
5644 		trap_LAN_ServerStatus( serverAddress, NULL, 0 );
5645 		return qfalse;
5646 	}
5647 
5648 	if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof( info->text ) ) ) {
5649 
5650 		menu = Menus_FindByName( "serverinfo_popmenu" );
5651 		menu2 = Menus_FindByName( "error_popmenu_diagnose" );
5652 
5653 		Q_strncpyz( info->address, serverAddress, sizeof( info->address ) );
5654 		p = info->text;
5655 		info->numLines = 0;
5656 		info->lines[info->numLines][0] = "Address";
5657 		info->lines[info->numLines][1] = "";
5658 		info->lines[info->numLines][2] = "";
5659 		info->lines[info->numLines][3] = info->address;
5660 		info->numLines++;
5661 		// cleanup of the URL cvars
5662 		trap_Cvar_Set( "ui_URL", "" );
5663 		trap_Cvar_Set( "ui_modURL", "" );
5664 		// get the cvars
5665 		while ( p && *p ) {
5666 			p = strchr( p, '\\' );
5667 			if ( !p ) {
5668 				break;
5669 			}
5670 			*p++ = '\0';
5671 			if ( p_name ) {
5672 				if ( !strcmp( p_name, "URL" ) ) {
5673 					trap_Cvar_Set( "ui_URL", p_val );
5674 					if ( menu ) {
5675 						Menu_ShowItemByName( menu, "serverURL", qtrue );
5676 					}
5677 					if ( menu2 ) {
5678 						Menu_ShowItemByName( menu2, "serverURL", qtrue );
5679 					}
5680 				} else if ( !strcmp( p_name, "mod_url" ) )        {
5681 					trap_Cvar_Set( "ui_modURL", p_val );
5682 					if ( menu ) {
5683 						Menu_ShowItemByName( menu, "modURL", qtrue );
5684 					}
5685 					if ( menu2 ) {
5686 						Menu_ShowItemByName( menu2, "modURL", qtrue );
5687 					}
5688 				}
5689 			}
5690 			if ( *p == '\\' ) {
5691 				break;
5692 			}
5693 			p_name = p;
5694 			info->lines[info->numLines][0] = p;
5695 			info->lines[info->numLines][1] = "";
5696 			info->lines[info->numLines][2] = "";
5697 			p = strchr( p, '\\' );
5698 			if ( !p ) {
5699 				break;
5700 			}
5701 			*p++ = '\0';
5702 			p_val = p;
5703 			info->lines[info->numLines][3] = p;
5704 
5705 			info->numLines++;
5706 			if ( info->numLines >= MAX_SERVERSTATUS_LINES ) {
5707 				break;
5708 			}
5709 		}
5710 		// get the player list
5711 		if ( info->numLines < MAX_SERVERSTATUS_LINES - 3 ) {
5712 			// empty line
5713 			info->lines[info->numLines][0] = "";
5714 			info->lines[info->numLines][1] = "";
5715 			info->lines[info->numLines][2] = "";
5716 			info->lines[info->numLines][3] = "";
5717 			info->numLines++;
5718 			// header
5719 			info->lines[info->numLines][0] = "num";
5720 			info->lines[info->numLines][1] = "score";
5721 			info->lines[info->numLines][2] = "ping";
5722 			info->lines[info->numLines][3] = "name";
5723 			info->numLines++;
5724 			// parse players
5725 			i = 0;
5726 			len = 0;
5727 			while ( p && *p ) {
5728 				if ( *p == '\\' ) {
5729 					*p++ = '\0';
5730 				}
5731 				score = p;
5732 				p = strchr( p, ' ' );
5733 				if ( !p ) {
5734 					break;
5735 				}
5736 				*p++ = '\0';
5737 				ping = p;
5738 				p = strchr( p, ' ' );
5739 				if ( !p ) {
5740 					break;
5741 				}
5742 				*p++ = '\0';
5743 				name = p;
5744 				Com_sprintf( &info->pings[len], sizeof( info->pings ) - len, "%d", i );
5745 				info->lines[info->numLines][0] = &info->pings[len];
5746 				len += strlen( &info->pings[len] ) + 1;
5747 				info->lines[info->numLines][1] = score;
5748 				info->lines[info->numLines][2] = ping;
5749 				info->lines[info->numLines][3] = name;
5750 				info->numLines++;
5751 				if ( info->numLines >= MAX_SERVERSTATUS_LINES ) {
5752 					break;
5753 				}
5754 				p = strchr( p, '\\' );
5755 				if ( !p ) {
5756 					break;
5757 				}
5758 				*p++ = '\0';
5759 				//
5760 				i++;
5761 			}
5762 		}
5763 		UI_SortServerStatusInfo( info );
5764 		return qtrue;
5765 	}
5766 	return qfalse;
5767 }
5768 
5769 /*
5770 ==================
5771 stristr
5772 ==================
5773 */
stristr(char * str,char * charset)5774 static char *stristr( char *str, char *charset ) {
5775 	int i;
5776 
5777 	while ( *str ) {
5778 		for ( i = 0; charset[i] && str[i]; i++ ) {
5779 			if ( toupper( charset[i] ) != toupper( str[i] ) ) {
5780 				break;
5781 			}
5782 		}
5783 		if ( !charset[i] ) {
5784 			return str;
5785 		}
5786 		str++;
5787 	}
5788 	return NULL;
5789 }
5790 
5791 /*
5792 ==================
5793 UI_BuildFindPlayerList
5794 ==================
5795 */
UI_BuildFindPlayerList(qboolean force)5796 static void UI_BuildFindPlayerList( qboolean force ) {
5797 	static int numFound, numTimeOuts;
5798 	int i, j, resend;
5799 	serverStatusInfo_t info;
5800 	char name[MAX_NAME_LENGTH + 2];
5801 	char infoString[MAX_STRING_CHARS];
5802 	int  lanSource;
5803 
5804 	if ( !force ) {
5805 		if ( !uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime ) {
5806 			return;
5807 		}
5808 	} else {
5809 		memset( &uiInfo.pendingServerStatus, 0, sizeof( uiInfo.pendingServerStatus ) );
5810 		uiInfo.numFoundPlayerServers = 0;
5811 		uiInfo.currentFoundPlayerServer = 0;
5812 		trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof( uiInfo.findPlayerName ) );
5813 		Q_CleanStr( uiInfo.findPlayerName );
5814 		// should have a string of some length
5815 		if ( !strlen( uiInfo.findPlayerName ) ) {
5816 			uiInfo.nextFindPlayerRefresh = 0;
5817 			return;
5818 		}
5819 		// set resend time
5820 		resend = ui_serverStatusTimeOut.integer / 2 - 10;
5821 		if ( resend < 50 ) {
5822 			resend = 50;
5823 		}
5824 		trap_Cvar_Set( "cl_serverStatusResendTime", va( "%d", resend ) );
5825 		// reset all server status requests
5826 		trap_LAN_ServerStatus( NULL, NULL, 0 );
5827 		//
5828 		uiInfo.numFoundPlayerServers = 1;
5829 		Com_sprintf( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
5830 					 sizeof( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1] ),
5831 					 "searching %d...", uiInfo.pendingServerStatus.num );
5832 		numFound = 0;
5833 		numTimeOuts++;
5834 	}
5835 	for ( i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) {
5836 		// if this pending server is valid
5837 		if ( uiInfo.pendingServerStatus.server[i].valid ) {
5838 			// try to get the server status for this server
5839 			if ( UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
5840 				//
5841 				numFound++;
5842 				// parse through the server status lines
5843 				for ( j = 0; j < info.numLines; j++ ) {
5844 					// should have ping info
5845 					if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
5846 						continue;
5847 					}
5848 					// clean string first
5849 					Q_strncpyz( name, info.lines[j][3], sizeof( name ) );
5850 					Q_CleanStr( name );
5851 					// if the player name is a substring
5852 					if ( stristr( name, uiInfo.findPlayerName ) ) {
5853 						// add to found server list if we have space (always leave space for a line with the number found)
5854 						if ( uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS - 1 ) {
5855 							//
5856 							Q_strncpyz( uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers - 1],
5857 										uiInfo.pendingServerStatus.server[i].adrstr,
5858 										sizeof( uiInfo.foundPlayerServerAddresses[0] ) );
5859 							Q_strncpyz( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
5860 										uiInfo.pendingServerStatus.server[i].name,
5861 										sizeof( uiInfo.foundPlayerServerNames[0] ) );
5862 							uiInfo.numFoundPlayerServers++;
5863 						} else {
5864 							// can't add any more so we're done
5865 							uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
5866 						}
5867 					}
5868 				}
5869 				Com_sprintf( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
5870 							 sizeof( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1] ),
5871 							 "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound );
5872 				// retrieved the server status so reuse this spot
5873 				uiInfo.pendingServerStatus.server[i].valid = qfalse;
5874 			}
5875 		}
5876 		// if empty pending slot or timed out
5877 		if ( !uiInfo.pendingServerStatus.server[i].valid ||
5878 			 uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer ) {
5879 			if ( uiInfo.pendingServerStatus.server[i].valid ) {
5880 				numTimeOuts++;
5881 			}
5882 			// reset server status request for this address
5883 			UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
5884 			// reuse pending slot
5885 			uiInfo.pendingServerStatus.server[i].valid = qfalse;
5886 			// if we didn't try to get the status of all servers in the main browser yet
5887 			if ( uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers ) {
5888 				uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
5889 				lanSource = UI_SourceForLAN();
5890 				trap_LAN_GetServerAddressString(lanSource, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
5891 												 uiInfo.pendingServerStatus.server[i].adrstr, sizeof( uiInfo.pendingServerStatus.server[i].adrstr ) );
5892 				trap_LAN_GetServerInfo(lanSource, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
5893 				Q_strncpyz( uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey( infoString, "hostname" ), sizeof( uiInfo.pendingServerStatus.server[0].name ) );
5894 				uiInfo.pendingServerStatus.server[i].valid = qtrue;
5895 				uiInfo.pendingServerStatus.num++;
5896 				Com_sprintf( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1],
5897 							 sizeof( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers - 1] ),
5898 							 "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound );
5899 			}
5900 		}
5901 	}
5902 	for ( i = 0; i < MAX_SERVERSTATUSREQUESTS; i++ ) {
5903 		if ( uiInfo.pendingServerStatus.server[i].valid ) {
5904 			break;
5905 		}
5906 	}
5907 	// if still trying to retrieve server status info
5908 	if ( i < MAX_SERVERSTATUSREQUESTS ) {
5909 		uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
5910 	} else {
5911 		// add a line that shows the number of servers found
5912 		if ( !uiInfo.numFoundPlayerServers ) {
5913 			Com_sprintf( uiInfo.foundPlayerServerNames[0], sizeof( uiInfo.foundPlayerServerNames[0] ), "no servers found" );
5914 		} else {
5915 			Com_sprintf( uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof( uiInfo.foundPlayerServerNames[0] ),
5916 						"%d server%s found with player %s", uiInfo.numFoundPlayerServers - 1,
5917 						uiInfo.numFoundPlayerServers == 2 ? "" : "s", uiInfo.findPlayerName );
5918 		}
5919 		uiInfo.nextFindPlayerRefresh = 0;
5920 		// show the server status info for the selected server
5921 		UI_FeederSelection( FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer );
5922 	}
5923 }
5924 
5925 /*
5926 ==================
5927 UI_BuildServerStatus
5928 ==================
5929 */
UI_BuildServerStatus(qboolean force)5930 static void UI_BuildServerStatus( qboolean force ) {
5931 	menuDef_t *menu;
5932 
5933 	if ( uiInfo.nextFindPlayerRefresh ) {
5934 		return;
5935 	}
5936 	if ( !force ) {
5937 		if ( !uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime ) {
5938 			return;
5939 		}
5940 	} else {
5941 		Menu_SetFeederSelection( NULL, FEEDER_SERVERSTATUS, 0, NULL );
5942 		uiInfo.serverStatusInfo.numLines = 0;
5943 		// TTimo - reset the server URL / mod URL till we get the new ones
5944 		// the URL buttons are used in the two menus, serverinfo_popmenu and error_popmenu_diagnose
5945 		menu = Menus_FindByName( "serverinfo_popmenu" );
5946 		if ( menu ) {
5947 			Menu_ShowItemByName( menu, "serverURL", qfalse );
5948 			Menu_ShowItemByName( menu, "modURL", qfalse );
5949 		}
5950 		menu = Menus_FindByName( "error_popmenu_diagnose" );
5951 		if ( menu ) {
5952 			Menu_ShowItemByName( menu, "serverURL", qfalse );
5953 			Menu_ShowItemByName( menu, "modURL", qfalse );
5954 		}
5955 		// reset all server status requests
5956 		trap_LAN_ServerStatus( NULL, NULL, 0 );
5957 	}
5958 	if ( uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0 ) {
5959 		return;
5960 	}
5961 	if ( UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
5962 		uiInfo.nextServerStatusRefresh = 0;
5963 		UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
5964 	} else {
5965 		uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
5966 	}
5967 }
5968 
5969 /*
5970 ==================
5971 UI_FeederCount
5972 ==================
5973 */
UI_FeederCount(float feederID)5974 static int UI_FeederCount( float feederID ) {
5975 	if ( feederID == FEEDER_HEADS ) {
5976 		return uiInfo.characterCount;
5977 	} else if ( feederID == FEEDER_Q3HEADS ) {
5978 		return uiInfo.q3HeadCount;
5979 	} else if ( feederID == FEEDER_CINEMATICS ) {
5980 		return uiInfo.movieCount;
5981 	} else if ( feederID == FEEDER_SAVEGAMES ) {
5982 		return uiInfo.savegameCount;
5983 	} else if ( feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS ) {
5984 		return UI_MapCountByGameType( feederID == FEEDER_MAPS ? qtrue : qfalse );
5985 	} else if ( feederID == FEEDER_SERVERS ) {
5986 		return uiInfo.serverStatus.numDisplayServers;
5987 	} else if ( feederID == FEEDER_SERVERSTATUS ) {
5988 		return uiInfo.serverStatusInfo.numLines;
5989 	} else if ( feederID == FEEDER_FINDPLAYER ) {
5990 		return uiInfo.numFoundPlayerServers;
5991 	} else if ( feederID == FEEDER_PLAYER_LIST ) {
5992 		if ( uiInfo.uiDC.realTime > uiInfo.playerRefresh ) {
5993 			uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
5994 			UI_BuildPlayerList();
5995 		}
5996 		return uiInfo.playerCount;
5997 	} else if ( feederID == FEEDER_TEAM_LIST ) {
5998 		if ( uiInfo.uiDC.realTime > uiInfo.playerRefresh ) {
5999 			uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
6000 			UI_BuildPlayerList();
6001 		}
6002 		return uiInfo.myTeamCount;
6003 	} else if ( feederID == FEEDER_MODS ) {
6004 		return uiInfo.modCount;
6005 	} else if ( feederID == FEEDER_DEMOS ) {
6006 		return uiInfo.demoCount;
6007 		// NERVE - SMF
6008 	} else if ( feederID == FEEDER_PICKSPAWN ) {
6009 		return uiInfo.spawnCount;
6010 	} else if ( feederID == FEEDER_SOLDIERWEAP ) {
6011 		int i, count;
6012 		for ( i = 0, count = 0; weaponTypes[i].name; i++ )
6013 			if ( weaponTypes[i].flags & PT_RIFLE ) {
6014 				count++;
6015 			}
6016 		return count;
6017 	} else if ( feederID == FEEDER_LIEUTWEAP ) {
6018 		int i, count;
6019 		for ( i = 0, count = 0; weaponTypes[i].name; i++ )
6020 			if ( weaponTypes[i].flags & PT_LIGHTONLY ) {
6021 				count++;
6022 			}
6023 		return count;
6024 	}
6025 	// -NERVE - SMF
6026 	return 0;
6027 }
6028 
UI_SelectedMap(int index,int * actual)6029 static const char *UI_SelectedMap( int index, int *actual ) {
6030 	int i, c;
6031 	c = 0;
6032 	*actual = 0;
6033 	for ( i = 0; i < uiInfo.mapCount; i++ ) {
6034 		if ( uiInfo.mapList[i].active ) {
6035 			if ( c == index ) {
6036 				*actual = i;
6037 				return uiInfo.mapList[i].mapName;
6038 			} else {
6039 				c++;
6040 			}
6041 		}
6042 	}
6043 	return "";
6044 }
6045 
UI_GetIndexFromSelection(int actual)6046 static int UI_GetIndexFromSelection( int actual ) {
6047 	int i, c;
6048 	c = 0;
6049 	for ( i = 0; i < uiInfo.mapCount; i++ ) {
6050 		if ( uiInfo.mapList[i].active ) {
6051 			if ( i == actual ) {
6052 				return c;
6053 			}
6054 			c++;
6055 		}
6056 	}
6057 	return 0;
6058 }
6059 
UI_UpdatePendingPings(void)6060 static void UI_UpdatePendingPings( void ) {
6061 	trap_LAN_ResetPings(UI_SourceForLAN());
6062 	uiInfo.serverStatus.refreshActive = qtrue;
6063 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
6064 }
6065 
6066 // NERVE - SMF
UI_FeederAddItem(float feederID,const char * name,int index)6067 static void UI_FeederAddItem( float feederID, const char *name, int index ) {
6068 
6069 }
6070 // -NERVE - SMF
6071 
6072 //----(SA)	added (whoops, this got nuked in a check-in...)
UI_FileText(char * fileName)6073 static const char *UI_FileText( char *fileName ) {
6074 	int len;
6075 	fileHandle_t f;
6076 	static char buf[MAX_MENUDEFFILE];
6077 
6078 //	return "flubber";
6079 
6080 	len = trap_FS_FOpenFile( fileName, &f, FS_READ );
6081 	if ( !f ) {
6082 		return NULL;
6083 	}
6084 
6085 	trap_FS_Read( buf, len, f );
6086 	buf[len] = 0;
6087 	trap_FS_FCloseFile( f );
6088 	return &buf[0];
6089 }
6090 //----(SA)	end
6091 
6092 
UI_FeederItemText(float feederID,int index,int column,qhandle_t * handle)6093 static const char *UI_FeederItemText( float feederID, int index, int column, qhandle_t *handle ) {
6094 	static char info[MAX_STRING_CHARS];
6095 	static char hostname[1024];
6096 	static char clientBuff[32];
6097 	static char pingstr[10];
6098 	static int lastColumn = -1;
6099 	static int lastTime = 0;
6100 	*handle = -1;
6101 	if ( feederID == FEEDER_HEADS ) {
6102 		if ( index >= 0 && index < uiInfo.characterCount ) {
6103 			return uiInfo.characterList[index].name;
6104 		}
6105 	} else if ( feederID == FEEDER_Q3HEADS ) {
6106 		if ( index >= 0 && index < uiInfo.q3HeadCount ) {
6107 			return uiInfo.q3HeadNames[index];
6108 		}
6109 	} else if ( feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS ) {
6110 		int actual;
6111 		return UI_SelectedMap( index, &actual );
6112 	} else if ( feederID == FEEDER_SERVERS ) {
6113 		if ( index >= 0 && index < uiInfo.serverStatus.numDisplayServers ) {
6114 			int ping, game, punkbuster, antilag;
6115 			if ( lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000 ) {
6116 				trap_LAN_GetServerInfo(UI_SourceForLAN(), uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
6117 				lastColumn = column;
6118 				lastTime = uiInfo.uiDC.realTime;
6119 			}
6120 			antilag = atoi( Info_ValueForKey( info, "g_antilag" ) );
6121 			ping = atoi( Info_ValueForKey( info, "ping" ) );
6122 			if ( ping == -1 ) {
6123 				// if we ever see a ping that is out of date, do a server refresh
6124 				// UI_UpdatePendingPings();
6125 			}
6126 			switch ( column ) {
6127 			case SORT_HOST:
6128 				if ( ping <= 0 ) {
6129 					return Info_ValueForKey( info, "addr" );
6130 				} else {
6131 					int nettype = atoi(Info_ValueForKey(info, "nettype"));
6132 
6133 						if (nettype < 0 || nettype >= ARRAY_LEN(netnames)) {
6134 							nettype = 0;
6135 						}
6136 
6137 					Com_sprintf( hostname, sizeof( hostname ), "^7|^2%s^7|  %s",
6138 						netnames[nettype],
6139 						Info_ValueForKey( info, "hostname" ));
6140 					return hostname;
6141 				}
6142 			case SORT_MAP: return Info_ValueForKey( info, "mapname" );
6143 			case SORT_CLIENTS:
6144 				Com_sprintf( clientBuff, sizeof( clientBuff ), "%s (%s)", Info_ValueForKey( info, "clients" ), Info_ValueForKey( info, "sv_maxclients" ) );
6145 				return clientBuff;
6146 			case SORT_GAME:
6147 				game = atoi( Info_ValueForKey( info, "gametype" ) );
6148 				if ( game >= 0 && game < numTeamArenaGameTypes ) {
6149 					return teamArenaGameTypes[game];
6150 				} else {
6151 					return "Unknown";
6152 				}
6153 			case SORT_PING:
6154 				if ( ping <= 0 ) {
6155 					return "...";
6156 				} else {
6157 					if ( !antilag ) {
6158 						Com_sprintf( pingstr, sizeof( pingstr ), "^3%s", Info_ValueForKey( info, "ping" ) );
6159 					} else {
6160 						Q_strncpyz( pingstr, Info_ValueForKey( info, "ping" ), sizeof( pingstr ) );
6161 					}
6162 					return pingstr;
6163 				}
6164 			case SORT_PUNKBUSTER:
6165 				punkbuster = atoi( Info_ValueForKey( info, "punkbuster" ) );
6166 				if ( punkbuster ) {
6167 					return translated_yes;
6168 				} else {
6169 					return translated_no;
6170 				}
6171 			}
6172 		}
6173 	} else if ( feederID == FEEDER_SERVERSTATUS ) {
6174 		if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
6175 			if ( column >= 0 && column < 4 ) {
6176 				return uiInfo.serverStatusInfo.lines[index][column];
6177 			}
6178 		}
6179 	} else if ( feederID == FEEDER_FINDPLAYER ) {
6180 		if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
6181 			//return uiInfo.foundPlayerServerAddresses[index];
6182 			return uiInfo.foundPlayerServerNames[index];
6183 		}
6184 	} else if ( feederID == FEEDER_PLAYER_LIST ) {
6185 		if ( index >= 0 && index < uiInfo.playerCount ) {
6186 			return uiInfo.playerNames[index];
6187 		}
6188 	} else if ( feederID == FEEDER_TEAM_LIST ) {
6189 		if ( index >= 0 && index < uiInfo.myTeamCount ) {
6190 			return uiInfo.teamNames[index];
6191 		}
6192 	} else if ( feederID == FEEDER_MODS ) {
6193 		if ( index >= 0 && index < uiInfo.modCount ) {
6194 			if ( uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr ) {
6195 				return uiInfo.modList[index].modDescr;
6196 			} else {
6197 				return uiInfo.modList[index].modName;
6198 			}
6199 		}
6200 	} else if ( feederID == FEEDER_CINEMATICS ) {
6201 		if ( index >= 0 && index < uiInfo.movieCount ) {
6202 			return uiInfo.movieList[index];
6203 		}
6204 	} else if ( feederID == FEEDER_SAVEGAMES ) {
6205 		if ( index >= 0 && index < uiInfo.savegameCount ) {
6206 			return uiInfo.savegameList[index].name;
6207 		}
6208 	} else if ( feederID == FEEDER_DEMOS ) {
6209 		if ( index >= 0 && index < uiInfo.demoCount ) {
6210 			return uiInfo.demoList[index];
6211 		}
6212 	}
6213 	// NERVE - SMF
6214 	else if ( feederID == FEEDER_PICKSPAWN ) {
6215 		return uiInfo.spawnPoints[index];
6216 	}
6217 	// -NERVE - SMF
6218 	return "";
6219 }
6220 
6221 
UI_FeederItemImage(float feederID,int index)6222 static qhandle_t UI_FeederItemImage( float feederID, int index ) {
6223 	if ( feederID == FEEDER_HEADS ) {
6224 		if ( index >= 0 && index < uiInfo.characterCount ) {
6225 			if ( uiInfo.characterList[index].headImage == -1 ) {
6226 				uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip( uiInfo.characterList[index].imageName );
6227 			}
6228 			return uiInfo.characterList[index].headImage;
6229 		}
6230 	} else if ( feederID == FEEDER_Q3HEADS ) {
6231 		if ( index >= 0 && index < uiInfo.q3HeadCount ) {
6232 			return uiInfo.q3HeadIcons[index];
6233 		}
6234 	} else if ( feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS ) {
6235 		int actual;
6236 
6237 		UI_SelectedMap( index, &actual );
6238 		index = actual;
6239 		if ( index >= 0 && index < uiInfo.mapCount ) {
6240 			if ( uiInfo.mapList[index].levelShot == -1 ) {
6241 				uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip( uiInfo.mapList[index].imageName );
6242 			}
6243 			return uiInfo.mapList[index].levelShot;
6244 		}
6245 	} else if ( feederID == FEEDER_SAVEGAMES ) {
6246 		if ( index >= 0 && index < uiInfo.savegameCount ) {
6247 			if ( uiInfo.savegameList[index].sshotImage == -1 ) {
6248 				uiInfo.savegameList[index].sshotImage = trap_R_RegisterShaderNoMip( va( "save/images/%s.tga", uiInfo.savegameList[index].name ) );
6249 			}
6250 			return uiInfo.savegameList[index].sshotImage;
6251 		}
6252 		// NERVE - SMF
6253 	} else if ( feederID == FEEDER_SOLDIERWEAP ) {
6254 		int i, count;
6255 		for ( i = 0, count = 0; weaponTypes[i].name; i++ ) {
6256 			if ( weaponTypes[i].flags & PT_RIFLE ) {
6257 				count++;
6258 			}
6259 			if ( count == index + 1 ) {
6260 				return trap_R_RegisterShaderNoMip( weaponTypes[i].name );
6261 			}
6262 		}
6263 	} else if ( feederID == FEEDER_LIEUTWEAP ) {
6264 		int i, count;
6265 		for ( i = 0, count = 0; weaponTypes[i].name; i++ ) {
6266 			if ( weaponTypes[i].flags & PT_LIGHTONLY ) {
6267 				count++;
6268 			}
6269 			if ( count == index + 1 ) {
6270 				return trap_R_RegisterShaderNoMip( weaponTypes[i].name );
6271 			}
6272 		}
6273 	}
6274 	// -NERVE - SMF
6275 
6276 	return 0;
6277 }
6278 
UI_FeederSelection(float feederID,int index)6279 static void UI_FeederSelection( float feederID, int index ) {
6280 	static char info[MAX_STRING_CHARS];
6281 	if ( feederID == FEEDER_HEADS ) {
6282 		if ( index >= 0 && index < uiInfo.characterCount ) {
6283 			trap_Cvar_Set( "team_model", uiInfo.characterList[index].female ? "janet" : "james" );
6284 			trap_Cvar_Set( "team_headmodel", va( "*%s", uiInfo.characterList[index].name ) );
6285 			updateModel = qtrue;
6286 		}
6287 	} else if ( feederID == FEEDER_Q3HEADS ) {
6288 		if ( index >= 0 && index < uiInfo.q3HeadCount ) {
6289 			trap_Cvar_Set( "model", uiInfo.q3HeadNames[index] );
6290 			trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index] );
6291 			updateModel = qtrue;
6292 		}
6293 	} else if ( feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS ) {
6294 		int actual, map;
6295 		map = ( feederID == FEEDER_ALLMAPS ) ? ui_currentNetMap.integer : ui_currentMap.integer;
6296 		if ( uiInfo.mapList[map].cinematic >= 0 ) {
6297 			trap_CIN_StopCinematic( uiInfo.mapList[map].cinematic );
6298 			uiInfo.mapList[map].cinematic = -1;
6299 		}
6300 		UI_SelectedMap( index, &actual );
6301 		trap_Cvar_Set( "ui_mapIndex", va( "%d", index ) );
6302 		ui_mapIndex.integer = index;
6303 
6304 		// NERVE - SMF - setup advanced server vars
6305 		if ( feederID == FEEDER_ALLMAPS ) {
6306 			ui_currentMap.integer = actual;
6307 			trap_Cvar_Set( "ui_currentMap", va( "%d", actual ) );
6308 			trap_Cvar_Set( "ui_userTimelimit", va( "%d", uiInfo.mapList[ui_currentMap.integer].Timelimit ) );
6309 			trap_Cvar_Set( "ui_userAxisRespawnTime", va( "%d", uiInfo.mapList[ui_currentMap.integer].AxisRespawnTime ) );
6310 			trap_Cvar_Set( "ui_userAlliedRespawnTime", va( "%d", uiInfo.mapList[ui_currentMap.integer].AlliedRespawnTime ) );
6311 		}
6312 		// -NERVE - SMF
6313 
6314 		if ( feederID == FEEDER_MAPS ) {
6315 			ui_currentMap.integer = actual;
6316 			trap_Cvar_Set( "ui_currentMap", va( "%d", actual ) );
6317 			uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic( va( "%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
6318 			UI_LoadBestScores( uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum );
6319 			trap_Cvar_Set( "ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName );
6320 			updateOpponentModel = qtrue;
6321 		} else {
6322 			ui_currentNetMap.integer = actual;
6323 			trap_Cvar_Set( "ui_currentNetMap", va( "%d", actual ) );
6324 			uiInfo.mapList[ui_currentNetMap.integer].cinematic = trap_CIN_PlayCinematic( va( "%s.roq", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
6325 		}
6326 
6327 	} else if ( feederID == FEEDER_SERVERS ) {
6328 		const char *mapName = NULL;
6329 		uiInfo.serverStatus.currentServer = index;
6330 		trap_LAN_GetServerInfo(UI_SourceForLAN(), uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
6331 		uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip( va( "levelshots/%s", Info_ValueForKey( info, "mapname" ) ) );
6332 		if ( uiInfo.serverStatus.currentServerCinematic >= 0 ) {
6333 			trap_CIN_StopCinematic( uiInfo.serverStatus.currentServerCinematic );
6334 			uiInfo.serverStatus.currentServerCinematic = -1;
6335 		}
6336 		mapName = Info_ValueForKey( info, "mapname" );
6337 		if ( mapName && *mapName ) {
6338 			uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic( va( "%s.roq", mapName ), 0, 0, 0, 0, ( CIN_loop | CIN_silent ) );
6339 		}
6340 	} else if ( feederID == FEEDER_SERVERSTATUS ) {
6341 		//
6342 	} else if ( feederID == FEEDER_FINDPLAYER ) {
6343 		uiInfo.currentFoundPlayerServer = index;
6344 		//
6345 		if ( index < uiInfo.numFoundPlayerServers - 1 ) {
6346 			// build a new server status for this server
6347 			Q_strncpyz( uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof( uiInfo.serverStatusAddress ) );
6348 			Menu_SetFeederSelection( NULL, FEEDER_SERVERSTATUS, 0, NULL );
6349 			UI_BuildServerStatus( qtrue );
6350 		}
6351 	} else if ( feederID == FEEDER_PLAYER_LIST ) {
6352 		uiInfo.playerIndex = index;
6353 	} else if ( feederID == FEEDER_TEAM_LIST ) {
6354 		uiInfo.teamIndex = index;
6355 	} else if ( feederID == FEEDER_MODS ) {
6356 		uiInfo.modIndex = index;
6357 	} else if ( feederID == FEEDER_CINEMATICS ) {
6358 		uiInfo.movieIndex = index;
6359 		if ( uiInfo.previewMovie >= 0 ) {
6360 			trap_CIN_StopCinematic( uiInfo.previewMovie );
6361 		}
6362 		uiInfo.previewMovie = -1;
6363 	} else if ( feederID == FEEDER_SAVEGAMES ) {
6364 		uiInfo.savegameIndex = index;
6365 	} else if ( feederID == FEEDER_DEMOS ) {
6366 		uiInfo.demoIndex = index;
6367 		// NERVE - SMF
6368 	} else if ( feederID == FEEDER_PICKSPAWN ) {
6369 		trap_Cmd_ExecuteText( EXEC_NOW, va( "setspawnpt %i\n", index ) );
6370 	} else if ( feederID == FEEDER_SOLDIERWEAP ) {
6371 		int i, count;
6372 		for ( i = 0, count = 0; weaponTypes[i].name; i++ ) {
6373 			if ( weaponTypes[i].flags & PT_RIFLE ) {
6374 				count++;
6375 			}
6376 			if ( count == index + 1 ) {
6377 				trap_Cvar_Set( weaponTypes[i].cvar, va( "%i", weaponTypes[i].value ) );
6378 				trap_Cvar_Set( "ui_weapon", UI_TranslateString( weaponTypes[i].desc ) );
6379 				WM_setWeaponPics();
6380 
6381 				break;
6382 			}
6383 		}
6384 	} else if ( feederID == FEEDER_LIEUTWEAP ) {
6385 		int i, count;
6386 		for ( i = 0, count = 0; weaponTypes[i].name; i++ ) {
6387 			if ( weaponTypes[i].flags & PT_LIGHTONLY ) {
6388 				count++;
6389 			}
6390 			if ( count == index + 1 ) {
6391 				trap_Cvar_Set( weaponTypes[i].cvar, va( "%i", weaponTypes[i].value ) );
6392 				trap_Cvar_Set( "ui_weapon", UI_TranslateString( weaponTypes[i].desc ) );
6393 				WM_setWeaponPics();
6394 				break;
6395 			}
6396 		}
6397 	}
6398 	// -NERVE - SMF
6399 }
6400 
6401 /*
6402 // TTimo: unused
6403 static qboolean Team_Parse(char **p) {
6404   char *token;
6405   const char *tempStr;
6406 	int i;
6407 
6408   token = COM_ParseExt(p, qtrue);
6409 
6410   if (token[0] != '{') {
6411 	return qfalse;
6412   }
6413 
6414   while ( 1 ) {
6415 
6416 	token = COM_ParseExt(p, qtrue);
6417 
6418 	if (Q_stricmp(token, "}") == 0) {
6419 	  return qtrue;
6420 	}
6421 
6422 	if ( !token[0] ) {
6423 	  return qfalse;
6424 	}
6425 
6426 	if (token[0] == '{') {
6427 		if (uiInfo.teamCount == MAX_TEAMS) {
6428 			uiInfo.teamCount--;
6429 			Com_Printf("Too many teams, last team replaced!\n");
6430 		}
6431 
6432 	  // seven tokens per line, team name and icon, and 5 team member names
6433 	  if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
6434 		return qfalse;
6435 	  }
6436 
6437 
6438 			uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
6439 		uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
6440 		  uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
6441 			uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
6442 
6443 			uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
6444 
6445 			for (i = 0; i < TEAM_MEMBERS; i++) {
6446 				uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
6447 				if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
6448 					return qfalse;
6449 				}
6450 			}
6451 
6452 	  Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
6453 	  uiInfo.teamCount++;
6454 
6455 	  token = COM_ParseExt(p, qtrue);
6456 	  if (token[0] != '}') {
6457 		return qfalse;
6458 	  }
6459 	}
6460   }
6461 
6462   return qfalse;
6463 }
6464 */
6465 
6466 /*
6467 // TTimo: unused
6468 static qboolean Character_Parse(char **p) {
6469   char *token;
6470   const char *tempStr;
6471 
6472   token = COM_ParseExt(p, qtrue);
6473 
6474   if (token[0] != '{') {
6475 	return qfalse;
6476   }
6477 
6478 
6479   while ( 1 ) {
6480 	token = COM_ParseExt(p, qtrue);
6481 
6482 	if (Q_stricmp(token, "}") == 0) {
6483 	  return qtrue;
6484 	}
6485 
6486 	if ( !token[0] ) {
6487 	  return qfalse;
6488 	}
6489 
6490 	if (token[0] == '{') {
6491 	  if (uiInfo.characterCount == MAX_HEADS) {
6492 		  uiInfo.characterCount--;
6493 		  Com_Printf("Too many characters, last character replaced!\n");
6494 	  }
6495 
6496 	  // two tokens per line, character name and sex
6497 	  if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
6498 		return qfalse;
6499 	  }
6500 
6501 	  uiInfo.characterList[uiInfo.characterCount].headImage = -1;
6502 			uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
6503 
6504 	  if (tempStr && (tempStr[0] == 'f' || tempStr[0] == 'F')) {
6505 		uiInfo.characterList[uiInfo.characterCount].female = qtrue;
6506 	  } else {
6507 		uiInfo.characterList[uiInfo.characterCount].female = qfalse;
6508 	  }
6509 
6510 	  Com_Printf("Loaded %s character %s.\n", tempStr, uiInfo.characterList[uiInfo.characterCount].name);
6511 	  uiInfo.characterCount++;
6512 
6513 	  token = COM_ParseExt(p, qtrue);
6514 	  if (token[0] != '}') {
6515 		return qfalse;
6516 	  }
6517 	}
6518   }
6519 
6520   return qfalse;
6521 }
6522 */
6523 
6524 /*
6525 // TTimo: unused
6526 static qboolean Alias_Parse(char **p) {
6527   char *token;
6528 
6529   token = COM_ParseExt(p, qtrue);
6530 
6531   if (token[0] != '{') {
6532 	return qfalse;
6533   }
6534 
6535   while ( 1 ) {
6536 	token = COM_ParseExt(p, qtrue);
6537 
6538 	if (Q_stricmp(token, "}") == 0) {
6539 	  return qtrue;
6540 	}
6541 
6542 	if ( !token[0] ) {
6543 	  return qfalse;
6544 	}
6545 
6546 	if (token[0] == '{') {
6547 	  if (uiInfo.aliasCount == MAX_ALIASES) {
6548 		  uiInfo.aliasCount--;
6549 		  Com_Printf("Too many aliases, last alias replaced!\n");
6550 	  }
6551 
6552 	  // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
6553 	  if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) {
6554 		return qfalse;
6555 	  }
6556 
6557 	  Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
6558 	  uiInfo.aliasCount++;
6559 
6560 	  token = COM_ParseExt(p, qtrue);
6561 	  if (token[0] != '}') {
6562 		return qfalse;
6563 	  }
6564 	}
6565   }
6566 
6567   return qfalse;
6568 }
6569 */
6570 
6571 // mode
6572 // 0 - high level parsing
6573 // 1 - team parsing
6574 // 2 - character parsing
6575 /*
6576 // TTimo: unused
6577 static void UI_ParseTeamInfo(const char *teamFile) {
6578 	char	*token;
6579   char *p;
6580   char *buff = NULL;
6581   //int mode = 0; // TTimo: unused
6582 
6583   buff = GetMenuBuffer(teamFile);
6584   if (!buff) {
6585 	return;
6586   }
6587 
6588   p = buff;
6589 
6590 	while ( 1 ) {
6591 		token = COM_ParseExt( &p, qtrue );
6592 		if( !token[0] || token[0] == '}') {
6593 			break;
6594 		}
6595 
6596 		if ( Q_stricmp( token, "}" ) == 0 ) {
6597 	  break;
6598 	}
6599 
6600 	if (Q_stricmp(token, "teams") == 0) {
6601 
6602 	  if (Team_Parse(&p)) {
6603 		continue;
6604 	  } else {
6605 		break;
6606 	  }
6607 	}
6608 
6609 	if (Q_stricmp(token, "characters") == 0) {
6610 	  Character_Parse(&p);
6611 	}
6612 
6613 	if (Q_stricmp(token, "aliases") == 0) {
6614 	  Alias_Parse(&p);
6615 	}
6616   }
6617 }
6618 */
6619 
6620 /*
6621 ==============
6622 GameType_Parse
6623 ==============
6624 */
GameType_Parse(char ** p,qboolean join)6625 static qboolean GameType_Parse( char **p, qboolean join ) {
6626 	char *token;
6627 
6628 	token = COM_ParseExt( p, qtrue );
6629 
6630 	if ( token[0] != '{' ) {
6631 		return qfalse;
6632 	}
6633 
6634 	if ( join ) {
6635 		uiInfo.numJoinGameTypes = 0;
6636 	} else {
6637 		uiInfo.numGameTypes = 0;
6638 	}
6639 
6640 	while ( 1 ) {
6641 		token = COM_ParseExt( p, qtrue );
6642 
6643 		if ( Q_stricmp( token, "}" ) == 0 ) {
6644 			return qtrue;
6645 		}
6646 
6647 		if ( !token[0] ) {
6648 			return qfalse;
6649 		}
6650 
6651 		if ( token[0] == '{' ) {
6652 			// two tokens per line, gametype name and number
6653 			if ( join ) {
6654 				if ( !String_Parse( p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType ) || !Int_Parse( p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum ) ) {
6655 					return qfalse;
6656 				}
6657 			} else {
6658 				if ( !String_Parse( p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType ) || !Int_Parse( p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum ) ) {
6659 					return qfalse;
6660 				}
6661 			}
6662 
6663 			if ( join ) {
6664 				if ( uiInfo.numJoinGameTypes < MAX_GAMETYPES ) {
6665 					uiInfo.numJoinGameTypes++;
6666 				} else {
6667 					Com_Printf( "Too many net game types, last one replace!\n" );
6668 				}
6669 			} else {
6670 				if ( uiInfo.numGameTypes < MAX_GAMETYPES ) {
6671 					uiInfo.numGameTypes++;
6672 				} else {
6673 					Com_Printf( "Too many game types, last one replace!\n" );
6674 				}
6675 			}
6676 
6677 			token = COM_ParseExt( p, qtrue );
6678 			if ( token[0] != '}' ) {
6679 				return qfalse;
6680 			}
6681 		}
6682 	}
6683 	return qfalse;
6684 }
6685 
MapList_Parse(char ** p)6686 static qboolean MapList_Parse( char **p ) {
6687 	char *token;
6688 
6689 	token = COM_ParseExt( p, qtrue );
6690 
6691 	if ( token[0] != '{' ) {
6692 		return qfalse;
6693 	}
6694 
6695 	uiInfo.mapCount = 0;
6696 
6697 	while ( 1 ) {
6698 		token = COM_ParseExt( p, qtrue );
6699 
6700 		if ( Q_stricmp( token, "}" ) == 0 ) {
6701 			return qtrue;
6702 		}
6703 
6704 		if ( !token[0] ) {
6705 			return qfalse;
6706 		}
6707 
6708 		if ( token[0] == '{' ) {
6709 			if ( !String_Parse( p, &uiInfo.mapList[uiInfo.mapCount].mapName ) || !String_Parse( p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName )
6710 				 || !Int_Parse( p, &uiInfo.mapList[uiInfo.mapCount].teamMembers ) ) {
6711 				return qfalse;
6712 			}
6713 
6714 			if ( !String_Parse( p, &uiInfo.mapList[uiInfo.mapCount].opponentName ) ) {
6715 				return qfalse;
6716 			}
6717 
6718 			uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
6719 
6720 			while ( 1 ) {
6721 				token = COM_ParseExt( p, qtrue );
6722 				if ( token[0] >= '0' && token[0] <= '9' ) {
6723 					uiInfo.mapList[uiInfo.mapCount].typeBits |= ( 1 << ( token[0] - 0x030 ) );
6724 					if ( !Int_Parse( p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30] ) ) {
6725 						return qfalse;
6726 					}
6727 				} else {
6728 					break;
6729 				}
6730 			}
6731 
6732 			//mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
6733 			//if (uiInfo.mapCount == 0) {
6734 			// only load the first cinematic, selection loads the others
6735 			//  uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
6736 			//}
6737 			uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
6738 			uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip( va( "levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName ) );
6739 
6740 			if ( uiInfo.mapCount < MAX_MAPS ) {
6741 				uiInfo.mapCount++;
6742 			} else {
6743 				Com_Printf( "Too many maps, last one replaced!\n" );
6744 			}
6745 		}
6746 	}
6747 	return qfalse;
6748 }
6749 
UI_ParseGameInfo(const char * teamFile)6750 static void UI_ParseGameInfo( const char *teamFile ) {
6751 	char    *token;
6752 	char *p;
6753 	char *buff = NULL;
6754 	// int mode = 0; // TTimo: unused
6755 
6756 	buff = GetMenuBuffer( teamFile );
6757 	if ( !buff ) {
6758 		return;
6759 	}
6760 
6761 	p = buff;
6762 
6763 	while ( 1 ) {
6764 		token = COM_ParseExt( &p, qtrue );
6765 		if ( !token[0] || token[0] == '}' ) {
6766 			break;
6767 		}
6768 
6769 		if ( Q_stricmp( token, "}" ) == 0 ) {
6770 			break;
6771 		}
6772 
6773 		if ( Q_stricmp( token, "gametypes" ) == 0 ) {
6774 
6775 			if ( GameType_Parse( &p, qfalse ) ) {
6776 				continue;
6777 			} else {
6778 				break;
6779 			}
6780 		}
6781 
6782 		if ( Q_stricmp( token, "joingametypes" ) == 0 ) {
6783 
6784 			if ( GameType_Parse( &p, qtrue ) ) {
6785 				continue;
6786 			} else {
6787 				break;
6788 			}
6789 		}
6790 
6791 		if ( Q_stricmp( token, "maps" ) == 0 ) {
6792 			// start a new menu
6793 			MapList_Parse( &p );
6794 		}
6795 
6796 	}
6797 }
6798 
UI_Pause(qboolean b)6799 static void UI_Pause( qboolean b ) {
6800 	if ( b ) {
6801 		// pause the game and set the ui keycatcher
6802 		trap_Cvar_Set( "cl_paused", "1" );
6803 		trap_Key_SetCatcher( KEYCATCH_UI );
6804 	} else {
6805 		// unpause the game and clear the ui keycatcher
6806 		trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
6807 		trap_Key_ClearStates();
6808 		trap_Cvar_Set( "cl_paused", "0" );
6809 	}
6810 }
6811 
6812 /*
6813 // TTimo: unused
6814 static int UI_OwnerDraw_Width(int ownerDraw) {
6815   return 0;
6816 }
6817 */
6818 
UI_PlayCinematic(const char * name,float x,float y,float w,float h)6819 static int UI_PlayCinematic( const char *name, float x, float y, float w, float h ) {
6820 	return trap_CIN_PlayCinematic( name, x, y, w, h, ( CIN_loop | CIN_silent ) );
6821 }
6822 
UI_StopCinematic(int handle)6823 static void UI_StopCinematic( int handle ) {
6824 	if ( handle >= 0 ) {
6825 		trap_CIN_StopCinematic( handle );
6826 	} else {
6827 		handle = abs( handle );
6828 		if ( handle == UI_MAPCINEMATIC ) {
6829 			if ( uiInfo.mapList[ui_currentMap.integer].cinematic >= 0 ) {
6830 				trap_CIN_StopCinematic( uiInfo.mapList[ui_currentMap.integer].cinematic );
6831 				uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
6832 			}
6833 		} else if ( handle == UI_NETMAPCINEMATIC ) {
6834 			if ( uiInfo.serverStatus.currentServerCinematic >= 0 ) {
6835 				trap_CIN_StopCinematic( uiInfo.serverStatus.currentServerCinematic );
6836 				uiInfo.serverStatus.currentServerCinematic = -1;
6837 			}
6838 		} else if ( handle == UI_CLANCINEMATIC ) {
6839 			int i = UI_TeamIndexFromName( UI_Cvar_VariableString( "ui_teamName" ) );
6840 			if ( i >= 0 && i < uiInfo.teamCount ) {
6841 				if ( uiInfo.teamList[i].cinematic >= 0 ) {
6842 					trap_CIN_StopCinematic( uiInfo.teamList[i].cinematic );
6843 					uiInfo.teamList[i].cinematic = -1;
6844 				}
6845 			}
6846 		}
6847 	}
6848 }
6849 
UI_DrawCinematic(int handle,float x,float y,float w,float h)6850 static void UI_DrawCinematic( int handle, float x, float y, float w, float h ) {
6851 	if ( ui_fixedAspect.integer ) {
6852 		if ( DC->glconfig.vidWidth * 480.0 > DC->glconfig.vidHeight * 640.0 ) {
6853 			float scaledx = x * ( 480.0 / 640.0 ) + ( DC->xBias / DC->xscaleStretch);
6854 			float scaledw = w * ( 480.0 / 640.0 );
6855 
6856 			trap_CIN_SetExtents( handle, scaledx, y, scaledw, h );
6857 		} else if ( DC->glconfig.vidWidth * 480.0 < DC->glconfig.vidHeight * 640.0 ) {
6858 			float scaledy = y * ( 480.0 / 640.0 ) + ( DC->yBias / DC->yscaleStretch);
6859 			float scaledh = h * ( 480.0 / 640.0 );
6860 
6861 			trap_CIN_SetExtents( handle, x, scaledy, w, scaledh );
6862 		} else {
6863 			trap_CIN_SetExtents( handle, x, y, w, h );
6864 		}
6865 	} else {
6866 		trap_CIN_SetExtents( handle, x, y, w, h );
6867 	}
6868 
6869 	trap_CIN_DrawCinematic( handle );
6870 }
6871 
UI_RunCinematicFrame(int handle)6872 static void UI_RunCinematicFrame( int handle ) {
6873 	trap_CIN_RunCinematic( handle );
6874 }
6875 
6876 
6877 
6878 /*
6879 =================
6880 PlayerModel_BuildList
6881 =================
6882 */
6883 /*
6884 // TTimo: unused
6885 static void UI_BuildQ3Model_List( void )
6886 {
6887 	int		numdirs;
6888 	int		numfiles;
6889 	char	dirlist[2048];
6890 	char	filelist[2048];
6891 	char	skinname[MAX_QPATH];
6892 	char*	dirptr;
6893 	char*	fileptr;
6894 	int		i;
6895 	int		j;
6896 	int		dirlen;
6897 	int		filelen;
6898 
6899 	uiInfo.q3HeadCount = 0;
6900 
6901 	// iterate directory of all player models
6902 	numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
6903 	dirptr  = dirlist;
6904 	for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
6905 	{
6906 		dirlen = strlen(dirptr);
6907 
6908 		if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
6909 
6910 		if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
6911 			continue;
6912 
6913 		// iterate all skin files in directory
6914 		numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
6915 		fileptr  = filelist;
6916 		for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
6917 		{
6918 			filelen = strlen(fileptr);
6919 
6920 			COM_StripExtension(fileptr, skinname, sizeof(skinname));
6921 
6922 			// look for icon_????
6923 			if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
6924 			{
6925 				if (Q_stricmp(skinname, "icon_default") == 0) {
6926 					Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
6927 				} else {
6928 					Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s/%s",dirptr, skinname + 5);
6929 				}
6930 				uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
6931 			}
6932 
6933 		}
6934 	}
6935 
6936 }
6937 */
6938 
6939 /*
6940 =================
6941 UI_Init
6942 =================
6943 */
_UI_Init(qboolean inGameLoad)6944 void _UI_Init( qboolean inGameLoad ) {
6945 
6946 	//uiInfo.inGameLoad = inGameLoad;
6947 
6948 	UI_RegisterCvars();
6949 	UI_InitMemory();
6950 
6951 	trap_Cvar_Set( "ui_menuFiles", "ui_mp/menus.txt" ); // NERVE - SMF - we need to hardwire for wolfMP
6952 
6953 	// cache redundant calulations
6954 	trap_GetGlconfig( &uiInfo.uiDC.glconfig );
6955 
6956 	// for 640x480 virtualized screen
6957 	if ( ui_fixedAspect.integer ) {
6958 		uiInfo.uiDC.xscaleStretch = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
6959 		uiInfo.uiDC.yscaleStretch = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
6960 		if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
6961 			uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
6962 			uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
6963 			// wide screen
6964 			uiInfo.uiDC.xBias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
6965 			uiInfo.uiDC.xscale = uiInfo.uiDC.yscale;
6966 			// no narrow screen
6967 			uiInfo.uiDC.yBias = 0;
6968 		} else {
6969 			uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
6970 			uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
6971 			// narrow screen
6972 			uiInfo.uiDC.yBias = 0.5 * ( uiInfo.uiDC.glconfig.vidHeight - ( uiInfo.uiDC.glconfig.vidWidth * (480.0/640.0) ) );
6973 			uiInfo.uiDC.yscale = uiInfo.uiDC.xscale;
6974 			// no wide screen
6975 			uiInfo.uiDC.xBias = 0;
6976 		}
6977 	} else {
6978 		uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * ( 1.0 / 480.0 );
6979 		uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * ( 1.0 / 640.0 );
6980 		if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
6981 			// wide screen
6982 			uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * ( 640.0 / 480.0 ) ) );
6983 		} else {
6984 			// no wide screen
6985 			uiInfo.uiDC.bias = 0;
6986 		}
6987 	}
6988 
6989 
6990 	//UI_Load();
6991 	uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
6992 	uiInfo.uiDC.setColor = &UI_SetColor;
6993 	uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
6994 	uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
6995 	uiInfo.uiDC.drawText = &Text_Paint;
6996 	uiInfo.uiDC.textWidth = &Text_Width;
6997 	uiInfo.uiDC.textHeight = &Text_Height;
6998 	uiInfo.uiDC.textFont = &Text_SetActiveFont;
6999 	uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
7000 	uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
7001 	uiInfo.uiDC.fillRect = &UI_FillRect;
7002 	uiInfo.uiDC.drawRect = &_UI_DrawRect;
7003 	uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
7004 	uiInfo.uiDC.clearScene = &trap_R_ClearScene;
7005 	uiInfo.uiDC.drawSides = &_UI_DrawSides;
7006 	uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
7007 	uiInfo.uiDC.renderScene = &trap_R_RenderScene;
7008 	uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
7009 	uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
7010 	uiInfo.uiDC.getValue = &UI_GetValue;
7011 	uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
7012 	uiInfo.uiDC.runScript = &UI_RunMenuScript;
7013 	uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
7014 	uiInfo.uiDC.setCVar = trap_Cvar_Set;
7015 	uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
7016 	uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
7017 	uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
7018 	uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
7019 	uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
7020 	uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
7021 	uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
7022 	uiInfo.uiDC.feederCount = &UI_FeederCount;
7023 	uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
7024 	uiInfo.uiDC.feederItemText = &UI_FeederItemText;
7025 	uiInfo.uiDC.fileText = &UI_FileText;    //----(SA)	re-added
7026 	uiInfo.uiDC.feederSelection = &UI_FeederSelection;
7027 	uiInfo.uiDC.feederAddItem = &UI_FeederAddItem;                  // NERVE - SMF
7028 	uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
7029 	uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
7030 	uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
7031 	uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
7032 	uiInfo.uiDC.Error = &Com_Error;
7033 	uiInfo.uiDC.Print = &Com_Printf;
7034 	uiInfo.uiDC.DPrint = &Com_DPrintf;
7035 	uiInfo.uiDC.Pause = &UI_Pause;
7036 	uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
7037 	uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
7038 	uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
7039 	uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
7040 	uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
7041 	uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
7042 	uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
7043 	uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
7044 	uiInfo.uiDC.translateString = &UI_TranslateString;            // NERVE - SMF
7045 	uiInfo.uiDC.checkAutoUpdate = &trap_CheckAutoUpdate;            // DHM - Nerve
7046 	uiInfo.uiDC.getAutoUpdate = &trap_GetAutoUpdate;                // DHM - Nerve
7047 
7048 	Init_Display( &uiInfo.uiDC );
7049 
7050 	String_Init();
7051 
7052 	uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
7053 
7054 	AssetCache();
7055 
7056 	uiInfo.teamCount = 0;
7057 	uiInfo.characterCount = 0;
7058 	uiInfo.aliasCount = 0;
7059 
7060 	UI_ParseGameInfo( "gameinfo.txt" );
7061 	UI_LoadArenas();
7062 
7063 	UI_LoadMenus( "ui_mp/ingame.txt", qfalse );
7064 
7065 	Menus_CloseAll();
7066 
7067 	trap_LAN_LoadCachedServers();
7068 	UI_LoadBestScores( uiInfo.mapList[0].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum );
7069 
7070 	// sets defaults for ui temp cvars
7071 	uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue( "color" ) - 1];
7072 	uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue( "cg_drawCrosshair" );
7073 	trap_Cvar_Set( "ui_mousePitch", ( trap_Cvar_VariableValue( "m_pitch" ) >= 0 ) ? "0" : "1" );
7074 
7075 	uiInfo.serverStatus.currentServerCinematic = -1;
7076 	uiInfo.previewMovie = -1;
7077 
7078 	if ( trap_Cvar_VariableValue( "ui_TeamArenaFirstRun" ) == 0 ) {
7079 		trap_Cvar_Set( "s_volume", "0.8" );
7080 		trap_Cvar_Set( "s_musicvolume", "0.5" );
7081 		trap_Cvar_Set( "ui_TeamArenaFirstRun", "1" );
7082 	}
7083 
7084 	trap_Cvar_Register( NULL, "debug_protocol", "", 0 );
7085 
7086 	// NERVE - SMF - hardwire net cvars
7087 	trap_Cvar_Set( "ui_netGameType", "0" );
7088 	trap_Cvar_Set( "ui_actualNetGameType", "5" );
7089 	// -NERVE - SMF
7090 
7091 	// init Yes/No once for cl_language -> server browser (punkbuster)
7092 	Q_strncpyz( translated_yes, DC->translateString( "Yes" ), sizeof( translated_yes ) );
7093 	Q_strncpyz( translated_no, DC->translateString( "No" ), sizeof( translated_no ) );
7094 }
7095 
7096 
7097 /*
7098 =================
7099 UI_KeyEvent
7100 =================
7101 */
_UI_KeyEvent(int key,qboolean down)7102 void _UI_KeyEvent( int key, qboolean down ) {
7103 	static qboolean bypassKeyClear = qfalse;
7104 
7105 	if ( Menu_Count() > 0 ) {
7106 		menuDef_t *menu = Menu_GetFocused();
7107 		if ( menu ) {
7108 			if ( trap_Cvar_VariableValue( "cl_bypassMouseInput" ) ) {
7109 				bypassKeyClear = qtrue;
7110 			}
7111 
7112 			if ( key == K_ESCAPE && down && !Menus_AnyFullScreenVisible() ) {
7113 				Menus_CloseAll();
7114 			} else {
7115 				Menu_HandleKey( menu, key, down );
7116 			}
7117 		} else {
7118 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
7119 
7120 			// NERVE - SMF - we don't want to clear key states if bypassing input
7121 			if ( !bypassKeyClear ) {
7122 				trap_Key_ClearStates();
7123 			}
7124 
7125 			bypassKeyClear = qfalse;
7126 
7127 			trap_Cvar_Set( "cl_paused", "0" );
7128 		}
7129 	}
7130 
7131 	//if ((s > 0) && (s != menu_null_sound)) {
7132 	//  trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
7133 	//}
7134 }
7135 
7136 /*
7137 =================
7138 UI_MouseEvent
7139 =================
7140 */
_UI_MouseEvent(int dx,int dy)7141 void _UI_MouseEvent( int dx, int dy ) {
7142 	// update mouse screen position
7143 	uiInfo.uiDC.cursorx += dx;
7144 	if ( uiInfo.uiDC.cursorx < 0 ) {
7145 		uiInfo.uiDC.cursorx = 0;
7146 	} else if ( uiInfo.uiDC.cursorx > SCREEN_WIDTH ) {
7147 		uiInfo.uiDC.cursorx = SCREEN_WIDTH;
7148 	}
7149 
7150 	uiInfo.uiDC.cursory += dy;
7151 	if ( uiInfo.uiDC.cursory < 0 ) {
7152 		uiInfo.uiDC.cursory = 0;
7153 	} else if ( uiInfo.uiDC.cursory > SCREEN_HEIGHT ) {
7154 		uiInfo.uiDC.cursory = SCREEN_HEIGHT;
7155 	}
7156 
7157 	if ( Menu_Count() > 0 ) {
7158 		//menuDef_t *menu = Menu_GetFocused();
7159 		//Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
7160 		Display_MouseMove( NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory );
7161 	}
7162 
7163 }
7164 
UI_LoadNonIngame(void)7165 void UI_LoadNonIngame( void ) {
7166 	const char *menuSet = UI_Cvar_VariableString( "ui_menuFiles" );
7167 
7168 	if ( menuSet == NULL || menuSet[0] == '\0' ) {
7169 		menuSet = "ui_mp/menus.txt";
7170 	}
7171 	UI_LoadMenus( menuSet, qfalse );
7172 	uiInfo.inGameLoad = qfalse;
7173 }
7174 
7175 
7176 //----(SA)	added
7177 static uiMenuCommand_t menutype = UIMENU_NONE;
7178 
_UI_GetActiveMenu(void)7179 uiMenuCommand_t _UI_GetActiveMenu( void ) {
7180 	return menutype;
7181 }
7182 //----(SA)	end
7183 
7184 #define MISSING_FILES_MSG "The following packs are missing:"
7185 
_UI_SetActiveMenu(uiMenuCommand_t menu)7186 void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
7187 	char buf[4096]; // com_errorMessage can go up to 4096
7188 	char *missing_files;
7189 
7190 	// this should be the ONLY way the menu system is brought up
7191 	// enusure minumum menu data is cached
7192 	if ( Menu_Count() > 0 ) {
7193 		vec3_t v;
7194 		v[0] = v[1] = v[2] = 0;
7195 
7196 		menutype = menu;    //----(SA)	added
7197 
7198 		switch ( menu ) {
7199 		case UIMENU_NONE:
7200 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
7201 			trap_Key_ClearStates();
7202 			trap_Cvar_Set( "cl_paused", "0" );
7203 			Menus_CloseAll();
7204 
7205 			return;
7206 		case UIMENU_MAIN:
7207 			trap_Key_SetCatcher( KEYCATCH_UI );
7208 			if ( uiInfo.inGameLoad ) {
7209 				UI_LoadNonIngame();
7210 			}
7211 			Menus_CloseAll();
7212 			Menus_ActivateByName( "main", qtrue );
7213 			trap_Cvar_VariableStringBuffer( "com_errorMessage", buf, sizeof( buf ) );
7214 			// JPW NERVE stricmp() is silly but works, take a look at error.menu to see why.  I think this is bustified in q3ta
7215 			// NOTE TTimo - I'm not sure Q_stricmp is useful to anything anymore
7216 			// show_bug.cgi?id=507
7217 			// TTimo - improved and tweaked that area a whole bunch
7218 			if ( ( strlen( buf ) ) && ( Q_stricmp( buf,";" ) ) ) {
7219 				trap_Cvar_Set( "com_errorMessage", UI_TranslateString( buf ) );        // NERVE - SMF
7220 				// hacky, wanted to have the printout of missing files
7221 				// text printing limitations force us to keep it all in a single message
7222 				// NOTE: this works thanks to flip flop in UI_Cvar_VariableString
7223 				if ( UI_Cvar_VariableString( "com_errorDiagnoseIP" )[0] ) {
7224 					missing_files = UI_Cvar_VariableString( "com_missingFiles" );
7225 					if ( missing_files[0] ) {
7226 						trap_Cvar_Set( "com_errorMessage",
7227 									   va( "%s\n\n%s\n%s",
7228 										   UI_Cvar_VariableString( "com_errorMessage" ),
7229 										   UI_TranslateString( MISSING_FILES_MSG ),
7230 										   missing_files ) );
7231 					}
7232 				}
7233 				Menus_ActivateByName( "error_popmenu_diagnose", qtrue );
7234 			}
7235 			return;
7236 
7237 		case UIMENU_TEAM:
7238 			trap_Key_SetCatcher( KEYCATCH_UI );
7239 			Menus_ActivateByName( "team", qtrue );
7240 			return;
7241 
7242 		case UIMENU_NEED_CD:
7243 			trap_Key_SetCatcher( KEYCATCH_UI );
7244 			Menus_ActivateByName( "needcd", qtrue );
7245 			return;
7246 
7247 		case UIMENU_BAD_CD_KEY:
7248 			trap_Key_SetCatcher( KEYCATCH_UI );
7249 			Menus_ActivateByName( "badcd", qtrue );
7250 			return;
7251 
7252 		case UIMENU_INGAME:
7253 			trap_Key_SetCatcher( KEYCATCH_UI );
7254 			UI_BuildPlayerList();
7255 			Menus_CloseAll();
7256 			Menus_ActivateByName( "ingame", qtrue );
7257 			return;
7258 
7259 			// NERVE - SMF
7260 		case UIMENU_WM_QUICKMESSAGE:
7261 			DC->cursorx = 639;
7262 			DC->cursory = 479;
7263 			trap_Key_SetCatcher( KEYCATCH_UI );
7264 			Menus_CloseAll();
7265 			Menus_OpenByName( "wm_quickmessage" );
7266 			return;
7267 
7268 		case UIMENU_WM_QUICKMESSAGEALT:
7269 			DC->cursorx = 639;
7270 			DC->cursory = 479;
7271 			trap_Key_SetCatcher( KEYCATCH_UI );
7272 			Menus_CloseAll();
7273 			Menus_OpenByName( "wm_quickmessageAlt" );
7274 			return;
7275 
7276 		case UIMENU_WM_LIMBO:
7277 			if ( !trap_Cvar_VariableValue( "ui_limboMode" ) ) {
7278 				DC->cursorx = 320;
7279 				DC->cursory = 240;
7280 			}
7281 			trap_Key_SetCatcher( KEYCATCH_UI );
7282 			Menus_CloseAll();
7283 			Menus_OpenByName( "wm_limboView" );
7284 			return;
7285 
7286 		case UIMENU_WM_AUTOUPDATE:
7287 			// TTimo - changing the auto-update strategy to a modal prompt
7288 			Menus_OpenByName( "wm_autoupdate_modal" );
7289 			return;
7290 			// -NERVE - SMF
7291 		default:
7292 			return; // TTimo: a lot of not handled
7293 		}
7294 	}
7295 }
7296 
_UI_IsFullscreen(void)7297 qboolean _UI_IsFullscreen( void ) {
7298 	return Menus_AnyFullScreenVisible();
7299 }
7300 
7301 
7302 
7303 static connstate_t lastConnState;
7304 static char lastLoadingText[MAX_INFO_VALUE];
7305 
UI_ReadableSize(char * buf,int bufsize,int value)7306 static void UI_ReadableSize( char *buf, int bufsize, int value ) {
7307 	if ( value > 1024 * 1024 * 1024 ) { // gigs
7308 		Com_sprintf( buf, bufsize, "%d", value / ( 1024 * 1024 * 1024 ) );
7309 		Com_sprintf( buf + strlen( buf ), bufsize - strlen( buf ), ".%02d GB",
7310 					 ( value % ( 1024 * 1024 * 1024 ) ) * 100 / ( 1024 * 1024 * 1024 ) );
7311 	} else if ( value > 1024 * 1024 ) { // megs
7312 		Com_sprintf( buf, bufsize, "%d", value / ( 1024 * 1024 ) );
7313 		Com_sprintf( buf + strlen( buf ), bufsize - strlen( buf ), ".%02d MB",
7314 					 ( value % ( 1024 * 1024 ) ) * 100 / ( 1024 * 1024 ) );
7315 	} else if ( value > 1024 ) { // kilos
7316 		Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
7317 	} else { // bytes
7318 		Com_sprintf( buf, bufsize, "%d bytes", value );
7319 	}
7320 }
7321 
7322 // Assumes time is in sec
UI_PrintTime(char * buf,int bufsize,int time)7323 static void UI_PrintTime( char *buf, int bufsize, int time ) {
7324 	//time /= 1000;  // change to seconds
7325 
7326 	if ( time > 3600 ) { // in the hours range
7327 		Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, ( time % 3600 ) / 60 );
7328 	} else if ( time > 60 ) { // mins
7329 		Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
7330 	} else  { // secs
7331 		Com_sprintf( buf, bufsize, "%d sec", time );
7332 	}
7333 }
7334 
Text_PaintCenter(float x,float y,float scale,vec4_t color,const char * text,float adjust)7335 void Text_PaintCenter( float x, float y, float scale, vec4_t color, const char *text, float adjust ) {
7336 	int len = Text_Width( text, scale, 0 );
7337 	Text_Paint( x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
7338 }
7339 
7340 #define ESTIMATES 80
UI_DisplayDownloadInfo(const char * downloadName,float centerPoint,float yStart,float scale)7341 static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
7342 	static char dlText[]    = "Downloading:";
7343 	static char etaText[]   = "Estimated time left:";
7344 	static char xferText[]  = "Transfer rate:";
7345 	static int tleEstimates[ESTIMATES] = { 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
7346 										   60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
7347 										   60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,
7348 										   60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60 };
7349 	static int tleIndex = 0;
7350 
7351 	int downloadSize, downloadCount, downloadTime;
7352 	char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
7353 	int xferRate;
7354 	const char *s;
7355 
7356 	vec4_t bg_color = { 0.3f, 0.3f, 0.3f, 0.8f };
7357 
7358 	downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
7359 	downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
7360 	downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
7361 
7362 	// Background
7363 	UI_FillRect( 0, yStart + 185, 640, 83, bg_color );
7364 
7365 	UI_SetColor( colorYellow );
7366 	Text_Paint( 92, yStart + 210, scale, colorYellow, dlText, 0, 64, ITEM_TEXTSTYLE_SHADOWEDMORE );
7367 	Text_Paint( 35, yStart + 235, scale, colorYellow, etaText, 0, 64, ITEM_TEXTSTYLE_SHADOWEDMORE );
7368 	Text_Paint( 86, yStart + 260, scale, colorYellow, xferText, 0, 64, ITEM_TEXTSTYLE_SHADOWEDMORE );
7369 
7370 	if ( downloadSize > 0 ) {
7371 		s = va( "%s (%d%%)", downloadName,
7372 			(int)( (float)downloadCount * 100.0f / downloadSize ) );
7373 	} else {
7374 		s = downloadName;
7375 	}
7376 
7377 	Text_Paint( 260, yStart + 210, scale, colorYellow, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
7378 
7379 	UI_ReadableSize( dlSizeBuf,     sizeof dlSizeBuf,       downloadCount );
7380 	UI_ReadableSize( totalSizeBuf,  sizeof totalSizeBuf,    downloadSize );
7381 
7382 	if ( downloadCount < 4096 || !downloadTime ) {
7383 		Text_PaintCenter( centerPoint, yStart + 235, scale, colorYellow, "estimating", 0 );
7384 		Text_PaintCenter( centerPoint, yStart + 340, scale, colorYellow, va( "(%s of %s copied)", dlSizeBuf, totalSizeBuf ), 0 );
7385 	} else {
7386 		if ( ( uiInfo.uiDC.realTime - downloadTime ) / 1000 ) {
7387 			xferRate = downloadCount / ( ( uiInfo.uiDC.realTime - downloadTime ) / 1000 );
7388 		} else {
7389 			xferRate = 0;
7390 		}
7391 		UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
7392 
7393 		// Extrapolate estimated completion time
7394 		if ( downloadSize && xferRate ) {
7395 			int n = downloadSize / xferRate; // estimated time for entire d/l in secs
7396 			int timeleft = 0, i;
7397 
7398 			// We do it in K (/1024) because we'd overflow around 4MB
7399 			tleEstimates[ tleIndex ] = ( n - ( ( ( downloadCount / 1024 ) * n ) / ( downloadSize / 1024 ) ) );
7400 			tleIndex++;
7401 			if ( tleIndex >= ESTIMATES ) {
7402 				tleIndex = 0;
7403 			}
7404 
7405 			for ( i = 0; i < ESTIMATES; i++ )
7406 				timeleft += tleEstimates[ i ];
7407 
7408 			timeleft /= ESTIMATES;
7409 
7410 			UI_PrintTime( dlTimeBuf, sizeof dlTimeBuf, timeleft );
7411 
7412 			Text_Paint( 260, yStart + 235, scale, colorYellow, dlTimeBuf, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
7413 			Text_PaintCenter( centerPoint, yStart + 340, scale, colorYellow, va( "(%s of %s copied)", dlSizeBuf, totalSizeBuf ), 0 );
7414 		} else {
7415 			Text_PaintCenter( centerPoint, yStart + 235, scale, colorYellow, "estimating", 0 );
7416 			if ( downloadSize ) {
7417 				Text_PaintCenter( centerPoint, yStart + 340, scale, colorYellow, va( "(%s of %s copied)", dlSizeBuf, totalSizeBuf ), 0 );
7418 			} else {
7419 				Text_PaintCenter( centerPoint, yStart + 340, scale, colorYellow, va( "(%s copied)", dlSizeBuf ), 0 );
7420 			}
7421 		}
7422 
7423 		if ( xferRate ) {
7424 			Text_Paint( 260, yStart + 260, scale, colorYellow, va( "%s/Sec", xferRateBuf ), 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE );
7425 		}
7426 	}
7427 }
7428 
7429 /*
7430 ========================
7431 UI_DrawConnectScreen
7432 
7433 This will also be overlaid on the cgame info screen during loading
7434 to prevent it from blinking away too rapidly on local or lan games.
7435 ========================
7436 */
7437 #define CP_LINEWIDTH 50
7438 
UI_DrawConnectScreen(qboolean overlay)7439 void UI_DrawConnectScreen( qboolean overlay ) {
7440 	char            *s;
7441 	uiClientState_t cstate;
7442 	char text[256];
7443 	float centerPoint, yStart, scale;
7444 	vec4_t color = { 0.3f, 0.3f, 0.3f, 0.8f };
7445 
7446 	char downloadName[MAX_INFO_VALUE];
7447 
7448 	menuDef_t *menu = Menus_FindByName( "Connect" );
7449 
7450 
7451 	if ( !overlay && menu ) {
7452 		Menu_Paint( menu, qtrue );
7453 	}
7454 
7455 	if ( !overlay ) {
7456 		centerPoint = 320;
7457 		yStart = 130;
7458 		scale = 0.4f;
7459 	} else {
7460 		return;
7461 	}
7462 
7463 	// see what information we should display
7464 	trap_GetClientState( &cstate );
7465 
7466 	if ( !Q_stricmp( cstate.servername,"localhost" ) ) {
7467 		Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, "Starting up...", ITEM_TEXTSTYLE_SHADOWEDMORE);
7468 	} else {
7469 		Com_sprintf(text, sizeof(text), UI_TranslateString( "Connecting to %s" ), cstate.servername );
7470 		Text_PaintCenter( centerPoint, yStart + 48, scale, colorWhite,text, ITEM_TEXTSTYLE_SHADOWEDMORE );
7471 	}
7472 
7473 	// display global MOTD at bottom (don't draw during download, the space is already used)
7474 	// moved downloadName query up, this is used in CA_CONNECTED
7475 	trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof( downloadName ) );
7476 	if ( !*downloadName ) {
7477 		Text_PaintCenter( centerPoint, 475, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0 );
7478 	}
7479 
7480 	// print any server info (server full, bad version, etc)
7481 	// DHM - Nerve :: This now accepts strings up to 256 chars long, and will break them up into multiple lines.
7482 	//					They are also now printed in Yellow for readability.
7483 	if ( cstate.connState < CA_CONNECTED ) {
7484 		char    *s;
7485 		char ps[60];
7486 		int i, len, index = 0, yPrint = yStart + 210;
7487 		qboolean neednewline = qfalse;
7488 
7489 		s = UI_TranslateString( cstate.messageString );
7490 		len = strlen( s );
7491 
7492 		for ( i = 0; i < len; i++, index++ ) {
7493 
7494 			// copy to temp buffer
7495 			ps[index] = s[i];
7496 
7497 			if ( index > ( CP_LINEWIDTH - 10 ) && i > 0 ) {
7498 				neednewline = qtrue;
7499 			}
7500 
7501 			// if out of temp buffer room OR end of string OR it is time to linebreak & we've found a space
7502 			if ( ( index >= 58 ) || ( i == ( len - 1 ) ) || ( neednewline && s[i] == ' ' ) ) {
7503 				ps[index + 1] = '\0';
7504 
7505 				DC->fillRect( 0, yPrint - 17, 640, 22, color );
7506 				Text_PaintCenter( centerPoint, yPrint, scale, colorYellow, ps, 0 );
7507 
7508 				neednewline = qfalse;
7509 				yPrint += 22;       // next line
7510 				index = -1;         // sigh, for loop will increment to 0
7511 			}
7512 		}
7513 
7514 	}
7515 
7516 	if ( lastConnState > cstate.connState ) {
7517 		lastLoadingText[0] = '\0';
7518 	}
7519 	lastConnState = cstate.connState;
7520 
7521 	switch ( cstate.connState ) {
7522 	case CA_CONNECTING:
7523 		s = va( UI_TranslateString( "Awaiting connection...%i" ), cstate.connectPacketCount );
7524 		break;
7525 	case CA_CHALLENGING:
7526 		s = va( UI_TranslateString( "Awaiting challenge...%i" ), cstate.connectPacketCount );
7527 		break;
7528 	case CA_CONNECTED:
7529 		if ( *downloadName ) {
7530 			UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
7531 			return;
7532 		}
7533 		s = UI_TranslateString( "Awaiting gamestate..." );
7534 		break;
7535 	case CA_LOADING:
7536 		return;
7537 	case CA_PRIMED:
7538 		return;
7539 	default:
7540 		return;
7541 	}
7542 
7543 
7544 	if ( Q_stricmp( cstate.servername,"localhost" ) ) {
7545 		Text_PaintCenter( centerPoint, yStart + 80, scale, colorWhite, s, 0 );
7546 	}
7547 
7548 	// password required / connection rejected information goes here
7549 }
7550 
7551 
7552 /*
7553 ================
7554 cvars
7555 ================
7556 */
7557 
7558 typedef struct {
7559 	vmCvar_t    *vmCvar;
7560 	char        *cvarName;
7561 	char        *defaultString;
7562 	int cvarFlags;
7563 } cvarTable_t;
7564 
7565 vmCvar_t ui_ffa_fraglimit;
7566 vmCvar_t ui_ffa_timelimit;
7567 
7568 vmCvar_t ui_tourney_fraglimit;
7569 vmCvar_t ui_tourney_timelimit;
7570 
7571 vmCvar_t ui_team_fraglimit;
7572 vmCvar_t ui_team_timelimit;
7573 vmCvar_t ui_team_friendly;
7574 
7575 vmCvar_t ui_ctf_capturelimit;
7576 vmCvar_t ui_ctf_timelimit;
7577 vmCvar_t ui_ctf_friendly;
7578 
7579 vmCvar_t ui_arenasFile;
7580 vmCvar_t ui_botsFile;
7581 vmCvar_t ui_spScores1;
7582 vmCvar_t ui_spScores2;
7583 vmCvar_t ui_spScores3;
7584 vmCvar_t ui_spScores4;
7585 vmCvar_t ui_spScores5;
7586 vmCvar_t ui_spAwards;
7587 vmCvar_t ui_spVideos;
7588 vmCvar_t ui_spSkill;
7589 
7590 vmCvar_t ui_spSelection;
7591 vmCvar_t ui_master;
7592 
7593 vmCvar_t ui_brassTime;
7594 vmCvar_t ui_drawCrosshair;
7595 vmCvar_t ui_drawCrosshairNames;
7596 vmCvar_t ui_drawCrosshairPickups;       //----(SA) added
7597 vmCvar_t ui_marks;
7598 // JOSEPH 12-3-99
7599 vmCvar_t ui_autoactivate;
7600 vmCvar_t ui_emptyswitch;        //----(SA)	added
7601 // END JOSEPH
7602 
7603 vmCvar_t ui_server1;
7604 vmCvar_t ui_server2;
7605 vmCvar_t ui_server3;
7606 vmCvar_t ui_server4;
7607 vmCvar_t ui_server5;
7608 vmCvar_t ui_server6;
7609 vmCvar_t ui_server7;
7610 vmCvar_t ui_server8;
7611 vmCvar_t ui_server9;
7612 vmCvar_t ui_server10;
7613 vmCvar_t ui_server11;
7614 vmCvar_t ui_server12;
7615 vmCvar_t ui_server13;
7616 vmCvar_t ui_server14;
7617 vmCvar_t ui_server15;
7618 vmCvar_t ui_server16;
7619 
7620 vmCvar_t ui_cdkeychecked;
7621 vmCvar_t ui_smallFont;
7622 vmCvar_t ui_bigFont;
7623 
7624 vmCvar_t ui_selectedPlayer;
7625 vmCvar_t ui_selectedPlayerName;
7626 vmCvar_t ui_netSource;
7627 vmCvar_t ui_menuFiles;
7628 vmCvar_t ui_gameType;
7629 vmCvar_t ui_netGameType;
7630 vmCvar_t ui_actualNetGameType;
7631 vmCvar_t ui_joinGameType;
7632 vmCvar_t ui_dedicated;
7633 
7634 vmCvar_t ui_notebookCurrentPage;        //----(SA)	added
7635 vmCvar_t ui_clipboardName;          // the name of the group for the current clipboard item //----(SA)	added
7636 vmCvar_t ui_hudAlpha;
7637 
7638 // NERVE - SMF - cvars for multiplayer
7639 vmCvar_t ui_serverFilterType;
7640 vmCvar_t ui_currentNetMap;
7641 vmCvar_t ui_currentMap;
7642 vmCvar_t ui_mapIndex;
7643 
7644 vmCvar_t ui_browserMaster;
7645 vmCvar_t ui_browserGameType;
7646 vmCvar_t ui_browserShowFull;
7647 vmCvar_t ui_browserShowEmpty;
7648 vmCvar_t ui_browserShowFriendlyFire;            // NERVE - SMF
7649 vmCvar_t ui_browserShowMaxlives;                // NERVE - SMF
7650 vmCvar_t ui_browserShowTourney;                 // NERVE - SMF
7651 vmCvar_t ui_browserShowPunkBuster;              // DHM - Nerve
7652 vmCvar_t ui_browserShowAntilag;     // TTimo
7653 
7654 vmCvar_t ui_serverStatusTimeOut;
7655 
7656 vmCvar_t ui_Q3Model;
7657 vmCvar_t ui_headModel;
7658 vmCvar_t ui_model;
7659 
7660 vmCvar_t ui_limboOptions;
7661 vmCvar_t ui_limboPrevOptions;
7662 vmCvar_t ui_limboObjective;
7663 
7664 vmCvar_t ui_cmd;
7665 
7666 vmCvar_t ui_prevTeam;
7667 vmCvar_t ui_prevClass;
7668 vmCvar_t ui_prevWeapon;
7669 
7670 vmCvar_t ui_limboMode;
7671 vmCvar_t ui_objective;
7672 
7673 vmCvar_t ui_team;
7674 vmCvar_t ui_class;
7675 vmCvar_t ui_weapon;
7676 
7677 vmCvar_t ui_isSpectator;
7678 
7679 vmCvar_t ui_friendlyFire;
7680 vmCvar_t ui_allowVote;
7681 
7682 vmCvar_t ui_userTimeLimit;
7683 vmCvar_t ui_userAlliedRespawnTime;
7684 vmCvar_t ui_userAxisRespawnTime;
7685 vmCvar_t ui_glCustom;    // JPW NERVE missing from q3ta
7686 // -NERVE - SMF
7687 
7688 cvarTable_t cvarTable[] = {
7689 
7690 	{ &ui_glCustom, "ui_glCustom", "4", CVAR_ARCHIVE }, // JPW NERVE missing from q3ta
7691 	{ &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
7692 	{ &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
7693 
7694 	{ &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
7695 	{ &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
7696 
7697 	{ &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
7698 	{ &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
7699 	{ &ui_team_friendly, "ui_team_friendly",  "1", CVAR_ARCHIVE },
7700 
7701 	{ &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
7702 	{ &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
7703 	{ &ui_ctf_friendly, "ui_ctf_friendly",  "0", CVAR_ARCHIVE },
7704 
7705 	{ &ui_arenasFile, "g_arenasFile", "", CVAR_INIT | CVAR_ROM },
7706 	{ &ui_botsFile, "g_botsFile", "", CVAR_INIT | CVAR_ROM },
7707 	{ &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE },
7708 	{ &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE },
7709 	{ &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE },
7710 	{ &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE },
7711 	{ &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE },
7712 	{ &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE },
7713 	{ &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE },
7714 	{ &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE | CVAR_LATCH },
7715 
7716 	// NERVE - SMF
7717 	{ &ui_friendlyFire, "g_friendlyFire", "1", CVAR_ARCHIVE },
7718 	{ &ui_allowVote, "g_allowvote", "1", CVAR_ARCHIVE },
7719 
7720 	{ &ui_userTimeLimit, "ui_userTimeLimit", "0", 0 },
7721 	{ &ui_userAlliedRespawnTime, "ui_userAlliedRespawnTime", "0", 0 },
7722 	{ &ui_userAxisRespawnTime, "ui_userAxisRespawnTime", "0", 0 },
7723 	// -NERVE - SMF
7724 
7725 // JPW NERVE
7726 	{ &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE}, // so sound stuff latches, strange as that seems
7727 // jpw
7728 
7729 	{ &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
7730 	{ &ui_master, "ui_master", "0", CVAR_ARCHIVE },
7731 
7732 	{ &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE }, // JPW NERVE
7733 	{ &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
7734 	{ &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
7735 	{ &ui_drawCrosshairPickups, "cg_drawCrosshairPickups", "1", CVAR_ARCHIVE },   //----(SA) added
7736 	{ &ui_marks, "cg_marktime", "20000", CVAR_ARCHIVE },
7737 	// JOSEPH 12-2-99
7738 	{ &ui_autoactivate, "cg_autoactivate", "1", CVAR_ARCHIVE },
7739 	// END JOSEPH
7740 
7741 	{ &ui_fixedAspect, "cg_fixedAspect", "0", CVAR_ARCHIVE | CVAR_LATCH },
7742 	{ &ui_fixedAspectFOV, "cg_fixedAspectFOV", "1", CVAR_ARCHIVE },
7743 
7744 	{ &ui_server1, "server1", "", CVAR_ARCHIVE },
7745 	{ &ui_server2, "server2", "", CVAR_ARCHIVE },
7746 	{ &ui_server3, "server3", "", CVAR_ARCHIVE },
7747 	{ &ui_server4, "server4", "", CVAR_ARCHIVE },
7748 	{ &ui_server5, "server5", "", CVAR_ARCHIVE },
7749 	{ &ui_server6, "server6", "", CVAR_ARCHIVE },
7750 	{ &ui_server7, "server7", "", CVAR_ARCHIVE },
7751 	{ &ui_server8, "server8", "", CVAR_ARCHIVE },
7752 	{ &ui_server9, "server9", "", CVAR_ARCHIVE },
7753 	{ &ui_server10, "server10", "", CVAR_ARCHIVE },
7754 	{ &ui_server11, "server11", "", CVAR_ARCHIVE },
7755 	{ &ui_server12, "server12", "", CVAR_ARCHIVE },
7756 	{ &ui_server13, "server13", "", CVAR_ARCHIVE },
7757 	{ &ui_server14, "server14", "", CVAR_ARCHIVE },
7758 	{ &ui_server15, "server15", "", CVAR_ARCHIVE },
7759 	{ &ui_server16, "server16", "", CVAR_ARCHIVE },
7760 
7761 	{ &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
7762 	{ &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
7763 	{ &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
7764 	{ &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
7765 	{ &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
7766 	{ &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
7767 	{ &ui_netSource, "ui_netSource", "1", CVAR_ARCHIVE },
7768 	{ &ui_menuFiles, "ui_menuFiles", "ui_mp/menus.txt", CVAR_ARCHIVE },
7769 	{ &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
7770 	{ &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
7771 	{ &ui_netGameType, "ui_netGametype", "0", CVAR_ARCHIVE },                 // NERVE - SMF - hardwired for now
7772 	{ &ui_actualNetGameType, "ui_actualNetGametype", "5", CVAR_ARCHIVE },     // NERVE - SMF - hardwired for now
7773 
7774 	{ &ui_notebookCurrentPage, "ui_notebookCurrentPage", "1", CVAR_ROM},
7775 	{ &ui_clipboardName, "cg_clipboardName", "", CVAR_ROM },
7776 
7777 	// NERVE - SMF - multiplayer cvars
7778 	{ &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
7779 	{ &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
7780 	{ &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
7781 
7782 	{ &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
7783 	{ &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
7784 	{ &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
7785 	{ &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
7786 	{ &ui_browserShowFriendlyFire, "ui_browserShowFriendlyFire", "0", CVAR_ARCHIVE },
7787 	{ &ui_browserShowMaxlives, "ui_browserShowMaxlives", "1", CVAR_ARCHIVE },
7788 	{ &ui_browserShowTourney, "ui_browserShowTourney", "1", CVAR_ARCHIVE },
7789 	{ &ui_browserShowPunkBuster, "ui_browserShowPunkBuster", "0", CVAR_ARCHIVE },
7790 	{ &ui_browserShowAntilag, "ui_browserShowAntilag", "0", CVAR_ARCHIVE },
7791 
7792 	{ &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
7793 
7794 	{ &ui_Q3Model, "ui_Q3Model", "1", 0 },
7795 	{ &ui_headModel, "headModel", "", 0 },
7796 
7797 	{ &ui_limboOptions, "ui_limboOptions", "0", 0 },
7798 	{ &ui_limboPrevOptions, "ui_limboPrevOptions", "0", 0 },
7799 	{ &ui_limboObjective, "ui_limboObjective", "0", 0 },
7800 	{ &ui_cmd, "ui_cmd", "", 0 },
7801 
7802 	{ &ui_prevTeam, "ui_prevTeam", "-1", 0 },
7803 	{ &ui_prevClass, "ui_prevClass", "-1", 0 },
7804 	{ &ui_prevWeapon, "ui_prevWeapon", "-1", 0 },
7805 
7806 	{ &ui_limboMode, "ui_limboMode", "0", 0 },
7807 	{ &ui_objective, "ui_objective", "", 0 },
7808 
7809 	{ &ui_team, "ui_team", "Axis", 0 },
7810 	{ &ui_class, "ui_class", "Soldier", 0 },
7811 	{ &ui_weapon, "ui_weapon", "MP 40", 0 },
7812 
7813 	{ &ui_isSpectator, "ui_isSpectator", "1", 0 },
7814 	// -NERVE - SMF
7815 
7816 	{ &ui_hudAlpha, "cg_hudAlpha", "1.0", CVAR_ARCHIVE },
7817 
7818 	{ NULL, "g_localTeamPref", "", 0 },
7819 };
7820 
7821 static int		cvarTableSize = ARRAY_LEN( cvarTable );
7822 
7823 
7824 /*
7825 =================
7826 UI_RegisterCvars
7827 =================
7828 */
UI_RegisterCvars(void)7829 void UI_RegisterCvars( void ) {
7830 	int i;
7831 	cvarTable_t *cv;
7832 
7833 	for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
7834 		trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
7835 	}
7836 }
7837 
7838 /*
7839 =================
7840 UI_UpdateCvars
7841 =================
7842 */
UI_UpdateCvars(void)7843 void UI_UpdateCvars( void ) {
7844 	int i;
7845 	cvarTable_t *cv;
7846 
7847 	for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
7848 		if ( !cv->vmCvar ) {
7849 			continue;
7850 		}
7851 
7852 		trap_Cvar_Update( cv->vmCvar );
7853 	}
7854 }
7855 
7856 // NERVE - SMF
7857 /*
7858 =================
7859 ArenaServers_StopRefresh
7860 =================
7861 */
UI_StopServerRefresh(void)7862 static void UI_StopServerRefresh( void ) {
7863 	int count;
7864 
7865 	if ( !uiInfo.serverStatus.refreshActive ) {
7866 		// not currently refreshing
7867 		return;
7868 	}
7869 	uiInfo.serverStatus.refreshActive = qfalse;
7870 	Com_Printf( "%d servers listed in browser with %d players.\n",
7871 				uiInfo.serverStatus.numDisplayServers,
7872 				uiInfo.serverStatus.numPlayersOnServers );
7873 	count = trap_LAN_GetServerCount(UI_SourceForLAN());
7874 	if ( count - uiInfo.serverStatus.numDisplayServers > 0 ) {
7875 		// TTimo - used to be about cl_maxping filtering, that was Q3 legacy, RTCW browser has much more filtering options
7876 		Com_Printf( "%d servers not listed (filtered out by game browser settings)\n",
7877 					count - uiInfo.serverStatus.numDisplayServers );
7878 	}
7879 
7880 }
7881 
7882 /*
7883 =================
7884 UI_DoServerRefresh
7885 =================
7886 */
UI_DoServerRefresh(void)7887 static void UI_DoServerRefresh( void ) {
7888 	qboolean wait = qfalse;
7889 
7890 	if ( !uiInfo.serverStatus.refreshActive ) {
7891 		return;
7892 	}
7893 	if (ui_netSource.integer != UIAS_FAVORITES) {
7894 		if (ui_netSource.integer == UIAS_LOCAL) {
7895 			if (!trap_LAN_GetServerCount(AS_LOCAL)) {
7896 				wait = qtrue;
7897 			}
7898 		} else {
7899 			if (trap_LAN_GetServerCount(AS_GLOBAL) < 0) {
7900 				wait = qtrue;
7901 			}
7902 		}
7903 	}
7904 
7905 	if ( uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime ) {
7906 		if ( wait ) {
7907 			return;
7908 		}
7909 	}
7910 
7911 	// if still trying to retrieve pings
7912 	if (trap_LAN_UpdateVisiblePings(UI_SourceForLAN())) {
7913 		uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
7914 	} else if ( !wait ) {
7915 		// get the last servers in the list
7916 		UI_BuildServerDisplayList( 2 );
7917 		// stop the refresh
7918 		UI_StopServerRefresh();
7919 	} else if ( ui_netSource.integer == UIAS_LOCAL ) {
7920 		// no local servers found, check again
7921 		trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
7922 		uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
7923 	}
7924 	//
7925 	UI_BuildServerDisplayList( qfalse );
7926 }
7927 
7928 /*
7929 =================
7930 UI_StartServerRefresh
7931 =================
7932 */
UI_StartServerRefresh(qboolean full,qboolean force)7933 static void UI_StartServerRefresh( qboolean full, qboolean force ) {
7934 	char    *ptr;
7935 	int		lanSource;
7936 	qtime_t q;
7937 
7938 	// This function is called with force=qfalse when server browser menu opens or net source changes.
7939 	// Automatically update local and favorite servers.
7940 	// Only auto update master server list if there is no server info cache.
7941 	if ( !force && ( ui_netSource.integer >= UIAS_GLOBAL0 && ui_netSource.integer <= UIAS_GLOBAL5 ) ) {
7942 		if ( trap_LAN_GetServerCount( UI_SourceForLAN() ) > 0 ) {
7943 			return; // have cached list
7944 		}
7945 	}
7946 
7947 	trap_RealTime( &q );
7948 	trap_Cvar_Set( va( "ui_lastServerRefresh_%i", ui_netSource.integer ), va( "%s-%i, %i at %02i:%02i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900 + q.tm_year,q.tm_hour,q.tm_min ) );
7949 
7950 	if ( !full ) {
7951 		UI_UpdatePendingPings();
7952 		return;
7953 	}
7954 
7955 	uiInfo.serverStatus.refreshActive = qtrue;
7956 	uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
7957 	// clear number of displayed servers
7958 	uiInfo.serverStatus.numDisplayServers = 0;
7959 	uiInfo.serverStatus.numPlayersOnServers = 0;
7960 
7961 	lanSource = UI_SourceForLAN();
7962 	// mark all servers as visible so we store ping updates for them
7963 	trap_LAN_MarkServerVisible(lanSource, -1, qtrue);
7964 	// reset all the pings
7965 	trap_LAN_ResetPings(lanSource);
7966 	//
7967 	if ( ui_netSource.integer == UIAS_LOCAL ) {
7968 		trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
7969 		uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
7970 		return;
7971 	}
7972 
7973 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
7974 	if( ui_netSource.integer >= UIAS_GLOBAL0 && ui_netSource.integer <= UIAS_GLOBAL5 ) {
7975 
7976 		ptr = UI_Cvar_VariableString( "debug_protocol" );
7977 		if ( strlen( ptr ) ) {
7978 			trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %s full empty\n", ui_netSource.integer - UIAS_GLOBAL0, ptr ) );
7979 		} else {
7980 			trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %d full empty\n", ui_netSource.integer - UIAS_GLOBAL0, (int)trap_Cvar_VariableValue( "protocol" ) ) );
7981 		}
7982 	}
7983 }
7984 // -NERVE - SMF
7985