]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - menu.c
cl_capturevideo_raw* modes now use O_NONBLOCKING file access for more performance
[xonotic/darkplaces.git] / menu.c
diff --git a/menu.c b/menu.c
index 0c50e8deaf14a106f9bf2ccf1d2dbf9e7318b9a7..3fcc7dbd10ac9b657ad9e366d9d36682aa6fde2e 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -18,7 +18,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */
 #include "quakedef.h"
+#include "cdaudio.h"
 #include "image.h"
+#include "progsvm.h"
 
 #include "mprogdefs.h"
 
@@ -34,6 +36,8 @@ enum m_state_e m_state;
 
 void M_Menu_Main_f (void);
        void M_Menu_SinglePlayer_f (void);
+               void M_Menu_Transfusion_Episode_f (void);
+                       void M_Menu_Transfusion_Skill_f (void);
                void M_Menu_Load_f (void);
                void M_Menu_Save_f (void);
        void M_Menu_MultiPlayer_f (void);
@@ -46,6 +50,7 @@ void M_Menu_Main_f (void);
                void M_Menu_Reset_f (void);
                void M_Menu_Video_f (void);
        void M_Menu_Help_f (void);
+       void M_Menu_Credits_f (void);
        void M_Menu_Quit_f (void);
 void M_Menu_LanConfig_f (void);
 void M_Menu_GameOptions_f (void);
@@ -53,6 +58,8 @@ void M_Menu_ServerList_f (void);
 
 void M_Main_Draw (void);
        void M_SinglePlayer_Draw (void);
+               void M_Transfusion_Episode_Draw (void);
+                       void M_Transfusion_Skill_Draw (void);
                void M_Load_Draw (void);
                void M_Save_Draw (void);
        void M_MultiPlayer_Draw (void);
@@ -65,6 +72,7 @@ void M_Main_Draw (void);
                void M_Reset_Draw (void);
                void M_Video_Draw (void);
        void M_Help_Draw (void);
+       void M_Credits_Draw (void);
        void M_Quit_Draw (void);
 void M_LanConfig_Draw (void);
 void M_GameOptions_Draw (void);
@@ -72,6 +80,8 @@ void M_ServerList_Draw (void);
 
 void M_Main_Key (int key, char ascii);
        void M_SinglePlayer_Key (int key, char ascii);
+               void M_Transfusion_Episode_Key (int key, char ascii);
+                       void M_Transfusion_Skill_Key (int key, char ascii);
                void M_Load_Key (int key, char ascii);
                void M_Save_Key (int key, char ascii);
        void M_MultiPlayer_Key (int key, char ascii);
@@ -84,6 +94,7 @@ void M_Main_Key (int key, char ascii);
                void M_Reset_Key (int key, char ascii);
                void M_Video_Key (int key, char ascii);
        void M_Help_Key (int key, char ascii);
+       void M_Credits_Key (int key, char ascii);
        void M_Quit_Key (int key, char ascii);
 void M_LanConfig_Key (int key, char ascii);
 void M_GameOptions_Key (int key, char ascii);
@@ -94,6 +105,13 @@ qboolean    m_entersound;           // play after drawing a frame, so caching
 
 char           m_return_reason [32];
 
+void M_Update_Return_Reason(char *s)
+{
+       strlcpy(m_return_reason, s, sizeof(m_return_reason));
+       if (s)
+               Con_Printf("%s\n", s);
+}
+
 #define StartingGame   (m_multiplayer_cursor == 1)
 #define JoiningGame            (m_multiplayer_cursor == 0)
 
@@ -147,8 +165,8 @@ float menu_x, menu_y, menu_width, menu_height;
 
 void M_Background(int width, int height)
 {
-       menu_width = width;
-       menu_height = height;
+       menu_width = bound(1, width, vid.conwidth);
+       menu_height = bound(1, height, vid.conheight);
        menu_x = (vid.conwidth - menu_width) * 0.5;
        menu_y = (vid.conheight - menu_height) * 0.5;
        //DrawQ_Fill(menu_x, menu_y, menu_width, menu_height, 0, 0, 0, 0.5, 0);
@@ -323,7 +341,7 @@ void M_Demo_Key (int k, char ascii)
                break;
 
        case K_ENTER:
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                m_state = m_none;
                key_dest = key_game;
                Cbuf_AddText (va ("playdemo %s\n", NehahraDemos[demo_cursor].name));
@@ -331,7 +349,7 @@ void M_Demo_Key (int k, char ascii)
 
        case K_UPARROW:
        case K_LEFTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                demo_cursor--;
                if (demo_cursor < 0)
                        demo_cursor = NumberOfNehahraDemos-1;
@@ -339,7 +357,7 @@ void M_Demo_Key (int k, char ascii)
 
        case K_DOWNARROW:
        case K_RIGHTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                demo_cursor++;
                if (demo_cursor >= NumberOfNehahraDemos)
                        demo_cursor = 0;
@@ -367,6 +385,12 @@ void M_Menu_Main_f (void)
        }
        else if (gamemode == GAME_NETHERWORLD)//VORTEX: menu restarting item
                MAIN_ITEMS = 6;
+       else if (gamemode == GAME_TRANSFUSION) {
+               if (sv.active && !cl.intermission && cl.islocalgame)
+                       MAIN_ITEMS = 8;
+               else
+                       MAIN_ITEMS = 7;
+       }
        else
                MAIN_ITEMS = 5;
 
@@ -388,8 +412,29 @@ void M_Main_Draw (void)
        int             f;
        cachepic_t      *p;
 
-       M_Background(320, 200);
+       if (gamemode == GAME_TRANSFUSION) {
+               int y1, y2, y3;
+               M_Background(640, 480);
+               p = Draw_CachePic ("gfx/tb-transfusion");
+               M_DrawPic (640/2 - p->width/2, 40, "gfx/tb-transfusion");
+               y2 = 120;
+               // 8 rather than MAIN_ITEMS to skip a number and not miss the last option
+               for (y1 = 1; y1 <= 8; y1++)
+               {
+                       if (MAIN_ITEMS == 7 && y1 == 4)
+                               y1++;
+                       M_DrawPic (0, y2, va("gfx/mainmenu%i", y1));
+                       y2 += 40;
+               }
+               if (MAIN_ITEMS == 7 && m_main_cursor > 2)
+                       y3 = m_main_cursor + 2;
+               else
+                       y3 = m_main_cursor + 1;
+               M_DrawPic (0, 120 + m_main_cursor * 40, va("gfx/mainmenu%iselected", y3));
+               return;
+       }
 
+       M_Background(320, 200);
        M_DrawPic (16, 4, "gfx/qplaque.lmp");
        p = Draw_CachePic ("gfx/ttl_main.lmp");
        M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_main.lmp");
@@ -425,13 +470,13 @@ void M_Main_Key (int key, char ascii)
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (++m_main_cursor >= MAIN_ITEMS)
                        m_main_cursor = 0;
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (--m_main_cursor < 0)
                        m_main_cursor = MAIN_ITEMS - 1;
                break;
@@ -554,6 +599,78 @@ void M_Main_Key (int key, char ascii)
                                break;
                        }
                }
+               else if (gamemode == GAME_TRANSFUSION) {
+                       if (MAIN_ITEMS == 7)
+                       {
+                               switch (m_main_cursor)
+                               {
+                               case 0:
+                                       M_Menu_Transfusion_Episode_f ();
+                                       break;
+
+                               case 1:
+                                       M_Menu_MultiPlayer_f ();
+                                       break;
+
+                               case 2:
+                                       M_Menu_Options_f ();
+                                       break;
+
+                               case 3:
+                                       M_Menu_Load_f ();
+                                       break;
+
+                               case 4:
+                                       M_Menu_Help_f ();
+                                       break;
+
+                               case 5:
+                                       M_Menu_Credits_f ();
+                                       break;
+
+                               case 6:
+                                       M_Menu_Quit_f ();
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               switch (m_main_cursor)
+                               {
+                               case 0:
+                                       M_Menu_Transfusion_Episode_f ();
+                                       break;
+
+                               case 1:
+                                       M_Menu_MultiPlayer_f ();
+                                       break;
+
+                               case 2:
+                                       M_Menu_Options_f ();
+                                       break;
+
+                               case 3:
+                                       M_Menu_Save_f ();
+                                       break;
+
+                               case 4:
+                                       M_Menu_Load_f ();
+                                       break;
+
+                               case 5:
+                                       M_Menu_Help_f ();
+                                       break;
+
+                               case 6:
+                                       M_Menu_Credits_f ();
+                                       break;
+
+                               case 7:
+                                       M_Menu_Quit_f ();
+                                       break;
+                               }
+                       }
+               }
                else
                {
                        switch (m_main_cursor)
@@ -606,8 +723,8 @@ void M_SinglePlayer_Draw (void)
        M_DrawPic (16, 4, "gfx/qplaque.lmp");
        p = Draw_CachePic ("gfx/ttl_sgl.lmp");
 
-       // Transfusion doesn't have a single player mode
-       if (gamemode == GAME_TRANSFUSION || gamemode == GAME_NEXUIZ || gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH)
+       // Some mods don't have a single player mode
+       if (gamemode == GAME_NEXUIZ || gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH)
        {
                M_DrawPic ((320 - p->width) / 2, 4, "gfx/ttl_sgl.lmp");
 
@@ -616,10 +733,8 @@ void M_SinglePlayer_Draw (void)
                        M_Print(95, 10 * 8, "Nexuiz is for");
                else if (gamemode == GAME_GOODVSBAD2)
                        M_Print(95, 10 * 8, "Good Vs Bad 2 is for");
-               else if (gamemode == GAME_BATTLEMECH)
+               else  // if (gamemode == GAME_BATTLEMECH)
                        M_Print(95, 10 * 8, "Battlemech is for");
-               else
-                       M_Print(95, 10 * 8, "Transfusion is for");
                M_Print(83, 11 * 8, "multiplayer play only");
        }
        else
@@ -638,7 +753,7 @@ void M_SinglePlayer_Draw (void)
 
 void M_SinglePlayer_Key (int key, char ascii)
 {
-       if (gamemode == GAME_TRANSFUSION || gamemode == GAME_NEXUIZ || gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH)
+       if (gamemode == GAME_NEXUIZ || gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH)
        {
                if (key == K_ESCAPE || key == K_ENTER)
                        m_state = m_main;
@@ -652,13 +767,13 @@ void M_SinglePlayer_Key (int key, char ascii)
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)
                        m_singleplayer_cursor = 0;
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (--m_singleplayer_cursor < 0)
                        m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;
                break;
@@ -675,10 +790,13 @@ void M_SinglePlayer_Key (int key, char ascii)
                        Cbuf_AddText ("maxplayers 1\n");
                        Cbuf_AddText ("deathmatch 0\n");
                        Cbuf_AddText ("coop 0\n");
-                       if (gamemode == GAME_NEHAHRA)
-                               Cbuf_AddText ("map nehstart\n");
-                       else
-                               Cbuf_AddText ("map start\n");
+                       if (gamemode == GAME_TRANSFUSION)
+                       {
+                               key_dest = key_menu;
+                               M_Menu_Transfusion_Episode_f ();
+                               break;
+                       }
+                       Cbuf_AddText ("startmap_sp\n");
                        break;
 
                case 1:
@@ -703,9 +821,10 @@ int                loadable[MAX_SAVEGAMES];
 
 void M_ScanSaves (void)
 {
-       int             i, j;
+       int             i, j, len;
        char    name[MAX_OSPATH];
-       char    *str;
+       char    buf[SAVEGAME_COMMENT_LENGTH + 256];
+       const char *t;
        qfile_t *f;
        int             version;
 
@@ -714,13 +833,19 @@ void M_ScanSaves (void)
                strcpy (m_filenames[i], "--- UNUSED SLOT ---");
                loadable[i] = false;
                sprintf (name, "s%i.sav", i);
-               f = FS_Open (name, "r", false);
+               f = FS_Open (name, "rb", false, false);
                if (!f)
                        continue;
-               str = FS_Getline (f);
-               sscanf (str, "%i\n", &version);
-               str = FS_Getline (f);
-               strlcpy (m_filenames[i], str, sizeof (m_filenames[i]));
+               // read enough to get the comment
+               len = FS_Read(f, buf, sizeof(buf) - 1);
+               buf[sizeof(buf) - 1] = 0;
+               t = buf;
+               // version
+               COM_ParseToken(&t, false);
+               version = atoi(com_token);
+               // description
+               COM_ParseToken(&t, false);
+               strlcpy (m_filenames[i], com_token, sizeof (m_filenames[i]));
 
        // change _ back to space
                for (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)
@@ -796,11 +921,14 @@ void M_Load_Key (int k, char ascii)
        switch (k)
        {
        case K_ESCAPE:
-               M_Menu_SinglePlayer_f ();
+               if (gamemode == GAME_TRANSFUSION)
+                       M_Menu_Main_f ();
+               else
+                       M_Menu_SinglePlayer_f ();
                break;
 
        case K_ENTER:
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                if (!loadable[load_cursor])
                        return;
                m_state = m_none;
@@ -812,7 +940,7 @@ void M_Load_Key (int k, char ascii)
 
        case K_UPARROW:
        case K_LEFTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                load_cursor--;
                if (load_cursor < 0)
                        load_cursor = MAX_SAVEGAMES-1;
@@ -820,7 +948,7 @@ void M_Load_Key (int k, char ascii)
 
        case K_DOWNARROW:
        case K_RIGHTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                load_cursor++;
                if (load_cursor >= MAX_SAVEGAMES)
                        load_cursor = 0;
@@ -834,7 +962,10 @@ void M_Save_Key (int k, char ascii)
        switch (k)
        {
        case K_ESCAPE:
-               M_Menu_SinglePlayer_f ();
+               if (gamemode == GAME_TRANSFUSION)
+                       M_Menu_Main_f ();
+               else
+                       M_Menu_SinglePlayer_f ();
                break;
 
        case K_ENTER:
@@ -845,7 +976,7 @@ void M_Save_Key (int k, char ascii)
 
        case K_UPARROW:
        case K_LEFTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                load_cursor--;
                if (load_cursor < 0)
                        load_cursor = MAX_SAVEGAMES-1;
@@ -853,7 +984,7 @@ void M_Save_Key (int k, char ascii)
 
        case K_DOWNARROW:
        case K_RIGHTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                load_cursor++;
                if (load_cursor >= MAX_SAVEGAMES)
                        load_cursor = 0;
@@ -861,6 +992,163 @@ void M_Save_Key (int k, char ascii)
        }
 }
 
+//=============================================================================
+/* Transfusion Single Player Episode Menu */
+
+int    m_episode_cursor;
+#define        EPISODE_ITEMS   6
+
+void M_Menu_Transfusion_Episode_f (void)
+{
+       m_entersound = true;
+       m_state = m_transfusion_episode;
+       key_dest = key_menu;
+}
+
+void M_Transfusion_Episode_Draw (void)
+{
+       int y;
+       cachepic_t *p;
+       M_Background(640, 480);
+
+       p = Draw_CachePic ("gfx/tb-episodes");
+       M_DrawPic (640/2 - p->width/2, 40, "gfx/tb-episodes");
+       for (y = 0; y < EPISODE_ITEMS; y++){
+               M_DrawPic (0, 160 + y * 40, va("gfx/episode%i", y+1));
+       }
+
+       M_DrawPic (0, 120 + (m_episode_cursor + 1) * 40, va("gfx/episode%iselected", m_episode_cursor + 1));
+}
+
+void M_Transfusion_Episode_Key (int key, char ascii)
+{
+       switch (key)
+       {
+       case K_ESCAPE:
+               M_Menu_Main_f ();
+               break;
+
+       case K_DOWNARROW:
+               S_LocalSound ("sound/misc/menu1.wav");
+               m_episode_cursor++;
+               if (m_episode_cursor >= EPISODE_ITEMS)
+                       m_episode_cursor = 0;
+               break;
+
+       case K_UPARROW:
+               S_LocalSound ("sound/misc/menu1.wav");
+               m_episode_cursor--;
+               if (m_episode_cursor < 0)
+                       m_episode_cursor = EPISODE_ITEMS - 1;
+               break;
+
+       case K_ENTER:
+               Cbuf_AddText ("deathmatch 0\n");
+               m_entersound = true;
+               M_Menu_Transfusion_Skill_f ();
+       }
+}
+
+//=============================================================================
+/* Transfusion Single Player Skill Menu */
+
+int    m_skill_cursor = 2;
+#define        SKILL_ITEMS     5
+
+void M_Menu_Transfusion_Skill_f (void)
+{
+       m_entersound = true;
+       m_state = m_transfusion_skill;
+       key_dest = key_menu;
+}
+
+void M_Transfusion_Skill_Draw (void)
+{
+       int y;
+       cachepic_t      *p;
+       M_Background(640, 480);
+
+       p = Draw_CachePic ("gfx/tb-difficulty");
+       M_DrawPic(640/2 - p->width/2, 40, "gfx/tb-difficulty");
+
+       for (y = 0; y < SKILL_ITEMS; y++)
+       {
+               M_DrawPic (0, 180 + y * 40, va("gfx/difficulty%i", y+1));
+       }
+       M_DrawPic (0, 140 + (m_skill_cursor + 1) *40, va("gfx/difficulty%iselected", m_skill_cursor + 1));
+}
+
+void M_Transfusion_Skill_Key (int key, char ascii)
+{
+       switch (key)
+       {
+       case K_ESCAPE:
+               M_Menu_Transfusion_Episode_f ();
+               break;
+
+       case K_DOWNARROW:
+               S_LocalSound ("sound/misc/menu1.wav");
+               m_skill_cursor++;
+               if (m_skill_cursor >= SKILL_ITEMS)
+                       m_skill_cursor = 0;
+               break;
+
+       case K_UPARROW:
+               S_LocalSound ("sound/misc/menu1.wav");
+               m_skill_cursor--;
+               if (m_skill_cursor < 0)
+                       m_skill_cursor = SKILL_ITEMS - 1;
+               break;
+
+       case K_ENTER:
+               m_entersound = true;
+               switch (m_skill_cursor)
+               {
+               case 0:
+                       Cbuf_AddText ("skill 0\n");
+                       break;
+               case 1:
+                       Cbuf_AddText ("skill 1\n");
+                       break;
+               case 2:
+                       Cbuf_AddText ("skill 2\n");
+                       break;
+               case 3:
+                       Cbuf_AddText ("skill 3\n");
+                       break;
+               case 4:
+                       Cbuf_AddText ("skill 4\n");
+                       break;
+               }
+               key_dest = key_game;
+               if (sv.active)
+                       Cbuf_AddText ("disconnect\n");
+               Cbuf_AddText ("maxplayers 1\n");
+               Cbuf_AddText ("deathmatch 0\n");
+               Cbuf_AddText ("coop 0\n");
+               switch (m_episode_cursor)
+               {
+               case 0:
+                       Cbuf_AddText ("map e1m1\n");
+                       break;
+               case 1:
+                       Cbuf_AddText ("map e2m1\n");
+                       break;
+               case 2:
+                       Cbuf_AddText ("map e3m1\n");
+                       break;
+               case 3:
+                       Cbuf_AddText ("map e4m1\n");
+                       break;
+               case 4:
+                       Cbuf_AddText ("map e6m1\n");
+                       break;
+               case 5:
+                       Cbuf_AddText ("map cp01\n");
+                       break;
+               }
+       }
+}
 //=============================================================================
 /* MULTIPLAYER MENU */
 
@@ -881,6 +1169,16 @@ void M_MultiPlayer_Draw (void)
        int             f;
        cachepic_t      *p;
 
+       if (gamemode == GAME_TRANSFUSION)
+       {
+               M_Background(640, 480);
+               p = Draw_CachePic ("gfx/tb-online");
+               M_DrawPic (640/2 - p->width/2, 140, "gfx/tb-online");
+               for (f = 1; f <= MULTIPLAYER_ITEMS; f++)
+                       M_DrawPic (0, 180 + f*40, va("gfx/online%i", f));
+               M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va("gfx/online%iselected", m_multiplayer_cursor + 1));
+               return;
+       }
        M_Background(320, 200);
 
        M_DrawPic (16, 4, "gfx/qplaque.lmp");
@@ -903,13 +1201,13 @@ void M_MultiPlayer_Key (int key, char ascii)
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)
                        m_multiplayer_cursor = 0;
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (--m_multiplayer_cursor < 0)
                        m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;
                break;
@@ -1074,14 +1372,14 @@ void M_Setup_Key (int k, char ascii)
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                setup_cursor--;
                if (setup_cursor < 0)
                        setup_cursor = NUM_SETUP_CMDS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                setup_cursor++;
                if (setup_cursor >= NUM_SETUP_CMDS)
                        setup_cursor = 0;
@@ -1090,7 +1388,7 @@ void M_Setup_Key (int k, char ascii)
        case K_LEFTARROW:
                if (setup_cursor < 1)
                        return;
-               S_LocalSound ("misc/menu3.wav", true);
+               S_LocalSound ("sound/misc/menu3.wav");
                if (setup_cursor == 1)
                        setup_top = setup_top - 1;
                if (setup_cursor == 2)
@@ -1107,7 +1405,7 @@ void M_Setup_Key (int k, char ascii)
                if (setup_cursor < 1)
                        return;
 forward:
-               S_LocalSound ("misc/menu3.wav", true);
+               S_LocalSound ("sound/misc/menu3.wav");
                if (setup_cursor == 1)
                        setup_top = setup_top + 1;
                if (setup_cursor == 2)
@@ -1215,7 +1513,6 @@ void M_Menu_Options_f (void)
        m_entersound = true;
 }
 
-extern cvar_t snd_staticvolume;
 extern cvar_t slowmo;
 extern dllhandle_t jpeg_dll;
 extern cvar_t gl_texture_anisotropy;
@@ -1224,7 +1521,7 @@ extern cvar_t r_textshadow;
 void M_Menu_Options_AdjustSliders (int dir)
 {
        int optnum;
-       S_LocalSound ("misc/menu3.wav", true);
+       S_LocalSound ("sound/misc/menu3.wav");
 
        optnum = 7;
        if (options_cursor == optnum++)
@@ -1350,7 +1647,7 @@ void M_Options_Draw (void)
        int visible;
        cachepic_t      *p;
 
-       M_Background(320, 240);
+       M_Background(320, bound(200, 32 + OPTIONS_ITEMS * 8, vid.conheight));
 
        M_DrawPic(16, 4, "gfx/qplaque.lmp");
        p = Draw_CachePic("gfx/p_option.lmp");
@@ -1358,7 +1655,7 @@ void M_Options_Draw (void)
 
        optnum = 0;
        optcursor = options_cursor;
-       visible = (vid.conheight - 32) / 8;
+       visible = (menu_height - 32) / 8;
        opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_ITEMS - visible)) * 8;
 
        M_Options_PrintCommand( "Customize controls", true);
@@ -1446,14 +1743,14 @@ void M_Options_Key (int k, char ascii)
                return;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_cursor--;
                if (options_cursor < 0)
                        options_cursor = OPTIONS_ITEMS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_cursor++;
                if (options_cursor >= OPTIONS_ITEMS)
                        options_cursor = 0;
@@ -1469,7 +1766,7 @@ void M_Options_Key (int k, char ascii)
        }
 }
 
-#define        OPTIONS_EFFECTS_ITEMS   34
+#define        OPTIONS_EFFECTS_ITEMS   37
 
 int options_effects_cursor;
 
@@ -1482,23 +1779,15 @@ void M_Menu_Options_Effects_f (void)
 
 
 extern cvar_t r_detailtextures;
-extern cvar_t cl_particles;
 extern cvar_t cl_stainmaps;
-extern cvar_t cl_stainmapsclearonload;
-extern cvar_t cl_decals;
+extern cvar_t cl_stainmaps_clearonload;
 extern cvar_t r_explosionclip;
 extern cvar_t r_modellights;
 extern cvar_t r_coronas;
 extern cvar_t gl_flashblend;
-extern cvar_t cl_particles_quality;
-extern cvar_t cl_particles_bulletimpacts;
-extern cvar_t cl_particles_smoke;
-extern cvar_t cl_particles_sparks;
-extern cvar_t cl_particles_bubbles;
-extern cvar_t cl_particles_blood;
-extern cvar_t cl_particles_blood_alpha;
-extern cvar_t cl_particles_blood_bloodhack;
-extern cvar_t cl_particles_explosions_shell;
+extern cvar_t cl_beams_polygon;
+extern cvar_t cl_beams_relative;
+extern cvar_t cl_beams_lightatend;
 extern cvar_t r_lightningbeam_thickness;
 extern cvar_t r_lightningbeam_scroll;
 extern cvar_t r_lightningbeam_repeatdistance;
@@ -1510,7 +1799,7 @@ extern cvar_t r_lightningbeam_qmbtexture;
 void M_Menu_Options_Effects_AdjustSliders (int dir)
 {
        int optnum;
-       S_LocalSound ("misc/menu3.wav", true);
+       S_LocalSound ("sound/misc/menu3.wav");
 
        optnum = 0;
             if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_modellights, bound(0, r_modellights.value + dir, 8));
@@ -1521,7 +1810,7 @@ void M_Menu_Options_Effects_AdjustSliders (int dir)
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_explosions_shell, !cl_particles_explosions_shell.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_explosionclip, !r_explosionclip.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_stainmaps, !cl_stainmaps.integer);
-       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_stainmapsclearonload, !cl_stainmapsclearonload.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_stainmaps_clearonload, !cl_stainmaps_clearonload.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_decals, !cl_decals.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_detailtextures, !r_detailtextures.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_bulletimpacts, !cl_particles_bulletimpacts.integer);
@@ -1531,6 +1820,9 @@ void M_Menu_Options_Effects_AdjustSliders (int dir)
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood, !cl_particles_blood.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood_alpha, bound(0.2, cl_particles_blood_alpha.value + dir * 0.1, 1));
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_blood_bloodhack, !cl_particles_blood_bloodhack.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_polygons, !cl_beams_polygons.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_relative, !cl_beams_relative.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_beams_lightatend, !cl_beams_lightatend.integer);
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_thickness, bound(1, r_lightningbeam_thickness.integer + dir, 10));
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_scroll, bound(0, r_lightningbeam_scroll.integer + dir, 10));
        else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lightningbeam_repeatdistance, bound(64, r_lightningbeam_repeatdistance.integer + dir * 64, 1024));
@@ -1554,7 +1846,7 @@ void M_Options_Effects_Draw (void)
        int visible;
        cachepic_t      *p;
 
-       M_Background(320, 200);
+       M_Background(320, bound(200, 32 + OPTIONS_EFFECTS_ITEMS * 8, vid.conheight));
 
        M_DrawPic(16, 4, "gfx/qplaque.lmp");
        p = Draw_CachePic("gfx/p_option.lmp");
@@ -1562,7 +1854,7 @@ void M_Options_Effects_Draw (void)
 
        optcursor = options_effects_cursor;
        optnum = 0;
-       visible = (vid.conheight - 32) / 8;
+       visible = (menu_height - 32) / 8;
        opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_EFFECTS_ITEMS - visible)) * 8;
 
        M_Options_PrintSlider(  "      Lights Per Model", true, r_modellights.value, 0, 8);
@@ -1573,7 +1865,7 @@ void M_Options_Effects_Draw (void)
        M_Options_PrintCheckbox("       Explosion Shell", true, cl_particles_explosions_shell.integer);
        M_Options_PrintCheckbox("  Explosion Shell Clip", true, r_explosionclip.integer);
        M_Options_PrintCheckbox("             Stainmaps", true, cl_stainmaps.integer);
-       M_Options_PrintCheckbox("Onload Clear Stainmaps", true, cl_stainmapsclearonload.integer);
+       M_Options_PrintCheckbox("Onload Clear Stainmaps", true, cl_stainmaps_clearonload.integer);
        M_Options_PrintCheckbox("                Decals", true, cl_decals.integer);
        M_Options_PrintCheckbox("      Detail Texturing", true, r_detailtextures.integer);
        M_Options_PrintCheckbox("        Bullet Impacts", true, cl_particles_bulletimpacts.integer);
@@ -1583,13 +1875,16 @@ void M_Options_Effects_Draw (void)
        M_Options_PrintCheckbox("                 Blood", true, cl_particles_blood.integer);
        M_Options_PrintSlider(  "         Blood Opacity", true, cl_particles_blood_alpha.value, 0.2, 1);
        M_Options_PrintCheckbox("Force New Blood Effect", true, cl_particles_blood_bloodhack.integer);
-       M_Options_PrintSlider(  "   Lightning Thickness", true, r_lightningbeam_thickness.integer, 1, 10);
-       M_Options_PrintSlider(  "      Lightning Scroll", true, r_lightningbeam_scroll.integer, 0, 10);
-       M_Options_PrintSlider(  " Lightning Repeat Dist", true, r_lightningbeam_repeatdistance.integer, 64, 1024);
-       M_Options_PrintSlider(  "   Lightning Color Red", true, r_lightningbeam_color_red.value, 0, 1);
-       M_Options_PrintSlider(  " Lightning Color Green", true, r_lightningbeam_color_green.value, 0, 1);
-       M_Options_PrintSlider(  "  Lightning Color Blue", true, r_lightningbeam_color_blue.value, 0, 1);
-       M_Options_PrintCheckbox(" Lightning QMB Texture", true, r_lightningbeam_qmbtexture.integer);
+       M_Options_PrintCheckbox("    Lightning Polygons", true, cl_beams_polygons.integer);
+       M_Options_PrintCheckbox("Lightning Smooth Sweep", true, cl_beams_relative.integer);
+       M_Options_PrintCheckbox("   Lightning End Light", true, cl_beams_lightatend.integer);
+       M_Options_PrintSlider(  "   Lightning Thickness", cl_beams_polygons.integer, r_lightningbeam_thickness.integer, 1, 10);
+       M_Options_PrintSlider(  "      Lightning Scroll", cl_beams_polygons.integer, r_lightningbeam_scroll.integer, 0, 10);
+       M_Options_PrintSlider(  " Lightning Repeat Dist", cl_beams_polygons.integer, r_lightningbeam_repeatdistance.integer, 64, 1024);
+       M_Options_PrintSlider(  "   Lightning Color Red", cl_beams_polygons.integer, r_lightningbeam_color_red.value, 0, 1);
+       M_Options_PrintSlider(  " Lightning Color Green", cl_beams_polygons.integer, r_lightningbeam_color_green.value, 0, 1);
+       M_Options_PrintSlider(  "  Lightning Color Blue", cl_beams_polygons.integer, r_lightningbeam_color_blue.value, 0, 1);
+       M_Options_PrintCheckbox(" Lightning QMB Texture", cl_beams_polygons.integer, r_lightningbeam_qmbtexture.integer);
        M_Options_PrintCheckbox("   Model Interpolation", true, r_lerpmodels.integer);
        M_Options_PrintCheckbox("  Sprite Interpolation", true, r_lerpsprites.integer);
        M_Options_PrintSlider(  "            View Blend", true, gl_polyblend.value, 0, 1);
@@ -1615,14 +1910,14 @@ void M_Options_Effects_Key (int k, char ascii)
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_effects_cursor--;
                if (options_effects_cursor < 0)
                        options_effects_cursor = OPTIONS_EFFECTS_ITEMS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_effects_cursor++;
                if (options_effects_cursor >= OPTIONS_EFFECTS_ITEMS)
                        options_effects_cursor = 0;
@@ -1639,7 +1934,7 @@ void M_Options_Effects_Key (int k, char ascii)
 }
 
 
-#define        OPTIONS_GRAPHICS_ITEMS  7
+#define        OPTIONS_GRAPHICS_ITEMS  12
 
 int options_graphics_cursor;
 
@@ -1657,12 +1952,17 @@ extern cvar_t r_shadow_realtime_world;
 extern cvar_t r_shadow_realtime_world_dlightshadows;
 extern cvar_t r_shadow_realtime_world_lightmaps;
 extern cvar_t r_shadow_realtime_world_shadows;
+extern cvar_t r_bloom;
+extern cvar_t r_bloom_intensity;
+extern cvar_t r_bloom_power;
+extern cvar_t r_bloom_blur;
+extern cvar_t r_bloom_resolution;
 
 void M_Menu_Options_Graphics_AdjustSliders (int dir)
 {
        int optnum;
-       S_LocalSound ("misc/menu3.wav", true);
+       S_LocalSound ("sound/misc/menu3.wav");
+
        optnum = 0;
 
                 if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_gloss,                                                  bound(0, r_shadow_gloss.integer + dir, 2));
@@ -1672,6 +1972,11 @@ void M_Menu_Options_Graphics_AdjustSliders (int dir)
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_dlightshadows,       !r_shadow_realtime_world_dlightshadows.integer);
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_lightmaps,           bound(0, r_shadow_realtime_world_lightmaps.value + dir * 0.1, 1));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world_shadows,                     !r_shadow_realtime_world_shadows.integer);
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom,                                 !r_bloom.integer);
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_intensity,                       bound(1, r_bloom_intensity.value + dir * 1, 16));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_power,                           bound(1, r_bloom_power.value + dir * 1, 16));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_blur,                            bound(1, r_bloom_blur.value + dir * 1, 16));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_resolution,                      bound(64, r_bloom_resolution.value + dir * 64, 2048));
 }
 
 
@@ -1680,7 +1985,7 @@ void M_Options_Graphics_Draw (void)
        int visible;
        cachepic_t      *p;
 
-       M_Background(320, 200);
+       M_Background(320, bound(200, 32 + OPTIONS_GRAPHICS_ITEMS * 8, vid.conheight));
 
        M_DrawPic(16, 4, "gfx/qplaque.lmp");
        p = Draw_CachePic("gfx/p_option.lmp");
@@ -1688,7 +1993,7 @@ void M_Options_Graphics_Draw (void)
 
        optcursor = options_graphics_cursor;
        optnum = 0;
-       visible = (vid.conheight - 32) / 8;
+       visible = (menu_height - 32) / 8;
        opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_GRAPHICS_ITEMS - visible)) * 8;
 
        M_Options_PrintSlider(  "             Gloss Mode", true, r_shadow_gloss.integer, 0, 2);
@@ -1698,6 +2003,11 @@ void M_Options_Graphics_Draw (void)
        M_Options_PrintCheckbox("RT World DLight Shadows", true, r_shadow_realtime_world_dlightshadows.integer);
        M_Options_PrintSlider(  "     RT World Lightmaps", true, r_shadow_realtime_world_lightmaps.value, 0, 1);
        M_Options_PrintCheckbox("        RT World Shadow", true, r_shadow_realtime_world_shadows.integer);
+       M_Options_PrintCheckbox("           Bloom Effect", true, r_bloom.integer);
+       M_Options_PrintSlider(  "        Bloom Intensity", true, r_bloom_intensity.value, 1, 16);
+       M_Options_PrintSlider(  "            Bloom Power", true, r_bloom_power.value, 1, 16);
+       M_Options_PrintSlider(  "             Bloom Blur", true, r_bloom_blur.value, 1, 16);
+       M_Options_PrintSlider(  "       Bloom Resolution", true, r_bloom_resolution.value, 64, 2048);
 }
 
 
@@ -1714,14 +2024,14 @@ void M_Options_Graphics_Key (int k, char ascii)
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_graphics_cursor--;
                if (options_graphics_cursor < 0)
                        options_graphics_cursor = OPTIONS_GRAPHICS_ITEMS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_graphics_cursor++;
                if (options_graphics_cursor >= OPTIONS_GRAPHICS_ITEMS)
                        options_graphics_cursor = 0;
@@ -1757,7 +2067,7 @@ void M_Menu_Options_ColorControl_AdjustSliders (int dir)
 {
        int optnum;
        float f;
-       S_LocalSound ("misc/menu3.wav", true);
+       S_LocalSound ("sound/misc/menu3.wav");
 
        optnum = 1;
        if (options_colorcontrol_cursor == optnum++)
@@ -1866,7 +2176,7 @@ void M_Options_ColorControl_Draw (void)
 
        optcursor = options_colorcontrol_cursor;
        optnum = 0;
-       visible = (vid.conheight - 32) / 8;
+       visible = (menu_height - 32) / 8;
        opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_COLORCONTROL_ITEMS - visible)) * 8;
 
        M_Options_PrintCommand( "     Reset to defaults", true);
@@ -1961,14 +2271,14 @@ void M_Options_ColorControl_Key (int k, char ascii)
                return;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_colorcontrol_cursor--;
                if (options_colorcontrol_cursor < 0)
                        options_colorcontrol_cursor = OPTIONS_COLORCONTROL_ITEMS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                options_colorcontrol_cursor++;
                if (options_colorcontrol_cursor >= OPTIONS_COLORCONTROL_ITEMS)
                        options_colorcontrol_cursor = 0;
@@ -2307,7 +2617,7 @@ void M_Keys_Key (int k, char ascii)
 
        if (bind_grab)
        {       // defining a key
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                if (k == K_ESCAPE)
                {
                        bind_grab = false;
@@ -2330,7 +2640,7 @@ void M_Keys_Key (int k, char ascii)
 
        case K_LEFTARROW:
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                do
                {
                        keys_cursor--;
@@ -2342,7 +2652,7 @@ void M_Keys_Key (int k, char ascii)
 
        case K_DOWNARROW:
        case K_RIGHTARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                do
                {
                        keys_cursor++;
@@ -2354,7 +2664,7 @@ void M_Keys_Key (int k, char ascii)
 
        case K_ENTER:           // go into bind mode
                M_FindKeysForCommand (bindnames[keys_cursor][0], keys);
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                if (keys[NUMKEYS - 1] != -1)
                        M_UnbindCommand (bindnames[keys_cursor][0]);
                bind_grab = true;
@@ -2362,7 +2672,7 @@ void M_Keys_Key (int k, char ascii)
 
        case K_BACKSPACE:               // delete bindings
        case K_DEL:                             // delete bindings
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                M_UnbindCommand (bindnames[keys_cursor][0]);
                break;
        }
@@ -2380,6 +2690,11 @@ void M_Reset_Key (int key, char ascii)
 {
        switch (key)
        {
+       case 'Y':
+       case 'y':
+               Cbuf_AddText ("exec default.cfg\n");
+               // no break here since we also exit the menu
+
        case K_ESCAPE:
        case 'n':
        case 'N':
@@ -2387,11 +2702,6 @@ void M_Reset_Key (int key, char ascii)
                m_entersound = true;
                break;
 
-       case 'Y':
-       case 'y':
-               Cbuf_AddText ("exec default.cfg\n");
-               break;
-
        default:
                break;
        }
@@ -2412,7 +2722,7 @@ void M_Reset_Draw (void)
 #define VIDEO_ITEMS 5
 
 int video_cursor = 0;
-int video_cursor_table[] = {56, 68, 80, 100, 120};
+int video_cursor_table[] = {56, 68, 80, 100, 130};
 // note: if modes are added to the beginning of this list, update the
 // video_resolution = x; in M_Menu_Video_f below
 unsigned short video_resolutions[][2] = {{320,240}, {400,300}, {512,384}, {640,480}, {800,600}, {1024,768}, {1152,864}, {1280,960}, {1280,1024}, {1600,1200}, {1792,1344}, {1920,1440}, {2048,1536}, {0,0}};
@@ -2490,7 +2800,7 @@ void M_Video_Draw (void)
 
 void M_Menu_Video_AdjustSliders (int dir)
 {
-       S_LocalSound ("misc/menu3.wav", true);
+       S_LocalSound ("sound/misc/menu3.wav");
 
        switch (video_cursor)
        {
@@ -2536,7 +2846,7 @@ void M_Video_Key (int key, char ascii)
                        Cvar_SetValueQuick(&vid_height, current_vid_height);
                        Cvar_SetValueQuick(&vid_bitsperpixel, current_vid_bitsperpixel);
 
-                       S_LocalSound ("misc/menu1.wav", true);
+                       S_LocalSound ("sound/misc/menu1.wav");
                        M_Menu_Options_f ();
                        break;
 
@@ -2554,14 +2864,14 @@ void M_Video_Key (int key, char ascii)
                        break;
 
                case K_UPARROW:
-                       S_LocalSound ("misc/menu1.wav", true);
+                       S_LocalSound ("sound/misc/menu1.wav");
                        video_cursor--;
                        if (video_cursor < 0)
                                video_cursor = VIDEO_ITEMS-1;
                        break;
 
                case K_DOWNARROW:
-                       S_LocalSound ("misc/menu1.wav", true);
+                       S_LocalSound ("sound/misc/menu1.wav");
                        video_cursor++;
                        if (video_cursor >= VIDEO_ITEMS)
                                video_cursor = 0;
@@ -2626,6 +2936,33 @@ void M_Help_Key (int key, char ascii)
 
 }
 
+//=============================================================================
+/* CEDITS MENU */
+
+void M_Menu_Credits_f (void)
+{
+       key_dest = key_menu;
+       m_state = m_credits;
+       m_entersound = true;
+}
+
+
+
+void M_Credits_Draw (void)
+{
+       M_Background(640, 480);
+       DrawQ_Pic (0, 0, "gfx/creditsmiddle", 0, 0, 1, 1, 1, 1, 0);
+       M_Print (640/2 - 14/2*8, 236, "Coming soon...");
+       DrawQ_Pic (0, 0, "gfx/creditstop", 0, 0, 1, 1, 1, 1, 0);
+       DrawQ_Pic (0, 433, "gfx/creditsbottom", 0, 0, 1, 1, 1, 1, 0);
+}
+
+
+void M_Credits_Key (int key, char ascii)
+{
+               M_Menu_Main_f ();
+}
+
 //=============================================================================
 /* QUIT MENU */
 
@@ -2798,7 +3135,7 @@ void M_Menu_LanConfig_f (void)
        lanConfig_port = 26000;
        sprintf(lanConfig_portname, "%u", lanConfig_port);
 
-       m_return_reason[0] = 0;
+       M_Update_Return_Reason("");
 }
 
 
@@ -2865,14 +3202,14 @@ void M_LanConfig_Key (int key, char ascii)
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                lanConfig_cursor--;
                if (lanConfig_cursor < 0)
                        lanConfig_cursor = NUM_LANCONFIG_CMDS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                lanConfig_cursor++;
                if (lanConfig_cursor >= NUM_LANCONFIG_CMDS)
                        lanConfig_cursor = 0;
@@ -3148,37 +3485,84 @@ episode_t       nehahraepisodes[] =
 // Map list for Transfusion
 level_t                transfusionlevels[] =
 {
-       {"bb1",                 "The Stronghold"},
-       {"bb2",                 "Winter Wonderland"},
-       {"bb3",                 "Bodies"},
-       {"bb4",                 "The Tower"},
-       {"bb5",                 "Click!"},
-       {"bb6",                 "Twin Fortress"},
-       {"bb7",                 "Midgard"},
-       {"bb8",                 "Fun With Heads"},
-
        {"e1m1",                "Cradle to Grave"},
        {"e1m2",                "Wrong Side of the Tracks"},
+       {"e1m3",                "Phantom Express"},
+       {"e1m4",                "Dark Carnival"},
+       {"e1m5",                "Hallowed Grounds"},
+       {"e1m6",                "The Great Temple"},
        {"e1m7",                "Altar of Stone"},
+       {"e1m8",                "House of Horrors"},
+
+       {"e2m1",                "Shipwrecked"},
+       {"e2m2",                "The Lumber Mill"},
+       {"e2m3",                "Rest for the Wicked"},
+       {"e2m4",                "The Overlooked Hotel"},
+       {"e2m5",                "The Haunting"},
+       {"e2m6",                "The Cold Rush"},
+       {"e2m7",                "Bowels of the Earth"},
        {"e2m8",                "The Lair of Shial"},
+       {"e2m9",                "Thin Ice"},
+
        {"e3m1",                "Ghost Town"},
+       {"e3m2",                "The Siege"},
+       {"e3m3",                "Raw Sewage"},
+       {"e3m4",                "The Sick Ward"},
+       {"e3m5",                "Spare Parts"},
+       {"e3m6",                "Monster Bait"},
        {"e3m7",                "The Pit of Cerberus"},
+       {"e3m8",                "Catacombs"},
+
        {"e4m1",                "Butchery Loves Company"},
+       {"e4m2",                "Breeding Grounds"},
+       {"e4m3",                "Charnel House"},
+       {"e4m4",                "Crystal Lake"},
+       {"e4m5",                "Fire and Brimstone"},
+       {"e4m6",                "The Ganglion Depths"},
        {"e4m7",                "In the Flesh"},
        {"e4m8",                "The Hall of the Epiphany"},
        {"e4m9",                "Mall of the Dead"},
 
+       {"bb1",                 "The Stronghold"},
+       {"bb2",                 "Winter Wonderland"},
+       {"bb3",                 "Bodies"},
+       {"bb4",                 "The Tower"},
+       {"bb5",                 "Click!"},
+       {"bb6",                 "Twin Fortress"},
+       {"bb7",                 "Midgard"},
+       {"bb8",                 "Fun With Heads"},
        {"dm1",                 "Monolith Building 11"},
        {"dm2",                 "Power!"},
        {"dm3",                 "Area 15"},
+
        {"e6m1",                "Welcome to Your Life"},
+       {"e6m2",                "They Are Here"},
+       {"e6m3",                "Public Storage"},
+       {"e6m4",                "Aqueducts"},
+       {"e6m5",                "The Ruined Temple"},
+       {"e6m6",                "Forbidden Rituals"},
+       {"e6m7",                "The Dungeon"},
        {"e6m8",                "Beauty and the Beast"},
        {"e6m9",                "Forgotten Catacombs"},
 
+       {"cp01",                "Boat Docks"},
+       {"cp02",                "Old Opera House"},
+       {"cp03",                "Gothic Library"},
+       {"cp04",                "Lost Monastery"},
+       {"cp05",                "Steamboat"},
+       {"cp06",                "Graveyard"},
+       {"cp07",                "Mountain Pass"},
+       {"cp08",                "Abysmal Mine"},
+       {"cp09",                "Castle"},
+       {"cps1",                "Boggy Creek"},
+
        {"cpbb01",              "Crypt of Despair"},
+       {"cpbb02",              "Pits of Blood"},
        {"cpbb03",              "Unholy Cathedral"},
+       {"cpbb04",              "Deadly Inspirations"},
 
        {"b2a15",               "Area 15 (B2)"},
+       {"b2power",             "BB_Power"},
        {"barena",              "Blood Arena"},
        {"bkeep",               "Blood Keep"},
        {"bstar",               "Brown Star"},
@@ -3204,13 +3588,17 @@ level_t         transfusionlevels[] =
 
 episode_t      transfusionepisodes[] =
 {
-       {"Blood", 0, 8},
-       {"Blood Single Player", 8, 10},
-       {"Plasma Pack", 18, 6},
-       {"Cryptic Passage", 24, 2},
-       {"Blood 2", 26, 5},
-       {"Transfusion", 31, 9},
-       {"Conversions", 40, 6}
+       {"The Way of All Flesh", 0, 8},
+       {"Even Death May Die", 8, 9},
+       {"Farewell to Arms", 17, 8},
+       {"Dead Reckoning", 25, 9},
+       {"BloodBath", 34, 11},
+       {"Post Mortem", 45, 9},
+       {"Cryptic Passage", 54, 10},
+       {"Cryptic BloodBath", 64, 4},
+       {"Blood 2", 68, 6},
+       {"Transfusion", 74, 9},
+       {"Conversions", 83, 6}
 };
 
 level_t goodvsbad2levels[] =
@@ -3278,7 +3666,7 @@ gamelevels_t registeredquakegame = {"Quake", quakelevels, quakeepisodes, 7};
 gamelevels_t hipnoticgame = {"Scourge of Armagon", hipnoticlevels, hipnoticepisodes, 6};
 gamelevels_t roguegame = {"Dissolution of Eternity", roguelevels, rogueepisodes, 4};
 gamelevels_t nehahragame = {"Nehahra", nehahralevels, nehahraepisodes, 4};
-gamelevels_t transfusiongame = {"Transfusion", transfusionlevels, transfusionepisodes, 7};
+gamelevels_t transfusiongame = {"Transfusion", transfusionlevels, transfusionepisodes, 11};
 gamelevels_t goodvsbad2game = {"Good Vs. Bad 2", goodvsbad2levels, goodvsbad2episodes, 1};
 gamelevels_t battlemechgame = {"Battlemech", battlemechlevels, battlemechepisodes, 1};
 gamelevels_t openquartzgame = {"OpenQuartz", openquartzlevels, openquartzepisodes, 3};
@@ -3359,9 +3747,11 @@ void M_GameOptions_Draw (void)
                M_Print(0, 64, "        Game Type");
                if (gamemode == GAME_TRANSFUSION)
                {
-                       if (!deathmatch.integer)
+                       if (!coop.integer && !deathmatch.integer)
                                Cvar_SetValue("deathmatch", 1);
-                       if (deathmatch.integer == 2)
+                       if (deathmatch.integer == 0)
+                               M_Print(160, 64, "Cooperative");
+                       else if (deathmatch.integer == 2)
                                M_Print(160, 64, "Capture the Flag");
                        else
                                M_Print(160, 64, "Blood Bath");
@@ -3508,10 +3898,26 @@ void M_NetStart_Change (int dir)
                        break;
                if (gamemode == GAME_TRANSFUSION)
                {
-                       if (deathmatch.integer == 2) // changing from CTF to BloodBath
-                               Cvar_SetValueQuick (&deathmatch, 0);
-                       else // changing from BloodBath to CTF
-                               Cvar_SetValueQuick (&deathmatch, 2);
+                       switch (deathmatch.integer)
+                       {
+                               // From Cooperative to BloodBath
+                               case 0:
+                                       Cvar_SetValueQuick (&coop, 0);
+                                       Cvar_SetValueQuick (&deathmatch, 1);
+                                       break;
+
+                               // From BloodBath to CTF
+                               case 1:
+                                       Cvar_SetValueQuick (&coop, 0);
+                                       Cvar_SetValueQuick (&deathmatch, 2);
+                                       break;
+
+                               // From CTF to Cooperative
+                               //case 2:
+                               default:
+                                       Cvar_SetValueQuick (&coop, 1);
+                                       Cvar_SetValueQuick (&deathmatch, 0);
+                       }
                }
                else if (gamemode == GAME_BATTLEMECH)
                {
@@ -3554,10 +3960,20 @@ void M_NetStart_Change (int dir)
                if (gamemode == GAME_GOODVSBAD2)
                        break;
                Cvar_SetValueQuick (&skill, skill.integer + dir);
-               if (skill.integer > 3)
-                       Cvar_SetValueQuick (&skill, 0);
-               if (skill.integer < 0)
-                       Cvar_SetValueQuick (&skill, 3);
+               if (gamemode == GAME_TRANSFUSION)
+               {
+                       if (skill.integer > 4)
+                               Cvar_SetValueQuick (&skill, 0);
+                       if (skill.integer < 0)
+                               Cvar_SetValueQuick (&skill, 4);
+               }
+               else
+               {
+                       if (skill.integer > 3)
+                               Cvar_SetValueQuick (&skill, 0);
+                       if (skill.integer < 0)
+                               Cvar_SetValueQuick (&skill, 3);
+               }
                break;
 
        case 5:
@@ -3636,14 +4052,14 @@ void M_GameOptions_Key (int key, char ascii)
                break;
 
        case K_UPARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                gameoptions_cursor--;
                if (gameoptions_cursor < 0)
                        gameoptions_cursor = NUM_GAMEOPTIONS-1;
                break;
 
        case K_DOWNARROW:
-               S_LocalSound ("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                gameoptions_cursor++;
                if (gameoptions_cursor >= NUM_GAMEOPTIONS)
                        gameoptions_cursor = 0;
@@ -3652,19 +4068,19 @@ void M_GameOptions_Key (int key, char ascii)
        case K_LEFTARROW:
                if (gameoptions_cursor == 0)
                        break;
-               S_LocalSound ("misc/menu3.wav", true);
+               S_LocalSound ("sound/misc/menu3.wav");
                M_NetStart_Change (-1);
                break;
 
        case K_RIGHTARROW:
                if (gameoptions_cursor == 0)
                        break;
-               S_LocalSound ("misc/menu3.wav", true);
+               S_LocalSound ("sound/misc/menu3.wav");
                M_NetStart_Change (1);
                break;
 
        case K_ENTER:
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                if (gameoptions_cursor == 0)
                {
                        if (sv.active)
@@ -3721,7 +4137,7 @@ void M_Menu_ServerList_f (void)
        m_state = m_slist;
        m_entersound = true;
        slist_cursor = 0;
-       m_return_reason[0] = 0;
+       M_Update_Return_Reason("");
        Net_Slist_f();
 }
 
@@ -3733,16 +4149,19 @@ void M_ServerList_Draw (void)
        const char *s;
 
        // use as much vertical space as available
-       M_Background(640, vid.conheight);
+       if (gamemode == GAME_TRANSFUSION)
+               M_Background(640, vid.conheight - 80);
+       else
+               M_Background(640, vid.conheight);
        // scroll the list as the cursor moves
        s = va("%i/%i masters %i/%i servers", masterreplycount, masterquerycount, serverreplycount, serverquerycount);
        M_PrintRed((640 - strlen(s) * 8) / 2, 32, s);
        if (*m_return_reason)
-               M_Print(16, vid.conheight - 8, m_return_reason);
+               M_Print(16, menu_height - 8, m_return_reason);
        y = 48;
-       visible = (vid.conheight - 16 - y) / 8;
-       start = bound(0, slist_cursor - (visible >> 1), hostCacheCount - visible);
-       end = min(start + visible, hostCacheCount);
+       visible = (menu_height - 16 - y) / 8 / 2;
+       start = bound(0, slist_cursor - (visible >> 1), hostcache_viewcount - visible);
+       end = min(start + visible, hostcache_viewcount);
 
        p = Draw_CachePic("gfx/p_multi.lmp");
        M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi.lmp");
@@ -3751,8 +4170,8 @@ void M_ServerList_Draw (void)
                for (n = start;n < end;n++)
                {
                        DrawQ_Fill(menu_x, menu_y + y, 640, 16, n == slist_cursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
-                       M_Print(0, y, hostcache[n].line1);y += 8;
-                       M_Print(0, y, hostcache[n].line2);y += 8;
+                       M_Print(0, y, hostcache_viewset[n]->line1);y += 8;
+                       M_Print(0, y, hostcache_viewset[n]->line2);y += 8;
                }
        }
        else if (realtime - masterquerytime < 3)
@@ -3779,23 +4198,24 @@ void M_ServerList_Key(int k, char ascii)
 
        case K_UPARROW:
        case K_LEFTARROW:
-               S_LocalSound("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                slist_cursor--;
                if (slist_cursor < 0)
-                       slist_cursor = hostCacheCount - 1;
+                       slist_cursor = hostcache_viewcount - 1;
                break;
 
        case K_DOWNARROW:
        case K_RIGHTARROW:
-               S_LocalSound("misc/menu1.wav", true);
+               S_LocalSound ("sound/misc/menu1.wav");
                slist_cursor++;
-               if (slist_cursor >= hostCacheCount)
+               if (slist_cursor >= hostcache_viewcount)
                        slist_cursor = 0;
                break;
 
        case K_ENTER:
-               S_LocalSound("misc/menu2.wav", true);
-               Cbuf_AddText(va("connect \"%s\"\n", hostcache[slist_cursor].cname));
+               S_LocalSound ("sound/misc/menu2.wav");
+               if (hostcache_viewcount)
+                       Cbuf_AddText(va("connect \"%s\"\n", hostcache_viewset[slist_cursor]->info.cname));
                break;
 
        default:
@@ -3834,6 +4254,9 @@ void M_Init (void)
        Cmd_AddCommand ("menu_reset", M_Menu_Reset_f);
        Cmd_AddCommand ("help", M_Menu_Help_f);
        Cmd_AddCommand ("menu_quit", M_Menu_Quit_f);
+       Cmd_AddCommand ("menu_transfusion_episode", M_Menu_Transfusion_Episode_f);
+       Cmd_AddCommand ("menu_transfusion_skill", M_Menu_Transfusion_Skill_f);
+       Cmd_AddCommand ("menu_credits", M_Menu_Credits_f);
 
        if (gamemode == GAME_TRANSFUSION)
        {
@@ -3919,6 +4342,14 @@ void M_Draw (void)
                M_SinglePlayer_Draw ();
                break;
 
+       case m_transfusion_episode:
+               M_Transfusion_Episode_Draw ();
+               break;
+
+       case m_transfusion_skill:
+               M_Transfusion_Skill_Draw ();
+               break;
+
        case m_load:
                M_Load_Draw ();
                break;
@@ -3967,6 +4398,10 @@ void M_Draw (void)
                M_Help_Draw ();
                break;
 
+       case m_credits:
+               M_Credits_Draw ();
+               break;
+
        case m_quit:
                M_Quit_Draw ();
                break;
@@ -3984,9 +4419,38 @@ void M_Draw (void)
                break;
        }
 
+       if (gamemode == GAME_TRANSFUSION) {
+               if (m_state != m_credits) {
+                       cachepic_t      *p;
+                       int g, scale_x, scale_y, scale_y_repeat, top_offset;
+                       float scale_y_rate;
+                       scale_y_repeat = vid.conheight * 2;
+                       g = (int)(realtime * 64)%96;
+                       scale_y_rate = (float)(g+1) / 96;
+                       top_offset = (g+12)/12;
+                       p = Draw_CachePic (va("gfx/blooddrip%i", top_offset));
+                       for (scale_x = 0; scale_x <= vid.conwidth; scale_x += p->width) {
+                               for (scale_y = -scale_y_repeat; scale_y <= vid.conheight; scale_y += scale_y_repeat) {
+                                       DrawQ_Pic (scale_x + 21, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x +  116, scale_y_repeat + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop1", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 180, scale_y_repeat * .275 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 242, scale_y_repeat * .75 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 304, scale_y_repeat * .25 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 362, scale_y_repeat * .46125 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 402, scale_y_repeat * .1725 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 438, scale_y_repeat * .9 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop1", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 484, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop3", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 557, scale_y_repeat * .9425 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop1", 0, 0, 1, 1, 1, 1, 0);
+                                       DrawQ_Pic (scale_x + 606, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, "gfx/blooddrop2", 0, 0, 1, 1, 1, 1, 0);
+                               }
+                               DrawQ_Pic (scale_x, -1, va("gfx/blooddrip%i", top_offset), 0, 0, 1, 1, 1, 1, 0);
+                       }
+               }
+       }
+
        if (m_entersound)
        {
-               S_LocalSound ("misc/menu2.wav", true);
+               S_LocalSound ("sound/misc/menu2.wav");
                m_entersound = false;
        }
 
@@ -4013,6 +4477,14 @@ void M_Keydown (int key, char ascii)
                M_SinglePlayer_Key (key, ascii);
                return;
 
+       case m_transfusion_episode:
+               M_Transfusion_Episode_Key (key, ascii);
+               return;
+
+       case m_transfusion_skill:
+               M_Transfusion_Skill_Key (key, ascii);
+               return;
+
        case m_load:
                M_Load_Key (key, ascii);
                return;
@@ -4062,6 +4534,10 @@ void M_Keydown (int key, char ascii)
                M_Help_Key (key, ascii);
                return;
 
+       case m_credits:
+               M_Credits_Key (key, ascii);
+               return;
+
        case m_quit:
                M_Quit_Key (key, ascii);
                return;
@@ -4084,6 +4560,8 @@ void M_Shutdown(void)
 {
        // reset key_dest
        key_dest = key_game;
+
+       Mem_FreePool (&menu_mempool);
 }
 
 void M_Restart(void)
@@ -4097,9 +4575,6 @@ mfunction_t *PRVM_ED_FindFunction(const char *);
 #define M_F_INIT               "m_init"
 #define M_F_KEYDOWN            "m_keydown"
 #define M_F_DRAW               "m_draw"
-// ng_menu function names
-#define        M_F_DISPLAY             "m_display"
-#define        M_F_HIDE                "m_hide"
 // normal menu names (rest)
 #define M_F_TOGGLE             "m_toggle"
 #define M_F_SHUTDOWN   "m_shutdown"
@@ -4108,12 +4583,7 @@ static char *m_required_func[] = {
 M_F_INIT,
 M_F_KEYDOWN,
 M_F_DRAW,
-#ifdef NG_MENU
-M_F_DISPLAY,
-M_F_HIDE,
-#else
 M_F_TOGGLE,
-#endif
 M_F_SHUTDOWN,
 };
 
@@ -4253,7 +4723,6 @@ void MP_Init (void)
 
 void MP_Restart(void)
 {
-
        MP_Init();
 }
 
@@ -4327,14 +4796,14 @@ void MR_Init_Commands(void)
 void MR_Init(void)
 {
        // use -forceqmenu to use always the normal quake menu (it sets forceqmenu to 1)
-// COMMANDLINEOPTION: -forceqmenu disables menu.dat (same as +forceqmenu 1)
+// COMMANDLINEOPTION: Client: -forceqmenu disables menu.dat (same as +forceqmenu 1)
        if(COM_CheckParm("-forceqmenu"))
                Cvar_SetValueQuick(&forceqmenu,1);
        // use -useqmenu for debugging proposes, cause it starts
        // the normal quake menu only the first time
-// COMMANDLINEOPTION: -useqmenu causes the first time you open the menu to use the quake menu, then reverts to menu.dat (if forceqmenu is 0)
+// COMMANDLINEOPTION: Client: -useqmenu causes the first time you open the menu to use the quake menu, then reverts to menu.dat (if forceqmenu is 0)
        if(COM_CheckParm("-useqmenu"))
                MR_SetRouting (TRUE);
-       else 
+       else
                MR_SetRouting (FALSE);
 }