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

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

unix.superglobalmegacorp.com

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