Annotation of quake2/client/menu.c, revision 1.1.1.1

1.1       root        1: #include <ctype.h>
                      2: #include <io.h>
                      3: #include "client.h"
                      4: #include "../client/qmenu.h"
                      5: static int     m_main_cursor;
                      6: #define NUM_CURSOR_FRAMES 15
                      7: static char *menu_in_sound             = "misc/menu1.wav";
                      8: static char *menu_move_sound   = "misc/menu2.wav";
                      9: static char *menu_out_sound            = "misc/menu3.wav";
                     10: void M_Menu_Main_f (void);
                     11:        void M_Menu_Game_f (void);
                     12:                void M_Menu_LoadGame_f (void);
                     13:                void M_Menu_SaveGame_f (void);
                     14:                void M_Menu_PlayerConfig_f (void);
                     15:                void M_Menu_Credits_f( void );
                     16:        void M_Menu_Multiplayer_f( void );
                     17:                void M_Menu_JoinServer_f (void);
                     18:                        void M_Menu_AddressBook_f( void );
                     19:                void M_Menu_StartServer_f (void);
                     20:                        void M_Menu_DMOptions_f (void);
                     21:        void M_Menu_Video_f (void);
                     22:        void M_Menu_Options_f (void);
                     23:                void M_Menu_Keys_f (void);
                     24:        void M_Menu_Quit_f (void);
                     25: 
                     26:        void M_Menu_Credits( void );
                     27: qboolean       m_entersound;           // play after drawing a frame, so caching
                     28:                                                                // won't disrupt the sound
                     29: void   (*m_drawfunc) (void);
                     30: const char *(*m_keyfunc) (int key);
                     31: //=============================================================================
                     32: /* Support Routines */
                     33: #define        MAX_MENU_DEPTH  8
                     34: typedef struct
                     35: {
                     36:        void    (*draw) (void);
                     37:        const char *(*key) (int k);
                     38: } menulayer_t;
                     39: menulayer_t    m_layers[MAX_MENU_DEPTH];
                     40: int            m_menudepth;
                     41: 
                     42: static void M_Banner( char *name )
                     43: {
                     44:        int w, h;
                     45: 
                     46:        re.DrawGetPicSize (&w, &h, name );
                     47:        re.DrawPic( viddef.width / 2 - w / 2, viddef.height / 2 - 110, name );
                     48: }
                     49: void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) )
                     50: {
                     51:        int             i;
                     52: 
                     53:        if (Cvar_VariableValue ("maxclients") == 1 
                     54:                && Com_ServerState ())
                     55:                Cvar_Set ("paused", "1");
                     56:        // if this menu is already present, drop back to that level
                     57:        // to avoid stacking menus by hotkeys
                     58:        for (i=0 ; i<m_menudepth ; i++)
                     59:                if (m_layers[i].draw == draw &&
                     60:                        m_layers[i].key == key)
                     61:                {
                     62:                        m_menudepth = i;
                     63:                }
                     64:        if (i == m_menudepth)
                     65:        {
                     66:                if (m_menudepth >= MAX_MENU_DEPTH)
                     67:                        Com_Error (ERR_FATAL, "M_PushMenu: MAX_MENU_DEPTH");
                     68:                m_layers[m_menudepth].draw = m_drawfunc;
                     69:                m_layers[m_menudepth].key = m_keyfunc;
                     70:                m_menudepth++;
                     71:        }
                     72:        m_drawfunc = draw;
                     73:        m_keyfunc = key;
                     74:        m_entersound = true;
                     75:        cls.key_dest = key_menu;
                     76: }
                     77: void M_ForceMenuOff (void)
                     78: {
                     79:        m_drawfunc = 0;
                     80:        m_keyfunc = 0;
                     81:        cls.key_dest = key_game;
                     82:        m_menudepth = 0;
                     83:        Key_ClearStates ();
                     84:        Cvar_Set ("paused", "0");
                     85: }
                     86: void M_PopMenu (void)
                     87: {
                     88:        S_StartLocalSound( menu_out_sound );
                     89:        if (m_menudepth < 1)
                     90:                Com_Error (ERR_FATAL, "M_PopMenu: depth < 1");
                     91:        m_menudepth--;
                     92:        m_drawfunc = m_layers[m_menudepth].draw;
                     93:        m_keyfunc = m_layers[m_menudepth].key;
                     94:        if (!m_menudepth)
                     95:                M_ForceMenuOff ();
                     96: }
                     97: const char *Default_MenuKey( menuframework_s *m, int key )
                     98: {
                     99:        const char *sound = NULL;
                    100:        menucommon_s *item;
                    101:        if ( m )
                    102:        {
                    103:                if ( ( item = Menu_ItemAtCursor( m ) ) != 0 )
                    104:                {
                    105:                        if ( item->type == MTYPE_FIELD )
                    106:                        {
                    107:                                if ( Field_Key( ( menufield_s * ) item, key ) )
                    108:                                        return NULL;
                    109:                        }
                    110:                }
                    111:        }
                    112:        switch ( key )
                    113:        {
                    114:        case K_ESCAPE:
                    115:                M_PopMenu();
                    116:                return menu_out_sound;
                    117:        case K_KP_UPARROW:
                    118:        case K_UPARROW:
                    119:                if ( m )
                    120:                {
                    121:                        m->cursor--;
                    122:                        Menu_AdjustCursor( m, -1 );
                    123:                        sound = menu_move_sound;
                    124:                }
                    125:                break;
                    126:        case K_TAB:
                    127:                if ( m )
                    128:                {
                    129:                        m->cursor++;
                    130:                        Menu_AdjustCursor( m, 1 );
                    131:                        sound = menu_move_sound;
                    132:                }
                    133:                break;
                    134:        case K_KP_DOWNARROW:
                    135:        case K_DOWNARROW:
                    136:                if ( m )
                    137:                {
                    138:                        m->cursor++;
                    139:                        Menu_AdjustCursor( m, 1 );
                    140:                        sound = menu_move_sound;
                    141:                }
                    142:                break;
                    143:        case K_KP_LEFTARROW:
                    144:        case K_LEFTARROW:
                    145:                if ( m )
                    146:                {
                    147:                        Menu_SlideItem( m, -1 );
                    148:                        sound = menu_move_sound;
                    149:                }
                    150:                break;
                    151:        case K_KP_RIGHTARROW:
                    152:        case K_RIGHTARROW:
                    153:                if ( m )
                    154:                {
                    155:                        Menu_SlideItem( m, 1 );
                    156:                        sound = menu_move_sound;
                    157:                }
                    158:                break;
                    159: 
                    160:        case K_MOUSE1:
                    161:        case K_MOUSE2:
                    162:        case K_MOUSE3:
                    163:        case K_JOY1:
                    164:        case K_JOY2:
                    165:        case K_JOY3:
                    166:        case K_JOY4:
                    167:        case K_AUX1:
                    168:        case K_AUX2:
                    169:        case K_AUX3:
                    170:        case K_AUX4:
                    171:        case K_AUX5:
                    172:        case K_AUX6:
                    173:        case K_AUX7:
                    174:        case K_AUX8:
                    175:        case K_AUX9:
                    176:        case K_AUX10:
                    177:        case K_AUX11:
                    178:        case K_AUX12:
                    179:        case K_AUX13:
                    180:        case K_AUX14:
                    181:        case K_AUX15:
                    182:        case K_AUX16:
                    183:        case K_AUX17:
                    184:        case K_AUX18:
                    185:        case K_AUX19:
                    186:        case K_AUX20:
                    187:        case K_AUX21:
                    188:        case K_AUX22:
                    189:        case K_AUX23:
                    190:        case K_AUX24:
                    191:        case K_AUX25:
                    192:        case K_AUX26:
                    193:        case K_AUX27:
                    194:        case K_AUX28:
                    195:        case K_AUX29:
                    196:        case K_AUX30:
                    197:        case K_AUX31:
                    198:        case K_AUX32:
                    199:                
                    200:        case K_KP_ENTER:
                    201:        case K_ENTER:
                    202:                if ( m )
                    203:                        Menu_SelectItem( m );
                    204:                sound = menu_move_sound;
                    205:                break;
                    206:        }
                    207:        return sound;
                    208: }
                    209: //=============================================================================
                    210: /*
                    211: ================
                    212: M_DrawCharacter
                    213: Draws one solid graphics character
                    214: cx and cy are in 320*240 coordinates, and will be centered on
                    215: higher res screens.
                    216: ================
                    217: */
                    218: void M_DrawCharacter (int cx, int cy, int num)
                    219: {
                    220:        re.DrawChar ( cx + ((viddef.width - 320)>>1), cy + ((viddef.height - 240)>>1), num);
                    221: }
                    222: void M_Print (int cx, int cy, char *str)
                    223: {
                    224:        while (*str)
                    225:        {
                    226:                M_DrawCharacter (cx, cy, (*str)+128);
                    227:                str++;
                    228:                cx += 8;
                    229:        }
                    230: }
                    231: void M_PrintWhite (int cx, int cy, char *str)
                    232: {
                    233:        while (*str)
                    234:        {
                    235:                M_DrawCharacter (cx, cy, *str);
                    236:                str++;
                    237:                cx += 8;
                    238:        }
                    239: }
                    240: void M_DrawPic (int x, int y, char *pic)
                    241: {
                    242:        re.DrawPic (x + ((viddef.width - 320)>>1), y + ((viddef.height - 240)>>1), pic);
                    243: }
                    244: /*
                    245: =============
                    246: M_DrawCursor
                    247: Draws an animating cursor with the point at
                    248: x,y.  The pic will extend to the left of x,
                    249: and both above and below y.
                    250: =============
                    251: */
                    252: void M_DrawCursor( int x, int y, int f )
                    253: {
                    254:        char    cursorname[80];
                    255:        static qboolean cached;
                    256: 
                    257:        if ( !cached )
                    258:        {
                    259:                int i;
                    260: 
                    261:                for ( i = 0; i < NUM_CURSOR_FRAMES; i++ )
                    262:                {
                    263:                        Com_sprintf( cursorname, sizeof( cursorname ), "m_cursor%d", i );
                    264: 
                    265:                        re.RegisterPic( cursorname );
                    266:                }
                    267:                cached = true;
                    268:        }
                    269:        Com_sprintf( cursorname, sizeof(cursorname), "m_cursor%d", f );
                    270:        re.DrawPic( x, y, cursorname );
                    271: }
                    272: void M_DrawTextBox (int x, int y, int width, int lines)
                    273: {
                    274:        int             cx, cy;
                    275:        int             n;
                    276:        // draw left side
                    277:        cx = x;
                    278:        cy = y;
                    279:        M_DrawCharacter (cx, cy, 1);
                    280:        for (n = 0; n < lines; n++)
                    281:        {
                    282:                cy += 8;
                    283:                M_DrawCharacter (cx, cy, 4);
                    284:        }
                    285:        M_DrawCharacter (cx, cy+8, 7);
                    286:        // draw middle
                    287:        cx += 8;
                    288:        while (width > 0)
                    289:        {
                    290:                cy = y;
                    291:                M_DrawCharacter (cx, cy, 2);
                    292:                for (n = 0; n < lines; n++)
                    293:                {
                    294:                        cy += 8;
                    295:                        M_DrawCharacter (cx, cy, 5);
                    296:                }
                    297:                M_DrawCharacter (cx, cy+8, 8);
                    298:                width -= 1;
                    299:                cx += 8;
                    300:        }
                    301:        // draw right side
                    302:        cy = y;
                    303:        M_DrawCharacter (cx, cy, 3);
                    304:        for (n = 0; n < lines; n++)
                    305:        {
                    306:                cy += 8;
                    307:                M_DrawCharacter (cx, cy, 6);
                    308:        }
                    309:        M_DrawCharacter (cx, cy+8, 9);
                    310: }
                    311:                
                    312: /*
                    313: =======================================================================
                    314: MAIN MENU
                    315: =======================================================================
                    316: */
                    317: #define        MAIN_ITEMS      5
                    318: void M_Main_Draw (void)
                    319: {
                    320:        int i;
                    321:        int w, h;
                    322:        int ystart;
                    323:        int     xoffset;
                    324:        int widest = -1;
                    325:        int totalheight = 0;
                    326:        char litname[80];
                    327:        char *names[] =
                    328:        {
                    329:                "m_main_game",
                    330:                "m_main_multiplayer",
                    331:                "m_main_options",
                    332:                "m_main_video",
                    333:                "m_main_quit",
                    334:                0
                    335:        };
                    336:        for ( i = 0; names[i] != 0; i++ )
                    337:        {
                    338:                re.DrawGetPicSize( &w, &h, names[i] );
                    339:                if ( w > widest )
                    340:                        widest = w;
                    341:                totalheight += ( h + 12 );
                    342:        }
                    343: 
                    344:        ystart = ( viddef.height / 2 - 110 );
                    345:        xoffset = ( viddef.width - widest + 70 ) / 2;
                    346:        for ( i = 0; names[i] != 0; i++ )
                    347:        {
                    348:                if ( i != m_main_cursor )
                    349:                        re.DrawPic( xoffset, ystart + i * 40 + 13, names[i] );
                    350:        }
                    351:        strcpy( litname, names[m_main_cursor] );
                    352:        strcat( litname, "_sel" );
                    353:        re.DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname );
                    354:        M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES );
                    355:        re.DrawGetPicSize( &w, &h, "m_main_plaque" );
                    356:        re.DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" );
                    357:        re.DrawPic( xoffset - 30 - w, ystart + h + 5, "m_main_logo" );
                    358: }
                    359: const char *M_Main_Key (int key)
                    360: {
                    361:        const char *sound = menu_move_sound;
                    362:        switch (key)
                    363:        {
                    364:        case K_ESCAPE:
                    365:                M_PopMenu ();
                    366:                break;
                    367: 
                    368:        case K_KP_DOWNARROW:
                    369:        case K_DOWNARROW:
                    370:                if (++m_main_cursor >= MAIN_ITEMS)
                    371:                        m_main_cursor = 0;
                    372:                return sound;
                    373:        case K_KP_UPARROW:
                    374:        case K_UPARROW:
                    375:                if (--m_main_cursor < 0)
                    376:                        m_main_cursor = MAIN_ITEMS - 1;
                    377:                return sound;
                    378: 
                    379:        case K_KP_ENTER:
                    380:        case K_ENTER:
                    381:                m_entersound = true;
                    382:                switch (m_main_cursor)
                    383:                {
                    384:                case 0:
                    385:                        M_Menu_Game_f ();
                    386:                        break;
                    387:                case 1:
                    388:                        M_Menu_Multiplayer_f();
                    389:                        break;
                    390:                case 2:
                    391:                        M_Menu_Options_f ();
                    392:                        break;
                    393:                case 3:
                    394:                        M_Menu_Video_f ();
                    395:                        break;
                    396:                case 4:
                    397:                        M_Menu_Quit_f ();
                    398:                        break;
                    399:                }
                    400:        }
                    401:        return NULL;
                    402: }
                    403: void M_Menu_Main_f (void)
                    404: {
                    405:        M_PushMenu (M_Main_Draw, M_Main_Key);
                    406: }
                    407: 
                    408: /*
                    409: =======================================================================
                    410: 
                    411: MULTIPLAYER MENU
                    412: 
                    413: =======================================================================
                    414: */
                    415: static menuframework_s s_multiplayer_menu;
                    416: static menuaction_s            s_join_network_server_action;
                    417: static menuaction_s            s_start_network_server_action;
                    418: static menuaction_s            s_player_setup_action;
                    419: 
                    420: static void Multiplayer_MenuDraw (void)
                    421: {
                    422:        M_Banner( "m_banner_multiplayer" );
                    423: 
                    424:        Menu_AdjustCursor( &s_multiplayer_menu, 1 );
                    425:        Menu_Draw( &s_multiplayer_menu );
                    426: }
                    427: 
                    428: static void PlayerSetupFunc( void *unused )
                    429: {
                    430:        M_Menu_PlayerConfig_f();
                    431: }
                    432: 
                    433: static void JoinNetworkServerFunc( void *unused )
                    434: {
                    435:        M_Menu_JoinServer_f();
                    436: }
                    437: 
                    438: static void StartNetworkServerFunc( void *unused )
                    439: {
                    440:        M_Menu_StartServer_f ();
                    441: }
                    442: 
                    443: void Multiplayer_MenuInit( void )
                    444: {
                    445:        s_multiplayer_menu.x = viddef.width * 0.50 - 64;
                    446:        s_multiplayer_menu.nitems = 0;
                    447: 
                    448:        s_join_network_server_action.generic.type       = MTYPE_ACTION;
                    449:        s_join_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
                    450:        s_join_network_server_action.generic.x          = 0;
                    451:        s_join_network_server_action.generic.y          = 0;
                    452:        s_join_network_server_action.generic.name       = " join network server";
                    453:        s_join_network_server_action.generic.callback = JoinNetworkServerFunc;
                    454: 
                    455:        s_start_network_server_action.generic.type      = MTYPE_ACTION;
                    456:        s_start_network_server_action.generic.flags  = QMF_LEFT_JUSTIFY;
                    457:        s_start_network_server_action.generic.x         = 0;
                    458:        s_start_network_server_action.generic.y         = 10;
                    459:        s_start_network_server_action.generic.name      = " start network server";
                    460:        s_start_network_server_action.generic.callback = StartNetworkServerFunc;
                    461: 
                    462:        s_player_setup_action.generic.type      = MTYPE_ACTION;
                    463:        s_player_setup_action.generic.flags  = QMF_LEFT_JUSTIFY;
                    464:        s_player_setup_action.generic.x         = 0;
                    465:        s_player_setup_action.generic.y         = 20;
                    466:        s_player_setup_action.generic.name      = " player setup";
                    467:        s_player_setup_action.generic.callback = PlayerSetupFunc;
                    468: 
                    469:        Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_join_network_server_action );
                    470:        Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_start_network_server_action );
                    471:        Menu_AddItem( &s_multiplayer_menu, ( void * ) &s_player_setup_action );
                    472: 
                    473:        Menu_Center( &s_multiplayer_menu );
                    474: }
                    475: 
                    476: const char *Multiplayer_MenuKey( int key )
                    477: {
                    478:        return Default_MenuKey( &s_multiplayer_menu, key );
                    479: }
                    480: 
                    481: void M_Menu_Multiplayer_f( void )
                    482: {
                    483:        Multiplayer_MenuInit();
                    484:        M_PushMenu( Multiplayer_MenuDraw, Multiplayer_MenuKey );
                    485: }
                    486: /*
                    487: =======================================================================
                    488: 
                    489: KEYS MENU
                    490: 
                    491: =======================================================================
                    492: */
                    493: char *bindnames[][2] =
                    494: {
                    495: {"+attack",            "attack"},
                    496: {"weapnext",           "next weapon"},
                    497: {"+forward",           "walk forward"},
                    498: {"+back",                      "backpedal"},
                    499: {"+left",                      "turn left"},
                    500: {"+right",                     "turn right"},
                    501: {"+speed",                     "run"},
                    502: {"+moveleft",          "step left"},
                    503: {"+moveright",                 "step right"},
                    504: {"+strafe",            "sidestep"},
                    505: {"+lookup",            "look up"},
                    506: {"+lookdown",          "look down"},
                    507: {"centerview",                 "center view"},
                    508: {"+mlook",                     "mouse look"},
                    509: {"+klook",                     "keyboard look"},
                    510: {"+moveup",                    "up / jump"},
                    511: {"+movedown",          "down / crouch"},
                    512: {"inven",                      "inventory"},
                    513: {"invuse",                     "use item"},
                    514: {"invdrop",                    "drop item"},
                    515: {"invprev",                    "prev item"},
                    516: {"invnext",                    "next item"},
                    517: {"cmd help",           "help computer" }, 
                    518: { 0, 0 }
                    519: };
                    520: int                            keys_cursor;
                    521: static int             bind_grab;
                    522: static menuframework_s s_keys_menu;
                    523: static menuaction_s            s_keys_attack_action;
                    524: static menuaction_s            s_keys_change_weapon_action;
                    525: static menuaction_s            s_keys_walk_forward_action;
                    526: static menuaction_s            s_keys_backpedal_action;
                    527: static menuaction_s            s_keys_turn_left_action;
                    528: static menuaction_s            s_keys_turn_right_action;
                    529: static menuaction_s            s_keys_run_action;
                    530: static menuaction_s            s_keys_step_left_action;
                    531: static menuaction_s            s_keys_step_right_action;
                    532: static menuaction_s            s_keys_sidestep_action;
                    533: static menuaction_s            s_keys_look_up_action;
                    534: static menuaction_s            s_keys_look_down_action;
                    535: static menuaction_s            s_keys_center_view_action;
                    536: static menuaction_s            s_keys_mouse_look_action;
                    537: static menuaction_s            s_keys_keyboard_look_action;
                    538: static menuaction_s            s_keys_move_up_action;
                    539: static menuaction_s            s_keys_move_down_action;
                    540: static menuaction_s            s_keys_inventory_action;
                    541: static menuaction_s            s_keys_inv_use_action;
                    542: static menuaction_s            s_keys_inv_drop_action;
                    543: static menuaction_s            s_keys_inv_prev_action;
                    544: static menuaction_s            s_keys_inv_next_action;
                    545: static menuaction_s            s_keys_help_computer_action;
                    546: static void M_UnbindCommand (char *command)
                    547: {
                    548:        int             j;
                    549:        int             l;
                    550:        char    *b;
                    551:        l = strlen(command);
                    552:        for (j=0 ; j<256 ; j++)
                    553:        {
                    554:                b = keybindings[j];
                    555:                if (!b)
                    556:                        continue;
                    557:                if (!strncmp (b, command, l) )
                    558:                        Key_SetBinding (j, "");
                    559:        }
                    560: }
                    561: static void M_FindKeysForCommand (char *command, int *twokeys)
                    562: {
                    563:        int             count;
                    564:        int             j;
                    565:        int             l;
                    566:        char    *b;
                    567:        twokeys[0] = twokeys[1] = -1;
                    568:        l = strlen(command);
                    569:        count = 0;
                    570:        for (j=0 ; j<256 ; j++)
                    571:        {
                    572:                b = keybindings[j];
                    573:                if (!b)
                    574:                        continue;
                    575:                if (!strncmp (b, command, l) )
                    576:                {
                    577:                        twokeys[count] = j;
                    578:                        count++;
                    579:                        if (count == 2)
                    580:                                break;
                    581:                }
                    582:        }
                    583: }
                    584: static void KeyCursorDrawFunc( menuframework_s *menu )
                    585: {
                    586:        if ( bind_grab )
                    587:                re.DrawChar( menu->x, menu->y + menu->cursor * 9, '=' );
                    588:        else
                    589:                re.DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) );
                    590: }
                    591: static void DrawKeyBindingFunc( void *self )
                    592: {
                    593:        int keys[2];
                    594:        menuaction_s *a = ( menuaction_s * ) self;
                    595:        M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
                    596:                
                    597:        if (keys[0] == -1)
                    598:        {
                    599:                Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, "???" );
                    600:        }
                    601:        else
                    602:        {
                    603:                int x;
                    604:                const char *name;
                    605:                name = Key_KeynumToString (keys[0]);
                    606:                Menu_DrawString( a->generic.x + a->generic.parent->x + 16, a->generic.y + a->generic.parent->y, name );
                    607:                x = strlen(name) * 8;
                    608:                if (keys[1] != -1)
                    609:                {
                    610:                        Menu_DrawString( a->generic.x + a->generic.parent->x + 24 + x, a->generic.y + a->generic.parent->y, "or" );
                    611:                        Menu_DrawString( a->generic.x + a->generic.parent->x + 48 + x, a->generic.y + a->generic.parent->y, Key_KeynumToString (keys[1]) );
                    612:                }
                    613:        }
                    614: }
                    615: static void KeyBindingFunc( void *self )
                    616: {
                    617:        menuaction_s *a = ( menuaction_s * ) self;
                    618:        int keys[2];
                    619:        M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );
                    620:        if (keys[1] != -1)
                    621:                M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);
                    622:        bind_grab = true;
                    623:        Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
                    624: }
                    625: static void Keys_MenuInit( void )
                    626: {
                    627:        int y = 0;
                    628:        int i = 0;
                    629:        s_keys_menu.x = viddef.width * 0.50;
                    630:        s_keys_menu.nitems = 0;
                    631:        s_keys_menu.cursordraw = KeyCursorDrawFunc;
                    632:        s_keys_attack_action.generic.type       = MTYPE_ACTION;
                    633:        s_keys_attack_action.generic.flags  = QMF_GRAYED;
                    634:        s_keys_attack_action.generic.x          = 0;
                    635:        s_keys_attack_action.generic.y          = y;
                    636:        s_keys_attack_action.generic.ownerdraw = DrawKeyBindingFunc;
                    637:        s_keys_attack_action.generic.localdata[0] = i;
                    638:        s_keys_attack_action.generic.name       = bindnames[s_keys_attack_action.generic.localdata[0]][1];
                    639:        s_keys_change_weapon_action.generic.type        = MTYPE_ACTION;
                    640:        s_keys_change_weapon_action.generic.flags  = QMF_GRAYED;
                    641:        s_keys_change_weapon_action.generic.x           = 0;
                    642:        s_keys_change_weapon_action.generic.y           = y += 9;
                    643:        s_keys_change_weapon_action.generic.ownerdraw = DrawKeyBindingFunc;
                    644:        s_keys_change_weapon_action.generic.localdata[0] = ++i;
                    645:        s_keys_change_weapon_action.generic.name        = bindnames[s_keys_change_weapon_action.generic.localdata[0]][1];
                    646:        s_keys_walk_forward_action.generic.type = MTYPE_ACTION;
                    647:        s_keys_walk_forward_action.generic.flags  = QMF_GRAYED;
                    648:        s_keys_walk_forward_action.generic.x            = 0;
                    649:        s_keys_walk_forward_action.generic.y            = y += 9;
                    650:        s_keys_walk_forward_action.generic.ownerdraw = DrawKeyBindingFunc;
                    651:        s_keys_walk_forward_action.generic.localdata[0] = ++i;
                    652:        s_keys_walk_forward_action.generic.name = bindnames[s_keys_walk_forward_action.generic.localdata[0]][1];
                    653:        s_keys_backpedal_action.generic.type    = MTYPE_ACTION;
                    654:        s_keys_backpedal_action.generic.flags  = QMF_GRAYED;
                    655:        s_keys_backpedal_action.generic.x               = 0;
                    656:        s_keys_backpedal_action.generic.y               = y += 9;
                    657:        s_keys_backpedal_action.generic.ownerdraw = DrawKeyBindingFunc;
                    658:        s_keys_backpedal_action.generic.localdata[0] = ++i;
                    659:        s_keys_backpedal_action.generic.name    = bindnames[s_keys_backpedal_action.generic.localdata[0]][1];
                    660:        s_keys_turn_left_action.generic.type    = MTYPE_ACTION;
                    661:        s_keys_turn_left_action.generic.flags  = QMF_GRAYED;
                    662:        s_keys_turn_left_action.generic.x               = 0;
                    663:        s_keys_turn_left_action.generic.y               = y += 9;
                    664:        s_keys_turn_left_action.generic.ownerdraw = DrawKeyBindingFunc;
                    665:        s_keys_turn_left_action.generic.localdata[0] = ++i;
                    666:        s_keys_turn_left_action.generic.name    = bindnames[s_keys_turn_left_action.generic.localdata[0]][1];
                    667:        s_keys_turn_right_action.generic.type   = MTYPE_ACTION;
                    668:        s_keys_turn_right_action.generic.flags  = QMF_GRAYED;
                    669:        s_keys_turn_right_action.generic.x              = 0;
                    670:        s_keys_turn_right_action.generic.y              = y += 9;
                    671:        s_keys_turn_right_action.generic.ownerdraw = DrawKeyBindingFunc;
                    672:        s_keys_turn_right_action.generic.localdata[0] = ++i;
                    673:        s_keys_turn_right_action.generic.name   = bindnames[s_keys_turn_right_action.generic.localdata[0]][1];
                    674:        s_keys_run_action.generic.type  = MTYPE_ACTION;
                    675:        s_keys_run_action.generic.flags  = QMF_GRAYED;
                    676:        s_keys_run_action.generic.x             = 0;
                    677:        s_keys_run_action.generic.y             = y += 9;
                    678:        s_keys_run_action.generic.ownerdraw = DrawKeyBindingFunc;
                    679:        s_keys_run_action.generic.localdata[0] = ++i;
                    680:        s_keys_run_action.generic.name  = bindnames[s_keys_run_action.generic.localdata[0]][1];
                    681:        s_keys_step_left_action.generic.type    = MTYPE_ACTION;
                    682:        s_keys_step_left_action.generic.flags  = QMF_GRAYED;
                    683:        s_keys_step_left_action.generic.x               = 0;
                    684:        s_keys_step_left_action.generic.y               = y += 9;
                    685:        s_keys_step_left_action.generic.ownerdraw = DrawKeyBindingFunc;
                    686:        s_keys_step_left_action.generic.localdata[0] = ++i;
                    687:        s_keys_step_left_action.generic.name    = bindnames[s_keys_step_left_action.generic.localdata[0]][1];
                    688:        s_keys_step_right_action.generic.type   = MTYPE_ACTION;
                    689:        s_keys_step_right_action.generic.flags  = QMF_GRAYED;
                    690:        s_keys_step_right_action.generic.x              = 0;
                    691:        s_keys_step_right_action.generic.y              = y += 9;
                    692:        s_keys_step_right_action.generic.ownerdraw = DrawKeyBindingFunc;
                    693:        s_keys_step_right_action.generic.localdata[0] = ++i;
                    694:        s_keys_step_right_action.generic.name   = bindnames[s_keys_step_right_action.generic.localdata[0]][1];
                    695:        s_keys_sidestep_action.generic.type     = MTYPE_ACTION;
                    696:        s_keys_sidestep_action.generic.flags  = QMF_GRAYED;
                    697:        s_keys_sidestep_action.generic.x                = 0;
                    698:        s_keys_sidestep_action.generic.y                = y += 9;
                    699:        s_keys_sidestep_action.generic.ownerdraw = DrawKeyBindingFunc;
                    700:        s_keys_sidestep_action.generic.localdata[0] = ++i;
                    701:        s_keys_sidestep_action.generic.name     = bindnames[s_keys_sidestep_action.generic.localdata[0]][1];
                    702:        s_keys_look_up_action.generic.type      = MTYPE_ACTION;
                    703:        s_keys_look_up_action.generic.flags  = QMF_GRAYED;
                    704:        s_keys_look_up_action.generic.x         = 0;
                    705:        s_keys_look_up_action.generic.y         = y += 9;
                    706:        s_keys_look_up_action.generic.ownerdraw = DrawKeyBindingFunc;
                    707:        s_keys_look_up_action.generic.localdata[0] = ++i;
                    708:        s_keys_look_up_action.generic.name      = bindnames[s_keys_look_up_action.generic.localdata[0]][1];
                    709:        s_keys_look_down_action.generic.type    = MTYPE_ACTION;
                    710:        s_keys_look_down_action.generic.flags  = QMF_GRAYED;
                    711:        s_keys_look_down_action.generic.x               = 0;
                    712:        s_keys_look_down_action.generic.y               = y += 9;
                    713:        s_keys_look_down_action.generic.ownerdraw = DrawKeyBindingFunc;
                    714:        s_keys_look_down_action.generic.localdata[0] = ++i;
                    715:        s_keys_look_down_action.generic.name    = bindnames[s_keys_look_down_action.generic.localdata[0]][1];
                    716:        s_keys_center_view_action.generic.type  = MTYPE_ACTION;
                    717:        s_keys_center_view_action.generic.flags  = QMF_GRAYED;
                    718:        s_keys_center_view_action.generic.x             = 0;
                    719:        s_keys_center_view_action.generic.y             = y += 9;
                    720:        s_keys_center_view_action.generic.ownerdraw = DrawKeyBindingFunc;
                    721:        s_keys_center_view_action.generic.localdata[0] = ++i;
                    722:        s_keys_center_view_action.generic.name  = bindnames[s_keys_center_view_action.generic.localdata[0]][1];
                    723:        s_keys_mouse_look_action.generic.type   = MTYPE_ACTION;
                    724:        s_keys_mouse_look_action.generic.flags  = QMF_GRAYED;
                    725:        s_keys_mouse_look_action.generic.x              = 0;
                    726:        s_keys_mouse_look_action.generic.y              = y += 9;
                    727:        s_keys_mouse_look_action.generic.ownerdraw = DrawKeyBindingFunc;
                    728:        s_keys_mouse_look_action.generic.localdata[0] = ++i;
                    729:        s_keys_mouse_look_action.generic.name   = bindnames[s_keys_mouse_look_action.generic.localdata[0]][1];
                    730:        s_keys_keyboard_look_action.generic.type        = MTYPE_ACTION;
                    731:        s_keys_keyboard_look_action.generic.flags  = QMF_GRAYED;
                    732:        s_keys_keyboard_look_action.generic.x           = 0;
                    733:        s_keys_keyboard_look_action.generic.y           = y += 9;
                    734:        s_keys_keyboard_look_action.generic.ownerdraw = DrawKeyBindingFunc;
                    735:        s_keys_keyboard_look_action.generic.localdata[0] = ++i;
                    736:        s_keys_keyboard_look_action.generic.name        = bindnames[s_keys_keyboard_look_action.generic.localdata[0]][1];
                    737:        s_keys_move_up_action.generic.type      = MTYPE_ACTION;
                    738:        s_keys_move_up_action.generic.flags  = QMF_GRAYED;
                    739:        s_keys_move_up_action.generic.x         = 0;
                    740:        s_keys_move_up_action.generic.y         = y += 9;
                    741:        s_keys_move_up_action.generic.ownerdraw = DrawKeyBindingFunc;
                    742:        s_keys_move_up_action.generic.localdata[0] = ++i;
                    743:        s_keys_move_up_action.generic.name      = bindnames[s_keys_move_up_action.generic.localdata[0]][1];
                    744:        s_keys_move_down_action.generic.type    = MTYPE_ACTION;
                    745:        s_keys_move_down_action.generic.flags  = QMF_GRAYED;
                    746:        s_keys_move_down_action.generic.x               = 0;
                    747:        s_keys_move_down_action.generic.y               = y += 9;
                    748:        s_keys_move_down_action.generic.ownerdraw = DrawKeyBindingFunc;
                    749:        s_keys_move_down_action.generic.localdata[0] = ++i;
                    750:        s_keys_move_down_action.generic.name    = bindnames[s_keys_move_down_action.generic.localdata[0]][1];
                    751:        s_keys_inventory_action.generic.type    = MTYPE_ACTION;
                    752:        s_keys_inventory_action.generic.flags  = QMF_GRAYED;
                    753:        s_keys_inventory_action.generic.x               = 0;
                    754:        s_keys_inventory_action.generic.y               = y += 9;
                    755:        s_keys_inventory_action.generic.ownerdraw = DrawKeyBindingFunc;
                    756:        s_keys_inventory_action.generic.localdata[0] = ++i;
                    757:        s_keys_inventory_action.generic.name    = bindnames[s_keys_inventory_action.generic.localdata[0]][1];
                    758:        s_keys_inv_use_action.generic.type      = MTYPE_ACTION;
                    759:        s_keys_inv_use_action.generic.flags  = QMF_GRAYED;
                    760:        s_keys_inv_use_action.generic.x         = 0;
                    761:        s_keys_inv_use_action.generic.y         = y += 9;
                    762:        s_keys_inv_use_action.generic.ownerdraw = DrawKeyBindingFunc;
                    763:        s_keys_inv_use_action.generic.localdata[0] = ++i;
                    764:        s_keys_inv_use_action.generic.name      = bindnames[s_keys_inv_use_action.generic.localdata[0]][1];
                    765:        s_keys_inv_drop_action.generic.type     = MTYPE_ACTION;
                    766:        s_keys_inv_drop_action.generic.flags  = QMF_GRAYED;
                    767:        s_keys_inv_drop_action.generic.x                = 0;
                    768:        s_keys_inv_drop_action.generic.y                = y += 9;
                    769:        s_keys_inv_drop_action.generic.ownerdraw = DrawKeyBindingFunc;
                    770:        s_keys_inv_drop_action.generic.localdata[0] = ++i;
                    771:        s_keys_inv_drop_action.generic.name     = bindnames[s_keys_inv_drop_action.generic.localdata[0]][1];
                    772:        s_keys_inv_prev_action.generic.type     = MTYPE_ACTION;
                    773:        s_keys_inv_prev_action.generic.flags  = QMF_GRAYED;
                    774:        s_keys_inv_prev_action.generic.x                = 0;
                    775:        s_keys_inv_prev_action.generic.y                = y += 9;
                    776:        s_keys_inv_prev_action.generic.ownerdraw = DrawKeyBindingFunc;
                    777:        s_keys_inv_prev_action.generic.localdata[0] = ++i;
                    778:        s_keys_inv_prev_action.generic.name     = bindnames[s_keys_inv_prev_action.generic.localdata[0]][1];
                    779:        s_keys_inv_next_action.generic.type     = MTYPE_ACTION;
                    780:        s_keys_inv_next_action.generic.flags  = QMF_GRAYED;
                    781:        s_keys_inv_next_action.generic.x                = 0;
                    782:        s_keys_inv_next_action.generic.y                = y += 9;
                    783:        s_keys_inv_next_action.generic.ownerdraw = DrawKeyBindingFunc;
                    784:        s_keys_inv_next_action.generic.localdata[0] = ++i;
                    785:        s_keys_inv_next_action.generic.name     = bindnames[s_keys_inv_next_action.generic.localdata[0]][1];
                    786:        s_keys_help_computer_action.generic.type        = MTYPE_ACTION;
                    787:        s_keys_help_computer_action.generic.flags  = QMF_GRAYED;
                    788:        s_keys_help_computer_action.generic.x           = 0;
                    789:        s_keys_help_computer_action.generic.y           = y += 9;
                    790:        s_keys_help_computer_action.generic.ownerdraw = DrawKeyBindingFunc;
                    791:        s_keys_help_computer_action.generic.localdata[0] = ++i;
                    792:        s_keys_help_computer_action.generic.name        = bindnames[s_keys_help_computer_action.generic.localdata[0]][1];
                    793:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_attack_action );
                    794:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_change_weapon_action );
                    795:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_walk_forward_action );
                    796:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_backpedal_action );
                    797:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_left_action );
                    798:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_turn_right_action );
                    799:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_run_action );
                    800:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_left_action );
                    801:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_step_right_action );
                    802:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_sidestep_action );
                    803:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_up_action );
                    804:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_look_down_action );
                    805:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_center_view_action );
                    806:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_mouse_look_action );
                    807:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_keyboard_look_action );
                    808:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_up_action );
                    809:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_move_down_action );
                    810:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inventory_action );
                    811:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_use_action );
                    812:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_drop_action );
                    813:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_prev_action );
                    814:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_inv_next_action );
                    815:        Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_help_computer_action );
                    816:        
                    817:        Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
                    818:        Menu_Center( &s_keys_menu );
                    819: }
                    820: static void Keys_MenuDraw (void)
                    821: {
                    822:        Menu_AdjustCursor( &s_keys_menu, 1 );
                    823:        Menu_Draw( &s_keys_menu );
                    824: }
                    825: static const char *Keys_MenuKey( int key )
                    826: {
                    827:        menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );
                    828:        if ( bind_grab )
                    829:        {       
                    830:                if ( key != K_ESCAPE && key != '`' )
                    831:                {
                    832:                        char cmd[1024];
                    833:                        Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
                    834:                        Cbuf_InsertText (cmd);
                    835:                }
                    836:                
                    837:                Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
                    838:                bind_grab = false;
                    839:                return menu_out_sound;
                    840:        }
                    841:        switch ( key )
                    842:        {
                    843:        case K_KP_ENTER:
                    844:        case K_ENTER:
                    845:                KeyBindingFunc( item );
                    846:                return menu_in_sound;
                    847:        case K_BACKSPACE:               // delete bindings
                    848:        case K_DEL:                             // delete bindings
                    849:        case K_KP_DEL:
                    850:                M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
                    851:                return menu_out_sound;
                    852:        default:
                    853:                return Default_MenuKey( &s_keys_menu, key );
                    854:        }
                    855: }
                    856: void M_Menu_Keys_f (void)
                    857: {
                    858:        Keys_MenuInit();
                    859:        M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
                    860: }
                    861: /*
                    862: =======================================================================
                    863: CONTROLS MENU
                    864: =======================================================================
                    865: */
                    866: static cvar_t *win_noalttab;
                    867: extern cvar_t *in_joystick;
                    868: static menuframework_s s_options_menu;
                    869: static menuaction_s            s_options_defaults_action;
                    870: static menuaction_s            s_options_customize_options_action;
                    871: static menuslider_s            s_options_sensitivity_slider;
                    872: static menulist_s              s_options_freelook_box;
                    873: static menulist_s              s_options_noalttab_box;
                    874: static menulist_s              s_options_alwaysrun_box;
                    875: static menulist_s              s_options_invertmouse_box;
                    876: static menulist_s              s_options_lookspring_box;
                    877: static menulist_s              s_options_lookstrafe_box;
                    878: static menulist_s              s_options_crosshair_box;
                    879: static menuslider_s            s_options_sfxvolume_slider;
                    880: static menulist_s              s_options_joystick_box;
                    881: static menulist_s              s_options_cdvolume_box;
                    882: static menulist_s              s_options_quality_list;
                    883: static menulist_s              s_options_compatibility_list;
                    884: static menulist_s              s_options_console_action;
                    885: 
                    886: static void CrosshairFunc( void *unused )
                    887: {
                    888:        Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
                    889: }
                    890: 
                    891: static void JoystickFunc( void *unused )
                    892: {
                    893:        Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
                    894: }
                    895: static void CustomizeControlsFunc( void *unused )
                    896: {
                    897:        M_Menu_Keys_f();
                    898: }
                    899: static void AlwaysRunFunc( void *unused )
                    900: {
                    901:        Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
                    902: }
                    903: static void FreeLookFunc( void *unused )
                    904: {
                    905:        Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
                    906: }
                    907: static void MouseSpeedFunc( void *unused )
                    908: {
                    909:        Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
                    910: }
                    911: static void NoAltTabFunc( void *unused )
                    912: {
                    913:        Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
                    914: }
                    915: static float ClampCvar( float min, float max, float value )
                    916: {
                    917:        if ( value < min ) return min;
                    918:        if ( value > max ) return max;
                    919:        return value;
                    920: }
                    921: 
                    922: static void ControlsSetMenuItemValues( void )
                    923: {
                    924:        s_options_sfxvolume_slider.curvalue             = Cvar_VariableValue( "s_volume" ) * 10;
                    925:        s_options_cdvolume_box.curvalue                 = !Cvar_VariableValue("cd_nocd");
                    926:        s_options_quality_list.curvalue                 = !Cvar_VariableValue( "s_loadas8bit" );
                    927:        s_options_sensitivity_slider.curvalue   = ( sensitivity->value ) * 2;
                    928: 
                    929:        Cvar_SetValue( "cl_run", ClampCvar( 0, 1, cl_run->value ) );
                    930:        s_options_alwaysrun_box.curvalue                = cl_run->value;
                    931: 
                    932:        s_options_invertmouse_box.curvalue              = m_pitch->value < 0;
                    933: 
                    934:        Cvar_SetValue( "lookspring", ClampCvar( 0, 1, lookspring->value ) );
                    935:        s_options_lookspring_box.curvalue               = lookspring->value;
                    936: 
                    937:        Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, lookstrafe->value ) );
                    938:        s_options_lookstrafe_box.curvalue               = lookstrafe->value;
                    939: 
                    940:        Cvar_SetValue( "freelook", ClampCvar( 0, 1, freelook->value ) );
                    941:        s_options_freelook_box.curvalue                 = freelook->value;
                    942: 
                    943:        Cvar_SetValue( "crosshair", ClampCvar( 0, 3, crosshair->value ) );
                    944:        s_options_crosshair_box.curvalue                = crosshair->value;
                    945: 
                    946:        Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, in_joystick->value ) );
                    947:        s_options_joystick_box.curvalue         = in_joystick->value;
                    948: 
                    949:        s_options_noalttab_box.curvalue                 = win_noalttab->value;
                    950: }
                    951: static void ControlsResetDefaultsFunc( void *unused )
                    952: {
                    953:        Cbuf_AddText ("exec default.cfg\n");
                    954:        Cbuf_Execute();
                    955: 
                    956:        ControlsSetMenuItemValues();
                    957: }
                    958: static void InvertMouseFunc( void *unused )
                    959: {
                    960:        Cvar_SetValue( "m_pitch", -m_pitch->value );
                    961: }
                    962: static void LookspringFunc( void *unused )
                    963: {
                    964:        Cvar_SetValue( "lookspring", !lookspring->value );
                    965: }
                    966: static void LookstrafeFunc( void *unused )
                    967: {
                    968:        Cvar_SetValue( "lookstrafe", !lookstrafe->value );
                    969: }
                    970: static void UpdateVolumeFunc( void *unused )
                    971: {
                    972:        Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
                    973: }
                    974: 
                    975: static void UpdateCDVolumeFunc( void *unused )
                    976: {
                    977:        Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
                    978: }
                    979: 
                    980: static void ConsoleFunc( void *unused )
                    981: {
                    982:        /*
                    983:        ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
                    984:        */
                    985:        extern void Key_ClearTyping( void );
                    986: 
                    987:        if ( cl.attractloop )
                    988:        {
                    989:                Cbuf_AddText ("killserver\n");
                    990:                return;
                    991:        }
                    992: 
                    993:        Key_ClearTyping ();
                    994:        Con_ClearNotify ();
                    995: 
                    996:        M_ForceMenuOff ();
                    997:        cls.key_dest = key_console;
                    998: }
                    999: 
                   1000: static void UpdateSoundQualityFunc( void *unused )
                   1001: {
                   1002:        if ( s_options_quality_list.curvalue )
                   1003:        {
                   1004:                Cvar_SetValue( "s_khz", 22 );
                   1005:                Cvar_SetValue( "s_loadas8bit", false );
                   1006:        }
                   1007:        else
                   1008:        {
                   1009:                Cvar_SetValue( "s_khz", 11 );
                   1010:                Cvar_SetValue( "s_loadas8bit", true );
                   1011:        }
                   1012:        
                   1013:        Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );
                   1014: 
                   1015:        M_DrawTextBox( 8, 120 - 48, 36, 3 );
                   1016:        M_Print( 16 + 16, 120 - 48 + 8,  "Restarting the sound system. This" );
                   1017:        M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
                   1018:        M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
                   1019: 
                   1020:        // the text box won't show up unless we do a buffer swap
                   1021:        re.EndFrame();
                   1022: 
                   1023:        CL_Snd_Restart_f();
                   1024: }
                   1025: 
                   1026: void Options_MenuInit( void )
                   1027: {
                   1028:        static const char *cd_music_items[] =
                   1029:        {
                   1030:                "disabled",
                   1031:                "enabled",
                   1032:                0
                   1033:        };
                   1034:        static const char *quality_items[] =
                   1035:        {
                   1036:                "low", "high", 0
                   1037:        };
                   1038: 
                   1039:        static const char *compatibility_items[] =
                   1040:        {
                   1041:                "max compatibility", "max performance", 0
                   1042:        };
                   1043: 
                   1044:        static const char *yesno_names[] =
                   1045:        {
                   1046:                "no",
                   1047:                "yes",
                   1048:                0
                   1049:        };
                   1050:        static const char *crosshair_names[] =
                   1051:        {
                   1052:                "none",
                   1053:                "cross",
                   1054:                "dot",
                   1055:                "angle",
                   1056:                0
                   1057:        };
                   1058:        win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
                   1059:        /*
                   1060:        ** configure controls menu and menu items
                   1061:        */
                   1062:        s_options_menu.x = viddef.width / 2;
                   1063:        s_options_menu.y = viddef.height / 2 - 58;
                   1064:        s_options_menu.nitems = 0;
                   1065: 
                   1066:        s_options_sfxvolume_slider.generic.type = MTYPE_SLIDER;
                   1067:        s_options_sfxvolume_slider.generic.x    = 0;
                   1068:        s_options_sfxvolume_slider.generic.y    = 0;
                   1069:        s_options_sfxvolume_slider.generic.name = "effects volume";
                   1070:        s_options_sfxvolume_slider.generic.callback     = UpdateVolumeFunc;
                   1071:        s_options_sfxvolume_slider.minvalue             = 0;
                   1072:        s_options_sfxvolume_slider.maxvalue             = 10;
                   1073:        s_options_sfxvolume_slider.curvalue             = Cvar_VariableValue( "s_volume" ) * 10;
                   1074: 
                   1075:        s_options_cdvolume_box.generic.type     = MTYPE_SPINCONTROL;
                   1076:        s_options_cdvolume_box.generic.x                = 0;
                   1077:        s_options_cdvolume_box.generic.y                = 10;
                   1078:        s_options_cdvolume_box.generic.name     = "CD music";
                   1079:        s_options_cdvolume_box.generic.callback = UpdateCDVolumeFunc;
                   1080:        s_options_cdvolume_box.itemnames                = cd_music_items;
                   1081:        s_options_cdvolume_box.curvalue                 = !Cvar_VariableValue("cd_nocd");
                   1082: 
                   1083:        s_options_quality_list.generic.type     = MTYPE_SPINCONTROL;
                   1084:        s_options_quality_list.generic.x                = 0;
                   1085:        s_options_quality_list.generic.y                = 20;;
                   1086:        s_options_quality_list.generic.name             = "sound quality";
                   1087:        s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
                   1088:        s_options_quality_list.itemnames                = quality_items;
                   1089:        s_options_quality_list.curvalue                 = !Cvar_VariableValue( "s_loadas8bit" );
                   1090: 
                   1091:        s_options_compatibility_list.generic.type       = MTYPE_SPINCONTROL;
                   1092:        s_options_compatibility_list.generic.x          = 0;
                   1093:        s_options_compatibility_list.generic.y          = 30;
                   1094:        s_options_compatibility_list.generic.name       = "sound compatibility";
                   1095:        s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
                   1096:        s_options_compatibility_list.itemnames          = compatibility_items;
                   1097:        s_options_compatibility_list.curvalue           = Cvar_VariableValue( "s_primary" );
                   1098: 
                   1099:        s_options_sensitivity_slider.generic.type       = MTYPE_SLIDER;
                   1100:        s_options_sensitivity_slider.generic.x          = 0;
                   1101:        s_options_sensitivity_slider.generic.y          = 50;
                   1102:        s_options_sensitivity_slider.generic.name       = "mouse speed";
                   1103:        s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
                   1104:        s_options_sensitivity_slider.minvalue           = 2;
                   1105:        s_options_sensitivity_slider.maxvalue           = 22;
                   1106:        s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
                   1107:        s_options_alwaysrun_box.generic.x       = 0;
                   1108:        s_options_alwaysrun_box.generic.y       = 60;
                   1109:        s_options_alwaysrun_box.generic.name    = "always run";
                   1110:        s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
                   1111:        s_options_alwaysrun_box.itemnames = yesno_names;
                   1112:        s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
                   1113:        s_options_invertmouse_box.generic.x     = 0;
                   1114:        s_options_invertmouse_box.generic.y     = 70;
                   1115:        s_options_invertmouse_box.generic.name  = "invert mouse";
                   1116:        s_options_invertmouse_box.generic.callback = InvertMouseFunc;
                   1117:        s_options_invertmouse_box.itemnames = yesno_names;
                   1118:        s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
                   1119:        s_options_lookspring_box.generic.x      = 0;
                   1120:        s_options_lookspring_box.generic.y      = 80;
                   1121:        s_options_lookspring_box.generic.name   = "lookspring";
                   1122:        s_options_lookspring_box.generic.callback = LookspringFunc;
                   1123:        s_options_lookspring_box.itemnames = yesno_names;
                   1124:        s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
                   1125:        s_options_lookstrafe_box.generic.x      = 0;
                   1126:        s_options_lookstrafe_box.generic.y      = 90;
                   1127:        s_options_lookstrafe_box.generic.name   = "lookstrafe";
                   1128:        s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
                   1129:        s_options_lookstrafe_box.itemnames = yesno_names;
                   1130:        s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
                   1131:        s_options_freelook_box.generic.x        = 0;
                   1132:        s_options_freelook_box.generic.y        = 100;
                   1133:        s_options_freelook_box.generic.name     = "free look";
                   1134:        s_options_freelook_box.generic.callback = FreeLookFunc;
                   1135:        s_options_freelook_box.itemnames = yesno_names;
                   1136: 
                   1137:        s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
                   1138:        s_options_crosshair_box.generic.x       = 0;
                   1139:        s_options_crosshair_box.generic.y       = 110;
                   1140:        s_options_crosshair_box.generic.name    = "crosshair";
                   1141:        s_options_crosshair_box.generic.callback = CrosshairFunc;
                   1142:        s_options_crosshair_box.itemnames = crosshair_names;
                   1143: /*
                   1144:        s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
                   1145:        s_options_noalttab_box.generic.x        = 0;
                   1146:        s_options_noalttab_box.generic.y        = 110;
                   1147:        s_options_noalttab_box.generic.name     = "disable alt-tab";
                   1148:        s_options_noalttab_box.generic.callback = NoAltTabFunc;
                   1149:        s_options_noalttab_box.itemnames = yesno_names;
                   1150: */
                   1151:        s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
                   1152:        s_options_joystick_box.generic.x        = 0;
                   1153:        s_options_joystick_box.generic.y        = 120;
                   1154:        s_options_joystick_box.generic.name     = "use joystick";
                   1155:        s_options_joystick_box.generic.callback = JoystickFunc;
                   1156:        s_options_joystick_box.itemnames = yesno_names;
                   1157: 
                   1158:        s_options_customize_options_action.generic.type = MTYPE_ACTION;
                   1159:        s_options_customize_options_action.generic.x            = 0;
                   1160:        s_options_customize_options_action.generic.y            = 140;
                   1161:        s_options_customize_options_action.generic.name = "customize controls";
                   1162:        s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
                   1163:        s_options_defaults_action.generic.type  = MTYPE_ACTION;
                   1164:        s_options_defaults_action.generic.x             = 0;
                   1165:        s_options_defaults_action.generic.y             = 150;
                   1166:        s_options_defaults_action.generic.name  = "reset defaults";
                   1167:        s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;
                   1168: 
                   1169:        s_options_console_action.generic.type   = MTYPE_ACTION;
                   1170:        s_options_console_action.generic.x              = 0;
                   1171:        s_options_console_action.generic.y              = 160;
                   1172:        s_options_console_action.generic.name   = "go to console";
                   1173:        s_options_console_action.generic.callback = ConsoleFunc;
                   1174: 
                   1175:        ControlsSetMenuItemValues();
                   1176: 
                   1177:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_sfxvolume_slider );
                   1178:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_cdvolume_box );
                   1179:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_quality_list );
                   1180:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_compatibility_list );
                   1181:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_sensitivity_slider );
                   1182:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_alwaysrun_box );
                   1183:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_invertmouse_box );
                   1184:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookspring_box );
                   1185:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_lookstrafe_box );
                   1186:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_freelook_box );
                   1187:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_crosshair_box );
                   1188:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_joystick_box );
                   1189:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_customize_options_action );
                   1190:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_defaults_action );
                   1191:        Menu_AddItem( &s_options_menu, ( void * ) &s_options_console_action );
                   1192: }
                   1193: void Options_MenuDraw (void)
                   1194: {
                   1195:        M_Banner( "m_banner_options" );
                   1196:        Menu_AdjustCursor( &s_options_menu, 1 );
                   1197:        Menu_Draw( &s_options_menu );
                   1198: }
                   1199: const char *Options_MenuKey( int key )
                   1200: {
                   1201:        return Default_MenuKey( &s_options_menu, key );
                   1202: }
                   1203: void M_Menu_Options_f (void)
                   1204: {
                   1205:        Options_MenuInit();
                   1206:        M_PushMenu ( Options_MenuDraw, Options_MenuKey );
                   1207: }
                   1208: /*
                   1209: =======================================================================
                   1210: VIDEO MENU
                   1211: =======================================================================
                   1212: */
                   1213: void M_Menu_Video_f (void)
                   1214: {
                   1215:        VID_MenuInit();
                   1216:        M_PushMenu( VID_MenuDraw, VID_MenuKey );
                   1217: }
                   1218: /*
                   1219: =============================================================================
                   1220: 
                   1221: END GAME MENU
                   1222: 
                   1223: =============================================================================
                   1224: */
                   1225: static int credits_start_time;
                   1226: static const char *credits[] =
                   1227: {
                   1228:        "+QUAKE II BY ID SOFTWARE",
                   1229:        "",
                   1230:        "+PROGRAMMING",
                   1231:        "John Carmack",
                   1232:        "John Cash",
                   1233:        "Brian Hook",
                   1234:        "",
                   1235:        "+ART",
                   1236:        "Adrian Carmack",
                   1237:        "Kevin Cloud",
                   1238:        "Paul Steed",
                   1239:        "",
                   1240:        "+LEVEL DESIGN",
                   1241:        "Tim Willits",
                   1242:        "American McGee",
                   1243:        "Christian Antkow",
                   1244:        "Paul Jaquays",
                   1245:        "Brandon James",
                   1246:        "",
                   1247:        "+BIZ",
                   1248:        "Todd Hollenshead",
                   1249:        "Barrett (Bear) Alexander",
                   1250:        "Donna Jackson",
                   1251:        "",
                   1252:        "",
                   1253:        "+SPECIAL THANKS",
                   1254:        "Ben Donges for beta testing",
                   1255:        "",
                   1256:        "",
                   1257:        "",
                   1258:        "",
                   1259:        "",
                   1260:        "",
                   1261:        "+ADDITIONAL SUPPORT",
                   1262:        "",
                   1263:        "+LINUX PORT AND CTF",
                   1264:        "Dave \"Zoid\" Kirsch",
                   1265:        "",
                   1266:        "+CINEMATIC SEQUENCES",
                   1267:        "Ending Cinematic by Blur Studio - ",
                   1268:        "Venice, CA",
                   1269:        "",
                   1270:        "Environment models for Introduction",
                   1271:        "Cinematic by Karl Dolgener",
                   1272:        "",
                   1273:        "Assistance with environment design",
                   1274:        "by Cliff Iwai",
                   1275:        "",
                   1276:        "+SOUND EFFECTS AND MUSIC",
                   1277:        "Sound Design by Soundelux Media Labs.",
                   1278:        "Music Composed and Produced by",
                   1279:        "Soundelux Media Labs.  Special thanks",
                   1280:        "to Bill Brown, Tom Ozanich, Brian",
                   1281:        "Celano, Jeff Eisner, and The Soundelux",
                   1282:        "Players.",
                   1283:        "",
                   1284:        "\"Level Music\" by Sonic Mayhem",
                   1285:        "www.sonicmayhem.com",
                   1286:        "",
                   1287:        "\"Quake II Theme Song\"",
                   1288:        "(C) 1997 Rob Zombie. All Rights",
                   1289:        "Reserved.",
                   1290:        "",
                   1291:        "Track 10 (\"Climb\") by Jer Sypult",
                   1292:        "",
                   1293:        "Voice of computers by",
                   1294:        "Carly Staehlin-Taylor",
                   1295:        "",
                   1296:        "+THANKS TO ACTIVISION",
                   1297:        "+IN PARTICULAR:",
                   1298:        "",
                   1299:        "John Tam",
                   1300:        "Steve Rosenthal",
                   1301:        "Marty Stratton",
                   1302:        "Henk Hartong",
                   1303:        "",
                   1304:        "Quake II(tm) (C)1997 Id Software, Inc.",
                   1305:        "All Rights Reserved.  Distributed by",
                   1306:        "Activision, Inc. under license.",
                   1307:        "Quake II(tm), the Id Software name,",
                   1308:        "the \"Q II\"(tm) logo and id(tm)",
                   1309:        "logo are trademarks of Id Software,",
                   1310:        "Inc. Activision(R) is a registered",
                   1311:        "trademark of Activision, Inc. All",
                   1312:        "other trademarks and trade names are",
                   1313:        "properties of their respective owners.",
                   1314:        0
                   1315: };
                   1316: 
                   1317: void M_Credits_MenuDraw( void )
                   1318: {
                   1319:        int i, y;
                   1320: 
                   1321:        /*
                   1322:        ** draw the credits
                   1323:        */
                   1324:        for ( i = 0, y = viddef.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < viddef.height; y += 10, i++ )
                   1325:        {
                   1326:                int j, stringoffset = 0;
                   1327:                int bold = false;
                   1328: 
                   1329:                if ( y <= -8 )
                   1330:                        continue;
                   1331: 
                   1332:                if ( credits[i][0] == '+' )
                   1333:                {
                   1334:                        bold = true;
                   1335:                        stringoffset = 1;
                   1336:                }
                   1337:                else
                   1338:                {
                   1339:                        bold = false;
                   1340:                        stringoffset = 0;
                   1341:                }
                   1342: 
                   1343:                for ( j = 0; credits[i][j+stringoffset]; j++ )
                   1344:                {
                   1345:                        int x;
                   1346: 
                   1347:                        x = ( viddef.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8;
                   1348: 
                   1349:                        if ( bold )
                   1350:                                re.DrawChar( x, y, credits[i][j+stringoffset] + 128 );
                   1351:                        else
                   1352:                                re.DrawChar( x, y, credits[i][j+stringoffset] );
                   1353:                }
                   1354:        }
                   1355: 
                   1356:        if ( y < 0 )
                   1357:                credits_start_time = cls.realtime;
                   1358: }
                   1359: 
                   1360: const char *M_Credits_Key( int key )
                   1361: {
                   1362:        switch (key)
                   1363:        {
                   1364:        case K_ESCAPE:
                   1365:                M_PopMenu ();
                   1366:                break;
                   1367:        }
                   1368: 
                   1369:        return menu_out_sound;
                   1370: 
                   1371: }
                   1372: 
                   1373: void M_Menu_Credits_f( void )
                   1374: {
                   1375:        credits_start_time = cls.realtime;
                   1376:        M_PushMenu( M_Credits_MenuDraw, M_Credits_Key);
                   1377: }
                   1378: /*
                   1379: =============================================================================
                   1380: 
                   1381: GAME MENU
                   1382: 
                   1383: =============================================================================
                   1384: */
                   1385: static int             m_game_cursor;
                   1386: static menuframework_s s_game_menu;
                   1387: static menuaction_s            s_easy_game_action;
                   1388: static menuaction_s            s_medium_game_action;
                   1389: static menuaction_s            s_hard_game_action;
                   1390: static menuaction_s            s_load_game_action;
                   1391: static menuaction_s            s_save_game_action;
                   1392: static menuaction_s            s_credits_action;
                   1393: static menuseparator_s s_blankline;
                   1394: static void StartGame( void )
                   1395: {
                   1396:        // disable updates and start the cinematic going
                   1397:        cl.servercount = -1;
                   1398:        M_ForceMenuOff ();
                   1399:        Cvar_SetValue( "deathmatch", 0 );
                   1400:        Cvar_SetValue( "coop", 0 );
                   1401:        Cbuf_AddText ("loading ; killserver ; wait ; newgame\n");
                   1402:        cls.key_dest = key_game;
                   1403: }
                   1404: static void EasyGameFunc( void *data )
                   1405: {
                   1406:        Cvar_ForceSet( "skill", "0" );
                   1407:        StartGame();
                   1408: }
                   1409: static void MediumGameFunc( void *data )
                   1410: {
                   1411:        Cvar_ForceSet( "skill", "1" );
                   1412:        StartGame();
                   1413: }
                   1414: static void HardGameFunc( void *data )
                   1415: {
                   1416:        Cvar_ForceSet( "skill", "2" );
                   1417:        StartGame();
                   1418: }
                   1419: static void LoadGameFunc( void *unused )
                   1420: {
                   1421:        M_Menu_LoadGame_f ();
                   1422: }
                   1423: static void SaveGameFunc( void *unused )
                   1424: {
                   1425:        M_Menu_SaveGame_f();
                   1426: }
                   1427: static void CreditsFunc( void *unused )
                   1428: {
                   1429:        M_Menu_Credits_f();
                   1430: }
                   1431: void Game_MenuInit( void )
                   1432: {
                   1433:        static const char *difficulty_names[] =
                   1434:        {
                   1435:                "easy",
                   1436:                "medium",
                   1437:                "hard",
                   1438:                0
                   1439:        };
                   1440:        s_game_menu.x = viddef.width * 0.50;
                   1441:        s_game_menu.nitems = 0;
                   1442:        s_easy_game_action.generic.type = MTYPE_ACTION;
                   1443:        s_easy_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1444:        s_easy_game_action.generic.x            = 0;
                   1445:        s_easy_game_action.generic.y            = 0;
                   1446:        s_easy_game_action.generic.name = "easy";
                   1447:        s_easy_game_action.generic.callback = EasyGameFunc;
                   1448:        s_medium_game_action.generic.type       = MTYPE_ACTION;
                   1449:        s_medium_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1450:        s_medium_game_action.generic.x          = 0;
                   1451:        s_medium_game_action.generic.y          = 10;
                   1452:        s_medium_game_action.generic.name       = "medium";
                   1453:        s_medium_game_action.generic.callback = MediumGameFunc;
                   1454:        s_hard_game_action.generic.type = MTYPE_ACTION;
                   1455:        s_hard_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1456:        s_hard_game_action.generic.x            = 0;
                   1457:        s_hard_game_action.generic.y            = 20;
                   1458:        s_hard_game_action.generic.name = "hard";
                   1459:        s_hard_game_action.generic.callback = HardGameFunc;
                   1460:        s_blankline.generic.type = MTYPE_SEPARATOR;
                   1461: 
                   1462:        s_load_game_action.generic.type = MTYPE_ACTION;
                   1463:        s_load_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1464:        s_load_game_action.generic.x            = 0;
                   1465:        s_load_game_action.generic.y            = 40;
                   1466:        s_load_game_action.generic.name = "load game";
                   1467:        s_load_game_action.generic.callback = LoadGameFunc;
                   1468:        s_save_game_action.generic.type = MTYPE_ACTION;
                   1469:        s_save_game_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1470:        s_save_game_action.generic.x            = 0;
                   1471:        s_save_game_action.generic.y            = 50;
                   1472:        s_save_game_action.generic.name = "save game";
                   1473:        s_save_game_action.generic.callback = SaveGameFunc;
                   1474: 
                   1475:        s_credits_action.generic.type   = MTYPE_ACTION;
                   1476:        s_credits_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1477:        s_credits_action.generic.x              = 0;
                   1478:        s_credits_action.generic.y              = 60;
                   1479:        s_credits_action.generic.name   = "credits";
                   1480:        s_credits_action.generic.callback = CreditsFunc;
                   1481:        Menu_AddItem( &s_game_menu, ( void * ) &s_easy_game_action );
                   1482:        Menu_AddItem( &s_game_menu, ( void * ) &s_medium_game_action );
                   1483:        Menu_AddItem( &s_game_menu, ( void * ) &s_hard_game_action );
                   1484:        Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
                   1485:        Menu_AddItem( &s_game_menu, ( void * ) &s_load_game_action );
                   1486:        Menu_AddItem( &s_game_menu, ( void * ) &s_save_game_action );
                   1487:        Menu_AddItem( &s_game_menu, ( void * ) &s_blankline );
                   1488:        Menu_AddItem( &s_game_menu, ( void * ) &s_credits_action );
                   1489:        Menu_Center( &s_game_menu );
                   1490: }
                   1491: void Game_MenuDraw( void )
                   1492: {
                   1493:        M_Banner( "m_banner_game" );
                   1494:        Menu_AdjustCursor( &s_game_menu, 1 );
                   1495:        Menu_Draw( &s_game_menu );
                   1496: }
                   1497: const char *Game_MenuKey( int key )
                   1498: {
                   1499:        return Default_MenuKey( &s_game_menu, key );
                   1500: }
                   1501: void M_Menu_Game_f (void)
                   1502: {
                   1503:        Game_MenuInit();
                   1504:        M_PushMenu( Game_MenuDraw, Game_MenuKey );
                   1505:        m_game_cursor = 1;
                   1506: }
                   1507: /*
                   1508: =============================================================================
                   1509: LOADGAME MENU
                   1510: =============================================================================
                   1511: */
                   1512: #define        MAX_SAVEGAMES   15
                   1513: static menuframework_s s_savegame_menu;
                   1514: static menuframework_s s_loadgame_menu;
                   1515: static menuaction_s            s_loadgame_actions[MAX_SAVEGAMES];
                   1516: char           m_savestrings[MAX_SAVEGAMES][32];
                   1517: qboolean       m_savevalid[MAX_SAVEGAMES];
                   1518: void Create_Savestrings (void)
                   1519: {
                   1520:        int             i;
                   1521:        FILE    *f;
                   1522:        char    name[MAX_OSPATH];
                   1523:        for (i=0 ; i<MAX_SAVEGAMES ; i++)
                   1524:        {
                   1525:                Com_sprintf (name, sizeof(name), "%s/save/save%i/server.ssv", FS_Gamedir(), i);
                   1526:                f = fopen (name, "rb");
                   1527:                if (!f)
                   1528:                {
                   1529:                        strcpy (m_savestrings[i], "<EMPTY>");
                   1530:                        m_savevalid[i] = false;
                   1531:                }
                   1532:                else
                   1533:                {
                   1534:                        FS_Read (m_savestrings[i], sizeof(m_savestrings[i]), f);
                   1535:                        fclose (f);
                   1536:                        m_savevalid[i] = true;
                   1537:                }
                   1538:        }
                   1539: }
                   1540: void LoadGameCallback( void *self )
                   1541: {
                   1542:        menuaction_s *a = ( menuaction_s * ) self;
                   1543:        if ( m_savevalid[ a->generic.localdata[0] ] )
                   1544:                Cbuf_AddText (va("load save%i\n",  a->generic.localdata[0] ) );
                   1545:        M_ForceMenuOff ();
                   1546: }
                   1547: void LoadGame_MenuInit( void )
                   1548: {
                   1549:        int i;
                   1550:        s_loadgame_menu.x = viddef.width / 2 - 120;
                   1551:        s_loadgame_menu.y = viddef.height / 2 - 58;
                   1552:        s_loadgame_menu.nitems = 0;
                   1553:        Create_Savestrings();
                   1554:        for ( i = 0; i < MAX_SAVEGAMES; i++ )
                   1555:        {
                   1556:                s_loadgame_actions[i].generic.name                      = m_savestrings[i];
                   1557:                s_loadgame_actions[i].generic.flags                     = QMF_LEFT_JUSTIFY;
                   1558:                s_loadgame_actions[i].generic.localdata[0]      = i;
                   1559:                s_loadgame_actions[i].generic.callback          = LoadGameCallback;
                   1560:                s_loadgame_actions[i].generic.x = 0;
                   1561:                s_loadgame_actions[i].generic.y = ( i ) * 10;
                   1562:                if (i>0)        // separate from autosave
                   1563:                        s_loadgame_actions[i].generic.y += 10;
                   1564:                s_loadgame_actions[i].generic.type = MTYPE_ACTION;
                   1565:                Menu_AddItem( &s_loadgame_menu, &s_loadgame_actions[i] );
                   1566:        }
                   1567: }
                   1568: void LoadGame_MenuDraw( void )
                   1569: {
                   1570:        M_Banner( "m_banner_load_game" );
                   1571: //     Menu_AdjustCursor( &s_loadgame_menu, 1 );
                   1572:        Menu_Draw( &s_loadgame_menu );
                   1573: }
                   1574: const char *LoadGame_MenuKey( int key )
                   1575: {
                   1576:        if ( key == K_ESCAPE || key == K_ENTER )
                   1577:        {
                   1578:                s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
                   1579:                if ( s_savegame_menu.cursor < 0 )
                   1580:                        s_savegame_menu.cursor = 0;
                   1581:        }
                   1582:        return Default_MenuKey( &s_loadgame_menu, key );
                   1583: }
                   1584: void M_Menu_LoadGame_f (void)
                   1585: {
                   1586:        LoadGame_MenuInit();
                   1587:        M_PushMenu( LoadGame_MenuDraw, LoadGame_MenuKey );
                   1588: }
                   1589: /*
                   1590: =============================================================================
                   1591: SAVEGAME MENU
                   1592: =============================================================================
                   1593: */
                   1594: static menuframework_s s_savegame_menu;
                   1595: static menuaction_s            s_savegame_actions[MAX_SAVEGAMES];
                   1596: void SaveGameCallback( void *self )
                   1597: {
                   1598:        menuaction_s *a = ( menuaction_s * ) self;
                   1599:        Cbuf_AddText (va("save save%i\n", a->generic.localdata[0] ));
                   1600:        M_ForceMenuOff ();
                   1601: }
                   1602: void SaveGame_MenuDraw( void )
                   1603: {
                   1604:        M_Banner( "m_banner_save_game" );
                   1605:        Menu_AdjustCursor( &s_savegame_menu, 1 );
                   1606:        Menu_Draw( &s_savegame_menu );
                   1607: }
                   1608: void SaveGame_MenuInit( void )
                   1609: {
                   1610:        int i;
                   1611:        s_savegame_menu.x = viddef.width / 2 - 120;
                   1612:        s_savegame_menu.y = viddef.height / 2 - 58;
                   1613:        s_savegame_menu.nitems = 0;
                   1614:        Create_Savestrings();
                   1615:        // don't include the autosave slot
                   1616:        for ( i = 0; i < MAX_SAVEGAMES-1; i++ )
                   1617:        {
                   1618:                s_savegame_actions[i].generic.name = m_savestrings[i+1];
                   1619:                s_savegame_actions[i].generic.localdata[0] = i+1;
                   1620:                s_savegame_actions[i].generic.flags = QMF_LEFT_JUSTIFY;
                   1621:                s_savegame_actions[i].generic.callback = SaveGameCallback;
                   1622:                s_savegame_actions[i].generic.x = 0;
                   1623:                s_savegame_actions[i].generic.y = ( i ) * 10;
                   1624:                s_savegame_actions[i].generic.type = MTYPE_ACTION;
                   1625:                Menu_AddItem( &s_savegame_menu, &s_savegame_actions[i] );
                   1626:        }
                   1627: }
                   1628: const char *SaveGame_MenuKey( int key )
                   1629: {
                   1630:        if ( key == K_ENTER || key == K_ESCAPE )
                   1631:        {
                   1632:                s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
                   1633:                if ( s_loadgame_menu.cursor < 0 )
                   1634:                        s_loadgame_menu.cursor = 0;
                   1635:        }
                   1636:        return Default_MenuKey( &s_savegame_menu, key );
                   1637: }
                   1638: void M_Menu_SaveGame_f (void)
                   1639: {
                   1640:        if (!Com_ServerState())
                   1641:                return;         // not playing a game
                   1642:        SaveGame_MenuInit();
                   1643:        M_PushMenu( SaveGame_MenuDraw, SaveGame_MenuKey );
                   1644:        Create_Savestrings ();
                   1645: }
                   1646: /*
                   1647: =============================================================================
                   1648: JOIN SERVER MENU
                   1649: =============================================================================
                   1650: */
                   1651: #define MAX_LOCAL_SERVERS 8
                   1652: static menuframework_s s_joinserver_menu;
                   1653: static menuseparator_s s_joinserver_server_title;
                   1654: static menuaction_s            s_joinserver_search_action;
                   1655: static menuaction_s            s_joinserver_address_book_action;
                   1656: static menuaction_s            s_joinserver_server_actions[MAX_LOCAL_SERVERS];
                   1657: 
                   1658: int            m_num_servers;
                   1659: #define        NO_SERVER_STRING        "<no server>"
                   1660: 
                   1661: // user readable information
                   1662: static char local_server_names[MAX_LOCAL_SERVERS][80];
                   1663: 
                   1664: // network address
                   1665: static netadr_t local_server_netadr[MAX_LOCAL_SERVERS];
                   1666: 
                   1667: void M_AddToServerList (netadr_t adr, char *info)
                   1668: {
                   1669:        int             i;
                   1670: 
                   1671:        if (m_num_servers == MAX_LOCAL_SERVERS)
                   1672:                return;
                   1673:        while ( *info == ' ' )
                   1674:                info++;
                   1675: 
                   1676:        // ignore if duplicated
                   1677:        for (i=0 ; i<m_num_servers ; i++)
                   1678:                if (!strcmp(info, local_server_names[i]))
                   1679:                        return;
                   1680: 
                   1681:        local_server_netadr[m_num_servers] = adr;
                   1682:        strncpy (local_server_names[m_num_servers], info, sizeof(local_server_names[0])-1);
                   1683:        m_num_servers++;
                   1684: }
                   1685: 
                   1686: void JoinServerFunc( void *self )
                   1687: {
                   1688:        char    buffer[128];
                   1689:        int             index;
                   1690: 
                   1691:        index = ( menuaction_s * ) self - s_joinserver_server_actions;
                   1692: 
                   1693:        if ( Q_stricmp( local_server_names[index], NO_SERVER_STRING ) == 0 )
                   1694:                return;
                   1695: 
                   1696:        if (index >= m_num_servers)
                   1697:                return;
                   1698: 
                   1699:        Com_sprintf (buffer, sizeof(buffer), "connect %s\n", NET_AdrToString (local_server_netadr[index]));
                   1700:        Cbuf_AddText (buffer);
                   1701:        M_ForceMenuOff ();
                   1702: }
                   1703: void AddressBookFunc( void *self )
                   1704: {
                   1705:        M_Menu_AddressBook_f();
                   1706: }
                   1707: void NullCursorDraw( void *self )
                   1708: {
                   1709: }
                   1710: 
                   1711: void SearchLocalGames( void )
                   1712: {
                   1713:        int             i;
                   1714: 
                   1715:        m_num_servers = 0;
                   1716:        for (i=0 ; i<MAX_LOCAL_SERVERS ; i++)
                   1717:                strcpy (local_server_names[i], NO_SERVER_STRING);
                   1718: 
                   1719:        M_DrawTextBox( 8, 120 - 48, 36, 3 );
                   1720:        M_Print( 16 + 16, 120 - 48 + 8,  "Searching for local servers, this" );
                   1721:        M_Print( 16 + 16, 120 - 48 + 16, "could take up to a minute, so" );
                   1722:        M_Print( 16 + 16, 120 - 48 + 24, "please be patient." );
                   1723: 
                   1724:        // the text box won't show up unless we do a buffer swap
                   1725:        re.EndFrame();
                   1726: 
                   1727:        // send out info packets
                   1728:        CL_PingServers_f();
                   1729: }
                   1730: void SearchLocalGamesFunc( void *self )
                   1731: {
                   1732:        SearchLocalGames();
                   1733: }
                   1734: void JoinServer_MenuInit( void )
                   1735: {
                   1736:        int i;
                   1737:        s_joinserver_menu.x = viddef.width * 0.50 - 120;
                   1738:        s_joinserver_menu.nitems = 0;
                   1739:        s_joinserver_address_book_action.generic.type   = MTYPE_ACTION;
                   1740:        s_joinserver_address_book_action.generic.name   = "address book";
                   1741:        s_joinserver_address_book_action.generic.flags  = QMF_LEFT_JUSTIFY;
                   1742:        s_joinserver_address_book_action.generic.x              = 0;
                   1743:        s_joinserver_address_book_action.generic.y              = 0;
                   1744:        s_joinserver_address_book_action.generic.callback = AddressBookFunc;
                   1745:        s_joinserver_search_action.generic.type = MTYPE_ACTION;
                   1746:        s_joinserver_search_action.generic.name = "refresh server list";
                   1747:        s_joinserver_search_action.generic.flags        = QMF_LEFT_JUSTIFY;
                   1748:        s_joinserver_search_action.generic.x    = 0;
                   1749:        s_joinserver_search_action.generic.y    = 10;
                   1750:        s_joinserver_search_action.generic.callback = SearchLocalGamesFunc;
                   1751:        s_joinserver_search_action.generic.statusbar = "search for servers";
                   1752:        s_joinserver_server_title.generic.type = MTYPE_SEPARATOR;
                   1753:        s_joinserver_server_title.generic.name = "connect to...";
                   1754:        s_joinserver_server_title.generic.x    = 80;
                   1755:        s_joinserver_server_title.generic.y        = 30;
                   1756:        for ( i = 0; i < MAX_LOCAL_SERVERS; i++ )
                   1757:        {
                   1758:                s_joinserver_server_actions[i].generic.type     = MTYPE_ACTION;
                   1759:                strcpy (local_server_names[i], NO_SERVER_STRING);
                   1760:                s_joinserver_server_actions[i].generic.name     = local_server_names[i];
                   1761:                s_joinserver_server_actions[i].generic.flags    = QMF_LEFT_JUSTIFY;
                   1762:                s_joinserver_server_actions[i].generic.x                = 0;
                   1763:                s_joinserver_server_actions[i].generic.y                = 40 + i*10;
                   1764:                s_joinserver_server_actions[i].generic.callback = JoinServerFunc;
                   1765:                s_joinserver_server_actions[i].generic.statusbar = "press ENTER to connect";
                   1766:        }
                   1767:        Menu_AddItem( &s_joinserver_menu, &s_joinserver_address_book_action );
                   1768:        Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_title );
                   1769:        Menu_AddItem( &s_joinserver_menu, &s_joinserver_search_action );
                   1770:        for ( i = 0; i < 8; i++ )
                   1771:                Menu_AddItem( &s_joinserver_menu, &s_joinserver_server_actions[i] );
                   1772:        Menu_Center( &s_joinserver_menu );
                   1773: 
                   1774:        SearchLocalGames();
                   1775: }
                   1776: void JoinServer_MenuDraw(void)
                   1777: {
                   1778:        M_Banner( "m_banner_join_server" );
                   1779:        Menu_Draw( &s_joinserver_menu );
                   1780: }
                   1781: const char *JoinServer_MenuKey( int key )
                   1782: {
                   1783:        return Default_MenuKey( &s_joinserver_menu, key );
                   1784: }
                   1785: void M_Menu_JoinServer_f (void)
                   1786: {
                   1787:        JoinServer_MenuInit();
                   1788:        M_PushMenu( JoinServer_MenuDraw, JoinServer_MenuKey );
                   1789: }
                   1790: 
                   1791: /*
                   1792: =============================================================================
                   1793: START SERVER MENU
                   1794: =============================================================================
                   1795: */
                   1796: static menuframework_s s_startserver_menu;
                   1797: static char **mapnames;
                   1798: static int       nummaps;
                   1799: static menuaction_s    s_startserver_start_action;
                   1800: static menuaction_s    s_startserver_dmoptions_action;
                   1801: static menufield_s     s_timelimit_field;
                   1802: static menufield_s     s_fraglimit_field;
                   1803: static menufield_s     s_maxclients_field;
                   1804: static menufield_s     s_hostname_field;
                   1805: static menulist_s      s_startmap_list;
                   1806: static menulist_s      s_rules_box;
                   1807: 
                   1808: void DMOptionsFunc( void *self )
                   1809: {
                   1810:        if (s_rules_box.curvalue == 1)
                   1811:                return;
                   1812:        M_Menu_DMOptions_f();
                   1813: }
                   1814: 
                   1815: void RulesChangeFunc ( void *self )
                   1816: {
                   1817:        // DM
                   1818:        if (s_rules_box.curvalue == 0)
                   1819:        {
                   1820:                s_maxclients_field.generic.statusbar = NULL;
                   1821:                s_startserver_dmoptions_action.generic.statusbar = NULL;
                   1822:        }
                   1823:        else // coop
                   1824:        {
                   1825:                s_maxclients_field.generic.statusbar = "4 maximum for cooperative";
                   1826:                if (atoi(s_maxclients_field.buffer) > 4)
                   1827:                        strcpy( s_maxclients_field.buffer, "4" );
                   1828:                s_startserver_dmoptions_action.generic.statusbar = "N/A for cooperative";
                   1829:        }
                   1830: }
                   1831: void StartServerActionFunc( void *self )
                   1832: {
                   1833:        char    startmap[1024];
                   1834:        int             timelimit;
                   1835:        int             fraglimit;
                   1836:        int             maxclients;
                   1837:        char    *spot;
                   1838:        strcpy( startmap, strchr( mapnames[s_startmap_list.curvalue], '\n' ) + 1 );
                   1839: 
                   1840:        maxclients  = atoi( s_maxclients_field.buffer );
                   1841:        timelimit       = atoi( s_timelimit_field.buffer );
                   1842:        fraglimit       = atoi( s_fraglimit_field.buffer );
                   1843: 
                   1844:        Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) );
                   1845:        Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) );
                   1846:        Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) );
                   1847:        Cvar_Set("hostname", s_hostname_field.buffer );
                   1848:        Cvar_SetValue ("deathmatch", !s_rules_box.curvalue );
                   1849:        Cvar_SetValue ("coop", s_rules_box.curvalue );
                   1850: 
                   1851:        spot = NULL;
                   1852:        if (s_rules_box.curvalue)
                   1853:        {
                   1854:                if(stricmp(startmap, "bunk1") == 0)
                   1855:                        spot = "start";
                   1856:                else if(stricmp(startmap, "mintro") == 0)
                   1857:                        spot = "start";
                   1858:                else if(stricmp(startmap, "fact1") == 0)
                   1859:                        spot = "start";
                   1860:                else if(stricmp(startmap, "power1") == 0)
                   1861:                        spot = "pstart";
                   1862:                else if(stricmp(startmap, "biggun") == 0)
                   1863:                        spot = "bstart";
                   1864:                else if(stricmp(startmap, "hangar1") == 0)
                   1865:                        spot = "unitstart";
                   1866:                else if(stricmp(startmap, "city1") == 0)
                   1867:                        spot = "unitstart";
                   1868:                else if(stricmp(startmap, "boss1") == 0)
                   1869:                        spot = "bosstart";
                   1870:        }
                   1871: 
                   1872:        if (spot)
                   1873:        {
                   1874:                if (Com_ServerState())
                   1875:                        Cbuf_AddText ("disconnect\n");
                   1876:                Cbuf_AddText (va("gamemap \"*%s$%s\"\n", startmap, spot));
                   1877:        }
                   1878:        else
                   1879:        {
                   1880:                Cbuf_AddText (va("map %s\n", startmap));
                   1881:        }
                   1882: 
                   1883:        M_ForceMenuOff ();
                   1884: }
                   1885: 
                   1886: void StartServer_MenuInit( void )
                   1887: {
                   1888:        static const char *dm_coop_names[] =
                   1889:        {
                   1890:                "deathmatch",
                   1891:                "cooperative",
                   1892:                0
                   1893:        };
                   1894:        char *buffer;
                   1895:        char  mapsname[1024];
                   1896:        char *s;
                   1897:        int length;
                   1898:        int i;
                   1899:        FILE *fp;
                   1900: 
                   1901:        /*
                   1902:        ** load the list of map names
                   1903:        */
                   1904:        Com_sprintf( mapsname, sizeof( mapsname ), "%s/maps.lst", FS_Gamedir() );
                   1905:        if ( ( fp = fopen( mapsname, "rb" ) ) == 0 )
                   1906:        {
                   1907:                if ( ( length = FS_LoadFile( "maps.lst", ( void ** ) &buffer ) ) == -1 )
                   1908:                        Com_Error( ERR_DROP, "couldn't find maps.lst\n" );
                   1909:        }
                   1910:        else
                   1911:        {
                   1912:                length = filelength( fileno( fp  ) );
                   1913:                buffer = malloc( length );
                   1914:                fread( buffer, length, 1, fp );
                   1915:        }
                   1916: 
                   1917:        s = buffer;
                   1918: 
                   1919:        i = 0;
                   1920:        while ( i < length )
                   1921:        {
                   1922:                if ( s[i] == '\r' )
                   1923:                        nummaps++;
                   1924:                i++;
                   1925:        }
                   1926: 
                   1927:        if ( nummaps == 0 )
                   1928:                Com_Error( ERR_DROP, "no maps in maps.lst\n" );
                   1929: 
                   1930:        mapnames = malloc( sizeof( char * ) * ( nummaps + 1 ) );
                   1931:        memset( mapnames, 0, sizeof( char * ) * ( nummaps + 1 ) );
                   1932: 
                   1933:        s = buffer;
                   1934: 
                   1935:        for ( i = 0; i < nummaps; i++ )
                   1936:        {
                   1937:     char  shortname[MAX_TOKEN_CHARS];
                   1938:     char  longname[MAX_TOKEN_CHARS];
                   1939:                char  scratch[200];
                   1940:                int             j, l;
                   1941: 
                   1942:                strcpy( shortname, COM_Parse( &s ) );
                   1943:                l = strlen(shortname);
                   1944:                for (j=0 ; j<l ; j++)
                   1945:                        shortname[j] = toupper(shortname[j]);
                   1946:                strcpy( longname, COM_Parse( &s ) );
                   1947:                Com_sprintf( scratch, sizeof( scratch ), "%s\n%s", longname, shortname );
                   1948: 
                   1949:                mapnames[i] = malloc( strlen( scratch ) + 1 );
                   1950:                strcpy( mapnames[i], scratch );
                   1951:        }
                   1952:        mapnames[nummaps] = 0;
                   1953: 
                   1954:        if ( fp != 0 )
                   1955:        {
                   1956:                fp = 0;
                   1957:                free( buffer );
                   1958:        }
                   1959:        else
                   1960:        {
                   1961:                FS_FreeFile( buffer );
                   1962:        }
                   1963: 
                   1964:        /*
                   1965:        ** initialize the menu stuff
                   1966:        */
                   1967:        s_startserver_menu.x = viddef.width * 0.50;
                   1968:        s_startserver_menu.nitems = 0;
                   1969:        s_startmap_list.generic.type = MTYPE_SPINCONTROL;
                   1970:        s_startmap_list.generic.x       = 0;
                   1971:        s_startmap_list.generic.y       = 0;
                   1972:        s_startmap_list.generic.name    = "initial map";
                   1973:        s_startmap_list.itemnames = mapnames;
                   1974:        s_rules_box.generic.type = MTYPE_SPINCONTROL;
                   1975:        s_rules_box.generic.x   = 0;
                   1976:        s_rules_box.generic.y   = 20;
                   1977:        s_rules_box.generic.name        = "rules";
                   1978:        s_rules_box.itemnames = dm_coop_names;
                   1979:        if (Cvar_VariableValue("coop"))
                   1980:                s_rules_box.curvalue = 1;
                   1981:        else
                   1982:                s_rules_box.curvalue = 0;
                   1983:        s_rules_box.generic.callback = RulesChangeFunc;
                   1984:        s_timelimit_field.generic.type = MTYPE_FIELD;
                   1985:        s_timelimit_field.generic.name = "time limit";
                   1986:        s_timelimit_field.generic.flags = QMF_NUMBERSONLY;
                   1987:        s_timelimit_field.generic.x     = 0;
                   1988:        s_timelimit_field.generic.y     = 36;
                   1989:        s_timelimit_field.generic.statusbar = "0 = no limit";
                   1990:        s_timelimit_field.length = 3;
                   1991:        s_timelimit_field.visible_length = 3;
                   1992:        strcpy( s_timelimit_field.buffer, Cvar_VariableString("timelimit") );
                   1993:        s_fraglimit_field.generic.type = MTYPE_FIELD;
                   1994:        s_fraglimit_field.generic.name = "frag limit";
                   1995:        s_fraglimit_field.generic.flags = QMF_NUMBERSONLY;
                   1996:        s_fraglimit_field.generic.x     = 0;
                   1997:        s_fraglimit_field.generic.y     = 54;
                   1998:        s_fraglimit_field.generic.statusbar = "0 = no limit";
                   1999:        s_fraglimit_field.length = 3;
                   2000:        s_fraglimit_field.visible_length = 3;
                   2001:        strcpy( s_fraglimit_field.buffer, Cvar_VariableString("fraglimit") );
                   2002: 
                   2003:        /*
                   2004:        ** maxclients determines the maximum number of players that can join
                   2005:        ** the game.  If maxclients is only "1" then we should default the menu
                   2006:        ** option to 8 players, otherwise use whatever its current value is. 
                   2007:        ** Clamping will be done when the server is actually started.
                   2008:        */
                   2009:        s_maxclients_field.generic.type = MTYPE_FIELD;
                   2010:        s_maxclients_field.generic.name = "max players";
                   2011:        s_maxclients_field.generic.flags = QMF_NUMBERSONLY;
                   2012:        s_maxclients_field.generic.x    = 0;
                   2013:        s_maxclients_field.generic.y    = 72;
                   2014:        s_maxclients_field.generic.statusbar = NULL;
                   2015:        s_maxclients_field.length = 3;
                   2016:        s_maxclients_field.visible_length = 3;
                   2017:        if ( Cvar_VariableValue( "maxclients" ) == 1 )
                   2018:                strcpy( s_maxclients_field.buffer, "8" );
                   2019:        else 
                   2020:                strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") );
                   2021: 
                   2022:        s_hostname_field.generic.type = MTYPE_FIELD;
                   2023:        s_hostname_field.generic.name = "hostname";
                   2024:        s_hostname_field.generic.flags = 0;
                   2025:        s_hostname_field.generic.x      = 0;
                   2026:        s_hostname_field.generic.y      = 90;
                   2027:        s_hostname_field.generic.statusbar = NULL;
                   2028:        s_hostname_field.length = 12;
                   2029:        s_hostname_field.visible_length = 12;
                   2030:        strcpy( s_hostname_field.buffer, Cvar_VariableString("hostname") );
                   2031: 
                   2032:        s_startserver_dmoptions_action.generic.type = MTYPE_ACTION;
                   2033:        s_startserver_dmoptions_action.generic.name     = " deathmatch flags";
                   2034:        s_startserver_dmoptions_action.generic.flags= QMF_LEFT_JUSTIFY;
                   2035:        s_startserver_dmoptions_action.generic.x        = 24;
                   2036:        s_startserver_dmoptions_action.generic.y        = 108;
                   2037:        s_startserver_dmoptions_action.generic.statusbar = NULL;
                   2038:        s_startserver_dmoptions_action.generic.callback = DMOptionsFunc;
                   2039: 
                   2040:        s_startserver_start_action.generic.type = MTYPE_ACTION;
                   2041:        s_startserver_start_action.generic.name = " begin";
                   2042:        s_startserver_start_action.generic.flags= QMF_LEFT_JUSTIFY;
                   2043:        s_startserver_start_action.generic.x    = 24;
                   2044:        s_startserver_start_action.generic.y    = 128;
                   2045:        s_startserver_start_action.generic.callback = StartServerActionFunc;
                   2046: 
                   2047:        Menu_AddItem( &s_startserver_menu, &s_startmap_list );
                   2048:        Menu_AddItem( &s_startserver_menu, &s_rules_box );
                   2049:        Menu_AddItem( &s_startserver_menu, &s_timelimit_field );
                   2050:        Menu_AddItem( &s_startserver_menu, &s_fraglimit_field );
                   2051:        Menu_AddItem( &s_startserver_menu, &s_maxclients_field );
                   2052:        Menu_AddItem( &s_startserver_menu, &s_hostname_field );
                   2053:        Menu_AddItem( &s_startserver_menu, &s_startserver_dmoptions_action );
                   2054:        Menu_AddItem( &s_startserver_menu, &s_startserver_start_action );
                   2055: 
                   2056:        Menu_Center( &s_startserver_menu );
                   2057: 
                   2058:        // call this now to set proper inital state
                   2059:        RulesChangeFunc ( NULL );
                   2060: }
                   2061: void StartServer_MenuDraw(void)
                   2062: {
                   2063:        Menu_Draw( &s_startserver_menu );
                   2064: }
                   2065: const char *StartServer_MenuKey( int key )
                   2066: {
                   2067:        if ( key == K_ESCAPE )
                   2068:        {
                   2069:                if ( mapnames )
                   2070:                {
                   2071:                        int i;
                   2072: 
                   2073:                        for ( i = 0; i < nummaps; i++ )
                   2074:                                free( mapnames[i] );
                   2075:                        free( mapnames );
                   2076:                }
                   2077:                mapnames = 0;
                   2078:                nummaps = 0;
                   2079:        }
                   2080:        return Default_MenuKey( &s_startserver_menu, key );
                   2081: }
                   2082: void M_Menu_StartServer_f (void)
                   2083: {
                   2084:        StartServer_MenuInit();
                   2085:        M_PushMenu( StartServer_MenuDraw, StartServer_MenuKey );
                   2086: }
                   2087: /*
                   2088: =============================================================================
                   2089: 
                   2090: DMOPTIONS BOOK MENU
                   2091: 
                   2092: =============================================================================
                   2093: */
                   2094: static char dmoptions_statusbar[128];
                   2095: 
                   2096: static menuframework_s s_dmoptions_menu;
                   2097: 
                   2098: static menulist_s      s_friendlyfire_box;
                   2099: static menulist_s      s_falls_box;
                   2100: static menulist_s      s_weapons_stay_box;
                   2101: static menulist_s      s_instant_powerups_box;
                   2102: static menulist_s      s_powerups_box;
                   2103: static menulist_s      s_health_box;
                   2104: static menulist_s      s_spawn_farthest_box;
                   2105: static menulist_s      s_teamplay_box;
                   2106: static menulist_s      s_samelevel_box;
                   2107: static menulist_s      s_force_respawn_box;
                   2108: static menulist_s      s_armor_box;
                   2109: static menulist_s      s_allow_exit_box;
                   2110: static menulist_s      s_infinite_ammo_box;
                   2111: static menulist_s      s_fixed_fov_box;
                   2112: static menulist_s      s_quad_drop_box;
                   2113: 
                   2114: static void DMFlagCallback( void *self )
                   2115: {
                   2116:        menulist_s *f = ( menulist_s * ) self;
                   2117:        int flags;
                   2118:        int bit = 0;
                   2119: 
                   2120:        flags = Cvar_VariableValue( "dmflags" );
                   2121: 
                   2122:        if ( f == &s_friendlyfire_box )
                   2123:        {
                   2124:                if ( f->curvalue )
                   2125:                        flags &= ~DF_NO_FRIENDLY_FIRE;
                   2126:                else
                   2127:                        flags |= DF_NO_FRIENDLY_FIRE;
                   2128:                goto setvalue;
                   2129:        }
                   2130:        else if ( f == &s_falls_box )
                   2131:        {
                   2132:                if ( f->curvalue )
                   2133:                        flags &= ~DF_NO_FALLING;
                   2134:                else
                   2135:                        flags |= DF_NO_FALLING;
                   2136:                goto setvalue;
                   2137:        }
                   2138:        else if ( f == &s_weapons_stay_box ) 
                   2139:        {
                   2140:                bit = DF_WEAPONS_STAY;
                   2141:        }
                   2142:        else if ( f == &s_instant_powerups_box )
                   2143:        {
                   2144:                bit = DF_INSTANT_ITEMS;
                   2145:        }
                   2146:        else if ( f == &s_allow_exit_box )
                   2147:        {
                   2148:                bit = DF_ALLOW_EXIT;
                   2149:        }
                   2150:        else if ( f == &s_powerups_box )
                   2151:        {
                   2152:                if ( f->curvalue )
                   2153:                        flags &= ~DF_NO_ITEMS;
                   2154:                else
                   2155:                        flags |= DF_NO_ITEMS;
                   2156:                goto setvalue;
                   2157:        }
                   2158:        else if ( f == &s_health_box )
                   2159:        {
                   2160:                if ( f->curvalue )
                   2161:                        flags &= ~DF_NO_HEALTH;
                   2162:                else
                   2163:                        flags |= DF_NO_HEALTH;
                   2164:                goto setvalue;
                   2165:        }
                   2166:        else if ( f == &s_spawn_farthest_box )
                   2167:        {
                   2168:                bit = DF_SPAWN_FARTHEST;
                   2169:        }
                   2170:        else if ( f == &s_teamplay_box )
                   2171:        {
                   2172:                if ( f->curvalue == 1 )
                   2173:                {
                   2174:                        flags |=  DF_SKINTEAMS;
                   2175:                        flags &= ~DF_MODELTEAMS;
                   2176:                }
                   2177:                else if ( f->curvalue == 2 )
                   2178:                {
                   2179:                        flags |=  DF_MODELTEAMS;
                   2180:                        flags &= ~DF_SKINTEAMS;
                   2181:                }
                   2182:                else
                   2183:                {
                   2184:                        flags &= ~( DF_MODELTEAMS | DF_SKINTEAMS );
                   2185:                }
                   2186: 
                   2187:                goto setvalue;
                   2188:        }
                   2189:        else if ( f == &s_samelevel_box )
                   2190:        {
                   2191:                bit = DF_SAME_LEVEL;
                   2192:        }
                   2193:        else if ( f == &s_force_respawn_box )
                   2194:        {
                   2195:                bit = DF_FORCE_RESPAWN;
                   2196:        }
                   2197:        else if ( f == &s_armor_box )
                   2198:        {
                   2199:                if ( f->curvalue )
                   2200:                        flags &= ~DF_NO_ARMOR;
                   2201:                else
                   2202:                        flags |= DF_NO_ARMOR;
                   2203:                goto setvalue;
                   2204:        }
                   2205:        else if ( f == &s_infinite_ammo_box )
                   2206:        {
                   2207:                bit = DF_INFINITE_AMMO;
                   2208:        }
                   2209:        else if ( f == &s_fixed_fov_box )
                   2210:        {
                   2211:                bit = DF_FIXED_FOV;
                   2212:        }
                   2213:        else if ( f == &s_quad_drop_box )
                   2214:        {
                   2215:                bit = DF_QUAD_DROP;
                   2216:        }
                   2217: 
                   2218: 
                   2219:        if ( f )
                   2220:        {
                   2221:                if ( f->curvalue == 0 )
                   2222:                        flags &= ~bit;
                   2223:                else
                   2224:                        flags |= bit;
                   2225:        }
                   2226: 
                   2227: setvalue:
                   2228:        Cvar_SetValue ("dmflags", flags);
                   2229: 
                   2230:        Com_sprintf( dmoptions_statusbar, sizeof( dmoptions_statusbar ), "dmflags = %d", flags );
                   2231: 
                   2232: }
                   2233: 
                   2234: void DMOptions_MenuInit( void )
                   2235: {
                   2236:        static const char *yes_no_names[] =
                   2237:        {
                   2238:                "no", "yes", 0
                   2239:        };
                   2240:        static const char *teamplay_names[] = 
                   2241:        {
                   2242:                "disabled", "by skin", "by model", 0
                   2243:        };
                   2244:        int dmflags = Cvar_VariableValue( "dmflags" );
                   2245:        int y = 0;
                   2246: 
                   2247:        s_dmoptions_menu.x = viddef.width * 0.50;
                   2248:        s_dmoptions_menu.nitems = 0;
                   2249: 
                   2250:        s_falls_box.generic.type = MTYPE_SPINCONTROL;
                   2251:        s_falls_box.generic.x   = 0;
                   2252:        s_falls_box.generic.y   = y;
                   2253:        s_falls_box.generic.name        = "falling damage";
                   2254:        s_falls_box.generic.callback = DMFlagCallback;
                   2255:        s_falls_box.itemnames = yes_no_names;
                   2256:        s_falls_box.curvalue = ( dmflags & DF_NO_FALLING ) == 0;
                   2257: 
                   2258:        s_weapons_stay_box.generic.type = MTYPE_SPINCONTROL;
                   2259:        s_weapons_stay_box.generic.x    = 0;
                   2260:        s_weapons_stay_box.generic.y    = y += 10;
                   2261:        s_weapons_stay_box.generic.name = "weapons stay";
                   2262:        s_weapons_stay_box.generic.callback = DMFlagCallback;
                   2263:        s_weapons_stay_box.itemnames = yes_no_names;
                   2264:        s_weapons_stay_box.curvalue = ( dmflags & DF_WEAPONS_STAY ) != 0;
                   2265: 
                   2266:        s_instant_powerups_box.generic.type = MTYPE_SPINCONTROL;
                   2267:        s_instant_powerups_box.generic.x        = 0;
                   2268:        s_instant_powerups_box.generic.y        = y += 10;
                   2269:        s_instant_powerups_box.generic.name     = "instant powerups";
                   2270:        s_instant_powerups_box.generic.callback = DMFlagCallback;
                   2271:        s_instant_powerups_box.itemnames = yes_no_names;
                   2272:        s_instant_powerups_box.curvalue = ( dmflags & DF_INSTANT_ITEMS ) != 0;
                   2273: 
                   2274:        s_powerups_box.generic.type = MTYPE_SPINCONTROL;
                   2275:        s_powerups_box.generic.x        = 0;
                   2276:        s_powerups_box.generic.y        = y += 10;
                   2277:        s_powerups_box.generic.name     = "allow powerups";
                   2278:        s_powerups_box.generic.callback = DMFlagCallback;
                   2279:        s_powerups_box.itemnames = yes_no_names;
                   2280:        s_powerups_box.curvalue = ( dmflags & DF_NO_ITEMS ) == 0;
                   2281: 
                   2282:        s_health_box.generic.type = MTYPE_SPINCONTROL;
                   2283:        s_health_box.generic.x  = 0;
                   2284:        s_health_box.generic.y  = y += 10;
                   2285:        s_health_box.generic.callback = DMFlagCallback;
                   2286:        s_health_box.generic.name       = "allow health";
                   2287:        s_health_box.itemnames = yes_no_names;
                   2288:        s_health_box.curvalue = ( dmflags & DF_NO_HEALTH ) == 0;
                   2289: 
                   2290:        s_armor_box.generic.type = MTYPE_SPINCONTROL;
                   2291:        s_armor_box.generic.x   = 0;
                   2292:        s_armor_box.generic.y   = y += 10;
                   2293:        s_armor_box.generic.name        = "allow armor";
                   2294:        s_armor_box.generic.callback = DMFlagCallback;
                   2295:        s_armor_box.itemnames = yes_no_names;
                   2296:        s_armor_box.curvalue = ( dmflags & DF_NO_ARMOR ) == 0;
                   2297: 
                   2298:        s_spawn_farthest_box.generic.type = MTYPE_SPINCONTROL;
                   2299:        s_spawn_farthest_box.generic.x  = 0;
                   2300:        s_spawn_farthest_box.generic.y  = y += 10;
                   2301:        s_spawn_farthest_box.generic.name       = "spawn farthest";
                   2302:        s_spawn_farthest_box.generic.callback = DMFlagCallback;
                   2303:        s_spawn_farthest_box.itemnames = yes_no_names;
                   2304:        s_spawn_farthest_box.curvalue = ( dmflags & DF_SPAWN_FARTHEST ) != 0;
                   2305: 
                   2306:        s_samelevel_box.generic.type = MTYPE_SPINCONTROL;
                   2307:        s_samelevel_box.generic.x       = 0;
                   2308:        s_samelevel_box.generic.y       = y += 10;
                   2309:        s_samelevel_box.generic.name    = "same map";
                   2310:        s_samelevel_box.generic.callback = DMFlagCallback;
                   2311:        s_samelevel_box.itemnames = yes_no_names;
                   2312:        s_samelevel_box.curvalue = ( dmflags & DF_SAME_LEVEL ) != 0;
                   2313: 
                   2314:        s_force_respawn_box.generic.type = MTYPE_SPINCONTROL;
                   2315:        s_force_respawn_box.generic.x   = 0;
                   2316:        s_force_respawn_box.generic.y   = y += 10;
                   2317:        s_force_respawn_box.generic.name        = "force respawn";
                   2318:        s_force_respawn_box.generic.callback = DMFlagCallback;
                   2319:        s_force_respawn_box.itemnames = yes_no_names;
                   2320:        s_force_respawn_box.curvalue = ( dmflags & DF_FORCE_RESPAWN ) != 0;
                   2321: 
                   2322:        s_teamplay_box.generic.type = MTYPE_SPINCONTROL;
                   2323:        s_teamplay_box.generic.x        = 0;
                   2324:        s_teamplay_box.generic.y        = y += 10;
                   2325:        s_teamplay_box.generic.name     = "teamplay";
                   2326:        s_teamplay_box.generic.callback = DMFlagCallback;
                   2327:        s_teamplay_box.itemnames = teamplay_names;
                   2328: 
                   2329:        s_allow_exit_box.generic.type = MTYPE_SPINCONTROL;
                   2330:        s_allow_exit_box.generic.x      = 0;
                   2331:        s_allow_exit_box.generic.y      = y += 10;
                   2332:        s_allow_exit_box.generic.name   = "allow exit";
                   2333:        s_allow_exit_box.generic.callback = DMFlagCallback;
                   2334:        s_allow_exit_box.itemnames = yes_no_names;
                   2335:        s_allow_exit_box.curvalue = ( dmflags & DF_ALLOW_EXIT ) != 0;
                   2336: 
                   2337:        s_infinite_ammo_box.generic.type = MTYPE_SPINCONTROL;
                   2338:        s_infinite_ammo_box.generic.x   = 0;
                   2339:        s_infinite_ammo_box.generic.y   = y += 10;
                   2340:        s_infinite_ammo_box.generic.name        = "infinite ammo";
                   2341:        s_infinite_ammo_box.generic.callback = DMFlagCallback;
                   2342:        s_infinite_ammo_box.itemnames = yes_no_names;
                   2343:        s_infinite_ammo_box.curvalue = ( dmflags & DF_INFINITE_AMMO ) != 0;
                   2344: 
                   2345:        s_fixed_fov_box.generic.type = MTYPE_SPINCONTROL;
                   2346:        s_fixed_fov_box.generic.x       = 0;
                   2347:        s_fixed_fov_box.generic.y       = y += 10;
                   2348:        s_fixed_fov_box.generic.name    = "fixed FOV";
                   2349:        s_fixed_fov_box.generic.callback = DMFlagCallback;
                   2350:        s_fixed_fov_box.itemnames = yes_no_names;
                   2351:        s_fixed_fov_box.curvalue = ( dmflags & DF_FIXED_FOV ) != 0;
                   2352: 
                   2353:        s_quad_drop_box.generic.type = MTYPE_SPINCONTROL;
                   2354:        s_quad_drop_box.generic.x       = 0;
                   2355:        s_quad_drop_box.generic.y       = y += 10;
                   2356:        s_quad_drop_box.generic.name    = "quad drop";
                   2357:        s_quad_drop_box.generic.callback = DMFlagCallback;
                   2358:        s_quad_drop_box.itemnames = yes_no_names;
                   2359:        s_quad_drop_box.curvalue = ( dmflags & DF_QUAD_DROP ) != 0;
                   2360: 
                   2361:        s_friendlyfire_box.generic.type = MTYPE_SPINCONTROL;
                   2362:        s_friendlyfire_box.generic.x    = 0;
                   2363:        s_friendlyfire_box.generic.y    = y += 10;
                   2364:        s_friendlyfire_box.generic.name = "friendly fire";
                   2365:        s_friendlyfire_box.generic.callback = DMFlagCallback;
                   2366:        s_friendlyfire_box.itemnames = yes_no_names;
                   2367:        s_friendlyfire_box.curvalue = ( dmflags & DF_NO_FRIENDLY_FIRE ) == 0;
                   2368: 
                   2369:        Menu_AddItem( &s_dmoptions_menu, &s_falls_box );
                   2370:        Menu_AddItem( &s_dmoptions_menu, &s_weapons_stay_box );
                   2371:        Menu_AddItem( &s_dmoptions_menu, &s_instant_powerups_box );
                   2372:        Menu_AddItem( &s_dmoptions_menu, &s_powerups_box );
                   2373:        Menu_AddItem( &s_dmoptions_menu, &s_health_box );
                   2374:        Menu_AddItem( &s_dmoptions_menu, &s_armor_box );
                   2375:        Menu_AddItem( &s_dmoptions_menu, &s_spawn_farthest_box );
                   2376:        Menu_AddItem( &s_dmoptions_menu, &s_samelevel_box );
                   2377:        Menu_AddItem( &s_dmoptions_menu, &s_force_respawn_box );
                   2378:        Menu_AddItem( &s_dmoptions_menu, &s_teamplay_box );
                   2379:        Menu_AddItem( &s_dmoptions_menu, &s_allow_exit_box );
                   2380:        Menu_AddItem( &s_dmoptions_menu, &s_infinite_ammo_box );
                   2381:        Menu_AddItem( &s_dmoptions_menu, &s_fixed_fov_box );
                   2382:        Menu_AddItem( &s_dmoptions_menu, &s_quad_drop_box );
                   2383:        Menu_AddItem( &s_dmoptions_menu, &s_friendlyfire_box );
                   2384: 
                   2385:        Menu_Center( &s_dmoptions_menu );
                   2386: 
                   2387:        // set the original dmflags statusbar
                   2388:        DMFlagCallback( 0 );
                   2389:        Menu_SetStatusBar( &s_dmoptions_menu, dmoptions_statusbar );
                   2390: }
                   2391: 
                   2392: void DMOptions_MenuDraw(void)
                   2393: {
                   2394:        Menu_Draw( &s_dmoptions_menu );
                   2395: }
                   2396: 
                   2397: const char *DMOptions_MenuKey( int key )
                   2398: {
                   2399:        return Default_MenuKey( &s_dmoptions_menu, key );
                   2400: }
                   2401: 
                   2402: void M_Menu_DMOptions_f (void)
                   2403: {
                   2404:        DMOptions_MenuInit();
                   2405:        M_PushMenu( DMOptions_MenuDraw, DMOptions_MenuKey );
                   2406: }
                   2407: 
                   2408: /*
                   2409: =============================================================================
                   2410: ADDRESS BOOK MENU
                   2411: =============================================================================
                   2412: */
                   2413: #define NUM_ADDRESSBOOK_ENTRIES 9
                   2414: static menuframework_s s_addressbook_menu;
                   2415: static menufield_s             s_addressbook_fields[NUM_ADDRESSBOOK_ENTRIES];
                   2416: void AddressBook_MenuInit( void )
                   2417: {
                   2418:        int i;
                   2419:        s_addressbook_menu.x = viddef.width / 2 - 142;
                   2420:        s_addressbook_menu.y = viddef.height / 2 - 58;
                   2421:        s_addressbook_menu.nitems = 0;
                   2422:        for ( i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++ )
                   2423:        {
                   2424:                cvar_t *adr;
                   2425:                char buffer[20];
                   2426: 
                   2427:                Com_sprintf( buffer, sizeof( buffer ), "adr%d", i );
                   2428: 
                   2429:                adr = Cvar_Get( buffer, "", CVAR_ARCHIVE );
                   2430:                s_addressbook_fields[i].generic.type = MTYPE_FIELD;
                   2431:                s_addressbook_fields[i].generic.name = 0;
                   2432:                s_addressbook_fields[i].generic.callback = 0;
                   2433:                s_addressbook_fields[i].generic.x               = 0;
                   2434:                s_addressbook_fields[i].generic.y               = i * 18 + 0;
                   2435:                s_addressbook_fields[i].generic.localdata[0] = i;
                   2436:                s_addressbook_fields[i].cursor                  = 0;
                   2437:                s_addressbook_fields[i].length                  = 60;
                   2438:                s_addressbook_fields[i].visible_length  = 30;
                   2439: 
                   2440:                strcpy( s_addressbook_fields[i].buffer, adr->string );
                   2441:                Menu_AddItem( &s_addressbook_menu, &s_addressbook_fields[i] );
                   2442:        }
                   2443: }
                   2444: const char *AddressBook_MenuKey( int key )
                   2445: {
                   2446:        if ( key == K_ESCAPE )
                   2447:        {
                   2448:                int index;
                   2449:                char buffer[20];
                   2450: 
                   2451:                for ( index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++ )
                   2452:                {
                   2453:                        Com_sprintf( buffer, sizeof( buffer ), "adr%d", index );
                   2454:                        Cvar_Set( buffer, s_addressbook_fields[index].buffer );
                   2455:                }
                   2456:        }
                   2457:        return Default_MenuKey( &s_addressbook_menu, key );
                   2458: }
                   2459: void AddressBook_MenuDraw(void)
                   2460: {
                   2461:        M_Banner( "m_banner_addressbook" );
                   2462:        Menu_Draw( &s_addressbook_menu );
                   2463: }
                   2464: void M_Menu_AddressBook_f(void)
                   2465: {
                   2466:        AddressBook_MenuInit();
                   2467:        M_PushMenu( AddressBook_MenuDraw, AddressBook_MenuKey );
                   2468: }
                   2469: /*
                   2470: =============================================================================
                   2471: PLAYER CONFIG MENU
                   2472: =============================================================================
                   2473: */
                   2474: static menuframework_s s_player_config_menu;
                   2475: static menufield_s             s_player_name_field;
                   2476: static menulist_s              s_player_model_box;
                   2477: static menulist_s              s_player_skin_box;
                   2478: static menulist_s              s_player_handedness_box;
                   2479: static menuseparator_s s_player_skin_title;
                   2480: static menuseparator_s s_player_model_title;
                   2481: static menuseparator_s s_player_hand_title;
                   2482: 
                   2483: #define MAX_DISPLAYNAME 16
                   2484: #define MAX_PLAYERMODELS 1024
                   2485: 
                   2486: typedef struct
                   2487: {
                   2488:        int             nskins;
                   2489:        char    **skindisplaynames;
                   2490:        char    displayname[MAX_DISPLAYNAME];
                   2491:        char    directory[MAX_QPATH];
                   2492: } playermodelinfo_s;
                   2493: 
                   2494: static playermodelinfo_s s_pmi[MAX_PLAYERMODELS];
                   2495: static char *s_pmnames[MAX_PLAYERMODELS];
                   2496: static int s_numplayermodels;
                   2497: 
                   2498: static void HandednessCallback( void *unused )
                   2499: {
                   2500:        Cvar_SetValue( "hand", s_player_handedness_box.curvalue );
                   2501: }
                   2502: 
                   2503: static void ModelCallback( void *unused )
                   2504: {
                   2505:        s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
                   2506:        s_player_skin_box.curvalue = 0;
                   2507: }
                   2508: 
                   2509: static void FreeFileList( char **list, int n )
                   2510: {
                   2511:        int i;
                   2512: 
                   2513:        for ( i = 0; i < n; i++ )
                   2514:        {
                   2515:                if ( list[i] )
                   2516:                {
                   2517:                        free( list[i] );
                   2518:                        list[i] = 0;
                   2519:                }
                   2520:        }
                   2521:        free( list );
                   2522: }
                   2523: 
                   2524: static qboolean IconOfSkinExists( char *skin, char **pcxfiles, int npcxfiles )
                   2525: {
                   2526:        int i;
                   2527:        char scratch[1024];
                   2528: 
                   2529:        strcpy( scratch, skin );
                   2530:        *strrchr( scratch, '.' ) = 0;
                   2531:        strcat( scratch, "_i.pcx" );
                   2532: 
                   2533:        for ( i = 0; i < npcxfiles; i++ )
                   2534:        {
                   2535:                if ( strcmp( pcxfiles[i], scratch ) == 0 )
                   2536:                        return true;
                   2537:        }
                   2538: 
                   2539:        return false;
                   2540: }
                   2541: 
                   2542: static qboolean PlayerConfig_ScanDirectories( void )
                   2543: {
                   2544:        char findname[1024];
                   2545:        char scratch[1024];
                   2546:        int ndirs = 0, npms = 0;
                   2547:        char **dirnames;
                   2548:        char *path = NULL;
                   2549:        int i;
                   2550: 
                   2551:        extern char **FS_ListFiles( char *, int *, unsigned, unsigned );
                   2552: 
                   2553:        s_numplayermodels = 0;
                   2554: 
                   2555:        /*
                   2556:        ** get a list of directories
                   2557:        */
                   2558:        do 
                   2559:        {
                   2560:                path = FS_NextPath( path );
                   2561:                Com_sprintf( findname, sizeof(findname), "%s/players/*.*", path );
                   2562: 
                   2563:                if ( ( dirnames = FS_ListFiles( findname, &ndirs, SFF_SUBDIR, 0 ) ) != 0 )
                   2564:                        break;
                   2565:        } while ( path );
                   2566: 
                   2567:        if ( !dirnames )
                   2568:                return false;
                   2569: 
                   2570:        /*
                   2571:        ** go through the subdirectories
                   2572:        */
                   2573:        npms = ndirs;
                   2574:        if ( npms > MAX_PLAYERMODELS )
                   2575:                npms = MAX_PLAYERMODELS;
                   2576: 
                   2577:        for ( i = 0; i < npms; i++ )
                   2578:        {
                   2579:                int k, s;
                   2580:                char *a, *b, *c;
                   2581:                char **pcxnames;
                   2582:                char **skinnames;
                   2583:                int npcxfiles;
                   2584:                int nskins = 0;
                   2585: 
                   2586:                if ( dirnames[i] == 0 )
                   2587:                        continue;
                   2588: 
                   2589:                // verify the existence of tris.md2
                   2590:                strcpy( scratch, dirnames[i] );
                   2591:                strcat( scratch, "/tris.md2" );
                   2592:                if ( !Sys_FindFirst( scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM ) )
                   2593:                {
                   2594:                        free( dirnames[i] );
                   2595:                        dirnames[i] = 0;
                   2596:                        Sys_FindClose();
                   2597:                        continue;
                   2598:                }
                   2599:                Sys_FindClose();
                   2600: 
                   2601:                // verify the existence of at least one pcx skin
                   2602:                strcpy( scratch, dirnames[i] );
                   2603:                strcat( scratch, "/*.pcx" );
                   2604:                pcxnames = FS_ListFiles( scratch, &npcxfiles, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
                   2605: 
                   2606:                if ( !pcxnames )
                   2607:                {
                   2608:                        free( dirnames[i] );
                   2609:                        dirnames[i] = 0;
                   2610:                        continue;
                   2611:                }
                   2612: 
                   2613:                // count valid skins, which consist of a skin with a matching "_i" icon
                   2614:                for ( k = 0; k < npcxfiles-1; k++ )
                   2615:                {
                   2616:                        if ( !strstr( pcxnames[k], "_i.pcx" ) )
                   2617:                        {
                   2618:                                if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
                   2619:                                {
                   2620:                                        nskins++;
                   2621:                                }
                   2622:                        }
                   2623:                }
                   2624:                if ( !nskins )
                   2625:                        continue;
                   2626: 
                   2627:                skinnames = malloc( sizeof( char * ) * ( nskins + 1 ) );
                   2628:                memset( skinnames, 0, sizeof( char * ) * ( nskins + 1 ) );
                   2629: 
                   2630:                // copy the valid skins
                   2631:                for ( s = 0, k = 0; k < npcxfiles-1; k++ )
                   2632:                {
                   2633:                        char *a, *b, *c;
                   2634: 
                   2635:                        if ( !strstr( pcxnames[k], "_i.pcx" ) )
                   2636:                        {
                   2637:                                if ( IconOfSkinExists( pcxnames[k], pcxnames, npcxfiles - 1 ) )
                   2638:                                {
                   2639:                                        a = strrchr( pcxnames[k], '/' );
                   2640:                                        b = strrchr( pcxnames[k], '\\' );
                   2641: 
                   2642:                                        if ( a > b )
                   2643:                                                c = a;
                   2644:                                        else
                   2645:                                                c = b;
                   2646: 
                   2647:                                        strcpy( scratch, c + 1 );
                   2648: 
                   2649:                                        if ( strrchr( scratch, '.' ) )
                   2650:                                                *strrchr( scratch, '.' ) = 0;
                   2651: 
                   2652:                                        skinnames[s] = strdup( scratch );
                   2653:                                        s++;
                   2654:                                }
                   2655:                        }
                   2656:                }
                   2657: 
                   2658:                // at this point we have a valid player model
                   2659:                s_pmi[s_numplayermodels].nskins = nskins;
                   2660:                s_pmi[s_numplayermodels].skindisplaynames = skinnames;
                   2661: 
                   2662:                // make short name for the model
                   2663:                a = strrchr( dirnames[i], '/' );
                   2664:                b = strrchr( dirnames[i], '\\' );
                   2665: 
                   2666:                if ( a > b )
                   2667:                        c = a;
                   2668:                else
                   2669:                        c = b;
                   2670: 
                   2671:                strncpy( s_pmi[s_numplayermodels].displayname, c + 1, MAX_DISPLAYNAME-1 );
                   2672:                strcpy( s_pmi[s_numplayermodels].directory, c + 1 );
                   2673: 
                   2674:                FreeFileList( pcxnames, npcxfiles );
                   2675: 
                   2676:                s_numplayermodels++;
                   2677:        }
                   2678:        if ( dirnames )
                   2679:                FreeFileList( dirnames, ndirs );
                   2680: }
                   2681: 
                   2682: static int pmicmpfnc( const void *_a, const void *_b )
                   2683: {
                   2684:        const playermodelinfo_s *a = ( const playermodelinfo_s * ) _a;
                   2685:        const playermodelinfo_s *b = ( const playermodelinfo_s * ) _b;
                   2686: 
                   2687:        /*
                   2688:        ** sort by male, female, then alphabetical
                   2689:        */
                   2690:        if ( strcmp( a->directory, "male" ) == 0 )
                   2691:                return -1;
                   2692:        else if ( strcmp( b->directory, "male" ) == 0 )
                   2693:                return 1;
                   2694: 
                   2695:        if ( strcmp( a->directory, "female" ) == 0 )
                   2696:                return -1;
                   2697:        else if ( strcmp( b->directory, "female" ) == 0 )
                   2698:                return 1;
                   2699: 
                   2700:        return strcmp( a->directory, b->directory );
                   2701: }
                   2702: 
                   2703: void PlayerConfig_MenuInit( void )
                   2704: {
                   2705:        extern cvar_t *name;
                   2706:        extern cvar_t *team;
                   2707:        extern cvar_t *skin;
                   2708:        char currentdirectory[1024];
                   2709:        char currentskin[1024];
                   2710:        int i = 0;
                   2711: 
                   2712:        int currentdirectoryindex = 0;
                   2713:        int currentskinindex = 0;
                   2714: 
                   2715:        cvar_t *hand = Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
                   2716: 
                   2717:        static const char *handedness[] = { "right", "left", "center", 0 };
                   2718: 
                   2719:        PlayerConfig_ScanDirectories();
                   2720: 
                   2721:        if ( hand->value < 0 || hand->value > 2 )
                   2722:                Cvar_SetValue( "hand", 0 );
                   2723: 
                   2724:        strcpy( currentdirectory, skin->string );
                   2725: 
                   2726:        if ( strchr( currentdirectory, '/' ) )
                   2727:        {
                   2728:                strcpy( currentskin, strchr( currentdirectory, '/' ) + 1 );
                   2729:                *strchr( currentdirectory, '/' ) = 0;
                   2730:        }
                   2731:        else if ( strchr( currentdirectory, '\\' ) )
                   2732:        {
                   2733:                strcpy( currentskin, strchr( currentdirectory, '\\' ) + 1 );
                   2734:                *strchr( currentdirectory, '\\' ) = 0;
                   2735:        }
                   2736:        else
                   2737:        {
                   2738:                strcpy( currentdirectory, "male" );
                   2739:                strcpy( currentskin, "grunt" );
                   2740:        }
                   2741: 
                   2742:        qsort( s_pmi, s_numplayermodels, sizeof( s_pmi[0] ), pmicmpfnc );
                   2743: 
                   2744:        memset( s_pmnames, 0, sizeof( s_pmnames ) );
                   2745:        for ( i = 0; i < s_numplayermodels; i++ )
                   2746:        {
                   2747:                s_pmnames[i] = s_pmi[i].displayname;
                   2748:                if ( Q_stricmp( s_pmi[i].directory, currentdirectory ) == 0 )
                   2749:                {
                   2750:                        int j;
                   2751: 
                   2752:                        currentdirectoryindex = i;
                   2753: 
                   2754:                        for ( j = 0; j < s_pmi[i].nskins; j++ )
                   2755:                        {
                   2756:                                if ( Q_stricmp( s_pmi[i].skindisplaynames[j], currentskin ) == 0 )
                   2757:                                {
                   2758:                                        currentskinindex = j;
                   2759:                                        break;
                   2760:                                }
                   2761:                        }
                   2762:                }
                   2763:        }
                   2764: 
                   2765:        s_player_config_menu.x = viddef.width / 2 - 95; 
                   2766:        s_player_config_menu.y = viddef.height / 2 - 97;
                   2767:        s_player_config_menu.nitems = 0;
                   2768: 
                   2769:        s_player_name_field.generic.type = MTYPE_FIELD;
                   2770:        s_player_name_field.generic.name = "name";
                   2771:        s_player_name_field.generic.callback = 0;
                   2772:        s_player_name_field.generic.x           = 0;
                   2773:        s_player_name_field.generic.y           = 0;
                   2774:        s_player_name_field.length      = 20;
                   2775:        s_player_name_field.visible_length = 20;
                   2776:        strcpy( s_player_name_field.buffer, name->string );
                   2777:        s_player_name_field.cursor = strlen( name->string );
                   2778: 
                   2779:        s_player_model_title.generic.type = MTYPE_SEPARATOR;
                   2780:        s_player_model_title.generic.name = "model";
                   2781:        s_player_model_title.generic.x    = -8;
                   2782:        s_player_model_title.generic.y   = 60;
                   2783: 
                   2784:        s_player_model_box.generic.type = MTYPE_SPINCONTROL;
                   2785:        s_player_model_box.generic.x    = -56;
                   2786:        s_player_model_box.generic.y    = 70;
                   2787:        s_player_model_box.generic.callback = ModelCallback;
                   2788:        s_player_model_box.generic.cursor_offset = -48;
                   2789:        s_player_model_box.curvalue = currentdirectoryindex;
                   2790:        s_player_model_box.itemnames = s_pmnames;
                   2791: 
                   2792:        s_player_skin_title.generic.type = MTYPE_SEPARATOR;
                   2793:        s_player_skin_title.generic.name = "skin";
                   2794:        s_player_skin_title.generic.x    = -16;
                   2795:        s_player_skin_title.generic.y    = 84;
                   2796: 
                   2797:        s_player_skin_box.generic.type = MTYPE_SPINCONTROL;
                   2798:        s_player_skin_box.generic.x     = -56;
                   2799:        s_player_skin_box.generic.y     = 94;
                   2800:        s_player_skin_box.generic.name  = 0;
                   2801:        s_player_skin_box.generic.callback = 0;
                   2802:        s_player_skin_box.generic.cursor_offset = -48;
                   2803:        s_player_skin_box.curvalue = currentskinindex;
                   2804:        s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
                   2805: 
                   2806:        s_player_hand_title.generic.type = MTYPE_SEPARATOR;
                   2807:        s_player_hand_title.generic.name = "handedness";
                   2808:        s_player_hand_title.generic.x    = 32;
                   2809:        s_player_hand_title.generic.y    = 108;
                   2810: 
                   2811:        s_player_handedness_box.generic.type = MTYPE_SPINCONTROL;
                   2812:        s_player_handedness_box.generic.x       = -56;
                   2813:        s_player_handedness_box.generic.y       = 118;
                   2814:        s_player_handedness_box.generic.name    = 0;
                   2815:        s_player_handedness_box.generic.cursor_offset = -48;
                   2816:        s_player_handedness_box.generic.callback = HandednessCallback;
                   2817:        s_player_handedness_box.curvalue = Cvar_VariableValue( "hand" );
                   2818:        s_player_handedness_box.itemnames = handedness;
                   2819: 
                   2820:        Menu_AddItem( &s_player_config_menu, &s_player_name_field );
                   2821:        Menu_AddItem( &s_player_config_menu, &s_player_model_title );
                   2822:        Menu_AddItem( &s_player_config_menu, &s_player_model_box );
                   2823:        if ( s_player_skin_box.itemnames )
                   2824:        {
                   2825:                Menu_AddItem( &s_player_config_menu, &s_player_skin_title );
                   2826:                Menu_AddItem( &s_player_config_menu, &s_player_skin_box );
                   2827:        }
                   2828:        Menu_AddItem( &s_player_config_menu, &s_player_hand_title );
                   2829:        Menu_AddItem( &s_player_config_menu, &s_player_handedness_box );
                   2830: }
                   2831: 
                   2832: void PlayerConfig_MenuDraw( void )
                   2833: {
                   2834:        extern float CalcFov( float fov_x, float w, float h );
                   2835:        refdef_t refdef;
                   2836:        char scratch[MAX_QPATH];
                   2837: 
                   2838:        memset( &refdef, 0, sizeof( refdef ) );
                   2839: 
                   2840:        refdef.x = viddef.width / 2;
                   2841:        refdef.y = viddef.height / 2 - 72;
                   2842:        refdef.width = 144;
                   2843:        refdef.height = 168;
                   2844:        refdef.fov_x = 40;
                   2845:        refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height );
                   2846:        refdef.time = cls.realtime*0.001;
                   2847: 
                   2848:        if ( s_pmi[s_player_model_box.curvalue].skindisplaynames )
                   2849:        {
                   2850:                static int yaw;
                   2851:                int maxframe = 29;
                   2852:                entity_t entity;
                   2853: 
                   2854:                memset( &entity, 0, sizeof( entity ) );
                   2855: 
                   2856:                Com_sprintf( scratch, sizeof( scratch ), "players/%s/tris.md2", s_pmi[s_player_model_box.curvalue].directory );
                   2857:                entity.model = re.RegisterModel( scratch );
                   2858:                Com_sprintf( scratch, sizeof( scratch ), "players/%s/%s.pcx", s_pmi[s_player_model_box.curvalue].directory, s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
                   2859:                entity.skin = re.RegisterSkin( scratch );
                   2860:                entity.flags = RF_FULLBRIGHT;
                   2861:                entity.origin[0] = 80;
                   2862:                entity.origin[1] = 0;
                   2863:                entity.origin[2] = 0;
                   2864:                VectorCopy( entity.origin, entity.oldorigin );
                   2865:                entity.frame = 0;
                   2866:                entity.oldframe = 0;
                   2867:                entity.backlerp = 0.0;
                   2868:                entity.angles[1] = yaw++;
                   2869:                if ( ++yaw > 360 )
                   2870:                        yaw -= 360;
                   2871: 
                   2872:                refdef.areabits = 0;
                   2873:                refdef.num_entities = 1;
                   2874:                refdef.entities = &entity;
                   2875:                refdef.lightstyles = 0;
                   2876:                refdef.rdflags = RDF_NOWORLDMODEL;
                   2877: 
                   2878:                Menu_Draw( &s_player_config_menu );
                   2879: 
                   2880:                M_DrawTextBox( ( refdef.x ) * ( 320.0F / viddef.width ) - 8, ( viddef.height / 2 ) * ( 240.0F / viddef.height) - 77, refdef.width / 8, refdef.height / 8 );
                   2881:                refdef.height += 4;
                   2882: 
                   2883:                re.RenderFrame( &refdef );
                   2884: 
                   2885:                Com_sprintf( scratch, sizeof( scratch ), "/players/%s/%s_i.pcx", 
                   2886:                        s_pmi[s_player_model_box.curvalue].directory,
                   2887:                        s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
                   2888:                re.DrawPic( s_player_config_menu.x - 40, refdef.y, scratch );
                   2889:        }
                   2890: }
                   2891: const char *PlayerConfig_MenuKey (int key)
                   2892: {
                   2893:        int i;
                   2894: 
                   2895:        if ( key == K_ESCAPE )
                   2896:        {
                   2897:                char scratch[1024];
                   2898: 
                   2899:                Cvar_Set( "name", s_player_name_field.buffer );
                   2900: 
                   2901:                Com_sprintf( scratch, sizeof( scratch ), "%s/%s", 
                   2902:                        s_pmi[s_player_model_box.curvalue].directory, 
                   2903:                        s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue] );
                   2904: 
                   2905:                Cvar_Set( "skin", scratch );
                   2906: 
                   2907:                for ( i = 0; i < s_numplayermodels; i++ )
                   2908:                {
                   2909:                        int j;
                   2910: 
                   2911:                        for ( j = 0; j < s_pmi[i].nskins; j++ )
                   2912:                        {
                   2913:                                if ( s_pmi[i].skindisplaynames[j] )
                   2914:                                        free( s_pmi[i].skindisplaynames[j] );
                   2915:                                s_pmi[i].skindisplaynames[j] = 0;
                   2916:                        }
                   2917:                        free( s_pmi[i].skindisplaynames );
                   2918:                        s_pmi[i].skindisplaynames = 0;
                   2919:                        s_pmi[i].nskins = 0;
                   2920:                }
                   2921:        }
                   2922:        return Default_MenuKey( &s_player_config_menu, key );
                   2923: }
                   2924: void M_Menu_PlayerConfig_f (void)
                   2925: {
                   2926:        PlayerConfig_MenuInit();
                   2927:        M_PushMenu( PlayerConfig_MenuDraw, PlayerConfig_MenuKey );
                   2928: }
                   2929: /*
                   2930: =======================================================================
                   2931: 
                   2932: GALLERY MENU
                   2933: 
                   2934: =======================================================================
                   2935: */
                   2936: #if 0
                   2937: void M_Menu_Gallery_f( void )
                   2938: {
                   2939:        extern void Gallery_MenuDraw( void );
                   2940:        extern const char *Gallery_MenuKey( int key );
                   2941:        M_PushMenu( Gallery_MenuDraw, Gallery_MenuKey );
                   2942: }
                   2943: #endif
                   2944: /*
                   2945: =======================================================================
                   2946: QUIT MENU
                   2947: =======================================================================
                   2948: */
                   2949: const char *M_Quit_Key (int key)
                   2950: {
                   2951:        switch (key)
                   2952:        {
                   2953:        case K_ESCAPE:
                   2954:        case 'n':
                   2955:        case 'N':
                   2956:                M_PopMenu ();
                   2957:                break;
                   2958:        case 'Y':
                   2959:        case 'y':
                   2960:                cls.key_dest = key_console;
                   2961:                CL_Quit_f ();
                   2962:                break;
                   2963:        default:
                   2964:                break;
                   2965:        }
                   2966:        return NULL;
                   2967: }
                   2968: void M_Quit_Draw (void)
                   2969: {
                   2970:        int             w, h;
                   2971:        re.DrawGetPicSize (&w, &h, "quit");
                   2972:        re.DrawPic ( (viddef.width-w)/2, (viddef.height-h)/2, "quit");
                   2973: }
                   2974: void M_Menu_Quit_f (void)
                   2975: {
                   2976:        M_PushMenu (M_Quit_Draw, M_Quit_Key);
                   2977: }
                   2978: //=============================================================================
                   2979: /* Menu Subsystem */
                   2980: /*
                   2981: =================
                   2982: M_Init
                   2983: =================
                   2984: */
                   2985: void M_Init (void)
                   2986: {
                   2987:        Cmd_AddCommand ("menu_main", M_Menu_Main_f);
                   2988:        Cmd_AddCommand ("menu_game", M_Menu_Game_f);
                   2989:                Cmd_AddCommand ("menu_loadgame", M_Menu_LoadGame_f);
                   2990:                Cmd_AddCommand ("menu_savegame", M_Menu_SaveGame_f);
                   2991:                Cmd_AddCommand ("menu_joinserver", M_Menu_JoinServer_f);
                   2992:                        Cmd_AddCommand ("menu_addressbook", M_Menu_AddressBook_f);
                   2993:                Cmd_AddCommand ("menu_startserver", M_Menu_StartServer_f);
                   2994:                        Cmd_AddCommand ("menu_dmoptions", M_Menu_DMOptions_f);
                   2995:                Cmd_AddCommand ("menu_playerconfig", M_Menu_PlayerConfig_f);
                   2996:                Cmd_AddCommand ("menu_credits", M_Menu_Credits_f );
                   2997:        Cmd_AddCommand ("menu_multiplayer", M_Menu_Multiplayer_f );
                   2998:        Cmd_AddCommand ("menu_video", M_Menu_Video_f);
                   2999:        Cmd_AddCommand ("menu_options", M_Menu_Options_f);
                   3000:                Cmd_AddCommand ("menu_keys", M_Menu_Keys_f);
                   3001:        Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
                   3002: }
                   3003: /*
                   3004: =================
                   3005: M_Draw
                   3006: =================
                   3007: */
                   3008: void M_Draw (void)
                   3009: {
                   3010:        if (cls.key_dest != key_menu)
                   3011:                return;
                   3012:        // repaint everything next frame
                   3013:        SCR_DirtyScreen ();
                   3014:        // dim everything behind it down
                   3015:        if (cl.cinematictime > 0)
                   3016:                re.DrawFill (0,0,viddef.width, viddef.height, 0);
                   3017:        else
                   3018:                re.DrawFadeScreen ();
                   3019:        m_drawfunc ();
                   3020:        // delay playing the enter sound until after the
                   3021:        // menu has been drawn, to avoid delay while
                   3022:        // caching images
                   3023:        if (m_entersound)
                   3024:        {
                   3025:                S_StartLocalSound( menu_in_sound );
                   3026:                m_entersound = false;
                   3027:        }
                   3028: }
                   3029: /*
                   3030: =================
                   3031: M_Keydown
                   3032: =================
                   3033: */
                   3034: void M_Keydown (int key)
                   3035: {
                   3036:        const char *s;
                   3037:        if (m_keyfunc)
                   3038:                if ( ( s = m_keyfunc( key ) ) != 0 )
                   3039:                        S_StartLocalSound( ( char * ) s );
                   3040: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.