]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - menu.c
added rate limiting to player setup menu
[xonotic/darkplaces.git] / menu.c
diff --git a/menu.c b/menu.c
index f552bfd95275ab6d8a1ef3b1e9456d34cb3a61e9..c4ce2787b9aab00e442c6ef4102e4c9871019a67 100644 (file)
--- a/menu.c
+++ b/menu.c
@@ -897,16 +897,17 @@ void M_MultiPlayer_Key (int key, char ascii)
 //=============================================================================
 /* SETUP MENU */
 
-int            setup_cursor = 3;
-int            setup_cursor_table[] = {40, 64, 88, 124};
+int            setup_cursor = 4;
+int            setup_cursor_table[] = {40, 64, 88, 124, 140};
 
 char   setup_myname[32];
 int            setup_oldtop;
 int            setup_oldbottom;
 int            setup_top;
 int            setup_bottom;
+int            setup_rate;
 
-#define        NUM_SETUP_CMDS  4
+#define        NUM_SETUP_CMDS  5
 
 void M_Menu_Setup_f (void)
 {
@@ -916,12 +917,46 @@ void M_Menu_Setup_f (void)
        strcpy(setup_myname, cl_name.string);
        setup_top = setup_oldtop = cl_color.integer >> 4;
        setup_bottom = setup_oldbottom = cl_color.integer & 15;
+       setup_rate = cl_rate.integer;
 }
 
 static int menuplyr_width, menuplyr_height, menuplyr_top, menuplyr_bottom, menuplyr_load;
 static qbyte *menuplyr_pixels;
 static unsigned int *menuplyr_translated;
 
+typedef struct ratetable_s
+{
+       int rate;
+       char *name;
+}
+ratetable_t;
+
+#define RATES ((int)(sizeof(setup_ratetable)/sizeof(setup_ratetable[0])))
+static ratetable_t setup_ratetable[] =
+{
+       {1000, "28.8 bad"},
+       {1500, "28.8 mediocre"},
+       {2000, "28.8 good"},
+       {2500, "33.6 mediocre"},
+       {3000, "33.6 good"},
+       {3500, "56k bad"},
+       {4000, "56k mediocre"},
+       {4500, "56k adequate"},
+       {5000, "56k good"},
+       {7000, "64k ISDN"},
+       {15000, "128k ISDN"},
+       {25000, "broadband"}
+};
+
+static int setup_rateindex(int rate)
+{
+       int i;
+       for (i = 0;i < RATES;i++)
+               if (setup_ratetable[i].rate > setup_rate)
+                       break;
+       return bound(1, i, RATES) - 1;
+}
+
 void M_Setup_Draw (void)
 {
        int i;
@@ -943,8 +978,11 @@ void M_Setup_Draw (void)
                M_Print (64, 88, "Pants color");
        }
 
-       M_DrawTextBox (64, 124-8, 14, 1);
-       M_Print (72, 124, "Accept Changes");
+       M_Print (64, 124-8, "Network speed limit");
+       M_Print (168, 124, va("%i (%s)", setup_rate, setup_ratetable[setup_rateindex(setup_rate)].name));
+
+       M_DrawTextBox (64, 140-8, 14, 1);
+       M_Print (72, 140, "Accept Changes");
 
        // LordHavoc: rewrote this code greatly
        if (menuplyr_load)
@@ -1020,6 +1058,13 @@ void M_Setup_Key (int k, char ascii)
                        setup_top = setup_top - 1;
                if (setup_cursor == 2)
                        setup_bottom = setup_bottom - 1;
+               if (setup_cursor == 3)
+               {
+                       l = setup_rateindex(setup_rate) - 1;
+                       if (l < 0)
+                               l = RATES - 1;
+                       setup_rate = setup_ratetable[l].rate;
+               }
                break;
        case K_RIGHTARROW:
                if (setup_cursor < 1)
@@ -1030,16 +1075,23 @@ forward:
                        setup_top = setup_top + 1;
                if (setup_cursor == 2)
                        setup_bottom = setup_bottom + 1;
+               if (setup_cursor == 3)
+               {
+                       l = setup_rateindex(setup_rate) + 1;
+                       if (l >= RATES)
+                               l = 0;
+                       setup_rate = setup_ratetable[l].rate;
+               }
                break;
 
        case K_ENTER:
                if (setup_cursor == 0)
                        return;
 
-               if (setup_cursor == 1 || setup_cursor == 2)
+               if (setup_cursor == 1 || setup_cursor == 2 || setup_cursor == 3)
                        goto forward;
 
-               // setup_cursor == 3 (Accept changes)
+               // setup_cursor == 4 (Accept changes)
                if (strcmp(cl_name.string, setup_myname) != 0)
                        Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
                if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
@@ -1112,7 +1164,7 @@ void M_DrawCheckbox (int x, int y, int on)
 }
 
 
-#define OPTIONS_ITEMS 33
+#define OPTIONS_ITEMS 34
 
 int options_cursor;
 
@@ -1149,6 +1201,8 @@ void M_Menu_Options_AdjustSliders (int dir)
                Cvar_SetValueQuick (&scr_viewsize, bound(30, scr_viewsize.value + dir * 10, 120));
        else if (options_cursor == optnum++)
                Cvar_SetValueQuick (&scr_screenshot_jpeg, !scr_screenshot_jpeg.integer);
+       else if (options_cursor == optnum++)
+               Cvar_SetValueQuick (&scr_screenshot_jpeg_quality, bound(0, scr_screenshot_jpeg_quality.value + dir * 0.1, 1));
        else if (options_cursor == optnum++)
                Cvar_SetValueQuick (&r_sky, !r_sky.integer);
        else if (options_cursor == optnum++)
@@ -1214,7 +1268,7 @@ void M_Options_PrintCommand(char *s, int enabled)
 {
        if (opty >= 32)
        {
-               DrawQ_Fill(menu_x, menu_y + opty, 640, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               DrawQ_Fill(menu_x, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
                M_ItemPrint(0, opty, s, enabled);
        }
        opty += 8;
@@ -1225,7 +1279,7 @@ void M_Options_PrintCheckbox(char *s, int enabled, int yes)
 {
        if (opty >= 32)
        {
-               DrawQ_Fill(menu_x, menu_y + opty, 640, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               DrawQ_Fill(menu_x, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
                M_ItemPrint(0, opty, s, enabled);
                M_DrawCheckbox(0 + strlen(s) * 8 + 8, opty, yes);
        }
@@ -1237,7 +1291,7 @@ void M_Options_PrintSlider(char *s, int enabled, float value, float minvalue, fl
 {
        if (opty >= 32)
        {
-               DrawQ_Fill(menu_x, menu_y + opty, 640, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               DrawQ_Fill(menu_x, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
                M_ItemPrint(0, opty, s, enabled);
                M_DrawSlider(0 + strlen(s) * 8 + 8, opty, value, minvalue, maxvalue);
        }
@@ -1256,8 +1310,6 @@ void M_Options_Draw (void)
        p = Draw_CachePic("gfx/p_option.lmp");
        M_DrawPic((320-p->width)/2, 4, "gfx/p_option.lmp");
 
-       // LordHavoc: FIXME: overbright needs to be disabled in GAME_GOODVSBAD2 but combine should not be disabled
-       // LordHavoc: perhaps it's time for Overbright Bits to die, and a r_lightmapintensity option to be added?
        optnum = 0;
        optcursor = options_cursor;
        visible = (vid.conheight - 32) / 8;
@@ -1276,15 +1328,16 @@ void M_Options_Draw (void)
        M_Options_PrintSlider(  "Conback Brightness", true, scr_conbrightness.value, 0, 1);
        M_Options_PrintSlider(  "       Screen size", true, scr_viewsize.value, 30, 120);
        M_Options_PrintCheckbox("  JPEG screenshots", jpeg_dll != NULL, scr_screenshot_jpeg.integer);
+       M_Options_PrintSlider(  "      JPEG quality", jpeg_dll != NULL, scr_screenshot_jpeg_quality.value, 0, 1);
        M_Options_PrintCheckbox("               Sky", true, r_sky.integer);
        M_Options_PrintCheckbox("   Texture Combine", true, gl_combine.integer);
        M_Options_PrintCheckbox("         Dithering", true, gl_dither.integer);
        M_Options_PrintCheckbox("Delay gfx (faster)", true, gl_delayfinish.integer);
        M_Options_PrintSlider(  "Anisotropic Filter", gl_support_anisotropy, gl_texture_anisotropy.value, 0, 8);
        M_Options_PrintSlider(  "        Game Speed", sv.active, slowmo.value, 0, 5);
-       M_Options_PrintSlider(  "   CD Music Volume", cdaudioinitialized, bgmvolume.value, 0, 1);
-       M_Options_PrintSlider(  "      Sound Volume", snd_initialized, volume.value, 0, 1);
-       M_Options_PrintSlider(gamemode == GAME_GOODVSBAD2 ? "      Music Volume" : "    Ambient Volume", snd_initialized, snd_staticvolume.value, 0, 1);
+       M_Options_PrintSlider(  "   CD Music Volume", cdaudioinitialized.integer, bgmvolume.value, 0, 1);
+       M_Options_PrintSlider(  "      Sound Volume", snd_initialized.integer, volume.value, 0, 1);
+       M_Options_PrintSlider(gamemode == GAME_GOODVSBAD2 ? "      Music Volume" : "    Ambient Volume", snd_initialized.integer, snd_staticvolume.value, 0, 1);
        M_Options_PrintSlider(  "         Crosshair", true, crosshair.value, 0, 5);
        M_Options_PrintSlider(  "    Crosshair Size", true, crosshair_size.value, 1, 5);
        M_Options_PrintCheckbox("  Static Crosshair", true, crosshair_static.integer);
@@ -1361,7 +1414,7 @@ void M_Options_Key (int k, char ascii)
        }
 }
 
-#define        OPTIONS_EFFECTS_ITEMS   20
+#define        OPTIONS_EFFECTS_ITEMS   22
 
 int options_effects_cursor;
 
@@ -1389,6 +1442,7 @@ 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;
 
 void M_Menu_Options_Effects_AdjustSliders (int dir)
 {
@@ -1396,46 +1450,28 @@ void M_Menu_Options_Effects_AdjustSliders (int dir)
        S_LocalSound ("misc/menu3.wav");
 
        optnum = 0;
-       if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&r_modellights, bound(0, r_modellights.value + dir, 8));
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&r_coronas, !r_coronas.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&gl_flashblend, !gl_flashblend.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_particles, !cl_particles.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_particles_quality, bound(1, cl_particles_quality.value + dir * 0.5, 4));
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_explosions, !cl_explosions.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_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);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_particles_smoke, !cl_particles_smoke.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_particles_sparks, !cl_particles_sparks.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&cl_particles_bubbles, !cl_particles_bubbles.integer);
-       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 (&r_lerpmodels, !r_lerpmodels.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&r_lerpsprites, !r_lerpsprites.integer);
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&r_waterscroll, bound(0, r_waterscroll.value + dir * 0.5, 10));
-       else if (options_effects_cursor == optnum++)
-               Cvar_SetValueQuick (&r_watershader, bound(0, r_watershader.value + dir * 0.25, 10));
+            if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_modellights, bound(0, r_modellights.value + dir, 8));
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_coronas, bound(0, r_coronas.value + dir * 0.125, 4));
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&gl_flashblend, !gl_flashblend.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles, !cl_particles.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_quality, bound(1, cl_particles_quality.value + dir * 0.5, 4));
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_explosions, !cl_explosions.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_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);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_smoke, !cl_particles_smoke.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_sparks, !cl_particles_sparks.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&cl_particles_bubbles, !cl_particles_bubbles.integer);
+       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 (&r_lerpmodels, !r_lerpmodels.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_lerpsprites, !r_lerpsprites.integer);
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_wateralpha, bound(0, r_wateralpha.value + dir * 0.1, 1));
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_waterscroll, bound(0, r_waterscroll.value + dir * 0.5, 10));
+       else if (options_effects_cursor == optnum++) Cvar_SetValueQuick (&r_watershader, bound(0, r_watershader.value + dir * 0.25, 10));
 }
 
 void M_Options_Effects_Draw (void)
@@ -1455,7 +1491,7 @@ void M_Options_Effects_Draw (void)
        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);
-       M_Options_PrintCheckbox("               Coronas", true, r_coronas.integer);
+       M_Options_PrintSlider(  "      Corona Intensity", true, r_coronas.value, 0, 4);
        M_Options_PrintCheckbox("      Use Only Coronas", true, gl_flashblend.integer);
        M_Options_PrintCheckbox("             Particles", true, cl_particles.integer);
        M_Options_PrintSlider(  "     Particles Quality", true, cl_particles_quality.value, 1, 4);
@@ -1470,8 +1506,10 @@ void M_Options_Effects_Draw (void)
        M_Options_PrintCheckbox("               Bubbles", true, cl_particles_bubbles.integer);
        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_PrintCheckbox("   Model Interpolation", true, r_lerpmodels.integer);
        M_Options_PrintCheckbox("  Sprite Interpolation", true, r_lerpsprites.integer);
+       M_Options_PrintSlider(  " Water Alpha (opacity)", true, r_wateralpha.value, 0, 1);
        M_Options_PrintSlider(  "        Water Movement", true, r_waterscroll.value, 0, 10);
        M_Options_PrintSlider(  " GeForce3 Water Shader", true, r_watershader.value, 0, 10);
 }
@@ -1649,8 +1687,8 @@ void M_Options_ColorControl_Draw (void)
        opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_COLORCONTROL_ITEMS - visible)) * 8;
 
        M_Options_PrintCommand( "     Reset to defaults", true);
-       M_Options_PrintCheckbox("Hardware Gamma Control", vid_hardwaregammasupported, v_hwgamma.integer);
-       M_Options_PrintSlider(  "                 Gamma", !v_color_enable.integer && vid_hardwaregammasupported && v_hwgamma.integer, v_gamma.value, 1, 5);
+       M_Options_PrintCheckbox("Hardware Gamma Control", vid_hardwaregammasupported.integer, v_hwgamma.integer);
+       M_Options_PrintSlider(  "                 Gamma", !v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_gamma.value, 1, 5);
        M_Options_PrintSlider(  "              Contrast", !v_color_enable.integer, v_contrast.value, 1, 5);
        M_Options_PrintSlider(  "            Brightness", !v_color_enable.integer, v_brightness.value, 0, 0.8);
        M_Options_PrintCheckbox("  Color Level Controls", true, v_color_enable.integer);
@@ -1658,10 +1696,10 @@ void M_Options_ColorControl_Draw (void)
        M_Options_PrintSlider(  "          Black: Green", v_color_enable.integer, v_color_black_g.value, 0, 0.8);
        M_Options_PrintSlider(  "          Black: Blue ", v_color_enable.integer, v_color_black_b.value, 0, 0.8);
        M_Options_PrintSlider(  "          Black: Grey ", v_color_enable.integer, (v_color_black_r.value + v_color_black_g.value + v_color_black_b.value) / 3, 0, 0.8);
-       M_Options_PrintSlider(  "           Grey: Red  ", v_color_enable.integer && vid_hardwaregammasupported && v_hwgamma.integer, v_color_grey_r.value, 0, 0.95);
-       M_Options_PrintSlider(  "           Grey: Green", v_color_enable.integer && vid_hardwaregammasupported && v_hwgamma.integer, v_color_grey_g.value, 0, 0.95);
-       M_Options_PrintSlider(  "           Grey: Blue ", v_color_enable.integer && vid_hardwaregammasupported && v_hwgamma.integer, v_color_grey_b.value, 0, 0.95);
-       M_Options_PrintSlider(  "           Grey: Grey ", v_color_enable.integer && vid_hardwaregammasupported && v_hwgamma.integer, (v_color_grey_r.value + v_color_grey_g.value + v_color_grey_b.value) / 3, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Red  ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_r.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Green", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_g.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Blue ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, v_color_grey_b.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Grey ", v_color_enable.integer && vid_hardwaregammasupported.integer && v_hwgamma.integer, (v_color_grey_r.value + v_color_grey_g.value + v_color_grey_b.value) / 3, 0, 0.95);
        M_Options_PrintSlider(  "          White: Red  ", v_color_enable.integer, v_color_white_r.value, 1, 5);
        M_Options_PrintSlider(  "          White: Green", v_color_enable.integer, v_color_white_g.value, 1, 5);
        M_Options_PrintSlider(  "          White: Blue ", v_color_enable.integer, v_color_white_b.value, 1, 5);
@@ -1732,7 +1770,6 @@ void M_Options_ColorControl_Key (int k, char ascii)
                        Cvar_SetValueQuick(&v_color_white_r, 1);
                        Cvar_SetValueQuick(&v_color_white_g, 1);
                        Cvar_SetValueQuick(&v_color_white_b, 1);
-                       Cbuf_AddText ("exec default.cfg\n");
                        break;
                default:
                        M_Menu_Options_ColorControl_AdjustSliders (1);
@@ -1980,7 +2017,7 @@ void M_FindKeysForCommand (char *command, int *keys)
 
        for (j=0 ; j<256 ; j++)
        {
-               b = keybindings[j];
+               b = keybindings[0][j];
                if (!b)
                        continue;
                if (!strcmp (b, command) )
@@ -1999,11 +2036,11 @@ void M_UnbindCommand (char *command)
 
        for (j=0 ; j<256 ; j++)
        {
-               b = keybindings[j];
+               b = keybindings[0][j];
                if (!b)
                        continue;
                if (!strcmp (b, command))
-                       Key_SetBinding (j, "");
+                       Key_SetBinding (j, 0, "");
        }
 }
 
@@ -2147,7 +2184,9 @@ int video_cursor_table[] = {56, 68, 80, 100};
 // 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}};
-#define VID_RES_COUNT ((int)sizeof(video_resolutions) / sizeof(video_resolutions[0]) - 1)
+// this is the number of the 640x480 mode in the list
+#define VID_640 3
+#define VID_RES_COUNT ((int)(sizeof(video_resolutions) / sizeof(video_resolutions[0])) - 1)
 int video_resolution;
 
 extern int current_vid_fullscreen;
@@ -2170,11 +2209,11 @@ void M_Menu_Video_f (void)
                        break;
        }
 
-       // Default to 800x600 if we didn't find it
+       // Default to VID_640 if we didn't find it
        if (video_resolution == VID_RES_COUNT)
        {
                // may need to update this number if mode list changes
-               video_resolution = 4;
+               video_resolution = VID_640;
                Cvar_SetValueQuick (&vid_width, video_resolutions[video_resolution][0]);
                Cvar_SetValueQuick (&vid_height, video_resolutions[video_resolution][1]);
        }
@@ -2223,10 +2262,10 @@ void M_Menu_Video_AdjustSliders (int dir)
                case 0:
                {
                        int new_resolution = video_resolution + dir;
-                       if (new_resolution < 0)
+                       if (gamemode == GAME_FNIGGIUM ? new_resolution < VID_640 : new_resolution < 0)
                                video_resolution = VID_RES_COUNT - 1;
-                       else if (new_resolution > VID_RES_COUNT)
-                               video_resolution = 0;
+                       else if (new_resolution > VID_RES_COUNT - 1)
+                               video_resolution = gamemode == GAME_FNIGGIUM ? VID_640 : 0;
                        else
                                video_resolution = new_resolution;
 
@@ -2877,6 +2916,8 @@ level_t           transfusionlevels[] =
        {"e1m7",                "Altar of Stone"},
        {"e2m8",                "The Lair of Shial"},
        {"e3m7",                "The Pit of Cerberus"},
+       {"e4m1",                "Butchery Loves Company"},
+       {"e4m7",                "In the Flesh"},
        {"e4m8",                "The Hall of the Epiphany"},
        {"e4m9",                "Mall of the Dead"},
 
@@ -2885,6 +2926,7 @@ level_t           transfusionlevels[] =
        {"dm3",                 "Area 15"},
        {"e6m1",                "Welcome to Your Life"},
        {"e6m8",                "Beauty and the Beast"},
+       {"e6m9",                "Forgotten Catacombs"},
 
        {"cpbb01",              "Crypt of Despair"},
        {"cpbb03",              "Unholy Cathedral"},
@@ -2896,6 +2938,8 @@ level_t           transfusionlevels[] =
        {"crypt",               "The Crypt"},
 
        {"bb3_2k1",             "Bodies Infusion"},
+       {"captasao",    "Captasao"},
+       {"curandero",   "Curandero"},
        {"dcamp",               "DeathCamp"},
        {"highnoon",    "HighNoon"},
        {"qbb1",                "The Confluence"},
@@ -2906,18 +2950,19 @@ level_t         transfusionlevels[] =
        {"fragm",               "Frag'M"},
        {"maim",                "Maim"},
        {"qe1m7",               "The House of Chthon"},
+       {"qmorbias",    "Dm-Morbias"},
        {"simple",              "Dead Simple"}
 };
 
 episode_t      transfusionepisodes[] =
 {
        {"Blood", 0, 8},
-       {"Blood Single Player", 8, 7},
-       {"Plasma Pack", 15, 5},
-       {"Cryptic Passage", 20, 2},
-       {"Blood 2", 22, 5},
-       {"Transfusion", 27, 6},
-       {"Conversions", 33, 5}
+       {"Blood Single Player", 8, 9},
+       {"Plasma Pack", 17, 6},
+       {"Cryptic Passage", 23, 2},
+       {"Blood 2", 25, 5},
+       {"Transfusion", 30, 8},
+       {"Conversions", 38, 6}
 };
 
 level_t goodvsbad2levels[] =
@@ -3488,8 +3533,6 @@ void M_Init (void)
        menuplyr_load = true;
        menuplyr_pixels = NULL;
 
-       Cmd_AddCommand ("togglemenu", M_ToggleMenu_f);
-
        Cmd_AddCommand ("menu_main", M_Menu_Main_f);
        Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f);
        Cmd_AddCommand ("menu_load", M_Menu_Load_f);
@@ -3936,11 +3979,18 @@ void MR_Restart(void)
        MR_SetRouting (FALSE);
 }
 
+void Call_MR_ToggleMenu_f(void)
+{
+       if(MR_ToggleMenu_f)
+               MR_ToggleMenu_f();
+}
+
 void MR_Init()
 {
        // set router console commands
        Cvar_RegisterVariable (&forceqmenu);
        Cmd_AddCommand ("menu_restart",MR_Restart);
+       Cmd_AddCommand ("togglemenu", Call_MR_ToggleMenu_f);
 
        // use -forceqmenu to use always the normal quake menu (it sets forceqmenu to 1)
        if(COM_CheckParm("-forceqmenu"))