/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" #include "winquake.h" #include "cl_slist.h" #include "input.h" #include "keys.h" #include "sound.h" #include "version.h" #ifndef CLIENTONLY #include "server.h" #endif #include "utils.h" #include "mp3_player.h" #ifdef GLQUAKE #include "gl_local.h" #endif #ifndef _WIN32 #include #include #endif qboolean vid_windowedmouse = true; void (*vid_menudrawfn)(void); void (*vid_menukeyfn)(int key); enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_options, m_video, m_keys, m_help, m_quit, m_gameoptions, m_slist, m_sedit, m_fps, m_demos, m_mp3_control, m_mp3_playlist} m_state; void M_Menu_Main_f (void); void M_Menu_SinglePlayer_f (void); void M_Menu_Load_f (void); void M_Menu_Save_f (void); void M_Menu_MultiPlayer_f (void); void M_Menu_ServerList_f (void); void M_Menu_SEdit_f (void); void M_Menu_Setup_f (void); void M_Menu_Demos_f (void); void M_Menu_GameOptions_f (void); void M_Menu_Options_f (void); void M_Menu_Keys_f (void); void M_Menu_Fps_f (void); void M_Menu_Video_f (void); void M_Menu_MP3_Control_f (void); void M_Menu_Quit_f (void); void M_Main_Draw (void); void M_SinglePlayer_Draw (void); void M_Load_Draw (void); void M_Save_Draw (void); void M_MultiPlayer_Draw (void); void M_ServerList_Draw (void); void M_SEdit_Draw (void); void M_Setup_Draw (void); void M_Demos_Draw (void); void M_GameOptions_Draw (void); void M_Options_Draw (void); void M_Keys_Draw (void); void M_Fps_Draw (void); void M_Video_Draw (void); void M_Help_Draw (void); void M_Quit_Draw (void); void M_Main_Key (int key); void M_SinglePlayer_Key (int key); void M_Load_Key (int key); void M_Save_Key (int key); void M_MultiPlayer_Key (int key); void M_ServerList_Key (int key); void M_SEdit_Key (int key); void M_Setup_Key (int key); void M_Demos_Key (int key); void M_GameOptions_Key (int key); void M_Options_Key (int key); void M_Keys_Key (int key); void M_Fps_Key (int key); void M_Video_Key (int key); void M_Help_Key (int key); void M_Quit_Key (int key); qboolean m_entersound; // play after drawing a frame, so caching // won't disrupt the sound qboolean m_recursiveDraw; int m_topmenu; // set if a submenu was entered via a // menu_* command //============================================================================= /* Support Routines */ #ifdef GLQUAKE cvar_t scr_scaleMenu = {"scr_scaleMenu","1"}; int menuwidth = 320; int menuheight = 240; #else #define menuwidth vid.width #define menuheight vid.height #endif cvar_t scr_centerMenu = {"scr_centerMenu","1"}; int m_yofs = 0; void M_DrawCharacter (int cx, int line, int num) { Draw_Character (cx + ((menuwidth - 320)>>1), line + m_yofs, num); } void M_Print (int cx, int cy, char *str) { Draw_Alt_String (cx + ((menuwidth - 320)>>1), cy + m_yofs, str); } void M_PrintWhite (int cx, int cy, char *str) { Draw_String (cx + ((menuwidth - 320)>>1), cy + m_yofs, str); } void M_DrawTransPic (int x, int y, mpic_t *pic) { Draw_TransPic (x + ((menuwidth - 320)>>1), y + m_yofs, pic); } void M_DrawPic (int x, int y, mpic_t *pic) { Draw_Pic (x + ((menuwidth - 320)>>1), y + m_yofs, pic); } byte identityTable[256]; byte translationTable[256]; void M_BuildTranslationTable(int top, int bottom) { int j; byte *dest, *source; for (j = 0; j < 256; j++) identityTable[j] = j; dest = translationTable; source = identityTable; memcpy (dest, source, 256); if (top < 128) // the artists made some backwards ranges. sigh. memcpy (dest + TOP_RANGE, source + top, 16); else for (j = 0; j < 16; j++) dest[TOP_RANGE + j] = source[top + 15 - j]; if (bottom < 128) memcpy (dest + BOTTOM_RANGE, source + bottom, 16); else for (j = 0; j < 16; j++) dest[BOTTOM_RANGE + j] = source[bottom + 15 - j]; } void M_DrawTransPicTranslate (int x, int y, mpic_t *pic) { Draw_TransPicTranslate (x + ((menuwidth - 320) >> 1), y + m_yofs, pic, translationTable); } void M_DrawTextBox (int x, int y, int width, int lines) { Draw_TextBox (x + ((menuwidth - 320) >> 1), y + m_yofs, width, lines); } //============================================================================= void M_ToggleMenu_f (void) { m_entersound = true; if (key_dest == key_menu) { if (m_state != m_main) { M_Menu_Main_f (); return; } key_dest = key_game; m_state = m_none; return; } else { M_Menu_Main_f (); } } void M_EnterMenu (int state) { if (key_dest != key_menu) { m_topmenu = state; Con_ClearNotify (); // hide the console scr_conlines = 0; scr_con_current = 0; } else { m_topmenu = m_none; } key_dest = key_menu; m_state = state; m_entersound = true; } void M_LeaveMenu (int parent) { if (m_topmenu == m_state) { m_state = m_none; key_dest = key_game; } else { m_state = parent; m_entersound = true; } } //============================================================================= /* MAIN MENU */ int m_main_cursor; #define MAIN_ITEMS 5 void M_Menu_Main_f (void) { M_EnterMenu (m_main); } void M_Main_Draw (void) { int f; mpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/ttl_main.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") ); f = (int)(curtime * 10)%6; M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); } void M_Main_Key (int key) { switch (key) { case K_ESCAPE: key_dest = key_game; m_state = m_none; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_main_cursor < 0) m_main_cursor = MAIN_ITEMS - 1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_main_cursor >= MAIN_ITEMS) m_main_cursor = 0; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); m_main_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); m_main_cursor = MAIN_ITEMS - 1; break; case K_ENTER: m_entersound = true; switch (m_main_cursor) { case 0: M_Menu_SinglePlayer_f (); break; case 1: M_Menu_MultiPlayer_f (); break; case 2: M_Menu_Options_f (); break; #if defined(_WIN32) || defined(__XMMS__) case 3: M_Menu_MP3_Control_f (); break; #endif case 4: M_Menu_Quit_f (); break; } } } //============================================================================= /* OPTIONS MENU */ #define OPTIONS_ITEMS 18 #define SLIDER_RANGE 10 int options_cursor; void M_Menu_Options_f (void) { M_EnterMenu (m_options); } void M_AdjustSliders (int dir) { S_LocalSound ("misc/menu3.wav"); switch (options_cursor) { case 3: // screen size scr_viewsize.value += dir * 10; if (scr_viewsize.value < 30) scr_viewsize.value = 30; if (scr_viewsize.value > 120) scr_viewsize.value = 120; Cvar_SetValue (&scr_viewsize, scr_viewsize.value); break; case 4: // gamma v_gamma.value -= dir * 0.05; if (v_gamma.value < 0.5) v_gamma.value = 0.5; if (v_gamma.value > 1) v_gamma.value = 1; Cvar_SetValue (&v_gamma, v_gamma.value); break; case 5: // contrast v_contrast.value += dir * 0.1; if (v_contrast.value < 1) v_contrast.value = 1; if (v_contrast.value > 2) v_contrast.value = 2; Cvar_SetValue (&v_contrast, v_contrast.value); break; case 6: // mouse speed sensitivity.value += dir * 0.5; if (sensitivity.value < 1) sensitivity.value = 1; if (sensitivity.value > 11) sensitivity.value = 11; Cvar_SetValue (&sensitivity, sensitivity.value); break; case 7: // music volume #ifdef _WIN32 bgmvolume.value += dir * 1.0; #else bgmvolume.value += dir * 0.1; #endif if (bgmvolume.value < 0) bgmvolume.value = 0; if (bgmvolume.value > 1) bgmvolume.value = 1; Cvar_SetValue (&bgmvolume, bgmvolume.value); break; case 8: // sfx volume s_volume.value += dir * 0.1; if (s_volume.value < 0) s_volume.value = 0; if (s_volume.value > 1) s_volume.value = 1; Cvar_SetValue (&s_volume, s_volume.value); break; case 9: // always run if (cl_forwardspeed.value > 200) { Cvar_SetValue (&cl_forwardspeed, 200); Cvar_SetValue (&cl_backspeed, 200); } else { Cvar_SetValue (&cl_forwardspeed, 400); Cvar_SetValue (&cl_backspeed, 400); } break; case 10: // mouse look Cvar_SetValue (&freelook, !freelook.value); break; case 11: // invert mouse Cvar_SetValue (&m_pitch, -m_pitch.value); break; case 12: // lookstrafe Cvar_SetValue (&lookstrafe, !lookstrafe.value); break; case 13: Cvar_SetValue (&cl_sbar, !cl_sbar.value); break; case 14: Cvar_SetValue (&cl_hudswap, !cl_hudswap.value); break; #ifndef NO_WINDOWED_MOUSE case 17: // _windowed_mouse Cvar_SetValue (&_windowed_mouse, !_windowed_mouse.value); break; #endif } } void M_DrawSlider (int x, int y, float range) { int i; range = bound(0, range, 1); M_DrawCharacter (x-8, y, 128); for (i=0 ; iwidth)/2, 4, p); M_Print (16, 32, " Customize controls"); M_Print (16, 40, " Go to console"); M_Print (16, 48, " Reset to defaults"); M_Print (16, 56, " Screen size"); r = (scr_viewsize.value - 30) / (120 - 30); M_DrawSlider (220, 56, r); M_Print (16, 64, " Gamma"); r = (1.0 - v_gamma.value) / 0.5; M_DrawSlider (220, 64, r); M_Print (16, 72, " Contrast"); r = v_contrast.value - 1.0; M_DrawSlider (220, 72, r); M_Print (16, 80, " Mouse speed"); r = (sensitivity.value - 1)/10; M_DrawSlider (220, 80, r); M_Print (16, 88, " CD music volume"); r = bgmvolume.value; M_DrawSlider (220, 88, r); M_Print (16, 96, " Sound volume"); r = s_volume.value; M_DrawSlider (220, 96, r); M_Print (16, 104, " Always run"); M_DrawCheckbox (220, 104, cl_forwardspeed.value > 200); M_Print (16, 112, " Mouse look"); M_DrawCheckbox (220, 112, freelook.value); M_Print (16, 120, " Invert mouse"); M_DrawCheckbox (220, 120, m_pitch.value < 0); M_Print (16, 128, " Lookstrafe"); M_DrawCheckbox (220, 128, lookstrafe.value); M_Print (16, 136, " Use old status bar"); M_DrawCheckbox (220, 136, cl_sbar.value); M_Print (16, 144, " HUD on left side"); M_DrawCheckbox (220, 144, cl_hudswap.value); M_Print (16, 152, " FPS settings"); if (vid_menudrawfn) M_Print (16, 160, " Video modes"); #ifdef _WIN32 if (modestate == MS_WINDOWED) #else if (vid_windowedmouse) #endif { M_Print (16, 168, " Use mouse"); M_DrawCheckbox (220, 168, _windowed_mouse.value); } // cursor M_DrawCharacter (200, 32 + options_cursor * 8, 12 + ((int)(curtime * 4) & 1)); } void M_Options_Key (int k) { switch (k) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_main); break; case K_ENTER: m_entersound = true; switch (options_cursor) { case 0: M_Menu_Keys_f (); break; case 1: m_state = m_none; key_dest = key_console; // Con_ToggleConsole_f (); break; case 2: Cbuf_AddText ("exec default.cfg\n"); break; case 15: M_Menu_Fps_f (); break; case 16: M_Menu_Video_f (); break; default: M_AdjustSliders (1); break; } return; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); options_cursor--; if (options_cursor < 0) options_cursor = OPTIONS_ITEMS - 1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); options_cursor++; if (options_cursor >= OPTIONS_ITEMS) options_cursor = 0; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); options_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); options_cursor = OPTIONS_ITEMS - 1; break; case K_LEFTARROW: M_AdjustSliders (-1); break; case K_RIGHTARROW: M_AdjustSliders (1); break; } if (k == K_UPARROW || k == K_END || k == K_PGDN) { #ifdef _WIN32 if (options_cursor == 17 && modestate != MS_WINDOWED) #else if (options_cursor == 17 && !vid_windowedmouse) #endif options_cursor = 16; if (options_cursor == 16 && vid_menudrawfn == NULL) options_cursor = 15; } else { if (options_cursor == 16 && vid_menudrawfn == NULL) options_cursor = 17; #ifdef _WIN32 if (options_cursor == 17 && modestate != MS_WINDOWED) #else if (options_cursor == 17 && !vid_windowedmouse) #endif options_cursor = 0; } } //============================================================================= /* KEYS MENU */ char *bindnames[][2] = { {"+attack", "attack"}, {"+use", "use"}, {"+jump", "jump"}, {"+forward", "move forward"}, {"+back", "move back"}, {"+moveleft", "move left"}, {"+moveright", "move right"}, {"+moveup", "swim up"}, {"+movedown", "swim down"}, {"impulse 12", "previous weapon"}, {"impulse 10", "next weapon"}, {"+speed", "run"}, {"+left", "turn left"}, {"+right", "turn right"}, {"+lookup", "look up"}, {"+lookdown", "look down"}, {"centerview", "center view"}, }; #define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0])) int keys_cursor; int bind_grab; void M_Menu_Keys_f (void) { M_EnterMenu (m_keys); } qboolean Key_IsLeftRightSameBind(int b); void M_FindKeysForCommand (char *command, int *twokeys) { int count, j, l; char *b; twokeys[0] = twokeys[1] = -1; l = strlen(command); count = 0; for (j = 0 ; j < 256; j++) { b = keybindings[j]; if (!b) continue; if (!strncmp (b, command, l) ) { if (count) { if (j == twokeys[0] + 1 && (twokeys[0] == K_LCTRL || twokeys[0] == K_LSHIFT || twokeys[0] == K_LALT)) { twokeys[0]--; continue; } } twokeys[count] = j; count++; if (count == 2) { if (Key_IsLeftRightSameBind(twokeys[1])) twokeys[1]++; break; } } } } void M_UnbindCommand (char *command) { int j, l; char *b; l = strlen(command); for (j = 0; j < 256; j++) { b = keybindings[j]; if (!b) continue; if (!strncmp (b, command, l) ) Key_Unbind (j); } } void M_Keys_Draw (void) { int x, y, i, l, keys[2]; char *name; mpic_t *p; p = Draw_CachePic ("gfx/ttl_cstm.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); if (bind_grab) M_Print (12, 32, "Press a key or button for this action"); else M_Print (18, 32, "Enter to change, del to clear"); // search for known bindings for (i = 0; i < NUMCOMMANDS; i++) { y = 48 + 8*i; M_Print (16, y, bindnames[i][1]); l = strlen (bindnames[i][0]); M_FindKeysForCommand (bindnames[i][0], keys); if (keys[0] == -1) { M_Print (156, y, "???"); } else { name = Key_KeynumToString (keys[0]); M_Print (156, y, name); x = strlen(name) * 8; if (keys[1] != -1) { M_Print (156 + x + 8, y, "or"); M_Print (156 + x + 32, y, Key_KeynumToString (keys[1])); } } } if (bind_grab) M_DrawCharacter (142, 48 + keys_cursor*8, '='); else M_DrawCharacter (142, 48 + keys_cursor*8, 12+((int)(curtime*4)&1)); } void M_Keys_Key (int k) { int keys[2]; if (bind_grab) { // defining a key S_LocalSound ("misc/menu1.wav"); if (k == K_ESCAPE) bind_grab = false; else if (k != '`') Key_SetBinding (k, bindnames[keys_cursor][0]); bind_grab = false; return; } switch (k) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_options); break; case K_LEFTARROW: case K_UPARROW: S_LocalSound ("misc/menu1.wav"); keys_cursor--; if (keys_cursor < 0) keys_cursor = NUMCOMMANDS-1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); keys_cursor++; if (keys_cursor >= NUMCOMMANDS) keys_cursor = 0; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); keys_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); keys_cursor = NUMCOMMANDS - 1; break; case K_ENTER: // go into bind mode M_FindKeysForCommand (bindnames[keys_cursor][0], keys); S_LocalSound ("misc/menu2.wav"); if (keys[1] != -1) M_UnbindCommand (bindnames[keys_cursor][0]); bind_grab = true; break; case K_DEL: // delete bindings S_LocalSound ("misc/menu2.wav"); M_UnbindCommand (bindnames[keys_cursor][0]); break; } } //============================================================================= /* FPS SETTINGS MENU */ #define FPS_ITEMS 15 int fps_cursor = 0; extern cvar_t v_bonusflash; extern cvar_t cl_rocket2grenade; extern cvar_t v_damagecshift; extern cvar_t r_fastsky; extern cvar_t r_drawflame; extern cvar_t gl_part_inferno; void M_Menu_Fps_f (void) { M_EnterMenu (m_fps); } #define ALIGN_FPS_OPTIONS 208 void M_Fps_Draw (void) { mpic_t *p; char temp[32]; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp")); p = Draw_CachePic ("gfx/ttl_cstm.lmp"); M_DrawPic ((320-p->width)/ 2, 4, p); M_Print (16, 32, " Explosions"); switch ((int) r_explosiontype.value) { case 0 : strcpy(temp, "fire + sparks"); break; case 1 : strcpy(temp, "fire only"); break; case 2 : strcpy(temp, "teleport"); break; case 3 : strcpy(temp, "blood"); break; case 4 : strcpy(temp, "big blood"); break; case 5 : strcpy(temp, "dbl gunshot"); break; case 6 : strcpy(temp, "blob effect"); break; case 7 : strcpy(temp, "big explosion"); break; default : strcpy(temp, "fire + sparks"); break; } M_Print (ALIGN_FPS_OPTIONS, 32, temp); M_Print (16, 40, " Muzzleflashes"); M_Print (ALIGN_FPS_OPTIONS, 40, cl_muzzleflash.value == 2 ? "own off" : cl_muzzleflash.value ? "on" : "off"); M_Print (16, 48, " Gib filter"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 48, cl_gibfilter.value); M_Print (16, 56, " Dead body filter"); M_Print (ALIGN_FPS_OPTIONS, 56, cl_deadbodyfilter.value == 2 ? "on (instant)" : cl_deadbodyfilter.value ? "on (normal)" : "off"); M_Print (16, 64, " Rocket model"); M_Print (ALIGN_FPS_OPTIONS, 64, cl_rocket2grenade.value ? "grenade" : "normal"); switch ((int) r_rockettrail.value) { case 0 : strcpy(temp, "off"); break; case 1 : strcpy(temp, "normal"); break; case 2 : strcpy(temp, "grenade"); break; case 3 : strcpy(temp, "alt normal"); break; case 4 : strcpy(temp, "slight blood"); break; case 5 : strcpy(temp, "big blood"); break; case 6 : strcpy(temp, "tracer 1"); break; case 7 : strcpy(temp, "tracer 2"); break; default : strcpy(temp, "normal"); break; } M_Print (16, 72, " Rocket trail"); M_Print (ALIGN_FPS_OPTIONS, 72, temp); M_Print (16, 80, " Rocket light"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 80, r_rocketlight.value); M_Print (16, 88, " Damage filter"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 88, v_damagecshift.value == 0); M_Print (16, 96, " Pickup flashes"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 96, v_bonusflash.value); M_Print (16, 104, " Powerup glow"); M_Print (ALIGN_FPS_OPTIONS, 104, r_powerupglow.value==2 ? "own off" : r_powerupglow.value ? "on" : "off"); M_Print (16, 112, " Draw torches"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 112, r_drawflame.value); M_Print (16, 120, " Fast sky"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 120, r_fastsky.value); #ifdef GLQUAKE M_Print (16, 128, " Fast lights"); M_DrawCheckbox (ALIGN_FPS_OPTIONS, 128, gl_flashblend.value); #endif M_PrintWhite (16, 136, " Fast mode"); M_PrintWhite (16, 144, " High quality"); // cursor M_DrawCharacter (196, 32 + fps_cursor * 8, 12 + ((int) (curtime * 4) & 1)); } void M_Fps_Key (int k) { int i; switch (k) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_options); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); fps_cursor--; #ifndef GLQUAKE if (fps_cursor == 12) fps_cursor = 11; #endif if (fps_cursor < 0) fps_cursor = FPS_ITEMS - 1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); fps_cursor++; #ifndef GLQUAKE if (fps_cursor == 12) fps_cursor = 13; #endif if (fps_cursor >= FPS_ITEMS) fps_cursor = 0; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); fps_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); fps_cursor = FPS_ITEMS - 1; break; case K_RIGHTARROW: case K_ENTER: S_LocalSound ("misc/menu2.wav"); switch (fps_cursor) { case 0: i = r_explosiontype.value + 1; if (i > 7 || i < 0) i = 0; Cvar_SetValue (&r_explosiontype, i); break; case 1: Cvar_SetValue (&cl_muzzleflash, cl_muzzleflash.value == 2 ? 1 : cl_muzzleflash.value ? 0 : 2); break; case 2: Cvar_SetValue (&cl_gibfilter, !cl_gibfilter.value); break; case 3: Cvar_SetValue (&cl_deadbodyfilter, cl_deadbodyfilter.value == 2 ? 1 : cl_deadbodyfilter.value ? 0 : 2); break; case 4: Cvar_SetValue (&cl_rocket2grenade, !cl_rocket2grenade.value); break; case 5: i = r_rockettrail.value + 1; if (i < 0 || i > 7) i = 0; Cvar_SetValue (&r_rockettrail, i); break; case 6: Cvar_SetValue (&r_rocketlight, !r_rocketlight.value); break; case 7: Cvar_SetValue (&v_damagecshift, !v_damagecshift.value); break; case 8: Cvar_SetValue (&v_bonusflash, !v_bonusflash.value); break; case 9: i = r_powerupglow.value + 1; if (i < 0 || i > 2) i = 0; Cvar_SetValue (&r_powerupglow, i); break; case 10: Cvar_SetValue (&r_drawflame, !r_drawflame.value); break; case 11: Cvar_SetValue (&r_fastsky, !r_fastsky.value); break; #ifdef GLQUAKE case 12: Cvar_SetValue (&gl_flashblend, !gl_flashblend.value); Cvar_SetValue (&r_dynamic, gl_flashblend.value); break; #endif // fast case 13: Cvar_SetValue (&r_explosiontype, 1); Cvar_SetValue (&r_explosionlight, 0); Cvar_SetValue (&cl_muzzleflash, 0); Cvar_SetValue (&cl_gibfilter, 1); Cvar_SetValue (&cl_deadbodyfilter, 1); Cvar_SetValue (&r_rocketlight, 0); Cvar_SetValue (&r_powerupglow, 0); Cvar_SetValue (&r_drawflame, 0); Cvar_SetValue (&r_fastsky, 1); Cvar_SetValue (&r_rockettrail, 1); Cvar_SetValue (&v_damagecshift, 0); #ifdef GLQUAKE Cvar_SetValue (&gl_flashblend, 1); Cvar_SetValue (&r_dynamic, 0); Cvar_SetValue (&gl_part_explosions, 0); Cvar_SetValue (&gl_part_trails, 0); Cvar_SetValue (&gl_part_spikes, 0); Cvar_SetValue (&gl_part_gunshots, 0); Cvar_SetValue (&gl_part_blood, 0); Cvar_SetValue (&gl_part_telesplash, 0); Cvar_SetValue (&gl_part_blobs, 0); Cvar_SetValue (&gl_part_lavasplash, 0); Cvar_SetValue (&gl_part_inferno, 0); #endif break; // high quality case 14: Cvar_SetValue (&r_explosiontype, 0); Cvar_SetValue (&r_explosionlight, 1); Cvar_SetValue (&cl_muzzleflash, 1); Cvar_SetValue (&cl_gibfilter, 0); Cvar_SetValue (&cl_deadbodyfilter, 0); Cvar_SetValue (&r_rocketlight, 1); Cvar_SetValue (&r_powerupglow, 2); Cvar_SetValue (&r_drawflame, 1); Cvar_SetValue (&r_fastsky, 0); Cvar_SetValue (&r_rockettrail, 1); Cvar_SetValue (&v_damagecshift, 1); #ifdef GLQUAKE Cvar_SetValue (&gl_flashblend, 0); Cvar_SetValue (&r_dynamic, 1); Cvar_SetValue (&gl_part_explosions, 1); Cvar_SetValue (&gl_part_trails, 1); Cvar_SetValue (&gl_part_spikes, 1); Cvar_SetValue (&gl_part_gunshots, 1); Cvar_SetValue (&gl_part_blood, 1); Cvar_SetValue (&gl_part_telesplash, 1); Cvar_SetValue (&gl_part_blobs, 1); Cvar_SetValue (&gl_part_lavasplash, 1); Cvar_SetValue (&gl_part_inferno, 1); #endif } } } //============================================================================= /* VIDEO MENU */ void M_Menu_Video_f (void) { M_EnterMenu (m_video); } void M_Video_Draw (void) { (*vid_menudrawfn) (); } void M_Video_Key (int key) { (*vid_menukeyfn) (key); } //============================================================================= /* HELP MENU */ int help_page; #define NUM_HELP_PAGES 6 void M_Menu_Help_f (void) { M_EnterMenu (m_help); help_page = 0; } void M_Help_Draw (void) { M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) ); } void M_Help_Key (int key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_main); break; case K_UPARROW: case K_RIGHTARROW: m_entersound = true; if (++help_page >= NUM_HELP_PAGES) help_page = 0; break; case K_DOWNARROW: case K_LEFTARROW: m_entersound = true; if (--help_page < 0) help_page = NUM_HELP_PAGES-1; break; } } //============================================================================= /* QUIT MENU */ int msgNumber; int m_quit_prevstate; qboolean wasInMenus; void M_Menu_Quit_f (void) { if (m_state == m_quit) return; wasInMenus = (key_dest == key_menu); m_quit_prevstate = m_state; msgNumber = rand()&7; M_EnterMenu (m_quit); } void M_Quit_Key (int key) { switch (key) { case K_ESCAPE: case 'n': case 'N': if (wasInMenus) { m_state = m_quit_prevstate; m_entersound = true; } else { key_dest = key_game; m_state = m_none; } break; case K_ENTER: case 'Y': case 'y': key_dest = key_console; Host_Quit (); break; default: break; } } //============================================================================= /* SINGLE PLAYER MENU */ #ifndef CLIENTONLY #define SINGLEPLAYER_ITEMS 3 int m_singleplayer_cursor; qboolean m_singleplayer_confirm; qboolean m_singleplayer_notavail; extern cvar_t maxclients; void M_Menu_SinglePlayer_f (void) { M_EnterMenu (m_singleplayer); m_singleplayer_confirm = false; m_singleplayer_notavail = false; } void M_SinglePlayer_Draw (void) { int f; mpic_t *p; if (m_singleplayer_notavail) { p = Draw_CachePic ("gfx/ttl_sgl.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTextBox (60, 10*8, 24, 4); M_PrintWhite (80, 12*8, " Cannot start a game"); M_PrintWhite (80, 13*8, "spprogs.dat not found"); return; } if (m_singleplayer_confirm) { M_PrintWhite (64, 11*8, "Are you sure you want to"); M_PrintWhite (64, 12*8, " start a new game?"); return; } M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/ttl_sgl.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") ); f = (int)(curtime * 10)%6; M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); } static void CheckSPGame (void) { FILE *f; FS_FOpenFile ("spprogs.dat", &f); if (f) { fclose (f); m_singleplayer_notavail = false; } else { m_singleplayer_notavail = true; } } extern int file_from_gamedir; static void StartNewGame (void) { key_dest = key_game; Cvar_Set (&maxclients, "1"); Cvar_Set (&teamplay, "0"); Cvar_Set (&deathmatch, "0"); Cvar_Set (&coop, "0"); if (com_serveractive) Cbuf_AddText ("disconnect\n"); progs = (dprograms_t *) FS_LoadHunkFile ("spprogs.dat"); Cbuf_AddText ("map start\n"); } void M_SinglePlayer_Key (int key) { if (m_singleplayer_notavail) { switch (key) { case K_BACKSPACE: case K_ESCAPE: case K_ENTER: m_singleplayer_notavail = false; break; } return; } if (m_singleplayer_confirm) { if (key == K_ESCAPE || key == 'n') { m_singleplayer_confirm = false; m_entersound = true; } else if (key == 'y' || key == K_ENTER) { StartNewGame (); } return; } switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_main); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS) m_singleplayer_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_singleplayer_cursor < 0) m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); m_singleplayer_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; break; case K_ENTER: switch (m_singleplayer_cursor) { case 0: CheckSPGame (); if (m_singleplayer_notavail) { m_entersound = true; return; } if (com_serveractive) { // bring up confirmation dialog m_singleplayer_confirm = true; m_entersound = true; } else { StartNewGame (); } break; case 1: M_Menu_Load_f (); break; case 2: M_Menu_Save_f (); break; } } } #else // !CLIENTONLY void M_Menu_SinglePlayer_f (void) { M_EnterMenu (m_singleplayer); } void M_SinglePlayer_Draw (void) { mpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/ttl_sgl.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); // M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") ); M_DrawTextBox (60, 10*8, 23, 4); M_PrintWhite (88, 12*8, "This client is for"); M_PrintWhite (88, 13*8, "Internet play only"); } void M_SinglePlayer_Key (key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: case K_ENTER: M_LeaveMenu (m_main); break; } } #endif // CLIENTONLY //============================================================================= /* LOAD/SAVE MENU */ #ifndef CLIENTONLY #define MAX_SAVEGAMES 12 int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH + 1]; int loadable[MAX_SAVEGAMES]; void M_ScanSaves (char *sp_gamedir) { int i, j, version; char name[MAX_OSPATH]; FILE *f; for (i = 0; i < MAX_SAVEGAMES; i++) { strcpy (m_filenames[i], "--- UNUSED SLOT ---"); loadable[i] = false; Q_snprintfz (name, sizeof(name), "%s/save/s%i.sav", sp_gamedir, i); if (!(f = fopen (name, "r"))) continue; fscanf (f, "%i\n", &version); fscanf (f, "%79s\n", name); Q_strncpyz (m_filenames[i], name, sizeof(m_filenames[i])); // change _ back to space for (j = 0; j < SAVEGAME_COMMENT_LENGTH; j++) if (m_filenames[i][j] == '_') m_filenames[i][j] = ' '; loadable[i] = true; fclose (f); } } void M_Menu_Load_f (void) { FILE *f; if (FS_FOpenFile ("spprogs.dat", &f) == -1) return; M_EnterMenu (m_load); M_ScanSaves (com_gamedir); } void M_Menu_Save_f (void) { if (sv.state != ss_active) return; if (cl.intermission) return; M_EnterMenu (m_save); M_ScanSaves (com_gamedir); } void M_Load_Draw (void) { int i; mpic_t *p; p = Draw_CachePic ("gfx/p_load.lmp"); M_DrawPic ( (320 - p->width) >> 1, 4, p); for (i = 0; i < MAX_SAVEGAMES; i++) M_Print (16, 32 + 8*i, m_filenames[i]); // line cursor M_DrawCharacter (8, 32 + load_cursor * 8, 12 + ((int)(curtime * 4) & 1)); } void M_Save_Draw (void) { int i; mpic_t *p; p = Draw_CachePic ("gfx/p_save.lmp"); M_DrawPic ( (320 - p->width) >> 1, 4, p); for (i = 0; i < MAX_SAVEGAMES; i++) M_Print (16, 32 + 8 * i, m_filenames[i]); // line cursor M_DrawCharacter (8, 32 + load_cursor * 8, 12 + ((int)(curtime * 4) & 1)); } void M_Load_Key (int key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_singleplayer); break; case K_ENTER: S_LocalSound ("misc/menu2.wav"); if (!loadable[load_cursor]) return; m_state = m_none; key_dest = key_game; // issue the load command if (FS_LoadHunkFile ("spprogs.dat") && !file_from_gamedir) Cbuf_AddText("disconnect\n"); Cbuf_AddText (va ("load s%i\n", load_cursor) ); return; case K_UPARROW: case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor--; if (load_cursor < 0) load_cursor = MAX_SAVEGAMES - 1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor++; if (load_cursor >= MAX_SAVEGAMES) load_cursor = 0; break; } } void M_Save_Key (int key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_singleplayer); break; case K_ENTER: m_state = m_none; key_dest = key_game; Cbuf_AddText (va("save s%i\n", load_cursor)); return; case K_UPARROW: case K_LEFTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor--; if (load_cursor < 0) load_cursor = MAX_SAVEGAMES-1; break; case K_DOWNARROW: case K_RIGHTARROW: S_LocalSound ("misc/menu1.wav"); load_cursor++; if (load_cursor >= MAX_SAVEGAMES) load_cursor = 0; break; } } #endif //============================================================================= /* MULTIPLAYER MENU */ int m_multiplayer_cursor; #ifdef CLIENTONLY #define MULTIPLAYER_ITEMS 3 #else #define MULTIPLAYER_ITEMS 4 #endif void M_Menu_MultiPlayer_f (void) { M_EnterMenu (m_multiplayer); } void M_MultiPlayer_Draw (void) { mpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_Print (80, 40, "Server List"); M_Print (80, 48, "Player Setup"); M_Print (80, 56, "Demos"); #ifndef CLIENTONLY M_Print (80, 64, "New Game"); #endif // cursor M_DrawCharacter (64, 40 + m_multiplayer_cursor * 8, 12 + ((int) (curtime * 4) & 1)); } void M_MultiPlayer_Key (int key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_main); break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS) m_multiplayer_cursor = 0; break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (--m_multiplayer_cursor < 0) m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; break; case K_HOME: case K_PGUP: S_LocalSound ("misc/menu1.wav"); m_multiplayer_cursor = 0; break; case K_END: case K_PGDN: S_LocalSound ("misc/menu1.wav"); m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; break; case K_ENTER: m_entersound = true; switch (m_multiplayer_cursor) { case 0: M_Menu_ServerList_f (); break; case 1: M_Menu_Setup_f (); break; case 2: M_Menu_Demos_f (); break; #ifndef CLIENTONLY case 3: M_Menu_GameOptions_f (); break; #endif } } } //============================================================================= #if _WIN32 || defined(__XMMS__) #define M_MP3_CONTROL_HEADINGROW 8 #define M_MP3_CONTROL_MENUROW (M_MP3_CONTROL_HEADINGROW + 56) #define M_MP3_CONTROL_COL 104 #define M_MP3_CONTROL_NUMENTRIES 12 #define M_MP3_CONTROL_BARHEIGHT (200 - 24) static int mp3_cursor = 0; static int last_status; void MP3_Menu_DrawInfo(void); void M_Menu_MP3_Playlist_f(void); void M_MP3_Control_Draw (void) { char songinfo_scroll[38 + 1], *s = NULL; int i, scroll_index, print_time; float frac, elapsed, realtime; static char lastsonginfo[128], last_title[128]; static float initial_time; static int last_length, last_elapsed, last_total, last_shuffle, last_repeat; M_Print ((320 - 8 * strlen(MP3_PLAYERNAME_ALLCAPS " CONTROL")) >> 1, M_MP3_CONTROL_HEADINGROW, MP3_PLAYERNAME_ALLCAPS " CONTROL"); M_Print (8, M_MP3_CONTROL_HEADINGROW + 16, "\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f"); if (!MP3_IsActive()) { M_PrintWhite((320 - 24 * 8) >> 1, M_MP3_CONTROL_HEADINGROW + 40, "XMMS LIBRARIES NOT FOUND"); return; } realtime = Sys_DoubleTime(); last_status = MP3_GetStatus(); if (last_status == MP3_PLAYING) M_PrintWhite(312 - 7 * 8, M_MP3_CONTROL_HEADINGROW + 8, "Playing"); else if (last_status == MP3_PAUSED) M_PrintWhite(312 - 6 * 8, M_MP3_CONTROL_HEADINGROW + 8, "Paused"); else if (last_status == MP3_STOPPED) M_PrintWhite(312 - 7 * 8, M_MP3_CONTROL_HEADINGROW + 8, "Stopped"); else M_PrintWhite(312 - 11 * 8, M_MP3_CONTROL_HEADINGROW + 8, "Not Running"); if (last_status == MP3_NOTRUNNING) { M_Print ((320 - 8 * strlen(MP3_PLAYERNAME_ALLCAPS " is not running")) >> 1, 40, MP3_PLAYERNAME_LEADINGCAP " is not running"); M_PrintWhite (56, 72, "Press"); M_Print (56 + 48, 72, "ENTER"); M_PrintWhite (56 + 48 + 48, 72, "to start " MP3_PLAYERNAME_NOCAPS); M_PrintWhite (56, 84, "Press"); M_Print (56 + 48, 84, "ESC"); M_PrintWhite (56 + 48 + 32, 84, "to exit this menu"); M_Print (16, 116, "The variable"); M_PrintWhite (16 + 104, 116, mp3_dir.name); M_Print (16 + 104 + 8 * (strlen(mp3_dir.name) + 1), 116, "needs to"); M_Print (20, 124, "be set to the path for " MP3_PLAYERNAME_NOCAPS " first"); return; } s = MP3_Menu_SongtTitle(); if (!strcmp(last_title, s = MP3_Menu_SongtTitle())) { elapsed = 3.5 * max(realtime - initial_time - 0.75, 0); scroll_index = (int) elapsed; frac = bound(0, elapsed - scroll_index, 1); scroll_index = scroll_index % last_length; } else { Q_snprintfz(lastsonginfo, sizeof(lastsonginfo), "%s *** ", s); Q_strncpyz(last_title, s, sizeof(last_title)); last_length = strlen(lastsonginfo); initial_time = realtime; frac = scroll_index = 0; } if ((!mp3_scrolltitle.value || last_length <= 38 + 7) && mp3_scrolltitle.value != 2) { char name[38 + 1]; Q_strncpyz(name, last_title, sizeof(name)); M_PrintWhite(max(8, (320 - (last_length - 7) * 8) >> 1), M_MP3_CONTROL_HEADINGROW + 32, name); initial_time = realtime; } else { for (i = 0; i < sizeof(songinfo_scroll) - 1; i++) songinfo_scroll[i] = lastsonginfo[(scroll_index + i) % last_length]; songinfo_scroll[sizeof(songinfo_scroll) - 1] = 0; M_PrintWhite(12 - (int) (8 * frac), M_MP3_CONTROL_HEADINGROW + 32, songinfo_scroll); } if (mp3_showtime.value) { MP3_GetOutputtime(&last_elapsed, &last_total); if (last_total == -1) goto menu_items; print_time = (mp3_showtime.value == 2) ? last_total - last_elapsed : last_elapsed; M_PrintWhite(8, M_MP3_CONTROL_HEADINGROW + 8, SecondsToMinutesString(print_time)); if (mp3_showtime.value != 2) M_PrintWhite(48, M_MP3_CONTROL_HEADINGROW + 8, va("/%s", SecondsToMinutesString(last_total))); } menu_items: M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW, "Play"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 8, last_status == MP3_PAUSED ? "Unpause" : "Pause"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 16, "Stop"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 24, "Next Track"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 32, "Prev Track"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 40, "Fast Forwd"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 48, "Rewind"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 56, "Volume"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 64, "Shuffle"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 72, "Repeat"); M_Print (M_MP3_CONTROL_COL, M_MP3_CONTROL_MENUROW + 88, "View Playlist"); M_DrawCharacter (M_MP3_CONTROL_COL - 8, M_MP3_CONTROL_MENUROW + mp3_cursor * 8, 12 + ((int)(curtime * 4) & 1)); if (mp3_volumectrl_active) M_DrawSlider(M_MP3_CONTROL_COL + 96, M_MP3_CONTROL_MENUROW + 56, bound(0, mp3_volume.value, 1)); else M_PrintWhite (M_MP3_CONTROL_COL + 88, M_MP3_CONTROL_MENUROW + 56, "Disabled");; MP3_GetToggleState(&last_shuffle, &last_repeat); M_PrintWhite (M_MP3_CONTROL_COL + 88, M_MP3_CONTROL_MENUROW + 64, last_shuffle ? "On" : "Off"); M_PrintWhite (M_MP3_CONTROL_COL + 88, M_MP3_CONTROL_MENUROW + 72, last_repeat ? "On" : "Off"); M_DrawCharacter (16, M_MP3_CONTROL_BARHEIGHT, 128); for (i = 0; i < 35; i++) M_DrawCharacter (24 + i * 8, M_MP3_CONTROL_BARHEIGHT, 129); M_DrawCharacter (320 - 16, M_MP3_CONTROL_BARHEIGHT, 130); M_DrawCharacter (17 + 286 * ((float) last_elapsed / last_total), M_MP3_CONTROL_BARHEIGHT, 131); } void M_Menu_MP3_Control_Key(int key) { float volume; if (!MP3_IsActive() || last_status == MP3_NOTRUNNING) { switch(key) { case K_BACKSPACE: m_topmenu = m_none; case K_ESCAPE: M_LeaveMenu (m_main); break; case K_ENTER: if (MP3_IsActive()) MP3_Execute_f(); break; } return; } con_suppress = true; switch (key) { case K_BACKSPACE: m_topmenu = m_none; case K_ESCAPE: M_LeaveMenu (m_main); break; case K_HOME: case K_PGUP: mp3_cursor = 0; break; case K_END: case K_PGDN: mp3_cursor = M_MP3_CONTROL_NUMENTRIES - 1; break; case K_DOWNARROW: if (mp3_cursor < M_MP3_CONTROL_NUMENTRIES - 1) mp3_cursor++; if (mp3_cursor == M_MP3_CONTROL_NUMENTRIES - 2) mp3_cursor++; break; case K_UPARROW: if (mp3_cursor > 0) mp3_cursor--; if (mp3_cursor == M_MP3_CONTROL_NUMENTRIES - 2) mp3_cursor--; break; case K_ENTER: switch (mp3_cursor) { case 0: MP3_Play_f(); break; case 1: MP3_Pause_f(); break; case 2: MP3_Stop_f(); break; case 3: MP3_Next_f(); break; case 4: MP3_Prev_f(); break; case 5: MP3_FastForward_f(); break; case 6: MP3_Rewind_f(); break; case 7: break; case 8: MP3_ToggleShuffle_f(); break; case 9: MP3_ToggleRepeat_f(); break; case 10: break; case 11: M_Menu_MP3_Playlist_f(); break; } break; case K_RIGHTARROW: switch(mp3_cursor) { case 7: volume = bound(0, mp3_volume.value, 1); Cvar_SetValue(&mp3_volume, bound(0, volume + 0.02, 1)); break; default: MP3_FastForward_f(); break; } break; case K_LEFTARROW: switch(mp3_cursor) { case 7: volume = bound(0, mp3_volume.value, 1); Cvar_SetValue(&mp3_volume, bound(0, volume - 0.02, 1)); break; default: MP3_Rewind_f(); break; } break; case 'r': MP3_ToggleRepeat_f(); break; case 's': MP3_ToggleShuffle_f(); break; case KP_LEFTARROW: case 'z': MP3_Prev_f(); break; case KP_5: case 'x': MP3_Play_f(); break; case 'c': MP3_Pause_f(); break; case 'v': MP3_Stop_f(); break; case 'V': MP3_FadeOut_f(); break; case KP_RIGHTARROW: case 'b': MP3_Next_f(); break; case KP_HOME: MP3_Rewind_f(); break; case KP_PGUP: MP3_FastForward_f(); break; } con_suppress = false; } void M_Menu_MP3_Control_f (void){ M_EnterMenu (m_mp3_control); } #define PLAYLIST_MAXENTRIES 2048 #define PLAYLIST_MAXLINES 17 #define PLAYLIST_HEADING_ROW 8 #define PLAYLIST_MAXTITLE (32 + 1) static int playlist_size = 0; static int playlist_cursor = 0, playlist_base = 0; static void Center_Playlist(void) { int current; MP3_GetPlaylistInfo(¤t, NULL); if (current >= 0 && current < playlist_size) { if (playlist_size - current - 1 < (PLAYLIST_MAXLINES >> 1)) { playlist_base = max(0, playlist_size - PLAYLIST_MAXLINES); playlist_cursor = current - playlist_base; } else { playlist_base = max(0, current - (PLAYLIST_MAXLINES >> 1)); playlist_cursor = current - playlist_base; } } } static char *playlist_entries[PLAYLIST_MAXENTRIES]; #ifdef _WIN32 void M_Menu_MP3_Playlist_Read(void) { int i, count = 0, skip = 0; long length; char *playlist_buf = NULL; for (i = 0; i < playlist_size; i++) { if (playlist_entries[i]) { free(playlist_entries[i]); playlist_entries[i] = NULL; } } playlist_base = playlist_cursor = playlist_size = 0; if ((length = MP3_GetPlaylist(&playlist_buf)) == -1) return; playlist_size = MP3_ParsePlaylist_EXTM3U(playlist_buf, length, playlist_entries, PLAYLIST_MAXENTRIES, PLAYLIST_MAXTITLE); free(playlist_buf); } #else void M_Menu_MP3_Playlist_Read(void) { int i; char *title; for (i = 0; i < playlist_size; i++) { if (playlist_entries[i]) { free(playlist_entries[i]); playlist_entries[i] = NULL; } } playlist_base = playlist_cursor = playlist_size = 0; if (MP3_GetStatus() == MP3_NOTRUNNING) return; playlist_size = qxmms_remote_get_playlist_length(XMMS_SESSION); for (i = 0; i < PLAYLIST_MAXENTRIES && i < playlist_size; i++) { title = qxmms_remote_get_playlist_title(XMMS_SESSION, i); if (strlen(title) > PLAYLIST_MAXTITLE) title[PLAYLIST_MAXTITLE] = 0; playlist_entries[i] = strdup(title); g_free(title); } } #endif void M_Menu_MP3_Playlist_Draw(void) { int index, print_time, i; char name[PLAYLIST_MAXTITLE]; float realtime; static int last_status,last_elapsed, last_total, last_current; realtime = Sys_DoubleTime(); last_status = MP3_GetStatus(); if (last_status == MP3_NOTRUNNING) { M_Menu_MP3_Control_f(); return; } M_Print ((320 - 8 * strlen(MP3_PLAYERNAME_ALLCAPS " PLAYLIST")) >> 1, PLAYLIST_HEADING_ROW, MP3_PLAYERNAME_ALLCAPS " PLAYLIST"); M_Print (8, PLAYLIST_HEADING_ROW + 16, "\x1d\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f"); if (last_status == MP3_PLAYING) M_PrintWhite(312 - 7 * 8, PLAYLIST_HEADING_ROW + 8, "Playing"); else if (last_status == MP3_PAUSED) M_PrintWhite(312 - 6 * 8, PLAYLIST_HEADING_ROW + 8, "Paused"); else if (last_status == MP3_STOPPED) M_PrintWhite(312 - 7 * 8, PLAYLIST_HEADING_ROW + 8, "Stopped"); if (mp3_showtime.value) { MP3_GetOutputtime(&last_elapsed, &last_total); if (last_total == -1) goto menu_items; print_time = (mp3_showtime.value == 2) ? last_total - last_elapsed : last_elapsed; M_PrintWhite(8, PLAYLIST_HEADING_ROW + 8, SecondsToMinutesString(print_time)); if (mp3_showtime.value != 2) M_PrintWhite(48, M_MP3_CONTROL_HEADINGROW + 8, va("/%s", SecondsToMinutesString(last_total))); } menu_items: if (!playlist_size) { M_Print (92, 32, "Playlist is empty"); return; } MP3_GetPlaylistInfo(&last_current, NULL); for (index = playlist_base; index < playlist_size && index < playlist_base + PLAYLIST_MAXLINES; index++) { char *spaces; if (index + 1 < 10) spaces = " "; else if (index + 1 < 100) spaces = " "; else spaces = ""; Q_strncpyz(name, playlist_entries[index], sizeof(name)); if (last_current != index) M_Print (16, PLAYLIST_HEADING_ROW + 24 + (index - playlist_base) * 8, va("%s%d %s", spaces, index + 1, name)); else M_PrintWhite (16, PLAYLIST_HEADING_ROW + 24 + (index - playlist_base) * 8, va("%s%d %s", spaces, index + 1, name)); } M_DrawCharacter (8, PLAYLIST_HEADING_ROW + 24 + playlist_cursor * 8, 12 + ((int)(curtime * 4) & 1)); M_DrawCharacter (16, M_MP3_CONTROL_BARHEIGHT, 128); for (i = 0; i < 35; i++) M_DrawCharacter (24 + i * 8, M_MP3_CONTROL_BARHEIGHT, 129); M_DrawCharacter (320 - 16, M_MP3_CONTROL_BARHEIGHT, 130); M_DrawCharacter (17 + 286 * ((float) last_elapsed / last_total), M_MP3_CONTROL_BARHEIGHT, 131); } void M_Menu_MP3_Playlist_Key (int k) { con_suppress = true; switch (k) { case K_BACKSPACE: m_topmenu = m_none; case K_ESCAPE: M_LeaveMenu (m_mp3_control); break; case K_UPARROW: if (playlist_cursor > 0) playlist_cursor--; else if (playlist_base > 0) playlist_base--; break; case K_DOWNARROW: if (playlist_cursor + playlist_base < playlist_size - 1) { if (playlist_cursor < PLAYLIST_MAXLINES - 1) playlist_cursor++; else playlist_base++; } break; case K_HOME: playlist_cursor = 0; playlist_base = 0; break; case K_END: if (playlist_size > PLAYLIST_MAXLINES) { playlist_cursor = PLAYLIST_MAXLINES - 1; playlist_base = playlist_size - playlist_cursor - 1; } else { playlist_base = 0; playlist_cursor = playlist_size - 1; } break; case K_PGUP: playlist_cursor -= PLAYLIST_MAXLINES - 1; if (playlist_cursor < 0) { playlist_base += playlist_cursor; if (playlist_base < 0) playlist_base = 0; playlist_cursor = 0; } break; case K_PGDN: playlist_cursor += PLAYLIST_MAXLINES - 1; if (playlist_base + playlist_cursor >= playlist_size) playlist_cursor = playlist_size - playlist_base - 1; if (playlist_cursor >= PLAYLIST_MAXLINES) { playlist_base += playlist_cursor - (PLAYLIST_MAXLINES - 1); playlist_cursor = PLAYLIST_MAXLINES - 1; if (playlist_base + playlist_cursor >= playlist_size) playlist_base = playlist_size - playlist_cursor - 1; } break; case K_ENTER: if (!playlist_size) break; Cbuf_AddText(va("mp3_playtrack %d\n", playlist_cursor + playlist_base + 1)); break; case K_SPACE: M_Menu_MP3_Playlist_Read(); Center_Playlist();break; case 'r': MP3_ToggleRepeat_f(); break; case 's': MP3_ToggleShuffle_f(); break; case KP_LEFTARROW: case 'z': MP3_Prev_f(); break; case KP_5: case 'x': MP3_Play_f(); break; case 'c': MP3_Pause_f(); break; case 'v': MP3_Stop_f(); break; case 'V': MP3_FadeOut_f(); break; case KP_RIGHTARROW: case 'b': MP3_Next_f(); break; case KP_HOME: case K_LEFTARROW: MP3_Rewind_f(); break; case KP_PGUP: case K_RIGHTARROW: MP3_FastForward_f(); break; } con_suppress = false; } void M_Menu_MP3_Playlist_f (void){ if (!MP3_IsActive()) { M_Menu_MP3_Control_f(); return; } M_Menu_MP3_Playlist_Read(); M_EnterMenu (m_mp3_playlist); Center_Playlist(); } #endif //============================================================================= /* DEMO MENU */ extern cvar_t demo_dir; #ifdef _WIN32 #define DEMO_TIME FILETIME #else #define DEMO_TIME time_t #endif #define MAX_DEMO_NAME MAX_OSPATH #define MAX_DEMO_FILES 2048 #define DEMO_MAXLINES 17 typedef enum direntry_type_s {dt_file = 0, dt_dir, dt_up, dt_msg} direntry_type_t; typedef enum demosort_type_s {ds_name = 0, ds_size, ds_time} demo_sort_t; typedef struct direntry_s { direntry_type_t type; char *name; int size; DEMO_TIME time; } direntry_t; static direntry_t demolist_data[MAX_DEMO_FILES]; static direntry_t *demolist[MAX_DEMO_FILES]; static int demolist_count; static char demo_currentdir[MAX_OSPATH] = {0}; static char demo_prevdemo[MAX_DEMO_NAME] = {0}; static float last_demo_time = 0; static int demo_cursor = 0; static int demo_base = 0; static demo_sort_t demo_sorttype = ds_name; static qboolean demo_reversesort = false; int Demo_SortCompare(const void *p1, const void *p2) { int retval; int sign; direntry_t *d1, *d2; d1 = *((direntry_t **) p1); d2 = *((direntry_t **) p2); if ((retval = d2->type - d1->type) || d1->type > dt_dir) return retval; if (d1->type == dt_dir) return Q_strcasecmp(d1->name, d2->name); sign = demo_reversesort ? -1 : 1; switch (demo_sorttype) { case ds_name: return sign * Q_strcasecmp(d1->name, d2->name); case ds_size: return sign * (d1->size - d2->size); case ds_time: #ifdef _WIN32 return -sign * CompareFileTime(&d1->time, &d2->time); #else return -sign * (d1->time - d2->time); #endif default: Sys_Error("Demo_SortCompare: unknown demo_sorttype (%d)", demo_sorttype); return 0; } } static void Demo_SortDemos(void) { int i; last_demo_time = 0; for (i = 0; i < demolist_count; i++) demolist[i] = &demolist_data[i]; qsort(demolist, demolist_count, sizeof(direntry_t *), Demo_SortCompare); } static void Demo_PositionCursor(void) { int i; last_demo_time = 0; demo_base = demo_cursor = 0; if (demo_prevdemo[0]) { for (i = 0; i < demolist_count; i++) { if (!strcmp (demolist[i]->name, demo_prevdemo)) { demo_cursor = i; if (demo_cursor >= DEMO_MAXLINES) { demo_base += demo_cursor - (DEMO_MAXLINES - 1); demo_cursor = DEMO_MAXLINES - 1; } break; } } } demo_prevdemo[0] = 0; } static void Demo_ReadDirectory(void) { int i, size; direntry_type_t type; DEMO_TIME time; char name[MAX_DEMO_NAME]; #ifdef _WIN32 HANDLE h; WIN32_FIND_DATA fd; #else DIR *d; struct dirent *dstruct; struct stat fileinfo; #endif demolist_count = demo_base = demo_cursor = 0; for (i = 0; i < MAX_DEMO_FILES; i++) { if (demolist_data[i].name) { free(demolist_data[i].name); demolist_data[i].name = NULL; } } if (demo_currentdir[0]) { demolist_data[0].name = strdup (".."); demolist_data[0].type = dt_up; demolist_count = 1; } #ifdef _WIN32 h = FindFirstFile (va("%s%s/*.*", com_basedir, demo_currentdir), &fd); if (h == INVALID_HANDLE_VALUE) { demolist_data[demolist_count].name = strdup ("Error reading directory"); demolist_data[demolist_count].type = dt_msg; demolist_count++; Demo_SortDemos(); return; } #else if (!(d = opendir(va("%s/%s", com_gamedir, demo_currentdir)))) { demolist_data[demolist_count].name = strdup ("Error reading directory"); demolist_data[demolist_count].type = dt_msg; demolist_count++; Demo_SortDemos(); return; } dstruct = readdir (d); #endif do { #ifdef _WIN32 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue; type = dt_dir; size = 0; memset(&time, 0, sizeof(time)); } else { i = strlen(fd.cFileName); if (i < 5 || ( Q_strcasecmp(fd.cFileName + i - 4, ".qwd") && Q_strcasecmp(fd.cFileName +i - 4, ".qwz") && Q_strcasecmp(fd.cFileName + i - 4, ".mvd") ) ) continue; type = dt_file; size = fd.nFileSizeLow; time = fd.ftLastWriteTime; } Q_strncpyz (name, fd.cFileName, sizeof(name)); #else stat (va("%s%s/%s", com_basedir, demo_currentdir, dstruct->d_name), &fileinfo); if (S_ISDIR(fileinfo.st_mode)) { if (!strcmp(dstruct->d_name, ".") || !strcmp(dstruct->d_name, "..")) continue; type = dt_dir; time = size = 0; } else { i = strlen(dstruct->d_name); if (i < 5 || ( Q_strcasecmp(dstruct->d_name + i - 4, ".qwd") && Q_strcasecmp(dstruct->d_name + i - 4, ".mvd") ) ) continue; type = dt_file; size = fileinfo.st_size; time = fileinfo.st_mtime; } Q_strncpyz (name, dstruct->d_name, sizeof(name)); #endif if (demolist_count == MAX_DEMO_FILES) break; demolist_data[demolist_count].name = strdup(name); demolist_data[demolist_count].type = type; demolist_data[demolist_count].size = size; demolist_data[demolist_count].time = time; demolist_count++; #ifdef _WIN32 } while (FindNextFile(h, &fd)); FindClose (h); #else } while ((dstruct = readdir (d))); closedir (d); #endif if (!demolist_count) { demolist_data[0].name = strdup("[ no files ]"); demolist_data[0].type = dt_msg; demolist_count = 1; } Demo_SortDemos(); Demo_PositionCursor(); } void M_Menu_Demos_f (void) { static qboolean demo_currentdir_init = false; char *s; M_EnterMenu(m_demos); if (!demo_currentdir_init) { demo_currentdir_init = true; if (demo_dir.string[0]) { for (s = demo_dir.string; *s == '/' || *s == '\\'; s++) ; if (*s) { strcpy(demo_currentdir, "/"); strncat(demo_currentdir, s, sizeof(demo_currentdir) - 1 - 1); for (s = demo_currentdir + strlen(demo_currentdir) - 1; *s == '/' || *s == '\\'; s--) *s = 0; } } else { strcpy(demo_currentdir, com_gamedir); } } Demo_ReadDirectory(); } static void Demo_FormatSize (char *t) { char *s; for (s = t; *s; s++) { if (*s >= '0' && *s <= '9') *s = *s - '0' + 18; else *s |= 128; } } #define DEMOLIST_NAME_WIDTH 29 void M_Demos_Draw (void) { int i, y; direntry_t *d; char demoname[DEMOLIST_NAME_WIDTH], demosize[36 - DEMOLIST_NAME_WIDTH]; static char last_demo_name[MAX_DEMO_NAME + 7]; static int last_demo_index = 0, last_demo_length = 0; char demoname_scroll[38 + 1]; int demoindex, scroll_index; float frac, time, elapsed; M_Print (140, 8, "DEMOS"); Q_strncpyz(demoname_scroll, demo_currentdir[0] ? demo_currentdir : "/", sizeof(demoname_scroll)); M_PrintWhite (16, 16, demoname_scroll); M_Print (8, 24, "\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f \x1d\x1e\x1e\x1e\x1e\x1e\x1f"); for (i = 0; i < demolist_count - demo_base && i < DEMO_MAXLINES; i++) { d = demolist[demo_base + i]; y = 32 + 8 * i; Q_strncpyz (demoname, d->name, sizeof(demoname)); switch (d->type) { case dt_file: M_Print (24, y, demoname); if (d->size > 99999 * 1024) Q_snprintfz(demosize, sizeof(demosize), "%5iM", d->size >> 20); else Q_snprintfz(demosize, sizeof(demosize), "%5iK", d->size >> 10); Demo_FormatSize(demosize); M_PrintWhite (24 + 8 * DEMOLIST_NAME_WIDTH, y, demosize); break; case dt_dir: M_PrintWhite (24, y, demoname); M_PrintWhite (24 + 8 * DEMOLIST_NAME_WIDTH, y, "folder"); break; case dt_up: M_PrintWhite (24, y, demoname); M_PrintWhite (24 + 8 * DEMOLIST_NAME_WIDTH, y, " up"); break; case dt_msg: M_Print (24, y, demoname); break; default: Sys_Error("M_Demos_Draw: unknown d->type (%d)", d->type); } } M_DrawCharacter (8, 32 + demo_cursor * 8, 12 + ((int) (curtime * 4) & 1)); demoindex = demo_base + demo_cursor; if (demolist[demoindex]->type == dt_file) { time = (float) Sys_DoubleTime(); if (!last_demo_time || last_demo_index != demoindex) { last_demo_index = demoindex; last_demo_time = time; frac = scroll_index = 0; Q_snprintfz(last_demo_name, sizeof(last_demo_name), "%s *** ", demolist[demoindex]->name); last_demo_length = strlen(last_demo_name); } else { elapsed = 3.5 * max(time - last_demo_time - 0.75, 0); scroll_index = (int) elapsed; frac = bound(0, elapsed - scroll_index, 1); scroll_index = scroll_index % last_demo_length; } if (last_demo_length <= 38 + 7) { Q_strncpyz(demoname_scroll, demolist[demoindex]->name, sizeof(demoname_scroll)); M_PrintWhite (160 - strlen(demoname_scroll) * 4, 40 + 8 * DEMO_MAXLINES, demoname_scroll); } else { for (i = 0; i < sizeof(demoname_scroll) - 1; i++) demoname_scroll[i] = last_demo_name[(scroll_index + i) % last_demo_length]; demoname_scroll[sizeof(demoname_scroll) - 1] = 0; M_PrintWhite (12 - (int) (8 * frac), 40 + 8 * DEMO_MAXLINES, demoname_scroll); } } else { last_demo_time = 0; } } void M_Demos_Key (int key) { char *p; demo_sort_t sort_target; switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: Q_strncpyz(demo_prevdemo, demolist[demo_cursor + demo_base]->name, sizeof(demo_prevdemo)); M_LeaveMenu (m_multiplayer); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); if (demo_cursor > 0) demo_cursor--; else if (demo_base > 0) demo_base--; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); if (demo_cursor + demo_base < demolist_count - 1) { if (demo_cursor < DEMO_MAXLINES - 1) demo_cursor++; else demo_base++; } break; case K_HOME: S_LocalSound ("misc/menu1.wav"); demo_cursor = 0; demo_base = 0; break; case K_END: S_LocalSound ("misc/menu1.wav"); if (demolist_count > DEMO_MAXLINES) { demo_cursor = DEMO_MAXLINES - 1; demo_base = demolist_count - demo_cursor - 1; } else { demo_base = 0; demo_cursor = demolist_count - 1; } break; case K_PGUP: S_LocalSound ("misc/menu1.wav"); demo_cursor -= DEMO_MAXLINES - 1; if (demo_cursor < 0) { demo_base += demo_cursor; if (demo_base < 0) demo_base = 0; demo_cursor = 0; } break; case K_PGDN: S_LocalSound ("misc/menu1.wav"); demo_cursor += DEMO_MAXLINES - 1; if (demo_base + demo_cursor >= demolist_count) demo_cursor = demolist_count - demo_base - 1; if (demo_cursor >= DEMO_MAXLINES) { demo_base += demo_cursor - (DEMO_MAXLINES - 1); demo_cursor = DEMO_MAXLINES - 1; if (demo_base + demo_cursor >= demolist_count) demo_base = demolist_count - demo_cursor - 1; } break; case K_ENTER: if (!demolist_count || demolist[demo_base + demo_cursor]->type == dt_msg) break; if (demolist[demo_base + demo_cursor]->type != dt_file) { if (demolist[demo_base + demo_cursor]->type == dt_up) { if ((p = strrchr(demo_currentdir, '/')) != NULL) { Q_strncpyz(demo_prevdemo, p + 1, sizeof(demo_prevdemo)); *p = 0; } } else { strncat(demo_currentdir, "/", sizeof(demo_currentdir) - strlen(demo_currentdir) - 1); strncat(demo_currentdir, demolist[demo_base + demo_cursor]->name, sizeof(demo_currentdir) - strlen(demo_currentdir) - 1); } demo_cursor = 0; Demo_ReadDirectory(); } else { key_dest = key_game; m_state = m_none; if (keydown[K_CTRL]) Cbuf_AddText (va("timedemo \"..%s/%s\"\n", demo_currentdir, demolist[demo_cursor + demo_base]->name)); else Cbuf_AddText (va("playdemo \"..%s/%s\"\n", demo_currentdir, demolist[demo_cursor + demo_base]->name)); Q_strncpyz(demo_prevdemo, demolist[demo_base + demo_cursor]->name, sizeof(demo_prevdemo)); } break; case 'n': case 's': case 't': if (!keydown[K_CTRL]) break; sort_target = (key == 'n') ? ds_name : (key == 's') ? ds_size : ds_time; if (demo_sorttype == sort_target) { demo_reversesort = !demo_reversesort; } else { demo_sorttype = sort_target; demo_reversesort = false; } Q_strncpyz(demo_prevdemo, demolist[demo_cursor + demo_base]->name, sizeof(demo_prevdemo)); Demo_SortDemos(); Demo_PositionCursor(); break; case K_SPACE: Q_strncpyz(demo_prevdemo, demolist[demo_cursor + demo_base]->name, sizeof(demo_prevdemo)); Demo_ReadDirectory(); break; } } //============================================================================= /* GAME OPTIONS MENU */ #ifndef CLIENTONLY typedef struct { char *name; char *description; } level_t; level_t levels[] = { {"start", "Entrance"}, // 0 {"e1m1", "Slipgate Complex"}, // 1 {"e1m2", "Castle of the Damned"}, {"e1m3", "The Necropolis"}, {"e1m4", "The Grisly Grotto"}, {"e1m5", "Gloom Keep"}, {"e1m6", "The Door To Chthon"}, {"e1m7", "The House of Chthon"}, {"e1m8", "Ziggurat Vertigo"}, {"e2m1", "The Installation"}, // 9 {"e2m2", "Ogre Citadel"}, {"e2m3", "Crypt of Decay"}, {"e2m4", "The Ebon Fortress"}, {"e2m5", "The Wizard's Manse"}, {"e2m6", "The Dismal Oubliette"}, {"e2m7", "Underearth"}, {"e3m1", "Termination Central"}, // 16 {"e3m2", "The Vaults of Zin"}, {"e3m3", "The Tomb of Terror"}, {"e3m4", "Satan's Dark Delight"}, {"e3m5", "Wind Tunnels"}, {"e3m6", "Chambers of Torment"}, {"e3m7", "The Haunted Halls"}, {"e4m1", "The Sewage System"}, // 23 {"e4m2", "The Tower of Despair"}, {"e4m3", "The Elder God Shrine"}, {"e4m4", "The Palace of Hate"}, {"e4m5", "Hell's Atrium"}, {"e4m6", "The Pain Maze"}, {"e4m7", "Azure Agony"}, {"e4m8", "The Nameless City"}, {"end", "Shub-Niggurath's Pit"}, // 31 {"dm1", "Place of Two Deaths"}, // 32 {"dm2", "Claustrophobopolis"}, {"dm3", "The Abandoned Base"}, {"dm4", "The Bad Place"}, {"dm5", "The Cistern"}, {"dm6", "The Dark Zone"} }; typedef struct { char *description; int firstLevel; int levels; } episode_t; episode_t episodes[] = { {"Welcome to Quake", 0, 1}, {"Doomed Dimension", 1, 8}, {"Realm of Black Magic", 9, 7}, {"Netherworld", 16, 7}, {"The Elder World", 23, 8}, {"Final Level", 31, 1}, {"Deathmatch Arena", 32, 6} }; extern cvar_t maxclients, maxspectators; int startepisode; int startlevel; int _maxclients, _maxspectators; int _deathmatch, _teamplay, _skill, _coop; int _fraglimit, _timelimit; void M_Menu_GameOptions_f (void) { M_EnterMenu (m_gameoptions); // 16 and 8 are not really limits --- just sane values // for these variables... _maxclients = min(16, (int)maxclients.value); if (_maxclients < 2) _maxclients = 8; _maxspectators = max(0, min((int)maxspectators.value, 8)); _deathmatch = max (0, min((int)deathmatch.value, 5)); _teamplay = max (0, min((int)teamplay.value, 2)); _skill = max (0, min((int)skill.value, 3)); _fraglimit = max (0, min((int)fraglimit.value, 100)); _timelimit = max (0, min((int)timelimit.value, 60)); } int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 96, 104, 120, 128}; #define NUM_GAMEOPTIONS 9 int gameoptions_cursor; void M_GameOptions_Draw (void) { mpic_t *p; char *msg; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_DrawTextBox (152, 32, 10, 1); M_Print (160, 40, "begin game"); M_Print (0, 56, " game type"); if (!_deathmatch) M_Print (160, 56, "cooperative"); else M_Print (160, 56, va("deathmatch %i", _deathmatch)); M_Print (0, 64, " teamplay"); switch(_teamplay) { default: msg = "Off"; break; case 1: msg = "No Friendly Fire"; break; case 2: msg = "Friendly Fire"; break; } M_Print (160, 64, msg); if (_deathmatch == 0) { M_Print (0, 72, " skill"); switch (_skill) { case 0: M_Print (160, 72, "Easy"); break; case 1: M_Print (160, 72, "Normal"); break; case 2: M_Print (160, 72, "Hard"); break; default: M_Print (160, 72, "Nightmare"); } } else { M_Print (0, 72, " fraglimit"); if (_fraglimit == 0) M_Print (160, 72, "none"); else M_Print (160, 72, va("%i frags", _fraglimit)); M_Print (0, 80, " timelimit"); if (_timelimit == 0) M_Print (160, 80, "none"); else M_Print (160, 80, va("%i minutes", _timelimit)); } M_Print (0, 96, " maxclients"); M_Print (160, 96, va("%i", _maxclients) ); M_Print (0, 104, " maxspect."); M_Print (160, 104, va("%i", _maxspectators) ); M_Print (0, 120, " Episode"); M_Print (160, 120, episodes[startepisode].description); M_Print (0, 128, " Level"); M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].description); M_Print (160, 136, levels[episodes[startepisode].firstLevel + startlevel].name); // line cursor M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(curtime*4)&1)); } void M_NetStart_Change (int dir) { int count; extern cvar_t registered; switch (gameoptions_cursor) { case 1: _deathmatch += dir; if (_deathmatch < 0) _deathmatch = 5; else if (_deathmatch > 5) _deathmatch = 0; break; case 2: _teamplay += dir; if (_teamplay < 0) _teamplay = 2; else if (_teamplay > 2) _teamplay = 0; break; case 3: if (_deathmatch == 0) { _skill += dir; if (_skill < 0) _skill = 3; else if (_skill > 3) _skill = 0; } else { _fraglimit += dir * 10; if (_fraglimit < 0) _fraglimit = 100; else if (_fraglimit > 100) _fraglimit = 0; } break; case 4: _timelimit += dir*5; if (_timelimit < 0) _timelimit = 60; else if (_timelimit > 60) _timelimit = 0; break; case 5: _maxclients += dir; if (_maxclients > 16) _maxclients = 2; else if (_maxclients < 2) _maxclients = 16; break; case 6: _maxspectators += dir; if (_maxspectators > 8) _maxspectators = 0; else if (_maxspectators < 0) _maxspectators = 8; break; case 7: startepisode += dir; if (registered.value) count = 7; else count = 2; if (startepisode < 0) startepisode = count - 1; if (startepisode >= count) startepisode = 0; startlevel = 0; break; case 8: startlevel += dir; count = episodes[startepisode].levels; if (startlevel < 0) startlevel = count - 1; if (startlevel >= count) startlevel = 0; break; } } void M_GameOptions_Key (int key) { switch (key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_multiplayer); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor--; if (!_deathmatch && gameoptions_cursor == 4) gameoptions_cursor--; if (gameoptions_cursor < 0) gameoptions_cursor = NUM_GAMEOPTIONS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor++; if (!_deathmatch && gameoptions_cursor == 4) gameoptions_cursor++; if (gameoptions_cursor >= NUM_GAMEOPTIONS) gameoptions_cursor = 0; break; case K_HOME: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor = 0; break; case K_END: S_LocalSound ("misc/menu1.wav"); gameoptions_cursor = NUM_GAMEOPTIONS-1; break; case K_LEFTARROW: if (gameoptions_cursor == 0) break; S_LocalSound ("misc/menu3.wav"); M_NetStart_Change (-1); break; case K_RIGHTARROW: if (gameoptions_cursor == 0) break; S_LocalSound ("misc/menu3.wav"); M_NetStart_Change (1); break; case K_ENTER: S_LocalSound ("misc/menu2.wav"); // if (gameoptions_cursor == 0) { key_dest = key_game; // Kill the server, unless we continue playing // deathmatch on another level if (!_deathmatch || !deathmatch.value) Cbuf_AddText ("disconnect\n"); if (_deathmatch == 0) { _coop = 1; _timelimit = 0; _fraglimit = 0; } else { _coop = 0; } Cvar_Set (&deathmatch, va("%i", _deathmatch)); Cvar_Set (&skill, va("%i", _skill)); Cvar_Set (&coop, va("%i", _coop)); Cvar_Set (&fraglimit, va("%i", _fraglimit)); Cvar_Set (&timelimit, va("%i", _timelimit)); Cvar_Set (&teamplay, va("%i", _teamplay)); Cvar_Set (&maxclients, va("%i", _maxclients)); Cvar_Set (&maxspectators, va("%i", _maxspectators)); // Cbuf_AddText ("gamedir qw\n"); Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) ); return; } // M_NetStart_Change (1); break; } } #endif // !CLIENTONLY //============================================================================= /* SETUP MENU */ int setup_cursor = 0; int setup_cursor_table[] = {40, 56, 80, 104, 140}; char setup_name[16]; char setup_team[16]; int setup_oldtop; int setup_oldbottom; int setup_top; int setup_bottom; extern cvar_t name, team; extern cvar_t topcolor, bottomcolor; #define NUM_SETUP_CMDS 5 void M_Menu_Setup_f (void) { M_EnterMenu (m_setup); Q_strncpyz (setup_name, name.string, sizeof(setup_name)); Q_strncpyz (setup_team, team.string, sizeof(setup_team)); setup_top = setup_oldtop = (int)topcolor.value; setup_bottom = setup_oldbottom = (int)bottomcolor.value; } void M_Setup_Draw (void) { mpic_t *p; M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); p = Draw_CachePic ("gfx/p_multi.lmp"); M_DrawPic ( (320-p->width)/2, 4, p); M_Print (64, 40, "Your name"); M_DrawTextBox (160, 32, 16, 1); M_PrintWhite (168, 40, setup_name); M_Print (64, 56, "Your team"); M_DrawTextBox (160, 48, 16, 1); M_PrintWhite (168, 56, setup_team); M_Print (64, 80, "Shirt color"); M_Print (64, 104, "Pants color"); M_DrawTextBox (64, 140-8, 14, 1); M_Print (72, 140, "Accept Changes"); p = Draw_CachePic ("gfx/bigbox.lmp"); M_DrawTransPic (160, 64, p); p = Draw_CachePic ("gfx/menuplyr.lmp"); M_BuildTranslationTable(setup_top*16, setup_bottom*16); M_DrawTransPicTranslate (172, 72, p); M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(curtime*4)&1)); if (setup_cursor == 0) M_DrawCharacter (168 + 8*strlen(setup_name), setup_cursor_table [setup_cursor], 10+((int)(curtime*4)&1)); if (setup_cursor == 1) M_DrawCharacter (168 + 8*strlen(setup_team), setup_cursor_table [setup_cursor], 10+((int)(curtime*4)&1)); } void M_Setup_Key (int k) { int l; switch (k) { case K_ESCAPE: M_LeaveMenu (m_multiplayer); break; case K_UPARROW: S_LocalSound ("misc/menu1.wav"); setup_cursor--; if (setup_cursor < 0) setup_cursor = NUM_SETUP_CMDS-1; break; case K_DOWNARROW: S_LocalSound ("misc/menu1.wav"); setup_cursor++; if (setup_cursor >= NUM_SETUP_CMDS) setup_cursor = 0; break; case K_HOME: S_LocalSound ("misc/menu1.wav"); setup_cursor = 0; break; case K_END: S_LocalSound ("misc/menu1.wav"); setup_cursor = NUM_SETUP_CMDS-1; break; case K_LEFTARROW: if (setup_cursor < 2) return; S_LocalSound ("misc/menu3.wav"); if (setup_cursor == 2) setup_top = setup_top - 1; if (setup_cursor == 3) setup_bottom = setup_bottom - 1; break; case K_RIGHTARROW: if (setup_cursor < 2) return; //forward: S_LocalSound ("misc/menu3.wav"); if (setup_cursor == 2) setup_top = setup_top + 1; if (setup_cursor == 3) setup_bottom = setup_bottom + 1; break; case K_ENTER: // if (setup_cursor == 0 || setup_cursor == 1) // return; // if (setup_cursor == 2 || setup_cursor == 3) // goto forward; // setup_cursor == 4 (OK) Cvar_Set (&name, setup_name); Cvar_Set (&team, setup_team); Cvar_Set (&topcolor, va("%i", setup_top)); Cvar_Set (&bottomcolor, va("%i", setup_bottom)); m_entersound = true; M_Menu_MultiPlayer_f (); break; case K_BACKSPACE: if (setup_cursor == 0) { if (strlen(setup_name)) setup_name[strlen(setup_name)-1] = 0; } else if (setup_cursor == 1) { if (strlen(setup_team)) setup_team[strlen(setup_team)-1] = 0; } else { m_topmenu = m_none; M_LeaveMenu (m_multiplayer); } break; default: if (k < 32 || k > 127) break; if (setup_cursor == 0) { l = strlen(setup_name); if (l < 15) { setup_name[l+1] = 0; setup_name[l] = k; } } if (setup_cursor == 1) { l = strlen(setup_team); if (l < 15) { setup_team[l + 1] = 0; setup_team[l] = k; } } } if (setup_top > 13) setup_top = 0; if (setup_top < 0) setup_top = 13; if (setup_bottom > 13) setup_bottom = 0; if (setup_bottom < 0) setup_bottom = 13; } // SLIST --> #define MENU_X 50 #define TITLE_Y 4 #define MENU_Y 21 #define STAT_Y 166 int m_multip_cursor = 0, m_multip_mins = 0, m_multip_maxs = 16, m_multip_state; void M_Menu_ServerList_f (void) { M_EnterMenu (m_slist); m_multip_state = 0; } void M_ServerList_Draw (void) { int serv, line; M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); M_DrawTextBox(MENU_X, TITLE_Y, 23, 1); M_PrintWhite(MENU_X + 60, TITLE_Y + 8, "Server List"); if (!slist[0].server) { M_PrintWhite(84, MENU_Y + 16 + 16, "Empty server list"); M_Print(60, MENU_Y + 16 + 32, "Press INS to add a server"); M_Print(64, MENU_Y + 16 + 40, "Press E to edit a server"); return; } M_DrawTextBox(MENU_X, STAT_Y, 23, 1); M_DrawTextBox(MENU_X, MENU_Y, 23, m_multip_maxs - m_multip_mins + 1); for (serv = m_multip_mins, line = 1; serv <= m_multip_maxs && serv < MAX_SERVER_LIST && slist[serv].server; serv++, line++) M_Print(MENU_X + 18, line * 8 + MENU_Y, va("%1.21s", slist[serv].description)); M_PrintWhite(MENU_X + 18, STAT_Y + 8, va("%1.22s", slist[m_multip_cursor].server)); M_DrawCharacter(MENU_X + 8, (m_multip_cursor - m_multip_mins + 1) * 8 + MENU_Y, 12 + ((int) (curtime * 4) & 1)); } void M_ServerList_Key (key) { int slist_length; extern cvar_t spectator; if (!slist[0].server && key != K_ESCAPE && key != K_INS) return; switch(key) { case K_BACKSPACE: m_topmenu = m_none; // intentional fallthrough case K_ESCAPE: M_LeaveMenu (m_multiplayer); break; case K_UPARROW: S_LocalSound("misc/menu1.wav"); if (m_multip_cursor > 0) { if (keydown[K_CTRL]) { SList_Switch(m_multip_cursor, m_multip_cursor - 1); m_multip_cursor--; } else { m_multip_cursor--; } } break; case K_DOWNARROW: S_LocalSound("misc/menu1.wav"); if (keydown[K_CTRL]) { if (m_multip_cursor != SList_Length() - 1) { SList_Switch(m_multip_cursor, m_multip_cursor + 1); m_multip_cursor++; } } else if (m_multip_cursor < MAX_SERVER_LIST - 1 && slist[m_multip_cursor + 1].server) { m_multip_cursor++; } break; case K_HOME: S_LocalSound("misc/menu1.wav"); m_multip_cursor = 0; break; case K_END: S_LocalSound("misc/menu1.wav"); m_multip_cursor = SList_Length() - 1; break; case K_PGUP: S_LocalSound("misc/menu1.wav"); m_multip_cursor -= (m_multip_maxs - m_multip_mins); if (m_multip_cursor < 0) m_multip_cursor = 0; break; case K_PGDN: S_LocalSound("misc/menu1.wav"); m_multip_cursor += (m_multip_maxs - m_multip_mins); if (m_multip_cursor >= MAX_SERVER_LIST) m_multip_cursor = MAX_SERVER_LIST - 1; while (!(slist[m_multip_cursor].server)) m_multip_cursor--; break; case K_ENTER: if (keydown[K_CTRL]) { M_Menu_SEdit_f(); break; } m_state = m_main; M_ToggleMenu_f(); Cbuf_AddText(va("%s %s\n", keydown[K_SHIFT] ? "observe" : "join", slist[m_multip_cursor].server)); break; case 'j': case 'J': m_state = m_main; M_ToggleMenu_f(); Cbuf_AddText(va("join %s\n", slist[m_multip_cursor].server)); break; case 'o': case 'O': m_state = m_main; M_ToggleMenu_f(); Cbuf_AddText(va("observe %s\n", slist[m_multip_cursor].server)); break; case 'e': case 'E': M_Menu_SEdit_f(); break; case 'c': case 'C': case 'x': case 'X': if (keydown[K_CTRL]) Sys_CopyToClipboard(slist[m_multip_cursor].server); break; case K_INS: S_LocalSound("misc/menu2.wav"); if ((slist_length = SList_Length()) < MAX_SERVER_LIST) { if (keydown[K_CTRL] && slist_length > 0) { if (m_multip_cursor < slist_length - 1) memmove(&slist[m_multip_cursor + 2], &slist[m_multip_cursor + 1], (slist_length - m_multip_cursor - 1) * sizeof(slist[0])); SList_Reset_NoFree(m_multip_cursor + 1); SList_Set(m_multip_cursor + 1, "127.0.0.1", ""); if (slist_length) m_multip_cursor++; } else { memmove(&slist[m_multip_cursor + 1], &slist[m_multip_cursor], (slist_length - m_multip_cursor) * sizeof(slist[0])); SList_Reset_NoFree(m_multip_cursor); SList_Set(m_multip_cursor, "127.0.0.1", ""); } } break; case K_DEL: S_LocalSound("misc/menu2.wav"); if ((slist_length = SList_Length()) > 0) { SList_Reset(m_multip_cursor); if (m_multip_cursor > 0 && slist_length - 1 == m_multip_cursor) { m_multip_cursor--; } else { memmove(&slist[m_multip_cursor], &slist[m_multip_cursor + 1], (slist_length - m_multip_cursor - 1) * sizeof(slist[0])); SList_Reset_NoFree(slist_length - 1); } } break; } if (m_multip_cursor < m_multip_mins) { m_multip_maxs -= (m_multip_mins - m_multip_cursor); m_multip_mins = m_multip_cursor; } if (m_multip_cursor > m_multip_maxs) { m_multip_mins += (m_multip_cursor - m_multip_maxs); m_multip_maxs = m_multip_cursor; } } #define SERV_X 60 #define SERV_Y 64 #define DESC_X 60 #define DESC_Y 40 #define SERV_L 23 #define DESC_L 23 #define SLIST_BUFSIZE 128 static char slist_serv[SLIST_BUFSIZE], slist_desc[SLIST_BUFSIZE]; static int slist_serv_max, slist_serv_min, slist_desc_max, slist_desc_min, sedit_state; void M_Menu_SEdit_f (void) { int size; M_EnterMenu (m_sedit); sedit_state = 0; Q_strncpyz (slist_serv, slist[m_multip_cursor].server, sizeof(slist_serv)); Q_strncpyz (slist_desc, slist[m_multip_cursor].description, sizeof(slist_desc)); slist_serv_max = (size = strlen(slist_serv)) > SERV_L ? size : SERV_L; slist_serv_min = slist_serv_max - SERV_L; slist_desc_max = (size = strlen(slist_desc)) > DESC_L ? size : DESC_L; slist_desc_min = slist_desc_max - DESC_L; } void M_SEdit_Draw (void) { mpic_t *p; M_DrawTransPic(16, 4, Draw_CachePic("gfx/qplaque.lmp")); p = Draw_CachePic("gfx/p_multi.lmp"); M_DrawPic((320 - p->width) / 2, 4, p); M_DrawTextBox(SERV_X,SERV_Y, 23, 1); M_DrawTextBox(DESC_X,DESC_Y, 23, 1); M_PrintWhite(SERV_X,SERV_Y - 4, "Hostname/IP:"); M_PrintWhite(DESC_X,DESC_Y - 4, "Description:"); M_Print(SERV_X + 9, SERV_Y + 8, va("%1.23s", slist_serv + slist_serv_min)); M_Print(DESC_X + 9, DESC_Y + 8, va("%1.23s", slist_desc + slist_desc_min)); if (sedit_state == 0) M_DrawCharacter(SERV_X + 9 + 8 * (strlen(slist_serv) - slist_serv_min), SERV_Y + 8, 10 + ((int) (curtime * 4) & 1)); else M_DrawCharacter(DESC_X + 9 + 8 * (strlen(slist_desc) - slist_desc_min), DESC_Y + 8, 10 + ((int) (curtime * 4) & 1)); } void M_SEdit_Key (int key) { int l; char *cliptext; switch (key) { case K_ESCAPE: M_Menu_ServerList_f (); break; case K_ENTER: SList_Set(m_multip_cursor, slist_serv, slist_desc); M_Menu_ServerList_f (); break; case K_UPARROW: S_LocalSound("misc/menu1.wav"); sedit_state = !sedit_state; break; case K_DOWNARROW: S_LocalSound("misc/menu1.wav"); sedit_state = !sedit_state; break; case K_BACKSPACE: if (sedit_state == 0) { if ((l = strlen(slist_serv))) slist_serv[--l] = 0; if (strlen(slist_serv) - 6 < slist_serv_min && slist_serv_min) { slist_serv_min--; slist_serv_max--; } } else { if ((l = strlen(slist_desc))) slist_desc[--l] = 0; if (strlen(slist_desc) - 6 < slist_desc_min && slist_desc_min) { slist_desc_min--; slist_desc_max--; } } break; case 'v': case 'V': if (keydown[K_CTRL]) { if ((cliptext = Sys_GetClipboardData())) { if (sedit_state == 0) { strncat(slist_serv, cliptext, sizeof(slist_serv) - strlen(slist_serv) - 1); l = strlen(slist_serv); if (l > slist_serv_max) { slist_serv_min += (l - slist_serv_max); slist_serv_max += (l - slist_serv_max); } } else { strncat(slist_desc, cliptext, sizeof(slist_desc) - strlen(slist_desc) - 1); l = strlen(slist_desc); if (l > slist_desc_max) { slist_desc_min += (l - slist_desc_max); slist_desc_max += (l - slist_desc_max); } } } return; } default: if (key < 32 || key > 127) break; if (sedit_state == 0) { l = strlen(slist_serv); if (l < SLIST_BUFSIZE - 1) { slist_serv[l + 1] = 0; slist_serv[l] = key; l++; } if (l > slist_serv_max) { slist_serv_min++; slist_serv_max++; } } else { l = strlen(slist_desc); if (l < SLIST_BUFSIZE - 1) { slist_desc[l + 1] = 0; slist_desc[l] = key; l++; } if (l > slist_desc_max) { slist_desc_min++; slist_desc_max++; } } } } // <-- SLIST void M_Quit_Draw (void) { static char *quitmsg[] = { "0FuhQuake " FUH_VERSION, "1", "1http://www.fuhquake.net", "1", "0Programming", "1A 'fuh' Nourai", "1", "0Based on ZQuake by Anton Gavrilov", "1", "0Id Software is not responsible for", "0providing technical support for", "0FuhQuake.", "1NOTICE: The copyright and trademark", "1 notices appearing in your copy of", "1Quake(r) are not modified by the use", "1of FuhQuake and remain in full force.", "0QuakeWorld(tm) is a trademark of", "0Id Software, Inc.", NULL}; char **p; int x, y; M_DrawTextBox (0, 12, 38, 19); y = 24; for (p = quitmsg; *p; p++, y += 8) { x = 18 + (36 - (strlen(*p + 1))) * 4; if (**p == '0') M_PrintWhite (x, y, *p + 1); else M_Print (x, y, *p + 1); } } //============================================================================= /* Menu Subsystem */ void M_Init (void) { Cvar_SetCurrentGroup(CVAR_GROUP_SCREEN); Cvar_Register (&scr_centerMenu); #ifdef GLQUAKE Cvar_Register (&scr_scaleMenu); #endif Cvar_ResetCurrentGroup(); Cmd_AddCommand ("togglemenu", M_ToggleMenu_f); Cmd_AddCommand ("menu_main", M_Menu_Main_f); #ifndef CLIENTONLY Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f); Cmd_AddCommand ("menu_load", M_Menu_Load_f); Cmd_AddCommand ("menu_save", M_Menu_Save_f); #endif Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f); Cmd_AddCommand ("menu_slist", M_Menu_ServerList_f); Cmd_AddCommand ("menu_setup", M_Menu_Setup_f); #if defined(_WIN32) || defined(__XMMS__) Cmd_AddCommand ("menu_mp3_control", M_Menu_MP3_Control_f); Cmd_AddCommand ("menu_mp3_playlist", M_Menu_MP3_Playlist_f); #endif Cmd_AddCommand ("menu_demos", M_Menu_Demos_f); Cmd_AddCommand ("menu_options", M_Menu_Options_f); Cmd_AddCommand ("menu_keys", M_Menu_Keys_f); Cmd_AddCommand ("menu_fps", M_Menu_Fps_f); Cmd_AddCommand ("menu_video", M_Menu_Video_f); Cmd_AddCommand ("help", M_Menu_Help_f); Cmd_AddCommand ("menu_help", M_Menu_Help_f); Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); } void M_Draw (void) { if (m_state == m_none || key_dest != key_menu) return; if (!m_recursiveDraw) { scr_copyeverything = 1; if (SCR_NEED_CONSOLE_BACKGROUND) { Draw_ConsoleBackground (scr_con_current); VID_UnlockBuffer (); S_ExtraUpdate (); VID_LockBuffer (); } else { Draw_FadeScreen (); } scr_fullupdate = 0; } else { m_recursiveDraw = false; } #ifdef GLQUAKE if (scr_scaleMenu.value) { menuwidth = 320; menuheight = min (vid.height, 240); glMatrixMode(GL_PROJECTION); glLoadIdentity (); glOrtho (0, menuwidth, menuheight, 0, -99999, 99999); } else { menuwidth = vid.width; menuheight = vid.height; } #endif if (scr_centerMenu.value) m_yofs = (menuheight - 200) / 2; else m_yofs = 0; switch (m_state) { case m_none: break; case m_main: M_Main_Draw (); break; case m_singleplayer: M_SinglePlayer_Draw (); break; #ifndef CLIENTONLY case m_load: M_Load_Draw (); break; case m_save: M_Save_Draw (); break; #endif case m_multiplayer: M_MultiPlayer_Draw (); break; case m_setup: M_Setup_Draw (); break; case m_options: M_Options_Draw (); break; case m_keys: M_Keys_Draw (); break; case m_fps: M_Fps_Draw (); break; case m_video: M_Video_Draw (); break; case m_help: M_Help_Draw (); break; case m_quit: M_Quit_Draw (); break; #ifndef CLIENTONLY case m_gameoptions: M_GameOptions_Draw (); break; #endif case m_slist: M_ServerList_Draw (); break; case m_sedit: M_SEdit_Draw (); break; case m_demos: M_Demos_Draw (); break; #if defined(_WIN32) || defined(__XMMS__) case m_mp3_control: M_MP3_Control_Draw (); break; case m_mp3_playlist: M_Menu_MP3_Playlist_Draw(); break; #endif } #ifdef GLQUAKE if (scr_scaleMenu.value) { glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, vid.width, vid.height, 0, -99999, 99999); } #endif if (m_entersound) { S_LocalSound ("misc/menu2.wav"); m_entersound = false; } VID_UnlockBuffer (); S_ExtraUpdate (); VID_LockBuffer (); } void M_Keydown (int key) { switch (m_state) { case m_none: return; case m_main: M_Main_Key (key); return; case m_singleplayer: M_SinglePlayer_Key (key); return; #ifndef CLIENTONLY case m_load: M_Load_Key (key); return; case m_save: M_Save_Key (key); return; #endif case m_multiplayer: M_MultiPlayer_Key (key); return; case m_setup: M_Setup_Key (key); return; case m_options: M_Options_Key (key); return; case m_keys: M_Keys_Key (key); return; case m_fps: M_Fps_Key (key); return; case m_video: M_Video_Key (key); return; case m_help: M_Help_Key (key); return; case m_quit: M_Quit_Key (key); return; #ifndef CLIENTONLY case m_gameoptions: M_GameOptions_Key (key); return; #endif case m_slist: M_ServerList_Key (key); return; case m_sedit: M_SEdit_Key (key); break; case m_demos: M_Demos_Key (key); break; #if defined(_WIN32) || defined(__XMMS__) case m_mp3_control: M_Menu_MP3_Control_Key (key); break; case m_mp3_playlist: M_Menu_MP3_Playlist_Key (key); break; #endif } }