Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ui_main.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 //
00023 /*
00024 =======================================================================
00025 
00026 USER INTERFACE MAIN
00027 
00028 =======================================================================
00029 */
00030 
00031 // use this to get a demo build without an explicit demo build, i.e. to get the demo ui files to build
00032 //#define PRE_RELEASE_TADEMO
00033 
00034 #include "ui_local.h"
00035 
00036 uiInfo_t uiInfo;
00037 
00038 static const char *MonthAbbrev[] = {
00039     "Jan","Feb","Mar",
00040     "Apr","May","Jun",
00041     "Jul","Aug","Sep",
00042     "Oct","Nov","Dec"
00043 };
00044 
00045 
00046 static const char *skillLevels[] = {
00047   "I Can Win",
00048   "Bring It On",
00049   "Hurt Me Plenty",
00050   "Hardcore",
00051   "Nightmare"
00052 };
00053 
00054 static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*);
00055 
00056 
00057 static const char *netSources[] = {
00058     "Local",
00059     "Mplayer",
00060     "Internet",
00061     "Favorites"
00062 };
00063 static const int numNetSources = sizeof(netSources) / sizeof(const char*);
00064 
00065 static const serverFilter_t serverFilters[] = {
00066     {"All", "" },
00067     {"Quake 3 Arena", "" },
00068     {"Team Arena", "missionpack" },
00069     {"Rocket Arena", "arena" },
00070     {"Alliance", "alliance20" },
00071     {"Weapons Factory Arena", "wfa" },
00072     {"OSP", "osp" },
00073 };
00074 
00075 static const char *teamArenaGameTypes[] = {
00076     "FFA",
00077     "TOURNAMENT",
00078     "SP",
00079     "TEAM DM",
00080     "CTF",
00081     "1FCTF",
00082     "OVERLOAD",
00083     "HARVESTER",
00084     "TEAMTOURNAMENT"
00085 };
00086 
00087 static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*);
00088 
00089 
00090 static const char *teamArenaGameNames[] = {
00091     "Free For All",
00092     "Tournament",
00093     "Single Player",
00094     "Team Deathmatch",
00095     "Capture the Flag",
00096     "One Flag CTF",
00097     "Overload",
00098     "Harvester",
00099     "Team Tournament",
00100 };
00101 
00102 static int const numTeamArenaGameNames = sizeof(teamArenaGameNames) / sizeof(const char*);
00103 
00104 
00105 static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t);
00106 
00107 static const char *sortKeys[] = {
00108     "Server Name",
00109     "Map Name",
00110     "Open Player Spots",
00111     "Game Type",
00112     "Ping Time"
00113 };
00114 static const int numSortKeys = sizeof(sortKeys) / sizeof(const char*);
00115 
00116 static char* netnames[] = {
00117     "???",
00118     "UDP",
00119     "IPX",
00120     NULL
00121 };
00122 
00123 #ifndef MISSIONPACK // bk001206
00124 static char quake3worldMessage[] = "Visit www.quake3world.com - News, Community, Events, Files";
00125 #endif
00126 
00127 static int gamecodetoui[] = {4,2,3,0,5,1,6};
00128 static int uitogamecode[] = {4,6,2,3,1,5,7};
00129 
00130 
00131 static void UI_StartServerRefresh(qboolean full);
00132 static void UI_StopServerRefresh( void );
00133 static void UI_DoServerRefresh( void );
00134 static void UI_FeederSelection(float feederID, int index);
00135 static void UI_BuildServerDisplayList(qboolean force);
00136 static void UI_BuildServerStatus(qboolean force);
00137 static void UI_BuildFindPlayerList(qboolean force);
00138 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 );
00139 static int UI_MapCountByGameType(qboolean singlePlayer);
00140 static int UI_HeadCountByTeam( void );
00141 static void UI_ParseGameInfo(const char *teamFile);
00142 static void UI_ParseTeamInfo(const char *teamFile);
00143 static const char *UI_SelectedMap(int index, int *actual);
00144 static const char *UI_SelectedHead(int index, int *actual);
00145 static int UI_GetIndexFromSelection(int actual);
00146 
00147 int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 );
00148 
00149 /*
00150 ================
00151 vmMain
00152 
00153 This is the only way control passes into the module.
00154 This must be the very first function compiled into the .qvm file
00155 ================
00156 */
00157 vmCvar_t  ui_new;
00158 vmCvar_t  ui_debug;
00159 vmCvar_t  ui_initialized;
00160 vmCvar_t  ui_teamArenaFirstRun;
00161 
00162 void _UI_Init( qboolean );
00163 void _UI_Shutdown( void );
00164 void _UI_KeyEvent( int key, qboolean down );
00165 void _UI_MouseEvent( int dx, int dy );
00166 void _UI_Refresh( int realtime );
00167 qboolean _UI_IsFullscreen( void );
00168 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  ) {
00169   switch ( command ) {
00170       case UI_GETAPIVERSION:
00171           return UI_API_VERSION;
00172 
00173       case UI_INIT:
00174           _UI_Init(arg0);
00175           return 0;
00176 
00177       case UI_SHUTDOWN:
00178           _UI_Shutdown();
00179           return 0;
00180 
00181       case UI_KEY_EVENT:
00182           _UI_KeyEvent( arg0, arg1 );
00183           return 0;
00184 
00185       case UI_MOUSE_EVENT:
00186           _UI_MouseEvent( arg0, arg1 );
00187           return 0;
00188 
00189       case UI_REFRESH:
00190           _UI_Refresh( arg0 );
00191           return 0;
00192 
00193       case UI_IS_FULLSCREEN:
00194           return _UI_IsFullscreen();
00195 
00196       case UI_SET_ACTIVE_MENU:
00197           _UI_SetActiveMenu( arg0 );
00198           return 0;
00199 
00200       case UI_CONSOLE_COMMAND:
00201           return UI_ConsoleCommand(arg0);
00202 
00203       case UI_DRAW_CONNECT_SCREEN:
00204           UI_DrawConnectScreen( arg0 );
00205           return 0;
00206       case UI_HASUNIQUECDKEY: // mod authors need to observe this
00207         return qtrue; // bk010117 - change this to qfalse for mods!
00208 
00209     }
00210 
00211     return -1;
00212 }
00213 
00214 
00215 
00216 void AssetCache() {
00217     int n;
00218     //if (Assets.textFont == NULL) {
00219     //}
00220     //Assets.background = trap_R_RegisterShaderNoMip( ASSET_BACKGROUND );
00221     //Com_Printf("Menu Size: %i bytes\n", sizeof(Menus));
00222     uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR );
00223     uiInfo.uiDC.Assets.fxBasePic = trap_R_RegisterShaderNoMip( ART_FX_BASE );
00224     uiInfo.uiDC.Assets.fxPic[0] = trap_R_RegisterShaderNoMip( ART_FX_RED );
00225     uiInfo.uiDC.Assets.fxPic[1] = trap_R_RegisterShaderNoMip( ART_FX_YELLOW );
00226     uiInfo.uiDC.Assets.fxPic[2] = trap_R_RegisterShaderNoMip( ART_FX_GREEN );
00227     uiInfo.uiDC.Assets.fxPic[3] = trap_R_RegisterShaderNoMip( ART_FX_TEAL );
00228     uiInfo.uiDC.Assets.fxPic[4] = trap_R_RegisterShaderNoMip( ART_FX_BLUE );
00229     uiInfo.uiDC.Assets.fxPic[5] = trap_R_RegisterShaderNoMip( ART_FX_CYAN );
00230     uiInfo.uiDC.Assets.fxPic[6] = trap_R_RegisterShaderNoMip( ART_FX_WHITE );
00231     uiInfo.uiDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
00232     uiInfo.uiDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
00233     uiInfo.uiDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
00234     uiInfo.uiDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
00235     uiInfo.uiDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
00236     uiInfo.uiDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
00237     uiInfo.uiDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
00238     uiInfo.uiDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
00239 
00240     for( n = 0; n < NUM_CROSSHAIRS; n++ ) {
00241         uiInfo.uiDC.Assets.crosshairShader[n] = trap_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a' + n ) );
00242     }
00243 
00244     uiInfo.newHighScoreSound = trap_S_RegisterSound("sound/feedback/voc_newhighscore.wav", qfalse);
00245 }
00246 
00247 void _UI_DrawSides(float x, float y, float w, float h, float size) {
00248     UI_AdjustFrom640( &x, &y, &w, &h );
00249     size *= uiInfo.uiDC.xscale;
00250     trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
00251     trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
00252 }
00253 
00254 void _UI_DrawTopBottom(float x, float y, float w, float h, float size) {
00255     UI_AdjustFrom640( &x, &y, &w, &h );
00256     size *= uiInfo.uiDC.yscale;
00257     trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
00258     trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, uiInfo.uiDC.whiteShader );
00259 }
00260 /*
00261 ================
00262 UI_DrawRect
00263 
00264 Coordinates are 640*480 virtual values
00265 =================
00266 */
00267 void _UI_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
00268     trap_R_SetColor( color );
00269 
00270   _UI_DrawTopBottom(x, y, width, height, size);
00271   _UI_DrawSides(x, y, width, height, size);
00272 
00273     trap_R_SetColor( NULL );
00274 }
00275 
00276 int Text_Width(const char *text, float scale, int limit) {
00277   int count,len;
00278     float out;
00279     glyphInfo_t *glyph;
00280     float useScale;
00281     const char *s = text;
00282     fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
00283     if (scale <= ui_smallFont.value) {
00284         font = &uiInfo.uiDC.Assets.smallFont;
00285     } else if (scale >= ui_bigFont.value) {
00286         font = &uiInfo.uiDC.Assets.bigFont;
00287     }
00288     useScale = scale * font->glyphScale;
00289   out = 0;
00290   if (text) {
00291     len = strlen(text);
00292         if (limit > 0 && len > limit) {
00293             len = limit;
00294         }
00295         count = 0;
00296         while (s && *s && count < len) {
00297             if ( Q_IsColorString(s) ) {
00298                 s += 2;
00299                 continue;
00300             } else {
00301                 glyph = &font->glyphs[(int)*s];
00302                 out += glyph->xSkip;
00303                 s++;
00304                 count++;
00305             }
00306     }
00307   }
00308   return out * useScale;
00309 }
00310 
00311 int Text_Height(const char *text, float scale, int limit) {
00312   int len, count;
00313     float max;
00314     glyphInfo_t *glyph;
00315     float useScale;
00316     const char *s = text; // bk001206 - unsigned
00317     fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
00318     if (scale <= ui_smallFont.value) {
00319         font = &uiInfo.uiDC.Assets.smallFont;
00320     } else if (scale >= ui_bigFont.value) {
00321         font = &uiInfo.uiDC.Assets.bigFont;
00322     }
00323     useScale = scale * font->glyphScale;
00324   max = 0;
00325   if (text) {
00326     len = strlen(text);
00327         if (limit > 0 && len > limit) {
00328             len = limit;
00329         }
00330         count = 0;
00331         while (s && *s && count < len) {
00332             if ( Q_IsColorString(s) ) {
00333                 s += 2;
00334                 continue;
00335             } else {
00336                 glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
00337           if (max < glyph->height) {
00338               max = glyph->height;
00339               }
00340                 s++;
00341                 count++;
00342             }
00343     }
00344   }
00345   return max * useScale;
00346 }
00347 
00348 void Text_PaintChar(float x, float y, float width, float height, float scale, float s, float t, float s2, float t2, qhandle_t hShader) {
00349   float w, h;
00350   w = width * scale;
00351   h = height * scale;
00352   UI_AdjustFrom640( &x, &y, &w, &h );
00353   trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader );
00354 }
00355 
00356 void Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style) {
00357   int len, count;
00358     vec4_t newColor;
00359     glyphInfo_t *glyph;
00360     float useScale;
00361     fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
00362     if (scale <= ui_smallFont.value) {
00363         font = &uiInfo.uiDC.Assets.smallFont;
00364     } else if (scale >= ui_bigFont.value) {
00365         font = &uiInfo.uiDC.Assets.bigFont;
00366     }
00367     useScale = scale * font->glyphScale;
00368   if (text) {
00369     const char *s = text; // bk001206 - unsigned
00370         trap_R_SetColor( color );
00371         memcpy(&newColor[0], &color[0], sizeof(vec4_t));
00372     len = strlen(text);
00373         if (limit > 0 && len > limit) {
00374             len = limit;
00375         }
00376         count = 0;
00377         while (s && *s && count < len) {
00378             glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
00379       //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
00380       //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
00381             if ( Q_IsColorString( s ) ) {
00382                 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
00383                 newColor[3] = color[3];
00384                 trap_R_SetColor( newColor );
00385                 s += 2;
00386                 continue;
00387             } else {
00388                 float yadj = useScale * glyph->top;
00389                 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
00390                     int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
00391                     colorBlack[3] = newColor[3];
00392                     trap_R_SetColor( colorBlack );
00393                     Text_PaintChar(x + ofs, y - yadj + ofs, 
00394                                                         glyph->imageWidth,
00395                                                         glyph->imageHeight,
00396                                                         useScale, 
00397                                                         glyph->s,
00398                                                         glyph->t,
00399                                                         glyph->s2,
00400                                                         glyph->t2,
00401                                                         glyph->glyph);
00402                     trap_R_SetColor( newColor );
00403                     colorBlack[3] = 1.0;
00404                 }
00405                 Text_PaintChar(x, y - yadj, 
00406                                                     glyph->imageWidth,
00407                                                     glyph->imageHeight,
00408                                                     useScale, 
00409                                                     glyph->s,
00410                                                     glyph->t,
00411                                                     glyph->s2,
00412                                                     glyph->t2,
00413                                                     glyph->glyph);
00414 
00415                 x += (glyph->xSkip * useScale) + adjust;
00416                 s++;
00417                 count++;
00418             }
00419     }
00420       trap_R_SetColor( NULL );
00421   }
00422 }
00423 
00424 void Text_PaintWithCursor(float x, float y, float scale, vec4_t color, const char *text, int cursorPos, char cursor, int limit, int style) {
00425   int len, count;
00426     vec4_t newColor;
00427     glyphInfo_t *glyph, *glyph2;
00428     float yadj;
00429     float useScale;
00430     fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
00431     if (scale <= ui_smallFont.value) {
00432         font = &uiInfo.uiDC.Assets.smallFont;
00433     } else if (scale >= ui_bigFont.value) {
00434         font = &uiInfo.uiDC.Assets.bigFont;
00435     }
00436     useScale = scale * font->glyphScale;
00437   if (text) {
00438     const char *s = text; // bk001206 - unsigned
00439         trap_R_SetColor( color );
00440         memcpy(&newColor[0], &color[0], sizeof(vec4_t));
00441     len = strlen(text);
00442         if (limit > 0 && len > limit) {
00443             len = limit;
00444         }
00445         count = 0;
00446         glyph2 = &font->glyphs[ (int) cursor]; // bk001206 - possible signed char
00447         while (s && *s && count < len) {
00448             glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
00449       //int yadj = Assets.textFont.glyphs[text[i]].bottom + Assets.textFont.glyphs[text[i]].top;
00450       //float yadj = scale * (Assets.textFont.glyphs[text[i]].imageHeight - Assets.textFont.glyphs[text[i]].height);
00451             if ( Q_IsColorString( s ) ) {
00452                 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
00453                 newColor[3] = color[3];
00454                 trap_R_SetColor( newColor );
00455                 s += 2;
00456                 continue;
00457             } else {
00458                 yadj = useScale * glyph->top;
00459                 if (style == ITEM_TEXTSTYLE_SHADOWED || style == ITEM_TEXTSTYLE_SHADOWEDMORE) {
00460                     int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2;
00461                     colorBlack[3] = newColor[3];
00462                     trap_R_SetColor( colorBlack );
00463                     Text_PaintChar(x + ofs, y - yadj + ofs, 
00464                                                         glyph->imageWidth,
00465                                                         glyph->imageHeight,
00466                                                         useScale, 
00467                                                         glyph->s,
00468                                                         glyph->t,
00469                                                         glyph->s2,
00470                                                         glyph->t2,
00471                                                         glyph->glyph);
00472                     colorBlack[3] = 1.0;
00473                     trap_R_SetColor( newColor );
00474                 }
00475                 Text_PaintChar(x, y - yadj, 
00476                                                     glyph->imageWidth,
00477                                                     glyph->imageHeight,
00478                                                     useScale, 
00479                                                     glyph->s,
00480                                                     glyph->t,
00481                                                     glyph->s2,
00482                                                     glyph->t2,
00483                                                     glyph->glyph);
00484 
00485           yadj = useScale * glyph2->top;
00486             if (count == cursorPos && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
00487                     Text_PaintChar(x, y - yadj, 
00488                                                         glyph2->imageWidth,
00489                                                         glyph2->imageHeight,
00490                                                         useScale, 
00491                                                         glyph2->s,
00492                                                         glyph2->t,
00493                                                         glyph2->s2,
00494                                                         glyph2->t2,
00495                                                         glyph2->glyph);
00496                 }
00497 
00498                 x += (glyph->xSkip * useScale);
00499                 s++;
00500                 count++;
00501             }
00502     }
00503     // need to paint cursor at end of text
00504     if (cursorPos == len && !((uiInfo.uiDC.realTime/BLINK_DIVISOR) & 1)) {
00505         yadj = useScale * glyph2->top;
00506         Text_PaintChar(x, y - yadj, 
00507                           glyph2->imageWidth,
00508                           glyph2->imageHeight,
00509                           useScale, 
00510                           glyph2->s,
00511                           glyph2->t,
00512                           glyph2->s2,
00513                           glyph2->t2,
00514                           glyph2->glyph);
00515 
00516     }
00517 
00518       trap_R_SetColor( NULL );
00519   }
00520 }
00521 
00522 
00523 static void Text_Paint_Limit(float *maxX, float x, float y, float scale, vec4_t color, const char* text, float adjust, int limit) {
00524   int len, count;
00525     vec4_t newColor;
00526     glyphInfo_t *glyph;
00527   if (text) {
00528     const char *s = text; // bk001206 - unsigned
00529         float max = *maxX;
00530         float useScale;
00531         fontInfo_t *font = &uiInfo.uiDC.Assets.textFont;
00532         if (scale <= ui_smallFont.value) {
00533             font = &uiInfo.uiDC.Assets.smallFont;
00534         } else if (scale > ui_bigFont.value) {
00535             font = &uiInfo.uiDC.Assets.bigFont;
00536         }
00537         useScale = scale * font->glyphScale;
00538         trap_R_SetColor( color );
00539     len = strlen(text);                  
00540         if (limit > 0 && len > limit) {
00541             len = limit;
00542         }
00543         count = 0;
00544         while (s && *s && count < len) {
00545             glyph = &font->glyphs[(int)*s]; // TTimo: FIXME: getting nasty warnings without the cast, hopefully this doesn't break the VM build
00546             if ( Q_IsColorString( s ) ) {
00547                 memcpy( newColor, g_color_table[ColorIndex(*(s+1))], sizeof( newColor ) );
00548                 newColor[3] = color[3];
00549                 trap_R_SetColor( newColor );
00550                 s += 2;
00551                 continue;
00552             } else {
00553           float yadj = useScale * glyph->top;
00554                 if (Text_Width(s, useScale, 1) + x > max) {
00555                     *maxX = 0;
00556                     break;
00557                 }
00558             Text_PaintChar(x, y - yadj, 
00559                              glyph->imageWidth,
00560                                glyph->imageHeight,
00561                                useScale, 
00562                                    glyph->s,
00563                                        glyph->t,
00564                                        glyph->s2,
00565                                          glyph->t2,
00566                                            glyph->glyph);
00567           x += (glyph->xSkip * useScale) + adjust;
00568                 *maxX = x;
00569                 count++;
00570                 s++;
00571         }
00572         }
00573       trap_R_SetColor( NULL );
00574   }
00575 
00576 }
00577 
00578 
00579 void UI_ShowPostGame(qboolean newHigh) {
00580     trap_Cvar_Set ("cg_cameraOrbit", "0");
00581     trap_Cvar_Set("cg_thirdPerson", "0");
00582     trap_Cvar_Set( "sv_killserver", "1" );
00583     uiInfo.soundHighScore = newHigh;
00584   _UI_SetActiveMenu(UIMENU_POSTGAME);
00585 }
00586 /*
00587 =================
00588 _UI_Refresh
00589 =================
00590 */
00591 
00592 void UI_DrawCenteredPic(qhandle_t image, int w, int h) {
00593   int x, y;
00594   x = (SCREEN_WIDTH - w) / 2;
00595   y = (SCREEN_HEIGHT - h) / 2;
00596   UI_DrawHandlePic(x, y, w, h, image);
00597 }
00598 
00599 int frameCount = 0;
00600 int startTime;
00601 
00602 #define UI_FPS_FRAMES   4
00603 void _UI_Refresh( int realtime )
00604 {
00605     static int index;
00606     static int  previousTimes[UI_FPS_FRAMES];
00607 
00608     //if ( !( trap_Key_GetCatcher() & KEYCATCH_UI ) ) {
00609     //  return;
00610     //}
00611 
00612     uiInfo.uiDC.frameTime = realtime - uiInfo.uiDC.realTime;
00613     uiInfo.uiDC.realTime = realtime;
00614 
00615     previousTimes[index % UI_FPS_FRAMES] = uiInfo.uiDC.frameTime;
00616     index++;
00617     if ( index > UI_FPS_FRAMES ) {
00618         int i, total;
00619         // average multiple frames together to smooth changes out a bit
00620         total = 0;
00621         for ( i = 0 ; i < UI_FPS_FRAMES ; i++ ) {
00622             total += previousTimes[i];
00623         }
00624         if ( !total ) {
00625             total = 1;
00626         }
00627         uiInfo.uiDC.FPS = 1000 * UI_FPS_FRAMES / total;
00628     }
00629 
00630 
00631 
00632     UI_UpdateCvars();
00633 
00634     if (Menu_Count() > 0) {
00635         // paint all the menus
00636         Menu_PaintAll();
00637         // refresh server browser list
00638         UI_DoServerRefresh();
00639         // refresh server status
00640         UI_BuildServerStatus(qfalse);
00641         // refresh find player list
00642         UI_BuildFindPlayerList(qfalse);
00643     } 
00644     
00645     // draw cursor
00646     UI_SetColor( NULL );
00647     if (Menu_Count() > 0) {
00648         UI_DrawHandlePic( uiInfo.uiDC.cursorx-16, uiInfo.uiDC.cursory-16, 32, 32, uiInfo.uiDC.Assets.cursor);
00649     }
00650 
00651 #ifndef NDEBUG
00652     if (uiInfo.uiDC.debug)
00653     {
00654         // cursor coordinates
00655         //FIXME
00656         //UI_DrawString( 0, 0, va("(%d,%d)",uis.cursorx,uis.cursory), UI_LEFT|UI_SMALLFONT, colorRed );
00657     }
00658 #endif
00659 
00660 }
00661 
00662 /*
00663 =================
00664 _UI_Shutdown
00665 =================
00666 */
00667 void _UI_Shutdown( void ) {
00668     trap_LAN_SaveCachedServers();
00669 }
00670 
00671 char *defaultMenu = NULL;
00672 
00673 char *GetMenuBuffer(const char *filename) {
00674     int len;
00675     fileHandle_t    f;
00676     static char buf[MAX_MENUFILE];
00677 
00678     len = trap_FS_FOpenFile( filename, &f, FS_READ );
00679     if ( !f ) {
00680         trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
00681         return defaultMenu;
00682     }
00683     if ( len >= MAX_MENUFILE ) {
00684         trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
00685         trap_FS_FCloseFile( f );
00686         return defaultMenu;
00687     }
00688 
00689     trap_FS_Read( buf, len, f );
00690     buf[len] = 0;
00691     trap_FS_FCloseFile( f );
00692     //COM_Compress(buf);
00693   return buf;
00694 
00695 }
00696 
00697 qboolean Asset_Parse(int handle) {
00698     pc_token_t token;
00699     const char *tempStr;
00700 
00701     if (!trap_PC_ReadToken(handle, &token))
00702         return qfalse;
00703     if (Q_stricmp(token.string, "{") != 0) {
00704         return qfalse;
00705     }
00706     
00707     while ( 1 ) {
00708 
00709         memset(&token, 0, sizeof(pc_token_t));
00710 
00711         if (!trap_PC_ReadToken(handle, &token))
00712             return qfalse;
00713 
00714         if (Q_stricmp(token.string, "}") == 0) {
00715             return qtrue;
00716         }
00717 
00718         // font
00719         if (Q_stricmp(token.string, "font") == 0) {
00720             int pointSize;
00721             if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
00722                 return qfalse;
00723             }
00724             trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.textFont);
00725             uiInfo.uiDC.Assets.fontRegistered = qtrue;
00726             continue;
00727         }
00728 
00729         if (Q_stricmp(token.string, "smallFont") == 0) {
00730             int pointSize;
00731             if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
00732                 return qfalse;
00733             }
00734             trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.smallFont);
00735             continue;
00736         }
00737 
00738         if (Q_stricmp(token.string, "bigFont") == 0) {
00739             int pointSize;
00740             if (!PC_String_Parse(handle, &tempStr) || !PC_Int_Parse(handle,&pointSize)) {
00741                 return qfalse;
00742             }
00743             trap_R_RegisterFont(tempStr, pointSize, &uiInfo.uiDC.Assets.bigFont);
00744             continue;
00745         }
00746 
00747 
00748         // gradientbar
00749         if (Q_stricmp(token.string, "gradientbar") == 0) {
00750             if (!PC_String_Parse(handle, &tempStr)) {
00751                 return qfalse;
00752             }
00753             uiInfo.uiDC.Assets.gradientBar = trap_R_RegisterShaderNoMip(tempStr);
00754             continue;
00755         }
00756 
00757         // enterMenuSound
00758         if (Q_stricmp(token.string, "menuEnterSound") == 0) {
00759             if (!PC_String_Parse(handle, &tempStr)) {
00760                 return qfalse;
00761             }
00762             uiInfo.uiDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse );
00763             continue;
00764         }
00765 
00766         // exitMenuSound
00767         if (Q_stricmp(token.string, "menuExitSound") == 0) {
00768             if (!PC_String_Parse(handle, &tempStr)) {
00769                 return qfalse;
00770             }
00771             uiInfo.uiDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse );
00772             continue;
00773         }
00774 
00775         // itemFocusSound
00776         if (Q_stricmp(token.string, "itemFocusSound") == 0) {
00777             if (!PC_String_Parse(handle, &tempStr)) {
00778                 return qfalse;
00779             }
00780             uiInfo.uiDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse );
00781             continue;
00782         }
00783 
00784         // menuBuzzSound
00785         if (Q_stricmp(token.string, "menuBuzzSound") == 0) {
00786             if (!PC_String_Parse(handle, &tempStr)) {
00787                 return qfalse;
00788             }
00789             uiInfo.uiDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse );
00790             continue;
00791         }
00792 
00793         if (Q_stricmp(token.string, "cursor") == 0) {
00794             if (!PC_String_Parse(handle, &uiInfo.uiDC.Assets.cursorStr)) {
00795                 return qfalse;
00796             }
00797             uiInfo.uiDC.Assets.cursor = trap_R_RegisterShaderNoMip( uiInfo.uiDC.Assets.cursorStr);
00798             continue;
00799         }
00800 
00801         if (Q_stricmp(token.string, "fadeClamp") == 0) {
00802             if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeClamp)) {
00803                 return qfalse;
00804             }
00805             continue;
00806         }
00807 
00808         if (Q_stricmp(token.string, "fadeCycle") == 0) {
00809             if (!PC_Int_Parse(handle, &uiInfo.uiDC.Assets.fadeCycle)) {
00810                 return qfalse;
00811             }
00812             continue;
00813         }
00814 
00815         if (Q_stricmp(token.string, "fadeAmount") == 0) {
00816             if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.fadeAmount)) {
00817                 return qfalse;
00818             }
00819             continue;
00820         }
00821 
00822         if (Q_stricmp(token.string, "shadowX") == 0) {
00823             if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowX)) {
00824                 return qfalse;
00825             }
00826             continue;
00827         }
00828 
00829         if (Q_stricmp(token.string, "shadowY") == 0) {
00830             if (!PC_Float_Parse(handle, &uiInfo.uiDC.Assets.shadowY)) {
00831                 return qfalse;
00832             }
00833             continue;
00834         }
00835 
00836         if (Q_stricmp(token.string, "shadowColor") == 0) {
00837             if (!PC_Color_Parse(handle, &uiInfo.uiDC.Assets.shadowColor)) {
00838                 return qfalse;
00839             }
00840             uiInfo.uiDC.Assets.shadowFadeClamp = uiInfo.uiDC.Assets.shadowColor[3];
00841             continue;
00842         }
00843 
00844     }
00845     return qfalse;
00846 }
00847 
00848 void Font_Report() {
00849   int i;
00850   Com_Printf("Font Info\n");
00851   Com_Printf("=========\n");
00852   for ( i = 32; i < 96; i++) {
00853     Com_Printf("Glyph handle %i: %i\n", i, uiInfo.uiDC.Assets.textFont.glyphs[i].glyph);
00854   }
00855 }
00856 
00857 void UI_Report() {
00858   String_Report();
00859   //Font_Report();
00860 
00861 }
00862 
00863 void UI_ParseMenu(const char *menuFile) {
00864     int handle;
00865     pc_token_t token;
00866 
00867     Com_Printf("Parsing menu file:%s\n", menuFile);
00868 
00869     handle = trap_PC_LoadSource(menuFile);
00870     if (!handle) {
00871         return;
00872     }
00873 
00874     while ( 1 ) {
00875         memset(&token, 0, sizeof(pc_token_t));
00876         if (!trap_PC_ReadToken( handle, &token )) {
00877             break;
00878         }
00879 
00880         //if ( Q_stricmp( token, "{" ) ) {
00881         //  Com_Printf( "Missing { in menu file\n" );
00882         //  break;
00883         //}
00884 
00885         //if ( menuCount == MAX_MENUS ) {
00886         //  Com_Printf( "Too many menus!\n" );
00887         //  break;
00888         //}
00889 
00890         if ( token.string[0] == '}' ) {
00891             break;
00892         }
00893 
00894         if (Q_stricmp(token.string, "assetGlobalDef") == 0) {
00895             if (Asset_Parse(handle)) {
00896                 continue;
00897             } else {
00898                 break;
00899             }
00900         }
00901 
00902         if (Q_stricmp(token.string, "menudef") == 0) {
00903             // start a new menu
00904             Menu_New(handle);
00905         }
00906     }
00907     trap_PC_FreeSource(handle);
00908 }
00909 
00910 qboolean Load_Menu(int handle) {
00911     pc_token_t token;
00912 
00913     if (!trap_PC_ReadToken(handle, &token))
00914         return qfalse;
00915     if (token.string[0] != '{') {
00916         return qfalse;
00917     }
00918 
00919     while ( 1 ) {
00920 
00921         if (!trap_PC_ReadToken(handle, &token))
00922             return qfalse;
00923     
00924         if ( token.string[0] == 0 ) {
00925             return qfalse;
00926         }
00927 
00928         if ( token.string[0] == '}' ) {
00929             return qtrue;
00930         }
00931 
00932         UI_ParseMenu(token.string); 
00933     }
00934     return qfalse;
00935 }
00936 
00937 void UI_LoadMenus(const char *menuFile, qboolean reset) {
00938     pc_token_t token;
00939     int handle;
00940     int start;
00941 
00942     start = trap_Milliseconds();
00943 
00944     handle = trap_PC_LoadSource( menuFile );
00945     if (!handle) {
00946         trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) );
00947         handle = trap_PC_LoadSource( "ui/menus.txt" );
00948         if (!handle) {
00949             trap_Error( va( S_COLOR_RED "default menu file not found: ui/menus.txt, unable to continue!\n", menuFile ) );
00950         }
00951     }
00952 
00953     ui_new.integer = 1;
00954 
00955     if (reset) {
00956         Menu_Reset();
00957     }
00958 
00959     while ( 1 ) {
00960         if (!trap_PC_ReadToken(handle, &token))
00961             break;
00962         if( token.string[0] == 0 || token.string[0] == '}') {
00963             break;
00964         }
00965 
00966         if ( token.string[0] == '}' ) {
00967             break;
00968         }
00969 
00970         if (Q_stricmp(token.string, "loadmenu") == 0) {
00971             if (Load_Menu(handle)) {
00972                 continue;
00973             } else {
00974                 break;
00975             }
00976         }
00977     }
00978 
00979     Com_Printf("UI menu load time = %d milli seconds\n", trap_Milliseconds() - start);
00980 
00981     trap_PC_FreeSource( handle );
00982 }
00983 
00984 void UI_Load() {
00985     char lastName[1024];
00986   menuDef_t *menu = Menu_GetFocused();
00987     char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
00988     if (menu && menu->window.name) {
00989         strcpy(lastName, menu->window.name);
00990     }
00991     if (menuSet == NULL || menuSet[0] == '\0') {
00992         menuSet = "ui/menus.txt";
00993     }
00994 
00995     String_Init();
00996 
00997 #ifdef PRE_RELEASE_TADEMO
00998     UI_ParseGameInfo("demogameinfo.txt");
00999 #else
01000     UI_ParseGameInfo("gameinfo.txt");
01001     UI_LoadArenas();
01002 #endif
01003 
01004     UI_LoadMenus(menuSet, qtrue);
01005     Menus_CloseAll();
01006     Menus_ActivateByName(lastName);
01007 
01008 }
01009 
01010 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};
01011 #ifndef MISSIONPACK // bk001206
01012 static int numHandicaps = sizeof(handicapValues) / sizeof(const char*);
01013 #endif
01014 
01015 static void UI_DrawHandicap(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01016   int i, h;
01017 
01018   h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
01019   i = 20 - h / 5;
01020 
01021   Text_Paint(rect->x, rect->y, scale, color, handicapValues[i], 0, 0, textStyle);
01022 }
01023 
01024 static void UI_DrawClanName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01025   Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_teamName"), 0, 0, textStyle);
01026 }
01027 
01028 
01029 static void UI_SetCapFragLimits(qboolean uiVars) {
01030     int cap = 5;
01031     int frag = 10;
01032     if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_OBELISK) {
01033         cap = 4;
01034     } else if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_HARVESTER) {
01035         cap = 15;
01036     }
01037     if (uiVars) {
01038         trap_Cvar_Set("ui_captureLimit", va("%d", cap));
01039         trap_Cvar_Set("ui_fragLimit", va("%d", frag));
01040     } else {
01041         trap_Cvar_Set("capturelimit", va("%d", cap));
01042         trap_Cvar_Set("fraglimit", va("%d", frag));
01043     }
01044 }
01045 // ui_gameType assumes gametype 0 is -1 ALL and will not show
01046 static void UI_DrawGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01047   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_gameType.integer].gameType, 0, 0, textStyle);
01048 }
01049 
01050 static void UI_DrawNetGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01051     if (ui_netGameType.integer < 0 || ui_netGameType.integer > uiInfo.numGameTypes) {
01052         trap_Cvar_Set("ui_netGameType", "0");
01053         trap_Cvar_Set("ui_actualNetGameType", "0");
01054     }
01055   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[ui_netGameType.integer].gameType , 0, 0, textStyle);
01056 }
01057 
01058 static void UI_DrawJoinGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01059     if (ui_joinGameType.integer < 0 || ui_joinGameType.integer > uiInfo.numJoinGameTypes) {
01060         trap_Cvar_Set("ui_joinGameType", "0");
01061     }
01062   Text_Paint(rect->x, rect->y, scale, color, uiInfo.joinGameTypes[ui_joinGameType.integer].gameType , 0, 0, textStyle);
01063 }
01064 
01065 
01066 
01067 static int UI_TeamIndexFromName(const char *name) {
01068   int i;
01069 
01070   if (name && *name) {
01071     for (i = 0; i < uiInfo.teamCount; i++) {
01072       if (Q_stricmp(name, uiInfo.teamList[i].teamName) == 0) {
01073         return i;
01074       }
01075     }
01076   } 
01077 
01078   return 0;
01079 
01080 }
01081 
01082 static void UI_DrawClanLogo(rectDef_t *rect, float scale, vec4_t color) {
01083   int i;
01084   i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01085   if (i >= 0 && i < uiInfo.teamCount) {
01086     trap_R_SetColor( color );
01087 
01088         if (uiInfo.teamList[i].teamIcon == -1) {
01089       uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01090       uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01091       uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01092         }
01093 
01094     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
01095     trap_R_SetColor(NULL);
01096   }
01097 }
01098 
01099 static void UI_DrawClanCinematic(rectDef_t *rect, float scale, vec4_t color) {
01100   int i;
01101   i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01102   if (i >= 0 && i < uiInfo.teamCount) {
01103 
01104         if (uiInfo.teamList[i].cinematic >= -2) {
01105             if (uiInfo.teamList[i].cinematic == -1) {
01106                 uiInfo.teamList[i].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.teamList[i].imageName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
01107             }
01108             if (uiInfo.teamList[i].cinematic >= 0) {
01109               trap_CIN_RunCinematic(uiInfo.teamList[i].cinematic);
01110                 trap_CIN_SetExtents(uiInfo.teamList[i].cinematic, rect->x, rect->y, rect->w, rect->h);
01111                 trap_CIN_DrawCinematic(uiInfo.teamList[i].cinematic);
01112             } else {
01113                 trap_R_SetColor( color );
01114                 UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal);
01115                 trap_R_SetColor(NULL);
01116                 uiInfo.teamList[i].cinematic = -2;
01117             }
01118         } else {
01119         trap_R_SetColor( color );
01120             UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon);
01121             trap_R_SetColor(NULL);
01122         }
01123     }
01124 
01125 }
01126 
01127 static void UI_DrawPreviewCinematic(rectDef_t *rect, float scale, vec4_t color) {
01128     if (uiInfo.previewMovie > -2) {
01129         uiInfo.previewMovie = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.movieList[uiInfo.movieIndex]), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
01130         if (uiInfo.previewMovie >= 0) {
01131           trap_CIN_RunCinematic(uiInfo.previewMovie);
01132             trap_CIN_SetExtents(uiInfo.previewMovie, rect->x, rect->y, rect->w, rect->h);
01133             trap_CIN_DrawCinematic(uiInfo.previewMovie);
01134         } else {
01135             uiInfo.previewMovie = -2;
01136         }
01137     } 
01138 
01139 }
01140 
01141 
01142 
01143 static void UI_DrawSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01144   int i;
01145     i = trap_Cvar_VariableValue( "g_spSkill" );
01146   if (i < 1 || i > numSkillLevels) {
01147     i = 1;
01148   }
01149   Text_Paint(rect->x, rect->y, scale, color, skillLevels[i-1],0, 0, textStyle);
01150 }
01151 
01152 
01153 static void UI_DrawTeamName(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int textStyle) {
01154   int i;
01155   i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
01156   if (i >= 0 && i < uiInfo.teamCount) {
01157     Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", (blue) ? "Blue" : "Red", uiInfo.teamList[i].teamName),0, 0, textStyle);
01158   }
01159 }
01160 
01161 static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboolean blue, int num, int textStyle) {
01162     // 0 - None
01163     // 1 - Human
01164     // 2..NumCharacters - Bot
01165     int value = trap_Cvar_VariableValue(va(blue ? "ui_blueteam%i" : "ui_redteam%i", num));
01166     const char *text;
01167     if (value <= 0) {
01168         text = "Closed";
01169     } else if (value == 1) {
01170         text = "Human";
01171     } else {
01172         value -= 2;
01173 
01174         if (ui_actualNetGameType.integer >= GT_TEAM) {
01175             if (value >= uiInfo.characterCount) {
01176                 value = 0;
01177             }
01178             text = uiInfo.characterList[value].name;
01179         } else {
01180             if (value >= UI_GetNumBots()) {
01181                 value = 0;
01182             }
01183             text = UI_GetBotNameByNumber(value);
01184         }
01185     }
01186   Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
01187 }
01188 
01189 static void UI_DrawEffects(rectDef_t *rect, float scale, vec4_t color) {
01190     UI_DrawHandlePic( rect->x, rect->y - 14, 128, 8, uiInfo.uiDC.Assets.fxBasePic );
01191     UI_DrawHandlePic( rect->x + uiInfo.effectsColor * 16 + 8, rect->y - 16, 16, 12, uiInfo.uiDC.Assets.fxPic[uiInfo.effectsColor] );
01192 }
01193 
01194 static void UI_DrawMapPreview(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
01195     int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
01196     if (map < 0 || map > uiInfo.mapCount) {
01197         if (net) {
01198             ui_currentNetMap.integer = 0;
01199             trap_Cvar_Set("ui_currentNetMap", "0");
01200         } else {
01201             ui_currentMap.integer = 0;
01202             trap_Cvar_Set("ui_currentMap", "0");
01203         }
01204         map = 0;
01205     }
01206 
01207     if (uiInfo.mapList[map].levelShot == -1) {
01208         uiInfo.mapList[map].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[map].imageName);
01209     }
01210 
01211     if (uiInfo.mapList[map].levelShot > 0) {
01212         UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.mapList[map].levelShot);
01213     } else {
01214         UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
01215     }
01216 }                        
01217 
01218 
01219 static void UI_DrawMapTimeToBeat(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01220     int minutes, seconds, time;
01221     if (ui_currentMap.integer < 0 || ui_currentMap.integer > uiInfo.mapCount) {
01222         ui_currentMap.integer = 0;
01223         trap_Cvar_Set("ui_currentMap", "0");
01224     }
01225 
01226     time = uiInfo.mapList[ui_currentMap.integer].timeToBeat[uiInfo.gameTypes[ui_gameType.integer].gtEnum];
01227 
01228     minutes = time / 60;
01229     seconds = time % 60;
01230 
01231   Text_Paint(rect->x, rect->y, scale, color, va("%02i:%02i", minutes, seconds), 0, 0, textStyle);
01232 }
01233 
01234 
01235 
01236 static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboolean net) {
01237 
01238     int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer; 
01239     if (map < 0 || map > uiInfo.mapCount) {
01240         if (net) {
01241             ui_currentNetMap.integer = 0;
01242             trap_Cvar_Set("ui_currentNetMap", "0");
01243         } else {
01244             ui_currentMap.integer = 0;
01245             trap_Cvar_Set("ui_currentMap", "0");
01246         }
01247         map = 0;
01248     }
01249 
01250     if (uiInfo.mapList[map].cinematic >= -1) {
01251         if (uiInfo.mapList[map].cinematic == -1) {
01252             uiInfo.mapList[map].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[map].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
01253         }
01254         if (uiInfo.mapList[map].cinematic >= 0) {
01255           trap_CIN_RunCinematic(uiInfo.mapList[map].cinematic);
01256           trap_CIN_SetExtents(uiInfo.mapList[map].cinematic, rect->x, rect->y, rect->w, rect->h);
01257             trap_CIN_DrawCinematic(uiInfo.mapList[map].cinematic);
01258         } else {
01259             uiInfo.mapList[map].cinematic = -2;
01260         }
01261     } else {
01262         UI_DrawMapPreview(rect, scale, color, net);
01263     }
01264 }
01265 
01266 
01267 
01268 static qboolean updateModel = qtrue;
01269 static qboolean q3Model = qfalse;
01270 
01271 static void UI_DrawPlayerModel(rectDef_t *rect) {
01272   static playerInfo_t info;
01273   char model[MAX_QPATH];
01274   char team[256];
01275     char head[256];
01276     vec3_t  viewangles;
01277     vec3_t  moveangles;
01278 
01279       if (trap_Cvar_VariableValue("ui_Q3Model")) {
01280       strcpy(model, UI_Cvar_VariableString("model"));
01281         strcpy(head, UI_Cvar_VariableString("headmodel"));
01282         if (!q3Model) {
01283             q3Model = qtrue;
01284             updateModel = qtrue;
01285         }
01286         team[0] = '\0';
01287     } else {
01288 
01289         strcpy(team, UI_Cvar_VariableString("ui_teamName"));
01290         strcpy(model, UI_Cvar_VariableString("team_model"));
01291         strcpy(head, UI_Cvar_VariableString("team_headmodel"));
01292         if (q3Model) {
01293             q3Model = qfalse;
01294             updateModel = qtrue;
01295         }
01296     }
01297   if (updateModel) {
01298     memset( &info, 0, sizeof(playerInfo_t) );
01299     viewangles[YAW]   = 180 - 10;
01300     viewangles[PITCH] = 0;
01301     viewangles[ROLL]  = 0;
01302     VectorClear( moveangles );
01303     UI_PlayerInfo_SetModel( &info, model, head, team);
01304     UI_PlayerInfo_SetInfo( &info, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
01305 //      UI_RegisterClientModelname( &info, model, head, team);
01306     updateModel = qfalse;
01307   }
01308 
01309   UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2);
01310 
01311 }
01312 
01313 static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01314     if (ui_netSource.integer < 0 || ui_netSource.integer > numNetSources) {
01315         ui_netSource.integer = 0;
01316     }
01317   Text_Paint(rect->x, rect->y, scale, color, va("Source: %s", netSources[ui_netSource.integer]), 0, 0, textStyle);
01318 }
01319 
01320 static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) {
01321 
01322     if (uiInfo.serverStatus.currentServerPreview > 0) {
01323         UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.serverStatus.currentServerPreview);
01324     } else {
01325         UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, trap_R_RegisterShaderNoMip("menu/art/unknownmap"));
01326     }
01327 }
01328 
01329 static void UI_DrawNetMapCinematic(rectDef_t *rect, float scale, vec4_t color) {
01330     if (ui_currentNetMap.integer < 0 || ui_currentNetMap.integer > uiInfo.mapCount) {
01331         ui_currentNetMap.integer = 0;
01332         trap_Cvar_Set("ui_currentNetMap", "0");
01333     }
01334 
01335     if (uiInfo.serverStatus.currentServerCinematic >= 0) {
01336       trap_CIN_RunCinematic(uiInfo.serverStatus.currentServerCinematic);
01337       trap_CIN_SetExtents(uiInfo.serverStatus.currentServerCinematic, rect->x, rect->y, rect->w, rect->h);
01338       trap_CIN_DrawCinematic(uiInfo.serverStatus.currentServerCinematic);
01339     } else {
01340         UI_DrawNetMapPreview(rect, scale, color);
01341     }
01342 }
01343 
01344 
01345 
01346 static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01347     if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
01348         ui_serverFilterType.integer = 0;
01349     }
01350   Text_Paint(rect->x, rect->y, scale, color, va("Filter: %s", serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle);
01351 }
01352 
01353 
01354 static void UI_DrawTier(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01355   int i;
01356     i = trap_Cvar_VariableValue( "ui_currentTier" );
01357   if (i < 0 || i >= uiInfo.tierCount) {
01358     i = 0;
01359   }
01360   Text_Paint(rect->x, rect->y, scale, color, va("Tier: %s", uiInfo.tierList[i].tierName),0, 0, textStyle);
01361 }
01362 
01363 static void UI_DrawTierMap(rectDef_t *rect, int index) {
01364   int i;
01365     i = trap_Cvar_VariableValue( "ui_currentTier" );
01366   if (i < 0 || i >= uiInfo.tierCount) {
01367     i = 0;
01368   }
01369 
01370     if (uiInfo.tierList[i].mapHandles[index] == -1) {
01371         uiInfo.tierList[i].mapHandles[index] = trap_R_RegisterShaderNoMip(va("levelshots/%s", uiInfo.tierList[i].maps[index]));
01372     }
01373                                                  
01374     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.tierList[i].mapHandles[index]);
01375 }
01376 
01377 static const char *UI_EnglishMapName(const char *map) {
01378     int i;
01379     for (i = 0; i < uiInfo.mapCount; i++) {
01380         if (Q_stricmp(map, uiInfo.mapList[i].mapLoadName) == 0) {
01381             return uiInfo.mapList[i].mapName;
01382         }
01383     }
01384     return "";
01385 }
01386 
01387 static void UI_DrawTierMapName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01388   int i, j;
01389     i = trap_Cvar_VariableValue( "ui_currentTier" );
01390   if (i < 0 || i >= uiInfo.tierCount) {
01391     i = 0;
01392   }
01393     j = trap_Cvar_VariableValue("ui_currentMap");
01394     if (j < 0 || j > MAPS_PER_TIER) {
01395         j = 0;
01396     }
01397 
01398   Text_Paint(rect->x, rect->y, scale, color, UI_EnglishMapName(uiInfo.tierList[i].maps[j]), 0, 0, textStyle);
01399 }
01400 
01401 static void UI_DrawTierGameType(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01402   int i, j;
01403     i = trap_Cvar_VariableValue( "ui_currentTier" );
01404   if (i < 0 || i >= uiInfo.tierCount) {
01405     i = 0;
01406   }
01407     j = trap_Cvar_VariableValue("ui_currentMap");
01408     if (j < 0 || j > MAPS_PER_TIER) {
01409         j = 0;
01410     }
01411 
01412   Text_Paint(rect->x, rect->y, scale, color, uiInfo.gameTypes[uiInfo.tierList[i].gameTypes[j]].gameType , 0, 0, textStyle);
01413 }
01414 
01415 
01416 #ifndef MISSIONPACK // bk001206
01417 static const char *UI_OpponentLeaderName() {
01418   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01419     return uiInfo.teamList[i].teamMembers[0];
01420 }
01421 #endif
01422 
01423 static const char *UI_AIFromName(const char *name) {
01424     int j;
01425     for (j = 0; j < uiInfo.aliasCount; j++) {
01426         if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
01427             return uiInfo.aliasList[j].ai;
01428         }
01429     }
01430     return "James";
01431 }
01432 
01433 #ifndef MISSIONPACK // bk001206
01434 static const int UI_AIIndex(const char *name) {
01435     int j;
01436     for (j = 0; j < uiInfo.characterCount; j++) {
01437         if (Q_stricmp(name, uiInfo.characterList[j].name) == 0) {
01438             return j;
01439         }
01440     }
01441     return 0;
01442 }
01443 #endif
01444 
01445 #ifndef MISSIONPACK // bk001206
01446 static const int UI_AIIndexFromName(const char *name) {
01447     int j;
01448     for (j = 0; j < uiInfo.aliasCount; j++) {
01449         if (Q_stricmp(uiInfo.aliasList[j].name, name) == 0) {
01450             return UI_AIIndex(uiInfo.aliasList[j].ai);
01451         }
01452     }
01453     return 0;
01454 }
01455 #endif
01456 
01457 
01458 #ifndef MISSIONPACK // bk001206
01459 static const char *UI_OpponentLeaderHead() {
01460     const char *leader = UI_OpponentLeaderName();
01461     return UI_AIFromName(leader);
01462 }
01463 #endif
01464 
01465 #ifndef MISSIONPACK // bk001206
01466 static const char *UI_OpponentLeaderModel() {
01467     int i;
01468     const char *head = UI_OpponentLeaderHead();
01469     for (i = 0; i < uiInfo.characterCount; i++) {
01470         if (Q_stricmp(head, uiInfo.characterList[i].name) == 0) {
01471             return uiInfo.characterList[i].base;
01472         }
01473     }
01474     return "James";
01475 }
01476 #endif
01477 
01478 
01479 static qboolean updateOpponentModel = qtrue;
01480 static void UI_DrawOpponent(rectDef_t *rect) {
01481   static playerInfo_t info2;
01482   char model[MAX_QPATH];
01483   char headmodel[MAX_QPATH];
01484   char team[256];
01485     vec3_t  viewangles;
01486     vec3_t  moveangles;
01487   
01488     if (updateOpponentModel) {
01489         
01490         strcpy(model, UI_Cvar_VariableString("ui_opponentModel"));
01491       strcpy(headmodel, UI_Cvar_VariableString("ui_opponentModel"));
01492         team[0] = '\0';
01493 
01494     memset( &info2, 0, sizeof(playerInfo_t) );
01495     viewangles[YAW]   = 180 - 10;
01496     viewangles[PITCH] = 0;
01497     viewangles[ROLL]  = 0;
01498     VectorClear( moveangles );
01499     UI_PlayerInfo_SetModel( &info2, model, headmodel, "");
01500     UI_PlayerInfo_SetInfo( &info2, LEGS_IDLE, TORSO_STAND, viewangles, vec3_origin, WP_MACHINEGUN, qfalse );
01501         UI_RegisterClientModelname( &info2, model, headmodel, team);
01502     updateOpponentModel = qfalse;
01503   }
01504 
01505   UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2);
01506 
01507 }
01508 
01509 static void UI_NextOpponent() {
01510   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01511   int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01512     i++;
01513     if (i >= uiInfo.teamCount) {
01514         i = 0;
01515     }
01516     if (i == j) {
01517         i++;
01518         if ( i >= uiInfo.teamCount) {
01519             i = 0;
01520         }
01521     }
01522     trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
01523 }
01524 
01525 static void UI_PriorOpponent() {
01526   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01527   int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01528     i--;
01529     if (i < 0) {
01530         i = uiInfo.teamCount - 1;
01531     }
01532     if (i == j) {
01533         i--;
01534         if ( i < 0) {
01535             i = uiInfo.teamCount - 1;
01536         }
01537     }
01538     trap_Cvar_Set( "ui_opponentName", uiInfo.teamList[i].teamName );
01539 }
01540 
01541 static void UI_DrawPlayerLogo(rectDef_t *rect, vec3_t color) {
01542   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01543 
01544     if (uiInfo.teamList[i].teamIcon == -1) {
01545     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01546     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01547     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01548     }
01549 
01550     trap_R_SetColor( color );
01551     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
01552     trap_R_SetColor( NULL );
01553 }
01554 
01555 static void UI_DrawPlayerLogoMetal(rectDef_t *rect, vec3_t color) {
01556   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01557     if (uiInfo.teamList[i].teamIcon == -1) {
01558     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01559     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01560     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01561     }
01562 
01563     trap_R_SetColor( color );
01564     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
01565     trap_R_SetColor( NULL );
01566 }
01567 
01568 static void UI_DrawPlayerLogoName(rectDef_t *rect, vec3_t color) {
01569   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
01570     if (uiInfo.teamList[i].teamIcon == -1) {
01571     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01572     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01573     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01574     }
01575 
01576     trap_R_SetColor( color );
01577     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
01578     trap_R_SetColor( NULL );
01579 }
01580 
01581 static void UI_DrawOpponentLogo(rectDef_t *rect, vec3_t color) {
01582   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01583     if (uiInfo.teamList[i].teamIcon == -1) {
01584     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01585     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01586     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01587     }
01588 
01589     trap_R_SetColor( color );
01590     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon );
01591     trap_R_SetColor( NULL );
01592 }
01593 
01594 static void UI_DrawOpponentLogoMetal(rectDef_t *rect, vec3_t color) {
01595   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01596     if (uiInfo.teamList[i].teamIcon == -1) {
01597     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01598     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01599     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01600     }
01601 
01602     trap_R_SetColor( color );
01603     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Metal );
01604     trap_R_SetColor( NULL );
01605 }
01606 
01607 static void UI_DrawOpponentLogoName(rectDef_t *rect, vec3_t color) {
01608   int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
01609     if (uiInfo.teamList[i].teamIcon == -1) {
01610     uiInfo.teamList[i].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[i].imageName);
01611     uiInfo.teamList[i].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[i].imageName));
01612     uiInfo.teamList[i].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[i].imageName));
01613     }
01614 
01615     trap_R_SetColor( color );
01616     UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.teamList[i].teamIcon_Name );
01617     trap_R_SetColor( NULL );
01618 }
01619 
01620 static void UI_DrawAllMapsSelection(rectDef_t *rect, float scale, vec4_t color, int textStyle, qboolean net) {
01621     int map = (net) ? ui_currentNetMap.integer : ui_currentMap.integer;
01622     if (map >= 0 && map < uiInfo.mapCount) {
01623       Text_Paint(rect->x, rect->y, scale, color, uiInfo.mapList[map].mapName, 0, 0, textStyle);
01624     }
01625 }
01626 
01627 static void UI_DrawOpponentName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01628   Text_Paint(rect->x, rect->y, scale, color, UI_Cvar_VariableString("ui_opponentName"), 0, 0, textStyle);
01629 }
01630 
01631 
01632 static int UI_OwnerDrawWidth(int ownerDraw, float scale) {
01633     int i, h, value;
01634     const char *text;
01635     const char *s = NULL;
01636 
01637   switch (ownerDraw) {
01638     case UI_HANDICAP:
01639               h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
01640                 i = 20 - h / 5;
01641                 s = handicapValues[i];
01642       break;
01643     case UI_CLANNAME:
01644                 s = UI_Cvar_VariableString("ui_teamName");
01645       break;
01646     case UI_GAMETYPE:
01647                 s = uiInfo.gameTypes[ui_gameType.integer].gameType;
01648       break;
01649     case UI_SKILL:
01650                 i = trap_Cvar_VariableValue( "g_spSkill" );
01651                 if (i < 1 || i > numSkillLevels) {
01652                     i = 1;
01653                 }
01654               s = skillLevels[i-1];
01655       break;
01656     case UI_BLUETEAMNAME:
01657               i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_blueTeam"));
01658               if (i >= 0 && i < uiInfo.teamCount) {
01659                 s = va("%s: %s", "Blue", uiInfo.teamList[i].teamName);
01660               }
01661       break;
01662     case UI_REDTEAMNAME:
01663               i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_redTeam"));
01664               if (i >= 0 && i < uiInfo.teamCount) {
01665                 s = va("%s: %s", "Red", uiInfo.teamList[i].teamName);
01666               }
01667       break;
01668     case UI_BLUETEAM1:
01669         case UI_BLUETEAM2:
01670         case UI_BLUETEAM3:
01671         case UI_BLUETEAM4:
01672         case UI_BLUETEAM5:
01673             value = trap_Cvar_VariableValue(va("ui_blueteam%i", ownerDraw-UI_BLUETEAM1 + 1));
01674             if (value <= 0) {
01675                 text = "Closed";
01676             } else if (value == 1) {
01677                 text = "Human";
01678             } else {
01679                 value -= 2;
01680                 if (value >= uiInfo.aliasCount) {
01681                     value = 0;
01682                 }
01683                 text = uiInfo.aliasList[value].name;
01684             }
01685             s = va("%i. %s", ownerDraw-UI_BLUETEAM1 + 1, text);
01686       break;
01687     case UI_REDTEAM1:
01688         case UI_REDTEAM2:
01689         case UI_REDTEAM3:
01690         case UI_REDTEAM4:
01691         case UI_REDTEAM5:
01692             value = trap_Cvar_VariableValue(va("ui_redteam%i", ownerDraw-UI_REDTEAM1 + 1));
01693             if (value <= 0) {
01694                 text = "Closed";
01695             } else if (value == 1) {
01696                 text = "Human";
01697             } else {
01698                 value -= 2;
01699                 if (value >= uiInfo.aliasCount) {
01700                     value = 0;
01701                 }
01702                 text = uiInfo.aliasList[value].name;
01703             }
01704             s = va("%i. %s", ownerDraw-UI_REDTEAM1 + 1, text);
01705       break;
01706         case UI_NETSOURCE:
01707             if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) {
01708                 ui_netSource.integer = 0;
01709             }
01710             s = va("Source: %s", netSources[ui_netSource.integer]);
01711             break;
01712         case UI_NETFILTER:
01713             if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) {
01714                 ui_serverFilterType.integer = 0;
01715             }
01716             s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description );
01717             break;
01718         case UI_TIER:
01719             break;
01720         case UI_TIER_MAPNAME:
01721             break;
01722         case UI_TIER_GAMETYPE:
01723             break;
01724         case UI_ALLMAPS_SELECTION:
01725             break;
01726         case UI_OPPONENT_NAME:
01727             break;
01728         case UI_KEYBINDSTATUS:
01729             if (Display_KeyBindPending()) {
01730                 s = "Waiting for new key... Press ESCAPE to cancel";
01731             } else {
01732                 s = "Press ENTER or CLICK to change, Press BACKSPACE to clear";
01733             }
01734             break;
01735         case UI_SERVERREFRESHDATE:
01736             s = UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer));
01737             break;
01738     default:
01739       break;
01740   }
01741 
01742     if (s) {
01743         return Text_Width(s, scale, 0);
01744     }
01745     return 0;
01746 }
01747 
01748 static void UI_DrawBotName(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01749     int value = uiInfo.botIndex;
01750     int game = trap_Cvar_VariableValue("g_gametype");
01751     const char *text = "";
01752     if (game >= GT_TEAM) {
01753         if (value >= uiInfo.characterCount) {
01754             value = 0;
01755         }
01756         text = uiInfo.characterList[value].name;
01757     } else {
01758         if (value >= UI_GetNumBots()) {
01759             value = 0;
01760         }
01761         text = UI_GetBotNameByNumber(value);
01762     }
01763   Text_Paint(rect->x, rect->y, scale, color, text, 0, 0, textStyle);
01764 }
01765 
01766 static void UI_DrawBotSkill(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01767     if (uiInfo.skillIndex >= 0 && uiInfo.skillIndex < numSkillLevels) {
01768       Text_Paint(rect->x, rect->y, scale, color, skillLevels[uiInfo.skillIndex], 0, 0, textStyle);
01769     }
01770 }
01771 
01772 static void UI_DrawRedBlue(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01773   Text_Paint(rect->x, rect->y, scale, color, (uiInfo.redBlue == 0) ? "Red" : "Blue", 0, 0, textStyle);
01774 }
01775 
01776 static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) {
01777     trap_R_SetColor( color );
01778     if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
01779         uiInfo.currentCrosshair = 0;
01780     }
01781     UI_DrawHandlePic( rect->x, rect->y - rect->h, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]);
01782     trap_R_SetColor( NULL );
01783 }
01784 
01785 /*
01786 ===============
01787 UI_BuildPlayerList
01788 ===============
01789 */
01790 static void UI_BuildPlayerList() {
01791     uiClientState_t cs;
01792     int     n, count, team, team2, playerTeamNumber;
01793     char    info[MAX_INFO_STRING];
01794 
01795     trap_GetClientState( &cs );
01796     trap_GetConfigString( CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING );
01797     uiInfo.playerNumber = cs.clientNum;
01798     uiInfo.teamLeader = atoi(Info_ValueForKey(info, "tl"));
01799     team = atoi(Info_ValueForKey(info, "t"));
01800     trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) );
01801     count = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
01802     uiInfo.playerCount = 0;
01803     uiInfo.myTeamCount = 0;
01804     playerTeamNumber = 0;
01805     for( n = 0; n < count; n++ ) {
01806         trap_GetConfigString( CS_PLAYERS + n, info, MAX_INFO_STRING );
01807 
01808         if (info[0]) {
01809             Q_strncpyz( uiInfo.playerNames[uiInfo.playerCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
01810             Q_CleanStr( uiInfo.playerNames[uiInfo.playerCount] );
01811             uiInfo.playerCount++;
01812             team2 = atoi(Info_ValueForKey(info, "t"));
01813             if (team2 == team) {
01814                 Q_strncpyz( uiInfo.teamNames[uiInfo.myTeamCount], Info_ValueForKey( info, "n" ), MAX_NAME_LENGTH );
01815                 Q_CleanStr( uiInfo.teamNames[uiInfo.myTeamCount] );
01816                 uiInfo.teamClientNums[uiInfo.myTeamCount] = n;
01817                 if (uiInfo.playerNumber == n) {
01818                     playerTeamNumber = uiInfo.myTeamCount;
01819                 }
01820                 uiInfo.myTeamCount++;
01821             }
01822         }
01823     }
01824 
01825     if (!uiInfo.teamLeader) {
01826         trap_Cvar_Set("cg_selectedPlayer", va("%d", playerTeamNumber));
01827     }
01828 
01829     n = trap_Cvar_VariableValue("cg_selectedPlayer");
01830     if (n < 0 || n > uiInfo.myTeamCount) {
01831         n = 0;
01832     }
01833     if (n < uiInfo.myTeamCount) {
01834         trap_Cvar_Set("cg_selectedPlayerName", uiInfo.teamNames[n]);
01835     }
01836 }
01837 
01838 
01839 static void UI_DrawSelectedPlayer(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01840     if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
01841         uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
01842         UI_BuildPlayerList();
01843     }
01844   Text_Paint(rect->x, rect->y, scale, color, (uiInfo.teamLeader) ? UI_Cvar_VariableString("cg_selectedPlayerName") : UI_Cvar_VariableString("name") , 0, 0, textStyle);
01845 }
01846 
01847 static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01848     if (uiInfo.serverStatus.refreshActive) {
01849         vec4_t lowLight, newColor;
01850         lowLight[0] = 0.8 * color[0]; 
01851         lowLight[1] = 0.8 * color[1]; 
01852         lowLight[2] = 0.8 * color[2]; 
01853         lowLight[3] = 0.8 * color[3]; 
01854         LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR));
01855       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);
01856     } else {
01857         char buff[64];
01858         Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64);
01859       Text_Paint(rect->x, rect->y, scale, color, va("Refresh Time: %s", buff), 0, 0, textStyle);
01860     }
01861 }
01862 
01863 static void UI_DrawServerMOTD(rectDef_t *rect, float scale, vec4_t color) {
01864     if (uiInfo.serverStatus.motdLen) {
01865         float maxX;
01866      
01867         if (uiInfo.serverStatus.motdWidth == -1) {
01868             uiInfo.serverStatus.motdWidth = 0;
01869             uiInfo.serverStatus.motdPaintX = rect->x + 1;
01870             uiInfo.serverStatus.motdPaintX2 = -1;
01871         }
01872 
01873         if (uiInfo.serverStatus.motdOffset > uiInfo.serverStatus.motdLen) {
01874             uiInfo.serverStatus.motdOffset = 0;
01875             uiInfo.serverStatus.motdPaintX = rect->x + 1;
01876             uiInfo.serverStatus.motdPaintX2 = -1;
01877         }
01878 
01879         if (uiInfo.uiDC.realTime > uiInfo.serverStatus.motdTime) {
01880             uiInfo.serverStatus.motdTime = uiInfo.uiDC.realTime + 10;
01881             if (uiInfo.serverStatus.motdPaintX <= rect->x + 2) {
01882                 if (uiInfo.serverStatus.motdOffset < uiInfo.serverStatus.motdLen) {
01883                     uiInfo.serverStatus.motdPaintX += Text_Width(&uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], scale, 1) - 1;
01884                     uiInfo.serverStatus.motdOffset++;
01885                 } else {
01886                     uiInfo.serverStatus.motdOffset = 0;
01887                     if (uiInfo.serverStatus.motdPaintX2 >= 0) {
01888                         uiInfo.serverStatus.motdPaintX = uiInfo.serverStatus.motdPaintX2;
01889                     } else {
01890                         uiInfo.serverStatus.motdPaintX = rect->x + rect->w - 2;
01891                     }
01892                     uiInfo.serverStatus.motdPaintX2 = -1;
01893                 }
01894             } else {
01895                 //serverStatus.motdPaintX--;
01896                 uiInfo.serverStatus.motdPaintX -= 2;
01897                 if (uiInfo.serverStatus.motdPaintX2 >= 0) {
01898                     //serverStatus.motdPaintX2--;
01899                     uiInfo.serverStatus.motdPaintX2 -= 2;
01900                 }
01901             }
01902         }
01903 
01904         maxX = rect->x + rect->w - 2;
01905         Text_Paint_Limit(&maxX, uiInfo.serverStatus.motdPaintX, rect->y + rect->h - 3, scale, color, &uiInfo.serverStatus.motd[uiInfo.serverStatus.motdOffset], 0, 0); 
01906         if (uiInfo.serverStatus.motdPaintX2 >= 0) {
01907             float maxX2 = rect->x + rect->w - 2;
01908             Text_Paint_Limit(&maxX2, uiInfo.serverStatus.motdPaintX2, rect->y + rect->h - 3, scale, color, uiInfo.serverStatus.motd, 0, uiInfo.serverStatus.motdOffset); 
01909         }
01910         if (uiInfo.serverStatus.motdOffset && maxX > 0) {
01911             // if we have an offset ( we are skipping the first part of the string ) and we fit the string
01912             if (uiInfo.serverStatus.motdPaintX2 == -1) {
01913                         uiInfo.serverStatus.motdPaintX2 = rect->x + rect->w - 2;
01914             }
01915         } else {
01916             uiInfo.serverStatus.motdPaintX2 = -1;
01917         }
01918 
01919     }
01920 }
01921 
01922 static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01923 //  int ofs = 0; TTimo: unused
01924     if (Display_KeyBindPending()) {
01925         Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle);
01926     } else {
01927         Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle);
01928     }
01929 }
01930 
01931 static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textStyle) {
01932     char * eptr;
01933     char buff[1024];
01934     const char *lines[64];
01935     int y, numLines, i;
01936 
01937     Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle);
01938     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);
01939     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);
01940 
01941     // build null terminated extension strings
01942   // TTimo: https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=399
01943   // in TA this was not directly crashing, but displaying a nasty broken shader right in the middle
01944   // brought down the string size to 1024, there's not much that can be shown on the screen anyway
01945     Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 1024);
01946     eptr = buff;
01947     y = rect->y + 45;
01948     numLines = 0;
01949     while ( y < rect->y + rect->h && *eptr )
01950     {
01951         while ( *eptr && *eptr == ' ' )
01952             *eptr++ = '\0';
01953 
01954         // track start of valid string
01955         if (*eptr && *eptr != ' ') {
01956             lines[numLines++] = eptr;
01957         }
01958 
01959         while ( *eptr && *eptr != ' ' )
01960             eptr++;
01961     }
01962 
01963     i = 0;
01964     while (i < numLines) {
01965         Text_Paint(rect->x + 2, y, scale, color, lines[i++], 0, 20, textStyle);
01966         if (i < numLines) {
01967             Text_Paint(rect->x + rect->w / 2, y, scale, color, lines[i++], 0, 20, textStyle);
01968         }
01969         y += 10;
01970         if (y > rect->y + rect->h - 11) {
01971             break;
01972         }
01973     }
01974 
01975 
01976 }
01977 
01978 // FIXME: table drive
01979 //
01980 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) {
01981     rectDef_t rect;
01982 
01983   rect.x = x + text_x;
01984   rect.y = y + text_y;
01985   rect.w = w;
01986   rect.h = h;
01987 
01988   switch (ownerDraw) {
01989     case UI_HANDICAP:
01990       UI_DrawHandicap(&rect, scale, color, textStyle);
01991       break;
01992     case UI_EFFECTS:
01993       UI_DrawEffects(&rect, scale, color);
01994       break;
01995     case UI_PLAYERMODEL:
01996       UI_DrawPlayerModel(&rect);
01997       break;
01998     case UI_CLANNAME:
01999       UI_DrawClanName(&rect, scale, color, textStyle);
02000       break;
02001     case UI_CLANLOGO:
02002       UI_DrawClanLogo(&rect, scale, color);
02003       break;
02004     case UI_CLANCINEMATIC:
02005       UI_DrawClanCinematic(&rect, scale, color);
02006       break;
02007     case UI_PREVIEWCINEMATIC:
02008       UI_DrawPreviewCinematic(&rect, scale, color);
02009       break;
02010     case UI_GAMETYPE:
02011       UI_DrawGameType(&rect, scale, color, textStyle);
02012       break;
02013     case UI_NETGAMETYPE:
02014       UI_DrawNetGameType(&rect, scale, color, textStyle);
02015       break;
02016     case UI_JOINGAMETYPE:
02017       UI_DrawJoinGameType(&rect, scale, color, textStyle);
02018       break;
02019     case UI_MAPPREVIEW:
02020       UI_DrawMapPreview(&rect, scale, color, qtrue);
02021       break;
02022     case UI_MAP_TIMETOBEAT:
02023       UI_DrawMapTimeToBeat(&rect, scale, color, textStyle);
02024       break;
02025     case UI_MAPCINEMATIC:
02026       UI_DrawMapCinematic(&rect, scale, color, qfalse);
02027       break;
02028     case UI_STARTMAPCINEMATIC:
02029       UI_DrawMapCinematic(&rect, scale, color, qtrue);
02030       break;
02031     case UI_SKILL:
02032       UI_DrawSkill(&rect, scale, color, textStyle);
02033       break;
02034     case UI_BLUETEAMNAME:
02035       UI_DrawTeamName(&rect, scale, color, qtrue, textStyle);
02036       break;
02037     case UI_REDTEAMNAME:
02038       UI_DrawTeamName(&rect, scale, color, qfalse, textStyle);
02039       break;
02040     case UI_BLUETEAM1:
02041         case UI_BLUETEAM2:
02042         case UI_BLUETEAM3:
02043         case UI_BLUETEAM4:
02044         case UI_BLUETEAM5:
02045       UI_DrawTeamMember(&rect, scale, color, qtrue, ownerDraw - UI_BLUETEAM1 + 1, textStyle);
02046       break;
02047     case UI_REDTEAM1:
02048         case UI_REDTEAM2:
02049         case UI_REDTEAM3:
02050         case UI_REDTEAM4:
02051         case UI_REDTEAM5:
02052       UI_DrawTeamMember(&rect, scale, color, qfalse, ownerDraw - UI_REDTEAM1 + 1, textStyle);
02053       break;
02054         case UI_NETSOURCE:
02055       UI_DrawNetSource(&rect, scale, color, textStyle);
02056             break;
02057     case UI_NETMAPPREVIEW:
02058       UI_DrawNetMapPreview(&rect, scale, color);
02059       break;
02060     case UI_NETMAPCINEMATIC:
02061       UI_DrawNetMapCinematic(&rect, scale, color);
02062       break;
02063         case UI_NETFILTER:
02064       UI_DrawNetFilter(&rect, scale, color, textStyle);
02065             break;
02066         case UI_TIER:
02067             UI_DrawTier(&rect, scale, color, textStyle);
02068             break;
02069         case UI_OPPONENTMODEL:
02070             UI_DrawOpponent(&rect);
02071             break;
02072         case UI_TIERMAP1:
02073             UI_DrawTierMap(&rect, 0);
02074             break;
02075         case UI_TIERMAP2:
02076             UI_DrawTierMap(&rect, 1);
02077             break;
02078         case UI_TIERMAP3:
02079             UI_DrawTierMap(&rect, 2);
02080             break;
02081         case UI_PLAYERLOGO:
02082             UI_DrawPlayerLogo(&rect, color);
02083             break;
02084         case UI_PLAYERLOGO_METAL:
02085             UI_DrawPlayerLogoMetal(&rect, color);
02086             break;
02087         case UI_PLAYERLOGO_NAME:
02088             UI_DrawPlayerLogoName(&rect, color);
02089             break;
02090         case UI_OPPONENTLOGO:
02091             UI_DrawOpponentLogo(&rect, color);
02092             break;
02093         case UI_OPPONENTLOGO_METAL:
02094             UI_DrawOpponentLogoMetal(&rect, color);
02095             break;
02096         case UI_OPPONENTLOGO_NAME:
02097             UI_DrawOpponentLogoName(&rect, color);
02098             break;
02099         case UI_TIER_MAPNAME:
02100             UI_DrawTierMapName(&rect, scale, color, textStyle);
02101             break;
02102         case UI_TIER_GAMETYPE:
02103             UI_DrawTierGameType(&rect, scale, color, textStyle);
02104             break;
02105         case UI_ALLMAPS_SELECTION:
02106             UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qtrue);
02107             break;
02108         case UI_MAPS_SELECTION:
02109             UI_DrawAllMapsSelection(&rect, scale, color, textStyle, qfalse);
02110             break;
02111         case UI_OPPONENT_NAME:
02112             UI_DrawOpponentName(&rect, scale, color, textStyle);
02113             break;
02114         case UI_BOTNAME:
02115             UI_DrawBotName(&rect, scale, color, textStyle);
02116             break;
02117         case UI_BOTSKILL:
02118             UI_DrawBotSkill(&rect, scale, color, textStyle);
02119             break;
02120         case UI_REDBLUE:
02121             UI_DrawRedBlue(&rect, scale, color, textStyle);
02122             break;
02123         case UI_CROSSHAIR:
02124             UI_DrawCrosshair(&rect, scale, color);
02125             break;
02126         case UI_SELECTEDPLAYER:
02127             UI_DrawSelectedPlayer(&rect, scale, color, textStyle);
02128             break;
02129         case UI_SERVERREFRESHDATE:
02130             UI_DrawServerRefreshDate(&rect, scale, color, textStyle);
02131             break;
02132         case UI_SERVERMOTD:
02133             UI_DrawServerMOTD(&rect, scale, color);
02134             break;
02135         case UI_GLINFO:
02136             UI_DrawGLInfo(&rect,scale, color, textStyle);
02137             break;
02138         case UI_KEYBINDSTATUS:
02139             UI_DrawKeyBindStatus(&rect,scale, color, textStyle);
02140             break;
02141     default:
02142       break;
02143   }
02144 
02145 }
02146 
02147 static qboolean UI_OwnerDrawVisible(int flags) {
02148     qboolean vis = qtrue;
02149 
02150     while (flags) {
02151 
02152         if (flags & UI_SHOW_FFA) {
02153             if (trap_Cvar_VariableValue("g_gametype") != GT_FFA) {
02154                 vis = qfalse;
02155             }
02156             flags &= ~UI_SHOW_FFA;
02157         }
02158 
02159         if (flags & UI_SHOW_NOTFFA) {
02160             if (trap_Cvar_VariableValue("g_gametype") == GT_FFA) {
02161                 vis = qfalse;
02162             }
02163             flags &= ~UI_SHOW_NOTFFA;
02164         }
02165 
02166         if (flags & UI_SHOW_LEADER) {
02167             // these need to show when this client can give orders to a player or a group
02168             if (!uiInfo.teamLeader) {
02169                 vis = qfalse;
02170             } else {
02171                 // if showing yourself
02172                 if (ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber) { 
02173                     vis = qfalse;
02174                 }
02175             }
02176             flags &= ~UI_SHOW_LEADER;
02177         } 
02178         if (flags & UI_SHOW_NOTLEADER) {
02179             // these need to show when this client is assigning their own status or they are NOT the leader
02180             if (uiInfo.teamLeader) {
02181                 // if not showing yourself
02182                 if (!(ui_selectedPlayer.integer < uiInfo.myTeamCount && uiInfo.teamClientNums[ui_selectedPlayer.integer] == uiInfo.playerNumber)) { 
02183                     vis = qfalse;
02184                 }
02185                 // these need to show when this client can give orders to a player or a group
02186             }
02187             flags &= ~UI_SHOW_NOTLEADER;
02188         } 
02189         if (flags & UI_SHOW_FAVORITESERVERS) {
02190             // this assumes you only put this type of display flag on something showing in the proper context
02191             if (ui_netSource.integer != AS_FAVORITES) {
02192                 vis = qfalse;
02193             }
02194             flags &= ~UI_SHOW_FAVORITESERVERS;
02195         } 
02196         if (flags & UI_SHOW_NOTFAVORITESERVERS) {
02197             // this assumes you only put this type of display flag on something showing in the proper context
02198             if (ui_netSource.integer == AS_FAVORITES) {
02199                 vis = qfalse;
02200             }
02201             flags &= ~UI_SHOW_NOTFAVORITESERVERS;
02202         } 
02203         if (flags & UI_SHOW_ANYTEAMGAME) {
02204             if (uiInfo.gameTypes[ui_gameType.integer].gtEnum <= GT_TEAM ) {
02205                 vis = qfalse;
02206             }
02207             flags &= ~UI_SHOW_ANYTEAMGAME;
02208         } 
02209         if (flags & UI_SHOW_ANYNONTEAMGAME) {
02210             if (uiInfo.gameTypes[ui_gameType.integer].gtEnum > GT_TEAM ) {
02211                 vis = qfalse;
02212             }
02213             flags &= ~UI_SHOW_ANYNONTEAMGAME;
02214         } 
02215         if (flags & UI_SHOW_NETANYTEAMGAME) {
02216             if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum <= GT_TEAM ) {
02217                 vis = qfalse;
02218             }
02219             flags &= ~UI_SHOW_NETANYTEAMGAME;
02220         } 
02221         if (flags & UI_SHOW_NETANYNONTEAMGAME) {
02222             if (uiInfo.gameTypes[ui_netGameType.integer].gtEnum > GT_TEAM ) {
02223                 vis = qfalse;
02224             }
02225             flags &= ~UI_SHOW_NETANYNONTEAMGAME;
02226         } 
02227         if (flags & UI_SHOW_NEWHIGHSCORE) {
02228             if (uiInfo.newHighScoreTime < uiInfo.uiDC.realTime) {
02229                 vis = qfalse;
02230             } else {
02231                 if (uiInfo.soundHighScore) {
02232                     if (trap_Cvar_VariableValue("sv_killserver") == 0) {
02233                         // wait on server to go down before playing sound
02234                         trap_S_StartLocalSound(uiInfo.newHighScoreSound, CHAN_ANNOUNCER);
02235                         uiInfo.soundHighScore = qfalse;
02236                     }
02237                 }
02238             }
02239             flags &= ~UI_SHOW_NEWHIGHSCORE;
02240         } 
02241         if (flags & UI_SHOW_NEWBESTTIME) {
02242             if (uiInfo.newBestTime < uiInfo.uiDC.realTime) {
02243                 vis = qfalse;
02244             }
02245             flags &= ~UI_SHOW_NEWBESTTIME;
02246         } 
02247         if (flags & UI_SHOW_DEMOAVAILABLE) {
02248             if (!uiInfo.demoAvailable) {
02249                 vis = qfalse;
02250             }
02251             flags &= ~UI_SHOW_DEMOAVAILABLE;
02252         } else {
02253             flags = 0;
02254         }
02255     }
02256   return vis;
02257 }
02258 
02259 static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) {
02260   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02261     int h;
02262     h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") );
02263         if (key == K_MOUSE2) {
02264         h -= 5;
02265         } else {
02266         h += 5;
02267         }
02268     if (h > 100) {
02269       h = 5;
02270     } else if (h < 0) {
02271             h = 100;
02272         }
02273     trap_Cvar_Set( "handicap", va( "%i", h) );
02274     return qtrue;
02275   }
02276   return qfalse;
02277 }
02278 
02279 static qboolean UI_Effects_HandleKey(int flags, float *special, int key) {
02280   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02281 
02282         if (key == K_MOUSE2) {
02283         uiInfo.effectsColor--;
02284         } else {
02285         uiInfo.effectsColor++;
02286         }
02287 
02288     if( uiInfo.effectsColor > 6 ) {
02289         uiInfo.effectsColor = 0;
02290         } else if (uiInfo.effectsColor < 0) {
02291         uiInfo.effectsColor = 6;
02292         }
02293 
02294       trap_Cvar_SetValue( "color1", uitogamecode[uiInfo.effectsColor] );
02295     return qtrue;
02296   }
02297   return qfalse;
02298 }
02299 
02300 static qboolean UI_ClanName_HandleKey(int flags, float *special, int key) {
02301   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02302     int i;
02303     i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
02304         if (uiInfo.teamList[i].cinematic >= 0) {
02305           trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
02306             uiInfo.teamList[i].cinematic = -1;
02307         }
02308         if (key == K_MOUSE2) {
02309         i--;
02310         } else {
02311         i++;
02312         }
02313     if (i >= uiInfo.teamCount) {
02314       i = 0;
02315     } else if (i < 0) {
02316             i = uiInfo.teamCount - 1;
02317         }
02318     trap_Cvar_Set( "ui_teamName", uiInfo.teamList[i].teamName);
02319     UI_HeadCountByTeam();
02320     UI_FeederSelection(FEEDER_HEADS, 0);
02321     updateModel = qtrue;
02322     return qtrue;
02323   }
02324   return qfalse;
02325 }
02326 
02327 static qboolean UI_GameType_HandleKey(int flags, float *special, int key, qboolean resetMap) {
02328   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02329         int oldCount = UI_MapCountByGameType(qtrue);
02330 
02331         // hard coded mess here
02332         if (key == K_MOUSE2) {
02333             ui_gameType.integer--;
02334             if (ui_gameType.integer == 2) {
02335                 ui_gameType.integer = 1;
02336             } else if (ui_gameType.integer < 2) {
02337                 ui_gameType.integer = uiInfo.numGameTypes - 1;
02338             }
02339         } else {
02340             ui_gameType.integer++;
02341             if (ui_gameType.integer >= uiInfo.numGameTypes) {
02342                 ui_gameType.integer = 1;
02343             } else if (ui_gameType.integer == 2) {
02344                 ui_gameType.integer = 3;
02345             }
02346         }
02347     
02348         if (uiInfo.gameTypes[ui_gameType.integer].gtEnum == GT_TOURNAMENT) {
02349             trap_Cvar_Set("ui_Q3Model", "1");
02350         } else {
02351             trap_Cvar_Set("ui_Q3Model", "0");
02352         }
02353 
02354         trap_Cvar_Set("ui_gameType", va("%d", ui_gameType.integer));
02355         UI_SetCapFragLimits(qtrue);
02356         UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
02357         if (resetMap && oldCount != UI_MapCountByGameType(qtrue)) {
02358         trap_Cvar_Set( "ui_currentMap", "0");
02359             Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, NULL);
02360         }
02361     return qtrue;
02362   }
02363   return qfalse;
02364 }
02365 
02366 static qboolean UI_NetGameType_HandleKey(int flags, float *special, int key) {
02367   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02368 
02369         if (key == K_MOUSE2) {
02370             ui_netGameType.integer--;
02371         } else {
02372             ui_netGameType.integer++;
02373         }
02374 
02375     if (ui_netGameType.integer < 0) {
02376       ui_netGameType.integer = uiInfo.numGameTypes - 1;
02377         } else if (ui_netGameType.integer >= uiInfo.numGameTypes) {
02378       ui_netGameType.integer = 0;
02379     } 
02380 
02381     trap_Cvar_Set( "ui_netGameType", va("%d", ui_netGameType.integer));
02382     trap_Cvar_Set( "ui_actualnetGameType", va("%d", uiInfo.gameTypes[ui_netGameType.integer].gtEnum));
02383     trap_Cvar_Set( "ui_currentNetMap", "0");
02384         UI_MapCountByGameType(qfalse);
02385         Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, NULL);
02386     return qtrue;
02387   }
02388   return qfalse;
02389 }
02390 
02391 static qboolean UI_JoinGameType_HandleKey(int flags, float *special, int key) {
02392     if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02393 
02394         if (key == K_MOUSE2) {
02395             ui_joinGameType.integer--;
02396         } else {
02397             ui_joinGameType.integer++;
02398         }
02399 
02400         if (ui_joinGameType.integer < 0) {
02401             ui_joinGameType.integer = uiInfo.numJoinGameTypes - 1;
02402         } else if (ui_joinGameType.integer >= uiInfo.numJoinGameTypes) {
02403             ui_joinGameType.integer = 0;
02404         }
02405 
02406         trap_Cvar_Set( "ui_joinGameType", va("%d", ui_joinGameType.integer));
02407         UI_BuildServerDisplayList(qtrue);
02408         return qtrue;
02409     }
02410     return qfalse;
02411 }
02412 
02413 
02414 
02415 static qboolean UI_Skill_HandleKey(int flags, float *special, int key) {
02416   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02417     int i = trap_Cvar_VariableValue( "g_spSkill" );
02418 
02419         if (key == K_MOUSE2) {
02420         i--;
02421         } else {
02422         i++;
02423         }
02424 
02425     if (i < 1) {
02426             i = numSkillLevels;
02427         } else if (i > numSkillLevels) {
02428       i = 1;
02429     }
02430 
02431     trap_Cvar_Set("g_spSkill", va("%i", i));
02432     return qtrue;
02433   }
02434   return qfalse;
02435 }
02436 
02437 static qboolean UI_TeamName_HandleKey(int flags, float *special, int key, qboolean blue) {
02438   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02439     int i;
02440     i = UI_TeamIndexFromName(UI_Cvar_VariableString((blue) ? "ui_blueTeam" : "ui_redTeam"));
02441 
02442         if (key == K_MOUSE2) {
02443         i--;
02444         } else {
02445         i++;
02446         }
02447 
02448     if (i >= uiInfo.teamCount) {
02449       i = 0;
02450     } else if (i < 0) {
02451             i = uiInfo.teamCount - 1;
02452         }
02453 
02454     trap_Cvar_Set( (blue) ? "ui_blueTeam" : "ui_redTeam", uiInfo.teamList[i].teamName);
02455 
02456     return qtrue;
02457   }
02458   return qfalse;
02459 }
02460 
02461 static qboolean UI_TeamMember_HandleKey(int flags, float *special, int key, qboolean blue, int num) {
02462   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02463         // 0 - None
02464         // 1 - Human
02465         // 2..NumCharacters - Bot
02466         char *cvar = va(blue ? "ui_blueteam%i" : "ui_redteam%i", num);
02467         int value = trap_Cvar_VariableValue(cvar);
02468 
02469         if (key == K_MOUSE2) {
02470             value--;
02471         } else {
02472             value++;
02473         }
02474 
02475         if (ui_actualNetGameType.integer >= GT_TEAM) {
02476             if (value >= uiInfo.characterCount + 2) {
02477                 value = 0;
02478             } else if (value < 0) {
02479                 value = uiInfo.characterCount + 2 - 1;
02480             }
02481         } else {
02482             if (value >= UI_GetNumBots() + 2) {
02483                 value = 0;
02484             } else if (value < 0) {
02485                 value = UI_GetNumBots() + 2 - 1;
02486             }
02487         }
02488 
02489         trap_Cvar_Set(cvar, va("%i", value));
02490     return qtrue;
02491   }
02492   return qfalse;
02493 }
02494 
02495 static qboolean UI_NetSource_HandleKey(int flags, float *special, int key) {
02496   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02497         
02498         if (key == K_MOUSE2) {
02499             ui_netSource.integer--;
02500             if (ui_netSource.integer == AS_MPLAYER)
02501                 ui_netSource.integer--;
02502         } else {
02503             ui_netSource.integer++;
02504             if (ui_netSource.integer == AS_MPLAYER)
02505                 ui_netSource.integer++;
02506         }
02507     
02508         if (ui_netSource.integer >= numNetSources) {
02509       ui_netSource.integer = 0;
02510     } else if (ui_netSource.integer < 0) {
02511       ui_netSource.integer = numNetSources - 1;
02512         }
02513 
02514         UI_BuildServerDisplayList(qtrue);
02515         if (ui_netSource.integer != AS_GLOBAL) {
02516             UI_StartServerRefresh(qtrue);
02517         }
02518     trap_Cvar_Set( "ui_netSource", va("%d", ui_netSource.integer));
02519     return qtrue;
02520   }
02521   return qfalse;
02522 }
02523 
02524 static qboolean UI_NetFilter_HandleKey(int flags, float *special, int key) {
02525   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02526 
02527         if (key == K_MOUSE2) {
02528             ui_serverFilterType.integer--;
02529         } else {
02530             ui_serverFilterType.integer++;
02531         }
02532 
02533     if (ui_serverFilterType.integer >= numServerFilters) {
02534       ui_serverFilterType.integer = 0;
02535     } else if (ui_serverFilterType.integer < 0) {
02536       ui_serverFilterType.integer = numServerFilters - 1;
02537         }
02538         UI_BuildServerDisplayList(qtrue);
02539     return qtrue;
02540   }
02541   return qfalse;
02542 }
02543 
02544 static qboolean UI_OpponentName_HandleKey(int flags, float *special, int key) {
02545   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02546         if (key == K_MOUSE2) {
02547             UI_PriorOpponent();
02548         } else {
02549             UI_NextOpponent();
02550         }
02551     return qtrue;
02552   }
02553   return qfalse;
02554 }
02555 
02556 static qboolean UI_BotName_HandleKey(int flags, float *special, int key) {
02557   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02558         int game = trap_Cvar_VariableValue("g_gametype");
02559         int value = uiInfo.botIndex;
02560 
02561         if (key == K_MOUSE2) {
02562             value--;
02563         } else {
02564             value++;
02565         }
02566 
02567         if (game >= GT_TEAM) {
02568             if (value >= uiInfo.characterCount + 2) {
02569                 value = 0;
02570             } else if (value < 0) {
02571                 value = uiInfo.characterCount + 2 - 1;
02572             }
02573         } else {
02574             if (value >= UI_GetNumBots() + 2) {
02575                 value = 0;
02576             } else if (value < 0) {
02577                 value = UI_GetNumBots() + 2 - 1;
02578             }
02579         }
02580         uiInfo.botIndex = value;
02581     return qtrue;
02582   }
02583   return qfalse;
02584 }
02585 
02586 static qboolean UI_BotSkill_HandleKey(int flags, float *special, int key) {
02587   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02588         if (key == K_MOUSE2) {
02589             uiInfo.skillIndex--;
02590         } else {
02591             uiInfo.skillIndex++;
02592         }
02593         if (uiInfo.skillIndex >= numSkillLevels) {
02594             uiInfo.skillIndex = 0;
02595         } else if (uiInfo.skillIndex < 0) {
02596             uiInfo.skillIndex = numSkillLevels-1;
02597         }
02598     return qtrue;
02599   }
02600     return qfalse;
02601 }
02602 
02603 static qboolean UI_RedBlue_HandleKey(int flags, float *special, int key) {
02604   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02605         uiInfo.redBlue ^= 1;
02606         return qtrue;
02607     }
02608     return qfalse;
02609 }
02610 
02611 static qboolean UI_Crosshair_HandleKey(int flags, float *special, int key) {
02612   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02613         if (key == K_MOUSE2) {
02614             uiInfo.currentCrosshair--;
02615         } else {
02616             uiInfo.currentCrosshair++;
02617         }
02618 
02619         if (uiInfo.currentCrosshair >= NUM_CROSSHAIRS) {
02620             uiInfo.currentCrosshair = 0;
02621         } else if (uiInfo.currentCrosshair < 0) {
02622             uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1;
02623         }
02624         trap_Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair)); 
02625         return qtrue;
02626     }
02627     return qfalse;
02628 }
02629 
02630 
02631 
02632 static qboolean UI_SelectedPlayer_HandleKey(int flags, float *special, int key) {
02633   if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) {
02634         int selected;
02635 
02636         UI_BuildPlayerList();
02637         if (!uiInfo.teamLeader) {
02638             return qfalse;
02639         }
02640         selected = trap_Cvar_VariableValue("cg_selectedPlayer");
02641         
02642         if (key == K_MOUSE2) {
02643             selected--;
02644         } else {
02645             selected++;
02646         }
02647 
02648         if (selected > uiInfo.myTeamCount) {
02649             selected = 0;
02650         } else if (selected < 0) {
02651             selected = uiInfo.myTeamCount;
02652         }
02653 
02654         if (selected == uiInfo.myTeamCount) {
02655             trap_Cvar_Set( "cg_selectedPlayerName", "Everyone");
02656         } else {
02657             trap_Cvar_Set( "cg_selectedPlayerName", uiInfo.teamNames[selected]);
02658         }
02659         trap_Cvar_Set( "cg_selectedPlayer", va("%d", selected));
02660     }
02661     return qfalse;
02662 }
02663 
02664 
02665 static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) {
02666   switch (ownerDraw) {
02667     case UI_HANDICAP:
02668       return UI_Handicap_HandleKey(flags, special, key);
02669       break;
02670     case UI_EFFECTS:
02671       return UI_Effects_HandleKey(flags, special, key);
02672       break;
02673     case UI_CLANNAME:
02674       return UI_ClanName_HandleKey(flags, special, key);
02675       break;
02676     case UI_GAMETYPE:
02677       return UI_GameType_HandleKey(flags, special, key, qtrue);
02678       break;
02679     case UI_NETGAMETYPE:
02680       return UI_NetGameType_HandleKey(flags, special, key);
02681       break;
02682     case UI_JOINGAMETYPE:
02683       return UI_JoinGameType_HandleKey(flags, special, key);
02684       break;
02685     case UI_SKILL:
02686       return UI_Skill_HandleKey(flags, special, key);
02687       break;
02688     case UI_BLUETEAMNAME:
02689       return UI_TeamName_HandleKey(flags, special, key, qtrue);
02690       break;
02691     case UI_REDTEAMNAME:
02692       return UI_TeamName_HandleKey(flags, special, key, qfalse);
02693       break;
02694     case UI_BLUETEAM1:
02695         case UI_BLUETEAM2:
02696         case UI_BLUETEAM3:
02697         case UI_BLUETEAM4:
02698         case UI_BLUETEAM5:
02699       UI_TeamMember_HandleKey(flags, special, key, qtrue, ownerDraw - UI_BLUETEAM1 + 1);
02700       break;
02701     case UI_REDTEAM1:
02702         case UI_REDTEAM2:
02703         case UI_REDTEAM3:
02704         case UI_REDTEAM4:
02705         case UI_REDTEAM5:
02706       UI_TeamMember_HandleKey(flags, special, key, qfalse, ownerDraw - UI_REDTEAM1 + 1);
02707       break;
02708         case UI_NETSOURCE:
02709       UI_NetSource_HandleKey(flags, special, key);
02710             break;
02711         case UI_NETFILTER:
02712       UI_NetFilter_HandleKey(flags, special, key);
02713             break;
02714         case UI_OPPONENT_NAME:
02715             UI_OpponentName_HandleKey(flags, special, key);
02716             break;
02717         case UI_BOTNAME:
02718             return UI_BotName_HandleKey(flags, special, key);
02719             break;
02720         case UI_BOTSKILL:
02721             return UI_BotSkill_HandleKey(flags, special, key);
02722             break;
02723         case UI_REDBLUE:
02724             UI_RedBlue_HandleKey(flags, special, key);
02725             break;
02726         case UI_CROSSHAIR:
02727             UI_Crosshair_HandleKey(flags, special, key);
02728             break;
02729         case UI_SELECTEDPLAYER:
02730             UI_SelectedPlayer_HandleKey(flags, special, key);
02731             break;
02732     default:
02733       break;
02734   }
02735 
02736   return qfalse;
02737 }
02738 
02739 
02740 static float UI_GetValue(int ownerDraw) {
02741   return 0;
02742 }
02743 
02744 /*
02745 =================
02746 UI_ServersQsortCompare
02747 =================
02748 */
02749 static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ) {
02750     return trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey, uiInfo.serverStatus.sortDir, *(int*)arg1, *(int*)arg2);
02751 }
02752 
02753 
02754 /*
02755 =================
02756 UI_ServersSort
02757 =================
02758 */
02759 void UI_ServersSort(int column, qboolean force) {
02760 
02761     if ( !force ) {
02762         if ( uiInfo.serverStatus.sortKey == column ) {
02763             return;
02764         }
02765     }
02766 
02767     uiInfo.serverStatus.sortKey = column;
02768     qsort( &uiInfo.serverStatus.displayServers[0], uiInfo.serverStatus.numDisplayServers, sizeof(int), UI_ServersQsortCompare);
02769 }
02770 
02771 /*
02772 static void UI_StartSinglePlayer() {
02773     int i,j, k, skill;
02774     char buff[1024];
02775     i = trap_Cvar_VariableValue( "ui_currentTier" );
02776   if (i < 0 || i >= tierCount) {
02777     i = 0;
02778   }
02779     j = trap_Cvar_VariableValue("ui_currentMap");
02780     if (j < 0 || j > MAPS_PER_TIER) {
02781         j = 0;
02782     }
02783 
02784     trap_Cvar_SetValue( "singleplayer", 1 );
02785     trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 7, tierList[i].gameTypes[j] ) );
02786     trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", tierList[i].maps[j] ) );
02787     skill = trap_Cvar_VariableValue( "g_spSkill" );
02788 
02789     if (j == MAPS_PER_TIER-1) {
02790         k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
02791         Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %i %s 250 %s\n", UI_AIFromName(teamList[k].teamMembers[0]), skill, "", teamList[k].teamMembers[0]);
02792     } else {
02793         k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
02794         for (i = 0; i < PLAYERS_PER_TEAM; i++) {
02795             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]);
02796             trap_Cmd_ExecuteText( EXEC_APPEND, buff );
02797         }
02798 
02799         k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
02800         for (i = 1; i < PLAYERS_PER_TEAM; i++) {
02801             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]);
02802             trap_Cmd_ExecuteText( EXEC_APPEND, buff );
02803         }
02804         trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
02805     }
02806     
02807 
02808 }
02809 */
02810 
02811 /*
02812 ===============
02813 UI_LoadMods
02814 ===============
02815 */
02816 static void UI_LoadMods() {
02817     int     numdirs;
02818     char    dirlist[2048];
02819     char    *dirptr;
02820   char  *descptr;
02821     int     i;
02822     int     dirlen;
02823 
02824     uiInfo.modCount = 0;
02825     numdirs = trap_FS_GetFileList( "$modlist", "", dirlist, sizeof(dirlist) );
02826     dirptr  = dirlist;
02827     for( i = 0; i < numdirs; i++ ) {
02828         dirlen = strlen( dirptr ) + 1;
02829     descptr = dirptr + dirlen;
02830         uiInfo.modList[uiInfo.modCount].modName = String_Alloc(dirptr);
02831         uiInfo.modList[uiInfo.modCount].modDescr = String_Alloc(descptr);
02832     dirptr += dirlen + strlen(descptr) + 1;
02833         uiInfo.modCount++;
02834         if (uiInfo.modCount >= MAX_MODS) {
02835             break;
02836         }
02837     }
02838 
02839 }
02840 
02841 
02842 /*
02843 ===============
02844 UI_LoadTeams
02845 ===============
02846 */
02847 static void UI_LoadTeams() {
02848     char    teamList[4096];
02849     char    *teamName;
02850     int     i, len, count;
02851 
02852     count = trap_FS_GetFileList( "", "team", teamList, 4096 );
02853 
02854     if (count) {
02855         teamName = teamList;
02856         for ( i = 0; i < count; i++ ) {
02857             len = strlen( teamName );
02858             UI_ParseTeamInfo(teamName);
02859             teamName += len + 1;
02860         }
02861     }
02862 
02863 }
02864 
02865 
02866 /*
02867 ===============
02868 UI_LoadMovies
02869 ===============
02870 */
02871 static void UI_LoadMovies() {
02872     char    movielist[4096];
02873     char    *moviename;
02874     int     i, len;
02875 
02876     uiInfo.movieCount = trap_FS_GetFileList( "video", "roq", movielist, 4096 );
02877 
02878     if (uiInfo.movieCount) {
02879         if (uiInfo.movieCount > MAX_MOVIES) {
02880             uiInfo.movieCount = MAX_MOVIES;
02881         }
02882         moviename = movielist;
02883         for ( i = 0; i < uiInfo.movieCount; i++ ) {
02884             len = strlen( moviename );
02885             if (!Q_stricmp(moviename +  len - 4,".roq")) {
02886                 moviename[len-4] = '\0';
02887             }
02888             Q_strupr(moviename);
02889             uiInfo.movieList[i] = String_Alloc(moviename);
02890             moviename += len + 1;
02891         }
02892     }
02893 
02894 }
02895 
02896 
02897 
02898 /*
02899 ===============
02900 UI_LoadDemos
02901 ===============
02902 */
02903 static void UI_LoadDemos() {
02904     char    demolist[4096];
02905     char demoExt[32];
02906     char    *demoname;
02907     int     i, len;
02908 
02909     Com_sprintf(demoExt, sizeof(demoExt), "dm_%d", (int)trap_Cvar_VariableValue("protocol"));
02910 
02911     uiInfo.demoCount = trap_FS_GetFileList( "demos", demoExt, demolist, 4096 );
02912 
02913     Com_sprintf(demoExt, sizeof(demoExt), ".dm_%d", (int)trap_Cvar_VariableValue("protocol"));
02914 
02915     if (uiInfo.demoCount) {
02916         if (uiInfo.demoCount > MAX_DEMOS) {
02917             uiInfo.demoCount = MAX_DEMOS;
02918         }
02919         demoname = demolist;
02920         for ( i = 0; i < uiInfo.demoCount; i++ ) {
02921             len = strlen( demoname );
02922             if (!Q_stricmp(demoname +  len - strlen(demoExt), demoExt)) {
02923                 demoname[len-strlen(demoExt)] = '\0';
02924             }
02925             Q_strupr(demoname);
02926             uiInfo.demoList[i] = String_Alloc(demoname);
02927             demoname += len + 1;
02928         }
02929     }
02930 
02931 }
02932 
02933 
02934 static qboolean UI_SetNextMap(int actual, int index) {
02935     int i;
02936     for (i = actual + 1; i < uiInfo.mapCount; i++) {
02937         if (uiInfo.mapList[i].active) {
02938             Menu_SetFeederSelection(NULL, FEEDER_MAPS, index + 1, "skirmish");
02939             return qtrue;
02940         }
02941     }
02942     return qfalse;
02943 }
02944 
02945 
02946 static void UI_StartSkirmish(qboolean next) {
02947     int i, k, g, delay, temp;
02948     float skill;
02949     char buff[MAX_STRING_CHARS];
02950 
02951     if (next) {
02952         int actual;
02953         int index = trap_Cvar_VariableValue("ui_mapIndex");
02954         UI_MapCountByGameType(qtrue);
02955         UI_SelectedMap(index, &actual);
02956         if (UI_SetNextMap(actual, index)) {
02957         } else {
02958             UI_GameType_HandleKey(0, 0, K_MOUSE1, qfalse);
02959             UI_MapCountByGameType(qtrue);
02960             Menu_SetFeederSelection(NULL, FEEDER_MAPS, 0, "skirmish");
02961         }
02962     }
02963 
02964     g = uiInfo.gameTypes[ui_gameType.integer].gtEnum;
02965     trap_Cvar_SetValue( "g_gametype", g );
02966     trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName) );
02967     skill = trap_Cvar_VariableValue( "g_spSkill" );
02968     trap_Cvar_Set("ui_scoreMap", uiInfo.mapList[ui_currentMap.integer].mapName);
02969 
02970     k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName"));
02971 
02972     trap_Cvar_Set("ui_singlePlayerActive", "1");
02973 
02974     // set up sp overrides, will be replaced on postgame
02975     temp = trap_Cvar_VariableValue( "capturelimit" );
02976     trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp));
02977     temp = trap_Cvar_VariableValue( "fraglimit" );
02978     trap_Cvar_Set("ui_saveFragLimit", va("%i", temp));
02979 
02980     UI_SetCapFragLimits(qfalse);
02981 
02982     temp = trap_Cvar_VariableValue( "cg_drawTimer" );
02983     trap_Cvar_Set("ui_drawTimer", va("%i", temp));
02984     temp = trap_Cvar_VariableValue( "g_doWarmup" );
02985     trap_Cvar_Set("ui_doWarmup", va("%i", temp));
02986     temp = trap_Cvar_VariableValue( "g_friendlyFire" );
02987     trap_Cvar_Set("ui_friendlyFire", va("%i", temp));
02988     temp = trap_Cvar_VariableValue( "sv_maxClients" );
02989     trap_Cvar_Set("ui_maxClients", va("%i", temp));
02990     temp = trap_Cvar_VariableValue( "g_warmup" );
02991     trap_Cvar_Set("ui_Warmup", va("%i", temp));
02992     temp = trap_Cvar_VariableValue( "sv_pure" );
02993     trap_Cvar_Set("ui_pure", va("%i", temp));
02994 
02995     trap_Cvar_Set("cg_cameraOrbit", "0");
02996     trap_Cvar_Set("cg_thirdPerson", "0");
02997     trap_Cvar_Set("cg_drawTimer", "1");
02998     trap_Cvar_Set("g_doWarmup", "1");
02999     trap_Cvar_Set("g_warmup", "15");
03000     trap_Cvar_Set("sv_pure", "0");
03001     trap_Cvar_Set("g_friendlyFire", "0");
03002     trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
03003     trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
03004 
03005     if (trap_Cvar_VariableValue("ui_recordSPDemo")) {
03006         Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g);
03007         trap_Cvar_Set("ui_recordSPDemoName", buff);
03008     }
03009 
03010     delay = 500;
03011 
03012     if (g == GT_TOURNAMENT) {
03013         trap_Cvar_Set("sv_maxClients", "2");
03014         Com_sprintf( buff, sizeof(buff), "wait ; addbot %s %f "", %i \n", uiInfo.mapList[ui_currentMap.integer].opponentName, skill, delay);
03015         trap_Cmd_ExecuteText( EXEC_APPEND, buff );
03016     } else {
03017         temp = uiInfo.mapList[ui_currentMap.integer].teamMembers * 2;
03018         trap_Cvar_Set("sv_maxClients", va("%d", temp));
03019         for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers; i++) {
03020             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]);
03021             trap_Cmd_ExecuteText( EXEC_APPEND, buff );
03022             delay += 500;
03023         }
03024         k = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
03025         for (i =0; i < uiInfo.mapList[ui_currentMap.integer].teamMembers-1; i++) {
03026             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]);
03027             trap_Cmd_ExecuteText( EXEC_APPEND, buff );
03028             delay += 500;
03029         }
03030     }
03031     if (g >= GT_TEAM ) {
03032         trap_Cmd_ExecuteText( EXEC_APPEND, "wait 5; team Red\n" );
03033     }
03034 }
03035 
03036 static void UI_Update(const char *name) {
03037     int val = trap_Cvar_VariableValue(name);
03038 
03039     if (Q_stricmp(name, "ui_SetName") == 0) {
03040         trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name"));
03041     } else if (Q_stricmp(name, "ui_setRate") == 0) {
03042         float rate = trap_Cvar_VariableValue("rate");
03043         if (rate >= 5000) {
03044             trap_Cvar_Set("cl_maxpackets", "30");
03045             trap_Cvar_Set("cl_packetdup", "1");
03046         } else if (rate >= 4000) {
03047             trap_Cvar_Set("cl_maxpackets", "15");
03048             trap_Cvar_Set("cl_packetdup", "2");     // favor less prediction errors when there's packet loss
03049         } else {
03050             trap_Cvar_Set("cl_maxpackets", "15");
03051             trap_Cvar_Set("cl_packetdup", "1");     // favor lower bandwidth
03052         }
03053     } else if (Q_stricmp(name, "ui_GetName") == 0) {
03054         trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name"));
03055     } else if (Q_stricmp(name, "r_colorbits") == 0) {
03056         switch (val) {
03057             case 0:
03058                 trap_Cvar_SetValue( "r_depthbits", 0 );
03059                 trap_Cvar_SetValue( "r_stencilbits", 0 );
03060             break;
03061             case 16:
03062                 trap_Cvar_SetValue( "r_depthbits", 16 );
03063                 trap_Cvar_SetValue( "r_stencilbits", 0 );
03064             break;
03065             case 32:
03066                 trap_Cvar_SetValue( "r_depthbits", 24 );
03067             break;
03068         }
03069     } else if (Q_stricmp(name, "r_lodbias") == 0) {
03070         switch (val) {
03071             case 0:
03072                 trap_Cvar_SetValue( "r_subdivisions", 4 );
03073             break;
03074             case 1:
03075                 trap_Cvar_SetValue( "r_subdivisions", 12 );
03076             break;
03077             case 2:
03078                 trap_Cvar_SetValue( "r_subdivisions", 20 );
03079             break;
03080         }
03081     } else if (Q_stricmp(name, "ui_glCustom") == 0) {
03082         switch (val) {
03083             case 0: // high quality
03084                 trap_Cvar_SetValue( "r_fullScreen", 1 );
03085                 trap_Cvar_SetValue( "r_subdivisions", 4 );
03086                 trap_Cvar_SetValue( "r_vertexlight", 0 );
03087                 trap_Cvar_SetValue( "r_lodbias", 0 );
03088                 trap_Cvar_SetValue( "r_colorbits", 32 );
03089                 trap_Cvar_SetValue( "r_depthbits", 24 );
03090                 trap_Cvar_SetValue( "r_picmip", 0 );
03091                 trap_Cvar_SetValue( "r_mode", 4 );
03092                 trap_Cvar_SetValue( "r_texturebits", 32 );
03093                 trap_Cvar_SetValue( "r_fastSky", 0 );
03094                 trap_Cvar_SetValue( "r_inGameVideo", 1 );
03095                 trap_Cvar_SetValue( "cg_shadows", 1 );
03096                 trap_Cvar_SetValue( "cg_brassTime", 2500 );
03097                 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
03098             break;
03099             case 1: // normal 
03100                 trap_Cvar_SetValue( "r_fullScreen", 1 );
03101                 trap_Cvar_SetValue( "r_subdivisions", 12 );
03102                 trap_Cvar_SetValue( "r_vertexlight", 0 );
03103                 trap_Cvar_SetValue( "r_lodbias", 0 );
03104                 trap_Cvar_SetValue( "r_colorbits", 0 );
03105                 trap_Cvar_SetValue( "r_depthbits", 24 );
03106                 trap_Cvar_SetValue( "r_picmip", 1 );
03107                 trap_Cvar_SetValue( "r_mode", 3 );
03108                 trap_Cvar_SetValue( "r_texturebits", 0 );
03109                 trap_Cvar_SetValue( "r_fastSky", 0 );
03110                 trap_Cvar_SetValue( "r_inGameVideo", 1 );
03111                 trap_Cvar_SetValue( "cg_brassTime", 2500 );
03112                 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" );
03113                 trap_Cvar_SetValue( "cg_shadows", 0 );
03114             break;
03115             case 2: // fast
03116                 trap_Cvar_SetValue( "r_fullScreen", 1 );
03117                 trap_Cvar_SetValue( "r_subdivisions", 8 );
03118                 trap_Cvar_SetValue( "r_vertexlight", 0 );
03119                 trap_Cvar_SetValue( "r_lodbias", 1 );
03120                 trap_Cvar_SetValue( "r_colorbits", 0 );
03121                 trap_Cvar_SetValue( "r_depthbits", 0 );
03122                 trap_Cvar_SetValue( "r_picmip", 1 );
03123                 trap_Cvar_SetValue( "r_mode", 3 );
03124                 trap_Cvar_SetValue( "r_texturebits", 0 );
03125                 trap_Cvar_SetValue( "cg_shadows", 0 );
03126                 trap_Cvar_SetValue( "r_fastSky", 1 );
03127                 trap_Cvar_SetValue( "r_inGameVideo", 0 );
03128                 trap_Cvar_SetValue( "cg_brassTime", 0 );
03129                 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
03130             break;
03131             case 3: // fastest
03132                 trap_Cvar_SetValue( "r_fullScreen", 1 );
03133                 trap_Cvar_SetValue( "r_subdivisions", 20 );
03134                 trap_Cvar_SetValue( "r_vertexlight", 1 );
03135                 trap_Cvar_SetValue( "r_lodbias", 2 );
03136                 trap_Cvar_SetValue( "r_colorbits", 16 );
03137                 trap_Cvar_SetValue( "r_depthbits", 16 );
03138                 trap_Cvar_SetValue( "r_mode", 3 );
03139                 trap_Cvar_SetValue( "r_picmip", 2 );
03140                 trap_Cvar_SetValue( "r_texturebits", 16 );
03141                 trap_Cvar_SetValue( "cg_shadows", 0 );
03142                 trap_Cvar_SetValue( "cg_brassTime", 0 );
03143                 trap_Cvar_SetValue( "r_fastSky", 1 );
03144                 trap_Cvar_SetValue( "r_inGameVideo", 0 );
03145                 trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" );
03146             break;
03147         }
03148     } else if (Q_stricmp(name, "ui_mousePitch") == 0) {
03149         if (val == 0) {
03150             trap_Cvar_SetValue( "m_pitch", 0.022f );
03151         } else {
03152             trap_Cvar_SetValue( "m_pitch", -0.022f );
03153         }
03154     }
03155 }
03156 
03157 static void UI_RunMenuScript(char **args) {
03158     const char *name, *name2;
03159     char buff[1024];
03160 
03161     if (String_Parse(args, &name)) {
03162         if (Q_stricmp(name, "StartServer") == 0) {
03163             int i, clients, oldclients;
03164             float skill;
03165             trap_Cvar_Set("cg_thirdPerson", "0");
03166             trap_Cvar_Set("cg_cameraOrbit", "0");
03167             trap_Cvar_Set("ui_singlePlayerActive", "0");
03168             trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) );
03169             trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) );
03170             trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName"));
03171             trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName"));
03172             trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) );
03173             skill = trap_Cvar_VariableValue( "g_spSkill" );
03174             // set max clients based on spots
03175             oldclients = trap_Cvar_VariableValue( "sv_maxClients" );
03176             clients = 0;
03177             for (i = 0; i < PLAYERS_PER_TEAM; i++) {
03178                 int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
03179                 if (bot >= 0) {
03180                     clients++;
03181                 }
03182                 bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
03183                 if (bot >= 0) {
03184                     clients++;
03185                 }
03186             }
03187             if (clients == 0) {
03188                 clients = 8;
03189             }
03190             
03191             if (oldclients > clients) {
03192                 clients = oldclients;
03193             }
03194 
03195             trap_Cvar_Set("sv_maxClients", va("%d",clients));
03196 
03197             for (i = 0; i < PLAYERS_PER_TEAM; i++) {
03198                 int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1));
03199                 if (bot > 1) {
03200                     if (ui_actualNetGameType.integer >= GT_TEAM) {
03201                         Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Blue");
03202                     } else {
03203                         Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
03204                     }
03205                     trap_Cmd_ExecuteText( EXEC_APPEND, buff );
03206                 }
03207                 bot = trap_Cvar_VariableValue( va("ui_redteam%i", i+1));
03208                 if (bot > 1) {
03209                     if (ui_actualNetGameType.integer >= GT_TEAM) {
03210                         Com_sprintf( buff, sizeof(buff), "addbot %s %f %s\n", uiInfo.characterList[bot-2].name, skill, "Red");
03211                     } else {
03212                         Com_sprintf( buff, sizeof(buff), "addbot %s %f \n", UI_GetBotNameByNumber(bot-2), skill);
03213                     }
03214                     trap_Cmd_ExecuteText( EXEC_APPEND, buff );
03215                 }
03216             }
03217         } else if (Q_stricmp(name, "updateSPMenu") == 0) {
03218             UI_SetCapFragLimits(qtrue);
03219             UI_MapCountByGameType(qtrue);
03220             ui_mapIndex.integer = UI_GetIndexFromSelection(ui_currentMap.integer);
03221             trap_Cvar_Set("ui_mapIndex", va("%d", ui_mapIndex.integer));
03222             Menu_SetFeederSelection(NULL, FEEDER_MAPS, ui_mapIndex.integer, "skirmish");
03223             UI_GameType_HandleKey(0, 0, K_MOUSE1, qfalse);
03224             UI_GameType_HandleKey(0, 0, K_MOUSE2, qfalse);
03225         } else if (Q_stricmp(name, "resetDefaults") == 0) {
03226             trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n");
03227             trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n");
03228             Controls_SetDefaults();
03229             trap_Cvar_Set("com_introPlayed", "1" );
03230             trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" );
03231         } else if (Q_stricmp(name, "getCDKey") == 0) {
03232             char out[17];
03233             trap_GetCDKey(buff, 17);
03234             trap_Cvar_Set("cdkey1", "");
03235             trap_Cvar_Set("cdkey2", "");
03236             trap_Cvar_Set("cdkey3", "");
03237             trap_Cvar_Set("cdkey4", "");
03238             if (strlen(buff) == CDKEY_LEN) {
03239                 Q_strncpyz(out, buff, 5);
03240                 trap_Cvar_Set("cdkey1", out);
03241                 Q_strncpyz(out, buff + 4, 5);
03242                 trap_Cvar_Set("cdkey2", out);
03243                 Q_strncpyz(out, buff + 8, 5);
03244                 trap_Cvar_Set("cdkey3", out);
03245                 Q_strncpyz(out, buff + 12, 5);
03246                 trap_Cvar_Set("cdkey4", out);
03247             }
03248 
03249         } else if (Q_stricmp(name, "verifyCDKey") == 0) {
03250             buff[0] = '\0';
03251             Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey1")); 
03252             Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey2")); 
03253             Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey3")); 
03254             Q_strcat(buff, 1024, UI_Cvar_VariableString("cdkey4")); 
03255             trap_Cvar_Set("cdkey", buff);
03256             if (trap_VerifyCDKey(buff, UI_Cvar_VariableString("cdkeychecksum"))) {
03257                 trap_Cvar_Set("ui_cdkeyvalid", "CD Key Appears to be valid.");
03258                 trap_SetCDKey(buff);
03259             } else {
03260                 trap_Cvar_Set("ui_cdkeyvalid", "CD Key does not appear to be valid.");
03261             }
03262         } else if (Q_stricmp(name, "loadArenas") == 0) {
03263             UI_LoadArenas();
03264             UI_MapCountByGameType(qfalse);
03265             Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, 0, "createserver");
03266         } else if (Q_stricmp(name, "saveControls") == 0) {
03267             Controls_SetConfig(qtrue);
03268         } else if (Q_stricmp(name, "loadControls") == 0) {
03269             Controls_GetConfig();
03270         } else if (Q_stricmp(name, "clearError") == 0) {
03271             trap_Cvar_Set("com_errorMessage", "");
03272         } else if (Q_stricmp(name, "loadGameInfo") == 0) {
03273 #ifdef PRE_RELEASE_TADEMO
03274             UI_ParseGameInfo("demogameinfo.txt");
03275 #else
03276             UI_ParseGameInfo("gameinfo.txt");
03277 #endif
03278             UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
03279         } else if (Q_stricmp(name, "resetScores") == 0) {
03280             UI_ClearScores();
03281         } else if (Q_stricmp(name, "RefreshServers") == 0) {
03282             UI_StartServerRefresh(qtrue);
03283             UI_BuildServerDisplayList(qtrue);
03284         } else if (Q_stricmp(name, "RefreshFilter") == 0) {
03285             UI_StartServerRefresh(qfalse);
03286             UI_BuildServerDisplayList(qtrue);
03287         } else if (Q_stricmp(name, "RunSPDemo") == 0) {
03288             if (uiInfo.demoAvailable) {
03289               trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s_%i\n", uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum));
03290             }
03291         } else if (Q_stricmp(name, "LoadDemos") == 0) {
03292             UI_LoadDemos();
03293         } else if (Q_stricmp(name, "LoadMovies") == 0) {
03294             UI_LoadMovies();
03295         } else if (Q_stricmp(name, "LoadMods") == 0) {
03296             UI_LoadMods();
03297         } else if (Q_stricmp(name, "playMovie") == 0) {
03298             if (uiInfo.previewMovie >= 0) {
03299               trap_CIN_StopCinematic(uiInfo.previewMovie);
03300             }
03301             trap_Cmd_ExecuteText( EXEC_APPEND, va("cinematic %s.roq 2\n", uiInfo.movieList[uiInfo.movieIndex]));
03302         } else if (Q_stricmp(name, "RunMod") == 0) {
03303             trap_Cvar_Set( "fs_game", uiInfo.modList[uiInfo.modIndex].modName);
03304             trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
03305         } else if (Q_stricmp(name, "RunDemo") == 0) {
03306             trap_Cmd_ExecuteText( EXEC_APPEND, va("demo %s\n", uiInfo.demoList[uiInfo.demoIndex]));
03307         } else if (Q_stricmp(name, "Quake3") == 0) {
03308             trap_Cvar_Set( "fs_game", "");
03309             trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" );
03310         } else if (Q_stricmp(name, "closeJoin") == 0) {
03311             if (uiInfo.serverStatus.refreshActive) {
03312                 UI_StopServerRefresh();
03313                 uiInfo.serverStatus.nextDisplayRefresh = 0;
03314                 uiInfo.nextServerStatusRefresh = 0;
03315                 uiInfo.nextFindPlayerRefresh = 0;
03316                 UI_BuildServerDisplayList(qtrue);
03317             } else {
03318                 Menus_CloseByName("joinserver");
03319                 Menus_OpenByName("main");
03320             }
03321         } else if (Q_stricmp(name, "StopRefresh") == 0) {
03322             UI_StopServerRefresh();
03323             uiInfo.serverStatus.nextDisplayRefresh = 0;
03324             uiInfo.nextServerStatusRefresh = 0;
03325             uiInfo.nextFindPlayerRefresh = 0;
03326         } else if (Q_stricmp(name, "UpdateFilter") == 0) {
03327             if (ui_netSource.integer == AS_LOCAL) {
03328                 UI_StartServerRefresh(qtrue);
03329             }
03330             UI_BuildServerDisplayList(qtrue);
03331             UI_FeederSelection(FEEDER_SERVERS, 0);
03332         } else if (Q_stricmp(name, "ServerStatus") == 0) {
03333             trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], uiInfo.serverStatusAddress, sizeof(uiInfo.serverStatusAddress));
03334             UI_BuildServerStatus(qtrue);
03335         } else if (Q_stricmp(name, "FoundPlayerServerStatus") == 0) {
03336             Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
03337             UI_BuildServerStatus(qtrue);
03338             Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
03339         } else if (Q_stricmp(name, "FindPlayer") == 0) {
03340             UI_BuildFindPlayerList(qtrue);
03341             // clear the displayed server status info
03342             uiInfo.serverStatusInfo.numLines = 0;
03343             Menu_SetFeederSelection(NULL, FEEDER_FINDPLAYER, 0, NULL);
03344         } else if (Q_stricmp(name, "JoinServer") == 0) {
03345             trap_Cvar_Set("cg_thirdPerson", "0");
03346             trap_Cvar_Set("cg_cameraOrbit", "0");
03347             trap_Cvar_Set("ui_singlePlayerActive", "0");
03348             if (uiInfo.serverStatus.currentServer >= 0 && uiInfo.serverStatus.currentServer < uiInfo.serverStatus.numDisplayServers) {
03349                 trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, 1024);
03350                 trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", buff ) );
03351             }
03352         } else if (Q_stricmp(name, "FoundPlayerJoinServer") == 0) {
03353             trap_Cvar_Set("ui_singlePlayerActive", "0");
03354             if (uiInfo.currentFoundPlayerServer >= 0 && uiInfo.currentFoundPlayerServer < uiInfo.numFoundPlayerServers) {
03355                 trap_Cmd_ExecuteText( EXEC_APPEND, va( "connect %s\n", uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer] ) );
03356             }
03357         } else if (Q_stricmp(name, "Quit") == 0) {
03358             trap_Cvar_Set("ui_singlePlayerActive", "0");
03359             trap_Cmd_ExecuteText( EXEC_NOW, "quit");
03360         } else if (Q_stricmp(name, "Controls") == 0) {
03361           trap_Cvar_Set( "cl_paused", "1" );
03362             trap_Key_SetCatcher( KEYCATCH_UI );
03363             Menus_CloseAll();
03364             Menus_ActivateByName("setup_menu2");
03365         } else if (Q_stricmp(name, "Leave") == 0) {
03366             trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" );
03367             trap_Key_SetCatcher( KEYCATCH_UI );
03368             Menus_CloseAll();
03369             Menus_ActivateByName("main");
03370         } else if (Q_stricmp(name, "ServerSort") == 0) {
03371             int sortColumn;
03372             if (Int_Parse(args, &sortColumn)) {
03373                 // if same column we're already sorting on then flip the direction
03374                 if (sortColumn == uiInfo.serverStatus.sortKey) {
03375                     uiInfo.serverStatus.sortDir = !uiInfo.serverStatus.sortDir;
03376                 }
03377                 // make sure we sort again
03378                 UI_ServersSort(sortColumn, qtrue);
03379             }
03380         } else if (Q_stricmp(name, "nextSkirmish") == 0) {
03381             UI_StartSkirmish(qtrue);
03382         } else if (Q_stricmp(name, "SkirmishStart") == 0) {
03383             UI_StartSkirmish(qfalse);
03384         } else if (Q_stricmp(name, "closeingame") == 0) {
03385             trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
03386             trap_Key_ClearStates();
03387             trap_Cvar_Set( "cl_paused", "0" );
03388             Menus_CloseAll();
03389         } else if (Q_stricmp(name, "voteMap") == 0) {
03390             if (ui_currentNetMap.integer >=0 && ui_currentNetMap.integer < uiInfo.mapCount) {
03391                 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote map %s\n",uiInfo.mapList[ui_currentNetMap.integer].mapLoadName) );
03392             }
03393         } else if (Q_stricmp(name, "voteKick") == 0) {
03394             if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) {
03395                 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) );
03396             }
03397         } else if (Q_stricmp(name, "voteGame") == 0) {
03398             if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) {
03399                 trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote g_gametype %i\n",uiInfo.gameTypes[ui_netGameType.integer].gtEnum) );
03400             }
03401         } else if (Q_stricmp(name, "voteLeader") == 0) {
03402             if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) {
03403                 trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) );
03404             }
03405         } else if (Q_stricmp(name, "addBot") == 0) {
03406             if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) {
03407                 trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", uiInfo.characterList[uiInfo.botIndex].name, uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
03408             } else {
03409                 trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot %s %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") );
03410             }
03411         } else if (Q_stricmp(name, "addFavorite") == 0) {
03412             if (ui_netSource.integer != AS_FAVORITES) {
03413                 char name[MAX_NAME_LENGTH];
03414                 char addr[MAX_NAME_LENGTH];
03415                 int res;
03416 
03417                 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
03418                 name[0] = addr[0] = '\0';
03419                 Q_strncpyz(name,    Info_ValueForKey(buff, "hostname"), MAX_NAME_LENGTH);
03420                 Q_strncpyz(addr,    Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
03421                 if (strlen(name) > 0 && strlen(addr) > 0) {
03422                     res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
03423                     if (res == 0) {
03424                         // server already in the list
03425                         Com_Printf("Favorite already in list\n");
03426                     }
03427                     else if (res == -1) {
03428                         // list full
03429                         Com_Printf("Favorite list full\n");
03430                     }
03431                     else {
03432                         // successfully added
03433                         Com_Printf("Added favorite server %s\n", addr);
03434                     }
03435                 }
03436             }
03437         } else if (Q_stricmp(name, "deleteFavorite") == 0) {
03438             if (ui_netSource.integer == AS_FAVORITES) {
03439                 char addr[MAX_NAME_LENGTH];
03440                 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.serverStatus.currentServer], buff, MAX_STRING_CHARS);
03441                 addr[0] = '\0';
03442                 Q_strncpyz(addr,    Info_ValueForKey(buff, "addr"), MAX_NAME_LENGTH);
03443                 if (strlen(addr) > 0) {
03444                     trap_LAN_RemoveServer(AS_FAVORITES, addr);
03445                 }
03446             }
03447         } else if (Q_stricmp(name, "createFavorite") == 0) {
03448             if (ui_netSource.integer == AS_FAVORITES) {
03449                 char name[MAX_NAME_LENGTH];
03450                 char addr[MAX_NAME_LENGTH];
03451                 int res;
03452 
03453                 name[0] = addr[0] = '\0';
03454                 Q_strncpyz(name,    UI_Cvar_VariableString("ui_favoriteName"), MAX_NAME_LENGTH);
03455                 Q_strncpyz(addr,    UI_Cvar_VariableString("ui_favoriteAddress"), MAX_NAME_LENGTH);
03456                 if (strlen(name) > 0 && strlen(addr) > 0) {
03457                     res = trap_LAN_AddServer(AS_FAVORITES, name, addr);
03458                     if (res == 0) {
03459                         // server already in the list
03460                         Com_Printf("Favorite already in list\n");
03461                     }
03462                     else if (res == -1) {
03463                         // list full
03464                         Com_Printf("Favorite list full\n");
03465                     }
03466                     else {
03467                         // successfully added
03468                         Com_Printf("Added favorite server %s\n", addr);
03469                     }
03470                 }
03471             }
03472         } else if (Q_stricmp(name, "orders") == 0) {
03473             const char *orders;
03474             if (String_Parse(args, &orders)) {
03475                 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
03476                 if (selectedPlayer < uiInfo.myTeamCount) {
03477                     strcpy(buff, orders);
03478                     trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
03479                     trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
03480                 } else {
03481                     int i;
03482                     for (i = 0; i < uiInfo.myTeamCount; i++) {
03483                         if (Q_stricmp(UI_Cvar_VariableString("name"), uiInfo.teamNames[i]) == 0) {
03484                             continue;
03485                         }
03486                         strcpy(buff, orders);
03487                         trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamNames[i]) );
03488                         trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
03489                     }
03490                 }
03491                 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
03492                 trap_Key_ClearStates();
03493                 trap_Cvar_Set( "cl_paused", "0" );
03494                 Menus_CloseAll();
03495             }
03496         } else if (Q_stricmp(name, "voiceOrdersTeam") == 0) {
03497             const char *orders;
03498             if (String_Parse(args, &orders)) {
03499                 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
03500                 if (selectedPlayer == uiInfo.myTeamCount) {
03501                     trap_Cmd_ExecuteText( EXEC_APPEND, orders );
03502                     trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
03503                 }
03504                 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
03505                 trap_Key_ClearStates();
03506                 trap_Cvar_Set( "cl_paused", "0" );
03507                 Menus_CloseAll();
03508             }
03509         } else if (Q_stricmp(name, "voiceOrders") == 0) {
03510             const char *orders;
03511             if (String_Parse(args, &orders)) {
03512                 int selectedPlayer = trap_Cvar_VariableValue("cg_selectedPlayer");
03513                 if (selectedPlayer < uiInfo.myTeamCount) {
03514                     strcpy(buff, orders);
03515                     trap_Cmd_ExecuteText( EXEC_APPEND, va(buff, uiInfo.teamClientNums[selectedPlayer]) );
03516                     trap_Cmd_ExecuteText( EXEC_APPEND, "\n" );
03517                 }
03518                 trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
03519                 trap_Key_ClearStates();
03520                 trap_Cvar_Set( "cl_paused", "0" );
03521                 Menus_CloseAll();
03522             }
03523         } else if (Q_stricmp(name, "glCustom") == 0) {
03524             trap_Cvar_Set("ui_glCustom", "4");
03525         } else if (Q_stricmp(name, "update") == 0) {
03526             if (String_Parse(args, &name2)) {
03527                 UI_Update(name2);
03528             }
03529         } else if (Q_stricmp(name, "setPbClStatus") == 0) {
03530             int stat;
03531             if ( Int_Parse( args, &stat ) )
03532                 trap_SetPbClStatus( stat );
03533         }
03534         else {
03535             Com_Printf("unknown UI script %s\n", name);
03536         }
03537     }
03538 }
03539 
03540 static void UI_GetTeamColor(vec4_t *color) {
03541 }
03542 
03543 /*
03544 ==================
03545 UI_MapCountByGameType
03546 ==================
03547 */
03548 static int UI_MapCountByGameType(qboolean singlePlayer) {
03549     int i, c, game;
03550     c = 0;
03551     game = singlePlayer ? uiInfo.gameTypes[ui_gameType.integer].gtEnum : uiInfo.gameTypes[ui_netGameType.integer].gtEnum;
03552     if (game == GT_SINGLE_PLAYER) {
03553         game++;
03554     } 
03555     if (game == GT_TEAM) {
03556         game = GT_FFA;
03557     }
03558 
03559     for (i = 0; i < uiInfo.mapCount; i++) {
03560         uiInfo.mapList[i].active = qfalse;
03561         if ( uiInfo.mapList[i].typeBits & (1 << game)) {
03562             if (singlePlayer) {
03563                 if (!(uiInfo.mapList[i].typeBits & (1 << GT_SINGLE_PLAYER))) {
03564                     continue;
03565                 }
03566             }
03567             c++;
03568             uiInfo.mapList[i].active = qtrue;
03569         }
03570     }
03571     return c;
03572 }
03573 
03574 qboolean UI_hasSkinForBase(const char *base, const char *team) {
03575     char    test[1024];
03576     
03577     Com_sprintf( test, sizeof( test ), "models/players/%s/%s/lower_default.skin", base, team );
03578 
03579     if (trap_FS_FOpenFile(test, 0, FS_READ)) {
03580         return qtrue;
03581     }
03582     Com_sprintf( test, sizeof( test ), "models/players/characters/%s/%s/lower_default.skin", base, team );
03583 
03584     if (trap_FS_FOpenFile(test, 0, FS_READ)) {
03585         return qtrue;
03586     }
03587     return qfalse;
03588 }
03589 
03590 /*
03591 ==================
03592 UI_MapCountByTeam
03593 ==================
03594 */
03595 static int UI_HeadCountByTeam() {
03596     static int init = 0;
03597     int i, j, k, c, tIndex;
03598     
03599     c = 0;
03600     if (!init) {
03601         for (i = 0; i < uiInfo.characterCount; i++) {
03602             uiInfo.characterList[i].reference = 0;
03603             for (j = 0; j < uiInfo.teamCount; j++) {
03604               if (UI_hasSkinForBase(uiInfo.characterList[i].base, uiInfo.teamList[j].teamName)) {
03605                     uiInfo.characterList[i].reference |= (1<<j);
03606               }
03607             }
03608         }
03609         init = 1;
03610     }
03611 
03612     tIndex = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
03613 
03614     // do names
03615     for (i = 0; i < uiInfo.characterCount; i++) {
03616         uiInfo.characterList[i].active = qfalse;
03617         for(j = 0; j < TEAM_MEMBERS; j++) {
03618             if (uiInfo.teamList[tIndex].teamMembers[j] != NULL) {
03619                 if (uiInfo.characterList[i].reference&(1<<tIndex)) {// && Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.characterList[i].name)==0) {
03620                     uiInfo.characterList[i].active = qtrue;
03621                     c++;
03622                     break;
03623                 }
03624             }
03625         }
03626     }
03627 
03628     // and then aliases
03629     for(j = 0; j < TEAM_MEMBERS; j++) {
03630         for(k = 0; k < uiInfo.aliasCount; k++) {
03631             if (uiInfo.aliasList[k].name != NULL) {
03632                 if (Q_stricmp(uiInfo.teamList[tIndex].teamMembers[j], uiInfo.aliasList[k].name)==0) {
03633                     for (i = 0; i < uiInfo.characterCount; i++) {
03634                         if (uiInfo.characterList[i].headImage != -1 && uiInfo.characterList[i].reference&(1<<tIndex) && Q_stricmp(uiInfo.aliasList[k].ai, uiInfo.characterList[i].name)==0) {
03635                             if (uiInfo.characterList[i].active == qfalse) {
03636                                 uiInfo.characterList[i].active = qtrue;
03637                                 c++;
03638                             }
03639                             break;
03640                         }
03641                     }
03642                 }
03643             }
03644         }
03645     }
03646     return c;
03647 }
03648 
03649 /*
03650 ==================
03651 UI_InsertServerIntoDisplayList
03652 ==================
03653 */
03654 static void UI_InsertServerIntoDisplayList(int num, int position) {
03655     int i;
03656 
03657     if (position < 0 || position > uiInfo.serverStatus.numDisplayServers ) {
03658         return;
03659     }
03660     //
03661     uiInfo.serverStatus.numDisplayServers++;
03662     for (i = uiInfo.serverStatus.numDisplayServers; i > position; i--) {
03663         uiInfo.serverStatus.displayServers[i] = uiInfo.serverStatus.displayServers[i-1];
03664     }
03665     uiInfo.serverStatus.displayServers[position] = num;
03666 }
03667 
03668 /*
03669 ==================
03670 UI_RemoveServerFromDisplayList
03671 ==================
03672 */
03673 static void UI_RemoveServerFromDisplayList(int num) {
03674     int i, j;
03675 
03676     for (i = 0; i < uiInfo.serverStatus.numDisplayServers; i++) {
03677         if (uiInfo.serverStatus.displayServers[i] == num) {
03678             uiInfo.serverStatus.numDisplayServers--;
03679             for (j = i; j < uiInfo.serverStatus.numDisplayServers; j++) {
03680                 uiInfo.serverStatus.displayServers[j] = uiInfo.serverStatus.displayServers[j+1];
03681             }
03682             return;
03683         }
03684     }
03685 }
03686 
03687 /*
03688 ==================
03689 UI_BinaryServerInsertion
03690 ==================
03691 */
03692 static void UI_BinaryServerInsertion(int num) {
03693     int mid, offset, res, len;
03694 
03695     // use binary search to insert server
03696     len = uiInfo.serverStatus.numDisplayServers;
03697     mid = len;
03698     offset = 0;
03699     res = 0;
03700     while(mid > 0) {
03701         mid = len >> 1;
03702         //
03703         res = trap_LAN_CompareServers( ui_netSource.integer, uiInfo.serverStatus.sortKey,
03704                     uiInfo.serverStatus.sortDir, num, uiInfo.serverStatus.displayServers[offset+mid]);
03705         // if equal
03706         if (res == 0) {
03707             UI_InsertServerIntoDisplayList(num, offset+mid);
03708             return;
03709         }
03710         // if larger
03711         else if (res == 1) {
03712             offset += mid;
03713             len -= mid;
03714         }
03715         // if smaller
03716         else {
03717             len -= mid;
03718         }
03719     }
03720     if (res == 1) {
03721         offset++;
03722     }
03723     UI_InsertServerIntoDisplayList(num, offset);
03724 }
03725 
03726 /*
03727 ==================
03728 UI_BuildServerDisplayList
03729 ==================
03730 */
03731 static void UI_BuildServerDisplayList(qboolean force) {
03732     int i, count, clients, maxClients, ping, game, len, visible;
03733     char info[MAX_STRING_CHARS];
03734 //  qboolean startRefresh = qtrue; TTimo: unused
03735     static int numinvisible;
03736 
03737     if (!(force || uiInfo.uiDC.realTime > uiInfo.serverStatus.nextDisplayRefresh)) {
03738         return;
03739     }
03740     // if we shouldn't reset
03741     if ( force == 2 ) {
03742         force = 0;
03743     }
03744 
03745     // do motd updates here too
03746     trap_Cvar_VariableStringBuffer( "cl_motdString", uiInfo.serverStatus.motd, sizeof(uiInfo.serverStatus.motd) );
03747     len = strlen(uiInfo.serverStatus.motd);
03748     if (len == 0) {
03749         strcpy(uiInfo.serverStatus.motd, "Welcome to Team Arena!");
03750         len = strlen(uiInfo.serverStatus.motd);
03751     } 
03752     if (len != uiInfo.serverStatus.motdLen) {
03753         uiInfo.serverStatus.motdLen = len;
03754         uiInfo.serverStatus.motdWidth = -1;
03755     } 
03756 
03757     if (force) {
03758         numinvisible = 0;
03759         // clear number of displayed servers
03760         uiInfo.serverStatus.numDisplayServers = 0;
03761         uiInfo.serverStatus.numPlayersOnServers = 0;
03762         // set list box index to zero
03763         Menu_SetFeederSelection(NULL, FEEDER_SERVERS, 0, NULL);
03764         // mark all servers as visible so we store ping updates for them
03765         trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
03766     }
03767 
03768     // get the server count (comes from the master)
03769     count = trap_LAN_GetServerCount(ui_netSource.integer);
03770     if (count == -1 || (ui_netSource.integer == AS_LOCAL && count == 0) ) {
03771         // still waiting on a response from the master
03772         uiInfo.serverStatus.numDisplayServers = 0;
03773         uiInfo.serverStatus.numPlayersOnServers = 0;
03774         uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 500;
03775         return;
03776     }
03777 
03778     visible = qfalse;
03779     for (i = 0; i < count; i++) {
03780         // if we already got info for this server
03781         if (!trap_LAN_ServerIsVisible(ui_netSource.integer, i)) {
03782             continue;
03783         }
03784         visible = qtrue;
03785         // get the ping for this server
03786         ping = trap_LAN_GetServerPing(ui_netSource.integer, i);
03787         if (ping > 0 || ui_netSource.integer == AS_FAVORITES) {
03788 
03789             trap_LAN_GetServerInfo(ui_netSource.integer, i, info, MAX_STRING_CHARS);
03790 
03791             clients = atoi(Info_ValueForKey(info, "clients"));
03792             uiInfo.serverStatus.numPlayersOnServers += clients;
03793 
03794             if (ui_browserShowEmpty.integer == 0) {
03795                 if (clients == 0) {
03796                     trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
03797                     continue;
03798                 }
03799             }
03800 
03801             if (ui_browserShowFull.integer == 0) {
03802                 maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
03803                 if (clients == maxClients) {
03804                     trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
03805                     continue;
03806                 }
03807             }
03808 
03809             if (uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum != -1) {
03810                 game = atoi(Info_ValueForKey(info, "gametype"));
03811                 if (game != uiInfo.joinGameTypes[ui_joinGameType.integer].gtEnum) {
03812                     trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
03813                     continue;
03814                 }
03815             }
03816                 
03817             if (ui_serverFilterType.integer > 0) {
03818                 if (Q_stricmp(Info_ValueForKey(info, "game"), serverFilters[ui_serverFilterType.integer].basedir) != 0) {
03819                     trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
03820                     continue;
03821                 }
03822             }
03823             // make sure we never add a favorite server twice
03824             if (ui_netSource.integer == AS_FAVORITES) {
03825                 UI_RemoveServerFromDisplayList(i);
03826             }
03827             // insert the server into the list
03828             UI_BinaryServerInsertion(i);
03829             // done with this server
03830             if (ping > 0) {
03831                 trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse);
03832                 numinvisible++;
03833             }
03834         }
03835     }
03836 
03837     uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime;
03838 
03839     // if there were no servers visible for ping updates
03840     if (!visible) {
03841 //      UI_StopServerRefresh();
03842 //      uiInfo.serverStatus.nextDisplayRefresh = 0;
03843     }
03844 }
03845 
03846 typedef struct
03847 {
03848     char *name, *altName;
03849 } serverStatusCvar_t;
03850 
03851 serverStatusCvar_t serverStatusCvars[] = {
03852     {"sv_hostname", "Name"},
03853     {"Address", ""},
03854     {"gamename", "Game name"},
03855     {"g_gametype", "Game type"},
03856     {"mapname", "Map"},
03857     {"version", ""},
03858     {"protocol", ""},
03859     {"timelimit", ""},
03860     {"fraglimit", ""},
03861     {NULL, NULL}
03862 };
03863 
03864 /*
03865 ==================
03866 UI_SortServerStatusInfo
03867 ==================
03868 */
03869 static void UI_SortServerStatusInfo( serverStatusInfo_t *info ) {
03870     int i, j, index;
03871     char *tmp1, *tmp2;
03872 
03873     // FIXME: if "gamename" == "baseq3" or "missionpack" then
03874     // replace the gametype number by FFA, CTF etc.
03875     //
03876     index = 0;
03877     for (i = 0; serverStatusCvars[i].name; i++) {
03878         for (j = 0; j < info->numLines; j++) {
03879             if ( !info->lines[j][1] || info->lines[j][1][0] ) {
03880                 continue;
03881             }
03882             if ( !Q_stricmp(serverStatusCvars[i].name, info->lines[j][0]) ) {
03883                 // swap lines
03884                 tmp1 = info->lines[index][0];
03885                 tmp2 = info->lines[index][3];
03886                 info->lines[index][0] = info->lines[j][0];
03887                 info->lines[index][3] = info->lines[j][3];
03888                 info->lines[j][0] = tmp1;
03889                 info->lines[j][3] = tmp2;
03890                 //
03891                 if ( strlen(serverStatusCvars[i].altName) ) {
03892                     info->lines[index][0] = serverStatusCvars[i].altName;
03893                 }
03894                 index++;
03895             }
03896         }
03897     }
03898 }
03899 
03900 /*
03901 ==================
03902 UI_GetServerStatusInfo
03903 ==================
03904 */
03905 static int UI_GetServerStatusInfo( const char *serverAddress, serverStatusInfo_t *info ) {
03906     char *p, *score, *ping, *name;
03907     int i, len;
03908 
03909     if (!info) {
03910         trap_LAN_ServerStatus( serverAddress, NULL, 0);
03911         return qfalse;
03912     }
03913     memset(info, 0, sizeof(*info));
03914     if ( trap_LAN_ServerStatus( serverAddress, info->text, sizeof(info->text)) ) {
03915         Q_strncpyz(info->address, serverAddress, sizeof(info->address));
03916         p = info->text;
03917         info->numLines = 0;
03918         info->lines[info->numLines][0] = "Address";
03919         info->lines[info->numLines][1] = "";
03920         info->lines[info->numLines][2] = "";
03921         info->lines[info->numLines][3] = info->address;
03922         info->numLines++;
03923         // get the cvars
03924         while (p && *p) {
03925             p = strchr(p, '\\');
03926             if (!p) break;
03927             *p++ = '\0';
03928             if (*p == '\\')
03929                 break;
03930             info->lines[info->numLines][0] = p;
03931             info->lines[info->numLines][1] = "";
03932             info->lines[info->numLines][2] = "";
03933             p = strchr(p, '\\');
03934             if (!p) break;
03935             *p++ = '\0';
03936             info->lines[info->numLines][3] = p;
03937 
03938             info->numLines++;
03939             if (info->numLines >= MAX_SERVERSTATUS_LINES)
03940                 break;
03941         }
03942         // get the player list
03943         if (info->numLines < MAX_SERVERSTATUS_LINES-3) {
03944             // empty line
03945             info->lines[info->numLines][0] = "";
03946             info->lines[info->numLines][1] = "";
03947             info->lines[info->numLines][2] = "";
03948             info->lines[info->numLines][3] = "";
03949             info->numLines++;
03950             // header
03951             info->lines[info->numLines][0] = "num";
03952             info->lines[info->numLines][1] = "score";
03953             info->lines[info->numLines][2] = "ping";
03954             info->lines[info->numLines][3] = "name";
03955             info->numLines++;
03956             // parse players
03957             i = 0;
03958             len = 0;
03959             while (p && *p) {
03960                 if (*p == '\\')
03961                     *p++ = '\0';
03962                 if (!p)
03963                     break;
03964                 score = p;
03965                 p = strchr(p, ' ');
03966                 if (!p)
03967                     break;
03968                 *p++ = '\0';
03969                 ping = p;
03970                 p = strchr(p, ' ');
03971                 if (!p)
03972                     break;
03973                 *p++ = '\0';
03974                 name = p;
03975                 Com_sprintf(&info->pings[len], sizeof(info->pings)-len, "%d", i);
03976                 info->lines[info->numLines][0] = &info->pings[len];
03977                 len += strlen(&info->pings[len]) + 1;
03978                 info->lines[info->numLines][1] = score;
03979                 info->lines[info->numLines][2] = ping;
03980                 info->lines[info->numLines][3] = name;
03981                 info->numLines++;
03982                 if (info->numLines >= MAX_SERVERSTATUS_LINES)
03983                     break;
03984                 p = strchr(p, '\\');
03985                 if (!p)
03986                     break;
03987                 *p++ = '\0';
03988                 //
03989                 i++;
03990             }
03991         }
03992         UI_SortServerStatusInfo( info );
03993         return qtrue;
03994     }
03995     return qfalse;
03996 }
03997 
03998 /*
03999 ==================
04000 stristr
04001 ==================
04002 */
04003 static char *stristr(char *str, char *charset) {
04004     int i;
04005 
04006     while(*str) {
04007         for (i = 0; charset[i] && str[i]; i++) {
04008             if (toupper(charset[i]) != toupper(str[i])) break;
04009         }
04010         if (!charset[i]) return str;
04011         str++;
04012     }
04013     return NULL;
04014 }
04015 
04016 /*
04017 ==================
04018 UI_BuildFindPlayerList
04019 ==================
04020 */
04021 static void UI_BuildFindPlayerList(qboolean force) {
04022     static int numFound, numTimeOuts;
04023     int i, j, resend;
04024     serverStatusInfo_t info;
04025     char name[MAX_NAME_LENGTH+2];
04026     char infoString[MAX_STRING_CHARS];
04027 
04028     if (!force) {
04029         if (!uiInfo.nextFindPlayerRefresh || uiInfo.nextFindPlayerRefresh > uiInfo.uiDC.realTime) {
04030             return;
04031         }
04032     }
04033     else {
04034         memset(&uiInfo.pendingServerStatus, 0, sizeof(uiInfo.pendingServerStatus));
04035         uiInfo.numFoundPlayerServers = 0;
04036         uiInfo.currentFoundPlayerServer = 0;
04037         trap_Cvar_VariableStringBuffer( "ui_findPlayer", uiInfo.findPlayerName, sizeof(uiInfo.findPlayerName));
04038         Q_CleanStr(uiInfo.findPlayerName);
04039         // should have a string of some length
04040         if (!strlen(uiInfo.findPlayerName)) {
04041             uiInfo.nextFindPlayerRefresh = 0;
04042             return;
04043         }
04044         // set resend time
04045         resend = ui_serverStatusTimeOut.integer / 2 - 10;
04046         if (resend < 50) {
04047             resend = 50;
04048         }
04049         trap_Cvar_Set("cl_serverStatusResendTime", va("%d", resend));
04050         // reset all server status requests
04051         trap_LAN_ServerStatus( NULL, NULL, 0);
04052         //
04053         uiInfo.numFoundPlayerServers = 1;
04054         Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
04055                         sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
04056                             "searching %d...", uiInfo.pendingServerStatus.num);
04057         numFound = 0;
04058         numTimeOuts++;
04059     }
04060     for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
04061         // if this pending server is valid
04062         if (uiInfo.pendingServerStatus.server[i].valid) {
04063             // try to get the server status for this server
04064             if (UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, &info ) ) {
04065                 //
04066                 numFound++;
04067                 // parse through the server status lines
04068                 for (j = 0; j < info.numLines; j++) {
04069                     // should have ping info
04070                     if ( !info.lines[j][2] || !info.lines[j][2][0] ) {
04071                         continue;
04072                     }
04073                     // clean string first
04074                     Q_strncpyz(name, info.lines[j][3], sizeof(name));
04075                     Q_CleanStr(name);
04076                     // if the player name is a substring
04077                     if (stristr(name, uiInfo.findPlayerName)) {
04078                         // add to found server list if we have space (always leave space for a line with the number found)
04079                         if (uiInfo.numFoundPlayerServers < MAX_FOUNDPLAYER_SERVERS-1) {
04080                             //
04081                             Q_strncpyz(uiInfo.foundPlayerServerAddresses[uiInfo.numFoundPlayerServers-1],
04082                                         uiInfo.pendingServerStatus.server[i].adrstr,
04083                                             sizeof(uiInfo.foundPlayerServerAddresses[0]));
04084                             Q_strncpyz(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
04085                                         uiInfo.pendingServerStatus.server[i].name,
04086                                             sizeof(uiInfo.foundPlayerServerNames[0]));
04087                             uiInfo.numFoundPlayerServers++;
04088                         }
04089                         else {
04090                             // can't add any more so we're done
04091                             uiInfo.pendingServerStatus.num = uiInfo.serverStatus.numDisplayServers;
04092                         }
04093                     }
04094                 }
04095                 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
04096                                 sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
04097                                     "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
04098                 // retrieved the server status so reuse this spot
04099                 uiInfo.pendingServerStatus.server[i].valid = qfalse;
04100             }
04101         }
04102         // if empty pending slot or timed out
04103         if (!uiInfo.pendingServerStatus.server[i].valid ||
04104             uiInfo.pendingServerStatus.server[i].startTime < uiInfo.uiDC.realTime - ui_serverStatusTimeOut.integer) {
04105             if (uiInfo.pendingServerStatus.server[i].valid) {
04106                 numTimeOuts++;
04107             }
04108             // reset server status request for this address
04109             UI_GetServerStatusInfo( uiInfo.pendingServerStatus.server[i].adrstr, NULL );
04110             // reuse pending slot
04111             uiInfo.pendingServerStatus.server[i].valid = qfalse;
04112             // if we didn't try to get the status of all servers in the main browser yet
04113             if (uiInfo.pendingServerStatus.num < uiInfo.serverStatus.numDisplayServers) {
04114                 uiInfo.pendingServerStatus.server[i].startTime = uiInfo.uiDC.realTime;
04115                 trap_LAN_GetServerAddressString(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num],
04116                             uiInfo.pendingServerStatus.server[i].adrstr, sizeof(uiInfo.pendingServerStatus.server[i].adrstr));
04117                 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[uiInfo.pendingServerStatus.num], infoString, sizeof(infoString));
04118                 Q_strncpyz(uiInfo.pendingServerStatus.server[i].name, Info_ValueForKey(infoString, "hostname"), sizeof(uiInfo.pendingServerStatus.server[0].name));
04119                 uiInfo.pendingServerStatus.server[i].valid = qtrue;
04120                 uiInfo.pendingServerStatus.num++;
04121                 Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1],
04122                                 sizeof(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1]),
04123                                     "searching %d/%d...", uiInfo.pendingServerStatus.num, numFound);
04124             }
04125         }
04126     }
04127     for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
04128         if (uiInfo.pendingServerStatus.server[i].valid) {
04129             break;
04130         }
04131     }
04132     // if still trying to retrieve server status info
04133     if (i < MAX_SERVERSTATUSREQUESTS) {
04134         uiInfo.nextFindPlayerRefresh = uiInfo.uiDC.realTime + 25;
04135     }
04136     else {
04137         // add a line that shows the number of servers found
04138         if (!uiInfo.numFoundPlayerServers) {
04139             Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]), "no servers found");
04140         }
04141         else {
04142             Com_sprintf(uiInfo.foundPlayerServerNames[uiInfo.numFoundPlayerServers-1], sizeof(uiInfo.foundPlayerServerAddresses[0]),
04143                         "%d server%s found with player %s", uiInfo.numFoundPlayerServers-1,
04144                         uiInfo.numFoundPlayerServers == 2 ? "":"s", uiInfo.findPlayerName);
04145         }
04146         uiInfo.nextFindPlayerRefresh = 0;
04147         // show the server status info for the selected server
04148         UI_FeederSelection(FEEDER_FINDPLAYER, uiInfo.currentFoundPlayerServer);
04149     }
04150 }
04151 
04152 /*
04153 ==================
04154 UI_BuildServerStatus
04155 ==================
04156 */
04157 static void UI_BuildServerStatus(qboolean force) {
04158 
04159     if (uiInfo.nextFindPlayerRefresh) {
04160         return;
04161     }
04162     if (!force) {
04163         if (!uiInfo.nextServerStatusRefresh || uiInfo.nextServerStatusRefresh > uiInfo.uiDC.realTime) {
04164             return;
04165         }
04166     }
04167     else {
04168         Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
04169         uiInfo.serverStatusInfo.numLines = 0;
04170         // reset all server status requests
04171         trap_LAN_ServerStatus( NULL, NULL, 0);
04172     }
04173     if (uiInfo.serverStatus.currentServer < 0 || uiInfo.serverStatus.currentServer > uiInfo.serverStatus.numDisplayServers || uiInfo.serverStatus.numDisplayServers == 0) {
04174         return;
04175     }
04176     if (UI_GetServerStatusInfo( uiInfo.serverStatusAddress, &uiInfo.serverStatusInfo ) ) {
04177         uiInfo.nextServerStatusRefresh = 0;
04178         UI_GetServerStatusInfo( uiInfo.serverStatusAddress, NULL );
04179     }
04180     else {
04181         uiInfo.nextServerStatusRefresh = uiInfo.uiDC.realTime + 500;
04182     }
04183 }
04184 
04185 /*
04186 ==================
04187 UI_FeederCount
04188 ==================
04189 */
04190 static int UI_FeederCount(float feederID) {
04191     if (feederID == FEEDER_HEADS) {
04192         return UI_HeadCountByTeam();
04193     } else if (feederID == FEEDER_Q3HEADS) {
04194         return uiInfo.q3HeadCount;
04195     } else if (feederID == FEEDER_CINEMATICS) {
04196         return uiInfo.movieCount;
04197     } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
04198         return UI_MapCountByGameType(feederID == FEEDER_MAPS ? qtrue : qfalse);
04199     } else if (feederID == FEEDER_SERVERS) {
04200         return uiInfo.serverStatus.numDisplayServers;
04201     } else if (feederID == FEEDER_SERVERSTATUS) {
04202         return uiInfo.serverStatusInfo.numLines;
04203     } else if (feederID == FEEDER_FINDPLAYER) {
04204         return uiInfo.numFoundPlayerServers;
04205     } else if (feederID == FEEDER_PLAYER_LIST) {
04206         if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
04207             uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
04208             UI_BuildPlayerList();
04209         }
04210         return uiInfo.playerCount;
04211     } else if (feederID == FEEDER_TEAM_LIST) {
04212         if (uiInfo.uiDC.realTime > uiInfo.playerRefresh) {
04213             uiInfo.playerRefresh = uiInfo.uiDC.realTime + 3000;
04214             UI_BuildPlayerList();
04215         }
04216         return uiInfo.myTeamCount;
04217     } else if (feederID == FEEDER_MODS) {
04218         return uiInfo.modCount;
04219     } else if (feederID == FEEDER_DEMOS) {
04220         return uiInfo.demoCount;
04221     }
04222     return 0;
04223 }
04224 
04225 static const char *UI_SelectedMap(int index, int *actual) {
04226     int i, c;
04227     c = 0;
04228     *actual = 0;
04229     for (i = 0; i < uiInfo.mapCount; i++) {
04230         if (uiInfo.mapList[i].active) {
04231             if (c == index) {
04232                 *actual = i;
04233                 return uiInfo.mapList[i].mapName;
04234             } else {
04235                 c++;
04236             }
04237         }
04238     }
04239     return "";
04240 }
04241 
04242 static const char *UI_SelectedHead(int index, int *actual) {
04243     int i, c;
04244     c = 0;
04245     *actual = 0;
04246     for (i = 0; i < uiInfo.characterCount; i++) {
04247         if (uiInfo.characterList[i].active) {
04248             if (c == index) {
04249                 *actual = i;
04250                 return uiInfo.characterList[i].name;
04251             } else {
04252                 c++;
04253             }
04254         }
04255     }
04256     return "";
04257 }
04258 
04259 static int UI_GetIndexFromSelection(int actual) {
04260     int i, c;
04261     c = 0;
04262     for (i = 0; i < uiInfo.mapCount; i++) {
04263         if (uiInfo.mapList[i].active) {
04264             if (i == actual) {
04265                 return c;
04266             }
04267                 c++;
04268         }
04269     }
04270   return 0;
04271 }
04272 
04273 static void UI_UpdatePendingPings() { 
04274     trap_LAN_ResetPings(ui_netSource.integer);
04275     uiInfo.serverStatus.refreshActive = qtrue;
04276     uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
04277 
04278 }
04279 
04280 static const char *UI_FeederItemText(float feederID, int index, int column, qhandle_t *handle) {
04281     static char info[MAX_STRING_CHARS];
04282     static char hostname[1024];
04283     static char clientBuff[32];
04284     static int lastColumn = -1;
04285     static int lastTime = 0;
04286     *handle = -1;
04287     if (feederID == FEEDER_HEADS) {
04288         int actual;
04289         return UI_SelectedHead(index, &actual);
04290     } else if (feederID == FEEDER_Q3HEADS) {
04291         if (index >= 0 && index < uiInfo.q3HeadCount) {
04292             return uiInfo.q3HeadNames[index];
04293         }
04294     } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
04295         int actual;
04296         return UI_SelectedMap(index, &actual);
04297     } else if (feederID == FEEDER_SERVERS) {
04298         if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) {
04299             int ping, game, punkbuster;
04300             if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) {
04301                 trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
04302                 lastColumn = column;
04303                 lastTime = uiInfo.uiDC.realTime;
04304             }
04305             ping = atoi(Info_ValueForKey(info, "ping"));
04306             if (ping == -1) {
04307                 // if we ever see a ping that is out of date, do a server refresh
04308                 // UI_UpdatePendingPings();
04309             }
04310             switch (column) {
04311                 case SORT_HOST : 
04312                     if (ping <= 0) {
04313                         return Info_ValueForKey(info, "addr");
04314                     } else {
04315                         if ( ui_netSource.integer == AS_LOCAL ) {
04316                             Com_sprintf( hostname, sizeof(hostname), "%s [%s]",
04317                                             Info_ValueForKey(info, "hostname"),
04318                                             netnames[atoi(Info_ValueForKey(info, "nettype"))] );
04319                             return hostname;
04320                         }
04321                         else {
04322                             Com_sprintf( hostname, sizeof(hostname), "%s", Info_ValueForKey(info, "hostname"));
04323                             return hostname;
04324                         }
04325                     }
04326                 case SORT_MAP : return Info_ValueForKey(info, "mapname");
04327                 case SORT_CLIENTS : 
04328                     Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients"));
04329                     return clientBuff;
04330                 case SORT_GAME : 
04331                     game = atoi(Info_ValueForKey(info, "gametype"));
04332                     if (game >= 0 && game < numTeamArenaGameTypes) {
04333                         return teamArenaGameTypes[game];
04334                     } else {
04335                         return "Unknown";
04336                     }
04337                 case SORT_PING : 
04338                     if (ping <= 0) {
04339                         return "...";
04340                     } else {
04341                         return Info_ValueForKey(info, "ping");
04342                     }
04343                 case SORT_PUNKBUSTER:
04344                     punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
04345                     if ( punkbuster ) {
04346                         return "Yes";
04347                     } else {
04348                         return "No";
04349                     }
04350             }
04351         }
04352     } else if (feederID == FEEDER_SERVERSTATUS) {
04353         if ( index >= 0 && index < uiInfo.serverStatusInfo.numLines ) {
04354             if ( column >= 0 && column < 4 ) {
04355                 return uiInfo.serverStatusInfo.lines[index][column];
04356             }
04357         }
04358     } else if (feederID == FEEDER_FINDPLAYER) {
04359         if ( index >= 0 && index < uiInfo.numFoundPlayerServers ) {
04360             //return uiInfo.foundPlayerServerAddresses[index];
04361             return uiInfo.foundPlayerServerNames[index];
04362         }
04363     } else if (feederID == FEEDER_PLAYER_LIST) {
04364         if (index >= 0 && index < uiInfo.playerCount) {
04365             return uiInfo.playerNames[index];
04366         }
04367     } else if (feederID == FEEDER_TEAM_LIST) {
04368         if (index >= 0 && index < uiInfo.myTeamCount) {
04369             return uiInfo.teamNames[index];
04370         }
04371     } else if (feederID == FEEDER_MODS) {
04372         if (index >= 0 && index < uiInfo.modCount) {
04373             if (uiInfo.modList[index].modDescr && *uiInfo.modList[index].modDescr) {
04374                 return uiInfo.modList[index].modDescr;
04375             } else {
04376                 return uiInfo.modList[index].modName;
04377             }
04378         }
04379     } else if (feederID == FEEDER_CINEMATICS) {
04380         if (index >= 0 && index < uiInfo.movieCount) {
04381             return uiInfo.movieList[index];
04382         }
04383     } else if (feederID == FEEDER_DEMOS) {
04384         if (index >= 0 && index < uiInfo.demoCount) {
04385             return uiInfo.demoList[index];
04386         }
04387     }
04388     return "";
04389 }
04390 
04391 
04392 static qhandle_t UI_FeederItemImage(float feederID, int index) {
04393   if (feederID == FEEDER_HEADS) {
04394     int actual;
04395     UI_SelectedHead(index, &actual);
04396     index = actual;
04397     if (index >= 0 && index < uiInfo.characterCount) {
04398         if (uiInfo.characterList[index].headImage == -1) {
04399             uiInfo.characterList[index].headImage = trap_R_RegisterShaderNoMip(uiInfo.characterList[index].imageName);
04400         }
04401         return uiInfo.characterList[index].headImage;
04402     }
04403   } else if (feederID == FEEDER_Q3HEADS) {
04404     if (index >= 0 && index < uiInfo.q3HeadCount) {
04405       return uiInfo.q3HeadIcons[index];
04406     }
04407     } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) {
04408         int actual;
04409         UI_SelectedMap(index, &actual);
04410         index = actual;
04411         if (index >= 0 && index < uiInfo.mapCount) {
04412             if (uiInfo.mapList[index].levelShot == -1) {
04413                 uiInfo.mapList[index].levelShot = trap_R_RegisterShaderNoMip(uiInfo.mapList[index].imageName);
04414             }
04415             return uiInfo.mapList[index].levelShot;
04416         }
04417     }
04418   return 0;
04419 }
04420 
04421 static void UI_FeederSelection(float feederID, int index) {
04422     static char info[MAX_STRING_CHARS];
04423   if (feederID == FEEDER_HEADS) {
04424     int actual;
04425     UI_SelectedHead(index, &actual);
04426     index = actual;
04427     if (index >= 0 && index < uiInfo.characterCount) {
04428         trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base));
04429         trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name)); 
04430         updateModel = qtrue;
04431     }
04432   } else if (feederID == FEEDER_Q3HEADS) {
04433     if (index >= 0 && index < uiInfo.q3HeadCount) {
04434       trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]);
04435       trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]);
04436             updateModel = qtrue;
04437         }
04438   } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) {
04439         int actual, map;
04440         map = (feederID == FEEDER_ALLMAPS) ? ui_currentNetMap.integer : ui_currentMap.integer;
04441         if (uiInfo.mapList[map].cinematic >= 0) {
04442           trap_CIN_StopCinematic(uiInfo.mapList[map].cinematic);
04443           uiInfo.mapList[map].cinematic = -1;
04444         }
04445         UI_SelectedMap(index, &actual);
04446         trap_Cvar_Set("ui_mapIndex", va("%d", index));
04447         ui_mapIndex.integer = index;
04448 
04449         if (feederID == FEEDER_MAPS) {
04450             ui_currentMap.integer = actual;
04451             trap_Cvar_Set("ui_currentMap", va("%d", actual));
04452         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) );
04453             UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
04454             trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName);
04455             updateOpponentModel = qtrue;
04456         } else {
04457             ui_currentNetMap.integer = actual;
04458             trap_Cvar_Set("ui_currentNetMap", va("%d", actual));
04459         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) );
04460         }
04461 
04462   } else if (feederID == FEEDER_SERVERS) {
04463         const char *mapName = NULL;
04464         uiInfo.serverStatus.currentServer = index;
04465         trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS);
04466         uiInfo.serverStatus.currentServerPreview = trap_R_RegisterShaderNoMip(va("levelshots/%s", Info_ValueForKey(info, "mapname")));
04467         if (uiInfo.serverStatus.currentServerCinematic >= 0) {
04468           trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
04469             uiInfo.serverStatus.currentServerCinematic = -1;
04470         }
04471         mapName = Info_ValueForKey(info, "mapname");
04472         if (mapName && *mapName) {
04473             uiInfo.serverStatus.currentServerCinematic = trap_CIN_PlayCinematic(va("%s.roq", mapName), 0, 0, 0, 0, (CIN_loop | CIN_silent) );
04474         }
04475   } else if (feederID == FEEDER_SERVERSTATUS) {
04476         //
04477   } else if (feederID == FEEDER_FINDPLAYER) {
04478       uiInfo.currentFoundPlayerServer = index;
04479       //
04480       if ( index < uiInfo.numFoundPlayerServers-1) {
04481             // build a new server status for this server
04482             Q_strncpyz(uiInfo.serverStatusAddress, uiInfo.foundPlayerServerAddresses[uiInfo.currentFoundPlayerServer], sizeof(uiInfo.serverStatusAddress));
04483             Menu_SetFeederSelection(NULL, FEEDER_SERVERSTATUS, 0, NULL);
04484             UI_BuildServerStatus(qtrue);
04485       }
04486   } else if (feederID == FEEDER_PLAYER_LIST) {
04487         uiInfo.playerIndex = index;
04488   } else if (feederID == FEEDER_TEAM_LIST) {
04489         uiInfo.teamIndex = index;
04490   } else if (feederID == FEEDER_MODS) {
04491         uiInfo.modIndex = index;
04492   } else if (feederID == FEEDER_CINEMATICS) {
04493         uiInfo.movieIndex = index;
04494         if (uiInfo.previewMovie >= 0) {
04495           trap_CIN_StopCinematic(uiInfo.previewMovie);
04496         }
04497         uiInfo.previewMovie = -1;
04498   } else if (feederID == FEEDER_DEMOS) {
04499         uiInfo.demoIndex = index;
04500     }
04501 }
04502 
04503 static qboolean Team_Parse(char **p) {
04504   char *token;
04505   const char *tempStr;
04506     int i;
04507 
04508   token = COM_ParseExt(p, qtrue);
04509 
04510   if (token[0] != '{') {
04511     return qfalse;
04512   }
04513 
04514   while ( 1 ) {
04515 
04516     token = COM_ParseExt(p, qtrue);
04517     
04518     if (Q_stricmp(token, "}") == 0) {
04519       return qtrue;
04520     }
04521 
04522     if ( !token || token[0] == 0 ) {
04523       return qfalse;
04524     }
04525 
04526     if (token[0] == '{') {
04527       // seven tokens per line, team name and icon, and 5 team member names
04528       if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) {
04529         return qfalse;
04530       }
04531     
04532 
04533             uiInfo.teamList[uiInfo.teamCount].imageName = tempStr;
04534         uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName);
04535           uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName));
04536             uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName));
04537 
04538             uiInfo.teamList[uiInfo.teamCount].cinematic = -1;
04539 
04540             for (i = 0; i < TEAM_MEMBERS; i++) {
04541                 uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL;
04542                 if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) {
04543                     return qfalse;
04544                 }
04545             }
04546 
04547       Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr);
04548       if (uiInfo.teamCount < MAX_TEAMS) {
04549         uiInfo.teamCount++;
04550       } else {
04551         Com_Printf("Too many teams, last team replaced!\n");
04552       }
04553       token = COM_ParseExt(p, qtrue);
04554       if (token[0] != '}') {
04555         return qfalse;
04556       }
04557     }
04558   }
04559 
04560   return qfalse;
04561 }
04562 
04563 static qboolean Character_Parse(char **p) {
04564   char *token;
04565   const char *tempStr;
04566 
04567   token = COM_ParseExt(p, qtrue);
04568 
04569   if (token[0] != '{') {
04570     return qfalse;
04571   }
04572 
04573 
04574   while ( 1 ) {
04575     token = COM_ParseExt(p, qtrue);
04576 
04577     if (Q_stricmp(token, "}") == 0) {
04578       return qtrue;
04579     }
04580 
04581     if ( !token || token[0] == 0 ) {
04582       return qfalse;
04583     }
04584 
04585     if (token[0] == '{') {
04586       // two tokens per line, character name and sex
04587       if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) {
04588         return qfalse;
04589       }
04590     
04591       uiInfo.characterList[uiInfo.characterCount].headImage = -1;
04592             uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name));
04593 
04594       if (tempStr && (!Q_stricmp(tempStr, "female"))) {
04595         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Janet"));
04596       } else if (tempStr && (!Q_stricmp(tempStr, "male"))) {
04597         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("James"));
04598       } else {
04599         uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr));
04600       }
04601 
04602       Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name);
04603       if (uiInfo.characterCount < MAX_HEADS) {
04604         uiInfo.characterCount++;
04605       } else {
04606         Com_Printf("Too many characters, last character replaced!\n");
04607       }
04608      
04609       token = COM_ParseExt(p, qtrue);
04610       if (token[0] != '}') {
04611         return qfalse;
04612       }
04613     }
04614   }
04615 
04616   return qfalse;
04617 }
04618 
04619 
04620 static qboolean Alias_Parse(char **p) {
04621   char *token;
04622 
04623   token = COM_ParseExt(p, qtrue);
04624 
04625   if (token[0] != '{') {
04626     return qfalse;
04627   }
04628 
04629   while ( 1 ) {
04630     token = COM_ParseExt(p, qtrue);
04631 
04632     if (Q_stricmp(token, "}") == 0) {
04633       return qtrue;
04634     }
04635 
04636     if ( !token || token[0] == 0 ) {
04637       return qfalse;
04638     }
04639 
04640     if (token[0] == '{') {
04641       // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense
04642       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)) {
04643         return qfalse;
04644       }
04645     
04646       Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai);
04647       if (uiInfo.aliasCount < MAX_ALIASES) {
04648         uiInfo.aliasCount++;
04649       } else {
04650         Com_Printf("Too many aliases, last alias replaced!\n");
04651       }
04652      
04653       token = COM_ParseExt(p, qtrue);
04654       if (token[0] != '}') {
04655         return qfalse;
04656       }
04657     }
04658   }
04659 
04660   return qfalse;
04661 }
04662 
04663 
04664 
04665 // mode 
04666 // 0 - high level parsing
04667 // 1 - team parsing
04668 // 2 - character parsing
04669 static void UI_ParseTeamInfo(const char *teamFile) {
04670     char    *token;
04671   char *p;
04672   char *buff = NULL;
04673   //static int mode = 0; TTimo: unused
04674 
04675   buff = GetMenuBuffer(teamFile);
04676   if (!buff) {
04677     return;
04678   }
04679 
04680   p = buff;
04681 
04682     while ( 1 ) {
04683         token = COM_ParseExt( &p, qtrue );
04684         if( !token || token[0] == 0 || token[0] == '}') {
04685             break;
04686         }
04687 
04688         if ( Q_stricmp( token, "}" ) == 0 ) {
04689       break;
04690     }
04691 
04692     if (Q_stricmp(token, "teams") == 0) {
04693 
04694       if (Team_Parse(&p)) {
04695         continue;
04696       } else {
04697         break;
04698       }
04699     }
04700 
04701     if (Q_stricmp(token, "characters") == 0) {
04702       Character_Parse(&p);
04703     }
04704 
04705     if (Q_stricmp(token, "aliases") == 0) {
04706       Alias_Parse(&p);
04707     }
04708 
04709   }
04710 
04711 }
04712 
04713 
04714 static qboolean GameType_Parse(char **p, qboolean join) {
04715     char *token;
04716 
04717     token = COM_ParseExt(p, qtrue);
04718 
04719     if (token[0] != '{') {
04720         return qfalse;
04721     }
04722 
04723     if (join) {
04724         uiInfo.numJoinGameTypes = 0;
04725     } else {
04726         uiInfo.numGameTypes = 0;
04727     }
04728 
04729     while ( 1 ) {
04730         token = COM_ParseExt(p, qtrue);
04731 
04732         if (Q_stricmp(token, "}") == 0) {
04733             return qtrue;
04734         }
04735 
04736         if ( !token || token[0] == 0 ) {
04737             return qfalse;
04738         }
04739 
04740         if (token[0] == '{') {
04741             // two tokens per line, character name and sex
04742             if (join) {
04743                 if (!String_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gameType) || !Int_Parse(p, &uiInfo.joinGameTypes[uiInfo.numJoinGameTypes].gtEnum)) {
04744                     return qfalse;
04745                 }
04746             } else {
04747                 if (!String_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gameType) || !Int_Parse(p, &uiInfo.gameTypes[uiInfo.numGameTypes].gtEnum)) {
04748                     return qfalse;
04749                 }
04750             }
04751     
04752             if (join) {
04753                 if (uiInfo.numJoinGameTypes < MAX_GAMETYPES) {
04754                     uiInfo.numJoinGameTypes++;
04755                 } else {
04756                     Com_Printf("Too many net game types, last one replace!\n");
04757                 }       
04758             } else {
04759                 if (uiInfo.numGameTypes < MAX_GAMETYPES) {
04760                     uiInfo.numGameTypes++;
04761                 } else {
04762                     Com_Printf("Too many game types, last one replace!\n");
04763                 }       
04764             }
04765      
04766             token = COM_ParseExt(p, qtrue);
04767             if (token[0] != '}') {
04768                 return qfalse;
04769             }
04770         }
04771     }
04772     return qfalse;
04773 }
04774 
04775 static qboolean MapList_Parse(char **p) {
04776     char *token;
04777 
04778     token = COM_ParseExt(p, qtrue);
04779 
04780     if (token[0] != '{') {
04781         return qfalse;
04782     }
04783 
04784     uiInfo.mapCount = 0;
04785 
04786     while ( 1 ) {
04787         token = COM_ParseExt(p, qtrue);
04788 
04789         if (Q_stricmp(token, "}") == 0) {
04790             return qtrue;
04791         }
04792 
04793         if ( !token || token[0] == 0 ) {
04794             return qfalse;
04795         }
04796 
04797         if (token[0] == '{') {
04798             if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapName) || !String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].mapLoadName) 
04799                 ||!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].teamMembers) ) {
04800                 return qfalse;
04801             }
04802 
04803             if (!String_Parse(p, &uiInfo.mapList[uiInfo.mapCount].opponentName)) {
04804                 return qfalse;
04805             }
04806 
04807             uiInfo.mapList[uiInfo.mapCount].typeBits = 0;
04808 
04809             while (1) {
04810                 token = COM_ParseExt(p, qtrue);
04811                 if (token[0] >= '0' && token[0] <= '9') {
04812                     uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << (token[0] - 0x030));
04813                     if (!Int_Parse(p, &uiInfo.mapList[uiInfo.mapCount].timeToBeat[token[0] - 0x30])) {
04814                         return qfalse;
04815                     }
04816                 } else {
04817                     break;
04818                 } 
04819             }
04820 
04821             //mapList[mapCount].imageName = String_Alloc(va("levelshots/%s", mapList[mapCount].mapLoadName));
04822             //if (uiInfo.mapCount == 0) {
04823               // only load the first cinematic, selection loads the others
04824             //  uiInfo.mapList[uiInfo.mapCount].cinematic = trap_CIN_PlayCinematic(va("%s.roq",uiInfo.mapList[uiInfo.mapCount].mapLoadName), qfalse, qfalse, qtrue, 0, 0, 0, 0);
04825             //}
04826         uiInfo.mapList[uiInfo.mapCount].cinematic = -1;
04827             uiInfo.mapList[uiInfo.mapCount].levelShot = trap_R_RegisterShaderNoMip(va("levelshots/%s_small", uiInfo.mapList[uiInfo.mapCount].mapLoadName));
04828 
04829             if (uiInfo.mapCount < MAX_MAPS) {
04830                 uiInfo.mapCount++;
04831             } else {
04832                 Com_Printf("Too many maps, last one replaced!\n");
04833             }
04834         }
04835     }
04836     return qfalse;
04837 }
04838 
04839 static void UI_ParseGameInfo(const char *teamFile) {
04840     char    *token;
04841     char *p;
04842     char *buff = NULL;
04843     //int mode = 0; TTimo: unused
04844 
04845     buff = GetMenuBuffer(teamFile);
04846     if (!buff) {
04847         return;
04848     }
04849 
04850     p = buff;
04851 
04852     while ( 1 ) {
04853         token = COM_ParseExt( &p, qtrue );
04854         if( !token || token[0] == 0 || token[0] == '}') {
04855             break;
04856         }
04857 
04858         if ( Q_stricmp( token, "}" ) == 0 ) {
04859             break;
04860         }
04861 
04862         if (Q_stricmp(token, "gametypes") == 0) {
04863 
04864             if (GameType_Parse(&p, qfalse)) {
04865                 continue;
04866             } else {
04867                 break;
04868             }
04869         }
04870 
04871         if (Q_stricmp(token, "joingametypes") == 0) {
04872 
04873             if (GameType_Parse(&p, qtrue)) {
04874                 continue;
04875             } else {
04876                 break;
04877             }
04878         }
04879 
04880         if (Q_stricmp(token, "maps") == 0) {
04881             // start a new menu
04882             MapList_Parse(&p);
04883         }
04884 
04885     }
04886 }
04887 
04888 static void UI_Pause(qboolean b) {
04889     if (b) {
04890         // pause the game and set the ui keycatcher
04891       trap_Cvar_Set( "cl_paused", "1" );
04892         trap_Key_SetCatcher( KEYCATCH_UI );
04893     } else {
04894         // unpause the game and clear the ui keycatcher
04895         trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
04896         trap_Key_ClearStates();
04897         trap_Cvar_Set( "cl_paused", "0" );
04898     }
04899 }
04900 
04901 #ifndef MISSIONPACK // bk001206
04902 static int UI_OwnerDraw_Width(int ownerDraw) {
04903   // bk001205 - LCC missing return value
04904   return 0;
04905 }
04906 #endif
04907 
04908 static int UI_PlayCinematic(const char *name, float x, float y, float w, float h) {
04909   return trap_CIN_PlayCinematic(name, x, y, w, h, (CIN_loop | CIN_silent));
04910 }
04911 
04912 static void UI_StopCinematic(int handle) {
04913     if (handle >= 0) {
04914       trap_CIN_StopCinematic(handle);
04915     } else {
04916         handle = abs(handle);
04917         if (handle == UI_MAPCINEMATIC) {
04918             if (uiInfo.mapList[ui_currentMap.integer].cinematic >= 0) {
04919               trap_CIN_StopCinematic(uiInfo.mapList[ui_currentMap.integer].cinematic);
04920               uiInfo.mapList[ui_currentMap.integer].cinematic = -1;
04921             }
04922         } else if (handle == UI_NETMAPCINEMATIC) {
04923             if (uiInfo.serverStatus.currentServerCinematic >= 0) {
04924               trap_CIN_StopCinematic(uiInfo.serverStatus.currentServerCinematic);
04925                 uiInfo.serverStatus.currentServerCinematic = -1;
04926             }
04927         } else if (handle == UI_CLANCINEMATIC) {
04928           int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName"));
04929           if (i >= 0 && i < uiInfo.teamCount) {
04930                 if (uiInfo.teamList[i].cinematic >= 0) {
04931                   trap_CIN_StopCinematic(uiInfo.teamList[i].cinematic);
04932                     uiInfo.teamList[i].cinematic = -1;
04933                 }
04934             }
04935         }
04936     }
04937 }
04938 
04939 static void UI_DrawCinematic(int handle, float x, float y, float w, float h) {
04940     trap_CIN_SetExtents(handle, x, y, w, h);
04941   trap_CIN_DrawCinematic(handle);
04942 }
04943 
04944 static void UI_RunCinematicFrame(int handle) {
04945   trap_CIN_RunCinematic(handle);
04946 }
04947 
04948 
04949 
04950 /*
04951 =================
04952 PlayerModel_BuildList
04953 =================
04954 */
04955 static void UI_BuildQ3Model_List( void )
04956 {
04957     int     numdirs;
04958     int     numfiles;
04959     char    dirlist[2048];
04960     char    filelist[2048];
04961     char    skinname[64];
04962     char    scratch[256];
04963     char*   dirptr;
04964     char*   fileptr;
04965     int     i;
04966     int     j, k, dirty;
04967     int     dirlen;
04968     int     filelen;
04969 
04970     uiInfo.q3HeadCount = 0;
04971 
04972     // iterate directory of all player models
04973     numdirs = trap_FS_GetFileList("models/players", "/", dirlist, 2048 );
04974     dirptr  = dirlist;
04975     for (i=0; i<numdirs && uiInfo.q3HeadCount < MAX_PLAYERMODELS; i++,dirptr+=dirlen+1)
04976     {
04977         dirlen = strlen(dirptr);
04978         
04979         if (dirlen && dirptr[dirlen-1]=='/') dirptr[dirlen-1]='\0';
04980 
04981         if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
04982             continue;
04983             
04984         // iterate all skin files in directory
04985         numfiles = trap_FS_GetFileList( va("models/players/%s",dirptr), "tga", filelist, 2048 );
04986         fileptr  = filelist;
04987         for (j=0; j<numfiles && uiInfo.q3HeadCount < MAX_PLAYERMODELS;j++,fileptr+=filelen+1)
04988         {
04989             filelen = strlen(fileptr);
04990 
04991             COM_StripExtension(fileptr,skinname);
04992 
04993             // look for icon_????
04994             if (Q_stricmpn(skinname, "icon_", 5) == 0 && !(Q_stricmp(skinname,"icon_blue") == 0 || Q_stricmp(skinname,"icon_red") == 0))
04995             {
04996                 if (Q_stricmp(skinname, "icon_default") == 0) {
04997                     Com_sprintf( scratch, sizeof(scratch), dirptr);
04998                 } else {
04999                     Com_sprintf( scratch, sizeof(scratch), "%s/%s",dirptr, skinname + 5);
05000                 }
05001                 dirty = 0;
05002                 for(k=0;k<uiInfo.q3HeadCount;k++) {
05003                     if (!Q_stricmp(scratch, uiInfo.q3HeadNames[uiInfo.q3HeadCount])) {
05004                         dirty = 1;
05005                         break;
05006                     }
05007                 }
05008                 if (!dirty) {
05009                     Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), scratch);
05010                     uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(va("models/players/%s/%s",dirptr,skinname));
05011                 }
05012             }
05013 
05014         }
05015     }   
05016 
05017 }
05018 
05019 
05020 
05021 /*
05022 =================
05023 UI_Init
05024 =================
05025 */
05026 void _UI_Init( qboolean inGameLoad ) {
05027     const char *menuSet;
05028     int start;
05029 
05030     //uiInfo.inGameLoad = inGameLoad;
05031 
05032     UI_RegisterCvars();
05033     UI_InitMemory();
05034 
05035     // cache redundant calulations
05036     trap_GetGlconfig( &uiInfo.uiDC.glconfig );
05037 
05038     // for 640x480 virtualized screen
05039     uiInfo.uiDC.yscale = uiInfo.uiDC.glconfig.vidHeight * (1.0/480.0);
05040     uiInfo.uiDC.xscale = uiInfo.uiDC.glconfig.vidWidth * (1.0/640.0);
05041     if ( uiInfo.uiDC.glconfig.vidWidth * 480 > uiInfo.uiDC.glconfig.vidHeight * 640 ) {
05042         // wide screen
05043         uiInfo.uiDC.bias = 0.5 * ( uiInfo.uiDC.glconfig.vidWidth - ( uiInfo.uiDC.glconfig.vidHeight * (640.0/480.0) ) );
05044     }
05045     else {
05046         // no wide screen
05047         uiInfo.uiDC.bias = 0;
05048     }
05049 
05050 
05051   //UI_Load();
05052     uiInfo.uiDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
05053     uiInfo.uiDC.setColor = &UI_SetColor;
05054     uiInfo.uiDC.drawHandlePic = &UI_DrawHandlePic;
05055     uiInfo.uiDC.drawStretchPic = &trap_R_DrawStretchPic;
05056     uiInfo.uiDC.drawText = &Text_Paint;
05057     uiInfo.uiDC.textWidth = &Text_Width;
05058     uiInfo.uiDC.textHeight = &Text_Height;
05059     uiInfo.uiDC.registerModel = &trap_R_RegisterModel;
05060     uiInfo.uiDC.modelBounds = &trap_R_ModelBounds;
05061     uiInfo.uiDC.fillRect = &UI_FillRect;
05062     uiInfo.uiDC.drawRect = &_UI_DrawRect;
05063     uiInfo.uiDC.drawSides = &_UI_DrawSides;
05064     uiInfo.uiDC.drawTopBottom = &_UI_DrawTopBottom;
05065     uiInfo.uiDC.clearScene = &trap_R_ClearScene;
05066     uiInfo.uiDC.drawSides = &_UI_DrawSides;
05067     uiInfo.uiDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
05068     uiInfo.uiDC.renderScene = &trap_R_RenderScene;
05069     uiInfo.uiDC.registerFont = &trap_R_RegisterFont;
05070     uiInfo.uiDC.ownerDrawItem = &UI_OwnerDraw;
05071     uiInfo.uiDC.getValue = &UI_GetValue;
05072     uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible;
05073     uiInfo.uiDC.runScript = &UI_RunMenuScript;
05074     uiInfo.uiDC.getTeamColor = &UI_GetTeamColor;
05075     uiInfo.uiDC.setCVar = trap_Cvar_Set;
05076     uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer;
05077     uiInfo.uiDC.getCVarValue = trap_Cvar_VariableValue;
05078     uiInfo.uiDC.drawTextWithCursor = &Text_PaintWithCursor;
05079     uiInfo.uiDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode;
05080     uiInfo.uiDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode;
05081     uiInfo.uiDC.startLocalSound = &trap_S_StartLocalSound;
05082     uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey;
05083     uiInfo.uiDC.feederCount = &UI_FeederCount;
05084     uiInfo.uiDC.feederItemImage = &UI_FeederItemImage;
05085     uiInfo.uiDC.feederItemText = &UI_FeederItemText;
05086     uiInfo.uiDC.feederSelection = &UI_FeederSelection;
05087     uiInfo.uiDC.setBinding = &trap_Key_SetBinding;
05088     uiInfo.uiDC.getBindingBuf = &trap_Key_GetBindingBuf;
05089     uiInfo.uiDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf;
05090     uiInfo.uiDC.executeText = &trap_Cmd_ExecuteText;
05091     uiInfo.uiDC.Error = &Com_Error; 
05092     uiInfo.uiDC.Print = &Com_Printf; 
05093     uiInfo.uiDC.Pause = &UI_Pause;
05094     uiInfo.uiDC.ownerDrawWidth = &UI_OwnerDrawWidth;
05095     uiInfo.uiDC.registerSound = &trap_S_RegisterSound;
05096     uiInfo.uiDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
05097     uiInfo.uiDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
05098     uiInfo.uiDC.playCinematic = &UI_PlayCinematic;
05099     uiInfo.uiDC.stopCinematic = &UI_StopCinematic;
05100     uiInfo.uiDC.drawCinematic = &UI_DrawCinematic;
05101     uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame;
05102 
05103     Init_Display(&uiInfo.uiDC);
05104 
05105     String_Init();
05106   
05107     uiInfo.uiDC.cursor  = trap_R_RegisterShaderNoMip( "menu/art/3_cursor2" );
05108     uiInfo.uiDC.whiteShader = trap_R_RegisterShaderNoMip( "white" );
05109 
05110     AssetCache();
05111 
05112     start = trap_Milliseconds();
05113 
05114   uiInfo.teamCount = 0;
05115   uiInfo.characterCount = 0;
05116   uiInfo.aliasCount = 0;
05117 
05118 #ifdef PRE_RELEASE_TADEMO
05119     UI_ParseTeamInfo("demoteaminfo.txt");
05120     UI_ParseGameInfo("demogameinfo.txt");
05121 #else
05122     UI_ParseTeamInfo("teaminfo.txt");
05123     UI_LoadTeams();
05124     UI_ParseGameInfo("gameinfo.txt");
05125 #endif
05126 
05127     menuSet = UI_Cvar_VariableString("ui_menuFiles");
05128     if (menuSet == NULL || menuSet[0] == '\0') {
05129         menuSet = "ui/menus.txt";
05130     }
05131 
05132 #if 0
05133     if (uiInfo.inGameLoad) {
05134         UI_LoadMenus("ui/ingame.txt", qtrue);
05135     } else { // bk010222: left this: UI_LoadMenus(menuSet, qtrue);
05136     }
05137 #else 
05138     UI_LoadMenus(menuSet, qtrue);
05139     UI_LoadMenus("ui/ingame.txt", qfalse);
05140 #endif
05141     
05142     Menus_CloseAll();
05143 
05144     trap_LAN_LoadCachedServers();
05145     UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum);
05146 
05147     UI_BuildQ3Model_List();
05148     UI_LoadBots();
05149 
05150     // sets defaults for ui temp cvars
05151     uiInfo.effectsColor = gamecodetoui[(int)trap_Cvar_VariableValue("color1")-1];
05152     uiInfo.currentCrosshair = (int)trap_Cvar_VariableValue("cg_drawCrosshair");
05153     trap_Cvar_Set("ui_mousePitch", (trap_Cvar_VariableValue("m_pitch") >= 0) ? "0" : "1");
05154 
05155     uiInfo.serverStatus.currentServerCinematic = -1;
05156     uiInfo.previewMovie = -1;
05157 
05158     if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) {
05159         trap_Cvar_Set("s_volume", "0.8");
05160         trap_Cvar_Set("s_musicvolume", "0.5");
05161         trap_Cvar_Set("ui_TeamArenaFirstRun", "1");
05162     }
05163 
05164     trap_Cvar_Register(NULL, "debug_protocol", "", 0 );
05165 
05166     trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer));
05167 }
05168 
05169 
05170 /*
05171 =================
05172 UI_KeyEvent
05173 =================
05174 */
05175 void _UI_KeyEvent( int key, qboolean down ) {
05176 
05177   if (Menu_Count() > 0) {
05178     menuDef_t *menu = Menu_GetFocused();
05179         if (menu) {
05180             if (key == K_ESCAPE && down && !Menus_AnyFullScreenVisible()) {
05181                 Menus_CloseAll();
05182             } else {
05183                 Menu_HandleKey(menu, key, down );
05184             }
05185         } else {
05186             trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
05187             trap_Key_ClearStates();
05188             trap_Cvar_Set( "cl_paused", "0" );
05189         }
05190   }
05191 
05192   //if ((s > 0) && (s != menu_null_sound)) {
05193     //  trap_S_StartLocalSound( s, CHAN_LOCAL_SOUND );
05194   //}
05195 }
05196 
05197 /*
05198 =================
05199 UI_MouseEvent
05200 =================
05201 */
05202 void _UI_MouseEvent( int dx, int dy )
05203 {
05204     // update mouse screen position
05205     uiInfo.uiDC.cursorx += dx;
05206     if (uiInfo.uiDC.cursorx < 0)
05207         uiInfo.uiDC.cursorx = 0;
05208     else if (uiInfo.uiDC.cursorx > SCREEN_WIDTH)
05209         uiInfo.uiDC.cursorx = SCREEN_WIDTH;
05210 
05211     uiInfo.uiDC.cursory += dy;
05212     if (uiInfo.uiDC.cursory < 0)
05213         uiInfo.uiDC.cursory = 0;
05214     else if (uiInfo.uiDC.cursory > SCREEN_HEIGHT)
05215         uiInfo.uiDC.cursory = SCREEN_HEIGHT;
05216 
05217   if (Menu_Count() > 0) {
05218     //menuDef_t *menu = Menu_GetFocused();
05219     //Menu_HandleMouseMove(menu, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
05220         Display_MouseMove(NULL, uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory);
05221   }
05222 
05223 }
05224 
05225 void UI_LoadNonIngame() {
05226     const char *menuSet = UI_Cvar_VariableString("ui_menuFiles");
05227     if (menuSet == NULL || menuSet[0] == '\0') {
05228         menuSet = "ui/menus.txt";
05229     }
05230     UI_LoadMenus(menuSet, qfalse);
05231     uiInfo.inGameLoad = qfalse;
05232 }
05233 
05234 void _UI_SetActiveMenu( uiMenuCommand_t menu ) {
05235     char buf[256];
05236 
05237     // this should be the ONLY way the menu system is brought up
05238     // enusure minumum menu data is cached
05239   if (Menu_Count() > 0) {
05240         vec3_t v;
05241         v[0] = v[1] = v[2] = 0;
05242       switch ( menu ) {
05243       case UIMENU_NONE:
05244             trap_Key_SetCatcher( trap_Key_GetCatcher() & ~KEYCATCH_UI );
05245             trap_Key_ClearStates();
05246             trap_Cvar_Set( "cl_paused", "0" );
05247             Menus_CloseAll();
05248 
05249           return;
05250       case UIMENU_MAIN:
05251             //trap_Cvar_Set( "sv_killserver", "1" );
05252             trap_Key_SetCatcher( KEYCATCH_UI );
05253             //trap_S_StartLocalSound( trap_S_RegisterSound("sound/misc/menu_background.wav", qfalse) , CHAN_LOCAL_SOUND );
05254             //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL);
05255             if (uiInfo.inGameLoad) {
05256                 UI_LoadNonIngame();
05257             }
05258             Menus_CloseAll();
05259             Menus_ActivateByName("main");
05260             trap_Cvar_VariableStringBuffer("com_errorMessage", buf, sizeof(buf));
05261             if (strlen(buf)) {
05262                 if (!ui_singlePlayerActive.integer) {
05263                     Menus_ActivateByName("error_popmenu");
05264                 } else {
05265                     trap_Cvar_Set("com_errorMessage", "");
05266                 }
05267             }
05268           return;
05269       case UIMENU_TEAM:
05270             trap_Key_SetCatcher( KEYCATCH_UI );
05271       Menus_ActivateByName("team");
05272           return;
05273       case UIMENU_NEED_CD:
05274             // no cd check in TA
05275             //trap_Key_SetCatcher( KEYCATCH_UI );
05276       //Menus_ActivateByName("needcd");
05277           //UI_ConfirmMenu( "Insert the CD", NULL, NeedCDAction );
05278           return;
05279       case UIMENU_BAD_CD_KEY:
05280             // no cd check in TA
05281             //trap_Key_SetCatcher( KEYCATCH_UI );
05282       //Menus_ActivateByName("badcd");
05283           //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
05284           return;
05285       case UIMENU_POSTGAME:
05286             //trap_Cvar_Set( "sv_killserver", "1" );
05287             trap_Key_SetCatcher( KEYCATCH_UI );
05288             if (uiInfo.inGameLoad) {
05289                 UI_LoadNonIngame();
05290             }
05291             Menus_CloseAll();
05292             Menus_ActivateByName("endofgame");
05293           //UI_ConfirmMenu( "Bad CD Key", NULL, NeedCDKeyAction );
05294           return;
05295       case UIMENU_INGAME:
05296           trap_Cvar_Set( "cl_paused", "1" );
05297             trap_Key_SetCatcher( KEYCATCH_UI );
05298             UI_BuildPlayerList();
05299             Menus_CloseAll();
05300             Menus_ActivateByName("ingame");
05301           return;
05302       }
05303   }
05304 }
05305 
05306 qboolean _UI_IsFullscreen( void ) {
05307     return Menus_AnyFullScreenVisible();
05308 }
05309 
05310 
05311 
05312 static connstate_t  lastConnState;
05313 static char         lastLoadingText[MAX_INFO_VALUE];
05314 
05315 static void UI_ReadableSize ( char *buf, int bufsize, int value )
05316 {
05317     if (value > 1024*1024*1024 ) { // gigs
05318         Com_sprintf( buf, bufsize, "%d", value / (1024*1024*1024) );
05319         Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d GB", 
05320             (value % (1024*1024*1024))*100 / (1024*1024*1024) );
05321     } else if (value > 1024*1024 ) { // megs
05322         Com_sprintf( buf, bufsize, "%d", value / (1024*1024) );
05323         Com_sprintf( buf+strlen(buf), bufsize-strlen(buf), ".%02d MB", 
05324             (value % (1024*1024))*100 / (1024*1024) );
05325     } else if (value > 1024 ) { // kilos
05326         Com_sprintf( buf, bufsize, "%d KB", value / 1024 );
05327     } else { // bytes
05328         Com_sprintf( buf, bufsize, "%d bytes", value );
05329     }
05330 }
05331 
05332 // Assumes time is in msec
05333 static void UI_PrintTime ( char *buf, int bufsize, int time ) {
05334     time /= 1000;  // change to seconds
05335 
05336     if (time > 3600) { // in the hours range
05337         Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 );
05338     } else if (time > 60) { // mins
05339         Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 );
05340     } else  { // secs
05341         Com_sprintf( buf, bufsize, "%d sec", time );
05342     }
05343 }
05344 
05345 void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust) {
05346     int len = Text_Width(text, scale, 0);
05347     Text_Paint(x - len / 2, y, scale, color, text, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE);
05348 }
05349 
05350 void Text_PaintCenter_AutoWrapped(float x, float y, float xmax, float ystep, float scale, vec4_t color, const char *str, float adjust) {
05351     int width;
05352     char *s1,*s2,*s3;
05353     char c_bcp;
05354     char buf[1024];
05355 
05356     if (!str || str[0]=='\0')
05357         return;
05358 
05359     Q_strncpyz(buf, str, sizeof(buf));
05360     s1 = s2 = s3 = buf;
05361 
05362     while (1) {
05363         do {
05364             s3++;
05365         } while (*s3!=' ' && *s3!='\0');
05366         c_bcp = *s3;
05367         *s3 = '\0';
05368         width = Text_Width(s1, scale, 0);
05369         *s3 = c_bcp;
05370         if (width > xmax) {
05371             if (s1==s2)
05372             {
05373                 // fuck, don't have a clean cut, we'll overflow
05374                 s2 = s3;
05375             }
05376             *s2 = '\0';
05377             Text_PaintCenter(x, y, scale, color, s1, adjust);
05378             y += ystep;
05379             if (c_bcp == '\0')
05380       {
05381                 // that was the last word
05382         // we could start a new loop, but that wouldn't be much use
05383         // even if the word is too long, we would overflow it (see above)
05384         // so just print it now if needed
05385         s2++;
05386         if (*s2 != '\0') // if we are printing an overflowing line we have s2 == s3
05387           Text_PaintCenter(x, y, scale, color, s2, adjust);
05388         break;
05389       }
05390             s2++;
05391             s1 = s2;
05392             s3 = s2;
05393         }
05394         else
05395         {
05396             s2 = s3;
05397             if (c_bcp == '\0') // we reached the end
05398             {
05399                 Text_PaintCenter(x, y, scale, color, s1, adjust);
05400                 break;
05401             }
05402         }
05403     }
05404 }
05405 
05406 static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale ) {
05407     static char dlText[]    = "Downloading:";
05408     static char etaText[]   = "Estimated time left:";
05409     static char xferText[]  = "Transfer rate:";
05410 
05411     int downloadSize, downloadCount, downloadTime;
05412     char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64];
05413     int xferRate;
05414     int leftWidth;
05415     const char *s;
05416 
05417     downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" );
05418     downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" );
05419     downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" );
05420 
05421     leftWidth = 320;
05422 
05423     UI_SetColor(colorWhite);
05424     Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0);
05425     Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0);
05426     Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0);
05427 
05428     if (downloadSize > 0) {
05429         s = va( "%s (%d%%)", downloadName, downloadCount * 100 / downloadSize );
05430     } else {
05431         s = downloadName;
05432     }
05433 
05434     Text_PaintCenter(centerPoint, yStart+136, scale, colorWhite, s, 0);
05435 
05436     UI_ReadableSize( dlSizeBuf,     sizeof dlSizeBuf,       downloadCount );
05437     UI_ReadableSize( totalSizeBuf,  sizeof totalSizeBuf,    downloadSize );
05438 
05439     if (downloadCount < 4096 || !downloadTime) {
05440         Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
05441         Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
05442     } else {
05443         if ((uiInfo.uiDC.realTime - downloadTime) / 1000) {
05444             xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000);
05445         } else {
05446             xferRate = 0;
05447         }
05448         UI_ReadableSize( xferRateBuf, sizeof xferRateBuf, xferRate );
05449 
05450         // Extrapolate estimated completion time
05451         if (downloadSize && xferRate) {
05452             int n = downloadSize / xferRate; // estimated time for entire d/l in secs
05453 
05454             // We do it in K (/1024) because we'd overflow around 4MB
05455             UI_PrintTime ( dlTimeBuf, sizeof dlTimeBuf, 
05456                 (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000);
05457 
05458             Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0);
05459             Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
05460         } else {
05461             Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0);
05462             if (downloadSize) {
05463                 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0);
05464             } else {
05465                 Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0);
05466             }
05467         }
05468 
05469         if (xferRate) {
05470             Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0);
05471         }
05472     }
05473 }
05474 
05475 /*
05476 ========================
05477 UI_DrawConnectScreen
05478 
05479 This will also be overlaid on the cgame info screen during loading
05480 to prevent it from blinking away too rapidly on local or lan games.
05481 ========================
05482 */
05483 void UI_DrawConnectScreen( qboolean overlay ) {
05484     char            *s;
05485     uiClientState_t cstate;
05486     char            info[MAX_INFO_VALUE];
05487     char text[256];
05488     float centerPoint, yStart, scale;
05489     
05490     menuDef_t *menu = Menus_FindByName("Connect");
05491 
05492 
05493     if ( !overlay && menu ) {
05494         Menu_Paint(menu, qtrue);
05495     }
05496 
05497     if (!overlay) {
05498         centerPoint = 320;
05499         yStart = 130;
05500         scale = 0.5f;
05501     } else {
05502         centerPoint = 320;
05503         yStart = 32;
05504         scale = 0.6f;
05505         return;
05506     }
05507 
05508     // see what information we should display
05509     trap_GetClientState( &cstate );
05510 
05511     info[0] = '\0';
05512     if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) {
05513         Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0);
05514     }
05515 
05516     if (!Q_stricmp(cstate.servername,"localhost")) {
05517         Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE);
05518     } else {
05519         strcpy(text, va("Connecting to %s", cstate.servername));
05520         Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE);
05521     }
05522 
05523     // display global MOTD at bottom
05524     Text_PaintCenter(centerPoint, 600, scale, colorWhite, Info_ValueForKey( cstate.updateInfoString, "motd" ), 0);
05525     // print any server info (server full, bad version, etc)
05526     if ( cstate.connState < CA_CONNECTED ) {
05527         Text_PaintCenter_AutoWrapped(centerPoint, yStart + 176, 630, 20, scale, colorWhite, cstate.messageString, 0);
05528     }
05529 
05530     if ( lastConnState > cstate.connState ) {
05531         lastLoadingText[0] = '\0';
05532     }
05533     lastConnState = cstate.connState;
05534 
05535     switch ( cstate.connState ) {
05536     case CA_CONNECTING:
05537         s = va("Awaiting connection...%i", cstate.connectPacketCount);
05538         break;
05539     case CA_CHALLENGING:
05540         s = va("Awaiting challenge...%i", cstate.connectPacketCount);
05541         break;
05542     case CA_CONNECTED: {
05543         char downloadName[MAX_INFO_VALUE];
05544 
05545             trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof(downloadName) );
05546             if (*downloadName) {
05547                 UI_DisplayDownloadInfo( downloadName, centerPoint, yStart, scale );
05548                 return;
05549             }
05550         }
05551         s = "Awaiting gamestate...";
05552         break;
05553     case CA_LOADING:
05554         return;
05555     case CA_PRIMED:
05556         return;
05557     default:
05558         return;
05559     }
05560 
05561 
05562     if (Q_stricmp(cstate.servername,"localhost")) {
05563         Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0);
05564     }
05565 
05566     // password required / connection rejected information goes here
05567 }
05568 
05569 
05570 /*
05571 ================
05572 cvars
05573 ================
05574 */
05575 
05576 typedef struct {
05577     vmCvar_t    *vmCvar;
05578     char        *cvarName;
05579     char        *defaultString;
05580     int         cvarFlags;
05581 } cvarTable_t;
05582 
05583 vmCvar_t    ui_ffa_fraglimit;
05584 vmCvar_t    ui_ffa_timelimit;
05585 
05586 vmCvar_t    ui_tourney_fraglimit;
05587 vmCvar_t    ui_tourney_timelimit;
05588 
05589 vmCvar_t    ui_team_fraglimit;
05590 vmCvar_t    ui_team_timelimit;
05591 vmCvar_t    ui_team_friendly;
05592 
05593 vmCvar_t    ui_ctf_capturelimit;
05594 vmCvar_t    ui_ctf_timelimit;
05595 vmCvar_t    ui_ctf_friendly;
05596 
05597 vmCvar_t    ui_arenasFile;
05598 vmCvar_t    ui_botsFile;
05599 vmCvar_t    ui_spScores1;
05600 vmCvar_t    ui_spScores2;
05601 vmCvar_t    ui_spScores3;
05602 vmCvar_t    ui_spScores4;
05603 vmCvar_t    ui_spScores5;
05604 vmCvar_t    ui_spAwards;
05605 vmCvar_t    ui_spVideos;
05606 vmCvar_t    ui_spSkill;
05607 
05608 vmCvar_t    ui_spSelection;
05609 
05610 vmCvar_t    ui_browserMaster;
05611 vmCvar_t    ui_browserGameType;
05612 vmCvar_t    ui_browserSortKey;
05613 vmCvar_t    ui_browserShowFull;
05614 vmCvar_t    ui_browserShowEmpty;
05615 
05616 vmCvar_t    ui_brassTime;
05617 vmCvar_t    ui_drawCrosshair;
05618 vmCvar_t    ui_drawCrosshairNames;
05619 vmCvar_t    ui_marks;
05620 
05621 vmCvar_t    ui_server1;
05622 vmCvar_t    ui_server2;
05623 vmCvar_t    ui_server3;
05624 vmCvar_t    ui_server4;
05625 vmCvar_t    ui_server5;
05626 vmCvar_t    ui_server6;
05627 vmCvar_t    ui_server7;
05628 vmCvar_t    ui_server8;
05629 vmCvar_t    ui_server9;
05630 vmCvar_t    ui_server10;
05631 vmCvar_t    ui_server11;
05632 vmCvar_t    ui_server12;
05633 vmCvar_t    ui_server13;
05634 vmCvar_t    ui_server14;
05635 vmCvar_t    ui_server15;
05636 vmCvar_t    ui_server16;
05637 
05638 vmCvar_t    ui_cdkeychecked;
05639 
05640 vmCvar_t    ui_redteam;
05641 vmCvar_t    ui_redteam1;
05642 vmCvar_t    ui_redteam2;
05643 vmCvar_t    ui_redteam3;
05644 vmCvar_t    ui_redteam4;
05645 vmCvar_t    ui_redteam5;
05646 vmCvar_t    ui_blueteam;
05647 vmCvar_t    ui_blueteam1;
05648 vmCvar_t    ui_blueteam2;
05649 vmCvar_t    ui_blueteam3;
05650 vmCvar_t    ui_blueteam4;
05651 vmCvar_t    ui_blueteam5;
05652 vmCvar_t    ui_teamName;
05653 vmCvar_t    ui_dedicated;
05654 vmCvar_t    ui_gameType;
05655 vmCvar_t    ui_netGameType;
05656 vmCvar_t    ui_actualNetGameType;
05657 vmCvar_t    ui_joinGameType;
05658 vmCvar_t    ui_netSource;
05659 vmCvar_t    ui_serverFilterType;
05660 vmCvar_t    ui_opponentName;
05661 vmCvar_t    ui_menuFiles;
05662 vmCvar_t    ui_currentTier;
05663 vmCvar_t    ui_currentMap;
05664 vmCvar_t    ui_currentNetMap;
05665 vmCvar_t    ui_mapIndex;
05666 vmCvar_t    ui_currentOpponent;
05667 vmCvar_t    ui_selectedPlayer;
05668 vmCvar_t    ui_selectedPlayerName;
05669 vmCvar_t    ui_lastServerRefresh_0;
05670 vmCvar_t    ui_lastServerRefresh_1;
05671 vmCvar_t    ui_lastServerRefresh_2;
05672 vmCvar_t    ui_lastServerRefresh_3;
05673 vmCvar_t    ui_singlePlayerActive;
05674 vmCvar_t    ui_scoreAccuracy;
05675 vmCvar_t    ui_scoreImpressives;
05676 vmCvar_t    ui_scoreExcellents;
05677 vmCvar_t    ui_scoreCaptures;
05678 vmCvar_t    ui_scoreDefends;
05679 vmCvar_t    ui_scoreAssists;
05680 vmCvar_t    ui_scoreGauntlets;
05681 vmCvar_t    ui_scoreScore;
05682 vmCvar_t    ui_scorePerfect;
05683 vmCvar_t    ui_scoreTeam;
05684 vmCvar_t    ui_scoreBase;
05685 vmCvar_t    ui_scoreTimeBonus;
05686 vmCvar_t    ui_scoreSkillBonus;
05687 vmCvar_t    ui_scoreShutoutBonus;
05688 vmCvar_t    ui_scoreTime;
05689 vmCvar_t    ui_captureLimit;
05690 vmCvar_t    ui_fragLimit;
05691 vmCvar_t    ui_smallFont;
05692 vmCvar_t    ui_bigFont;
05693 vmCvar_t    ui_findPlayer;
05694 vmCvar_t    ui_Q3Model;
05695 vmCvar_t    ui_hudFiles;
05696 vmCvar_t    ui_recordSPDemo;
05697 vmCvar_t    ui_realCaptureLimit;
05698 vmCvar_t    ui_realWarmUp;
05699 vmCvar_t    ui_serverStatusTimeOut;
05700 
05701 
05702 // bk001129 - made static to avoid aliasing
05703 static cvarTable_t      cvarTable[] = {
05704     { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE },
05705     { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE },
05706 
05707     { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE },
05708     { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE },
05709 
05710     { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE },
05711     { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE },
05712     { &ui_team_friendly, "ui_team_friendly",  "1", CVAR_ARCHIVE },
05713 
05714     { &ui_ctf_capturelimit, "ui_ctf_capturelimit", "8", CVAR_ARCHIVE },
05715     { &ui_ctf_timelimit, "ui_ctf_timelimit", "30", CVAR_ARCHIVE },
05716     { &ui_ctf_friendly, "ui_ctf_friendly",  "0", CVAR_ARCHIVE },
05717 
05718     { &ui_arenasFile, "g_arenasFile", "", CVAR_INIT|CVAR_ROM },
05719     { &ui_botsFile, "g_botsFile", "", CVAR_INIT|CVAR_ROM },
05720     { &ui_spScores1, "g_spScores1", "", CVAR_ARCHIVE | CVAR_ROM },
05721     { &ui_spScores2, "g_spScores2", "", CVAR_ARCHIVE | CVAR_ROM },
05722     { &ui_spScores3, "g_spScores3", "", CVAR_ARCHIVE | CVAR_ROM },
05723     { &ui_spScores4, "g_spScores4", "", CVAR_ARCHIVE | CVAR_ROM },
05724     { &ui_spScores5, "g_spScores5", "", CVAR_ARCHIVE | CVAR_ROM },
05725     { &ui_spAwards, "g_spAwards", "", CVAR_ARCHIVE | CVAR_ROM },
05726     { &ui_spVideos, "g_spVideos", "", CVAR_ARCHIVE | CVAR_ROM },
05727     { &ui_spSkill, "g_spSkill", "2", CVAR_ARCHIVE },
05728 
05729     { &ui_spSelection, "ui_spSelection", "", CVAR_ROM },
05730 
05731     { &ui_browserMaster, "ui_browserMaster", "0", CVAR_ARCHIVE },
05732     { &ui_browserGameType, "ui_browserGameType", "0", CVAR_ARCHIVE },
05733     { &ui_browserSortKey, "ui_browserSortKey", "4", CVAR_ARCHIVE },
05734     { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE },
05735     { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE },
05736 
05737     { &ui_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE },
05738     { &ui_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
05739     { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
05740     { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE },
05741 
05742     { &ui_server1, "server1", "", CVAR_ARCHIVE },
05743     { &ui_server2, "server2", "", CVAR_ARCHIVE },
05744     { &ui_server3, "server3", "", CVAR_ARCHIVE },
05745     { &ui_server4, "server4", "", CVAR_ARCHIVE },
05746     { &ui_server5, "server5", "", CVAR_ARCHIVE },
05747     { &ui_server6, "server6", "", CVAR_ARCHIVE },
05748     { &ui_server7, "server7", "", CVAR_ARCHIVE },
05749     { &ui_server8, "server8", "", CVAR_ARCHIVE },
05750     { &ui_server9, "server9", "", CVAR_ARCHIVE },
05751     { &ui_server10, "server10", "", CVAR_ARCHIVE },
05752     { &ui_server11, "server11", "", CVAR_ARCHIVE },
05753     { &ui_server12, "server12", "", CVAR_ARCHIVE },
05754     { &ui_server13, "server13", "", CVAR_ARCHIVE },
05755     { &ui_server14, "server14", "", CVAR_ARCHIVE },
05756     { &ui_server15, "server15", "", CVAR_ARCHIVE },
05757     { &ui_server16, "server16", "", CVAR_ARCHIVE },
05758     { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM },
05759     { &ui_new, "ui_new", "0", CVAR_TEMP },
05760     { &ui_debug, "ui_debug", "0", CVAR_TEMP },
05761     { &ui_initialized, "ui_initialized", "0", CVAR_TEMP },
05762     { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE },
05763     { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE },
05764     { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE },
05765     { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE },
05766     { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE },
05767     { &ui_gameType, "ui_gametype", "3", CVAR_ARCHIVE },
05768     { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE },
05769     { &ui_netGameType, "ui_netGametype", "3", CVAR_ARCHIVE },
05770     { &ui_actualNetGameType, "ui_actualNetGametype", "3", CVAR_ARCHIVE },
05771     { &ui_redteam1, "ui_redteam1", "0", CVAR_ARCHIVE },
05772     { &ui_redteam2, "ui_redteam2", "0", CVAR_ARCHIVE },
05773     { &ui_redteam3, "ui_redteam3", "0", CVAR_ARCHIVE },
05774     { &ui_redteam4, "ui_redteam4", "0", CVAR_ARCHIVE },
05775     { &ui_redteam5, "ui_redteam5", "0", CVAR_ARCHIVE },
05776     { &ui_blueteam1, "ui_blueteam1", "0", CVAR_ARCHIVE },
05777     { &ui_blueteam2, "ui_blueteam2", "0", CVAR_ARCHIVE },
05778     { &ui_blueteam3, "ui_blueteam3", "0", CVAR_ARCHIVE },
05779     { &ui_blueteam4, "ui_blueteam4", "0", CVAR_ARCHIVE },
05780     { &ui_blueteam5, "ui_blueteam5", "0", CVAR_ARCHIVE },
05781     { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE },
05782     { &ui_menuFiles, "ui_menuFiles", "ui/menus.txt", CVAR_ARCHIVE },
05783     { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE },
05784     { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE },
05785     { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE },
05786     { &ui_mapIndex, "ui_mapIndex", "0", CVAR_ARCHIVE },
05787     { &ui_currentOpponent, "ui_currentOpponent", "0", CVAR_ARCHIVE },
05788     { &ui_selectedPlayer, "cg_selectedPlayer", "0", CVAR_ARCHIVE},
05789     { &ui_selectedPlayerName, "cg_selectedPlayerName", "", CVAR_ARCHIVE},
05790     { &ui_lastServerRefresh_0, "ui_lastServerRefresh_0", "", CVAR_ARCHIVE},
05791     { &ui_lastServerRefresh_1, "ui_lastServerRefresh_1", "", CVAR_ARCHIVE},
05792     { &ui_lastServerRefresh_2, "ui_lastServerRefresh_2", "", CVAR_ARCHIVE},
05793     { &ui_lastServerRefresh_3, "ui_lastServerRefresh_3", "", CVAR_ARCHIVE},
05794     { &ui_singlePlayerActive, "ui_singlePlayerActive", "0", 0},
05795     { &ui_scoreAccuracy, "ui_scoreAccuracy", "0", CVAR_ARCHIVE},
05796     { &ui_scoreImpressives, "ui_scoreImpressives", "0", CVAR_ARCHIVE},
05797     { &ui_scoreExcellents, "ui_scoreExcellents", "0", CVAR_ARCHIVE},
05798     { &ui_scoreCaptures, "ui_scoreCaptures", "0", CVAR_ARCHIVE},
05799     { &ui_scoreDefends, "ui_scoreDefends", "0", CVAR_ARCHIVE},
05800     { &ui_scoreAssists, "ui_scoreAssists", "0", CVAR_ARCHIVE},
05801     { &ui_scoreGauntlets, "ui_scoreGauntlets", "0",CVAR_ARCHIVE},
05802     { &ui_scoreScore, "ui_scoreScore", "0", CVAR_ARCHIVE},
05803     { &ui_scorePerfect, "ui_scorePerfect", "0", CVAR_ARCHIVE},
05804     { &ui_scoreTeam, "ui_scoreTeam", "0 to 0", CVAR_ARCHIVE},
05805     { &ui_scoreBase, "ui_scoreBase", "0", CVAR_ARCHIVE},
05806     { &ui_scoreTime, "ui_scoreTime", "00:00", CVAR_ARCHIVE},
05807     { &ui_scoreTimeBonus, "ui_scoreTimeBonus", "0", CVAR_ARCHIVE},
05808     { &ui_scoreSkillBonus, "ui_scoreSkillBonus", "0", CVAR_ARCHIVE},
05809     { &ui_scoreShutoutBonus, "ui_scoreShutoutBonus", "0", CVAR_ARCHIVE},
05810     { &ui_fragLimit, "ui_fragLimit", "10", 0},
05811     { &ui_captureLimit, "ui_captureLimit", "5", 0},
05812     { &ui_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE},
05813     { &ui_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE},
05814     { &ui_findPlayer, "ui_findPlayer", "Sarge", CVAR_ARCHIVE},
05815     { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE},
05816     { &ui_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
05817     { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE},
05818     { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE},
05819     { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE},
05820     { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART},
05821     { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE},
05822 
05823 };
05824 
05825 // bk001129 - made static to avoid aliasing
05826 static int      cvarTableSize = sizeof(cvarTable) / sizeof(cvarTable[0]);
05827 
05828 
05829 /*
05830 =================
05831 UI_RegisterCvars
05832 =================
05833 */
05834 void UI_RegisterCvars( void ) {
05835     int         i;
05836     cvarTable_t *cv;
05837 
05838     for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
05839         trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
05840     }
05841 }
05842 
05843 /*
05844 =================
05845 UI_UpdateCvars
05846 =================
05847 */
05848 void UI_UpdateCvars( void ) {
05849     int         i;
05850     cvarTable_t *cv;
05851 
05852     for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
05853         trap_Cvar_Update( cv->vmCvar );
05854     }
05855 }
05856 
05857 
05858 /*
05859 =================
05860 ArenaServers_StopRefresh
05861 =================
05862 */
05863 static void UI_StopServerRefresh( void )
05864 {
05865     int count;
05866 
05867     if (!uiInfo.serverStatus.refreshActive) {
05868         // not currently refreshing
05869         return;
05870     }
05871     uiInfo.serverStatus.refreshActive = qfalse;
05872     Com_Printf("%d servers listed in browser with %d players.\n",
05873                     uiInfo.serverStatus.numDisplayServers,
05874                     uiInfo.serverStatus.numPlayersOnServers);
05875     count = trap_LAN_GetServerCount(ui_netSource.integer);
05876     if (count - uiInfo.serverStatus.numDisplayServers > 0) {
05877         Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n",
05878                         count - uiInfo.serverStatus.numDisplayServers,
05879                         (int) trap_Cvar_VariableValue("cl_maxPing"));
05880     }
05881 
05882 }
05883 
05884 /*
05885 =================
05886 ArenaServers_MaxPing
05887 =================
05888 */
05889 #ifndef MISSIONPACK // bk001206
05890 static int ArenaServers_MaxPing( void ) {
05891     int     maxPing;
05892 
05893     maxPing = (int)trap_Cvar_VariableValue( "cl_maxPing" );
05894     if( maxPing < 100 ) {
05895         maxPing = 100;
05896     }
05897     return maxPing;
05898 }
05899 #endif
05900 
05901 /*
05902 =================
05903 UI_DoServerRefresh
05904 =================
05905 */
05906 static void UI_DoServerRefresh( void )
05907 {
05908     qboolean wait = qfalse;
05909 
05910     if (!uiInfo.serverStatus.refreshActive) {
05911         return;
05912     }
05913     if (ui_netSource.integer != AS_FAVORITES) {
05914         if (ui_netSource.integer == AS_LOCAL) {
05915             if (!trap_LAN_GetServerCount(ui_netSource.integer)) {
05916                 wait = qtrue;
05917             }
05918         } else {
05919             if (trap_LAN_GetServerCount(ui_netSource.integer) < 0) {
05920                 wait = qtrue;
05921             }
05922         }
05923     }
05924 
05925     if (uiInfo.uiDC.realTime < uiInfo.serverStatus.refreshtime) {
05926         if (wait) {
05927             return;
05928         }
05929     }
05930 
05931     // if still trying to retrieve pings
05932     if (trap_LAN_UpdateVisiblePings(ui_netSource.integer)) {
05933         uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
05934     } else if (!wait) {
05935         // get the last servers in the list
05936         UI_BuildServerDisplayList(2);
05937         // stop the refresh
05938         UI_StopServerRefresh();
05939     }
05940     //
05941     UI_BuildServerDisplayList(qfalse);
05942 }
05943 
05944 /*
05945 =================
05946 UI_StartServerRefresh
05947 =================
05948 */
05949 static void UI_StartServerRefresh(qboolean full)
05950 {
05951     int     i;
05952     char    *ptr;
05953 
05954     qtime_t q;
05955     trap_RealTime(&q);
05956     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));
05957 
05958     if (!full) {
05959         UI_UpdatePendingPings();
05960         return;
05961     }
05962 
05963     uiInfo.serverStatus.refreshActive = qtrue;
05964     uiInfo.serverStatus.nextDisplayRefresh = uiInfo.uiDC.realTime + 1000;
05965     // clear number of displayed servers
05966     uiInfo.serverStatus.numDisplayServers = 0;
05967     uiInfo.serverStatus.numPlayersOnServers = 0;
05968     // mark all servers as visible so we store ping updates for them
05969     trap_LAN_MarkServerVisible(ui_netSource.integer, -1, qtrue);
05970     // reset all the pings
05971     trap_LAN_ResetPings(ui_netSource.integer);
05972     //
05973     if( ui_netSource.integer == AS_LOCAL ) {
05974         trap_Cmd_ExecuteText( EXEC_NOW, "localservers\n" );
05975         uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 1000;
05976         return;
05977     }
05978 
05979     uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime + 5000;
05980     if( ui_netSource.integer == AS_GLOBAL || ui_netSource.integer == AS_MPLAYER ) {
05981         if( ui_netSource.integer == AS_GLOBAL ) {
05982             i = 0;
05983         }
05984         else {
05985             i = 1;
05986         }
05987 
05988         ptr = UI_Cvar_VariableString("debug_protocol");
05989         if (strlen(ptr)) {
05990             trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %s full empty\n", i, ptr));
05991         }
05992         else {
05993             trap_Cmd_ExecuteText( EXEC_NOW, va( "globalservers %d %d full empty\n", i, (int)trap_Cvar_VariableValue( "protocol" ) ) );
05994         }
05995     }
05996 }
05997 

Generated on Thu Aug 25 12:37:42 2005 for Quake III Arena by  doxygen 1.3.9.1