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

ui_startserver.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 START SERVER MENU *****
00027 
00028 =============================================================================
00029 */
00030 
00031 
00032 #include "ui_local.h"
00033 
00034 
00035 #define GAMESERVER_BACK0        "menu/art/back_0"
00036 #define GAMESERVER_BACK1        "menu/art/back_1"
00037 #define GAMESERVER_NEXT0        "menu/art/next_0"
00038 #define GAMESERVER_NEXT1        "menu/art/next_1"
00039 #define GAMESERVER_FRAMEL       "menu/art/frame2_l"
00040 #define GAMESERVER_FRAMER       "menu/art/frame1_r"
00041 #define GAMESERVER_SELECT       "menu/art/maps_select"
00042 #define GAMESERVER_SELECTED     "menu/art/maps_selected"
00043 #define GAMESERVER_FIGHT0       "menu/art/fight_0"
00044 #define GAMESERVER_FIGHT1       "menu/art/fight_1"
00045 #define GAMESERVER_UNKNOWNMAP   "menu/art/unknownmap"
00046 #define GAMESERVER_ARROWS       "menu/art/gs_arrows_0"
00047 #define GAMESERVER_ARROWSL      "menu/art/gs_arrows_l"
00048 #define GAMESERVER_ARROWSR      "menu/art/gs_arrows_r"
00049 
00050 #define MAX_MAPROWS     2
00051 #define MAX_MAPCOLS     2
00052 #define MAX_MAPSPERPAGE 4
00053 
00054 #define MAX_SERVERSTEXT 8192
00055 
00056 #define MAX_SERVERMAPS  64
00057 #define MAX_NAMELENGTH  16
00058 
00059 #define ID_GAMETYPE             10
00060 #define ID_PICTURES             11  // 12, 13, 14
00061 #define ID_PREVPAGE             15
00062 #define ID_NEXTPAGE             16
00063 #define ID_STARTSERVERBACK      17
00064 #define ID_STARTSERVERNEXT      18
00065 
00066 typedef struct {
00067     menuframework_s menu;
00068 
00069     menutext_s      banner;
00070     menubitmap_s    framel;
00071     menubitmap_s    framer;
00072 
00073     menulist_s      gametype;
00074     menubitmap_s    mappics[MAX_MAPSPERPAGE];
00075     menubitmap_s    mapbuttons[MAX_MAPSPERPAGE];
00076     menubitmap_s    arrows;
00077     menubitmap_s    prevpage;
00078     menubitmap_s    nextpage;
00079     menubitmap_s    back;
00080     menubitmap_s    next;
00081 
00082     menutext_s      mapname;
00083     menubitmap_s    item_null;
00084 
00085     qboolean        multiplayer;
00086     int             currentmap;
00087     int             nummaps;
00088     int             page;
00089     int             maxpages;
00090     char            maplist[MAX_SERVERMAPS][MAX_NAMELENGTH];
00091     int             mapGamebits[MAX_SERVERMAPS];
00092 } startserver_t;
00093 
00094 static startserver_t s_startserver;
00095 
00096 static const char *gametype_items[] = {
00097     "Free For All",
00098     "Team Deathmatch",
00099     "Tournament",
00100     "Capture the Flag",
00101     0
00102 };
00103 
00104 static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};
00105 static int gametype_remap2[] = {0, 2, 0, 1, 3};
00106 
00107 // use ui_servers2.c definition
00108 extern const char* punkbuster_items[];
00109 
00110 static void UI_ServerOptionsMenu( qboolean multiplayer );
00111 
00112 
00113 /*
00114 =================
00115 GametypeBits
00116 =================
00117 */
00118 static int GametypeBits( char *string ) {
00119     int     bits;
00120     char    *p;
00121     char    *token;
00122 
00123     bits = 0;
00124     p = string;
00125     while( 1 ) {
00126         token = COM_ParseExt( &p, qfalse );
00127         if( token[0] == 0 ) {
00128             break;
00129         }
00130 
00131         if( Q_stricmp( token, "ffa" ) == 0 ) {
00132             bits |= 1 << GT_FFA;
00133             continue;
00134         }
00135 
00136         if( Q_stricmp( token, "tourney" ) == 0 ) {
00137             bits |= 1 << GT_TOURNAMENT;
00138             continue;
00139         }
00140 
00141         if( Q_stricmp( token, "single" ) == 0 ) {
00142             bits |= 1 << GT_SINGLE_PLAYER;
00143             continue;
00144         }
00145 
00146         if( Q_stricmp( token, "team" ) == 0 ) {
00147             bits |= 1 << GT_TEAM;
00148             continue;
00149         }
00150 
00151         if( Q_stricmp( token, "ctf" ) == 0 ) {
00152             bits |= 1 << GT_CTF;
00153             continue;
00154         }
00155     }
00156 
00157     return bits;
00158 }
00159 
00160 
00161 /*
00162 =================
00163 StartServer_Update
00164 =================
00165 */
00166 static void StartServer_Update( void ) {
00167     int             i;
00168     int             top;
00169     static  char    picname[MAX_MAPSPERPAGE][64];
00170 
00171     top = s_startserver.page*MAX_MAPSPERPAGE;
00172 
00173     for (i=0; i<MAX_MAPSPERPAGE; i++)
00174     {
00175         if (top+i >= s_startserver.nummaps)
00176             break;
00177 
00178         Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] );
00179 
00180         s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
00181         s_startserver.mappics[i].generic.name   = picname[i];
00182         s_startserver.mappics[i].shader         = 0;
00183 
00184         // reset
00185         s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
00186         s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE;
00187     }
00188 
00189     for (; i<MAX_MAPSPERPAGE; i++)
00190     {
00191         s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
00192         s_startserver.mappics[i].generic.name   = NULL;
00193         s_startserver.mappics[i].shader         = 0;
00194 
00195         // disable
00196         s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
00197         s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
00198     }
00199 
00200 
00201     // no servers to start
00202     if( !s_startserver.nummaps ) {
00203         s_startserver.next.generic.flags |= QMF_INACTIVE;
00204 
00205         // set the map name
00206         strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
00207     }
00208     else {
00209         // set the highlight
00210         s_startserver.next.generic.flags &= ~QMF_INACTIVE;
00211         i = s_startserver.currentmap - top;
00212         if ( i >=0 && i < MAX_MAPSPERPAGE ) 
00213         {
00214             s_startserver.mappics[i].generic.flags    |= QMF_HIGHLIGHT;
00215             s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
00216         }
00217 
00218         // set the map name
00219         strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] );
00220     }
00221     
00222     Q_strupr( s_startserver.mapname.string );
00223 }
00224 
00225 
00226 /*
00227 =================
00228 StartServer_MapEvent
00229 =================
00230 */
00231 static void StartServer_MapEvent( void* ptr, int event ) {
00232     if( event != QM_ACTIVATED) {
00233         return;
00234     }
00235 
00236     s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
00237     StartServer_Update();
00238 }
00239 
00240 
00241 /*
00242 =================
00243 StartServer_GametypeEvent
00244 =================
00245 */
00246 static void StartServer_GametypeEvent( void* ptr, int event ) {
00247     int         i;
00248     int         count;
00249     int         gamebits;
00250     int         matchbits;
00251     const char  *info;
00252 
00253     if( event != QM_ACTIVATED) {
00254         return;
00255     }
00256 
00257     count = UI_GetNumArenas();
00258     s_startserver.nummaps = 0;
00259     matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
00260     if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {
00261         matchbits |= ( 1 << GT_SINGLE_PLAYER );
00262     }
00263     for( i = 0; i < count; i++ ) {
00264         info = UI_GetArenaInfoByNumber( i );
00265 
00266         gamebits = GametypeBits( Info_ValueForKey( info, "type") );
00267         if( !( gamebits & matchbits ) ) {
00268             continue;
00269         }
00270 
00271         Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
00272         Q_strupr( s_startserver.maplist[s_startserver.nummaps] );
00273         s_startserver.mapGamebits[s_startserver.nummaps] = gamebits;
00274         s_startserver.nummaps++;
00275     }
00276     s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
00277     s_startserver.page = 0;
00278     s_startserver.currentmap = 0;
00279 
00280     StartServer_Update();
00281 }
00282 
00283 
00284 /*
00285 =================
00286 StartServer_MenuEvent
00287 =================
00288 */
00289 static void StartServer_MenuEvent( void* ptr, int event ) {
00290     if( event != QM_ACTIVATED ) {
00291         return;
00292     }
00293 
00294     switch( ((menucommon_s*)ptr)->id ) {
00295     case ID_PREVPAGE:
00296         if( s_startserver.page > 0 ) {
00297             s_startserver.page--;
00298             StartServer_Update();
00299         }
00300         break;
00301 
00302     case ID_NEXTPAGE:
00303         if( s_startserver.page < s_startserver.maxpages - 1 ) {
00304             s_startserver.page++;
00305             StartServer_Update();
00306         }
00307         break;
00308 
00309     case ID_STARTSERVERNEXT:
00310         trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
00311         UI_ServerOptionsMenu( s_startserver.multiplayer );
00312         break;
00313 
00314     case ID_STARTSERVERBACK:
00315         UI_PopMenu();
00316         break;
00317     }
00318 }
00319 
00320 
00321 /*
00322 ===============
00323 StartServer_LevelshotDraw
00324 ===============
00325 */
00326 static void StartServer_LevelshotDraw( void *self ) {
00327     menubitmap_s    *b;
00328     int             x;
00329     int             y;
00330     int             w;
00331     int             h;
00332     int             n;
00333 
00334     b = (menubitmap_s *)self;
00335 
00336     if( !b->generic.name ) {
00337         return;
00338     }
00339 
00340     if( b->generic.name && !b->shader ) {
00341         b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
00342         if( !b->shader && b->errorpic ) {
00343             b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
00344         }
00345     }
00346 
00347     if( b->focuspic && !b->focusshader ) {
00348         b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
00349     }
00350 
00351     x = b->generic.x;
00352     y = b->generic.y;
00353     w = b->width;
00354     h = b->height;
00355     if( b->shader ) {
00356         UI_DrawHandlePic( x, y, w, h, b->shader );
00357     }
00358 
00359     x = b->generic.x;
00360     y = b->generic.y + b->height;
00361     UI_FillRect( x, y, b->width, 28, colorBlack );
00362 
00363     x += b->width / 2;
00364     y += 4;
00365     n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
00366     UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange );
00367 
00368     x = b->generic.x;
00369     y = b->generic.y;
00370     w = b->width;
00371     h = b->height + 28;
00372     if( b->generic.flags & QMF_HIGHLIGHT ) {    
00373         UI_DrawHandlePic( x, y, w, h, b->focusshader );
00374     }
00375 }
00376 
00377 
00378 /*
00379 =================
00380 StartServer_MenuInit
00381 =================
00382 */
00383 static void StartServer_MenuInit( void ) {
00384     int i;
00385     int x;
00386     int y;
00387     static char mapnamebuffer[64];
00388 
00389     // zero set all our globals
00390     memset( &s_startserver, 0 ,sizeof(startserver_t) );
00391 
00392     StartServer_Cache();
00393 
00394     s_startserver.menu.wrapAround = qtrue;
00395     s_startserver.menu.fullscreen = qtrue;
00396 
00397     s_startserver.banner.generic.type  = MTYPE_BTEXT;
00398     s_startserver.banner.generic.x     = 320;
00399     s_startserver.banner.generic.y     = 16;
00400     s_startserver.banner.string        = "GAME SERVER";
00401     s_startserver.banner.color         = color_white;
00402     s_startserver.banner.style         = UI_CENTER;
00403 
00404     s_startserver.framel.generic.type  = MTYPE_BITMAP;
00405     s_startserver.framel.generic.name  = GAMESERVER_FRAMEL;
00406     s_startserver.framel.generic.flags = QMF_INACTIVE;
00407     s_startserver.framel.generic.x     = 0;  
00408     s_startserver.framel.generic.y     = 78;
00409     s_startserver.framel.width         = 256;
00410     s_startserver.framel.height        = 329;
00411 
00412     s_startserver.framer.generic.type  = MTYPE_BITMAP;
00413     s_startserver.framer.generic.name  = GAMESERVER_FRAMER;
00414     s_startserver.framer.generic.flags = QMF_INACTIVE;
00415     s_startserver.framer.generic.x     = 376;
00416     s_startserver.framer.generic.y     = 76;
00417     s_startserver.framer.width         = 256;
00418     s_startserver.framer.height        = 334;
00419 
00420     s_startserver.gametype.generic.type     = MTYPE_SPINCONTROL;
00421     s_startserver.gametype.generic.name     = "Game Type:";
00422     s_startserver.gametype.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
00423     s_startserver.gametype.generic.callback = StartServer_GametypeEvent;
00424     s_startserver.gametype.generic.id       = ID_GAMETYPE;
00425     s_startserver.gametype.generic.x        = 320 - 24;
00426     s_startserver.gametype.generic.y        = 368;
00427     s_startserver.gametype.itemnames        = gametype_items;
00428 
00429     for (i=0; i<MAX_MAPSPERPAGE; i++)
00430     {
00431         x = (i % MAX_MAPCOLS) * (128+8) + 188;
00432         y = (i / MAX_MAPROWS) * (128+8) + 96;
00433 
00434         s_startserver.mappics[i].generic.type   = MTYPE_BITMAP;
00435         s_startserver.mappics[i].generic.flags  = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
00436         s_startserver.mappics[i].generic.x      = x;
00437         s_startserver.mappics[i].generic.y      = y;
00438         s_startserver.mappics[i].generic.id     = ID_PICTURES+i;
00439         s_startserver.mappics[i].width          = 128;
00440         s_startserver.mappics[i].height         = 96;
00441         s_startserver.mappics[i].focuspic       = GAMESERVER_SELECTED;
00442         s_startserver.mappics[i].errorpic       = GAMESERVER_UNKNOWNMAP;
00443         s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
00444 
00445         s_startserver.mapbuttons[i].generic.type     = MTYPE_BITMAP;
00446         s_startserver.mapbuttons[i].generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
00447         s_startserver.mapbuttons[i].generic.id       = ID_PICTURES+i;
00448         s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
00449         s_startserver.mapbuttons[i].generic.x        = x - 30;
00450         s_startserver.mapbuttons[i].generic.y        = y - 32;
00451         s_startserver.mapbuttons[i].width            = 256;
00452         s_startserver.mapbuttons[i].height           = 248;
00453         s_startserver.mapbuttons[i].generic.left     = x;
00454         s_startserver.mapbuttons[i].generic.top      = y;
00455         s_startserver.mapbuttons[i].generic.right    = x + 128;
00456         s_startserver.mapbuttons[i].generic.bottom   = y + 128;
00457         s_startserver.mapbuttons[i].focuspic         = GAMESERVER_SELECT;
00458     }
00459 
00460     s_startserver.arrows.generic.type  = MTYPE_BITMAP;
00461     s_startserver.arrows.generic.name  = GAMESERVER_ARROWS;
00462     s_startserver.arrows.generic.flags = QMF_INACTIVE;
00463     s_startserver.arrows.generic.x     = 260;
00464     s_startserver.arrows.generic.y     = 400;
00465     s_startserver.arrows.width         = 128;
00466     s_startserver.arrows.height        = 32;
00467 
00468     s_startserver.prevpage.generic.type     = MTYPE_BITMAP;
00469     s_startserver.prevpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
00470     s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
00471     s_startserver.prevpage.generic.id       = ID_PREVPAGE;
00472     s_startserver.prevpage.generic.x        = 260;
00473     s_startserver.prevpage.generic.y        = 400;
00474     s_startserver.prevpage.width            = 64;
00475     s_startserver.prevpage.height           = 32;
00476     s_startserver.prevpage.focuspic         = GAMESERVER_ARROWSL;
00477 
00478     s_startserver.nextpage.generic.type     = MTYPE_BITMAP;
00479     s_startserver.nextpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
00480     s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
00481     s_startserver.nextpage.generic.id       = ID_NEXTPAGE;
00482     s_startserver.nextpage.generic.x        = 321;
00483     s_startserver.nextpage.generic.y        = 400;
00484     s_startserver.nextpage.width            = 64;
00485     s_startserver.nextpage.height           = 32;
00486     s_startserver.nextpage.focuspic         = GAMESERVER_ARROWSR;
00487 
00488     s_startserver.mapname.generic.type  = MTYPE_PTEXT;
00489     s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
00490     s_startserver.mapname.generic.x     = 320;
00491     s_startserver.mapname.generic.y     = 440;
00492     s_startserver.mapname.string        = mapnamebuffer;
00493     s_startserver.mapname.style         = UI_CENTER|UI_BIGFONT;
00494     s_startserver.mapname.color         = text_color_normal;
00495 
00496     s_startserver.back.generic.type     = MTYPE_BITMAP;
00497     s_startserver.back.generic.name     = GAMESERVER_BACK0;
00498     s_startserver.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
00499     s_startserver.back.generic.callback = StartServer_MenuEvent;
00500     s_startserver.back.generic.id       = ID_STARTSERVERBACK;
00501     s_startserver.back.generic.x        = 0;
00502     s_startserver.back.generic.y        = 480-64;
00503     s_startserver.back.width            = 128;
00504     s_startserver.back.height           = 64;
00505     s_startserver.back.focuspic         = GAMESERVER_BACK1;
00506 
00507     s_startserver.next.generic.type     = MTYPE_BITMAP;
00508     s_startserver.next.generic.name     = GAMESERVER_NEXT0;
00509     s_startserver.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
00510     s_startserver.next.generic.callback = StartServer_MenuEvent;
00511     s_startserver.next.generic.id       = ID_STARTSERVERNEXT;
00512     s_startserver.next.generic.x        = 640;
00513     s_startserver.next.generic.y        = 480-64;
00514     s_startserver.next.width            = 128;
00515     s_startserver.next.height           = 64;
00516     s_startserver.next.focuspic         = GAMESERVER_NEXT1;
00517 
00518     s_startserver.item_null.generic.type    = MTYPE_BITMAP;
00519     s_startserver.item_null.generic.flags   = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
00520     s_startserver.item_null.generic.x       = 0;
00521     s_startserver.item_null.generic.y       = 0;
00522     s_startserver.item_null.width           = 640;
00523     s_startserver.item_null.height          = 480;
00524 
00525     Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
00526     Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
00527     Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
00528 
00529     Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
00530     for (i=0; i<MAX_MAPSPERPAGE; i++)
00531     {
00532         Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
00533         Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
00534     }
00535 
00536     Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
00537     Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
00538     Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
00539     Menu_AddItem( &s_startserver.menu, &s_startserver.back );
00540     Menu_AddItem( &s_startserver.menu, &s_startserver.next );
00541     Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
00542     Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
00543 
00544     StartServer_GametypeEvent( NULL, QM_ACTIVATED );
00545 }
00546 
00547 
00548 /*
00549 =================
00550 StartServer_Cache
00551 =================
00552 */
00553 void StartServer_Cache( void )
00554 {
00555     int             i;
00556     const char      *info;
00557     qboolean        precache;
00558     char            picname[64];
00559 
00560     trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 ); 
00561     trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 ); 
00562     trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 ); 
00563     trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 ); 
00564     trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );    
00565     trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );    
00566     trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );    
00567     trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );  
00568     trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
00569     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
00570     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
00571     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
00572 
00573     precache = trap_Cvar_VariableValue("com_buildscript");
00574 
00575     s_startserver.nummaps = UI_GetNumArenas();
00576 
00577     for( i = 0; i < s_startserver.nummaps; i++ ) {
00578         info = UI_GetArenaInfoByNumber( i );
00579 
00580         Q_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
00581         Q_strupr( s_startserver.maplist[i] );
00582         s_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, "type") );
00583 
00584         if( precache ) {
00585             Com_sprintf( picname, sizeof(picname), "levelshots/%s", s_startserver.maplist[i] );
00586             trap_R_RegisterShaderNoMip(picname);
00587         }
00588     }
00589 
00590     s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
00591 }
00592 
00593 
00594 /*
00595 =================
00596 UI_StartServerMenu
00597 =================
00598 */
00599 void UI_StartServerMenu( qboolean multiplayer ) {
00600     StartServer_MenuInit();
00601     s_startserver.multiplayer = multiplayer;
00602     UI_PushMenu( &s_startserver.menu );
00603 }
00604 
00605 
00606 
00607 /*
00608 =============================================================================
00609 
00610 SERVER OPTIONS MENU *****
00611 
00612 =============================================================================
00613 */
00614 
00615 #define ID_PLAYER_TYPE          20
00616 #define ID_MAXCLIENTS           21
00617 #define ID_DEDICATED            22
00618 #define ID_GO                   23
00619 #define ID_BACK                 24
00620 
00621 #define PLAYER_SLOTS            12
00622 
00623 
00624 typedef struct {
00625     menuframework_s     menu;
00626 
00627     menutext_s          banner;
00628 
00629     menubitmap_s        mappic;
00630     menubitmap_s        picframe;
00631 
00632     menulist_s          dedicated;
00633     menufield_s         timelimit;
00634     menufield_s         fraglimit;
00635     menufield_s         flaglimit;
00636     menuradiobutton_s   friendlyfire;
00637     menufield_s         hostname;
00638     menuradiobutton_s   pure;
00639     menulist_s          botSkill;
00640 
00641     menutext_s          player0;
00642     menulist_s          playerType[PLAYER_SLOTS];
00643     menutext_s          playerName[PLAYER_SLOTS];
00644     menulist_s          playerTeam[PLAYER_SLOTS];
00645 
00646     menubitmap_s        go;
00647     menubitmap_s        next;
00648     menubitmap_s        back;
00649 
00650     qboolean            multiplayer;
00651     int                 gametype;
00652     char                mapnamebuffer[32];
00653     char                playerNameBuffers[PLAYER_SLOTS][16];
00654 
00655     qboolean            newBot;
00656     int                 newBotIndex;
00657     char                newBotName[16];
00658     
00659     menulist_s      punkbuster;
00660 } serveroptions_t;
00661 
00662 static serveroptions_t s_serveroptions;
00663 
00664 static const char *dedicated_list[] = {
00665     "No",
00666     "LAN",
00667     "Internet",
00668     0
00669 };
00670 
00671 static const char *playerType_list[] = {
00672     "Open",
00673     "Bot",
00674     "----",
00675     0
00676 };
00677 
00678 static const char *playerTeam_list[] = {
00679     "Blue",
00680     "Red",
00681     0
00682 };
00683 
00684 static const char *botSkill_list[] = {
00685     "I Can Win",
00686     "Bring It On",
00687     "Hurt Me Plenty",
00688     "Hardcore",
00689     "Nightmare!",
00690     0
00691 };
00692 
00693 
00694 /*
00695 =================
00696 BotAlreadySelected
00697 =================
00698 */
00699 static qboolean BotAlreadySelected( const char *checkName ) {
00700     int     n;
00701 
00702     for( n = 1; n < PLAYER_SLOTS; n++ ) {
00703         if( s_serveroptions.playerType[n].curvalue != 1 ) {
00704             continue;
00705         }
00706         if( (s_serveroptions.gametype >= GT_TEAM) &&
00707             (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
00708             continue;
00709         }
00710         if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
00711             return qtrue;
00712         }
00713     }
00714 
00715     return qfalse;
00716 }
00717 
00718 
00719 /*
00720 =================
00721 ServerOptions_Start
00722 =================
00723 */
00724 static void ServerOptions_Start( void ) {
00725     int     timelimit;
00726     int     fraglimit;
00727     int     maxclients;
00728     int     dedicated;
00729     int     friendlyfire;
00730     int     flaglimit;
00731     int     pure;
00732     int     skill;
00733     int     n;
00734     char    buf[64];
00735 
00736 
00737     timelimit    = atoi( s_serveroptions.timelimit.field.buffer );
00738     fraglimit    = atoi( s_serveroptions.fraglimit.field.buffer );
00739     flaglimit    = atoi( s_serveroptions.flaglimit.field.buffer );
00740     dedicated    = s_serveroptions.dedicated.curvalue;
00741     friendlyfire = s_serveroptions.friendlyfire.curvalue;
00742     pure         = s_serveroptions.pure.curvalue;
00743     skill        = s_serveroptions.botSkill.curvalue + 1;
00744 
00745     //set maxclients
00746     for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
00747         if( s_serveroptions.playerType[n].curvalue == 2 ) {
00748             continue;
00749         }
00750         if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
00751             continue;
00752         }
00753         maxclients++;
00754     }
00755 
00756     switch( s_serveroptions.gametype ) {
00757     case GT_FFA:
00758     default:
00759         trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
00760         trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
00761         break;
00762 
00763     case GT_TOURNAMENT:
00764         trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
00765         trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
00766         break;
00767 
00768     case GT_TEAM:
00769         trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
00770         trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
00771         trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
00772         break;
00773 
00774     case GT_CTF:
00775         trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
00776         trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
00777         trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
00778         break;
00779     }
00780 
00781     trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
00782     trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
00783     trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
00784     trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
00785     trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
00786     trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
00787     trap_Cvar_SetValue( "sv_pure", pure );
00788     trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
00789     
00790     trap_Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue );
00791 
00792     // the wait commands will allow the dedicated to take effect
00793     trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) );
00794 
00795     // add bots
00796     trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
00797     for( n = 1; n < PLAYER_SLOTS; n++ ) {
00798         if( s_serveroptions.playerType[n].curvalue != 1 ) {
00799             continue;
00800         }
00801         if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
00802             continue;
00803         }
00804         if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
00805             continue;
00806         }
00807         if( s_serveroptions.gametype >= GT_TEAM ) {
00808             Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
00809                 playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
00810         }
00811         else {
00812             Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
00813         }
00814         trap_Cmd_ExecuteText( EXEC_APPEND, buf );
00815     }
00816 
00817     // set player's team
00818     if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) {
00819         trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
00820     }
00821 }
00822 
00823 
00824 /*
00825 =================
00826 ServerOptions_InitPlayerItems
00827 =================
00828 */
00829 static void ServerOptions_InitPlayerItems( void ) {
00830     int     n;
00831     int     v;
00832 
00833     // init types
00834     if( s_serveroptions.multiplayer ) {
00835         v = 0;  // open
00836     }
00837     else {
00838         v = 1;  // bot
00839     }
00840     
00841     for( n = 0; n < PLAYER_SLOTS; n++ ) {
00842         s_serveroptions.playerType[n].curvalue = v;
00843     }
00844 
00845     if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) {
00846         for( n = 8; n < PLAYER_SLOTS; n++ ) {
00847             s_serveroptions.playerType[n].curvalue = 2;
00848         }
00849     }
00850 
00851     // if not a dedicated server, first slot is reserved for the human on the server
00852     if( s_serveroptions.dedicated.curvalue == 0 ) {
00853         // human
00854         s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
00855         s_serveroptions.playerType[0].curvalue = 0;
00856         trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
00857         Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
00858     }
00859 
00860     // init teams
00861     if( s_serveroptions.gametype >= GT_TEAM ) {
00862         for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
00863             s_serveroptions.playerTeam[n].curvalue = 0;
00864         }
00865         for( ; n < PLAYER_SLOTS; n++ ) {
00866             s_serveroptions.playerTeam[n].curvalue = 1;
00867         }
00868     }
00869     else {
00870         for( n = 0; n < PLAYER_SLOTS; n++ ) {
00871             s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
00872         }
00873     }
00874 }
00875 
00876 
00877 /*
00878 =================
00879 ServerOptions_SetPlayerItems
00880 =================
00881 */
00882 static void ServerOptions_SetPlayerItems( void ) {
00883     int     start;
00884     int     n;
00885 
00886     // types
00887 //  for( n = 0; n < PLAYER_SLOTS; n++ ) {
00888 //      if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
00889 //          s_serveroptions.playerType[n].curvalue = 1;
00890 //      }
00891 //  }
00892 
00893     // names
00894     if( s_serveroptions.dedicated.curvalue == 0 ) {
00895         s_serveroptions.player0.string = "Human";
00896         s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN;
00897 
00898         start = 1;
00899     }
00900     else {
00901         s_serveroptions.player0.string = "Open";
00902         start = 0;
00903     }
00904     for( n = start; n < PLAYER_SLOTS; n++ ) {
00905         if( s_serveroptions.