home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / ui_startserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  56.9 KB  |  1,905 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. /*
  4. =============================================================================
  5.  
  6. START SERVER MENU *****
  7.  
  8. =============================================================================
  9. */
  10.  
  11.  
  12. #include "ui_local.h"
  13.  
  14.  
  15. #define GAMESERVER_BACK0        "menu/art/back_0"
  16. #define GAMESERVER_BACK1        "menu/art/back_1"
  17. #define GAMESERVER_NEXT0        "menu/art/next_0"
  18. #define GAMESERVER_NEXT1        "menu/art/next_1"
  19. #define GAMESERVER_FRAMEL        "menu/art/frame2_l"
  20. #define GAMESERVER_FRAMER        "menu/art/frame1_r"
  21. #define GAMESERVER_SELECT        "menu/art/maps_select"
  22. #define GAMESERVER_SELECTED        "menu/art/maps_selected"
  23. #define GAMESERVER_FIGHT0        "menu/art/fight_0"
  24. #define GAMESERVER_FIGHT1        "menu/art/fight_1"
  25. #define GAMESERVER_UNKNOWNMAP    "menu/art/unknownmap"
  26. #define GAMESERVER_ARROWS        "menu/art/gs_arrows_0"
  27. #define GAMESERVER_ARROWSL        "menu/art/gs_arrows_l"
  28. #define GAMESERVER_ARROWSR        "menu/art/gs_arrows_r"
  29.  
  30. #define MAX_MAPROWS        2
  31. #define MAX_MAPCOLS        2
  32. #define MAX_MAPSPERPAGE    4
  33.  
  34. #define    MAX_SERVERSTEXT    8192
  35.  
  36. #define MAX_SERVERMAPS    64
  37. #define MAX_NAMELENGTH    16
  38.  
  39. #define ID_GAMETYPE                10
  40. #define ID_PICTURES                11    // 12, 13, 14
  41. #define ID_PREVPAGE                15
  42. #define ID_NEXTPAGE                16
  43. #define ID_STARTSERVERBACK        17
  44. #define ID_STARTSERVERNEXT        18
  45.  
  46.  
  47. typedef struct {
  48.     menuframework_s    menu;
  49.  
  50.     menutext_s        banner;
  51.     menubitmap_s    framel;
  52.     menubitmap_s    framer;
  53.  
  54.     menulist_s        gametype;
  55.     menubitmap_s    mappics[MAX_MAPSPERPAGE];
  56.     menubitmap_s    mapbuttons[MAX_MAPSPERPAGE];
  57.     menubitmap_s    arrows;
  58.     menubitmap_s    prevpage;
  59.     menubitmap_s    nextpage;
  60.     menubitmap_s    back;
  61.     menubitmap_s    next;
  62.  
  63.     menutext_s        mapname;
  64.     menubitmap_s    item_null;
  65.  
  66.     qboolean        multiplayer;
  67.     int                currentmap;
  68.     int                nummaps;
  69.     int                page;
  70.     int                maxpages;
  71.     char            maplist[MAX_SERVERMAPS][MAX_NAMELENGTH];
  72.     int                mapGamebits[MAX_SERVERMAPS];
  73. } startserver_t;
  74.  
  75. static startserver_t s_startserver;
  76.  
  77. static const char *gametype_items[] = {
  78.     "Free For All",
  79.     "Team Deathmatch",
  80.     "Tournament",
  81.     "Capture the Flag",
  82.     0
  83. };
  84.  
  85. static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};
  86. static int gametype_remap2[] = {0, 2, 0, 1, 3};
  87.  
  88.  
  89. static void UI_ServerOptionsMenu( qboolean multiplayer );
  90.  
  91.  
  92. /*
  93. =================
  94. GametypeBits
  95. =================
  96. */
  97. static int GametypeBits( char *string ) {
  98.     int        bits;
  99.     char    *p;
  100.     char    *token;
  101.  
  102.     bits = 0;
  103.     p = string;
  104.     while( 1 ) {
  105.         token = COM_ParseExt( &p, qfalse );
  106.         if( token[0] == 0 ) {
  107.             break;
  108.         }
  109.  
  110.         if( Q_stricmp( token, "ffa" ) == 0 ) {
  111.             bits |= 1 << GT_FFA;
  112.             continue;
  113.         }
  114.  
  115.         if( Q_stricmp( token, "tourney" ) == 0 ) {
  116.             bits |= 1 << GT_TOURNAMENT;
  117.             continue;
  118.         }
  119.  
  120.         if( Q_stricmp( token, "single" ) == 0 ) {
  121.             bits |= 1 << GT_SINGLE_PLAYER;
  122.             continue;
  123.         }
  124.  
  125.         if( Q_stricmp( token, "team" ) == 0 ) {
  126.             bits |= 1 << GT_TEAM;
  127.             continue;
  128.         }
  129.  
  130.         if( Q_stricmp( token, "ctf" ) == 0 ) {
  131.             bits |= 1 << GT_CTF;
  132.             continue;
  133.         }
  134.     }
  135.  
  136.     return bits;
  137. }
  138.  
  139.  
  140. /*
  141. =================
  142. StartServer_Update
  143. =================
  144. */
  145. static void StartServer_Update( void ) {
  146.     int                i;
  147.     int                top;
  148.     static    char    picname[MAX_MAPSPERPAGE][64];
  149.  
  150.     top = s_startserver.page*MAX_MAPSPERPAGE;
  151.  
  152.     for (i=0; i<MAX_MAPSPERPAGE; i++)
  153.     {
  154.         if (top+i >= s_startserver.nummaps)
  155.             break;
  156.  
  157.         Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] );
  158.  
  159.         s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
  160.         s_startserver.mappics[i].generic.name   = picname[i];
  161.         s_startserver.mappics[i].shader         = 0;
  162.  
  163.         // reset
  164.         s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
  165.         s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE;
  166.     }
  167.  
  168.     for (; i<MAX_MAPSPERPAGE; i++)
  169.     {
  170.         s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
  171.         s_startserver.mappics[i].generic.name   = NULL;
  172.         s_startserver.mappics[i].shader         = 0;
  173.  
  174.         // disable
  175.         s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  176.         s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
  177.     }
  178.  
  179.     // no servers to start
  180.     if( !s_startserver.nummaps ) {
  181.         s_startserver.next.generic.flags |= QMF_INACTIVE;
  182.  
  183.         // set the map name
  184.         strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
  185.     }
  186.     else {
  187.         // set the highlight
  188.         s_startserver.next.generic.flags &= ~QMF_INACTIVE;
  189.         i = s_startserver.currentmap - top;
  190.         if ( i >=0 && i < MAX_MAPSPERPAGE ) 
  191.         {
  192.             s_startserver.mappics[i].generic.flags    |= QMF_HIGHLIGHT;
  193.             s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  194.         }
  195.  
  196.         // set the map name
  197.         strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] );
  198.     }
  199.  
  200.     Q_strupr( s_startserver.mapname.string );
  201. }
  202.  
  203.  
  204. /*
  205. =================
  206. StartServer_MapEvent
  207. =================
  208. */
  209. static void StartServer_MapEvent( void* ptr, int event ) {
  210.     if( event != QM_ACTIVATED) {
  211.         return;
  212.     }
  213.  
  214.     s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
  215.     StartServer_Update();
  216. }
  217.  
  218.  
  219. /*
  220. =================
  221. StartServer_GametypeEvent
  222. =================
  223. */
  224. static void StartServer_GametypeEvent( void* ptr, int event ) {
  225.     int            i;
  226.     int            count;
  227.     int            gamebits;
  228.     int            matchbits;
  229.     const char    *info;
  230.  
  231.     if( event != QM_ACTIVATED) {
  232.         return;
  233.     }
  234.  
  235.     count = UI_GetNumArenas();
  236.     s_startserver.nummaps = 0;
  237.     matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
  238.     if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA ) {
  239.         matchbits |= ( 1 << GT_SINGLE_PLAYER );
  240.     }
  241.     for( i = 0; i < count; i++ ) {
  242.         info = UI_GetArenaInfoByNumber( i );
  243.  
  244.         gamebits = GametypeBits( Info_ValueForKey( info, "type") );
  245.         if( !( gamebits & matchbits ) ) {
  246.             continue;
  247.         }
  248.  
  249.         Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
  250.         Q_strupr( s_startserver.maplist[s_startserver.nummaps] );
  251.         s_startserver.mapGamebits[s_startserver.nummaps] = gamebits;
  252.         s_startserver.nummaps++;
  253.     }
  254.     s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
  255.     s_startserver.page = 0;
  256.     s_startserver.currentmap = 0;
  257.  
  258.     StartServer_Update();
  259. }
  260.  
  261.  
  262. /*
  263. =================
  264. StartServer_MenuEvent
  265. =================
  266. */
  267. static void StartServer_MenuEvent( void* ptr, int event ) {
  268.     if( event != QM_ACTIVATED ) {
  269.         return;
  270.     }
  271.  
  272.     switch( ((menucommon_s*)ptr)->id ) {
  273.     case ID_PREVPAGE:
  274.         if( s_startserver.page > 0 ) {
  275.             s_startserver.page--;
  276.             StartServer_Update();
  277.         }
  278.         break;
  279.  
  280.     case ID_NEXTPAGE:
  281.         if( s_startserver.page < s_startserver.maxpages - 1 ) {
  282.             s_startserver.page++;
  283.             StartServer_Update();
  284.         }
  285.         break;
  286.  
  287.     case ID_STARTSERVERNEXT:
  288.         trap_Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
  289.         UI_ServerOptionsMenu( s_startserver.multiplayer );
  290.         break;
  291.  
  292.     case ID_STARTSERVERBACK:
  293.         UI_PopMenu();
  294.         break;
  295.     }
  296. }
  297.  
  298.  
  299. /*
  300. ===============
  301. StartServer_LevelshotDraw
  302. ===============
  303. */
  304. static void StartServer_LevelshotDraw( void *self ) {
  305.     menubitmap_s    *b;
  306.     int                x;
  307.     int                y;
  308.     int                w;
  309.     int                h;
  310.     int                n;
  311.  
  312.     b = (menubitmap_s *)self;
  313.  
  314.     if( !b->generic.name ) {
  315.         return;
  316.     }
  317.  
  318.     if( b->generic.name && !b->shader ) {
  319.         b->shader = trap_R_RegisterShaderNoMip( b->generic.name );
  320.         if( !b->shader && b->errorpic ) {
  321.             b->shader = trap_R_RegisterShaderNoMip( b->errorpic );
  322.         }
  323.     }
  324.  
  325.     if( b->focuspic && !b->focusshader ) {
  326.         b->focusshader = trap_R_RegisterShaderNoMip( b->focuspic );
  327.     }
  328.  
  329.     x = b->generic.x;
  330.     y = b->generic.y;
  331.     w = b->width;
  332.     h =    b->height;
  333.     if( b->shader ) {
  334.         UI_DrawHandlePic( x, y, w, h, b->shader );
  335.     }
  336.  
  337.     x = b->generic.x;
  338.     y = b->generic.y + b->height;
  339.     UI_FillRect( x, y, b->width, 28, colorBlack );
  340.  
  341.     x += b->width / 2;
  342.     y += 4;
  343.     n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
  344.     UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange );
  345.  
  346.     x = b->generic.x;
  347.     y = b->generic.y;
  348.     w = b->width;
  349.     h =    b->height + 28;
  350.     if( b->generic.flags & QMF_HIGHLIGHT ) {    
  351.         UI_DrawHandlePic( x, y, w, h, b->focusshader );
  352.     }
  353. }
  354.  
  355.  
  356. /*
  357. =================
  358. StartServer_MenuInit
  359. =================
  360. */
  361. static void StartServer_MenuInit( void ) {
  362.     int    i;
  363.     int    x;
  364.     int    y;
  365.     static char mapnamebuffer[64];
  366.  
  367.     // zero set all our globals
  368.     memset( &s_startserver, 0 ,sizeof(startserver_t) );
  369.  
  370.     StartServer_Cache();
  371.  
  372.     s_startserver.menu.wrapAround = qtrue;
  373.     s_startserver.menu.fullscreen = qtrue;
  374.  
  375.     s_startserver.banner.generic.type  = MTYPE_BTEXT;
  376.     s_startserver.banner.generic.x       = 320;
  377.     s_startserver.banner.generic.y       = 16;
  378.     s_startserver.banner.string        = "GAME SERVER";
  379.     s_startserver.banner.color         = color_white;
  380.     s_startserver.banner.style         = UI_CENTER;
  381.  
  382.     s_startserver.framel.generic.type  = MTYPE_BITMAP;
  383.     s_startserver.framel.generic.name  = GAMESERVER_FRAMEL;
  384.     s_startserver.framel.generic.flags = QMF_INACTIVE;
  385.     s_startserver.framel.generic.x       = 0;  
  386.     s_startserver.framel.generic.y       = 78;
  387.     s_startserver.framel.width         = 256;
  388.     s_startserver.framel.height         = 329;
  389.  
  390.     s_startserver.framer.generic.type  = MTYPE_BITMAP;
  391.     s_startserver.framer.generic.name  = GAMESERVER_FRAMER;
  392.     s_startserver.framer.generic.flags = QMF_INACTIVE;
  393.     s_startserver.framer.generic.x       = 376;
  394.     s_startserver.framer.generic.y       = 76;
  395.     s_startserver.framer.width         = 256;
  396.     s_startserver.framer.height         = 334;
  397.  
  398.     s_startserver.gametype.generic.type        = MTYPE_SPINCONTROL;
  399.     s_startserver.gametype.generic.name        = "Game Type:";
  400.     s_startserver.gametype.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  401.     s_startserver.gametype.generic.callback    = StartServer_GametypeEvent;
  402.     s_startserver.gametype.generic.id        = ID_GAMETYPE;
  403.     s_startserver.gametype.generic.x        = 320 - 24;
  404.     s_startserver.gametype.generic.y        = 368;
  405.     s_startserver.gametype.itemnames        = gametype_items;
  406.  
  407.     for (i=0; i<MAX_MAPSPERPAGE; i++)
  408.     {
  409.         x =    (i % MAX_MAPCOLS) * (128+8) + 188;
  410.         y = (i / MAX_MAPROWS) * (128+8) + 96;
  411.  
  412.         s_startserver.mappics[i].generic.type   = MTYPE_BITMAP;
  413.         s_startserver.mappics[i].generic.flags  = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  414.         s_startserver.mappics[i].generic.x        = x;
  415.         s_startserver.mappics[i].generic.y        = y;
  416.         s_startserver.mappics[i].generic.id        = ID_PICTURES+i;
  417.         s_startserver.mappics[i].width          = 128;
  418.         s_startserver.mappics[i].height          = 96;
  419.         s_startserver.mappics[i].focuspic       = GAMESERVER_SELECTED;
  420.         s_startserver.mappics[i].errorpic       = GAMESERVER_UNKNOWNMAP;
  421.         s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;
  422.  
  423.         s_startserver.mapbuttons[i].generic.type     = MTYPE_BITMAP;
  424.         s_startserver.mapbuttons[i].generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
  425.         s_startserver.mapbuttons[i].generic.id       = ID_PICTURES+i;
  426.         s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
  427.         s_startserver.mapbuttons[i].generic.x         = x - 30;
  428.         s_startserver.mapbuttons[i].generic.y         = y - 32;
  429.         s_startserver.mapbuttons[i].width               = 256;
  430.         s_startserver.mapbuttons[i].height           = 248;
  431.         s_startserver.mapbuttons[i].generic.left     = x;
  432.         s_startserver.mapbuttons[i].generic.top       = y;
  433.         s_startserver.mapbuttons[i].generic.right    = x + 128;
  434.         s_startserver.mapbuttons[i].generic.bottom   = y + 128;
  435.         s_startserver.mapbuttons[i].focuspic         = GAMESERVER_SELECT;
  436.     }
  437.  
  438.     s_startserver.arrows.generic.type  = MTYPE_BITMAP;
  439.     s_startserver.arrows.generic.name  = GAMESERVER_ARROWS;
  440.     s_startserver.arrows.generic.flags = QMF_INACTIVE;
  441.     s_startserver.arrows.generic.x       = 260;
  442.     s_startserver.arrows.generic.y       = 400;
  443.     s_startserver.arrows.width         = 128;
  444.     s_startserver.arrows.height         = 32;
  445.  
  446.     s_startserver.prevpage.generic.type        = MTYPE_BITMAP;
  447.     s_startserver.prevpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  448.     s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
  449.     s_startserver.prevpage.generic.id        = ID_PREVPAGE;
  450.     s_startserver.prevpage.generic.x        = 260;
  451.     s_startserver.prevpage.generic.y        = 400;
  452.     s_startserver.prevpage.width              = 64;
  453.     s_startserver.prevpage.height              = 32;
  454.     s_startserver.prevpage.focuspic         = GAMESERVER_ARROWSL;
  455.  
  456.     s_startserver.nextpage.generic.type        = MTYPE_BITMAP;
  457.     s_startserver.nextpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  458.     s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
  459.     s_startserver.nextpage.generic.id        = ID_NEXTPAGE;
  460.     s_startserver.nextpage.generic.x        = 321;
  461.     s_startserver.nextpage.generic.y        = 400;
  462.     s_startserver.nextpage.width              = 64;
  463.     s_startserver.nextpage.height              = 32;
  464.     s_startserver.nextpage.focuspic         = GAMESERVER_ARROWSR;
  465.  
  466.     s_startserver.mapname.generic.type  = MTYPE_PTEXT;
  467.     s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
  468.     s_startserver.mapname.generic.x        = 320;
  469.     s_startserver.mapname.generic.y        = 440;
  470.     s_startserver.mapname.string        = mapnamebuffer;
  471.     s_startserver.mapname.style         = UI_CENTER|UI_BIGFONT;
  472.     s_startserver.mapname.color         = text_color_normal;
  473.  
  474.     s_startserver.back.generic.type        = MTYPE_BITMAP;
  475.     s_startserver.back.generic.name     = GAMESERVER_BACK0;
  476.     s_startserver.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  477.     s_startserver.back.generic.callback = StartServer_MenuEvent;
  478.     s_startserver.back.generic.id        = ID_STARTSERVERBACK;
  479.     s_startserver.back.generic.x        = 0;
  480.     s_startserver.back.generic.y        = 480-64;
  481.     s_startserver.back.width              = 128;
  482.     s_startserver.back.height              = 64;
  483.     s_startserver.back.focuspic         = GAMESERVER_BACK1;
  484.  
  485.     s_startserver.next.generic.type        = MTYPE_BITMAP;
  486.     s_startserver.next.generic.name     = GAMESERVER_NEXT0;
  487.     s_startserver.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
  488.     s_startserver.next.generic.callback = StartServer_MenuEvent;
  489.     s_startserver.next.generic.id        = ID_STARTSERVERNEXT;
  490.     s_startserver.next.generic.x        = 640;
  491.     s_startserver.next.generic.y        = 480-64;
  492.     s_startserver.next.width              = 128;
  493.     s_startserver.next.height              = 64;
  494.     s_startserver.next.focuspic         = GAMESERVER_NEXT1;
  495.  
  496.     s_startserver.item_null.generic.type    = MTYPE_BITMAP;
  497.     s_startserver.item_null.generic.flags    = QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
  498.     s_startserver.item_null.generic.x        = 0;
  499.     s_startserver.item_null.generic.y        = 0;
  500.     s_startserver.item_null.width            = 640;
  501.     s_startserver.item_null.height            = 480;
  502.  
  503.     Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
  504.     Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
  505.     Menu_AddItem( &s_startserver.menu, &s_startserver.framer );
  506.  
  507.     Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
  508.     for (i=0; i<MAX_MAPSPERPAGE; i++)
  509.     {
  510.         Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
  511.         Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
  512.     }
  513.  
  514.     Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
  515.     Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
  516.     Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
  517.     Menu_AddItem( &s_startserver.menu, &s_startserver.back );
  518.     Menu_AddItem( &s_startserver.menu, &s_startserver.next );
  519.     Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
  520.     Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );
  521.  
  522.     StartServer_GametypeEvent( NULL, QM_ACTIVATED );
  523. }
  524.  
  525.  
  526. /*
  527. =================
  528. StartServer_Cache
  529. =================
  530. */
  531. void StartServer_Cache( void )
  532. {
  533.     int                i;
  534.     const char        *info;
  535.     qboolean        precache;
  536.     char            picname[64];
  537.  
  538.     trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );    
  539.     trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );    
  540.     trap_R_RegisterShaderNoMip( GAMESERVER_NEXT0 );    
  541.     trap_R_RegisterShaderNoMip( GAMESERVER_NEXT1 );    
  542.     trap_R_RegisterShaderNoMip( GAMESERVER_FRAMEL );    
  543.     trap_R_RegisterShaderNoMip( GAMESERVER_FRAMER );    
  544.     trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );    
  545.     trap_R_RegisterShaderNoMip( GAMESERVER_SELECTED );    
  546.     trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
  547.     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWS );
  548.     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSL );
  549.     trap_R_RegisterShaderNoMip( GAMESERVER_ARROWSR );
  550.  
  551.     precache = trap_Cvar_VariableValue("com_buildscript");
  552.  
  553.     s_startserver.nummaps = UI_GetNumArenas();
  554.  
  555.     for( i = 0; i < s_startserver.nummaps; i++ ) {
  556.         info = UI_GetArenaInfoByNumber( i );
  557.  
  558.         Q_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
  559.         Q_strupr( s_startserver.maplist[i] );
  560.         s_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, "type") );
  561.  
  562.         if( precache ) {
  563.             Com_sprintf( picname, sizeof(picname), "levelshots/%s", s_startserver.maplist[i] );
  564.             trap_R_RegisterShaderNoMip(picname);
  565.         }
  566.     }
  567.  
  568.     s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
  569. }
  570.  
  571.  
  572. /*
  573. =================
  574. UI_StartServerMenu
  575. =================
  576. */
  577. void UI_StartServerMenu( qboolean multiplayer ) {
  578.     StartServer_MenuInit();
  579.     s_startserver.multiplayer = multiplayer;
  580.     UI_PushMenu( &s_startserver.menu );
  581. }
  582.  
  583.  
  584.  
  585. /*
  586. =============================================================================
  587.  
  588. SERVER OPTIONS MENU *****
  589.  
  590. =============================================================================
  591. */
  592.  
  593. #define ID_PLAYER_TYPE            10
  594. #define ID_MAXCLIENTS            11
  595. #define ID_DEDICATED            12
  596. #define ID_GO                    13
  597. #define ID_BACK                    14
  598.  
  599. #define PLAYER_SLOTS            12
  600.  
  601.  
  602. typedef struct {
  603.     menuframework_s        menu;
  604.  
  605.     menutext_s            banner;
  606.  
  607.     menubitmap_s        mappic;
  608.     menubitmap_s        picframe;
  609.  
  610.     menulist_s            dedicated;
  611.     menufield_s            timelimit;
  612.     menufield_s            fraglimit;
  613.     menufield_s            flaglimit;
  614.     menuradiobutton_s    friendlyfire;
  615.     menufield_s            hostname;
  616.     menuradiobutton_s    pure;
  617.     menulist_s            botSkill;
  618.  
  619.     menutext_s            player0;
  620.     menulist_s            playerType[PLAYER_SLOTS];
  621.     menutext_s            playerName[PLAYER_SLOTS];
  622.     menulist_s            playerTeam[PLAYER_SLOTS];
  623.  
  624.     menubitmap_s        go;
  625.     menubitmap_s        back;
  626.  
  627.     qboolean            multiplayer;
  628.     int                    gametype;
  629.     char                mapnamebuffer[32];
  630.     char                playerNameBuffers[PLAYER_SLOTS][16];
  631.  
  632.     qboolean            newBot;
  633.     int                    newBotIndex;
  634.     char                newBotName[16];
  635. } serveroptions_t;
  636.  
  637. static serveroptions_t s_serveroptions;
  638.  
  639. static const char *dedicated_list[] = {
  640.     "No",
  641.     "LAN",
  642.     "Internet",
  643.     0
  644. };
  645.  
  646. static const char *playerType_list[] = {
  647.     "Open",
  648.     "Bot",
  649.     "----",
  650.     0
  651. };
  652.  
  653. static const char *playerTeam_list[] = {
  654.     "Blue",
  655.     "Red",
  656.     0
  657. };
  658.  
  659. static const char *botSkill_list[] = {
  660.     "I Can Win",
  661.     "Bring It On",
  662.     "Hurt Me Plenty",
  663.     "Hardcore",
  664.     "Nightmare!",
  665.     0
  666. };
  667.  
  668.  
  669. /*
  670. =================
  671. BotAlreadySelected
  672. =================
  673. */
  674. static qboolean BotAlreadySelected( const char *checkName ) {
  675.     int        n;
  676.  
  677.     for( n = 1; n < PLAYER_SLOTS; n++ ) {
  678.         if( s_serveroptions.playerType[n].curvalue != 1 ) {
  679.             continue;
  680.         }
  681.         if( (s_serveroptions.gametype >= GT_TEAM) &&
  682.             (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) ) {
  683.             continue;
  684.         }
  685.         if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 ) {
  686.             return qtrue;
  687.         }
  688.     }
  689.  
  690.     return qfalse;
  691. }
  692.  
  693.  
  694. /*
  695. =================
  696. ServerOptions_Start
  697. =================
  698. */
  699. static void ServerOptions_Start( void ) {
  700.     int        timelimit;
  701.     int        fraglimit;
  702.     int        maxclients;
  703.     int        dedicated;
  704.     int        friendlyfire;
  705.     int        flaglimit;
  706.     int        pure;
  707.     int        skill;
  708.     int        n;
  709.     char    buf[64];
  710.  
  711.     timelimit     = atoi( s_serveroptions.timelimit.field.buffer );
  712.     fraglimit     = atoi( s_serveroptions.fraglimit.field.buffer );
  713.     flaglimit     = atoi( s_serveroptions.flaglimit.field.buffer );
  714.     dedicated     = s_serveroptions.dedicated.curvalue;
  715.     friendlyfire = s_serveroptions.friendlyfire.curvalue;
  716.     pure         = s_serveroptions.pure.curvalue;
  717.     skill         = s_serveroptions.botSkill.curvalue + 1;
  718.  
  719.     //set maxclients
  720.     for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ ) {
  721.         if( s_serveroptions.playerType[n].curvalue == 2 ) {
  722.             continue;
  723.         }
  724.         if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) ) {
  725.             continue;
  726.         }
  727.         maxclients++;
  728.     }
  729.  
  730.     switch( s_serveroptions.gametype ) {
  731.     case GT_FFA:
  732.     default:
  733.         trap_Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
  734.         trap_Cvar_SetValue( "ui_ffa_timelimit", timelimit );
  735.         break;
  736.  
  737.     case GT_TOURNAMENT:
  738.         trap_Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
  739.         trap_Cvar_SetValue( "ui_tourney_timelimit", timelimit );
  740.         break;
  741.  
  742.     case GT_TEAM:
  743.         trap_Cvar_SetValue( "ui_team_fraglimit", fraglimit );
  744.         trap_Cvar_SetValue( "ui_team_timelimit", timelimit );
  745.         trap_Cvar_SetValue( "ui_team_friendlt", friendlyfire );
  746.         break;
  747.  
  748.     case GT_CTF:
  749.         trap_Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
  750.         trap_Cvar_SetValue( "ui_ctf_timelimit", timelimit );
  751.         trap_Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
  752.         break;
  753.     }
  754.  
  755.     trap_Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
  756.     trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
  757.     trap_Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
  758.     trap_Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
  759.     trap_Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
  760.     trap_Cvar_SetValue( "g_friendlyfire", friendlyfire );
  761.     trap_Cvar_SetValue( "sv_pure", pure );
  762.     trap_Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );
  763.  
  764.     // the wait commands will allow the dedicated to take effect
  765.     trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) );
  766.  
  767.     // add bots
  768.     trap_Cmd_ExecuteText( EXEC_APPEND, "wait 3\n" );
  769.     for( n = 1; n < PLAYER_SLOTS; n++ ) {
  770.         if( s_serveroptions.playerType[n].curvalue != 1 ) {
  771.             continue;
  772.         }
  773.         if( s_serveroptions.playerNameBuffers[n][0] == 0 ) {
  774.             continue;
  775.         }
  776.         if( s_serveroptions.playerNameBuffers[n][0] == '-' ) {
  777.             continue;
  778.         }
  779.         if( s_serveroptions.gametype >= GT_TEAM ) {
  780.             Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
  781.                 playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
  782.         }
  783.         else {
  784.             Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
  785.         }
  786.         trap_Cmd_ExecuteText( EXEC_APPEND, buf );
  787.     }
  788.  
  789.     // set player's team
  790.     if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM ) {
  791.         trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
  792.     }
  793. }
  794.  
  795.  
  796. /*
  797. =================
  798. ServerOptions_InitPlayerItems
  799. =================
  800. */
  801. static void ServerOptions_InitPlayerItems( void ) {
  802.     int        n;
  803.     int        v;
  804.  
  805.     // init types
  806.     if( s_serveroptions.multiplayer ) {
  807.         v = 0;    // open
  808.     }
  809.     else {
  810.         v = 1;    // bot
  811.     }
  812.     
  813.     for( n = 0; n < PLAYER_SLOTS; n++ ) {
  814.         s_serveroptions.playerType[n].curvalue = v;
  815.     }
  816.  
  817.     if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) ) {
  818.         for( n = 8; n < PLAYER_SLOTS; n++ ) {
  819.             s_serveroptions.playerType[n].curvalue = 2;
  820.         }
  821.     }
  822.  
  823.     // if not a dedicated server, first slot is reserved for the human on the server
  824.     if( s_serveroptions.dedicated.curvalue == 0 ) {
  825.         // human
  826.         s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
  827.         s_serveroptions.playerType[0].curvalue = 0;
  828.         trap_Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
  829.         Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
  830.     }
  831.  
  832.     // init teams
  833.     if( s_serveroptions.gametype >= GT_TEAM ) {
  834.         for( n = 0; n < (PLAYER_SLOTS / 2); n++ ) {
  835.             s_serveroptions.playerTeam[n].curvalue = 0;
  836.         }
  837.         for( ; n < PLAYER_SLOTS; n++ ) {
  838.             s_serveroptions.playerTeam[n].curvalue = 1;
  839.         }
  840.     }
  841.     else {
  842.         for( n = 0; n < PLAYER_SLOTS; n++ ) {
  843.             s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
  844.         }
  845.     }
  846. }
  847.  
  848.  
  849. /*
  850. =================
  851. ServerOptions_SetPlayerItems
  852. =================
  853. */
  854. static void ServerOptions_SetPlayerItems( void ) {
  855.     int        start;
  856.     int        n;
  857.  
  858.     // types
  859. //    for( n = 0; n < PLAYER_SLOTS; n++ ) {
  860. //        if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
  861. //            s_serveroptions.playerType[n].curvalue = 1;
  862. //        }
  863. //    }
  864.  
  865.     // names
  866.     if( s_serveroptions.dedicated.curvalue == 0 ) {
  867.         s_serveroptions.player0.string = "Human";
  868.         s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN;
  869.  
  870.         start = 1;
  871.     }
  872.     else {
  873.         s_serveroptions.player0.string = "Open";
  874.         start = 0;
  875.     }
  876.     for( n = start; n < PLAYER_SLOTS; n++ ) {
  877.         if( s_serveroptions.playerType[n].curvalue == 1 ) {
  878.             s_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
  879.         }
  880.         else {
  881.             s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
  882.         }
  883.     }
  884.  
  885.     // teams
  886.     if( s_serveroptions.gametype < GT_TEAM ) {
  887.         return;
  888.     }
  889.     for( n = start; n < PLAYER_SLOTS; n++ ) {
  890.         if( s_serveroptions.playerType[n].curvalue == 2 ) {
  891.             s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
  892.         }
  893.         else {
  894.             s_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
  895.         }
  896.     }
  897. }
  898.  
  899.  
  900. /*
  901. =================
  902. ServerOptions_Event
  903. =================
  904. */
  905. static void ServerOptions_Event( void* ptr, int event ) {
  906.     switch( ((menucommon_s*)ptr)->id ) {
  907.     case ID_PLAYER_TYPE:
  908.         if( event != QM_ACTIVATED ) {
  909.             break;
  910.         }
  911.         ServerOptions_SetPlayerItems();
  912.         break;
  913.  
  914.     case ID_MAXCLIENTS:
  915.     case ID_DEDICATED:
  916.         ServerOptions_SetPlayerItems();
  917.         break;
  918.  
  919.     case ID_GO:
  920.         if( event != QM_ACTIVATED ) {
  921.             break;
  922.         }
  923.         ServerOptions_Start();
  924.         break;
  925.  
  926.     case ID_BACK:
  927.         if( event != QM_ACTIVATED ) {
  928.             break;
  929.         }
  930.         UI_PopMenu();
  931.         break;
  932.     }
  933. }
  934.  
  935.  
  936. static void ServerOptions_PlayerNameEvent( void* ptr, int event ) {
  937.     int        n;
  938.  
  939.     if( event != QM_ACTIVATED ) {
  940.         return;
  941.     }
  942.     n = ((menutext_s*)ptr)->generic.id;
  943.     s_serveroptions.newBotIndex = n;
  944.     UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
  945. }
  946.  
  947.  
  948. /*
  949. =================
  950. ServerOptions_StatusBar
  951. =================
  952. */
  953. static void ServerOptions_StatusBar( void* ptr ) {
  954.     UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
  955. }
  956.  
  957.  
  958. /*
  959. ===============
  960. ServerOptions_LevelshotDraw
  961. ===============
  962. */
  963. static void ServerOptions_LevelshotDraw( void *self ) {
  964.     menubitmap_s    *b;
  965.     int                x;
  966.     int                y;
  967.  
  968.     // strange place for this, but it works
  969.     if( s_serveroptions.newBot ) {
  970.         Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
  971.         s_serveroptions.newBot = qfalse;
  972.     }
  973.  
  974.     b = (menubitmap_s *)self;
  975.  
  976.     Bitmap_Draw( b );
  977.  
  978.     x = b->generic.x;
  979.     y = b->generic.y + b->height;
  980.     UI_FillRect( x, y, b->width, 40, colorBlack );
  981.  
  982.     x += b->width / 2;
  983.     y += 4;
  984.     UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );
  985.  
  986.     y += SMALLCHAR_HEIGHT;
  987.     UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
  988. }
  989.  
  990.  
  991. static void ServerOptions_InitBotNames( void ) {
  992.     int            count;
  993.     int            n;
  994.     const char    *arenaInfo;
  995.     const char    *botInfo;
  996.     char        *p;
  997.     char        *bot;
  998.     char        bots[MAX_INFO_STRING];
  999.  
  1000.     if( s_serveroptions.gametype >= GT_TEAM ) {
  1001.         Q_strncpyz( s_serveroptions.playerNameBuffers[1], "grunt", 16 );
  1002.         Q_strncpyz( s_serveroptions.playerNameBuffers[2], "major", 16 );
  1003.         if( s_serveroptions.gametype == GT_TEAM ) {
  1004.             Q_strncpyz( s_serveroptions.playerNameBuffers[3], "visor", 16 );
  1005.         }
  1006.         else {
  1007.             s_serveroptions.playerType[3].curvalue = 2;
  1008.         }
  1009.         s_serveroptions.playerType[4].curvalue = 2;
  1010.         s_serveroptions.playerType[5].curvalue = 2;
  1011.  
  1012.         Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sarge", 16 );
  1013.         Q_strncpyz( s_serveroptions.playerNameBuffers[7], "grunt", 16 );
  1014.         Q_strncpyz( s_serveroptions.playerNameBuffers[8], "major", 16 );
  1015.         if( s_serveroptions.gametype == GT_TEAM ) {
  1016.             Q_strncpyz( s_serveroptions.playerNameBuffers[9], "visor", 16 );
  1017.         }
  1018.         else {
  1019.             s_serveroptions.playerType[9].curvalue = 2;
  1020.         }
  1021.         s_serveroptions.playerType[10].curvalue = 2;
  1022.         s_serveroptions.playerType[11].curvalue = 2;
  1023.  
  1024.         return;
  1025.     }
  1026.  
  1027.     count = 1;    // skip the first slot, reserved for a human
  1028.  
  1029.     // get info for this map
  1030.     arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );
  1031.  
  1032.     // get the bot info - we'll seed with them if any are listed
  1033.     Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
  1034.     p = &bots[0];
  1035.     while( *p && count < PLAYER_SLOTS ) {
  1036.         //skip spaces
  1037.         while( *p && *p == ' ' ) {
  1038.             p++;
  1039.         }
  1040.         if( !p ) {
  1041.             break;
  1042.         }
  1043.  
  1044.         // mark start of bot name
  1045.         bot = p;
  1046.  
  1047.         // skip until space of null
  1048.         while( *p && *p != ' ' ) {
  1049.             p++;
  1050.         }
  1051.         if( *p ) {
  1052.             *p++ = 0;
  1053.         }
  1054.  
  1055.         botInfo = UI_GetBotInfoByName( bot );
  1056.         bot = Info_ValueForKey( botInfo, "name" );
  1057.  
  1058.         Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
  1059.         count++;
  1060.     }
  1061.  
  1062.     // set the rest of the bot slots to "---"
  1063.     for( n = count; n < PLAYER_SLOTS; n++ ) {
  1064.         strcpy( s_serveroptions.playerNameBuffers[n], "--------" );
  1065.     }
  1066.  
  1067.     // pad up to #8 as open slots
  1068.     for( ;count < 8; count++ ) {
  1069.         s_serveroptions.playerType[count].curvalue = 0;
  1070.     }
  1071.  
  1072.     // close off the rest by default
  1073.     for( ;count < PLAYER_SLOTS; count++ ) {
  1074.         if( s_serveroptions.playerType[count].curvalue == 1 ) {
  1075.             s_serveroptions.playerType[count].curvalue = 2;
  1076.         }
  1077.     }
  1078. }
  1079.  
  1080.  
  1081. /*
  1082. =================
  1083. ServerOptions_SetMenuItems
  1084. =================
  1085. */
  1086. static void ServerOptions_SetMenuItems( void ) {
  1087.     static char picname[64];
  1088.  
  1089.     switch( s_serveroptions.gametype ) {
  1090.     case GT_FFA:
  1091.     default:
  1092.         Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
  1093.         Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
  1094.         break;
  1095.  
  1096.     case GT_TOURNAMENT:
  1097.         Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
  1098.         Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
  1099.         break;
  1100.  
  1101.     case GT_TEAM:
  1102.         Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_fraglimit" ) ) );
  1103.         Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_team_timelimit" ) ) );
  1104.         s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_team_friendly" ) );
  1105.         break;
  1106.  
  1107.     case GT_CTF:
  1108.         Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, trap_Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
  1109.         Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, trap_Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
  1110.         s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, trap_Cvar_VariableValue( "ui_ctf_friendly" ) );
  1111.         break;
  1112.     }
  1113.  
  1114.     Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
  1115.     s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, trap_Cvar_VariableValue( "sv_pure" ) );
  1116.  
  1117.  
  1118.     // set the map pic
  1119.     Com_sprintf( picname, 64, "levelshots/%s", s_startserver.maplist[s_startserver.currentmap] );
  1120.     s_serveroptions.mappic.generic.name = picname;
  1121.  
  1122.     // set the map name
  1123.     strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
  1124.     Q_strupr( s_serveroptions.mapnamebuffer );
  1125.  
  1126.     // get the player selections initialized
  1127.     ServerOptions_InitPlayerItems();
  1128.     ServerOptions_SetPlayerItems();
  1129.  
  1130.     // seed bot names
  1131.     ServerOptions_InitBotNames();
  1132.     ServerOptions_SetPlayerItems();
  1133. }
  1134.  
  1135. /*
  1136. =================
  1137. PlayerName_Draw
  1138. =================
  1139. */
  1140. static void PlayerName_Draw( void *item ) {
  1141.     menutext_s    *s;
  1142.     float        *color;
  1143.     int            x, y;
  1144.     int            style;
  1145.     qboolean    focus;
  1146.  
  1147.     s = (menutext_s *)item;
  1148.  
  1149.     x = s->generic.x;
  1150.     y =    s->generic.y;
  1151.  
  1152.     style = UI_SMALLFONT;
  1153.     focus = (s->generic.parent->cursor == s->generic.menuPosition);
  1154.  
  1155.     if ( s->generic.flags & QMF_GRAYED )
  1156.         color = text_color_disabled;
  1157.     else if ( focus )
  1158.     {
  1159.         color = text_color_highlight;
  1160.         style |= UI_PULSE;
  1161.     }
  1162.     else if ( s->generic.flags & QMF_BLINK )
  1163.     {
  1164.         color = text_color_highlight;
  1165.         style |= UI_BLINK;
  1166.     }
  1167.     else
  1168.         color = text_color_normal;
  1169.  
  1170.     if ( focus )
  1171.     {
  1172.         // draw cursor
  1173.         UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color ); 
  1174.         UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
  1175.     }
  1176.  
  1177.     UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
  1178.     UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
  1179. }
  1180.  
  1181.  
  1182. /*
  1183. =================
  1184. ServerOptions_MenuInit
  1185. =================
  1186. */
  1187. #define OPTIONS_X    456
  1188.  
  1189. static void ServerOptions_MenuInit( qboolean multiplayer ) {
  1190.     int        y;
  1191.     int        n;
  1192.  
  1193.     memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
  1194.     s_serveroptions.multiplayer = multiplayer;
  1195.     s_serveroptions.gametype = (int)Com_Clamp( 0, 5, trap_Cvar_VariableValue( "g_gameType" ) );
  1196.  
  1197.     ServerOptions_Cache();
  1198.  
  1199.     s_serveroptions.menu.wrapAround = qtrue;
  1200.     s_serveroptions.menu.fullscreen = qtrue;
  1201.  
  1202.     s_serveroptions.banner.generic.type            = MTYPE_BTEXT;
  1203.     s_serveroptions.banner.generic.x            = 320;
  1204.     s_serveroptions.banner.generic.y            = 16;
  1205.     s_serveroptions.banner.string                  = "GAME SERVER";
  1206.     s_serveroptions.banner.color                  = color_white;
  1207.     s_serveroptions.banner.style                  = UI_CENTER;
  1208.  
  1209.     s_serveroptions.mappic.generic.type            = MTYPE_BITMAP;
  1210.     s_serveroptions.mappic.generic.flags        = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  1211.     s_serveroptions.mappic.generic.x            = 352;
  1212.     s_serveroptions.mappic.generic.y            = 80;
  1213.     s_serveroptions.mappic.width                = 160;
  1214.     s_serveroptions.mappic.height                = 120;
  1215.     s_serveroptions.mappic.errorpic                = GAMESERVER_UNKNOWNMAP;
  1216.     s_serveroptions.mappic.generic.ownerdraw    = ServerOptions_LevelshotDraw;
  1217.  
  1218.     s_serveroptions.picframe.generic.type        = MTYPE_BITMAP;
  1219.     s_serveroptions.picframe.generic.flags        = QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
  1220.     s_serveroptions.picframe.generic.x            = 352 - 38;
  1221.     s_serveroptions.picframe.generic.y            = 80 - 40;
  1222.     s_serveroptions.picframe.width              = 320;
  1223.     s_serveroptions.picframe.height              = 320;
  1224.     s_serveroptions.picframe.focuspic            = GAMESERVER_SELECT;
  1225.  
  1226.     y = 272;
  1227.     if( s_serveroptions.gametype != GT_CTF ) {
  1228.         s_serveroptions.fraglimit.generic.type       = MTYPE_FIELD;
  1229.         s_serveroptions.fraglimit.generic.name       = "Frag Limit:";
  1230.         s_serveroptions.fraglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1231.         s_serveroptions.fraglimit.generic.x             = OPTIONS_X;
  1232.         s_serveroptions.fraglimit.generic.y             = y;
  1233.         s_serveroptions.fraglimit.generic.statusbar  = ServerOptions_StatusBar;
  1234.         s_serveroptions.fraglimit.field.widthInChars = 3;
  1235.         s_serveroptions.fraglimit.field.maxchars     = 3;
  1236.     }
  1237.     else {
  1238.         s_serveroptions.flaglimit.generic.type       = MTYPE_FIELD;
  1239.         s_serveroptions.flaglimit.generic.name       = "Capture Limit:";
  1240.         s_serveroptions.flaglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1241.         s_serveroptions.flaglimit.generic.x             = OPTIONS_X;
  1242.         s_serveroptions.flaglimit.generic.y             = y;
  1243.         s_serveroptions.flaglimit.generic.statusbar  = ServerOptions_StatusBar;
  1244.         s_serveroptions.flaglimit.field.widthInChars = 3;
  1245.         s_serveroptions.flaglimit.field.maxchars     = 3;
  1246.     }
  1247.  
  1248.     y += BIGCHAR_HEIGHT+2;
  1249.     s_serveroptions.timelimit.generic.type       = MTYPE_FIELD;
  1250.     s_serveroptions.timelimit.generic.name       = "Time Limit:";
  1251.     s_serveroptions.timelimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1252.     s_serveroptions.timelimit.generic.x             = OPTIONS_X;
  1253.     s_serveroptions.timelimit.generic.y             = y;
  1254.     s_serveroptions.timelimit.generic.statusbar  = ServerOptions_StatusBar;
  1255.     s_serveroptions.timelimit.field.widthInChars = 3;
  1256.     s_serveroptions.timelimit.field.maxchars     = 3;
  1257.  
  1258.     if( s_serveroptions.gametype >= GT_TEAM ) {
  1259.         y += BIGCHAR_HEIGHT+2;
  1260.         s_serveroptions.friendlyfire.generic.type     = MTYPE_RADIOBUTTON;
  1261.         s_serveroptions.friendlyfire.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1262.         s_serveroptions.friendlyfire.generic.x          = OPTIONS_X;
  1263.         s_serveroptions.friendlyfire.generic.y          = y;
  1264.         s_serveroptions.friendlyfire.generic.name      = "Friendly Fire:";
  1265.     }
  1266.  
  1267.     y += BIGCHAR_HEIGHT+2;
  1268.     s_serveroptions.pure.generic.type            = MTYPE_RADIOBUTTON;
  1269.     s_serveroptions.pure.generic.flags            = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1270.     s_serveroptions.pure.generic.x                = OPTIONS_X;
  1271.     s_serveroptions.pure.generic.y                = y;
  1272.     s_serveroptions.pure.generic.name            = "Pure Server:";
  1273.  
  1274.     if( s_serveroptions.multiplayer ) {
  1275.         y += BIGCHAR_HEIGHT+2;
  1276.         s_serveroptions.dedicated.generic.type        = MTYPE_SPINCONTROL;
  1277.         s_serveroptions.dedicated.generic.id        = ID_DEDICATED;
  1278.         s_serveroptions.dedicated.generic.flags        = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1279.         s_serveroptions.dedicated.generic.callback    = ServerOptions_Event;
  1280.         s_serveroptions.dedicated.generic.x            = OPTIONS_X;
  1281.         s_serveroptions.dedicated.generic.y            = y;
  1282.         s_serveroptions.dedicated.generic.name        = "Dedicated:";
  1283.         s_serveroptions.dedicated.itemnames            = dedicated_list;
  1284.     }
  1285.  
  1286.     if( s_serveroptions.multiplayer ) {
  1287.         y += BIGCHAR_HEIGHT+2;
  1288.         s_serveroptions.hostname.generic.type       = MTYPE_FIELD;
  1289.         s_serveroptions.hostname.generic.name       = "Hostname:";
  1290.         s_serveroptions.hostname.generic.flags      = QMF_SMALLFONT;
  1291.         s_serveroptions.hostname.generic.x          = OPTIONS_X;
  1292.         s_serveroptions.hostname.generic.y            = y;
  1293.         s_serveroptions.hostname.field.widthInChars = 18;
  1294.         s_serveroptions.hostname.field.maxchars     = 64;
  1295.     }
  1296.  
  1297.     y = 80;
  1298.     s_serveroptions.botSkill.generic.type            = MTYPE_SPINCONTROL;
  1299.     s_serveroptions.botSkill.generic.flags            = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
  1300.     s_serveroptions.botSkill.generic.name            = "Bot Skill:  ";
  1301.     s_serveroptions.botSkill.generic.x                = 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
  1302.     s_serveroptions.botSkill.generic.y                = y;
  1303.     s_serveroptions.botSkill.itemnames                = botSkill_list;
  1304.     s_serveroptions.botSkill.curvalue                = 1;
  1305.  
  1306.     y += ( 2 * SMALLCHAR_HEIGHT );
  1307.     s_serveroptions.player0.generic.type            = MTYPE_TEXT;
  1308.     s_serveroptions.player0.generic.flags            = QMF_SMALLFONT;
  1309.     s_serveroptions.player0.generic.x                = 32 + SMALLCHAR_WIDTH;
  1310.     s_serveroptions.player0.generic.y                = y;
  1311.     s_serveroptions.player0.color                    = color_orange;
  1312.     s_serveroptions.player0.style                    = UI_LEFT|UI_SMALLFONT;
  1313.  
  1314.     for( n = 0; n < PLAYER_SLOTS; n++ ) {
  1315.         s_serveroptions.playerType[n].generic.type        = MTYPE_SPINCONTROL;
  1316.         s_serveroptions.playerType[n].generic.flags        = QMF_SMALLFONT;
  1317.         s_serveroptions.playerType[n].generic.id        = ID_PLAYER_TYPE;
  1318.         s_serveroptions.playerType[n].generic.callback    = ServerOptions_Event;
  1319.         s_serveroptions.playerType[n].generic.x            = 32;
  1320.         s_serveroptions.playerType[n].generic.y            = y;
  1321.         s_serveroptions.playerType[n].itemnames            = playerType_list;
  1322.  
  1323.         s_serveroptions.playerName[n].generic.type        = MTYPE_TEXT;
  1324.         s_serveroptions.playerName[n].generic.flags        = QMF_SMALLFONT;
  1325.         s_serveroptions.playerName[n].generic.x            = 96;
  1326.         s_serveroptions.playerName[n].generic.y            = y;
  1327.         s_serveroptions.playerName[n].generic.callback    = ServerOptions_PlayerNameEvent;
  1328.         s_serveroptions.playerName[n].generic.id        = n;
  1329.         s_serveroptions.playerName[n].generic.ownerdraw    = PlayerName_Draw;
  1330.         s_serveroptions.playerName[n].color                = color_orange;
  1331.         s_serveroptions.playerName[n].style                = UI_SMALLFONT;
  1332.         s_serveroptions.playerName[n].string            = s_serveroptions.playerNameBuffers[n];
  1333.         s_serveroptions.playerName[n].generic.top        = s_serveroptions.playerName[n].generic.y;
  1334.         s_serveroptions.playerName[n].generic.bottom    = s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
  1335.         s_serveroptions.playerName[n].generic.left        = s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
  1336.         s_serveroptions.playerName[n].generic.right        = s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;
  1337.  
  1338.         s_serveroptions.playerTeam[n].generic.type        = MTYPE_SPINCONTROL;
  1339.         s_serveroptions.playerTeam[n].generic.flags        = QMF_SMALLFONT;
  1340.         s_serveroptions.playerTeam[n].generic.x            = 240;
  1341.         s_serveroptions.playerTeam[n].generic.y            = y;
  1342.         s_serveroptions.playerTeam[n].itemnames            = playerTeam_list;
  1343.  
  1344.         y += ( SMALLCHAR_HEIGHT + 4 );
  1345.     }
  1346.  
  1347.     s_serveroptions.back.generic.type      = MTYPE_BITMAP;
  1348.     s_serveroptions.back.generic.name     = GAMESERVER_BACK0;
  1349.     s_serveroptions.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  1350.     s_serveroptions.back.generic.callback = ServerOptions_Event;
  1351.     s_serveroptions.back.generic.id          = ID_BACK;
  1352.     s_serveroptions.back.generic.x          = 0;
  1353.     s_serveroptions.back.generic.y          = 480-64;
  1354.     s_serveroptions.back.width            = 128;
  1355.     s_serveroptions.back.height            = 64;
  1356.     s_serveroptions.back.focuspic         = GAMESERVER_BACK1;
  1357.  
  1358.     s_serveroptions.go.generic.type        = MTYPE_BITMAP;
  1359.     s_serveroptions.go.generic.name     = GAMESERVER_FIGHT0;
  1360.     s_serveroptions.go.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
  1361.     s_serveroptions.go.generic.callback = ServerOptions_Event;
  1362.     s_serveroptions.go.generic.id        = ID_GO;
  1363.     s_serveroptions.go.generic.x        = 640;
  1364.     s_serveroptions.go.generic.y        = 480-64;
  1365.     s_serveroptions.go.width              = 128;
  1366.     s_serveroptions.go.height              = 64;
  1367.     s_serveroptions.go.focuspic         = GAMESERVER_FIGHT1;
  1368.  
  1369.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );
  1370.  
  1371.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
  1372.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );
  1373.  
  1374.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
  1375.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
  1376.     for( n = 0; n < PLAYER_SLOTS; n++ ) {
  1377.         if( n != 0 ) {
  1378.             Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
  1379.         }
  1380.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
  1381.         if( s_serveroptions.gametype >= GT_TEAM ) {
  1382.             Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
  1383.         }
  1384.     }
  1385.  
  1386.     if( s_serveroptions.gametype != GT_CTF ) {
  1387.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
  1388.     }
  1389.     else {
  1390.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
  1391.     }
  1392.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
  1393.     if( s_serveroptions.gametype >= GT_TEAM ) {
  1394.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
  1395.     }
  1396.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
  1397.     if( s_serveroptions.multiplayer ) {
  1398.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated );
  1399.     }
  1400.     if( s_serveroptions.multiplayer ) {
  1401.         Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
  1402.     }
  1403.  
  1404.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
  1405.     Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );
  1406.  
  1407.     ServerOptions_SetMenuItems();
  1408. }
  1409.  
  1410. /*
  1411. =================
  1412. ServerOptions_Cache
  1413. =================
  1414. */
  1415. void ServerOptions_Cache( void ) {
  1416.     trap_R_RegisterShaderNoMip( GAMESERVER_BACK0 );
  1417.     trap_R_RegisterShaderNoMip( GAMESERVER_BACK1 );
  1418.     trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
  1419.     trap_R_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
  1420.     trap_R_RegisterShaderNoMip( GAMESERVER_SELECT );
  1421.     trap_R_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
  1422. }
  1423.  
  1424.  
  1425. /*
  1426. =================
  1427. UI_ServerOptionsMenu
  1428. =================
  1429. */
  1430. static void UI_ServerOptionsMenu( qboolean multiplayer ) {
  1431.     ServerOptions_MenuInit( multiplayer );
  1432.     UI_PushMenu( &s_serveroptions.menu );
  1433. }
  1434.  
  1435.  
  1436.  
  1437. /*
  1438. =============================================================================
  1439.  
  1440. BOT SELECT MENU *****
  1441.  
  1442. =============================================================================
  1443. */
  1444.  
  1445.  
  1446. #define BOTSELECT_BACK0            "menu/art/back_0"
  1447. #define BOTSELECT_BACK1            "menu/art/back_1"
  1448. #define BOTSELECT_ACCEPT0        "menu/art/accept_0"
  1449. #define BOTSELECT_ACCEPT1        "menu/art/accept_1"
  1450. #define BOTSELECT_SELECT        "menu/art/opponents_select"
  1451. #define BOTSELECT_SELECTED        "menu/art/opponents_selected"
  1452. #define BOTSELECT_ARROWS        "menu/art/gs_arrows_0"
  1453. #define BOTSELECT_ARROWSL        "menu/art/gs_arrows_l"
  1454. #define BOTSELECT_ARROWSR        "menu/art/gs_arrows_r"
  1455.  
  1456. #define PLAYERGRID_COLS            4
  1457. #define PLAYERGRID_ROWS            4
  1458. #define MAX_MODELSPERPAGE        (PLAYERGRID_ROWS * PLAYERGRID_COLS)
  1459.  
  1460.  
  1461. typedef struct {
  1462.     menuframework_s    menu;
  1463.  
  1464.     menutext_s        banner;
  1465.  
  1466.     menubitmap_s    pics[MAX_MODELSPERPAGE];
  1467.     menubitmap_s    picbuttons[MAX_MODELSPERPAGE];
  1468.     menutext_s        picnames[MAX_MODELSPERPAGE];
  1469.  
  1470.     menubitmap_s    arrows;
  1471.     menubitmap_s    left;
  1472.     menubitmap_s    right;
  1473.  
  1474.     menubitmap_s    go;
  1475.     menubitmap_s    back;
  1476.  
  1477.     int                numBots;
  1478.     int                modelpage;
  1479.     int                numpages;
  1480.     int                selectedmodel;
  1481.     int                sortedBotNums[MAX_BOTS];
  1482.     char            boticons[MAX_MODELSPERPAGE][MAX_QPATH];
  1483.     char            botnames[MAX_MODELSPERPAGE][16];
  1484. } botSelectInfo_t;
  1485.  
  1486. static botSelectInfo_t    botSelectInfo;
  1487.  
  1488.  
  1489. /*
  1490. =================
  1491. UI_BotSelectMenu_SortCompare
  1492. =================
  1493. */
  1494. static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 ) {
  1495.     int            num1, num2;
  1496.     const char    *info1, *info2;
  1497.     const char    *name1, *name2;
  1498.  
  1499.     num1 = *(int *)arg1;
  1500.     num2 = *(int *)arg2;
  1501.  
  1502.     info1 = UI_GetBotInfoByNumber( num1 );
  1503.     info2 = UI_GetBotInfoByNumber( num2 );
  1504.  
  1505.     name1 = Info_ValueForKey( info1, "name" );
  1506.     name2 = Info_ValueForKey( info2, "name" );
  1507.  
  1508.     return Q_stricmp( name1, name2 );
  1509. }
  1510.  
  1511.  
  1512. /*
  1513. =================
  1514. UI_BotSelectMenu_BuildList
  1515. =================
  1516. */
  1517. static void UI_BotSelectMenu_BuildList( void ) {
  1518.     int        n;
  1519.  
  1520.     botSelectInfo.modelpage = 0;
  1521.     botSelectInfo.numBots = UI_GetNumBots();
  1522.     botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
  1523.     if( botSelectInfo.numBots % MAX_MODELSPERPAGE ) {
  1524.         botSelectInfo.numpages++;
  1525.     }
  1526.  
  1527.     // initialize the array
  1528.     for( n = 0; n < botSelectInfo.numBots; n++ ) {
  1529.         botSelectInfo.sortedBotNums[n] = n;
  1530.     }
  1531.  
  1532.     // now sort it
  1533.     qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
  1534. }
  1535.  
  1536.  
  1537. /*
  1538. =================
  1539. ServerPlayerIcon
  1540. =================
  1541. */
  1542. static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize ) {
  1543.     char    *skin;
  1544.     char    model[MAX_QPATH];
  1545.  
  1546.     Q_strncpyz( model, modelAndSkin, sizeof(model));
  1547.     skin = Q_strrchr( model, '/' );
  1548.     if ( skin ) {
  1549.         *skin++ = '\0';
  1550.     }
  1551.     else {
  1552.         skin = "default";
  1553.     }
  1554.  
  1555.     Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );
  1556.  
  1557.     if( !trap_R_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 ) {
  1558.         Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
  1559.     }
  1560. }
  1561.  
  1562.  
  1563. /*
  1564. =================
  1565. UI_BotSelectMenu_UpdateGrid
  1566. =================
  1567. */
  1568. static void UI_BotSelectMenu_UpdateGrid( void ) {
  1569.     const char    *info;
  1570.     int            i;
  1571.     int            j;
  1572.  
  1573.     j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
  1574.     for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++) {
  1575.         if( j < botSelectInfo.numBots ) { 
  1576.             info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
  1577.             ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
  1578.             Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
  1579.             Q_CleanStr( botSelectInfo.botnames[i] );
  1580.              botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
  1581.             if( BotAlreadySelected( botSelectInfo.botnames[i] ) ) {
  1582.                 botSelectInfo.picnames[i].color = color_red;
  1583.             }
  1584.             else {
  1585.                 botSelectInfo.picnames[i].color = color_orange;
  1586.             }
  1587.             botSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
  1588.         }
  1589.         else {
  1590.             // dead slot
  1591.              botSelectInfo.pics[i].generic.name         = NULL;
  1592.             botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
  1593.             botSelectInfo.botnames[i][0] = 0;
  1594.         }
  1595.  
  1596.          botSelectInfo.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;
  1597.          botSelectInfo.pics[i].shader               = 0;
  1598.          botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
  1599.     }
  1600.  
  1601.     // set selected model
  1602.     i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
  1603.     botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
  1604.     botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  1605.  
  1606.     if( botSelectInfo.numpages > 1 ) {
  1607.         if( botSelectInfo.modelpage > 0 ) {
  1608.             botSelectInfo.left.generic.flags &= ~QMF_INACTIVE;
  1609.         }
  1610.         else {
  1611.             botSelectInfo.left.generic.flags |= QMF_INACTIVE;
  1612.         }
  1613.  
  1614.         if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) ) {
  1615.             botSelectInfo.right.generic.flags &= ~QMF_INACTIVE;
  1616.         }
  1617.         else {
  1618.             botSelectInfo.right.generic.flags |= QMF_INACTIVE;
  1619.         }
  1620.     }
  1621.     else {
  1622.         // hide left/right markers
  1623.         botSelectInfo.left.generic.flags |= QMF_INACTIVE;
  1624.         botSelectInfo.right.generic.flags |= QMF_INACTIVE;
  1625.     }
  1626. }
  1627.  
  1628.  
  1629. /*
  1630. =================
  1631. UI_BotSelectMenu_Default
  1632. =================
  1633. */
  1634. static void UI_BotSelectMenu_Default( char *bot ) {
  1635.     const char    *botInfo;
  1636.     const char    *test;
  1637.     int            n;
  1638.     int            i;
  1639.  
  1640.     for( n = 0; n < botSelectInfo.numBots; n++ ) {
  1641.         botInfo = UI_GetBotInfoByNumber( n );
  1642.         test = Info_ValueForKey( botInfo, "name" );
  1643.         if( Q_stricmp( bot, test ) == 0 ) {
  1644.             break;
  1645.         }
  1646.     }
  1647.     if( n == botSelectInfo.numBots ) {
  1648.         botSelectInfo.selectedmodel = 0;
  1649.         return;
  1650.     }
  1651.  
  1652.     for( i = 0; i < botSelectInfo.numBots; i++ ) {
  1653.         if( botSelectInfo.sortedBotNums[i] == n ) {
  1654.             break;
  1655.         }
  1656.     }
  1657.     if( i == botSelectInfo.numBots ) {
  1658.         botSelectInfo.selectedmodel = 0;
  1659.         return;
  1660.     }
  1661.  
  1662.     botSelectInfo.selectedmodel = i;
  1663. }
  1664.  
  1665.  
  1666. /*
  1667. =================
  1668. UI_BotSelectMenu_LeftEvent
  1669. =================
  1670. */
  1671. static void UI_BotSelectMenu_LeftEvent( void* ptr, int event ) {
  1672.     if( event != QM_ACTIVATED ) {
  1673.         return;
  1674.     }
  1675.     if( botSelectInfo.modelpage > 0 ) {
  1676.         botSelectInfo.modelpage--;
  1677.         botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
  1678.         UI_BotSelectMenu_UpdateGrid();
  1679.     }
  1680. }
  1681.  
  1682.  
  1683. /*
  1684. =================
  1685. UI_BotSelectMenu_RightEvent
  1686. =================
  1687. */
  1688. static void UI_BotSelectMenu_RightEvent( void* ptr, int event ) {
  1689.     if( event != QM_ACTIVATED ) {
  1690.         return;
  1691.     }
  1692.     if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 ) {
  1693.         botSelectInfo.modelpage++;
  1694.         botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
  1695.         UI_BotSelectMenu_UpdateGrid();
  1696.     }
  1697. }
  1698.  
  1699.  
  1700. /*
  1701. =================
  1702. UI_BotSelectMenu_BotEvent
  1703. =================
  1704. */
  1705. static void UI_BotSelectMenu_BotEvent( void* ptr, int event ) {
  1706.     int        i;
  1707.  
  1708.     if( event != QM_ACTIVATED ) {
  1709.         return;
  1710.     }
  1711.  
  1712.     for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ ) {
  1713.          botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
  1714.          botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
  1715.     }
  1716.  
  1717.     // set selected
  1718.     i = ((menucommon_s*)ptr)->id;
  1719.     botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
  1720.     botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
  1721.     botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
  1722. }
  1723.  
  1724.  
  1725. /*
  1726. =================
  1727. UI_BotSelectMenu_BackEvent
  1728. =================
  1729. */
  1730. static void UI_BotSelectMenu_BackEvent( void* ptr, int event ) {
  1731.     if( event != QM_ACTIVATED ) {
  1732.         return;
  1733.     }
  1734.     UI_PopMenu();
  1735. }
  1736.  
  1737.  
  1738. /*
  1739. =================
  1740. UI_BotSelectMenu_SelectEvent
  1741. =================
  1742. */
  1743. static void UI_BotSelectMenu_SelectEvent( void* ptr, int event ) {
  1744.     if( event != QM_ACTIVATED ) {
  1745.         return;
  1746.     }
  1747.     UI_PopMenu();
  1748.  
  1749.     s_serveroptions.newBot = qtrue;
  1750.     Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
  1751. }
  1752.  
  1753.  
  1754. /*
  1755. =================
  1756. UI_BotSelectMenu_Cache
  1757. =================
  1758. */
  1759. void UI_BotSelectMenu_Cache( void ) {
  1760.     trap_R_RegisterShaderNoMip( BOTSELECT_BACK0 );
  1761.     trap_R_RegisterShaderNoMip( BOTSELECT_BACK1 );
  1762.     trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
  1763.     trap_R_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
  1764.     trap_R_RegisterShaderNoMip( BOTSELECT_SELECT );
  1765.     trap_R_RegisterShaderNoMip( BOTSELECT_SELECTED );
  1766.     trap_R_RegisterShaderNoMip( BOTSELECT_ARROWS );
  1767.     trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSL );
  1768.     trap_R_RegisterShaderNoMip( BOTSELECT_ARROWSR );
  1769. }
  1770.  
  1771.  
  1772. static void UI_BotSelectMenu_Init( char *bot ) {
  1773.     int        i, j, k;
  1774.     int        x, y;
  1775.  
  1776.     memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
  1777.     botSelectInfo.menu.wrapAround = qtrue;
  1778.     botSelectInfo.menu.fullscreen = qtrue;
  1779.  
  1780.     UI_BotSelectMenu_Cache();
  1781.  
  1782.     botSelectInfo.banner.generic.type    = MTYPE_BTEXT;
  1783.     botSelectInfo.banner.generic.x        = 320;
  1784.     botSelectInfo.banner.generic.y        = 16;
  1785.     botSelectInfo.banner.string            = "SELECT BOT";
  1786.     botSelectInfo.banner.color            = color_white;
  1787.     botSelectInfo.banner.style            = UI_CENTER;
  1788.  
  1789.     y =    80;
  1790.     for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++) {
  1791.         x =    180;
  1792.         for( j = 0; j < PLAYERGRID_COLS; j++, k++ ) {
  1793.             botSelectInfo.pics[k].generic.type                = MTYPE_BITMAP;
  1794.             botSelectInfo.pics[k].generic.flags                = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
  1795.             botSelectInfo.pics[k].generic.x                    = x;
  1796.             botSelectInfo.pics[k].generic.y                    = y;
  1797.              botSelectInfo.pics[k].generic.name                = botSelectInfo.boticons[k];
  1798.             botSelectInfo.pics[k].width                        = 64;
  1799.             botSelectInfo.pics[k].height                    = 64;
  1800.             botSelectInfo.pics[k].focuspic                    = BOTSELECT_SELECTED;
  1801.             botSelectInfo.pics[k].focuscolor                = colorRed;
  1802.  
  1803.             botSelectInfo.picbuttons[k].generic.type        = MTYPE_BITMAP;
  1804.             botSelectInfo.picbuttons[k].generic.flags        = QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
  1805.             botSelectInfo.picbuttons[k].generic.callback    = UI_BotSelectMenu_BotEvent;
  1806.             botSelectInfo.picbuttons[k].generic.id            = k;
  1807.             botSelectInfo.picbuttons[k].generic.x            = x - 16;
  1808.             botSelectInfo.picbuttons[k].generic.y            = y - 16;
  1809.             botSelectInfo.picbuttons[k].generic.left        = x;
  1810.             botSelectInfo.picbuttons[k].generic.top            = y;
  1811.             botSelectInfo.picbuttons[k].generic.right        = x + 64;
  1812.             botSelectInfo.picbuttons[k].generic.bottom        = y + 64;
  1813.             botSelectInfo.picbuttons[k].width                = 128;
  1814.             botSelectInfo.picbuttons[k].height                = 128;
  1815.             botSelectInfo.picbuttons[k].focuspic            = BOTSELECT_SELECT;
  1816.             botSelectInfo.picbuttons[k].focuscolor            = colorRed;
  1817.  
  1818.             botSelectInfo.picnames[k].generic.type            = MTYPE_TEXT;
  1819.             botSelectInfo.picnames[k].generic.flags            = QMF_SMALLFONT;
  1820.             botSelectInfo.picnames[k].generic.x                = x + 32;
  1821.             botSelectInfo.picnames[k].generic.y                = y + 64;
  1822.             botSelectInfo.picnames[k].string                = botSelectInfo.botnames[k];
  1823.             botSelectInfo.picnames[k].color                    = color_orange;
  1824.             botSelectInfo.picnames[k].style                    = UI_CENTER|UI_SMALLFONT;
  1825.  
  1826.             x += (64 + 6);
  1827.         }
  1828.         y += (64 + SMALLCHAR_HEIGHT + 6);
  1829.     }
  1830.  
  1831.     botSelectInfo.arrows.generic.type        = MTYPE_BITMAP;
  1832.     botSelectInfo.arrows.generic.name        = BOTSELECT_ARROWS;
  1833.     botSelectInfo.arrows.generic.flags        = QMF_INACTIVE;
  1834.     botSelectInfo.arrows.generic.x            = 260;
  1835.     botSelectInfo.arrows.generic.y            = 440;
  1836.     botSelectInfo.arrows.width                = 128;
  1837.     botSelectInfo.arrows.height                = 32;
  1838.  
  1839.     botSelectInfo.left.generic.type            = MTYPE_BITMAP;
  1840.     botSelectInfo.left.generic.flags        = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  1841.     botSelectInfo.left.generic.callback        = UI_BotSelectMenu_LeftEvent;
  1842.     botSelectInfo.left.generic.x            = 260;
  1843.     botSelectInfo.left.generic.y            = 440;
  1844.     botSelectInfo.left.width                  = 64;
  1845.     botSelectInfo.left.height                  = 32;
  1846.     botSelectInfo.left.focuspic                = BOTSELECT_ARROWSL;
  1847.  
  1848.     botSelectInfo.right.generic.type        = MTYPE_BITMAP;
  1849.     botSelectInfo.right.generic.flags        = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  1850.     botSelectInfo.right.generic.callback    = UI_BotSelectMenu_RightEvent;
  1851.     botSelectInfo.right.generic.x            = 321;
  1852.     botSelectInfo.right.generic.y            = 440;
  1853.     botSelectInfo.right.width                  = 64;
  1854.     botSelectInfo.right.height              = 32;
  1855.     botSelectInfo.right.focuspic            = BOTSELECT_ARROWSR;
  1856.  
  1857.     botSelectInfo.back.generic.type        = MTYPE_BITMAP;
  1858.     botSelectInfo.back.generic.name        = BOTSELECT_BACK0;
  1859.     botSelectInfo.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
  1860.     botSelectInfo.back.generic.callback    = UI_BotSelectMenu_BackEvent;
  1861.     botSelectInfo.back.generic.x        = 0;
  1862.     botSelectInfo.back.generic.y        = 480-64;
  1863.     botSelectInfo.back.width            = 128;
  1864.     botSelectInfo.back.height            = 64;
  1865.     botSelectInfo.back.focuspic            = BOTSELECT_BACK1;
  1866.  
  1867.     botSelectInfo.go.generic.type        = MTYPE_BITMAP;
  1868.     botSelectInfo.go.generic.name        = BOTSELECT_ACCEPT0;
  1869.     botSelectInfo.go.generic.flags        = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
  1870.     botSelectInfo.go.generic.callback    = UI_BotSelectMenu_SelectEvent;
  1871.     botSelectInfo.go.generic.x            = 640;
  1872.     botSelectInfo.go.generic.y            = 480-64;
  1873.     botSelectInfo.go.width                = 128;
  1874.     botSelectInfo.go.height                = 64;
  1875.     botSelectInfo.go.focuspic            = BOTSELECT_ACCEPT1;
  1876.  
  1877.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
  1878.     for( i = 0; i < MAX_MODELSPERPAGE; i++ ) {
  1879.         Menu_AddItem( &botSelectInfo.menu,    &botSelectInfo.pics[i] );
  1880.         Menu_AddItem( &botSelectInfo.menu,    &botSelectInfo.picbuttons[i] );
  1881.         Menu_AddItem( &botSelectInfo.menu,    &botSelectInfo.picnames[i] );
  1882.     }
  1883.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
  1884.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
  1885.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
  1886.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
  1887.     Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );
  1888.  
  1889.     UI_BotSelectMenu_BuildList();
  1890.     UI_BotSelectMenu_Default( bot );
  1891.     botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
  1892.     UI_BotSelectMenu_UpdateGrid();
  1893. }
  1894.  
  1895.  
  1896. /*
  1897. =================
  1898. UI_BotSelectMenu
  1899. =================
  1900. */
  1901. void UI_BotSelectMenu( char *bot ) {
  1902.     UI_BotSelectMenu_Init( bot );
  1903.     UI_PushMenu( &botSelectInfo.menu );
  1904. }
  1905.