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