Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ui_main.c (181054B)


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