1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 //
23 /*
24 =======================================================================
25 
26 USER INTERFACE MAIN
27 
28 =======================================================================
29 */
30 
31 // use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
32 //#define PRE_RELEASE_TADEMO
33 
34 #include "ui_local.h"
35 
36 uiInfo_t uiInfo;
37 
38 static const char *MonthAbbrev[] = {
39 	"Jan","Feb","Mar",
40 	"Apr","May","Jun",
41 	"Jul","Aug","Sep",
42 	"Oct","Nov","Dec"
43 };
44 
45 
46 static const char *skillLevels[] = {
47   "I Can Win",
48   "Bring It On",
49   "Hurt Me Plenty",
50   "Hardcore",
51   "Nightmare"
52 };
53 
54 static const int numSkillLevels = ARRAY_LEN( skillLevels );
55 
56 
57 static const char *netSources[] = {
58 	"Local",
59 	"Mplayer",
60 	"Internet",
61 	"Favorites"
62 };
63 static const int numNetSources = ARRAY_LEN( netSources );
64 
65 static const serverFilter_t serverFilters[] = {
66 	{"All", "" },
67 	{"Quake 3 Arena", "" },
68 	{"Team Arena", BASETA },
69 	{"Rocket Arena", "arena" },
70 	{"Alliance", "alliance20" },
71 	{"Weapons Factory Arena", "wfa" },
72 	{"OSP", "osp" },
73 };
74 
75 static const int numServerFilters = ARRAY_LEN( serverFilters );
76 
77 
78 static const char *teamArenaGameTypes[] = {
79 	"FFA",
80 	"TOURNAMENT",
81 	"SP",
82 	"TEAM DM",
83 	"CTF",
84 	"1FCTF",
85 	"OVERLOAD",
86 	"HARVESTER",
87 	"TEAMTOURNAMENT"
88 };
89 
90 static int const numTeamArenaGameTypes = ARRAY_LEN( teamArenaGameTypes );
91 
92 
93 static char* netnames[] = {
94 	"???",
95 	"UDP",
96 	"UDP6"
97 };
98 
99 #ifndef MISSIONPACK
100 static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
101 #endif
102 
103 static int gamecodetoui[] = {4,2,3,0,5,1,6};
104 static int uitogamecode[] = {4,6,2,3,1,5,7};
105 
106 
107 static void UI_StartServerRefresh(qboolean full);
108 static void UI_StopServerRefresh( void );
109 static void UI_DoServerRefresh( void );
110 static void UI_FeederSelection(float feederID, int index);
111 static void UI_BuildServerDisplayList(qboolean force);
112 static void UI_BuildServerStatus(qboolean force);
113 static void UI_BuildFindPlayerList(qboolean force);
114 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
115 static int UI_MapCountByGameType(qboolean singlePlayer);
116 static int UI_HeadCountByTeam( void );
117 static void UI_ParseGameInfo(const char *teamFile);
118 static void UI_ParseTeamInfo(const char *teamFile);
119 static const char *UI_SelectedMap(int index, int *actual);
120 static const char *UI_SelectedHead(int index, int *actual);
121 static int UI_GetIndexFromSelection(int actual);
122 
123 int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
124 
125 /*
126 ================
127 vmMain
128 
129 This is the only way control passes into the module.
130 This must be the very first function compiled into the .qvm file
131 ================
132 */
133 vmCvar_t  ui_new;
134 vmCvar_t  ui_debug;
135 vmCvar_t  ui_initialized;
136 vmCvar_t  ui_teamArenaFirstRun;
137 
138 void _UI_Init( qboolean );
139 void _UI_Shutdown( void );
140 void _UI_KeyEvent( int key, qboolean down );
141 void _UI_MouseEvent( int dx, int dy );
142 void _UI_Refresh( int realtime );
143 qboolean _UI_IsFullscreen( void );
vmMain(int command,int arg0,int arg1,int arg2,int arg3,int arg4,int arg5,int arg6,int arg7,int arg8,int arg9,int arg10,int arg11)144 Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11  ) {
145   switch ( command ) {
146 	  case UI_GETAPIVERSION:
147 		  return UI_API_VERSION;
148 
149 	  case UI_INIT:
150 		  _UI_Init(arg0);
151 		  return 0;
152 
153 	  case UI_SHUTDOWN:
154 		  _UI_Shutdown();
155 		  return 0;
156 
157 	  case UI_KEY_EVENT:
158 		  _UI_KeyEvent( arg0, arg1 );
159 		  return 0;
160 
161 	  case UI_MOUSE_EVENT:
162 		  _UI_MouseEvent( arg0, arg1 );
163 		  return 0;
164 
165 	  case UI_REFRESH:
166 		  _UI_Refresh( arg0 );
167 		  return 0;
168 
169 	  case UI_IS_FULLSCREEN:
170 		  return _UI_IsFullscreen();
171 
172 	  case UI_SET_ACTIVE_MENU:
173 		  _UI_SetActiveMenu( arg0 );
174 		  return 0;
175 
176 	  case UI_CONSOLE_COMMAND:
177 		  return UI_ConsoleCommand(arg0);
178 
179 	  case UI_DRAW_CONNECT_SCREEN:
180 		  UI_DrawConnectScreen( arg0 );
181 		  return 0;
182 	  case UI_HASUNIQUECDKEY: // mod authors need to observe this
183 	    return qtrue; // change this to qfalse for mods!
184 
185 	}
186 
187 	return -1;
188 }
189 
190 
191 
AssetCache(void)192 void AssetCache( void ) {
193 	int n;
194 	//if (Assets.textFont == NULL) {
195 	//}
196 	//Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
197 	//Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
198 	uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
199 	uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
200 	uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
201 	uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
202 	uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
203 	uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
204 	uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
205 	uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
206 	uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
207 	uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
208 	uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
209 	uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
210 	uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
211 	uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
212 	uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
213 	uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
214 	uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
215 
216 	for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
217 		uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
218 	}
219 
220 	uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
221 }
222 
_UI_DrawSides(float x,float y,float w,float h,float size)223 void _UI_DrawSides(float x, float y, float w, float h, float size) {
224 	UI_AdjustFrom640( &x, &y, &w, &h );
225 	size *= uiInfo.uiDC.xscale;
226 	trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
227 	trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
228 }
229 
_UI_DrawTopBottom(float x,float y,float w,float h,float size)230 void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
231 	UI_AdjustFrom640( &x, &y, &w, &h );
232 	size *= uiInfo.uiDC.yscale;
233 	trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
234 	trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
235 }
236 /*
237 ================
238 UI_DrawRect
239 
240 Coordinates are 640*480 virtual values
241 =================
242 */
_UI_DrawRect(float x,float y,float width,float height,float size,const float * color)243 void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
244 	trap_R_SetColor( color );
245 
246   _UI_DrawTopBottom(x, y, width, height, size);
247   _UI_DrawSides(x, y, width, height, size);
248 
249 	trap_R_SetColor( NULL );
250 }
251 
Text_Width(const char * text,float scale,int limit)252 int Text_Width(const char *text, float scale, int limit) {
253   int count,len;
254 	float out;
255 	glyphInfo_t *glyph;
256 	float useScale;
257 	const char *s = text;
258 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
259 	if (scale <= ui_smallFont.value) {
260 		font = &uiInfo.uiDC.Assets.smallFont;
261 	} else if (scale >= ui_bigFont.value) {
262 		font = &uiInfo.uiDC.Assets.bigFont;
263 	}
264 	useScale = scale * font->glyphScale;
265   out = 0;
266   if (text) {
267     len = strlen(text);
268 		if (limit > 0 && len > limit) {
269 			len = limit;
270 		}
271 		count = 0;
272 		while (s && *s && count < len) {
273 			if ( Q_IsColorString(s) ) {
274 				s += 2;
275 				continue;
276 			} else {
277 				glyph = &font->glyphs[(int)*s];
278 				out += glyph->xSkip;
279 				s++;
280 				count++;
281 			}
282     }
283   }
284   return out * useScale;
285 }
286 
Text_Height(const char * text,float scale,int limit)287 int Text_Height(const char *text, float scale, int limit) {
288   int len, count;
289 	float max;
290 	glyphInfo_t *glyph;
291 	float useScale;
292 	const char *s = text;
293 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
294 	if (scale <= ui_smallFont.value) {
295 		font = &uiInfo.uiDC.Assets.smallFont;
296 	} else if (scale >= ui_bigFont.value) {
297 		font = &uiInfo.uiDC.Assets.bigFont;
298 	}
299 	useScale = scale * font->glyphScale;
300   max = 0;
301   if (text) {
302     len = strlen(text);
303 		if (limit > 0 && len > limit) {
304 			len = limit;
305 		}
306 		count = 0;
307 		while (s && *s && count < len) {
308 			if ( Q_IsColorString(s) ) {
309 				s += 2;
310 				continue;
311 			} else {
312 				glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
313 	      if (max < glyph->height) {
314 		      max = glyph->height;
315 			  }
316 				s++;
317 				count++;
318 			}
319     }
320   }
321   return max * useScale;
322 }
323 
Text_PaintChar(float x,float y,float width,float height,float scale,float s,float t,float s2,float t2,qhandle_t hShader)324 void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
325   float w, h;
326   w = width * scale;
327   h = height * scale;
328   UI_AdjustFrom640( &x, &y, &w, &h );
329   trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
330 }
331 
Text_Paint(float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit,int style)332 void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
333   int len, count;
334 	vec4_t newColor;
335 	glyphInfo_t *glyph;
336 	float useScale;
337 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
338 	if (scale <= ui_smallFont.value) {
339 		font = &uiInfo.uiDC.Assets.smallFont;
340 	} else if (scale >= ui_bigFont.value) {
341 		font = &uiInfo.uiDC.Assets.bigFont;
342 	}
343 	useScale = scale * font->glyphScale;
344   if (text) {
345     const char *s = text;
346 		trap_R_SetColor( color );
347 		memcpy(&newColor[0], &color[0], sizeof(vec4_t));
348     len = strlen(text);
349 		if (limit > 0 && len > limit) {
350 			len = limit;
351 		}
352 		count = 0;
353 		while (s && *s && count < len) {
354 			glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
355       //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
356       //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
357 			if ( Q_IsColorString( s ) ) {
358 				memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
359 				newColor[3] = color[3];
360 				trap_R_SetColor( newColor );
361 				s += 2;
362 				continue;
363 			} else {
364 				float yadj = useScale * glyph->top;
365 				if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
366 					int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
367 					colorBlack[3] = newColor[3];
368 					trap_R_SetColor( colorBlack );
369 					Text_PaintChar(x + ofs, y - yadj + ofs,
370 														glyph->imageWidth,
371 														glyph->imageHeight,
372 														useScale,
373 														glyph->s,
374 														glyph->t,
375 														glyph->s2,
376 														glyph->t2,
377 														glyph->glyph);
378 					trap_R_SetColor( newColor );
379 					colorBlack[3] = 1.0;
380 				}
381 				Text_PaintChar(x, y - yadj,
382 													glyph->imageWidth,
383 													glyph->imageHeight,
384 													useScale,
385 													glyph->s,
386 													glyph->t,
387 													glyph->s2,
388 													glyph->t2,
389 													glyph->glyph);
390 
391 				x += (glyph->xSkip * useScale) + adjust;
392 				s++;
393 				count++;
394 			}
395     }
396 	  trap_R_SetColor( NULL );
397   }
398 }
399 
Text_PaintWithCursor(float x,float y,float scale,vec4_t color,const char * text,int cursorPos,char cursor,int limit,int style)400 void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
401   int len, count;
402 	vec4_t newColor;
403 	glyphInfo_t *glyph, *glyph2;
404 	float yadj;
405 	float useScale;
406 	fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
407 	if (scale <= ui_smallFont.value) {
408 		font = &uiInfo.uiDC.Assets.smallFont;
409 	} else if (scale >= ui_bigFont.value) {
410 		font = &uiInfo.uiDC.Assets.bigFont;
411 	}
412 	useScale = scale * font->glyphScale;
413   if (text) {
414     const char *s = text;
415 		trap_R_SetColor( color );
416 		memcpy(&newColor[0], &color[0], sizeof(vec4_t));
417     len = strlen(text);
418 		if (limit > 0 && len > limit) {
419 			len = limit;
420 		}
421 		count = 0;
422 		glyph2 = &font->glyphs[ (int) cursor];
423 		while (s && *s && count < len) {
424 			glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
425       //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
426       //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
427 			if ( Q_IsColorString( s ) ) {
428 				memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
429 				newColor[3] = color[3];
430 				trap_R_SetColor( newColor );
431 				s += 2;
432 				continue;
433 			} else {
434 				yadj = useScale * glyph->top;
435 				if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
436 					int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
437 					colorBlack[3] = newColor[3];
438 					trap_R_SetColor( colorBlack );
439 					Text_PaintChar(x + ofs, y - yadj + ofs,
440 														glyph->imageWidth,
441 														glyph->imageHeight,
442 														useScale,
443 														glyph->s,
444 														glyph->t,
445 														glyph->s2,
446 														glyph->t2,
447 														glyph->glyph);
448 					colorBlack[3] = 1.0;
449 					trap_R_SetColor( newColor );
450 				}
451 				Text_PaintChar(x, y - yadj,
452 													glyph->imageWidth,
453 													glyph->imageHeight,
454 													useScale,
455 													glyph->s,
456 													glyph->t,
457 													glyph->s2,
458 													glyph->t2,
459 													glyph->glyph);
460 
461 	      yadj = useScale * glyph2->top;
462 		    if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
463 					Text_PaintChar(x, y - yadj,
464 														glyph2->imageWidth,
465 														glyph2->imageHeight,
466 														useScale,
467 														glyph2->s,
468 														glyph2->t,
469 														glyph2->s2,
470 														glyph2->t2,
471 														glyph2->glyph);
472 				}
473 
474 				x += (glyph->xSkip * useScale);
475 				s++;
476 				count++;
477 			}
478     }
479     // need to paint cursor at end of text
480     if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
481         yadj = useScale * glyph2->top;
482         Text_PaintChar(x, y - yadj,
483                           glyph2->imageWidth,
484                           glyph2->imageHeight,
485                           useScale,
486                           glyph2->s,
487                           glyph2->t,
488                           glyph2->s2,
489                           glyph2->t2,
490                           glyph2->glyph);
491 
492     }
493 
494 	  trap_R_SetColor( NULL );
495   }
496 }
497 
498 
Text_Paint_Limit(float * maxX,float x,float y,float scale,vec4_t color,const char * text,float adjust,int limit)499 static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
500   int len, count;
501 	vec4_t newColor;
502 	glyphInfo_t *glyph;
503   if (text) {
504     const char *s = text;
505 		float max = *maxX;
506 		float useScale;
507 		fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
508 		if (scale <= ui_smallFont.value) {
509 			font = &uiInfo.uiDC.Assets.smallFont;
510 		} else if (scale > ui_bigFont.value) {
511 			font = &uiInfo.uiDC.Assets.bigFont;
512 		}
513 		useScale = scale * font->glyphScale;
514 		trap_R_SetColor( color );
515     len = strlen(text);
516 		if (limit > 0 && len > limit) {
517 			len = limit;
518 		}
519 		count = 0;
520 		while (s && *s && count < len) {
521 			glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
522 			if ( Q_IsColorString( s ) ) {
523 				memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
524 				newColor[3] = color[3];
525 				trap_R_SetColor( newColor );
526 				s += 2;
527 				continue;
528 			} else {
529 	      float yadj = useScale * glyph->top;
530 				if (Text_Width(s, useScale, 1) + x > max) {
531 					*maxX = 0;
532 					break;
533 				}
534 		    Text_PaintChar(x, y - yadj,
535 			                 glyph->imageWidth,
536 				               glyph->imageHeight,
537 				               useScale,
538 						           glyph->s,
539 								       glyph->t,
540 								       glyph->s2,
541 									     glyph->t2,
542 										   glyph->glyph);
543 	      x += (glyph->xSkip * useScale) + adjust;
544 				*maxX = x;
545 				count++;
546 				s++;
547 	    }
548 		}
549 	  trap_R_SetColor( NULL );
550   }
551 
552 }
553 
554 
UI_ShowPostGame(qboolean newHigh)555 void UI_ShowPostGame(qboolean newHigh) {
556 	trap_Cvar_Set ("cg_cameraOrbit", "0");
557 	trap_Cvar_Set("cg_thirdPerson", "0");
558 	uiInfo.soundHighScore = newHigh;
559   _UI_SetActiveMenu(UIMENU_POSTGAME);
560 }
561 /*
562 =================
563 _UI_Refresh
564 =================
565 */
566 
UI_DrawCenteredPic(qhandle_t image,int w,int h)567 void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
568   int x, y;
569   x = (SCREEN_WIDTH - w) / 2;
570   y = (SCREEN_HEIGHT - h) / 2;
571   UI_DrawHandlePic(x, y, w, h, image);
572 }
573 
574 int frameCount = 0;
575 int startTime;
576 
577 #define	UI_FPS_FRAMES	4
_UI_Refresh(int realtime)578 void _UI_Refresh( int realtime )
579 {
580 	static int index;
581 	static int	previousTimes[UI_FPS_FRAMES];
582 
583 	//if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
584 	//	return;
585 	//}
586 
587 	uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
588 	uiInfo.uiDC.realTime = realtime;
589 
590 	previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
591 	index++;
592 	if ( index > UI_FPS_FRAMES ) {
593 		int i, total;
594 		// average multiple frames together to smooth changes out a bit
595 		total = 0;
596 		for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
597 			total += previousTimes[i];
598 		}
599 		if ( !total ) {
600 			total = 1;
601 		}
602 		uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
603 	}
604 
605 
606 
607 	UI_UpdateCvars();
608 
609 	if (Menu_Count() > 0) {
610 		// paint all the menus
611 		Menu_PaintAll();
612 		// refresh server browser list
613 		UI_DoServerRefresh();
614 		// refresh server status
615 		UI_BuildServerStatus(qfalse);
616 		// refresh find player list
617 		UI_BuildFindPlayerList(qfalse);
618 	}
619 
620 	// draw cursor
621 	UI_SetColor( NULL );
622 	if (Menu_Count() > 0) {
623 		UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
624 	}
625 
626 #ifndef NDEBUG
627 	if (uiInfo.uiDC.debug)
628 	{
629 		// cursor coordinates
630 		//FIXME
631 		//UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
632 	}
633 #endif
634 
635 }
636 
637 /*
638 =================
639 _UI_Shutdown
640 =================
641 */
_UI_Shutdown(void)642 void _UI_Shutdown( void ) {
643 	trap_LAN_SaveCachedServers();
644 }
645 
646 char *defaultMenu = NULL;
647 
GetMenuBuffer(const char * filename)648 char *GetMenuBuffer(const char *filename) {
649 	int	len;
650 	fileHandle_t	f;
651 	static char buf[MAX_MENUFILE];
652 
653 	len = trap_FS_FOpenFile( filename, &f, FS_READ );
654 	if ( !f ) {
655 		trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
656 		return defaultMenu;
657 	}
658 	if ( len >= MAX_MENUFILE ) {
659 		trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
660 		trap_FS_FCloseFile( f );
661 		return defaultMenu;
662 	}
663 
664 	trap_FS_Read( buf, len, f );
665 	buf[len] = 0;
666 	trap_FS_FCloseFile( f );
667 	//COM_Compress(buf);
668   return buf;
669 
670 }
671 
Asset_Parse(int handle)672 qboolean Asset_Parse(int handle) {
673 	pc_token_t token;
674 	const char *tempStr;
675 
676 	if (!trap_PC_ReadToken(handle, &token))
677 		return qfalse;
678 	if (Q_stricmp(token.string, "{") != 0) {
679 		return qfalse;
680 	}
681 
682 	while ( 1 ) {
683 
684 		memset(&token, 0, sizeof(pc_token_t));
685 
686 		if (!trap_PC_ReadToken(handle, &token))
687 			return qfalse;
688 
689 		if (Q_stricmp(token.string, "}") == 0) {
690 			return qtrue;
691 		}
692 
693 		// font
694 		if (Q_stricmp(token.string, "font") == 0) {
695 			int pointSize;
696 			if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
697 				return qfalse;
698 			}
699 			trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
700 			uiInfo.uiDC.Assets.fontRegistered = qtrue;
701 			continue;
702 		}
703 
704 		if (Q_stricmp(token.string, "smallFont") == 0) {
705 			int pointSize;
706 			if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
707 				return qfalse;
708 			}
709 			trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
710 			continue;
711 		}
712 
713 		if (Q_stricmp(token.string, "bigFont") == 0) {
714 			int pointSize;
715 			if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
716 				return qfalse;
717 			}
718 			trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
719 			continue;
720 		}
721 
722 
723 		// gradientbar
724 		if (Q_stricmp(token.string, "gradientbar") == 0) {
725 			if (!PC_String_Parse(handle, &tempStr)) {
726 				return qfalse;
727 			}
728 			uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
729 			continue;
730 		}
731 
732 		// enterMenuSound
733 		if (Q_stricmp(token.string, "menuEnterSound") == 0) {
734 			if (!PC_String_Parse(handle, &tempStr)) {
735 				return qfalse;
736 			}
737 			uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
738 			continue;
739 		}
740 
741 		// exitMenuSound
742 		if (Q_stricmp(token.string, "menuExitSound") == 0) {
743 			if (!PC_String_Parse(handle, &tempStr)) {
744 				return qfalse;
745 			}
746 			uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
747 			continue;
748 		}
749 
750 		// itemFocusSound
751 		if (Q_stricmp(token.string, "itemFocusSound") == 0) {
752 			if (!PC_String_Parse(handle, &tempStr)) {
753 				return qfalse;
754 			}
755 			uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
756 			continue;
757 		}
758 
759 		// menuBuzzSound
760 		if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
761 			if (!PC_String_Parse(handle, &tempStr)) {
762 				return qfalse;
763 			}
764 			uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
765 			continue;
766 		}
767 
768 		if (Q_stricmp(token.string, "cursor") == 0) {
769 			if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
770 				return qfalse;
771 			}
772 			uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
773 			continue;
774 		}
775 
776 		if (Q_stricmp(token.string, "fadeClamp") == 0) {
777 			if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
778 				return qfalse;
779 			}
780 			continue;
781 		}
782 
783 		if (Q_stricmp(token.string, "fadeCycle") == 0) {
784 			if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
785 				return qfalse;
786 			}
787 			continue;
788 		}
789 
790 		if (Q_stricmp(token.string, "fadeAmount") == 0) {
791 			if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
792 				return qfalse;
793 			}
794 			continue;
795 		}
796 
797 		if (Q_stricmp(token.string, "shadowX") == 0) {
798 			if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
799 				return qfalse;
800 			}
801 			continue;
802 		}
803 
804 		if (Q_stricmp(token.string, "shadowY") == 0) {
805 			if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
806 				return qfalse;
807 			}
808 			continue;
809 		}
810 
811 		if (Q_stricmp(token.string, "shadowColor") == 0) {
812 			if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
813 				return qfalse;
814 			}
815 			uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
816 			continue;
817 		}
818 
819 	}
820 	return qfalse;
821 }
822 
Font_Report(void)823 void Font_Report( void ) {
824   int i;
825   Com_Printf("Font Info\n");
826   Com_Printf("=========\n");
827   for ( i = 32; i < 96; i++) {
828     Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
829   }
830 }
831 
UI_Report(void)832 void UI_Report( void ) {
833   String_Report();
834   //Font_Report();
835 
836 }
837 
UI_ParseMenu(const char * menuFile)838 void UI_ParseMenu(const char *menuFile) {
839 	int handle;
840 	pc_token_t token;
841 
842 	Com_Printf("Parsing menu file:%s\n", menuFile);
843 
844 	handle = trap_PC_LoadSource(menuFile);
845 	if (!handle) {
846 		return;
847 	}
848 
849 	while ( 1 ) {
850 		memset(&token, 0, sizeof(pc_token_t));
851 		if (!trap_PC_ReadToken( handle, &token )) {
852 			break;
853 		}
854 
855 		//if ( Q_stricmp( token, "{" ) ) {
856 		//	Com_Printf( "Missing { in menu file\n" );
857 		//	break;
858 		//}
859 
860 		//if ( menuCount == MAX_MENUS ) {
861 		//	Com_Printf( "Too many menus!\n" );
862 		//	break;
863 		//}
864 
865 		if ( token.string[0] == '}' ) {
866 			break;
867 		}
868 
869 		if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
870 			if (Asset_Parse(handle)) {
871 				continue;
872 			} else {
873 				break;
874 			}
875 		}
876 
877 		if (Q_stricmp(token.string, "menudef") == 0) {
878 			// start a new menu
879 			Menu_New(handle);
880 		}
881 	}
882 	trap_PC_FreeSource(handle);
883 }
884 
Load_Menu(int handle)885 qboolean Load_Menu(int handle) {
886 	pc_token_t token;
887 
888 	if (!trap_PC_ReadToken(handle, &token))
889 		return qfalse;
890 	if (token.string[0] != '{') {
891 		return qfalse;
892 	}
893 
894 	while ( 1 ) {
895 
896 		if (!trap_PC_ReadToken(handle, &token))
897 			return qfalse;
898 
899 		if ( token.string[0] == 0 ) {
900 			return qfalse;
901 		}
902 
903 		if ( token.string[0] == '}' ) {
904 			return qtrue;
905 		}
906 
907 		UI_ParseMenu(token.string);
908 	}
909 	return qfalse;
910 }
911 
UI_LoadMenus(const char * menuFile,qboolean reset)912 void UI_LoadMenus(const char *menuFile, qboolean reset) {
913 	pc_token_t token;
914 	int handle;
915 	int start;
916 
917 	start = trap_Milliseconds();
918 
919 	handle = trap_PC_LoadSource( menuFile );
920 	if (!handle) {
921 		Com_Printf( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile );
922 		handle = trap_PC_LoadSource( "ui/menus.txt" );
923 		if (!handle) {
924 			trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n") );
925 		}
926 	}
927 
928 	ui_new.integer = 1;
929 
930 	if (reset) {
931 		Menu_Reset();
932 	}
933 
934 	while ( 1 ) {
935 		if (!trap_PC_ReadToken(handle, &token))
936 			break;
937 		if( token.string[0] == 0 || token.string[0] == '}') {
938 			break;
939 		}
940 
941 		if ( token.string[0] == '}' ) {
942 			break;
943 		}
944 
945 		if (Q_stricmp(token.string, "loadmenu") == 0) {
946 			if (Load_Menu(handle)) {
947 				continue;
948 			} else {
949 				break;
950 			}
951 		}
952 	}
953 
954 	Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
955 
956 	trap_PC_FreeSource( handle );
957 }
958 
UI_Load(void)959 void UI_Load(void) {
960 	char lastName[1024];
961   menuDef_t *menu = Menu_GetFocused();
962 	char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
963 	if (menu && menu->window.name) {
964 		strcpy(lastName, menu->window.name);
965 	}
966 	if (menuSet == NULL || menuSet[0] == '\0') {
967 		menuSet = "ui/menus.txt";
968 	}
969 
970 	String_Init();
971 
972 #ifdef PRE_RELEASE_TADEMO
973 	UI_ParseGameInfo("demogameinfo.txt");
974 #else
975 	UI_ParseGameInfo("gameinfo.txt");
976 	UI_LoadArenas();
977 #endif
978 
979 	UI_LoadMenus(menuSet, qtrue);
980 	Menus_CloseAll();
981 	Menus_ActivateByName(lastName);
982 
983 }
984 
985 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};
986 #ifndef MISSIONPACK
987 static int numHandicaps = ARRAY_LEN(handicapValues);
988 #endif
989 
UI_DrawHandicap(rectDef_t * rect,float scale,vec4_t color,int textStyle)990 static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
991   int i, h;
992 
993   h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
994   i = 20 - h / 5;
995 
996   Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
997 }
998 
UI_DrawClanName(rectDef_t * rect,float scale,vec4_t color,int textStyle)999 static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1000   Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
1001 }
1002 
1003 
UI_SetCapFragLimits(qboolean uiVars)1004 static void UI_SetCapFragLimits(qboolean uiVars) {
1005 	int cap = 5;
1006 	int frag = 10;
1007 	if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
1008 		cap = 4;
1009 	} else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
1010 		cap = 15;
1011 	}
1012 	if (uiVars) {
1013 		trap_Cvar_Set("ui_captureLimit", va("%d", cap));
1014 		trap_Cvar_Set("ui_fragLimit", va("%d", frag));
1015 	} else {
1016 		trap_Cvar_Set("capturelimit", va("%d", cap));
1017 		trap_Cvar_Set("fraglimit", va("%d", frag));
1018 	}
1019 }
1020 // ui_gameType assumes gametype 0 is -1 ALL and will not show
UI_DrawGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1021 static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1022   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
1023 }
1024 
UI_DrawNetGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1025 static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1026 	if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
1027 		trap_Cvar_Set("ui_netGameType", "0");
1028 		trap_Cvar_Set("ui_actualNetGameType", "0");
1029 	}
1030   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
1031 }
1032 
UI_DrawJoinGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1033 static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1034 	if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
1035 		trap_Cvar_Set("ui_joinGameType", "0");
1036 	}
1037   Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
1038 }
1039 
1040 
1041 
UI_TeamIndexFromName(const char * name)1042 static int UI_TeamIndexFromName(const char *name) {
1043   int i;
1044 
1045   if (name && *name) {
1046     for (i = 0; i < uiInfo.teamCount; i++) {
1047       if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
1048         return i;
1049       }
1050     }
1051   }
1052 
1053   return 0;
1054 
1055 }
1056 
UI_DrawClanLogo(rectDef_t * rect,float scale,vec4_t color)1057 static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
1058   int i;
1059   i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1060   if (i >= 0 && i < uiInfo.teamCount) {
1061   	trap_R_SetColor( color );
1062 
1063 		if (uiInfo.teamList[i].teamIcon == -1) {
1064       uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1065       uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1066       uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1067 		}
1068 
1069   	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
1070     trap_R_SetColor(NULL);
1071   }
1072 }
1073 
UI_DrawClanCinematic(rectDef_t * rect,float scale,vec4_t color)1074 static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
1075   int i;
1076   i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1077   if (i >= 0 && i < uiInfo.teamCount) {
1078 
1079 		if (uiInfo.teamList[i].cinematic >= -2) {
1080 			if (uiInfo.teamList[i].cinematic == -1) {
1081 				uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1082 			}
1083 			if (uiInfo.teamList[i].cinematic >= 0) {
1084 			  trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
1085 				trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
1086 	 			trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
1087 			} else {
1088 			  	trap_R_SetColor( color );
1089 				UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
1090 				trap_R_SetColor(NULL);
1091 				uiInfo.teamList[i].cinematic = -2;
1092 			}
1093 		} else {
1094 	  	trap_R_SetColor( color );
1095 			UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
1096 			trap_R_SetColor(NULL);
1097 		}
1098 	}
1099 
1100 }
1101 
UI_DrawPreviewCinematic(rectDef_t * rect,float scale,vec4_t color)1102 static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
1103 	if (uiInfo.previewMovie > -2) {
1104 		uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1105 		if (uiInfo.previewMovie >= 0) {
1106 		  trap_CIN_RunCinematic(uiInfo.previewMovie);
1107 			trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
1108  			trap_CIN_DrawCinematic(uiInfo.previewMovie);
1109 		} else {
1110 			uiInfo.previewMovie = -2;
1111 		}
1112 	}
1113 
1114 }
1115 
1116 
1117 
UI_DrawSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)1118 static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1119   int i;
1120 	i = trap_Cvar_VariableValue( "g_spSkill" );
1121   if (i < 1 || i > numSkillLevels) {
1122     i = 1;
1123   }
1124   Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
1125 }
1126 
1127 
UI_DrawTeamName(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int textStyle)1128 static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
1129   int i;
1130   i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
1131   if (i >= 0 && i < uiInfo.teamCount) {
1132     Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
1133   }
1134 }
1135 
UI_DrawTeamMember(rectDef_t * rect,float scale,vec4_t color,qboolean blue,int num,int textStyle)1136 static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
1137 	// 0 - None
1138 	// 1 - Human
1139 	// 2..NumCharacters - Bot
1140 	int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
1141 	const char *text;
1142 	if (value <= 0) {
1143 		text = "Closed";
1144 	} else if (value == 1) {
1145 		text = "Human";
1146 	} else {
1147 		value -= 2;
1148 
1149 		if (ui_actualNetGameType.integer >= GT_TEAM) {
1150 			if (value >= uiInfo.characterCount) {
1151 				value = 0;
1152 			}
1153 			text = uiInfo.characterList[value].name;
1154 		} else {
1155 			if (value >= UI_GetNumBots()) {
1156 				value = 0;
1157 			}
1158 			text = UI_GetBotNameByNumber(value);
1159 		}
1160 	}
1161   Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
1162 }
1163 
UI_DrawEffects(rectDef_t * rect,float scale,vec4_t color)1164 static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
1165 	UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
1166 	UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
1167 }
1168 
UI_DrawMapPreview(rectDef_t * rect,float scale,vec4_t color,qboolean net)1169 static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
1170 	int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1171 	if (map < 0 || map > uiInfo.mapCount) {
1172 		if (net) {
1173 			ui_currentNetMap.integer = 0;
1174 			trap_Cvar_Set("ui_currentNetMap", "0");
1175 		} else {
1176 			ui_currentMap.integer = 0;
1177 			trap_Cvar_Set("ui_currentMap", "0");
1178 		}
1179 		map = 0;
1180 	}
1181 
1182 	if (uiInfo.mapList[map].levelShot == -1) {
1183 		uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
1184 	}
1185 
1186 	if (uiInfo.mapList[map].levelShot > 0) {
1187 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
1188 	} else {
1189 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
1190 	}
1191 }
1192 
1193 
UI_DrawMapTimeToBeat(rectDef_t * rect,float scale,vec4_t color,int textStyle)1194 static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1195 	int minutes, seconds, time;
1196 	if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
1197 		ui_currentMap.integer = 0;
1198 		trap_Cvar_Set("ui_currentMap", "0");
1199 	}
1200 
1201 	time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
1202 
1203 	minutes = time / 60;
1204 	seconds = time % 60;
1205 
1206   Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
1207 }
1208 
1209 
1210 
UI_DrawMapCinematic(rectDef_t * rect,float scale,vec4_t color,qboolean net)1211 static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
1212 
1213 	int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1214 	if (map < 0 || map > uiInfo.mapCount) {
1215 		if (net) {
1216 			ui_currentNetMap.integer = 0;
1217 			trap_Cvar_Set("ui_currentNetMap", "0");
1218 		} else {
1219 			ui_currentMap.integer = 0;
1220 			trap_Cvar_Set("ui_currentMap", "0");
1221 		}
1222 		map = 0;
1223 	}
1224 
1225 	if (uiInfo.mapList[map].cinematic >= -1) {
1226 		if (uiInfo.mapList[map].cinematic == -1) {
1227 			uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
1228 		}
1229 		if (uiInfo.mapList[map].cinematic >= 0) {
1230 		  trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
1231 		  trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
1232  			trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
1233 		} else {
1234 			uiInfo.mapList[map].cinematic = -2;
1235 		}
1236 	} else {
1237 		UI_DrawMapPreview(rect, scale, color, net);
1238 	}
1239 }
1240 
1241 
1242 
1243 static qboolean updateModel = qtrue;
1244 static qboolean q3Model = qfalse;
1245 
UI_DrawPlayerModel(rectDef_t * rect)1246 static void UI_DrawPlayerModel(rectDef_t *rect) {
1247   static playerInfo_t info;
1248   char model[MAX_QPATH];
1249   char team[256];
1250 	char head[256];
1251 	vec3_t	viewangles;
1252 	vec3_t	moveangles;
1253 
1254 	  if (trap_Cvar_VariableValue("ui_Q3Model")) {
1255 	  strcpy(model, UI_Cvar_VariableString("model"));
1256 		strcpy(head, UI_Cvar_VariableString("headmodel"));
1257 		if (!q3Model) {
1258 			q3Model = qtrue;
1259 			updateModel = qtrue;
1260 		}
1261 		team[0] = '\0';
1262 	} else {
1263 
1264 		strcpy(team, UI_Cvar_VariableString("ui_teamName"));
1265 		strcpy(model, UI_Cvar_VariableString("team_model"));
1266 		strcpy(head, UI_Cvar_VariableString("team_headmodel"));
1267 		if (q3Model) {
1268 			q3Model = qfalse;
1269 			updateModel = qtrue;
1270 		}
1271 	}
1272   if (updateModel) {
1273   	memset( &info, 0, sizeof(playerInfo_t) );
1274   	viewangles[YAW]   = 180 - 10;
1275   	viewangles[PITCH] = 0;
1276   	viewangles[ROLL]  = 0;
1277   	VectorClear( moveangles );
1278     UI_PlayerInfo_SetModel( &info, model, head, team);
1279     UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
1280 //		UI_RegisterClientModelname( &info, model, head, team);
1281     updateModel = qfalse;
1282   }
1283 
1284   UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
1285 
1286 }
1287 
UI_DrawNetSource(rectDef_t * rect,float scale,vec4_t color,int textStyle)1288 static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1289 	if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
1290 		ui_netSource.integer = 0;
1291 	}
1292   Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
1293 }
1294 
UI_DrawNetMapPreview(rectDef_t * rect,float scale,vec4_t color)1295 static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
1296 
1297 	if (uiInfo.serverStatus.currentServerPreview > 0) {
1298 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
1299 	} else {
1300 		UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
1301 	}
1302 }
1303 
UI_DrawNetMapCinematic(rectDef_t * rect,float scale,vec4_t color)1304 static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
1305 	if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
1306 		ui_currentNetMap.integer = 0;
1307 		trap_Cvar_Set("ui_currentNetMap", "0");
1308 	}
1309 
1310 	if (uiInfo.serverStatus.currentServerCinematic >= 0) {
1311 	  trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
1312 	  trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
1313  	  trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
1314 	} else {
1315 		UI_DrawNetMapPreview(rect, scale, color);
1316 	}
1317 }
1318 
1319 
1320 
UI_DrawNetFilter(rectDef_t * rect,float scale,vec4_t color,int textStyle)1321 static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1322 	if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
1323 		ui_serverFilterType.integer = 0;
1324 	}
1325   Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
1326 }
1327 
1328 
UI_DrawTier(rectDef_t * rect,float scale,vec4_t color,int textStyle)1329 static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1330   int i;
1331 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1332   if (i < 0 || i >= uiInfo.tierCount) {
1333     i = 0;
1334   }
1335   Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
1336 }
1337 
UI_DrawTierMap(rectDef_t * rect,int index)1338 static void UI_DrawTierMap(rectDef_t *rect, int index) {
1339   int i;
1340 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1341   if (i < 0 || i >= uiInfo.tierCount) {
1342     i = 0;
1343   }
1344 
1345 	if (uiInfo.tierList[i].mapHandles[index] == -1) {
1346 		uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
1347 	}
1348 
1349 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
1350 }
1351 
UI_EnglishMapName(const char * map)1352 static const char *UI_EnglishMapName(const char *map) {
1353 	int i;
1354 	for (i = 0; i < uiInfo.mapCount; i++) {
1355 		if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
1356 			return uiInfo.mapList[i].mapName;
1357 		}
1358 	}
1359 	return "";
1360 }
1361 
UI_DrawTierMapName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1362 static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1363   int i, j;
1364 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1365   if (i < 0 || i >= uiInfo.tierCount) {
1366     i = 0;
1367   }
1368 	j = trap_Cvar_VariableValue("ui_currentMap");
1369 	if (j < 0 || j > MAPS_PER_TIER) {
1370 		j = 0;
1371 	}
1372 
1373   Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
1374 }
1375 
UI_DrawTierGameType(rectDef_t * rect,float scale,vec4_t color,int textStyle)1376 static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1377   int i, j;
1378 	i = trap_Cvar_VariableValue( "ui_currentTier" );
1379   if (i < 0 || i >= uiInfo.tierCount) {
1380     i = 0;
1381   }
1382 	j = trap_Cvar_VariableValue("ui_currentMap");
1383 	if (j < 0 || j > MAPS_PER_TIER) {
1384 		j = 0;
1385 	}
1386 
1387   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
1388 }
1389 
1390 
1391 #ifndef MISSIONPACK
UI_OpponentLeaderName(void)1392 static const char *UI_OpponentLeaderName(void) {
1393   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1394 	return uiInfo.teamList[i].teamMembers[0];
1395 }
1396 #endif
1397 
UI_AIFromName(const char * name)1398 static const char *UI_AIFromName(const char *name) {
1399 	int j;
1400 	for (j = 0; j < uiInfo.aliasCount; j++) {
1401 		if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
1402 			return uiInfo.aliasList[j].ai;
1403 		}
1404 	}
1405 	return "James";
1406 }
1407 
1408 #ifndef MISSIONPACK
UI_AIIndex(const char * name)1409 static const int UI_AIIndex(const char *name) {
1410 	int j;
1411 	for (j = 0; j < uiInfo.characterCount; j++) {
1412 		if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
1413 			return j;
1414 		}
1415 	}
1416 	return 0;
1417 }
1418 #endif
1419 
1420 #ifndef MISSIONPACK
UI_AIIndexFromName(const char * name)1421 static const int UI_AIIndexFromName(const char *name) {
1422 	int j;
1423 	for (j = 0; j < uiInfo.aliasCount; j++) {
1424 		if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
1425 			return UI_AIIndex(uiInfo.aliasList[j].ai);
1426 		}
1427 	}
1428 	return 0;
1429 }
1430 #endif
1431 
1432 
1433 #ifndef MISSIONPACK
UI_OpponentLeaderHead(void)1434 static const char *UI_OpponentLeaderHead(void) {
1435 	const char *leader = UI_OpponentLeaderName();
1436 	return UI_AIFromName(leader);
1437 }
1438 #endif
1439 
1440 #ifndef MISSIONPACK
UI_OpponentLeaderModel(void)1441 static const char *UI_OpponentLeaderModel(void) {
1442 	int i;
1443 	const char *head = UI_OpponentLeaderHead();
1444 	for (i = 0; i < uiInfo.characterCount; i++) {
1445 		if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
1446 			return uiInfo.characterList[i].base;
1447 		}
1448 	}
1449 	return "James";
1450 }
1451 #endif
1452 
1453 
1454 static qboolean updateOpponentModel = qtrue;
UI_DrawOpponent(rectDef_t * rect)1455 static void UI_DrawOpponent(rectDef_t *rect) {
1456   static playerInfo_t info2;
1457   char model[MAX_QPATH];
1458   char headmodel[MAX_QPATH];
1459   char team[256];
1460 	vec3_t	viewangles;
1461 	vec3_t	moveangles;
1462 
1463 	if (updateOpponentModel) {
1464 
1465 		strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
1466 	  strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
1467 		team[0] = '\0';
1468 
1469   	memset( &info2, 0, sizeof(playerInfo_t) );
1470   	viewangles[YAW]   = 180 - 10;
1471   	viewangles[PITCH] = 0;
1472   	viewangles[ROLL]  = 0;
1473   	VectorClear( moveangles );
1474     UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
1475     UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
1476 		UI_RegisterClientModelname( &info2, model, headmodel, team);
1477     updateOpponentModel = qfalse;
1478   }
1479 
1480   UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
1481 
1482 }
1483 
UI_NextOpponent(void)1484 static void UI_NextOpponent( void ) {
1485   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1486   int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1487 	i++;
1488 	if (i >= uiInfo.teamCount) {
1489 		i = 0;
1490 	}
1491 	if (i == j) {
1492 		i++;
1493 		if ( i >= uiInfo.teamCount) {
1494 			i = 0;
1495 		}
1496 	}
1497  	trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
1498 }
1499 
UI_PriorOpponent(void)1500 static void UI_PriorOpponent( void ) {
1501   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1502   int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1503 	i--;
1504 	if (i < 0) {
1505 		i = uiInfo.teamCount - 1;
1506 	}
1507 	if (i == j) {
1508 		i--;
1509 		if ( i < 0) {
1510 			i = uiInfo.teamCount - 1;
1511 		}
1512 	}
1513  	trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
1514 }
1515 
UI_DrawPlayerLogo(rectDef_t * rect,vec3_t color)1516 static void	UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
1517   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1518 
1519 	if (uiInfo.teamList[i].teamIcon == -1) {
1520     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1521     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1522     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1523 	}
1524 
1525  	trap_R_SetColor( color );
1526 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1527  	trap_R_SetColor( NULL );
1528 }
1529 
UI_DrawPlayerLogoMetal(rectDef_t * rect,vec3_t color)1530 static void	UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
1531   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1532 	if (uiInfo.teamList[i].teamIcon == -1) {
1533     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1534     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1535     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1536 	}
1537 
1538  	trap_R_SetColor( color );
1539 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
1540  	trap_R_SetColor( NULL );
1541 }
1542 
UI_DrawPlayerLogoName(rectDef_t * rect,vec3_t color)1543 static void	UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
1544   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
1545 	if (uiInfo.teamList[i].teamIcon == -1) {
1546     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1547     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1548     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1549 	}
1550 
1551  	trap_R_SetColor( color );
1552 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
1553  	trap_R_SetColor( NULL );
1554 }
1555 
UI_DrawOpponentLogo(rectDef_t * rect,vec3_t color)1556 static void	UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
1557   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1558 	if (uiInfo.teamList[i].teamIcon == -1) {
1559     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1560     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1561     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1562 	}
1563 
1564  	trap_R_SetColor( color );
1565 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
1566  	trap_R_SetColor( NULL );
1567 }
1568 
UI_DrawOpponentLogoMetal(rectDef_t * rect,vec3_t color)1569 static void	UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
1570   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1571 	if (uiInfo.teamList[i].teamIcon == -1) {
1572     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1573     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1574     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1575 	}
1576 
1577  	trap_R_SetColor( color );
1578 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
1579  	trap_R_SetColor( NULL );
1580 }
1581 
UI_DrawOpponentLogoName(rectDef_t * rect,vec3_t color)1582 static void	UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
1583   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
1584 	if (uiInfo.teamList[i].teamIcon == -1) {
1585     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
1586     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
1587     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
1588 	}
1589 
1590  	trap_R_SetColor( color );
1591 	UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
1592  	trap_R_SetColor( NULL );
1593 }
1594 
UI_DrawAllMapsSelection(rectDef_t * rect,float scale,vec4_t color,int textStyle,qboolean net)1595 static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
1596 	int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
1597 	if (map >= 0 && map < uiInfo.mapCount) {
1598 	  Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
1599 	}
1600 }
1601 
UI_DrawOpponentName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1602 static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1603   Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
1604 }
1605 
1606 
UI_OwnerDrawWidth(int ownerDraw,float scale)1607 static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
1608 	int i, h, value;
1609 	const char *text;
1610 	const char *s = NULL;
1611 
1612   switch (ownerDraw) {
1613     case UI_HANDICAP:
1614 			  h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
1615 				i = 20 - h / 5;
1616 				s = handicapValues[i];
1617       break;
1618     case UI_CLANNAME:
1619 				s = UI_Cvar_VariableString("ui_teamName");
1620       break;
1621     case UI_GAMETYPE:
1622 				s = uiInfo.gameTypes[ui_gameType.integer].gameType;
1623       break;
1624     case UI_SKILL:
1625 				i = trap_Cvar_VariableValue( "g_spSkill" );
1626 				if (i < 1 || i > numSkillLevels) {
1627 					i = 1;
1628 				}
1629 			  s = skillLevels[i-1];
1630       break;
1631     case UI_BLUETEAMNAME:
1632 			  i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
1633 			  if (i >= 0 && i < uiInfo.teamCount) {
1634 			    s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
1635 			  }
1636       break;
1637     case UI_REDTEAMNAME:
1638 			  i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
1639 			  if (i >= 0 && i < uiInfo.teamCount) {
1640 			    s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
1641 			  }
1642       break;
1643     case UI_BLUETEAM1:
1644 		case UI_BLUETEAM2:
1645 		case UI_BLUETEAM3:
1646 		case UI_BLUETEAM4:
1647 		case UI_BLUETEAM5:
1648 			value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
1649 			if (value <= 0) {
1650 				text = "Closed";
1651 			} else if (value == 1) {
1652 				text = "Human";
1653 			} else {
1654 				value -= 2;
1655 				if (value >= uiInfo.aliasCount) {
1656 					value = 0;
1657 				}
1658 				text = uiInfo.aliasList[value].name;
1659 			}
1660 			s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
1661       break;
1662     case UI_REDTEAM1:
1663 		case UI_REDTEAM2:
1664 		case UI_REDTEAM3:
1665 		case UI_REDTEAM4:
1666 		case UI_REDTEAM5:
1667 			value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
1668 			if (value <= 0) {
1669 				text = "Closed";
1670 			} else if (value == 1) {
1671 				text = "Human";
1672 			} else {
1673 				value -= 2;
1674 				if (value >= uiInfo.aliasCount) {
1675 					value = 0;
1676 				}
1677 				text = uiInfo.aliasList[value].name;
1678 			}
1679 			s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
1680       break;
1681 		case UI_NETSOURCE:
1682 			if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
1683 				ui_netSource.integer = 0;
1684 			}
1685 			s = va("Source: %s", netSources[ui_netSource.integer]);
1686 			break;
1687 		case UI_NETFILTER:
1688 			if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
1689 				ui_serverFilterType.integer = 0;
1690 			}
1691 			s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
1692 			break;
1693 		case UI_TIER:
1694 			break;
1695 		case UI_TIER_MAPNAME:
1696 			break;
1697 		case UI_TIER_GAMETYPE:
1698 			break;
1699 		case UI_ALLMAPS_SELECTION:
1700 			break;
1701 		case UI_OPPONENT_NAME:
1702 			break;
1703 		case UI_KEYBINDSTATUS:
1704 			if (Display_KeyBindPending()) {
1705 				s = "Waiting for new key... Press ESCAPE to cancel";
1706 			} else {
1707 				s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
1708 			}
1709 			break;
1710 		case UI_SERVERREFRESHDATE:
1711 			s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
1712 			break;
1713     default:
1714       break;
1715   }
1716 
1717 	if (s) {
1718 		return Text_Width(s, scale, 0);
1719 	}
1720 	return 0;
1721 }
1722 
UI_DrawBotName(rectDef_t * rect,float scale,vec4_t color,int textStyle)1723 static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1724 	int value = uiInfo.botIndex;
1725 	int game = trap_Cvar_VariableValue("g_gametype");
1726 	const char *text = "";
1727 	if (game >= GT_TEAM) {
1728 		if (value >= uiInfo.characterCount) {
1729 			value = 0;
1730 		}
1731 		text = uiInfo.characterList[value].name;
1732 	} else {
1733 		if (value >= UI_GetNumBots()) {
1734 			value = 0;
1735 		}
1736 		text = UI_GetBotNameByNumber(value);
1737 	}
1738   Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
1739 }
1740 
UI_DrawBotSkill(rectDef_t * rect,float scale,vec4_t color,int textStyle)1741 static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1742 	if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
1743 	  Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
1744 	}
1745 }
1746 
UI_DrawRedBlue(rectDef_t * rect,float scale,vec4_t color,int textStyle)1747 static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1748   Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
1749 }
1750 
UI_DrawCrosshair(rectDef_t * rect,float scale,vec4_t color)1751 static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
1752  	trap_R_SetColor( color );
1753 	if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
1754 		uiInfo.currentCrosshair = 0;
1755 	}
1756 	UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
1757  	trap_R_SetColor( NULL );
1758 }
1759 
1760 /*
1761 ===============
1762 UI_BuildPlayerList
1763 ===============
1764 */
UI_BuildPlayerList(void)1765 static void UI_BuildPlayerList( void ) {
1766 	uiClientState_t	cs;
1767 	int		n, count, team, team2, playerTeamNumber;
1768 	char	info[MAX_INFO_STRING];
1769 
1770 	trap_GetClientState( &cs );
1771 	trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
1772 	uiInfo.playerNumber = cs.clientNum;
1773 	uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
1774 	team = atoi(Info_ValueForKey(info, "t"));
1775 	trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
1776 	count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
1777 	uiInfo.playerCount = 0;
1778 	uiInfo.myTeamCount = 0;
1779 	playerTeamNumber = 0;
1780 	for( n = 0; n < count; n++ ) {
1781 		trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
1782 
1783 		if (info[0]) {
1784 			Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
1785 			Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
1786 			uiInfo.playerCount++;
1787 			team2 = atoi(Info_ValueForKey(info, "t"));
1788 			if (team2 == team) {
1789 				Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
1790 				Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
1791 				uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
1792 				if (uiInfo.playerNumber == n) {
1793 					playerTeamNumber = uiInfo.myTeamCount;
1794 				}
1795 				uiInfo.myTeamCount++;
1796 			}
1797 		}
1798 	}
1799 
1800 	if (!uiInfo.teamLeader) {
1801 		trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
1802 	}
1803 
1804 	n = trap_Cvar_VariableValue("cg_selectedPlayer");
1805 	if (n < 0 || n > uiInfo.myTeamCount) {
1806 		n = 0;
1807 	}
1808 	if (n < uiInfo.myTeamCount) {
1809 		trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
1810 	}
1811 }
1812 
1813 
UI_DrawSelectedPlayer(rectDef_t * rect,float scale,vec4_t color,int textStyle)1814 static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1815 	if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
1816 		uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
1817 		UI_BuildPlayerList();
1818 	}
1819   Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
1820 }
1821 
UI_DrawServerRefreshDate(rectDef_t * rect,float scale,vec4_t color,int textStyle)1822 static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1823 	if (uiInfo.serverStatus.refreshActive) {
1824 		vec4_t lowLight, newColor;
1825 		lowLight[0] = 0.8 * color[0];
1826 		lowLight[1] = 0.8 * color[1];
1827 		lowLight[2] = 0.8 * color[2];
1828 		lowLight[3] = 0.8 * color[3];
1829 		LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
1830 	  Text_Paint(rect->x, rect->y, scale, newColor, va("Getting info for %d servers (ESC to cancel)", trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle);
1831 	} else {
1832 		char buff[64];
1833 		Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
1834 	  Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
1835 	}
1836 }
1837 
UI_DrawServerMOTD(rectDef_t * rect,float scale,vec4_t color)1838 static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
1839 	if (uiInfo.serverStatus.motdLen) {
1840 		float maxX;
1841 
1842 		if (uiInfo.serverStatus.motdWidth == -1) {
1843 			uiInfo.serverStatus.motdWidth = 0;
1844 			uiInfo.serverStatus.motdPaintX = rect->x + 1;
1845 			uiInfo.serverStatus.motdPaintX2 = -1;
1846 		}
1847 
1848 		if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
1849 			uiInfo.serverStatus.motdOffset = 0;
1850 			uiInfo.serverStatus.motdPaintX = rect->x + 1;
1851 			uiInfo.serverStatus.motdPaintX2 = -1;
1852 		}
1853 
1854 		if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
1855 			uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
1856 			if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
1857 				if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
1858 					uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
1859 					uiInfo.serverStatus.motdOffset++;
1860 				} else {
1861 					uiInfo.serverStatus.motdOffset = 0;
1862 					if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1863 						uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
1864 					} else {
1865 						uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
1866 					}
1867 					uiInfo.serverStatus.motdPaintX2 = -1;
1868 				}
1869 			} else {
1870 				//serverStatus.motdPaintX--;
1871 				uiInfo.serverStatus.motdPaintX -= 2;
1872 				if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1873 					//serverStatus.motdPaintX2--;
1874 					uiInfo.serverStatus.motdPaintX2 -= 2;
1875 				}
1876 			}
1877 		}
1878 
1879 		maxX = rect->x + rect->w - 2;
1880 		Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0);
1881 		if (uiInfo.serverStatus.motdPaintX2 >= 0) {
1882 			float maxX2 = rect->x + rect->w - 2;
1883 			Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset);
1884 		}
1885 		if (uiInfo.serverStatus.motdOffset && maxX > 0) {
1886 			// if we have an offset ( we are skipping the first part of the string ) and we fit the string
1887 			if (uiInfo.serverStatus.motdPaintX2 == -1) {
1888 						uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
1889 			}
1890 		} else {
1891 			uiInfo.serverStatus.motdPaintX2 = -1;
1892 		}
1893 
1894 	}
1895 }
1896 
UI_DrawKeyBindStatus(rectDef_t * rect,float scale,vec4_t color,int textStyle)1897 static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1898 //	int ofs = 0; TTimo: unused
1899 	if (Display_KeyBindPending()) {
1900 		Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
1901 	} else {
1902 		Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
1903 	}
1904 }
1905 
UI_DrawGLInfo(rectDef_t * rect,float scale,vec4_t color,int textStyle)1906 static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
1907 	char * eptr;
1908 	char buff[1024];
1909 	const char *lines[64];
1910 	int y, numLines, i;
1911 
1912 	Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
1913 	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);
1914 	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);
1915 
1916 	// build null terminated extension strings
1917   // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
1918   // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
1919   // brought down the string size to 1024, there's not much that can be shown on the screen anyway
1920 	Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
1921 	eptr = buff;
1922 	y = rect->y + 45;
1923 	numLines = 0;
1924 	while ( y < rect->y + rect->h && *eptr )
1925 	{
1926 		while ( *eptr && *eptr == ' ' )
1927 			*eptr++ = '\0';
1928 
1929 		// track start of valid string
1930 		if (*eptr && *eptr != ' ') {
1931 			lines[numLines++] = eptr;
1932 		}
1933 
1934 		while ( *eptr && *eptr != ' ' )
1935 			eptr++;
1936 	}
1937 
1938 	i = 0;
1939 	while (i < numLines) {
1940 		Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
1941 		if (i < numLines) {
1942 			Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
1943 		}
1944 		y += 10;
1945 		if (y > rect->y + rect->h - 11) {
1946 			break;
1947 		}
1948 	}
1949 
1950 
1951 }
1952 
1953 // FIXME: table drive
1954 //
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)1955 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) {
1956 	rectDef_t rect;
1957 
1958   rect.x = x + text_x;
1959   rect.y = y + text_y;
1960   rect.w = w;
1961   rect.h = h;
1962 
1963   switch (ownerDraw) {
1964     case UI_HANDICAP:
1965       UI_DrawHandicap(&rect, scale, color, textStyle);
1966       break;
1967     case UI_EFFECTS:
1968       UI_DrawEffects(&rect, scale, color);
1969       break;
1970     case UI_PLAYERMODEL:
1971       UI_DrawPlayerModel(&rect);
1972       break;
1973     case UI_CLANNAME:
1974       UI_DrawClanName(&rect, scale, color, textStyle);
1975       break;
1976     case UI_CLANLOGO:
1977       UI_DrawClanLogo(&rect, scale, color);
1978       break;
1979     case UI_CLANCINEMATIC:
1980       UI_DrawClanCinematic(&rect, scale, color);
1981       break;
1982     case UI_PREVIEWCINEMATIC:
1983       UI_DrawPreviewCinematic(&rect, scale, color);
1984       break;
1985     case UI_GAMETYPE:
1986       UI_DrawGameType(&rect, scale, color, textStyle);
1987       break;
1988     case UI_NETGAMETYPE:
1989       UI_DrawNetGameType(&rect, scale, color, textStyle);
1990       break;
1991     case UI_JOINGAMETYPE:
1992 	  UI_DrawJoinGameType(&rect, scale, color, textStyle);
1993 	  break;
1994     case UI_MAPPREVIEW:
1995       UI_DrawMapPreview(&rect, scale, color, qtrue);
1996       break;
1997     case UI_MAP_TIMETOBEAT:
1998       UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
1999       break;
2000     case UI_MAPCINEMATIC:
2001       UI_DrawMapCinematic(&rect, scale, color, qfalse);
2002       break;
2003     case UI_STARTMAPCINEMATIC:
2004       UI_DrawMapCinematic(&rect, scale, color, qtrue);
2005       break;
2006     case UI_SKILL:
2007       UI_DrawSkill(&rect, scale, color, textStyle);
2008       break;
2009     case UI_BLUETEAMNAME:
2010       UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
2011       break;
2012     case UI_REDTEAMNAME:
2013       UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
2014       break;
2015     case UI_BLUETEAM1:
2016 		case UI_BLUETEAM2:
2017 		case UI_BLUETEAM3:
2018 		case UI_BLUETEAM4:
2019 		case UI_BLUETEAM5:
2020       UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
2021       break;
2022     case UI_REDTEAM1:
2023 		case UI_REDTEAM2:
2024 		case UI_REDTEAM3:
2025 		case UI_REDTEAM4:
2026 		case UI_REDTEAM5:
2027       UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
2028       break;
2029 		case UI_NETSOURCE:
2030       UI_DrawNetSource(&rect, scale, color, textStyle);
2031 			break;
2032     case UI_NETMAPPREVIEW:
2033       UI_DrawNetMapPreview(&rect, scale, color);
2034       break;
2035     case UI_NETMAPCINEMATIC:
2036       UI_DrawNetMapCinematic(&rect, scale, color);
2037       break;
2038 		case UI_NETFILTER:
2039       UI_DrawNetFilter(&rect, scale, color, textStyle);
2040 			break;
2041 		case UI_TIER:
2042 			UI_DrawTier(&rect, scale, color, textStyle);
2043 			break;
2044 		case UI_OPPONENTMODEL:
2045 			UI_DrawOpponent(&rect);
2046 			break;
2047 		case UI_TIERMAP1:
2048 			UI_DrawTierMap(&rect, 0);
2049 			break;
2050 		case UI_TIERMAP2:
2051 			UI_DrawTierMap(&rect, 1);
2052 			break;
2053 		case UI_TIERMAP3:
2054 			UI_DrawTierMap(&rect, 2);
2055 			break;
2056 		case UI_PLAYERLOGO:
2057 			UI_DrawPlayerLogo(&rect, color);
2058 			break;
2059 		case UI_PLAYERLOGO_METAL:
2060 			UI_DrawPlayerLogoMetal(&rect, color);
2061 			break;
2062 		case UI_PLAYERLOGO_NAME:
2063 			UI_DrawPlayerLogoName(&rect, color);
2064 			break;
2065 		case UI_OPPONENTLOGO:
2066 			UI_DrawOpponentLogo(&rect, color);
2067 			break;
2068 		case UI_OPPONENTLOGO_METAL:
2069 			UI_DrawOpponentLogoMetal(&rect, color);
2070 			break;
2071 		case UI_OPPONENTLOGO_NAME:
2072 			UI_DrawOpponentLogoName(&rect, color);
2073 			break;
2074 		case UI_TIER_MAPNAME:
2075 			UI_DrawTierMapName(&rect, scale, color, textStyle);
2076 			break;
2077 		case UI_TIER_GAMETYPE:
2078 			UI_DrawTierGameType(&rect, scale, color, textStyle);
2079 			break;
2080 		case UI_ALLMAPS_SELECTION:
2081 			UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
2082 			break;
2083 		case UI_MAPS_SELECTION:
2084 			UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
2085 			break;
2086 		case UI_OPPONENT_NAME:
2087 			UI_DrawOpponentName(&rect, scale, color, textStyle);
2088 			break;
2089 		case UI_BOTNAME:
2090 			UI_DrawBotName(&rect, scale, color, textStyle);
2091 			break;
2092 		case UI_BOTSKILL:
2093 			UI_DrawBotSkill(&rect, scale, color, textStyle);
2094 			break;
2095 		case UI_REDBLUE:
2096 			UI_DrawRedBlue(&rect, scale, color, textStyle);
2097 			break;
2098 		case UI_CROSSHAIR:
2099 			UI_DrawCrosshair(&rect, scale, color);
2100 			break;
2101 		case UI_SELECTEDPLAYER:
2102 			UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
2103 			break;
2104 		case UI_SERVERREFRESHDATE:
2105 			UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
2106 			break;
2107 		case UI_SERVERMOTD:
2108 			UI_DrawServerMOTD(&rect, scale, color);
2109 			break;
2110 		case UI_GLINFO:
2111 			UI_DrawGLInfo(&rect,scale, color, textStyle);
2112 			break;
2113 		case UI_KEYBINDSTATUS:
2114 			UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
2115 			break;
2116     default:
2117       break;
2118   }
2119 
2120 }
2121 
UI_OwnerDrawVisible(int flags)2122 static qboolean UI_OwnerDrawVisible(int flags) {
2123 	qboolean vis = qtrue;
2124 
2125 	while (flags) {
2126 
2127 		if (flags & UI_SHOW_FFA) {
2128 			if (trap_Cvar_VariableValue("g_gametype") != GT_FFA) {
2129 				vis = qfalse;
2130 			}
2131 			flags &= ~UI_SHOW_FFA;
2132 		}
2133 
2134 		if (flags & UI_SHOW_NOTFFA) {
2135 			if (trap_Cvar_VariableValue("g_gametype") == GT_FFA) {
2136 				vis = qfalse;
2137 			}
2138 			flags &= ~UI_SHOW_NOTFFA;
2139 		}
2140 
2141 		if (flags & UI_SHOW_LEADER) {
2142 			// these need to show when this client can give orders to a player or a group
2143 			if (!uiInfo.teamLeader) {
2144 				vis = qfalse;
2145 			} else {
2146 				// if showing yourself
2147 				if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) {
2148 					vis = qfalse;
2149 				}
2150 			}
2151 			flags &= ~UI_SHOW_LEADER;
2152 		}
2153 		if (flags & UI_SHOW_NOTLEADER) {
2154 			// these need to show when this client is assigning their own status or they are NOT the leader
2155 			if (uiInfo.teamLeader) {
2156 				// if not showing yourself
2157 				if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) {
2158 					vis = qfalse;
2159 				}
2160 				// these need to show when this client can give orders to a player or a group
2161 			}
2162 			flags &= ~UI_SHOW_NOTLEADER;
2163 		}
2164 		if (flags & UI_SHOW_FAVORITESERVERS) {
2165 			// this assumes you only put this type of display flag on something showing in the proper context
2166 			if (ui_netSource.integer != AS_FAVORITES) {
2167 				vis = qfalse;
2168 			}
2169 			flags &= ~UI_SHOW_FAVORITESERVERS;
2170 		}
2171 		if (flags & UI_SHOW_NOTFAVORITESERVERS) {
2172 			// this assumes you only put this type of display flag on something showing in the proper context
2173 			if (ui_netSource.integer == AS_FAVORITES) {
2174 				vis = qfalse;
2175 			}
2176 			flags &= ~UI_SHOW_NOTFAVORITESERVERS;
2177 		}
2178 		if (flags & UI_SHOW_ANYTEAMGAME) {
2179 			if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM ) {
2180 				vis = qfalse;
2181 			}
2182 			flags &= ~UI_SHOW_ANYTEAMGAME;
2183 		}
2184 		if (flags & UI_SHOW_ANYNONTEAMGAME) {
2185 			if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM ) {
2186 				vis = qfalse;
2187 			}
2188 			flags &= ~UI_SHOW_ANYNONTEAMGAME;
2189 		}
2190 		if (flags & UI_SHOW_NETANYTEAMGAME) {
2191 			if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM ) {
2192 				vis = qfalse;
2193 			}
2194 			flags &= ~UI_SHOW_NETANYTEAMGAME;
2195 		}
2196 		if (flags & UI_SHOW_NETANYNONTEAMGAME) {
2197 			if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM ) {
2198 				vis = qfalse;
2199 			}
2200 			flags &= ~UI_SHOW_NETANYNONTEAMGAME;
2201 		}
2202 		if (flags & UI_SHOW_NEWHIGHSCORE) {
2203 			if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
2204 				vis = qfalse;
2205 			} else {
2206 				if (uiInfo.soundHighScore) {
2207 					if (trap_Cvar_VariableValue("sv_killserver") == 0) {
2208 						// wait on server to go down before playing sound
2209 						trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
2210 						uiInfo.soundHighScore = qfalse;
2211 					}
2212 				}
2213 			}
2214 			flags &= ~UI_SHOW_NEWHIGHSCORE;
2215 		}
2216 		if (flags & UI_SHOW_NEWBESTTIME) {
2217 			if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
2218 				vis = qfalse;
2219 			}
2220 			flags &= ~UI_SHOW_NEWBESTTIME;
2221 		}
2222 		if (flags & UI_SHOW_DEMOAVAILABLE) {
2223 			if (!uiInfo.demoAvailable) {
2224 				vis = qfalse;
2225 			}
2226 			flags &= ~UI_SHOW_DEMOAVAILABLE;
2227 		} else {
2228 			flags = 0;
2229 		}
2230 	}
2231   return vis;
2232 }
2233 
UI_Handicap_HandleKey(int flags,float * special,int key)2234 static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
2235   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2236     int h;
2237     h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
2238 		if (key == K_MOUSE2) {
2239 	    h -= 5;
2240 		} else {
2241 	    h += 5;
2242 		}
2243     if (h > 100) {
2244       h = 5;
2245     } else if (h < 5) {
2246 			h = 100;
2247 		}
2248   	trap_Cvar_Set( "handicap", va( "%i", h) );
2249     return qtrue;
2250   }
2251   return qfalse;
2252 }
2253 
UI_Effects_HandleKey(int flags,float * special,int key)2254 static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
2255   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2256 
2257 		if (key == K_MOUSE2) {
2258 	    uiInfo.effectsColor--;
2259 		} else {
2260 	    uiInfo.effectsColor++;
2261 		}
2262 
2263     if( uiInfo.effectsColor > 6 ) {
2264 	  	uiInfo.effectsColor = 0;
2265 		} else if (uiInfo.effectsColor < 0) {
2266 	  	uiInfo.effectsColor = 6;
2267 		}
2268 
2269 	  trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
2270     return qtrue;
2271   }
2272   return qfalse;
2273 }
2274 
UI_ClanName_HandleKey(int flags,float * special,int key)2275 static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
2276   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2277     int i;
2278     i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2279 		if (uiInfo.teamList[i].cinematic >= 0) {
2280 		  trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
2281 			uiInfo.teamList[i].cinematic = -1;
2282 		}
2283 		if (key == K_MOUSE2) {
2284 	    i--;
2285 		} else {
2286 	    i++;
2287 		}
2288     if (i >= uiInfo.teamCount) {
2289       i = 0;
2290     } else if (i < 0) {
2291 			i = uiInfo.teamCount - 1;
2292 		}
2293   	trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
2294 	UI_HeadCountByTeam();
2295 	UI_FeederSelection(FEEDER_HEADS, 0);
2296 	updateModel = qtrue;
2297     return qtrue;
2298   }
2299   return qfalse;
2300 }
2301 
UI_GameType_HandleKey(int flags,float * special,int key,qboolean resetMap)2302 static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
2303   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2304 		int oldCount = UI_MapCountByGameType(qtrue);
2305 
2306 		// hard coded mess here
2307 		if (key == K_MOUSE2) {
2308 			ui_gameType.integer--;
2309 			if (ui_gameType.integer == 2) {
2310 				ui_gameType.integer = 1;
2311 			} else if (ui_gameType.integer < 2) {
2312 				ui_gameType.integer = uiInfo.numGameTypes - 1;
2313 			}
2314 		} else {
2315 			ui_gameType.integer++;
2316 			if (ui_gameType.integer >= uiInfo.numGameTypes) {
2317 				ui_gameType.integer = 1;
2318 			} else if (ui_gameType.integer == 2) {
2319 				ui_gameType.integer = 3;
2320 			}
2321 		}
2322 
2323 		if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
2324 			trap_Cvar_Set("ui_Q3Model", "1");
2325 		} else {
2326 			trap_Cvar_Set("ui_Q3Model", "0");
2327 		}
2328 
2329 		trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
2330 		UI_SetCapFragLimits(qtrue);
2331 		UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
2332 		if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
2333 	  	trap_Cvar_Set( "ui_currentMap", "0");
2334 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
2335 		}
2336     return qtrue;
2337   }
2338   return qfalse;
2339 }
2340 
UI_NetGameType_HandleKey(int flags,float * special,int key)2341 static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
2342   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2343 
2344 		if (key == K_MOUSE2) {
2345 			ui_netGameType.integer--;
2346 		} else {
2347 			ui_netGameType.integer++;
2348 		}
2349 
2350     if (ui_netGameType.integer < 0) {
2351       ui_netGameType.integer = uiInfo.numGameTypes - 1;
2352 		} else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
2353       ui_netGameType.integer = 0;
2354     }
2355 
2356   	trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
2357   	trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
2358   	trap_Cvar_Set( "ui_currentNetMap", "0");
2359 		UI_MapCountByGameType(qfalse);
2360 		Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
2361     return qtrue;
2362   }
2363   return qfalse;
2364 }
2365 
UI_JoinGameType_HandleKey(int flags,float * special,int key)2366 static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
2367 	if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2368 
2369 		if (key == K_MOUSE2) {
2370 			ui_joinGameType.integer--;
2371 		} else {
2372 			ui_joinGameType.integer++;
2373 		}
2374 
2375 		if (ui_joinGameType.integer < 0) {
2376 			ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
2377 		} else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
2378 			ui_joinGameType.integer = 0;
2379 		}
2380 
2381 		trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
2382 		UI_BuildServerDisplayList(qtrue);
2383 		return qtrue;
2384 	}
2385 	return qfalse;
2386 }
2387 
2388 
2389 
UI_Skill_HandleKey(int flags,float * special,int key)2390 static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
2391   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2392   	int i = trap_Cvar_VariableValue( "g_spSkill" );
2393 
2394 		if (key == K_MOUSE2) {
2395 	    i--;
2396 		} else {
2397 	    i++;
2398 		}
2399 
2400     if (i < 1) {
2401 			i = numSkillLevels;
2402 		} else if (i > numSkillLevels) {
2403       i = 1;
2404     }
2405 
2406     trap_Cvar_Set("g_spSkill", va("%i", i));
2407     return qtrue;
2408   }
2409   return qfalse;
2410 }
2411 
UI_TeamName_HandleKey(int flags,float * special,int key,qboolean blue)2412 static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
2413   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2414     int i;
2415     i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
2416 
2417 		if (key == K_MOUSE2) {
2418 	    i--;
2419 		} else {
2420 	    i++;
2421 		}
2422 
2423     if (i >= uiInfo.teamCount) {
2424       i = 0;
2425     } else if (i < 0) {
2426 			i = uiInfo.teamCount - 1;
2427 		}
2428 
2429     trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
2430 
2431     return qtrue;
2432   }
2433   return qfalse;
2434 }
2435 
UI_TeamMember_HandleKey(int flags,float * special,int key,qboolean blue,int num)2436 static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
2437   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2438 		// 0 - None
2439 		// 1 - Human
2440 		// 2..NumCharacters - Bot
2441 		char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
2442 		int value = trap_Cvar_VariableValue(cvar);
2443 
2444 		if (key == K_MOUSE2) {
2445 			value--;
2446 		} else {
2447 			value++;
2448 		}
2449 
2450 		if (ui_actualNetGameType.integer >= GT_TEAM) {
2451 			if (value >= uiInfo.characterCount + 2) {
2452 				value = 0;
2453 			} else if (value < 0) {
2454 				value = uiInfo.characterCount + 2 - 1;
2455 			}
2456 		} else {
2457 			if (value >= UI_GetNumBots() + 2) {
2458 				value = 0;
2459 			} else if (value < 0) {
2460 				value = UI_GetNumBots() + 2 - 1;
2461 			}
2462 		}
2463 
2464 		trap_Cvar_Set(cvar, va("%i", value));
2465     return qtrue;
2466   }
2467   return qfalse;
2468 }
2469 
UI_NetSource_HandleKey(int flags,float * special,int key)2470 static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
2471   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2472 
2473 		if (key == K_MOUSE2) {
2474 			ui_netSource.integer--;
2475 		} else {
2476 			ui_netSource.integer++;
2477 		}
2478 
2479 		if (ui_netSource.integer >= numNetSources) {
2480       ui_netSource.integer = 0;
2481     } else if (ui_netSource.integer < 0) {
2482       ui_netSource.integer = numNetSources - 1;
2483 		}
2484 
2485 		UI_BuildServerDisplayList(qtrue);
2486 		if (ui_netSource.integer != AS_GLOBAL) {
2487 			UI_StartServerRefresh(qtrue);
2488 		}
2489   	trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
2490     return qtrue;
2491   }
2492   return qfalse;
2493 }
2494 
UI_NetFilter_HandleKey(int flags,float * special,int key)2495 static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
2496   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2497 
2498 		if (key == K_MOUSE2) {
2499 			ui_serverFilterType.integer--;
2500 		} else {
2501 			ui_serverFilterType.integer++;
2502 		}
2503 
2504     if (ui_serverFilterType.integer >= numServerFilters) {
2505       ui_serverFilterType.integer = 0;
2506     } else if (ui_serverFilterType.integer < 0) {
2507       ui_serverFilterType.integer = numServerFilters - 1;
2508 		}
2509 		UI_BuildServerDisplayList(qtrue);
2510     return qtrue;
2511   }
2512   return qfalse;
2513 }
2514 
UI_OpponentName_HandleKey(int flags,float * special,int key)2515 static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
2516   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2517 		if (key == K_MOUSE2) {
2518 			UI_PriorOpponent();
2519 		} else {
2520 			UI_NextOpponent();
2521 		}
2522     return qtrue;
2523   }
2524   return qfalse;
2525 }
2526 
UI_BotName_HandleKey(int flags,float * special,int key)2527 static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
2528   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2529 		int game = trap_Cvar_VariableValue("g_gametype");
2530 		int value = uiInfo.botIndex;
2531 
2532 		if (key == K_MOUSE2) {
2533 			value--;
2534 		} else {
2535 			value++;
2536 		}
2537 
2538 		if (game >= GT_TEAM) {
2539 			if (value >= uiInfo.characterCount + 2) {
2540 				value = 0;
2541 			} else if (value < 0) {
2542 				value = uiInfo.characterCount + 2 - 1;
2543 			}
2544 		} else {
2545 			if (value >= UI_GetNumBots() + 2) {
2546 				value = 0;
2547 			} else if (value < 0) {
2548 				value = UI_GetNumBots() + 2 - 1;
2549 			}
2550 		}
2551 		uiInfo.botIndex = value;
2552     return qtrue;
2553   }
2554   return qfalse;
2555 }
2556 
UI_BotSkill_HandleKey(int flags,float * special,int key)2557 static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
2558   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2559 		if (key == K_MOUSE2) {
2560 			uiInfo.skillIndex--;
2561 		} else {
2562 			uiInfo.skillIndex++;
2563 		}
2564 		if (uiInfo.skillIndex >= numSkillLevels) {
2565 			uiInfo.skillIndex = 0;
2566 		} else if (uiInfo.skillIndex < 0) {
2567 			uiInfo.skillIndex = numSkillLevels-1;
2568 		}
2569     return qtrue;
2570   }
2571 	return qfalse;
2572 }
2573 
UI_RedBlue_HandleKey(int flags,float * special,int key)2574 static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
2575   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2576 		uiInfo.redBlue ^= 1;
2577 		return qtrue;
2578 	}
2579 	return qfalse;
2580 }
2581 
UI_Crosshair_HandleKey(int flags,float * special,int key)2582 static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
2583   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2584 		if (key == K_MOUSE2) {
2585 			uiInfo.currentCrosshair--;
2586 		} else {
2587 			uiInfo.currentCrosshair++;
2588 		}
2589 
2590 		if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
2591 			uiInfo.currentCrosshair = 0;
2592 		} else if (uiInfo.currentCrosshair < 0) {
2593 			uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
2594 		}
2595 		trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair));
2596 		return qtrue;
2597 	}
2598 	return qfalse;
2599 }
2600 
2601 
2602 
UI_SelectedPlayer_HandleKey(int flags,float * special,int key)2603 static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
2604   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
2605 		int selected;
2606 
2607 		UI_BuildPlayerList();
2608 		if (!uiInfo.teamLeader) {
2609 			return qfalse;
2610 		}
2611 		selected = trap_Cvar_VariableValue("cg_selectedPlayer");
2612 
2613 		if (key == K_MOUSE2) {
2614 			selected--;
2615 		} else {
2616 			selected++;
2617 		}
2618 
2619 		if (selected > uiInfo.myTeamCount) {
2620 			selected = 0;
2621 		} else if (selected < 0) {
2622 			selected = uiInfo.myTeamCount;
2623 		}
2624 
2625 		if (selected == uiInfo.myTeamCount) {
2626 		 	trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
2627 		} else {
2628 		 	trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
2629 		}
2630 	 	trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
2631 	}
2632 	return qfalse;
2633 }
2634 
2635 
UI_OwnerDrawHandleKey(int ownerDraw,int flags,float * special,int key)2636 static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
2637   switch (ownerDraw) {
2638     case UI_HANDICAP:
2639       return UI_Handicap_HandleKey(flags, special, key);
2640       break;
2641     case UI_EFFECTS:
2642       return UI_Effects_HandleKey(flags, special, key);
2643       break;
2644     case UI_CLANNAME:
2645       return UI_ClanName_HandleKey(flags, special, key);
2646       break;
2647     case UI_GAMETYPE:
2648       return UI_GameType_HandleKey(flags, special, key, qtrue);
2649       break;
2650     case UI_NETGAMETYPE:
2651       return UI_NetGameType_HandleKey(flags, special, key);
2652       break;
2653     case UI_JOINGAMETYPE:
2654       return UI_JoinGameType_HandleKey(flags, special, key);
2655       break;
2656     case UI_SKILL:
2657       return UI_Skill_HandleKey(flags, special, key);
2658       break;
2659     case UI_BLUETEAMNAME:
2660       return UI_TeamName_HandleKey(flags, special, key, qtrue);
2661       break;
2662     case UI_REDTEAMNAME:
2663       return UI_TeamName_HandleKey(flags, special, key, qfalse);
2664       break;
2665     case UI_BLUETEAM1:
2666 		case UI_BLUETEAM2:
2667 		case UI_BLUETEAM3:
2668 		case UI_BLUETEAM4:
2669 		case UI_BLUETEAM5:
2670       UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
2671       break;
2672     case UI_REDTEAM1:
2673 		case UI_REDTEAM2:
2674 		case UI_REDTEAM3:
2675 		case UI_REDTEAM4:
2676 		case UI_REDTEAM5:
2677       UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
2678       break;
2679 		case UI_NETSOURCE:
2680       UI_NetSource_HandleKey(flags, special, key);
2681 			break;
2682 		case UI_NETFILTER:
2683       UI_NetFilter_HandleKey(flags, special, key);
2684 			break;
2685 		case UI_OPPONENT_NAME:
2686 			UI_OpponentName_HandleKey(flags, special, key);
2687 			break;
2688 		case UI_BOTNAME:
2689 			return UI_BotName_HandleKey(flags, special, key);
2690 			break;
2691 		case UI_BOTSKILL:
2692 			return UI_BotSkill_HandleKey(flags, special, key);
2693 			break;
2694 		case UI_REDBLUE:
2695 			UI_RedBlue_HandleKey(flags, special, key);
2696 			break;
2697 		case UI_CROSSHAIR:
2698 			UI_Crosshair_HandleKey(flags, special, key);
2699 			break;
2700 		case UI_SELECTEDPLAYER:
2701 			UI_SelectedPlayer_HandleKey(flags, special, key);
2702 			break;
2703     default:
2704       break;
2705   }
2706 
2707   return qfalse;
2708 }
2709 
2710 
UI_GetValue(int ownerDraw)2711 static float UI_GetValue(int ownerDraw) {
2712   return 0;
2713 }
2714 
2715 /*
2716 =================
2717 UI_ServersQsortCompare
2718 =================
2719 */
UI_ServersQsortCompare(const void * arg1,const void * arg2)2720 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
2721 	return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
2722 }
2723 
2724 
2725 /*
2726 =================
2727 UI_ServersSort
2728 =================
2729 */
UI_ServersSort(int column,qboolean force)2730 void UI_ServersSort(int column, qboolean force) {
2731 
2732 	if ( !force ) {
2733 		if ( uiInfo.serverStatus.sortKey == column ) {
2734 			return;
2735 		}
2736 	}
2737 
2738 	uiInfo.serverStatus.sortKey = column;
2739 	qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
2740 }
2741 
2742 /*
2743 static void UI_StartSinglePlayer(void) {
2744 	int i,j, k, skill;
2745 	char buff[1024];
2746 	i = trap_Cvar_VariableValue( "ui_currentTier" );
2747   if (i < 0 || i >= tierCount) {
2748     i = 0;
2749   }
2750 	j = trap_Cvar_VariableValue("ui_currentMap");
2751 	if (j < 0 || j > MAPS_PER_TIER) {
2752 		j = 0;
2753 	}
2754 
2755  	trap_Cvar_SetValue( "singleplayer", 1 );
2756  	trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, GT_MAX_GAME_TYPE-1, tierList[i].gameTypes[j] ) );
2757 	trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
2758 	skill = trap_Cvar_VariableValue( "g_spSkill" );
2759 
2760 	if (j == MAPS_PER_TIER-1) {
2761 		k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2762 		Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
2763 	} else {
2764 		k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2765 		for (i = 0; i < PLAYERS_PER_TEAM; i++) {
2766 			Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Blue", teamList[k].teamMembers[i]);
2767 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2768 		}
2769 
2770 		k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2771 		for (i = 1; i < PLAYERS_PER_TEAM; i++) {
2772 			Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[i]), skill, "Red", teamList[k].teamMembers[i]);
2773 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2774 		}
2775 		trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
2776 	}
2777 
2778 
2779 }
2780 */
2781 
2782 /*
2783 ===============
2784 UI_LoadMods
2785 ===============
2786 */
UI_LoadMods(void)2787 static void UI_LoadMods( void ) {
2788 	int		numdirs;
2789 	char	dirlist[2048];
2790 	char	*dirptr;
2791   char  *descptr;
2792 	int		i;
2793 	int		dirlen;
2794 
2795 	uiInfo.modCount = 0;
2796 	numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
2797 	dirptr  = dirlist;
2798 	for( i = 0; i < numdirs; i++ ) {
2799 		dirlen = strlen( dirptr ) + 1;
2800     descptr = dirptr + dirlen;
2801 		uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
2802 		uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
2803     dirptr += dirlen + strlen(descptr) + 1;
2804 		uiInfo.modCount++;
2805 		if (uiInfo.modCount >= MAX_MODS) {
2806 			break;
2807 		}
2808 	}
2809 
2810 }
2811 
2812 
2813 /*
2814 ===============
2815 UI_LoadTeams
2816 ===============
2817 */
UI_LoadTeams(void)2818 static void UI_LoadTeams( void ) {
2819 	char	teamList[4096];
2820 	char	*teamName;
2821 	int		i, len, count;
2822 
2823 	count = trap_FS_GetFileList( "", "team", teamList, 4096 );
2824 
2825 	if (count) {
2826 		teamName = teamList;
2827 		for ( i = 0; i < count; i++ ) {
2828 			len = strlen( teamName );
2829 			UI_ParseTeamInfo(teamName);
2830 			teamName += len + 1;
2831 		}
2832 	}
2833 
2834 }
2835 
2836 
2837 /*
2838 ===============
2839 UI_LoadMovies
2840 ===============
2841 */
UI_LoadMovies(void)2842 static void UI_LoadMovies( void ) {
2843 	char	movielist[4096];
2844 	char	*moviename;
2845 	int		i, len;
2846 
2847 	uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
2848 
2849 	if (uiInfo.movieCount) {
2850 		if (uiInfo.movieCount > MAX_MOVIES) {
2851 			uiInfo.movieCount = MAX_MOVIES;
2852 		}
2853 		moviename = movielist;
2854 		for ( i = 0; i < uiInfo.movieCount; i++ ) {
2855 			len = strlen( moviename );
2856 			if (!Q_stricmp(moviename +  len - 4,".roq")) {
2857 				moviename[len-4] = '\0';
2858 			}
2859 			Q_strupr(moviename);
2860 			uiInfo.movieList[i] = String_Alloc(moviename);
2861 			moviename += len + 1;
2862 		}
2863 	}
2864 
2865 }
2866 
2867 
2868 
2869 /*
2870 ===============
2871 UI_LoadDemos
2872 ===============
2873 */
UI_LoadDemos(void)2874 static void UI_LoadDemos( void ) {
2875 	char	demolist[4096];
2876 	char demoExt[32];
2877 	char	*demoname;
2878 	int		i, len;
2879 
2880 	Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
2881 
2882 	uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
2883 
2884 	Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
2885 
2886 	if (uiInfo.demoCount) {
2887 		if (uiInfo.demoCount > MAX_DEMOS) {
2888 			uiInfo.demoCount = MAX_DEMOS;
2889 		}
2890 		demoname = demolist;
2891 		for ( i = 0; i < uiInfo.demoCount; i++ ) {
2892 			len = strlen( demoname );
2893 			if (!Q_stricmp(demoname +  len - strlen(demoExt), demoExt)) {
2894 				demoname[len-strlen(demoExt)] = '\0';
2895 			}
2896 			Q_strupr(demoname);
2897 			uiInfo.demoList[i] = String_Alloc(demoname);
2898 			demoname += len + 1;
2899 		}
2900 	}
2901 
2902 }
2903 
2904 
UI_SetNextMap(int actual,int index)2905 static qboolean UI_SetNextMap(int actual, int index) {
2906 	int i;
2907 	for (i = actual + 1; i < uiInfo.mapCount; i++) {
2908 		if (uiInfo.mapList[i].active) {
2909 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
2910 			return qtrue;
2911 		}
2912 	}
2913 	return qfalse;
2914 }
2915 
2916 
UI_StartSkirmish(qboolean next)2917 static void UI_StartSkirmish(qboolean next) {
2918 	int i, k, g, delay, temp;
2919 	float skill;
2920 	char buff[MAX_STRING_CHARS];
2921 
2922 	if (next) {
2923 		int actual;
2924 		int index = trap_Cvar_VariableValue("ui_mapIndex");
2925 	 	UI_MapCountByGameType(qtrue);
2926 		UI_SelectedMap(index, &actual);
2927 		if (UI_SetNextMap(actual, index)) {
2928 		} else {
2929 			UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
2930 			UI_MapCountByGameType(qtrue);
2931 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
2932 		}
2933 	}
2934 
2935 	g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
2936 	trap_Cvar_SetValue( "g_gametype", g );
2937 	trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
2938 	skill = trap_Cvar_VariableValue( "g_spSkill" );
2939 	trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
2940 
2941 	k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
2942 
2943 	trap_Cvar_Set("ui_singlePlayerActive", "1");
2944 
2945 	// set up sp overrides, will be replaced on postgame
2946 	temp = trap_Cvar_VariableValue( "capturelimit" );
2947 	trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
2948 	temp = trap_Cvar_VariableValue( "fraglimit" );
2949 	trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
2950 
2951 	UI_SetCapFragLimits(qfalse);
2952 
2953 	temp = trap_Cvar_VariableValue( "cg_drawTimer" );
2954 	trap_Cvar_Set("ui_drawTimer", va("%i", temp));
2955 	temp = trap_Cvar_VariableValue( "g_doWarmup" );
2956 	trap_Cvar_Set("ui_doWarmup", va("%i", temp));
2957 	temp = trap_Cvar_VariableValue( "g_friendlyFire" );
2958 	trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
2959 	temp = trap_Cvar_VariableValue( "sv_maxClients" );
2960 	trap_Cvar_Set("ui_maxClients", va("%i", temp));
2961 	temp = trap_Cvar_VariableValue( "g_warmup" );
2962 	trap_Cvar_Set("ui_Warmup", va("%i", temp));
2963 	temp = trap_Cvar_VariableValue( "sv_pure" );
2964 	trap_Cvar_Set("ui_pure", va("%i", temp));
2965 
2966 	trap_Cvar_Set("cg_cameraOrbit", "0");
2967 	trap_Cvar_Set("cg_thirdPerson", "0");
2968 	trap_Cvar_Set("cg_drawTimer", "1");
2969 	trap_Cvar_Set("g_doWarmup", "1");
2970 	trap_Cvar_Set("g_warmup", "15");
2971 	trap_Cvar_Set("sv_pure", "0");
2972 	trap_Cvar_Set("g_friendlyFire", "0");
2973 	trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
2974 	trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
2975 
2976 	if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
2977 		Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
2978 		trap_Cvar_Set("ui_recordSPDemoName", buff);
2979 	}
2980 
2981 	delay = 500;
2982 
2983 	if (g == GT_TOURNAMENT) {
2984 		trap_Cvar_Set("sv_maxClients", "2");
2985 		Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
2986 		trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2987 	} else {
2988 		temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
2989 		trap_Cvar_Set("sv_maxClients", va("%d", temp));
2990 		for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
2991 			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]);
2992 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2993 			delay += 500;
2994 		}
2995 		k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
2996 		for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
2997 			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]);
2998 			trap_Cmd_ExecuteText( EXEC_APPEND, buff );
2999 			delay += 500;
3000 		}
3001 	}
3002 	if (g >= GT_TEAM ) {
3003 		trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
3004 	}
3005 }
3006 
UI_Update(const char * name)3007 static void UI_Update(const char *name) {
3008 	int	val = trap_Cvar_VariableValue(name);
3009 
3010  	if (Q_stricmp(name, "ui_SetName") == 0) {
3011 		trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
3012  	} else if (Q_stricmp(name, "ui_setRate") == 0) {
3013 		float rate = trap_Cvar_VariableValue("rate");
3014 		if (rate >= 5000) {
3015 			trap_Cvar_Set("cl_maxpackets", "30");
3016 			trap_Cvar_Set("cl_packetdup", "1");
3017 		} else if (rate >= 4000) {
3018 			trap_Cvar_Set("cl_maxpackets", "15");
3019 			trap_Cvar_Set("cl_packetdup", "2");		// favor less prediction errors when there's packet loss
3020 		} else {
3021 			trap_Cvar_Set("cl_maxpackets", "15");
3022 			trap_Cvar_Set("cl_packetdup", "1");		// favor lower bandwidth
3023 		}
3024  	} else if (Q_stricmp(name, "ui_GetName") == 0) {
3025 		trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
3026  	} else if (Q_stricmp(name, "r_colorbits") == 0) {
3027 		switch (val) {
3028 			case 0:
3029 				trap_Cvar_SetValue( "r_depthbits", 0 );
3030 				trap_Cvar_SetValue( "r_stencilbits", 0 );
3031 			break;
3032 			case 16:
3033 				trap_Cvar_SetValue( "r_depthbits", 16 );
3034 				trap_Cvar_SetValue( "r_stencilbits", 0 );
3035 			break;
3036 			case 32:
3037 				trap_Cvar_SetValue( "r_depthbits", 24 );
3038 			break;
3039 		}
3040 	} else if (Q_stricmp(name, "r_lodbias") == 0) {
3041 		switch (val) {
3042 			case 0:
3043 				trap_Cvar_SetValue( "r_subdivisions", 4 );
3044 			break;
3045 			case 1:
3046 				trap_Cvar_SetValue( "r_subdivisions", 12 );
3047 			break;
3048 			case 2:
3049 				trap_Cvar_SetValue( "r_subdivisions", 20 );
3050 			break;
3051 		}
3052 	} else if (Q_stricmp(name, "ui_glCustom") == 0) {
3053 		switch (val) {
3054 			case 0:	// high quality
3055 				trap_Cvar_SetValue( "r_fullScreen", 1 );
3056 				trap_Cvar_SetValue( "r_subdivisions", 4 );
3057 				trap_Cvar_SetValue( "r_vertexlight", 0 );
3058 				trap_Cvar_SetValue( "r_lodbias", 0 );
3059 				trap_Cvar_SetValue( "r_colorbits", 32 );
3060 				trap_Cvar_SetValue( "r_depthbits", 24 );
3061 				trap_Cvar_SetValue( "r_picmip", 0 );
3062 				trap_Cvar_SetValue( "r_mode", 4 );
3063 				trap_Cvar_SetValue( "r_texturebits", 32 );
3064 				trap_Cvar_SetValue( "r_fastSky", 0 );
3065 				trap_Cvar_SetValue( "r_inGameVideo", 1 );
3066 				trap_Cvar_SetValue( "cg_shadows", 1 );
3067 				trap_Cvar_SetValue( "cg_brassTime", 2500 );
3068 				trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
3069 			break;
3070 			case 1: // normal
3071 				trap_Cvar_SetValue( "r_fullScreen", 1 );
3072 				trap_Cvar_SetValue( "r_subdivisions", 12 );
3073 				trap_Cvar_SetValue( "r_vertexlight", 0 );
3074 				trap_Cvar_SetValue( "r_lodbias", 0 );
3075 				trap_Cvar_SetValue( "r_colorbits", 0 );
3076 				trap_Cvar_SetValue( "r_depthbits", 24 );
3077 				trap_Cvar_SetValue( "r_picmip", 1 );
3078 				trap_Cvar_SetValue( "r_mode", 3 );
3079 				trap_Cvar_SetValue( "r_texturebits", 0 );
3080 				trap_Cvar_SetValue( "r_fastSky", 0 );
3081 				trap_Cvar_SetValue( "r_inGameVideo", 1 );
3082 				trap_Cvar_SetValue( "cg_brassTime", 2500 );
3083 				trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
3084 				trap_Cvar_SetValue( "cg_shadows", 0 );
3085 			break;
3086 			case 2: // fast
3087 				trap_Cvar_SetValue( "r_fullScreen", 1 );
3088 				trap_Cvar_SetValue( "r_subdivisions", 8 );
3089 				trap_Cvar_SetValue( "r_vertexlight", 0 );
3090 				trap_Cvar_SetValue( "r_lodbias", 1 );
3091 				trap_Cvar_SetValue( "r_colorbits", 0 );
3092 				trap_Cvar_SetValue( "r_depthbits", 0 );
3093 				trap_Cvar_SetValue( "r_picmip", 1 );
3094 				trap_Cvar_SetValue( "r_mode", 3 );
3095 				trap_Cvar_SetValue( "r_texturebits", 0 );
3096 				trap_Cvar_SetValue( "cg_shadows", 0 );
3097 				trap_Cvar_SetValue( "r_fastSky", 1 );
3098 				trap_Cvar_SetValue( "r_inGameVideo", 0 );
3099 				trap_Cvar_SetValue( "cg_brassTime", 0 );
3100 				trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
3101 			break;
3102 			case 3: // fastest
3103 				trap_Cvar_SetValue( "r_fullScreen", 1 );
3104 				trap_Cvar_SetValue( "r_subdivisions", 20 );
3105 				trap_Cvar_SetValue( "r_vertexlight", 1 );
3106 				trap_Cvar_SetValue( "r_lodbias", 2 );
3107 				trap_Cvar_SetValue( "r_colorbits", 16 );
3108 				trap_Cvar_SetValue( "r_depthbits", 16 );
3109 				trap_Cvar_SetValue( "r_mode", 3 );
3110 				trap_Cvar_SetValue( "r_picmip", 2 );
3111 				trap_Cvar_SetValue( "r_texturebits", 16 );
3112 				trap_Cvar_SetValue( "cg_shadows", 0 );
3113 				trap_Cvar_SetValue( "cg_brassTime", 0 );
3114 				trap_Cvar_SetValue( "r_fastSky", 1 );
3115 				trap_Cvar_SetValue( "r_inGameVideo", 0 );
3116 				trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
3117 			break;
3118 		}
3119 	} else if (Q_stricmp(name, "ui_mousePitch") == 0) {
3120 		if (val == 0) {
3121 			trap_Cvar_SetValue( "m_pitch", 0.022f );
3122 		} else {
3123 			trap_Cvar_SetValue( "m_pitch", -0.022f );
3124 		}
3125 	}
3126 }
3127 
UI_RunMenuScript(char ** args)3128 static void UI_RunMenuScript(char **args) {
3129 	const char *name, *name2;
3130 	char buff[1024];
3131 
3132 	if (String_Parse(args, &name)) {
3133 		if (Q_stricmp(name, "StartServer") == 0) {
3134 			int i, clients, oldclients;
3135 			float skill;
3136 			trap_Cvar_Set("cg_thirdPerson", "0");
3137 			trap_Cvar_Set("cg_cameraOrbit", "0");
3138 			trap_Cvar_Set("ui_singlePlayerActive", "0");
3139 			trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
3140 			trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, GT_MAX_GAME_TYPE-1, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
3141 			trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
3142 			trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
3143 			trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
3144 			skill = trap_Cvar_VariableValue( "g_spSkill" );
3145 			// set max clients based on spots
3146 			oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
3147 			clients = 0;
3148 			for (i = 0; i < PLAYERS_PER_TEAM; i++) {
3149 				int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
3150 				if (bot >= 0) {
3151 					clients++;
3152 				}
3153 				bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
3154 				if (bot >= 0) {
3155 					clients++;
3156 				}
3157 			}
3158 			if (clients == 0) {
3159 				clients = 8;
3160 			}
3161 
3162 			if (oldclients > clients) {
3163 				clients = oldclients;
3164 			}
3165 
3166 			trap_Cvar_Set("sv_maxClients", va("%d",clients));
3167 
3168 			for (i = 0; i < PLAYERS_PER_TEAM; i++) {
3169 				int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
3170 				if (bot > 1) {
3171 					if (ui_actualNetGameType.integer >= GT_TEAM) {
3172 						Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
3173 					} else {
3174 						Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
3175 					}
3176 					trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3177 				}
3178 				bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
3179 				if (bot > 1) {
3180 					if (ui_actualNetGameType.integer >= GT_TEAM) {
3181 						Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
3182 					} else {
3183 						Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
3184 					}
3185 					trap_Cmd_ExecuteText( EXEC_APPEND, buff );
3186 				}
3187 			}
3188 		} else if (Q_stricmp(name, "updateSPMenu") == 0) {
3189 			UI_SetCapFragLimits(qtrue);
3190 			UI_MapCountByGameType(qtrue);
3191 			ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
3192 			trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
3193 			Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
3194 			UI_GameType_HandleKey(0, NULL, K_MOUSE1, qfalse);
3195 			UI_GameType_HandleKey(0, NULL, K_MOUSE2, qfalse);
3196 		} else if (Q_stricmp(name, "resetDefaults") == 0) {
3197 			trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
3198 			trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
3199 			Controls_SetDefaults();
3200 			trap_Cvar_Set("com_introPlayed", "1" );
3201 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
3202 		} else if (Q_stricmp(name, "getCDKey") == 0) {
3203 			char out[17];
3204 			trap_GetCDKey(buff, 17);
3205 			trap_Cvar_Set("cdkey1", "");
3206 			trap_Cvar_Set("cdkey2", "");
3207 			trap_Cvar_Set("cdkey3", "");
3208 			trap_Cvar_Set("cdkey4", "");
3209 			if (strlen(buff) == CDKEY_LEN) {
3210 				Q_strncpyz(out, buff, 5);
3211 				trap_Cvar_Set("cdkey1", out);
3212 				Q_strncpyz(out, buff + 4, 5);
3213 				trap_Cvar_Set("cdkey2", out);
3214 				Q_strncpyz(out, buff + 8, 5);
3215 				trap_Cvar_Set("cdkey3", out);
3216 				Q_strncpyz(out, buff + 12, 5);
3217 				trap_Cvar_Set("cdkey4", out);
3218 			}
3219 
3220 		} else if (Q_stricmp(name, "verifyCDKey") == 0) {
3221 			buff[0] = '\0';
3222 			Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1"));
3223 			Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2"));
3224 			Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3"));
3225 			Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4"));
3226 			trap_Cvar_Set("cdkey", buff);
3227 			if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
3228 				trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
3229 				trap_SetCDKey(buff);
3230 			} else {
3231 				trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
3232 			}
3233 		} else if (Q_stricmp(name, "loadArenas") == 0) {
3234 			UI_LoadArenas();
3235 			UI_MapCountByGameType(qfalse);
3236 			Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
3237 		} else if (Q_stricmp(name, "saveControls") == 0) {
3238 			Controls_SetConfig(qtrue);
3239 		} else if (Q_stricmp(name, "loadControls") == 0) {
3240 			Controls_GetConfig();
3241 		} else if (Q_stricmp(name, "clearError") == 0) {
3242 			trap_Cvar_Set("com_errorMessage", "");
3243 		} else if (Q_stricmp(name, "loadGameInfo") == 0) {
3244 #ifdef PRE_RELEASE_TADEMO
3245 			UI_ParseGameInfo("demogameinfo.txt");
3246 #else
3247 			UI_ParseGameInfo("gameinfo.txt");
3248 #endif
3249 			UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
3250 		} else if (Q_stricmp(name, "resetScores") == 0) {
3251 			UI_ClearScores();
3252 		} else if (Q_stricmp(name, "RefreshServers") == 0) {
3253 			UI_StartServerRefresh(qtrue);
3254 			UI_BuildServerDisplayList(qtrue);
3255 		} else if (Q_stricmp(name, "RefreshFilter") == 0) {
3256 			UI_StartServerRefresh(qfalse);
3257 			UI_BuildServerDisplayList(qtrue);
3258 		} else if (Q_stricmp(name, "RunSPDemo") == 0) {
3259 			if (uiInfo.demoAvailable) {
3260 			  trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
3261 			}
3262 		} else if (Q_stricmp(name, "LoadDemos") == 0) {
3263 			UI_LoadDemos();
3264 		} else if (Q_stricmp(name, "LoadMovies") == 0) {
3265 			UI_LoadMovies();
3266 		} else if (Q_stricmp(name, "LoadMods") == 0) {
3267 			UI_LoadMods();
3268 		} else if (Q_stricmp(name, "playMovie") == 0) {
3269 			if (uiInfo.previewMovie >= 0) {
3270 			  trap_CIN_StopCinematic(uiInfo.previewMovie);
3271 			}
3272 			trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
3273 		} else if (Q_stricmp(name, "RunMod") == 0) {
3274 			trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
3275 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
3276 		} else if (Q_stricmp(name, "RunDemo") == 0) {
3277 			trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
3278 		} else if (Q_stricmp(name, "Quake3") == 0) {
3279 			trap_Cvar_Set( "fs_game", "");
3280 			trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
3281 		} else if (Q_stricmp(name, "closeJoin") == 0) {
3282 			if (uiInfo.serverStatus.refreshActive) {
3283 				UI_StopServerRefresh();
3284 				uiInfo.serverStatus.nextDisplayRefresh = 0;
3285 				uiInfo.nextServerStatusRefresh = 0;
3286 				uiInfo.nextFindPlayerRefresh = 0;
3287 				UI_BuildServerDisplayList(qtrue);
3288 			} else {
3289 				Menus_CloseByName("joinserver");
3290 				Menus_OpenByName("main");
3291 			}
3292 		} else if (Q_stricmp(name, "StopRefresh") == 0) {
3293 			UI_StopServerRefresh();
3294 			uiInfo.serverStatus.nextDisplayRefresh = 0;
3295 			uiInfo.nextServerStatusRefresh = 0;
3296 			uiInfo.nextFindPlayerRefresh = 0;
3297 		} else if (Q_stricmp(name, "UpdateFilter") == 0) {
3298 			if (ui_netSource.integer == AS_LOCAL) {
3299 				UI_StartServerRefresh(qtrue);
3300 			}
3301 			UI_BuildServerDisplayList(qtrue);
3302 			UI_FeederSelection(FEEDER_SERVERS, 0);
3303 		} else if (Q_stricmp(name, "ServerStatus") == 0) {
3304 			trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
3305 			UI_BuildServerStatus(qtrue);
3306 		} else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
3307 			Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
3308 			UI_BuildServerStatus(qtrue);
3309 			Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
3310 		} else if (Q_stricmp(name, "FindPlayer") == 0) {
3311 			UI_BuildFindPlayerList(qtrue);
3312 			// clear the displayed server status info
3313 			uiInfo.serverStatusInfo.numLines = 0;
3314 			Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
3315 		} else if (Q_stricmp(name, "JoinServer") == 0) {
3316 			trap_Cvar_Set("cg_thirdPerson", "0");
3317 			trap_Cvar_Set("cg_cameraOrbit", "0");
3318 			trap_Cvar_Set("ui_singlePlayerActive", "0");
3319 			if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
3320 				trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
3321 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
3322 			}
3323 		} else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
3324 			trap_Cvar_Set("ui_singlePlayerActive", "0");
3325 			if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
3326 				trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
3327 			}
3328 		} else if (Q_stricmp(name, "Quit") == 0) {
3329 			trap_Cvar_Set("ui_singlePlayerActive", "0");
3330 			trap_Cmd_ExecuteText( EXEC_NOW, "quit");
3331 		} else if (Q_stricmp(name, "Controls") == 0) {
3332 		  trap_Cvar_Set( "cl_paused", "1" );
3333 			trap_Key_SetCatcher( KEYCATCH_UI );
3334 			Menus_CloseAll();
3335 			Menus_ActivateByName("setup_menu2");
3336 		} else if (Q_stricmp(name, "Leave") == 0) {
3337 			trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
3338 			trap_Key_SetCatcher( KEYCATCH_UI );
3339 			Menus_CloseAll();
3340 			Menus_ActivateByName("main");
3341 		} else if (Q_stricmp(name, "ServerSort") == 0) {
3342 			int sortColumn;
3343 			if (Int_Parse(args, &sortColumn)) {
3344 				// if same column we're already sorting on then flip the direction
3345 				if (sortColumn == uiInfo.serverStatus.sortKey) {
3346 					uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
3347 				}
3348 				// make sure we sort again
3349 				UI_ServersSort(sortColumn, qtrue);
3350 			}
3351 		} else if (Q_stricmp(name, "nextSkirmish") == 0) {
3352 			UI_StartSkirmish(qtrue);
3353 		} else if (Q_stricmp(name, "SkirmishStart") == 0) {
3354 			UI_StartSkirmish(qfalse);
3355 		} else if (Q_stricmp(name, "closeingame") == 0) {
3356 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3357 			trap_Key_ClearStates();
3358 			trap_Cvar_Set( "cl_paused", "0" );
3359 			Menus_CloseAll();
3360 		} else if (Q_stricmp(name, "voteMap") == 0) {
3361 			if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
3362 				trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
3363 			}
3364 		} else if (Q_stricmp(name, "voteKick") == 0) {
3365 			if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
3366 				trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
3367 			}
3368 		} else if (Q_stricmp(name, "voteGame") == 0) {
3369 			if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
3370 				trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
3371 			}
3372 		} else if (Q_stricmp(name, "voteLeader") == 0) {
3373 			if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
3374 				trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
3375 			}
3376 		} else if (Q_stricmp(name, "addBot") == 0) {
3377 			if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) {
3378 				trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
3379 			} else {
3380 				trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
3381 			}
3382 		} else if (Q_stricmp(name, "addFavorite") == 0) {
3383 			if (ui_netSource.integer != AS_FAVORITES) {
3384 				char name[MAX_NAME_LENGTH];
3385 				char addr[MAX_NAME_LENGTH];
3386 				int res;
3387 
3388 				trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
3389 				name[0] = addr[0] = '\0';
3390 				Q_strncpyz(name, 	Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
3391 				Q_strncpyz(addr, 	Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
3392 				if (strlen(name) > 0 && strlen(addr) > 0) {
3393 					res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
3394 					if (res == 0) {
3395 						// server already in the list
3396 						Com_Printf("Favorite already in list\n");
3397 					}
3398 					else if (res == -1) {
3399 						// list full
3400 						Com_Printf("Favorite list full\n");
3401 					}
3402 					else {
3403 						// successfully added
3404 						Com_Printf("Added favorite server %s\n", addr);
3405 					}
3406 				}
3407 			}
3408 		} else if (Q_stricmp(name, "deleteFavorite") == 0) {
3409 			if (ui_netSource.integer == AS_FAVORITES) {
3410 				char addr[MAX_NAME_LENGTH];
3411 				trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
3412 				addr[0] = '\0';
3413 				Q_strncpyz(addr, 	Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
3414 				if (strlen(addr) > 0) {
3415 					trap_LAN_RemoveServer(AS_FAVORITES, addr);
3416 				}
3417 			}
3418 		} else if (Q_stricmp(name, "createFavorite") == 0) {
3419 			if (ui_netSource.integer == AS_FAVORITES) {
3420 				char name[MAX_NAME_LENGTH];
3421 				char addr[MAX_NAME_LENGTH];
3422 				int res;
3423 
3424 				name[0] = addr[0] = '\0';
3425 				Q_strncpyz(name, 	UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
3426 				Q_strncpyz(addr, 	UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
3427 				if (strlen(name) > 0 && strlen(addr) > 0) {
3428 					res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
3429 					if (res == 0) {
3430 						// server already in the list
3431 						Com_Printf("Favorite already in list\n");
3432 					}
3433 					else if (res == -1) {
3434 						// list full
3435 						Com_Printf("Favorite list full\n");
3436 					}
3437 					else {
3438 						// successfully added
3439 						Com_Printf("Added favorite server %s\n", addr);
3440 					}
3441 				}
3442 			}
3443 		} else if (Q_stricmp(name, "orders") == 0) {
3444 			const char *orders;
3445 			if (String_Parse(args, &orders)) {
3446 				int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3447 				if (selectedPlayer < uiInfo.myTeamCount) {
3448 					strcpy(buff, orders);
3449 					trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
3450 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3451 				} else {
3452 					int i;
3453 					for (i = 0; i < uiInfo.myTeamCount; i++) {
3454 						if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
3455 							continue;
3456 						}
3457 						strcpy(buff, orders);
3458 						trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
3459 						trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3460 					}
3461 				}
3462 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3463 				trap_Key_ClearStates();
3464 				trap_Cvar_Set( "cl_paused", "0" );
3465 				Menus_CloseAll();
3466 			}
3467 		} else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
3468 			const char *orders;
3469 			if (String_Parse(args, &orders)) {
3470 				int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3471 				if (selectedPlayer == uiInfo.myTeamCount) {
3472 					trap_Cmd_ExecuteText( EXEC_APPEND, orders );
3473 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3474 				}
3475 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3476 				trap_Key_ClearStates();
3477 				trap_Cvar_Set( "cl_paused", "0" );
3478 				Menus_CloseAll();
3479 			}
3480 		} else if (Q_stricmp(name, "voiceOrders") == 0) {
3481 			const char *orders;
3482 			if (String_Parse(args, &orders)) {
3483 				int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
3484 				if (selectedPlayer < uiInfo.myTeamCount) {
3485 					strcpy(buff, orders);
3486 					trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
3487 					trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
3488 				}
3489 				trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
3490 				trap_Key_ClearStates();
3491 				trap_Cvar_Set( "cl_paused", "0" );
3492 				Menus_CloseAll();
3493 			}
3494 		} else if (Q_stricmp(name, "glCustom") == 0) {
3495 			trap_Cvar_Set("ui_glCustom", "4");
3496 		} else if (Q_stricmp(name, "update") == 0) {
3497 			if (String_Parse(args, &name2)) {
3498 				UI_Update(name2);
3499 			}
3500 		} else if (Q_stricmp(name, "setPbClStatus") == 0) {
3501 			int stat;
3502 			if ( Int_Parse( args, &stat ) )
3503 				trap_SetPbClStatus( stat );
3504 		}
3505 		else {
3506 			Com_Printf("unknown UI script %s\n", name);
3507 		}
3508 	}
3509 }
3510 
UI_GetTeamColor(vec4_t * color)3511 static void UI_GetTeamColor(vec4_t *color) {
3512 }
3513 
3514 /*
3515 ==================
3516 UI_MapCountByGameType
3517 ==================
3518 */
UI_MapCountByGameType(qboolean singlePlayer)3519 static int UI_MapCountByGameType(qboolean singlePlayer) {
3520 	int i, c, game;
3521 	c = 0;
3522 	game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
3523 	if (game == GT_SINGLE_PLAYER) {
3524 		game++;
3525 	}
3526 	if (game == GT_TEAM) {
3527 		game = GT_FFA;
3528 	}
3529 
3530 	for (i = 0; i < uiInfo.mapCount; i++) {
3531 		uiInfo.mapList[i].active = qfalse;
3532 		if ( uiInfo.mapList[i].typeBits & (1 << game)) {
3533 			if (singlePlayer) {
3534 				if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
3535 					continue;
3536 				}
3537 			}
3538 			c++;
3539 			uiInfo.mapList[i].active = qtrue;
3540 		}
3541 	}
3542 	return c;
3543 }
3544 
UI_hasSkinForBase(const char * base,const char * team)3545 qboolean UI_hasSkinForBase(const char *base, const char *team) {
3546 	char	test[1024];
3547 
3548 	Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
3549 
3550 	if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
3551 		return qtrue;
3552 	}
3553 	Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
3554 
3555 	if (trap_FS_FOpenFile(test, NULL, FS_READ)) {
3556 		return qtrue;
3557 	}
3558 	return qfalse;
3559 }
3560 
3561 /*
3562 ==================
3563 UI_MapCountByTeam
3564 ==================
3565 */
UI_HeadCountByTeam(void)3566 static int UI_HeadCountByTeam(void) {
3567 	static int init = 0;
3568 	int i, j, k, c, tIndex;
3569 
3570 	c = 0;
3571 	if (!init) {
3572 		for (i = 0; i < uiInfo.characterCount; i++) {
3573 			uiInfo.characterList[i].reference = 0;
3574 			for (j = 0; j < uiInfo.teamCount; j++) {
3575 			  if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
3576 					uiInfo.characterList[i].reference |= (1<<j);
3577 			  }
3578 			}
3579 		}
3580 		init = 1;
3581 	}
3582 
3583 	tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
3584 
3585 	// do names
3586 	for (i = 0; i < uiInfo.characterCount; i++) {
3587 		uiInfo.characterList[i].active = qfalse;
3588 		for(j = 0; j < TEAM_MEMBERS; j++) {
3589 			if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
3590 				if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
3591 					uiInfo.characterList[i].active = qtrue;
3592 					c++;
3593 					break;
3594 				}
3595 			}
3596 		}
3597 	}
3598 
3599 	// and then aliases
3600 	for(j = 0; j < TEAM_MEMBERS; j++) {
3601 		for(k = 0; k < uiInfo.aliasCount; k++) {
3602 			if (uiInfo.aliasList[k].name != NULL) {
3603 				if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
3604 					for (i = 0; i < uiInfo.characterCount; i++) {
3605 						if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
3606 							if (uiInfo.characterList[i].active == qfalse) {
3607 								uiInfo.characterList[i].active = qtrue;
3608 								c++;
3609 							}
3610 							break;
3611 						}
3612 					}
3613 				}
3614 			}
3615 		}
3616 	}
3617 	return c;
3618 }
3619 
3620 /*
3621 ==================
3622 UI_InsertServerIntoDisplayList
3623 ==================
3624 */
UI_InsertServerIntoDisplayList(int num,int position)3625 static void UI_InsertServerIntoDisplayList(int num, int position) {
3626 	int i;
3627 
3628 	if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
3629 		return;
3630 	}
3631 	//
3632 	uiInfo.serverStatus.numDisplayServers++;
3633 	for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
3634 		uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
3635 	}
3636 	uiInfo.serverStatus.displayServers[position] = num;
3637 }
3638 
3639 /*
3640 ==================
3641 UI_RemoveServerFromDisplayList
3642 ==================
3643 */
UI_RemoveServerFromDisplayList(int num)3644 static void UI_RemoveServerFromDisplayList(int num) {
3645 	int i, j;
3646 
3647 	for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
3648 		if (uiInfo.serverStatus.displayServers[i] == num) {
3649 			uiInfo.serverStatus.numDisplayServers--;
3650 			for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
3651 				uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
3652 			}
3653 			return;
3654 		}
3655 	}
3656 }
3657 
3658 /*
3659 ==================
3660 UI_BinaryServerInsertion
3661 ==================
3662 */
UI_BinaryServerInsertion(int num)3663 static void UI_BinaryServerInsertion(int num) {
3664 	int mid, offset, res, len;
3665 
3666 	// use binary search to insert server
3667 	len = uiInfo.serverStatus.numDisplayServers;
3668 	mid = len;
3669 	offset = 0;
3670 	res = 0;
3671 	while(mid > 0) {
3672 		mid = len >> 1;
3673 		//
3674 		res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
3675 					uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
3676 		// if equal
3677 		if (res == 0) {
3678 			UI_InsertServerIntoDisplayList(num, offset+mid);
3679 			return;
3680 		}
3681 		// if larger
3682 		else if (res == 1) {
3683 			offset += mid;
3684 			len -= mid;
3685 		}
3686 		// if smaller
3687 		else {
3688 			len -= mid;
3689 		}
3690 	}
3691 	if (res == 1) {
3692 		offset++;
3693 	}
3694 	UI_InsertServerIntoDisplayList(num, offset);
3695 }
3696 
3697 /*
3698 ==================
3699 UI_BuildServerDisplayList
3700 ==================
3701 */
UI_BuildServerDisplayList(qboolean force)3702 static void UI_BuildServerDisplayList(qboolean force) {
3703 	int i, count, clients, maxClients, ping, game, len, visible;
3704 	char info[MAX_STRING_CHARS];
3705 //	qboolean startRefresh = qtrue; TTimo: unused
3706 	static int numinvisible;
3707 
3708 	if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
3709 		return;
3710 	}
3711 	// if we shouldn't reset
3712 	if ( force == 2 ) {
3713 		force = 0;
3714 	}
3715 
3716 	// do motd updates here too
3717 	trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
3718 	len = strlen(uiInfo.serverStatus.motd);
3719 	if (len == 0) {
3720 		strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
3721 		len = strlen(uiInfo.serverStatus.motd);
3722 	}
3723 	if (len != uiInfo.serverStatus.motdLen) {
3724 		uiInfo.serverStatus.motdLen = len;
3725 		uiInfo.serverStatus.motdWidth = -1;
3726 	}
3727 
3728 	if (force) {
3729 		numinvisible = 0;
3730 		// clear number of displayed servers
3731 		uiInfo.serverStatus.numDisplayServers = 0;
3732 		uiInfo.serverStatus.numPlayersOnServers = 0;
3733 		// set list box index to zero
3734 		Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
3735 		// mark all servers as visible so we store ping updates for them
3736 		trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
3737 	}
3738 
3739 	// get the server count (comes from the master)
3740 	count = trap_LAN_GetServerCount(ui_netSource.integer);
3741 	if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
3742 		// still waiting on a response from the master
3743 		uiInfo.serverStatus.numDisplayServers = 0;
3744 		uiInfo.serverStatus.numPlayersOnServers = 0;
3745 		uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
3746 		return;
3747 	}
3748 
3749 	visible = qfalse;
3750 	for (i = 0; i < count; i++) {
3751 		// if we already got info for this server
3752 		if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
3753 			continue;
3754 		}
3755 		visible = qtrue;
3756 		// get the ping for this server
3757 		ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
3758 		if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
3759 
3760 			trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
3761 
3762 			clients = atoi(Info_ValueForKey(info, "clients"));
3763 			uiInfo.serverStatus.numPlayersOnServers += clients;
3764 
3765 			if (ui_browserShowEmpty.integer == 0) {
3766 				if (clients == 0) {
3767 					trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3768 					continue;
3769 				}
3770 			}
3771 
3772 			if (ui_browserShowFull.integer == 0) {
3773 				maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
3774 				if (clients == maxClients) {
3775 					trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3776 					continue;
3777 				}
3778 			}
3779 
3780 			if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
3781 				game = atoi(Info_ValueForKey(info, "gametype"));
3782 				if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
3783 					trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3784 					continue;
3785 				}
3786 			}
3787 
3788 			if (ui_serverFilterType.integer > 0) {
3789 				if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
3790 					trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3791 					continue;
3792 				}
3793 			}
3794 			// make sure we never add a favorite server twice
3795 			if (ui_netSource.integer == AS_FAVORITES) {
3796 				UI_RemoveServerFromDisplayList(i);
3797 			}
3798 			// insert the server into the list
3799 			UI_BinaryServerInsertion(i);
3800 			// done with this server
3801 			if (ping > 0) {
3802 				trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
3803 				numinvisible++;
3804 			}
3805 		}
3806 	}
3807 
3808 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
3809 
3810 	// if there were no servers visible for ping updates
3811 	if (!visible) {
3812 //		UI_StopServerRefresh();
3813 //		uiInfo.serverStatus.nextDisplayRefresh = 0;
3814 	}
3815 }
3816 
3817 typedef struct
3818 {
3819 	char *name, *altName;
3820 } serverStatusCvar_t;
3821 
3822 serverStatusCvar_t serverStatusCvars[] = {
3823 	{"sv_hostname", "Name"},
3824 	{"Address", ""},
3825 	{"gamename", "Game name"},
3826 	{"g_gametype", "Game type"},
3827 	{"mapname", "Map"},
3828 	{"version", ""},
3829 	{"protocol", ""},
3830 	{"timelimit", ""},
3831 	{"fraglimit", ""},
3832 	{NULL, NULL}
3833 };
3834 
3835 /*
3836 ==================
3837 UI_SortServerStatusInfo
3838 ==================
3839 */
UI_SortServerStatusInfo(serverStatusInfo_t * info)3840 static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
3841 	int i, j, index;
3842 	char *tmp1, *tmp2;
3843 
3844 	// FIXME: if "gamename" == "baseq3" or "missionpack" then
3845 	// replace the gametype number by FFA, CTF etc.
3846 	//
3847 	index = 0;
3848 	for (i = 0; serverStatusCvars[i].name; i++) {
3849 		for (j = 0; j < info->numLines; j++) {
3850 			if ( !info->lines[j][1] || info->lines[j][1][0] ) {
3851 				continue;
3852 			}
3853 			if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
3854 				// swap lines
3855 				tmp1 = info->lines[index][0];
3856 				tmp2 = info->lines[index][3];
3857 				info->lines[index][0] = info->lines[j][0];
3858 				info->lines[index][3] = info->lines[j][3];
3859 				info->lines[j][0] = tmp1;
3860 				info->lines[j][3] = tmp2;
3861 				//
3862 				if ( strlen(serverStatusCvars[i].altName) ) {
3863 					info->lines[index][0] = serverStatusCvars[i].altName;
3864 				}
3865 				index++;
3866 			}
3867 		}
3868 	}
3869 }
3870 
3871 /*
3872 ==================
3873 UI_GetServerStatusInfo
3874 ==================
3875 */
UI_GetServerStatusInfo(const char * serverAddress,serverStatusInfo_t * info)3876 static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
3877 	char *p, *score, *ping, *name;
3878 	int i, len;
3879 
3880 	if (!info) {
3881 		trap_LAN_ServerStatus( serverAddress, NULL, 0);
3882 		return qfalse;
3883 	}
3884 	memset(info, 0, sizeof(*info));
3885 	if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
3886 		Q_strncpyz(info->address, serverAddress, sizeof(info->address));
3887 		p = info->text;
3888 		info->numLines = 0;
3889 		info->lines[info->numLines][0] = "Address";
3890 		info->lines[info->numLines][1] = "";
3891 		info->lines[info->numLines][2] = "";
3892 		info->lines[info->numLines][3] = info->address;
3893 		info->numLines++;
3894 		// get the cvars
3895 		while (p && *p) {
3896 			p = strchr(p, '\\');
3897 			if (!p) break;
3898 			*p++ = '\0';
3899 			if (*p == '\\')
3900 				break;
3901 			info->lines[info->numLines][0] = p;
3902 			info->lines[info->numLines][1] = "";
3903 			info->lines[info->numLines][2] = "";
3904 			p = strchr(p, '\\');
3905 			if (!p) break;
3906 			*p++ = '\0';
3907 			info->lines[info->numLines][3] = p;
3908 
3909 			info->numLines++;
3910 			if (info->numLines >= MAX_SERVERSTATUS_LINES)
3911 				break;
3912 		}
3913 		// get the player list
3914 		if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
3915 			// empty line
3916 			info->lines[info->numLines][0] = "";
3917 			info->lines[info->numLines][1] = "";
3918 			info->lines[info->numLines][2] = "";
3919 			info->lines[info->numLines][3] = "";
3920 			info->numLines++;
3921 			// header
3922 			info->lines[info->numLines][0] = "num";
3923 			info->lines[info->numLines][1] = "score";
3924 			info->lines[info->numLines][2] = "ping";
3925 			info->lines[info->numLines][3] = "name";
3926 			info->numLines++;
3927 			// parse players
3928 			i = 0;
3929 			len = 0;
3930 			while (p && *p) {
3931 				if (*p == '\\')
3932 					*p++ = '\0';
3933 				if (!p)
3934 					break;
3935 				score = p;
3936 				p = strchr(p, ' ');
3937 				if (!p)
3938 					break;
3939 				*p++ = '\0';
3940 				ping = p;
3941 				p = strchr(p, ' ');
3942 				if (!p)
3943 					break;
3944 				*p++ = '\0';
3945 				name = p;
3946 				Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
3947 				info->lines[info->numLines][0] = &info->pings[len];
3948 				len += strlen(&info->pings[len]) + 1;
3949 				info->lines[info->numLines][1] = score;
3950 				info->lines[info->numLines][2] = ping;
3951 				info->lines[info->numLines][3] = name;
3952 				info->numLines++;
3953 				if (info->numLines >= MAX_SERVERSTATUS_LINES)
3954 					break;
3955 				p = strchr(p, '\\');
3956 				if (!p)
3957 					break;
3958 				*p++ = '\0';
3959 				//
3960 				i++;
3961 			}
3962 		}
3963 		UI_SortServerStatusInfo( info );
3964 		return qtrue;
3965 	}
3966 	return qfalse;
3967 }
3968 
3969 /*
3970 ==================
3971 stristr
3972 ==================
3973 */
stristr(char * str,char * charset)3974 static char *stristr(char *str, char *charset) {
3975 	int i;
3976 
3977 	while(*str) {
3978 		for (i = 0; charset[i] && str[i]; i++) {
3979 			if (toupper(charset[i]) != toupper(str[i])) break;
3980 		}
3981 		if (!charset[i]) return str;
3982 		str++;
3983 	}
3984 	return NULL;
3985 }
3986 
3987 /*
3988 ==================
3989 UI_BuildFindPlayerList
3990 ==================
3991 */
UI_BuildFindPlayerList(qboolean force)3992 static void UI_BuildFindPlayerList(qboolean force) {
3993 	static int numFound, numTimeOuts;
3994 	int i, j, resend;
3995 	serverStatusInfo_t info;
3996 	char name[MAX_NAME_LENGTH+2];
3997 	char infoString[MAX_STRING_CHARS];
3998 
3999 	if (!force) {
4000 		if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
4001 			return;
4002 		}
4003 	}
4004 	else {
4005 		memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
4006 		uiInfo.numFoundPlayerServers = 0;
4007 		uiInfo.currentFoundPlayerServer = 0;
4008 		trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
4009 		Q_CleanStr(uiInfo.findPlayerName);
4010 		// should have a string of some length
4011 		if (!strlen(uiInfo.findPlayerName)) {
4012 			uiInfo.nextFindPlayerRefresh = 0;
4013 			return;
4014 		}
4015 		// set resend time
4016 		resend = ui_serverStatusTimeOut.integer / 2 - 10;
4017 		if (resend < 50) {
4018 			resend = 50;
4019 		}
4020 		trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
4021 		// reset all server status requests
4022 		trap_LAN_ServerStatus( NULL, NULL, 0);
4023 		//
4024 		uiInfo.numFoundPlayerServers = 1;
4025 		Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4026 						sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4027 							"searching %d...", uiInfo.pendingServerStatus.num);
4028 		numFound = 0;
4029 		numTimeOuts++;
4030 	}
4031 	for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
4032 		// if this pending server is valid
4033 		if (uiInfo.pendingServerStatus.server[i].valid) {
4034 			// try to get the server status for this server
4035 			if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
4036 				//
4037 				numFound++;
4038 				// parse through the server status lines
4039 				for (j = 0; j < info.numLines; j++) {
4040 					// should have ping info
4041 					if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
4042 						continue;
4043 					}
4044 					// clean string first
4045 					Q_strncpyz(name, info.lines[j][3], sizeof(name));
4046 					Q_CleanStr(name);
4047 					// if the player name is a substring
4048 					if (stristr(name, uiInfo.findPlayerName)) {
4049 						// add to found server list if we have space (always leave space for a line with the number found)
4050 						if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
4051 							//
4052 							Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
4053 										uiInfo.pendingServerStatus.server[i].adrstr,
4054 											sizeof(uiInfo.foundPlayerServerAddresses[0]));
4055 							Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4056 										uiInfo.pendingServerStatus.server[i].name,
4057 											sizeof(uiInfo.foundPlayerServerNames[0]));
4058 							uiInfo.numFoundPlayerServers++;
4059 						}
4060 						else {
4061 							// can't add any more so we're done
4062 							uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
4063 						}
4064 					}
4065 				}
4066 				Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4067 								sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4068 									"searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
4069 				// retrieved the server status so reuse this spot
4070 				uiInfo.pendingServerStatus.server[i].valid = qfalse;
4071 			}
4072 		}
4073 		// if empty pending slot or timed out
4074 		if (!uiInfo.pendingServerStatus.server[i].valid ||
4075 			uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
4076 			if (uiInfo.pendingServerStatus.server[i].valid) {
4077 				numTimeOuts++;
4078 			}
4079 			// reset server status request for this address
4080 			UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
4081 			// reuse pending slot
4082 			uiInfo.pendingServerStatus.server[i].valid = qfalse;
4083 			// if we didn't try to get the status of all servers in the main browser yet
4084 			if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
4085 				uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
4086 				trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
4087 							uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
4088 				trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
4089 				Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
4090 				uiInfo.pendingServerStatus.server[i].valid = qtrue;
4091 				uiInfo.pendingServerStatus.num++;
4092 				Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
4093 								sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
4094 									"searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
4095 			}
4096 		}
4097 	}
4098 	for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
4099 		if (uiInfo.pendingServerStatus.server[i].valid) {
4100 			break;
4101 		}
4102 	}
4103 	// if still trying to retrieve server status info
4104 	if (i < MAX_SERVERSTATUSREQUESTS) {
4105 		uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
4106 	}
4107 	else {
4108 		// add a line that shows the number of servers found
4109 		if (!uiInfo.numFoundPlayerServers) {
4110 			Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
4111 		}
4112 		else {
4113 			Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
4114 						"%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
4115 						uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
4116 		}
4117 		uiInfo.nextFindPlayerRefresh = 0;
4118 		// show the server status info for the selected server
4119 		UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
4120 	}
4121 }
4122 
4123 /*
4124 ==================
4125 UI_BuildServerStatus
4126 ==================
4127 */
UI_BuildServerStatus(qboolean force)4128 static void UI_BuildServerStatus(qboolean force) {
4129 
4130 	if (uiInfo.nextFindPlayerRefresh) {
4131 		return;
4132 	}
4133 	if (!force) {
4134 		if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
4135 			return;
4136 		}
4137 	}
4138 	else {
4139 		Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
4140 		uiInfo.serverStatusInfo.numLines = 0;
4141 		// reset all server status requests
4142 		trap_LAN_ServerStatus( NULL, NULL, 0);
4143 	}
4144 	if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
4145 		return;
4146 	}
4147 	if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
4148 		uiInfo.nextServerStatusRefresh = 0;
4149 		UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
4150 	}
4151 	else {
4152 		uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
4153 	}
4154 }
4155 
4156 /*
4157 ==================
4158 UI_FeederCount
4159 ==================
4160 */
UI_FeederCount(float feederID)4161 static int UI_FeederCount(float feederID) {
4162 	if (feederID == FEEDER_HEADS) {
4163 		return UI_HeadCountByTeam();
4164 	} else if (feederID == FEEDER_Q3HEADS) {
4165 		return uiInfo.q3HeadCount;
4166 	} else if (feederID == FEEDER_CINEMATICS) {
4167 		return uiInfo.movieCount;
4168 	} else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4169 		return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
4170 	} else if (feederID == FEEDER_SERVERS) {
4171 		return uiInfo.serverStatus.numDisplayServers;
4172 	} else if (feederID == FEEDER_SERVERSTATUS) {
4173 		return uiInfo.serverStatusInfo.numLines;
4174 	} else if (feederID == FEEDER_FINDPLAYER) {
4175 		return uiInfo.numFoundPlayerServers;
4176 	} else if (feederID == FEEDER_PLAYER_LIST) {
4177 		if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
4178 			uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
4179 			UI_BuildPlayerList();
4180 		}
4181 		return uiInfo.playerCount;
4182 	} else if (feederID == FEEDER_TEAM_LIST) {
4183 		if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
4184 			uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
4185 			UI_BuildPlayerList();
4186 		}
4187 		return uiInfo.myTeamCount;
4188 	} else if (feederID == FEEDER_MODS) {
4189 		return uiInfo.modCount;
4190 	} else if (feederID == FEEDER_DEMOS) {
4191 		return uiInfo.demoCount;
4192 	}
4193 	return 0;
4194 }
4195 
UI_SelectedMap(int index,int * actual)4196 static const char *UI_SelectedMap(int index, int *actual) {
4197 	int i, c;
4198 	c = 0;
4199 	*actual = 0;
4200 	for (i = 0; i < uiInfo.mapCount; i++) {
4201 		if (uiInfo.mapList[i].active) {
4202 			if (c == index) {
4203 				*actual = i;
4204 				return uiInfo.mapList[i].mapName;
4205 			} else {
4206 				c++;
4207 			}
4208 		}
4209 	}
4210 	return "";
4211 }
4212 
UI_SelectedHead(int index,int * actual)4213 static const char *UI_SelectedHead(int index, int *actual) {
4214 	int i, c;
4215 	c = 0;
4216 	*actual = 0;
4217 	for (i = 0; i < uiInfo.characterCount; i++) {
4218 		if (uiInfo.characterList[i].active) {
4219 			if (c == index) {
4220 				*actual = i;
4221 				return uiInfo.characterList[i].name;
4222 			} else {
4223 				c++;
4224 			}
4225 		}
4226 	}
4227 	return "";
4228 }
4229 
UI_GetIndexFromSelection(int actual)4230 static int UI_GetIndexFromSelection(int actual) {
4231 	int i, c;
4232 	c = 0;
4233 	for (i = 0; i < uiInfo.mapCount; i++) {
4234 		if (uiInfo.mapList[i].active) {
4235 			if (i == actual) {
4236 				return c;
4237 			}
4238 				c++;
4239 		}
4240 	}
4241   return 0;
4242 }
4243 
UI_UpdatePendingPings(void)4244 static void UI_UpdatePendingPings( void ) {
4245 	trap_LAN_ResetPings(ui_netSource.integer);
4246 	uiInfo.serverStatus.refreshActive = qtrue;
4247 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
4248 
4249 }
4250 
UI_FeederItemText(float feederID,int index,int column,qhandle_t * handle)4251 static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
4252 	static char info[MAX_STRING_CHARS];
4253 	static char hostname[1024];
4254 	static char clientBuff[32];
4255 	static int lastColumn = -1;
4256 	static int lastTime = 0;
4257 	*handle = -1;
4258 	if (feederID == FEEDER_HEADS) {
4259 		int actual;
4260 		return UI_SelectedHead(index, &actual);
4261 	} else if (feederID == FEEDER_Q3HEADS) {
4262 		if (index >= 0 && index < uiInfo.q3HeadCount) {
4263 			return uiInfo.q3HeadNames[index];
4264 		}
4265 	} else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4266 		int actual;
4267 		return UI_SelectedMap(index, &actual);
4268 	} else if (feederID == FEEDER_SERVERS) {
4269 		if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
4270 			int ping, game, punkbuster;
4271 			if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
4272 				trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
4273 				lastColumn = column;
4274 				lastTime = uiInfo.uiDC.realTime;
4275 			}
4276 			ping = atoi(Info_ValueForKey(info, "ping"));
4277 			if (ping == -1) {
4278 				// if we ever see a ping that is out of date, do a server refresh
4279 				// UI_UpdatePendingPings();
4280 			}
4281 			switch (column) {
4282 				case SORT_HOST :
4283 					if (ping <= 0) {
4284 						return Info_ValueForKey(info, "addr");
4285 					} else {
4286 						if ( ui_netSource.integer == AS_LOCAL ) {
4287 							int nettype = atoi(Info_ValueForKey(info, "nettype"));
4288 
4289 							if (nettype < 0 || nettype >= ARRAY_LEN(netnames)) {
4290 								nettype = 0;
4291 							}
4292 
4293 							Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
4294 											Info_ValueForKey(info, "hostname"),
4295 											netnames[nettype] );
4296 							return hostname;
4297 						}
4298 						else {
4299 							Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
4300 							return hostname;
4301 						}
4302 					}
4303 				case SORT_MAP : return Info_ValueForKey(info, "mapname");
4304 				case SORT_CLIENTS :
4305 					Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
4306 					return clientBuff;
4307 				case SORT_GAME :
4308 					game = atoi(Info_ValueForKey(info, "gametype"));
4309 					if (game >= 0 && game < numTeamArenaGameTypes) {
4310 						return teamArenaGameTypes[game];
4311 					} else {
4312 						return "Unknown";
4313 					}
4314 				case SORT_PING :
4315 					if (ping <= 0) {
4316 						return "...";
4317 					} else {
4318 						return Info_ValueForKey(info, "ping");
4319 					}
4320 				case SORT_PUNKBUSTER:
4321 					punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
4322 					if ( punkbuster ) {
4323 						return "Yes";
4324 					} else {
4325 						return "No";
4326 					}
4327 			}
4328 		}
4329 	} else if (feederID == FEEDER_SERVERSTATUS) {
4330 		if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
4331 			if ( column >= 0 && column < 4 ) {
4332 				return uiInfo.serverStatusInfo.lines[index][column];
4333 			}
4334 		}
4335 	} else if (feederID == FEEDER_FINDPLAYER) {
4336 		if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
4337 			//return uiInfo.foundPlayerServerAddresses[index];
4338 			return uiInfo.foundPlayerServerNames[index];
4339 		}
4340 	} else if (feederID == FEEDER_PLAYER_LIST) {
4341 		if (index >= 0 && index < uiInfo.playerCount) {
4342 			return uiInfo.playerNames[index];
4343 		}
4344 	} else if (feederID == FEEDER_TEAM_LIST) {
4345 		if (index >= 0 && index < uiInfo.myTeamCount) {
4346 			return uiInfo.teamNames[index];
4347 		}
4348 	} else if (feederID == FEEDER_MODS) {
4349 		if (index >= 0 && index < uiInfo.modCount) {
4350 			if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
4351 				return uiInfo.modList[index].modDescr;
4352 			} else {
4353 				return uiInfo.modList[index].modName;
4354 			}
4355 		}
4356 	} else if (feederID == FEEDER_CINEMATICS) {
4357 		if (index >= 0 && index < uiInfo.movieCount) {
4358 			return uiInfo.movieList[index];
4359 		}
4360 	} else if (feederID == FEEDER_DEMOS) {
4361 		if (index >= 0 && index < uiInfo.demoCount) {
4362 			return uiInfo.demoList[index];
4363 		}
4364 	}
4365 	return "";
4366 }
4367 
4368 
UI_FeederItemImage(float feederID,int index)4369 static qhandle_t UI_FeederItemImage(float feederID, int index) {
4370   if (feederID == FEEDER_HEADS) {
4371 	int actual;
4372 	UI_SelectedHead(index, &actual);
4373 	index = actual;
4374 	if (index >= 0 && index < uiInfo.characterCount) {
4375 		if (uiInfo.characterList[index].headImage == -1) {
4376 			uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
4377 		}
4378 		return uiInfo.characterList[index].headImage;
4379 	}
4380   } else if (feederID == FEEDER_Q3HEADS) {
4381     if (index >= 0 && index < uiInfo.q3HeadCount) {
4382       return uiInfo.q3HeadIcons[index];
4383     }
4384 	} else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
4385 		int actual;
4386 		UI_SelectedMap(index, &actual);
4387 		index = actual;
4388 		if (index >= 0 && index < uiInfo.mapCount) {
4389 			if (uiInfo.mapList[index].levelShot == -1) {
4390 				uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
4391 			}
4392 			return uiInfo.mapList[index].levelShot;
4393 		}
4394 	}
4395   return 0;
4396 }
4397 
UI_FeederSelection(float feederID,int index)4398 static void UI_FeederSelection(float feederID, int index) {
4399 	static char info[MAX_STRING_CHARS];
4400   if (feederID == FEEDER_HEADS) {
4401 	int actual;
4402 	UI_SelectedHead(index, &actual);
4403 	index = actual;
4404     if (index >= 0 && index < uiInfo.characterCount) {
4405 		trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
4406 		trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name));
4407 		updateModel = qtrue;
4408     }
4409   } else if (feederID == FEEDER_Q3HEADS) {
4410     if (index >= 0 && index < uiInfo.q3HeadCount) {
4411       trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
4412       trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
4413 			updateModel = qtrue;
4414 		}
4415   } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
4416 		int actual, map;
4417 		map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
4418 		if (uiInfo.mapList[map].cinematic >= 0) {
4419 		  trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
4420 		  uiInfo.mapList[map].cinematic = -1;
4421 		}
4422 		UI_SelectedMap(index, &actual);
4423 		trap_Cvar_Set("ui_mapIndex", va("%d", index));
4424 		ui_mapIndex.integer = index;
4425 
4426 		if (feederID == FEEDER_MAPS) {
4427 			ui_currentMap.integer = actual;
4428 			trap_Cvar_Set("ui_currentMap", va("%d", actual));
4429 	  	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) );
4430 			UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
4431 			trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
4432 			updateOpponentModel = qtrue;
4433 		} else {
4434 			ui_currentNetMap.integer = actual;
4435 			trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
4436 	  	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) );
4437 		}
4438 
4439   } else if (feederID == FEEDER_SERVERS) {
4440 		const char *mapName = NULL;
4441 		uiInfo.serverStatus.currentServer = index;
4442 		trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
4443 		uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
4444 		if (uiInfo.serverStatus.currentServerCinematic >= 0) {
4445 		  trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
4446 			uiInfo.serverStatus.currentServerCinematic = -1;
4447 		}
4448 		mapName = Info_ValueForKey(info, "mapname");
4449 		if (mapName && *mapName) {
4450 			uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
4451 		}
4452   } else if (feederID == FEEDER_SERVERSTATUS) {
4453 		//
4454   } else if (feederID == FEEDER_FINDPLAYER) {
4455 	  uiInfo.currentFoundPlayerServer = index;
4456 	  //
4457 	  if ( index < uiInfo.numFoundPlayerServers-1) {
4458 			// build a new server status for this server
4459 			Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
4460 			Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
4461 			UI_BuildServerStatus(qtrue);
4462 	  }
4463   } else if (feederID == FEEDER_PLAYER_LIST) {
4464 		uiInfo.playerIndex = index;
4465   } else if (feederID == FEEDER_TEAM_LIST) {
4466 		uiInfo.teamIndex = index;
4467   } else if (feederID == FEEDER_MODS) {
4468 		uiInfo.modIndex = index;
4469   } else if (feederID == FEEDER_CINEMATICS) {
4470 		uiInfo.movieIndex = index;
4471 		if (uiInfo.previewMovie >= 0) {
4472 		  trap_CIN_StopCinematic(uiInfo.previewMovie);
4473 		}
4474 		uiInfo.previewMovie = -1;
4475   } else if (feederID == FEEDER_DEMOS) {
4476 		uiInfo.demoIndex = index;
4477 	}
4478 }
4479 
Team_Parse(char ** p)4480 static qboolean Team_Parse(char **p) {
4481   char *token;
4482   const char *tempStr;
4483 	int i;
4484 
4485   token = COM_ParseExt(p, qtrue);
4486 
4487   if (token[0] != '{') {
4488     return qfalse;
4489   }
4490 
4491   while ( 1 ) {
4492 
4493     token = COM_ParseExt(p, qtrue);
4494 
4495     if (Q_stricmp(token, "}") == 0) {
4496       return qtrue;
4497     }
4498 
4499     if ( !token || token[0] == 0 ) {
4500       return qfalse;
4501     }
4502 
4503     if (token[0] == '{') {
4504       // seven tokens per line, team name and icon, and 5 team member names
4505       if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
4506         return qfalse;
4507       }
4508 
4509 
4510 			uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
4511 	    uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
4512 		  uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
4513 			uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
4514 
4515 			uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
4516 
4517 			for (i = 0; i < TEAM_MEMBERS; i++) {
4518 				uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
4519 				if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
4520 					return qfalse;
4521 				}
4522 			}
4523 
4524       Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
4525       if (uiInfo.teamCount < MAX_TEAMS) {
4526         uiInfo.teamCount++;
4527       } else {
4528         Com_Printf("Too many teams, last team replaced!\n");
4529       }
4530       token = COM_ParseExt(p, qtrue);
4531       if (token[0] != '}') {
4532         return qfalse;
4533       }
4534     }
4535   }
4536 
4537   return qfalse;
4538 }
4539 
Character_Parse(char ** p)4540 static qboolean Character_Parse(char **p) {
4541   char *token;
4542   const char *tempStr;
4543 
4544   token = COM_ParseExt(p, qtrue);
4545 
4546   if (token[0] != '{') {
4547     return qfalse;
4548   }
4549 
4550 
4551   while ( 1 ) {
4552     token = COM_ParseExt(p, qtrue);
4553 
4554     if (Q_stricmp(token, "}") == 0) {
4555       return qtrue;
4556     }
4557 
4558     if ( !token || token[0] == 0 ) {
4559       return qfalse;
4560     }
4561 
4562     if (token[0] == '{') {
4563       // two tokens per line, character name and sex
4564       if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
4565         return qfalse;
4566       }
4567 
4568       uiInfo.characterList[uiInfo.characterCount].headImage = -1;
4569 			uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
4570 
4571 	  if (tempStr && (!Q_stricmp(tempStr, "female"))) {
4572         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Janet"));
4573       } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
4574         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("James"));
4575 	  } else {
4576         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
4577 	  }
4578 
4579       Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
4580       if (uiInfo.characterCount < MAX_HEADS) {
4581         uiInfo.characterCount++;
4582       } else {
4583         Com_Printf("Too many characters, last character replaced!\n");
4584       }
4585 
4586       token = COM_ParseExt(p, qtrue);
4587       if (token[0] != '}') {
4588         return qfalse;
4589       }
4590     }
4591   }
4592 
4593   return qfalse;
4594 }
4595 
4596 
Alias_Parse(char ** p)4597 static qboolean Alias_Parse(char **p) {
4598   char *token;
4599 
4600   token = COM_ParseExt(p, qtrue);
4601 
4602   if (token[0] != '{') {
4603     return qfalse;
4604   }
4605 
4606   while ( 1 ) {
4607     token = COM_ParseExt(p, qtrue);
4608 
4609     if (Q_stricmp(token, "}") == 0) {
4610       return qtrue;
4611     }
4612 
4613     if ( !token || token[0] == 0 ) {
4614       return qfalse;
4615     }
4616 
4617     if (token[0] == '{') {
4618       // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
4619       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)) {
4620         return qfalse;
4621       }
4622 
4623       Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
4624       if (uiInfo.aliasCount < MAX_ALIASES) {
4625         uiInfo.aliasCount++;
4626       } else {
4627         Com_Printf("Too many aliases, last alias replaced!\n");
4628       }
4629 
4630       token = COM_ParseExt(p, qtrue);
4631       if (token[0] != '}') {
4632         return qfalse;
4633       }
4634     }
4635   }
4636 
4637   return qfalse;
4638 }
4639 
4640 
4641 
4642 // mode
4643 // 0 - high level parsing
4644 // 1 - team parsing
4645 // 2 - character parsing
UI_ParseTeamInfo(const char * teamFile)4646 static void UI_ParseTeamInfo(const char *teamFile) {
4647 	char	*token;
4648   char *p;
4649   char *buff = NULL;
4650   //static int mode = 0; TTimo: unused
4651 
4652   buff = GetMenuBuffer(teamFile);
4653   if (!buff) {
4654     return;
4655   }
4656 
4657   p = buff;
4658 
4659 	while ( 1 ) {
4660 		token = COM_ParseExt( &p, qtrue );
4661 		if( !token || token[0] == 0 || token[0] == '}') {
4662 			break;
4663 		}
4664 
4665 		if ( Q_stricmp( token, "}" ) == 0 ) {
4666       break;
4667     }
4668 
4669     if (Q_stricmp(token, "teams") == 0) {
4670 
4671       if (Team_Parse(&p)) {
4672         continue;
4673       } else {
4674         break;
4675       }
4676     }
4677 
4678     if (Q_stricmp(token, "characters") == 0) {
4679       Character_Parse(&p);
4680     }
4681 
4682     if (Q_stricmp(token, "aliases") == 0) {
4683       Alias_Parse(&p);
4684     }
4685 
4686   }
4687 
4688 }
4689 
4690 
GameType_Parse(char ** p,qboolean join)4691 static qboolean GameType_Parse(char **p, qboolean join) {
4692 	char *token;
4693 
4694 	token = COM_ParseExt(p, qtrue);
4695 
4696 	if (token[0] != '{') {
4697 		return qfalse;
4698 	}
4699 
4700 	if (join) {
4701 		uiInfo.numJoinGameTypes = 0;
4702 	} else {
4703 		uiInfo.numGameTypes = 0;
4704 	}
4705 
4706 	while ( 1 ) {
4707 		token = COM_ParseExt(p, qtrue);
4708 
4709 		if (Q_stricmp(token, "}") == 0) {
4710 			return qtrue;
4711 		}
4712 
4713 		if ( !token || token[0] == 0 ) {
4714 			return qfalse;
4715 		}
4716 
4717 		if (token[0] == '{') {
4718 			// two tokens per line, character name and sex
4719 			if (join) {
4720 				if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
4721 					return qfalse;
4722 				}
4723 			} else {
4724 				if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
4725 					return qfalse;
4726 				}
4727 			}
4728 
4729 			if (join) {
4730 				if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
4731 					uiInfo.numJoinGameTypes++;
4732 				} else {
4733 					Com_Printf("Too many net game types, last one replace!\n");
4734 				}
4735 			} else {
4736 				if (uiInfo.numGameTypes < MAX_GAMETYPES) {
4737 					uiInfo.numGameTypes++;
4738 				} else {
4739 					Com_Printf("Too many game types, last one replace!\n");
4740 				}
4741 			}
4742 
4743 			token = COM_ParseExt(p, qtrue);
4744 			if (token[0] != '}') {
4745 				return qfalse;
4746 			}
4747 		}
4748 	}
4749 	return qfalse;
4750 }
4751 
MapList_Parse(char ** p)4752 static qboolean MapList_Parse(char **p) {
4753 	char *token;
4754 
4755 	token = COM_ParseExt(p, qtrue);
4756 
4757 	if (token[0] != '{') {
4758 		return qfalse;
4759 	}
4760 
4761 	uiInfo.mapCount = 0;
4762 
4763 	while ( 1 ) {
4764 		token = COM_ParseExt(p, qtrue);
4765 
4766 		if (Q_stricmp(token, "}") == 0) {
4767 			return qtrue;
4768 		}
4769 
4770 		if ( !token || token[0] == 0 ) {
4771 			return qfalse;
4772 		}
4773 
4774 		if (token[0] == '{') {
4775 			if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName)
4776 				||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
4777 				return qfalse;
4778 			}
4779 
4780 			if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
4781 				return qfalse;
4782 			}
4783 
4784 			uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
4785 
4786 			while (1) {
4787 				token = COM_ParseExt(p, qtrue);
4788 				if (token[0] >= '0' && token[0] <= '9') {
4789 					uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
4790 					if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
4791 						return qfalse;
4792 					}
4793 				} else {
4794 					break;
4795 				}
4796 			}
4797 
4798 			//mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
4799 			//if (uiInfo.mapCount == 0) {
4800 			  // only load the first cinematic, selection loads the others
4801   			//  uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
4802 			//}
4803   		uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
4804 			uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
4805 
4806 			if (uiInfo.mapCount < MAX_MAPS) {
4807 				uiInfo.mapCount++;
4808 			} else {
4809 				Com_Printf("Too many maps, last one replaced!\n");
4810 			}
4811 		}
4812 	}
4813 	return qfalse;
4814 }
4815 
UI_ParseGameInfo(const char * teamFile)4816 static void UI_ParseGameInfo(const char *teamFile) {
4817 	char	*token;
4818 	char *p;
4819 	char *buff = NULL;
4820 	//int mode = 0; TTimo: unused
4821 
4822 	buff = GetMenuBuffer(teamFile);
4823 	if (!buff) {
4824 		return;
4825 	}
4826 
4827 	p = buff;
4828 
4829 	while ( 1 ) {
4830 		token = COM_ParseExt( &p, qtrue );
4831 		if( !token || token[0] == 0 || token[0] == '}') {
4832 			break;
4833 		}
4834 
4835 		if ( Q_stricmp( token, "}" ) == 0 ) {
4836 			break;
4837 		}
4838 
4839 		if (Q_stricmp(token, "gametypes") == 0) {
4840 
4841 			if (GameType_Parse(&p, qfalse)) {
4842 				continue;
4843 			} else {
4844 				break;
4845 			}
4846 		}
4847 
4848 		if (Q_stricmp(token, "joingametypes") == 0) {
4849 
4850 			if (GameType_Parse(&p, qtrue)) {
4851 				continue;
4852 			} else {
4853 				break;
4854 			}
4855 		}
4856 
4857 		if (Q_stricmp(token, "maps") == 0) {
4858 			// start a new menu
4859 			MapList_Parse(&p);
4860 		}
4861 
4862 	}
4863 }
4864 
UI_Pause(qboolean b)4865 static void UI_Pause(qboolean b) {
4866 	if (b) {
4867 		// pause the game and set the ui keycatcher
4868 	  trap_Cvar_Set( "cl_paused", "1" );
4869 		trap_Key_SetCatcher( KEYCATCH_UI );
4870 	} else {
4871 		// unpause the game and clear the ui keycatcher
4872 		trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
4873 		trap_Key_ClearStates();
4874 		trap_Cvar_Set( "cl_paused", "0" );
4875 	}
4876 }
4877 
4878 #ifndef MISSIONPACK
UI_OwnerDraw_Width(int ownerDraw)4879 static int UI_OwnerDraw_Width(int ownerDraw) {
4880   return 0;
4881 }
4882 #endif
4883 
UI_PlayCinematic(const char * name,float x,float y,float w,float h)4884 static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
4885   return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
4886 }
4887 
UI_StopCinematic(int handle)4888 static void UI_StopCinematic(int handle) {
4889 	if (handle >= 0) {
4890 	  trap_CIN_StopCinematic(handle);
4891 	} else {
4892 		handle = abs(handle);
4893 		if (handle == UI_MAPCINEMATIC) {
4894 			if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
4895 			  trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
4896 			  uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
4897 			}
4898 		} else if (handle == UI_NETMAPCINEMATIC) {
4899 			if (uiInfo.serverStatus.currentServerCinematic >= 0) {
4900 			  trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
4901 				uiInfo.serverStatus.currentServerCinematic = -1;
4902 			}
4903 		} else if (handle == UI_CLANCINEMATIC) {
4904 		  int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
4905 		  if (i >= 0 && i < uiInfo.teamCount) {
4906 				if (uiInfo.teamList[i].cinematic >= 0) {
4907 				  trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
4908 					uiInfo.teamList[i].cinematic = -1;
4909 				}
4910 			}
4911 		}
4912 	}
4913 }
4914 
UI_DrawCinematic(int handle,float x,float y,float w,float h)4915 static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
4916 	trap_CIN_SetExtents(handle, x, y, w, h);
4917   trap_CIN_DrawCinematic(handle);
4918 }
4919 
UI_RunCinematicFrame(int handle)4920 static void UI_RunCinematicFrame(int handle) {
4921   trap_CIN_RunCinematic(handle);
4922 }
4923 
4924 
4925 
4926 /*
4927 =================
4928 PlayerModel_BuildList
4929 =================
4930 */
UI_BuildQ3Model_List(void)4931 static void UI_BuildQ3Model_List( void )
4932 {
4933 	int		numdirs;
4934 	int		numfiles;
4935 	char	dirlist[2048];
4936 	char	filelist[2048];
4937 	char	skinname[MAX_QPATH];
4938 	char	scratch[256];
4939 	char*	dirptr;
4940 	char*	fileptr;
4941 	int		i;
4942 	int		j, k, dirty;
4943 	int		dirlen;
4944 	int		filelen;
4945 
4946 	uiInfo.q3HeadCount = 0;
4947 
4948 	// iterate directory of all player models
4949 	numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
4950 	dirptr  = dirlist;
4951 	for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
4952 	{
4953 		dirlen = strlen(dirptr);
4954 
4955 		if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
4956 
4957 		if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
4958 			continue;
4959 
4960 		// iterate all skin files in directory
4961 		numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
4962 		fileptr  = filelist;
4963 		for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
4964 		{
4965 			filelen = strlen(fileptr);
4966 
4967 			COM_StripExtension(fileptr, skinname, sizeof(skinname));
4968 
4969 			// look for icon_????
4970 			if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
4971 			{
4972 				if (Q_stricmp(skinname, "icon_default") == 0) {
4973 					Com_sprintf( scratch, sizeof(scratch), "%s", dirptr);
4974 				} else {
4975 					Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
4976 				}
4977 				dirty = 0;
4978 				for(k=0;k<uiInfo.q3HeadCount;k++) {
4979 					if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
4980 						dirty = 1;
4981 						break;
4982 					}
4983 				}
4984 				if (!dirty) {
4985 					Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), "%s", scratch);
4986 					uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
4987 				}
4988 			}
4989 
4990 		}
4991 	}
4992 
4993 }
4994 
4995 
4996 
4997 /*
4998 =================
4999 UI_Init
5000 =================
5001 */
_UI_Init(qboolean inGameLoad)5002 void _UI_Init( qboolean inGameLoad ) {
5003 	const char *menuSet;
5004 	int start;
5005 
5006 	//uiInfo.inGameLoad = inGameLoad;
5007 
5008 	UI_RegisterCvars();
5009 	UI_InitMemory();
5010 
5011 	// cache redundant calulations
5012 	trap_GetGlconfig( &uiInfo.uiDC.glconfig );
5013 
5014 	// for 640x480 virtualized screen
5015 	uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
5016 	uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
5017 	if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
5018 		// wide screen
5019 		uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
5020 	}
5021 	else {
5022 		// no wide screen
5023 		uiInfo.uiDC.bias = 0;
5024 	}
5025 
5026 
5027   //UI_Load();
5028 	uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
5029 	uiInfo.uiDC.setColor = &UI_SetColor;
5030 	uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
5031 	uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
5032 	uiInfo.uiDC.drawText = &Text_Paint;
5033 	uiInfo.uiDC.textWidth = &Text_Width;
5034 	uiInfo.uiDC.textHeight = &Text_Height;
5035 	uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
5036 	uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
5037 	uiInfo.uiDC.fillRect = &UI_FillRect;
5038 	uiInfo.uiDC.drawRect = &_UI_DrawRect;
5039 	uiInfo.uiDC.drawSides = &_UI_DrawSides;
5040 	uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
5041 	uiInfo.uiDC.clearScene = &trap_R_ClearScene;
5042 	uiInfo.uiDC.drawSides = &_UI_DrawSides;
5043 	uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
5044 	uiInfo.uiDC.renderScene = &trap_R_RenderScene;
5045 	uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
5046 	uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
5047 	uiInfo.uiDC.getValue = &UI_GetValue;
5048 	uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
5049 	uiInfo.uiDC.runScript = &UI_RunMenuScript;
5050 	uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
5051 	uiInfo.uiDC.setCVar = trap_Cvar_Set;
5052 	uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
5053 	uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
5054 	uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
5055 	uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
5056 	uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
5057 	uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
5058 	uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
5059 	uiInfo.uiDC.feederCount = &UI_FeederCount;
5060 	uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
5061 	uiInfo.uiDC.feederItemText = &UI_FeederItemText;
5062 	uiInfo.uiDC.feederSelection = &UI_FeederSelection;
5063 	uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
5064 	uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
5065 	uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
5066 	uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
5067 	uiInfo.uiDC.Error = &Com_Error;
5068 	uiInfo.uiDC.Print = &Com_Printf;
5069 	uiInfo.uiDC.Pause = &UI_Pause;
5070 	uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
5071 	uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
5072 	uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
5073 	uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
5074 	uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
5075 	uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
5076 	uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
5077 	uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
5078 
5079 	Init_Display(&uiInfo.uiDC);
5080 
5081 	String_Init();
5082 
5083 	uiInfo.uiDC.cursor	= trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
5084 	uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
5085 
5086 	AssetCache();
5087 
5088 	start = trap_Milliseconds();
5089 
5090   uiInfo.teamCount = 0;
5091   uiInfo.characterCount = 0;
5092   uiInfo.aliasCount = 0;
5093 
5094 #ifdef PRE_RELEASE_TADEMO
5095 	UI_ParseTeamInfo("demoteaminfo.txt");
5096 	UI_ParseGameInfo("demogameinfo.txt");
5097 #else
5098 	UI_ParseTeamInfo("teaminfo.txt");
5099 	UI_LoadTeams();
5100 	UI_ParseGameInfo("gameinfo.txt");
5101 #endif
5102 
5103 	menuSet = UI_Cvar_VariableString("ui_menuFiles");
5104 	if (menuSet == NULL || menuSet[0] == '\0') {
5105 		menuSet = "ui/menus.txt";
5106 	}
5107 
5108 #if 0
5109 	if (uiInfo.inGameLoad) {
5110 		UI_LoadMenus("ui/ingame.txt", qtrue);
5111 	} else {
5112 	}
5113 #else
5114 	UI_LoadMenus(menuSet, qtrue);
5115 	UI_LoadMenus("ui/ingame.txt", qfalse);
5116 #endif
5117 
5118 	Menus_CloseAll();
5119 
5120 	trap_LAN_LoadCachedServers();
5121 	UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
5122 
5123 	UI_BuildQ3Model_List();
5124 	UI_LoadBots();
5125 
5126 	// sets defaults for ui temp cvars
5127 	uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
5128 	uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
5129 	trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
5130 
5131 	uiInfo.serverStatus.currentServerCinematic = -1;
5132 	uiInfo.previewMovie = -1;
5133 
5134 	if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
5135 		trap_Cvar_Set("s_volume", "0.8");
5136 		trap_Cvar_Set("s_musicvolume", "0.5");
5137 		trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
5138 	}
5139 
5140 	trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
5141 
5142 	trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
5143 }
5144 
5145 
5146 /*
5147 =================
5148 UI_KeyEvent
5149 =================
5150 */
_UI_KeyEvent(int key,qboolean down)5151 void _UI_KeyEvent( int key, qboolean down ) {
5152 
5153   if (Menu_Count() > 0) {
5154     menuDef_t *menu = Menu_GetFocused();
5155 		if (menu) {
5156 			if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
5157 				Menus_CloseAll();
5158 			} else {
5159 				Menu_HandleKey(menu, key, down );
5160 			}
5161 		} else {
5162 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
5163 			trap_Key_ClearStates();
5164 			trap_Cvar_Set( "cl_paused", "0" );
5165 		}
5166   }
5167 
5168   //if ((s > 0) && (s != menu_null_sound)) {
5169 	//  trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
5170   //}
5171 }
5172 
5173 /*
5174 =================
5175 UI_MouseEvent
5176 =================
5177 */
_UI_MouseEvent(int dx,int dy)5178 void _UI_MouseEvent( int dx, int dy )
5179 {
5180 	// update mouse screen position
5181 	uiInfo.uiDC.cursorx += dx;
5182 	if (uiInfo.uiDC.cursorx < 0)
5183 		uiInfo.uiDC.cursorx = 0;
5184 	else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
5185 		uiInfo.uiDC.cursorx = SCREEN_WIDTH;
5186 
5187 	uiInfo.uiDC.cursory += dy;
5188 	if (uiInfo.uiDC.cursory < 0)
5189 		uiInfo.uiDC.cursory = 0;
5190 	else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
5191 		uiInfo.uiDC.cursory = SCREEN_HEIGHT;
5192 
5193   if (Menu_Count() > 0) {
5194     //menuDef_t *menu = Menu_GetFocused();
5195     //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
5196 		Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
5197   }
5198 
5199 }
5200 
UI_LoadNonIngame(void)5201 void UI_LoadNonIngame( void ) {
5202 	const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
5203 	if (menuSet == NULL || menuSet[0] == '\0') {
5204 		menuSet = "ui/menus.txt";
5205 	}
5206 	UI_LoadMenus(menuSet, qfalse);
5207 	uiInfo.inGameLoad = qfalse;
5208 }
5209 
_UI_SetActiveMenu(uiMenuCommand_t menu)5210 void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
5211 	char buf[256];
5212 
5213 	// this should be the ONLY way the menu system is brought up
5214 	// enusure minumum menu data is cached
5215   if (Menu_Count() > 0) {
5216 		vec3_t v;
5217 		v[0] = v[1] = v[2] = 0;
5218 	  switch ( menu ) {
5219 	  case UIMENU_NONE:
5220 			trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
5221 			trap_Key_ClearStates();
5222 			trap_Cvar_Set( "cl_paused", "0" );
5223 			Menus_CloseAll();
5224 
5225 		  return;
5226 	  case UIMENU_MAIN:
5227 			trap_Cvar_Set( "sv_killserver", "1" );
5228 			trap_Key_SetCatcher( KEYCATCH_UI );
5229 			//trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
5230 			//trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
5231 			if (uiInfo.inGameLoad) {
5232 				UI_LoadNonIngame();
5233 			}
5234 			Menus_CloseAll();
5235 			Menus_ActivateByName("main");
5236 			trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
5237 			if (strlen(buf)) {
5238 				if (!ui_singlePlayerActive.integer) {
5239 					Menus_ActivateByName("error_popmenu");
5240 				} else {
5241 					trap_Cvar_Set("com_errorMessage", "");
5242 				}
5243 			}
5244 		  return;
5245 	  case UIMENU_TEAM:
5246 			trap_Key_SetCatcher( KEYCATCH_UI );
5247       Menus_ActivateByName("team");
5248 		  return;
5249 	  case UIMENU_NEED_CD:
5250 			// no cd check in TA
5251 			//trap_Key_SetCatcher( KEYCATCH_UI );
5252       //Menus_ActivateByName("needcd");
5253 		  //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
5254 		  return;
5255 	  case UIMENU_BAD_CD_KEY:
5256 			// no cd check in TA
5257 			//trap_Key_SetCatcher( KEYCATCH_UI );
5258       //Menus_ActivateByName("badcd");
5259 		  //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
5260 		  return;
5261 	  case UIMENU_POSTGAME:
5262 			trap_Cvar_Set( "sv_killserver", "1" );
5263 			trap_Key_SetCatcher( KEYCATCH_UI );
5264 			if (uiInfo.inGameLoad) {
5265 				UI_LoadNonIngame();
5266 			}
5267 			Menus_CloseAll();
5268 			Menus_ActivateByName("endofgame");
5269 		  //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
5270 		  return;
5271 	  case UIMENU_INGAME:
5272 		  trap_Cvar_Set( "cl_paused", "1" );
5273 			trap_Key_SetCatcher( KEYCATCH_UI );
5274 			UI_BuildPlayerList();
5275 			Menus_CloseAll();
5276 			Menus_ActivateByName("ingame");
5277 		  return;
5278 	  }
5279   }
5280 }
5281 
_UI_IsFullscreen(void)5282 qboolean _UI_IsFullscreen( void ) {
5283 	return Menus_AnyFullScreenVisible();
5284 }
5285 
5286 
5287 
5288 static connstate_t	lastConnState;
5289 static char			lastLoadingText[MAX_INFO_VALUE];
5290 
UI_ReadableSize(char * buf,int bufsize,int value)5291 static void UI_ReadableSize ( char *buf, int bufsize, int value )
5292 {
5293 	if (value > 1024*1024*1024 ) { // gigs
5294 		Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
5295 		Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB",
5296 			(value % (1024*1024*1024))*100 / (1024*1024*1024) );
5297 	} else if (value > 1024*1024 ) { // megs
5298 		Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
5299 		Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB",
5300 			(value % (1024*1024))*100 / (1024*1024) );
5301 	} else if (value > 1024 ) { // kilos
5302 		Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
5303 	} else { // bytes
5304 		Com_sprintf( buf, bufsize, "%d bytes", value );
5305 	}
5306 }
5307 
5308 // Assumes time is in msec
UI_PrintTime(char * buf,int bufsize,int time)5309 static void UI_PrintTime ( char *buf, int bufsize, int time ) {
5310 	time /= 1000;  // change to seconds
5311 
5312 	if (time > 3600) { // in the hours range
5313 		Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
5314 	} else if (time > 60) { // mins
5315 		Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
5316 	} else  { // secs
5317 		Com_sprintf( buf, bufsize, "%d sec", time );
5318 	}
5319 }
5320 
Text_PaintCenter(float x,float y,float scale,vec4_t color,const char * text,float adjust)5321 void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
5322 	int len = Text_Width(text, scale, 0);
5323 	Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
5324 }
5325 
Text_PaintCenter_AutoWrapped(float x,float y,float xmax,float ystep,float scale,vec4_t color,const char * str,float adjust)5326 void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
5327 	int width;
5328 	char *s1,*s2,*s3;
5329 	char c_bcp;
5330 	char buf[1024];
5331 
5332 	if (!str || str[0]=='\0')
5333 		return;
5334 
5335 	Q_strncpyz(buf, str, sizeof(buf));
5336 	s1 = s2 = s3 = buf;
5337 
5338 	while (1) {
5339 		do {
5340 			s3++;
5341 		} while (*s3!=' ' && *s3!='\0');
5342 		c_bcp = *s3;
5343 		*s3 = '\0';
5344 		width = Text_Width(s1, scale, 0);
5345 		*s3 = c_bcp;
5346 		if (width > xmax) {
5347 			if (s1==s2)
5348 			{
5349 				// fuck, don't have a clean cut, we'll overflow
5350 				s2 = s3;
5351 			}
5352 			*s2 = '\0';
5353 			Text_PaintCenter(x, y, scale, color, s1, adjust);
5354 			y += ystep;
5355 			if (c_bcp == '\0')
5356       {
5357 				// that was the last word
5358         // we could start a new loop, but that wouldn't be much use
5359         // even if the word is too long, we would overflow it (see above)
5360         // so just print it now if needed
5361         s2++;
5362         if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
5363           Text_PaintCenter(x, y, scale, color, s2, adjust);
5364         break;
5365       }
5366 			s2++;
5367 			s1 = s2;
5368 			s3 = s2;
5369 		}
5370 		else
5371 		{
5372 			s2 = s3;
5373 			if (c_bcp == '\0') // we reached the end
5374 			{
5375 				Text_PaintCenter(x, y, scale, color, s1, adjust);
5376 				break;
5377 			}
5378 		}
5379 	}
5380 }
5381 
UI_DisplayDownloadInfo(const char * downloadName,float centerPoint,float yStart,float scale)5382 static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
5383 	static char dlText[]	= "Downloading:";
5384 	static char etaText[]	= "Estimated time left:";
5385 	static char xferText[]	= "Transfer rate:";
5386 
5387 	int downloadSize, downloadCount, downloadTime;
5388 	char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
5389 	int xferRate;
5390 	int leftWidth;
5391 	const char *s;
5392 
5393 	downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
5394 	downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
5395 	downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
5396 
5397 	leftWidth = 320;
5398 
5399 	UI_SetColor(colorWhite);
5400 	Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
5401 	Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
5402 	Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
5403 
5404 	if (downloadSize > 0) {
5405 		s = va( "%s (%d%%)", downloadName,
5406 			(int)( (float)downloadCount * 100.0f / downloadSize ) );
5407 	} else {
5408 		s = downloadName;
5409 	}
5410 
5411 	Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
5412 
5413 	UI_ReadableSize( dlSizeBuf,		sizeof dlSizeBuf,		downloadCount );
5414 	UI_ReadableSize( totalSizeBuf,	sizeof totalSizeBuf,	downloadSize );
5415 
5416 	if (downloadCount < 4096 || !downloadTime) {
5417 		Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
5418 		Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5419 	} else {
5420 		if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
5421 			xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
5422 		} else {
5423 			xferRate = 0;
5424 		}
5425 		UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
5426 
5427 		// Extrapolate estimated completion time
5428 		if (downloadSize && xferRate) {
5429 			int n = downloadSize / xferRate; // estimated time for entire d/l in secs
5430 
5431 			// We do it in K (/1024) because we'd overflow around 4MB
5432 			UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf,
5433 				(n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
5434 
5435 			Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
5436 			Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5437 		} else {
5438 			Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
5439 			if (downloadSize) {
5440 				Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
5441 			} else {
5442 				Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
5443 			}
5444 		}
5445 
5446 		if (xferRate) {
5447 			Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
5448 		}
5449 	}
5450 }
5451 
5452 /*
5453 ========================
5454 UI_DrawConnectScreen
5455 
5456 This will also be overlaid on the cgame info screen during loading
5457 to prevent it from blinking away too rapidly on local or lan games.
5458 ========================
5459 */
UI_DrawConnectScreen(qboolean overlay)5460 void UI_DrawConnectScreen( qboolean overlay ) {
5461 	char			*s;
5462 	uiClientState_t	cstate;
5463 	char			info[MAX_INFO_VALUE];
5464 	char text[256];
5465 	float centerPoint, yStart, scale;
5466 
5467 	menuDef_t *menu = Menus_FindByName("Connect");
5468 
5469 
5470 	if ( !overlay && menu ) {
5471 		Menu_Paint(menu, qtrue);
5472 	}
5473 
5474 	if (!overlay) {
5475 		centerPoint = 320;
5476 		yStart = 130;
5477 		scale = 0.5f;
5478 	} else {
5479 		centerPoint = 320;
5480 		yStart = 32;
5481 		scale = 0.6f;
5482 		return;
5483 	}
5484 
5485 	// see what information we should display
5486 	trap_GetClientState( &cstate );
5487 
5488 	info[0] = '\0';
5489 	if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
5490 		Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
5491 	}
5492 
5493 	if (!Q_stricmp(cstate.servername,"localhost")) {
5494 		Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
5495 	} else {
5496 		strcpy(text, va("Connecting to %s", cstate.servername));
5497 		Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
5498 	}
5499 
5500 	// display global MOTD at bottom
5501 	Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
5502 	// print any server info (server full, bad version, etc)
5503 	if ( cstate.connState < CA_CONNECTED ) {
5504 		Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
5505 	}
5506 
5507 	if ( lastConnState > cstate.connState ) {
5508 		lastLoadingText[0] = '\0';
5509 	}
5510 	lastConnState = cstate.connState;
5511 
5512 	switch ( cstate.connState ) {
5513 	case CA_CONNECTING:
5514 		s = va("Awaiting connection...%i", cstate.connectPacketCount);
5515 		break;
5516 	case CA_CHALLENGING:
5517 		s = va("Awaiting challenge...%i", cstate.connectPacketCount);
5518 		break;
5519 	case CA_CONNECTED: {
5520 		char downloadName[MAX_INFO_VALUE];
5521 
5522 			trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
5523 			if (*downloadName) {
5524 				UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
5525 				return;
5526 			}
5527 		}
5528 		s = "Awaiting gamestate...";
5529 		break;
5530 	case CA_LOADING:
5531 		return;
5532 	case CA_PRIMED:
5533 		return;
5534 	default:
5535 		return;
5536 	}
5537 
5538 
5539 	if (Q_stricmp(cstate.servername,"localhost")) {
5540 		Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
5541 	}
5542 
5543 	// password required / connection rejected information goes here
5544 }
5545 
5546 
5547 /*
5548 ================
5549 cvars
5550 ================
5551 */
5552 
5553 typedef struct {
5554 	vmCvar_t	*vmCvar;
5555 	char		*cvarName;
5556 	char		*defaultString;
5557 	int			cvarFlags;
5558 } cvarTable_t;
5559 
5560 vmCvar_t	ui_ffa_fraglimit;
5561 vmCvar_t	ui_ffa_timelimit;
5562 
5563 vmCvar_t	ui_tourney_fraglimit;
5564 vmCvar_t	ui_tourney_timelimit;
5565 
5566 vmCvar_t	ui_team_fraglimit;
5567 vmCvar_t	ui_team_timelimit;
5568 vmCvar_t	ui_team_friendly;
5569 
5570 vmCvar_t	ui_ctf_capturelimit;
5571 vmCvar_t	ui_ctf_timelimit;
5572 vmCvar_t	ui_ctf_friendly;
5573 
5574 vmCvar_t	ui_arenasFile;
5575 vmCvar_t	ui_botsFile;
5576 vmCvar_t	ui_spScores1;
5577 vmCvar_t	ui_spScores2;
5578 vmCvar_t	ui_spScores3;
5579 vmCvar_t	ui_spScores4;
5580 vmCvar_t	ui_spScores5;
5581 vmCvar_t	ui_spAwards;
5582 vmCvar_t	ui_spVideos;
5583 vmCvar_t	ui_spSkill;
5584 
5585 vmCvar_t	ui_spSelection;
5586 
5587 vmCvar_t	ui_browserMaster;
5588 vmCvar_t	ui_browserGameType;
5589 vmCvar_t	ui_browserShowFull;
5590 vmCvar_t	ui_browserShowEmpty;
5591 
5592 vmCvar_t	ui_brassTime;
5593 vmCvar_t	ui_drawCrosshair;
5594 vmCvar_t	ui_drawCrosshairNames;
5595 vmCvar_t	ui_marks;
5596 
5597 vmCvar_t	ui_server1;
5598 vmCvar_t	ui_server2;
5599 vmCvar_t	ui_server3;
5600 vmCvar_t	ui_server4;
5601 vmCvar_t	ui_server5;
5602 vmCvar_t	ui_server6;
5603 vmCvar_t	ui_server7;
5604 vmCvar_t	ui_server8;
5605 vmCvar_t	ui_server9;
5606 vmCvar_t	ui_server10;
5607 vmCvar_t	ui_server11;
5608 vmCvar_t	ui_server12;
5609 vmCvar_t	ui_server13;
5610 vmCvar_t	ui_server14;
5611 vmCvar_t	ui_server15;
5612 vmCvar_t	ui_server16;
5613 
5614 vmCvar_t	ui_cdkeychecked;
5615 
5616 vmCvar_t	ui_redteam;
5617 vmCvar_t	ui_redteam1;
5618 vmCvar_t	ui_redteam2;
5619 vmCvar_t	ui_redteam3;
5620 vmCvar_t	ui_redteam4;
5621 vmCvar_t	ui_redteam5;
5622 vmCvar_t	ui_blueteam;
5623 vmCvar_t	ui_blueteam1;
5624 vmCvar_t	ui_blueteam2;
5625 vmCvar_t	ui_blueteam3;
5626 vmCvar_t	ui_blueteam4;
5627 vmCvar_t	ui_blueteam5;
5628 vmCvar_t	ui_teamName;
5629 vmCvar_t	ui_dedicated;
5630 vmCvar_t	ui_gameType;
5631 vmCvar_t	ui_netGameType;
5632 vmCvar_t	ui_actualNetGameType;
5633 vmCvar_t	ui_joinGameType;
5634 vmCvar_t	ui_netSource;
5635 vmCvar_t	ui_serverFilterType;
5636 vmCvar_t	ui_opponentName;
5637 vmCvar_t	ui_menuFiles;
5638 vmCvar_t	ui_currentTier;
5639 vmCvar_t	ui_currentMap;
5640 vmCvar_t	ui_currentNetMap;
5641 vmCvar_t	ui_mapIndex;
5642 vmCvar_t	ui_currentOpponent;
5643 vmCvar_t	ui_selectedPlayer;
5644 vmCvar_t	ui_selectedPlayerName;
5645 vmCvar_t	ui_lastServerRefresh_0;
5646 vmCvar_t	ui_lastServerRefresh_1;
5647 vmCvar_t	ui_lastServerRefresh_2;
5648 vmCvar_t	ui_lastServerRefresh_3;
5649 vmCvar_t	ui_singlePlayerActive;
5650 vmCvar_t	ui_scoreAccuracy;
5651 vmCvar_t	ui_scoreImpressives;
5652 vmCvar_t	ui_scoreExcellents;
5653 vmCvar_t	ui_scoreCaptures;
5654 vmCvar_t	ui_scoreDefends;
5655 vmCvar_t	ui_scoreAssists;
5656 vmCvar_t	ui_scoreGauntlets;
5657 vmCvar_t	ui_scoreScore;
5658 vmCvar_t	ui_scorePerfect;
5659 vmCvar_t	ui_scoreTeam;
5660 vmCvar_t	ui_scoreBase;
5661 vmCvar_t	ui_scoreTimeBonus;
5662 vmCvar_t	ui_scoreSkillBonus;
5663 vmCvar_t	ui_scoreShutoutBonus;
5664 vmCvar_t	ui_scoreTime;
5665 vmCvar_t	ui_captureLimit;
5666 vmCvar_t	ui_fragLimit;
5667 vmCvar_t	ui_smallFont;
5668 vmCvar_t	ui_bigFont;
5669 vmCvar_t	ui_findPlayer;
5670 vmCvar_t	ui_Q3Model;
5671 vmCvar_t	ui_hudFiles;
5672 vmCvar_t	ui_recordSPDemo;
5673 vmCvar_t	ui_realCaptureLimit;
5674 vmCvar_t	ui_realWarmUp;
5675 vmCvar_t	ui_serverStatusTimeOut;
5676 
5677 static cvarTable_t		cvarTable[] = {
5678 	{ &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
5679 	{ &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
5680 
5681 	{ &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
5682 	{ &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
5683 
5684 	{ &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
5685 	{ &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
5686 	{ &ui_team_friendly, "ui_team_friendly",  "1", CVAR_ARCHIVE },
5687 
5688 	{ &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
5689 	{ &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
5690 	{ &ui_ctf_friendly, "ui_ctf_friendly",  "0", CVAR_ARCHIVE },
5691 
5692 	{ &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
5693 	{ &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
5694 	{ &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE },
5695 	{ &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE },
5696 	{ &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE },
5697 	{ &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE },
5698 	{ &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE },
5699 	{ &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE },
5700 	{ &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE },
5701 	{ &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
5702 
5703 	{ &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
5704 
5705 	{ &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
5706 	{ &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
5707 	{ &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
5708 	{ &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
5709 
5710 	{ &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
5711 	{ &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
5712 	{ &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
5713 	{ &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
5714 
5715 	{ &ui_server1, "server1", "", CVAR_ARCHIVE },
5716 	{ &ui_server2, "server2", "", CVAR_ARCHIVE },
5717 	{ &ui_server3, "server3", "", CVAR_ARCHIVE },
5718 	{ &ui_server4, "server4", "", CVAR_ARCHIVE },
5719 	{ &ui_server5, "server5", "", CVAR_ARCHIVE },
5720 	{ &ui_server6, "server6", "", CVAR_ARCHIVE },
5721 	{ &ui_server7, "server7", "", CVAR_ARCHIVE },
5722 	{ &ui_server8, "server8", "", CVAR_ARCHIVE },
5723 	{ &ui_server9, "server9", "", CVAR_ARCHIVE },
5724 	{ &ui_server10, "server10", "", CVAR_ARCHIVE },
5725 	{ &ui_server11, "server11", "", CVAR_ARCHIVE },
5726 	{ &ui_server12, "server12", "", CVAR_ARCHIVE },
5727 	{ &ui_server13, "server13", "", CVAR_ARCHIVE },
5728 	{ &ui_server14, "server14", "", CVAR_ARCHIVE },
5729 	{ &ui_server15, "server15", "", CVAR_ARCHIVE },
5730 	{ &ui_server16, "server16", "", CVAR_ARCHIVE },
5731 	{ &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
5732 	{ &ui_new, "ui_new", "0", CVAR_TEMP },
5733 	{ &ui_debug, "ui_debug", "0", CVAR_TEMP },
5734 	{ &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
5735 	{ &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
5736 	{ &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
5737 	{ &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
5738 	{ &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
5739 	{ &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
5740 	{ &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
5741 	{ &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
5742 	{ &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
5743 	{ &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
5744 	{ &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
5745 	{ &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
5746 	{ &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
5747 	{ &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
5748 	{ &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
5749 	{ &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
5750 	{ &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
5751 	{ &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
5752 	{ &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
5753 	{ &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
5754 	{ &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
5755 	{ &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
5756 	{ &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
5757 	{ &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
5758 	{ &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
5759 	{ &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
5760 	{ &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
5761 	{ &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
5762 	{ &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
5763 	{ &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
5764 	{ &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
5765 	{ &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
5766 	{ &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
5767 	{ &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
5768 	{ &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
5769 	{ &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
5770 	{ &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
5771 	{ &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
5772 	{ &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
5773 	{ &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
5774 	{ &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
5775 	{ &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
5776 	{ &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
5777 	{ &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
5778 	{ &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
5779 	{ &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
5780 	{ &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
5781 	{ &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
5782 	{ &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
5783 	{ &ui_fragLimit, "ui_fragLimit", "10", 0},
5784 	{ &ui_captureLimit, "ui_captureLimit", "5", 0},
5785 	{ &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
5786 	{ &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
5787 	{ &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
5788 	{ &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
5789 	{ &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
5790 	{ &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
5791 	{ &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
5792 	{ &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
5793 	{ &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
5794 	{ &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
5795 
5796 };
5797 
5798 static int		cvarTableSize = ARRAY_LEN( cvarTable );
5799 
5800 
5801 /*
5802 =================
5803 UI_RegisterCvars
5804 =================
5805 */
UI_RegisterCvars(void)5806 void UI_RegisterCvars( void ) {
5807 	int			i;
5808 	cvarTable_t	*cv;
5809 
5810 	for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
5811 		trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
5812 	}
5813 }
5814 
5815 /*
5816 =================
5817 UI_UpdateCvars
5818 =================
5819 */
UI_UpdateCvars(void)5820 void UI_UpdateCvars( void ) {
5821 	int			i;
5822 	cvarTable_t	*cv;
5823 
5824 	for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
5825 		trap_Cvar_Update( cv->vmCvar );
5826 	}
5827 }
5828 
5829 
5830 /*
5831 =================
5832 ArenaServers_StopRefresh
5833 =================
5834 */
UI_StopServerRefresh(void)5835 static void UI_StopServerRefresh( void )
5836 {
5837 	int count;
5838 
5839 	if (!uiInfo.serverStatus.refreshActive) {
5840 		// not currently refreshing
5841 		return;
5842 	}
5843 	uiInfo.serverStatus.refreshActive = qfalse;
5844 	Com_Printf("%d servers listed in browser with %d players.\n",
5845 					uiInfo.serverStatus.numDisplayServers,
5846 					uiInfo.serverStatus.numPlayersOnServers);
5847 	count = trap_LAN_GetServerCount(ui_netSource.integer);
5848 	if (count - uiInfo.serverStatus.numDisplayServers > 0) {
5849 		Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
5850 						count - uiInfo.serverStatus.numDisplayServers,
5851 						(int) trap_Cvar_VariableValue("cl_maxPing"));
5852 	}
5853 
5854 }
5855 
5856 /*
5857 =================
5858 ArenaServers_MaxPing
5859 =================
5860 */
5861 #ifndef MISSIONPACK
ArenaServers_MaxPing(void)5862 static int ArenaServers_MaxPing( void ) {
5863 	int		maxPing;
5864 
5865 	maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
5866 	if( maxPing < 100 ) {
5867 		maxPing = 100;
5868 	}
5869 	return maxPing;
5870 }
5871 #endif
5872 
5873 /*
5874 =================
5875 UI_DoServerRefresh
5876 =================
5877 */
UI_DoServerRefresh(void)5878 static void UI_DoServerRefresh( void )
5879 {
5880 	qboolean wait = qfalse;
5881 
5882 	if (!uiInfo.serverStatus.refreshActive) {
5883 		return;
5884 	}
5885 	if (ui_netSource.integer != AS_FAVORITES) {
5886 		if (ui_netSource.integer == AS_LOCAL) {
5887 			if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
5888 				wait = qtrue;
5889 			}
5890 		} else {
5891 			if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
5892 				wait = qtrue;
5893 			}
5894 		}
5895 	}
5896 
5897 	if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
5898 		if (wait) {
5899 			return;
5900 		}
5901 	}
5902 
5903 	// if still trying to retrieve pings
5904 	if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
5905 		uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
5906 	} else if (!wait) {
5907 		// get the last servers in the list
5908 		UI_BuildServerDisplayList(2);
5909 		// stop the refresh
5910 		UI_StopServerRefresh();
5911 	}
5912 	//
5913 	UI_BuildServerDisplayList(qfalse);
5914 }
5915 
5916 /*
5917 =================
5918 UI_StartServerRefresh
5919 =================
5920 */
UI_StartServerRefresh(qboolean full)5921 static void UI_StartServerRefresh(qboolean full)
5922 {
5923 	char	*ptr;
5924 
5925 	qtime_t q;
5926 	trap_RealTime(&q);
5927  	trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min));
5928 
5929 	if (!full) {
5930 		UI_UpdatePendingPings();
5931 		return;
5932 	}
5933 
5934 	uiInfo.serverStatus.refreshActive = qtrue;
5935 	uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
5936 	// clear number of displayed servers
5937 	uiInfo.serverStatus.numDisplayServers = 0;
5938 	uiInfo.serverStatus.numPlayersOnServers = 0;
5939 	// mark all servers as visible so we store ping updates for them
5940 	trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
5941 	// reset all the pings
5942 	trap_LAN_ResetPings(ui_netSource.integer);
5943 	//
5944 	if( ui_netSource.integer == AS_LOCAL ) {
5945 		trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
5946 		uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
5947 		return;
5948 	}
5949 
5950 	uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
5951 	if( ui_netSource.integer == AS_GLOBAL ) {
5952 
5953 		ptr = UI_Cvar_VariableString("debug_protocol");
5954 		if (strlen(ptr)) {
5955 			trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %s full empty\n", ptr));
5956 		}
5957 		else {
5958 			trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers 0 %d full empty\n", (int)trap_Cvar_VariableValue( "protocol" ) ) );
5959 		}
5960 	}
5961 }
5962 
5963