Fix a crash on Doombringer duel5.bsp where one of the lights has more than 32768...
[xonotic/darkplaces.git] / menu.c
diff --git a/menu.c b/menu.c
index 9644edb..9d3a4c2 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"
+#ifdef CONFIG_CD
 #include "cdaudio.h"
+#endif
 #include "image.h"
 #include "progsvm.h"
 
@@ -29,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #define TYPE_BOTH 3
 
 static cvar_t forceqmenu = { 0, "forceqmenu", "0", "enables the quake menu instead of the quakec menu.dat (if present)" };
+static cvar_t menu_progs = { 0, "menu_progs", "menu.dat", "name of quakec menu.dat file" };
 
 static int NehGameType;
 
@@ -273,7 +276,7 @@ static void M_DrawTextBox(float x, float y, float width, float height)
 M_ToggleMenu
 ================
 */
-void M_ToggleMenu(int mode)
+static void M_ToggleMenu(int mode)
 {
        m_entersound = true;
 
@@ -308,7 +311,7 @@ static void M_Demo_Draw (void)
 }
 
 
-void M_Menu_Demos_f (void)
+static void M_Menu_Demos_f (void)
 {
        key_dest = key_menu;
        m_state = m_demo;
@@ -318,6 +321,7 @@ void M_Menu_Demos_f (void)
 
 static void M_Demo_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -328,7 +332,7 @@ static void M_Demo_Key (int k, int ascii)
                S_LocalSound ("sound/misc/menu2.wav");
                m_state = m_none;
                key_dest = key_game;
-               Cbuf_AddText (va ("playdemo %s\n", NehahraDemos[demo_cursor].name));
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "playdemo %s\n", NehahraDemos[demo_cursor].name));
                return;
 
        case K_UPARROW:
@@ -410,7 +414,7 @@ void M_Menu_Main_f (void)
                MAIN_ITEMS = 5;
 
        // check if the game data is missing and use a different main menu if so
-       m_missingdata = !forceqmenu.integer && Draw_CachePic (s)->tex == r_texture_notexture;
+       m_missingdata = !forceqmenu.integer && !Draw_IsPicLoaded(Draw_CachePic_Flags(s, CACHEPICFLAG_FAILONMISSING));
        if (m_missingdata)
                MAIN_ITEMS = 2;
 
@@ -431,6 +435,7 @@ static void M_Main_Draw (void)
 {
        int             f;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if (m_missingdata)
        {
@@ -453,28 +458,28 @@ static void M_Main_Draw (void)
                int y1, y2, y3;
                M_Background(640, 480);
                p = Draw_CachePic ("gfx/menu/tb-transfusion");
-               M_DrawPic (640/2 - p->width/2, 40, "gfx/menu/tb-transfusion");
+               M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/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/menu/mainmenu%i", y1));
+                       M_DrawPic (0, y2, va(vabuf, sizeof(vabuf), "gfx/menu/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/menu/mainmenu%iselected", y3));
+               M_DrawPic (0, 120 + m_main_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/mainmenu%iselected", y3));
                return;
        }
 
        M_Background(320, 200);
        M_DrawPic (16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/ttl_main");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_main");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_main");
 // Nehahra
        if (gamemode == GAME_NEHAHRA)
        {
@@ -490,7 +495,7 @@ static void M_Main_Draw (void)
 
        f = (int)(realtime * 10)%6;
 
-       M_DrawPic (54, 32 + m_main_cursor * 20, va("gfx/menudot%i", f+1));
+       M_DrawPic (54, 32 + m_main_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
 }
 
 
@@ -743,6 +748,7 @@ void M_Menu_SinglePlayer_f (void)
 static void M_SinglePlayer_Draw (void)
 {
        cachepic_t      *p;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
@@ -752,7 +758,7 @@ static void M_SinglePlayer_Draw (void)
        // Some mods don't have a single player mode
        if (gamemode == GAME_GOODVSBAD2 || gamemode == GAME_BATTLEMECH)
        {
-               M_DrawPic ((320 - p->width) / 2, 4, "gfx/ttl_sgl");
+               M_DrawPic ((320 - Draw_GetPicWidth(p)) / 2, 4, "gfx/ttl_sgl");
 
                M_DrawTextBox (60, 8 * 8, 23, 4);
                if (gamemode == GAME_GOODVSBAD2)
@@ -765,12 +771,12 @@ static void M_SinglePlayer_Draw (void)
        {
                int             f;
 
-               M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_sgl");
+               M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_sgl");
                M_DrawPic (72, 32, "gfx/sp_menu");
 
                f = (int)(realtime * 10)%6;
 
-               M_DrawPic (54, 32 + m_singleplayer_cursor * 20, va("gfx/menudot%i", f+1));
+               M_DrawPic (54, 32 + m_singleplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
        }
 }
 
@@ -866,10 +872,10 @@ static void M_ScanSaves (void)
                buf[len] = 0;
                t = buf;
                // version
-               COM_ParseToken_Simple(&t, false, false);
+               COM_ParseToken_Simple(&t, false, false, true);
                //version = atoi(com_token);
                // description
-               COM_ParseToken_Simple(&t, false, false);
+               COM_ParseToken_Simple(&t, false, false, true);
                strlcpy (m_filenames[i], com_token, sizeof (m_filenames[i]));
 
        // change _ back to space
@@ -919,7 +925,7 @@ static void M_Load_Draw (void)
        M_Background(320, 200);
 
        p = Draw_CachePic ("gfx/p_load");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_load" );
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_load" );
 
        for (i=0 ; i< MAX_SAVEGAMES; i++)
                M_Print(16, 32 + 8*i, m_filenames[i]);
@@ -937,7 +943,7 @@ static void M_Save_Draw (void)
        M_Background(320, 200);
 
        p = Draw_CachePic ("gfx/p_save");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_save");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_save");
 
        for (i=0 ; i<MAX_SAVEGAMES ; i++)
                M_Print(16, 32 + 8*i, m_filenames[i]);
@@ -949,6 +955,7 @@ static void M_Save_Draw (void)
 
 static void M_Load_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -966,7 +973,7 @@ static void M_Load_Key (int k, int ascii)
                key_dest = key_game;
 
                // issue the load command
-               Cbuf_AddText (va ("load s%i\n", load_cursor) );
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "load s%i\n", load_cursor) );
                return;
 
        case K_UPARROW:
@@ -990,6 +997,7 @@ static void M_Load_Key (int k, int ascii)
 
 static void M_Save_Key (int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -1002,7 +1010,7 @@ static void M_Save_Key (int k, int ascii)
        case K_ENTER:
                m_state = m_none;
                key_dest = key_game;
-               Cbuf_AddText (va("save s%i\n", load_cursor));
+               Cbuf_AddText (va(vabuf, sizeof(vabuf), "save s%i\n", load_cursor));
                return;
 
        case K_UPARROW:
@@ -1040,15 +1048,16 @@ static void M_Transfusion_Episode_Draw (void)
 {
        int y;
        cachepic_t *p;
+       char vabuf[1024];
        M_Background(640, 480);
 
        p = Draw_CachePic ("gfx/menu/tb-episodes");
-       M_DrawPic (640/2 - p->width/2, 40, "gfx/menu/tb-episodes");
+       M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/tb-episodes");
        for (y = 0; y < EPISODE_ITEMS; y++){
-               M_DrawPic (0, 160 + y * 40, va("gfx/menu/episode%i", y+1));
+               M_DrawPic (0, 160 + y * 40, va(vabuf, sizeof(vabuf), "gfx/menu/episode%i", y+1));
        }
 
-       M_DrawPic (0, 120 + (m_episode_cursor + 1) * 40, va("gfx/menu/episode%iselected", m_episode_cursor + 1));
+       M_DrawPic (0, 120 + (m_episode_cursor + 1) * 40, va(vabuf, sizeof(vabuf), "gfx/menu/episode%iselected", m_episode_cursor + 1));
 }
 
 static void M_Transfusion_Episode_Key (int key, int ascii)
@@ -1097,16 +1106,17 @@ static void M_Transfusion_Skill_Draw (void)
 {
        int y;
        cachepic_t      *p;
+       char vabuf[1024];
        M_Background(640, 480);
 
        p = Draw_CachePic ("gfx/menu/tb-difficulty");
-       M_DrawPic(640/2 - p->width/2, 40, "gfx/menu/tb-difficulty");
+       M_DrawPic(640/2 - Draw_GetPicWidth(p)/2, 40, "gfx/menu/tb-difficulty");
 
        for (y = 0; y < SKILL_ITEMS; y++)
        {
-               M_DrawPic (0, 180 + y * 40, va("gfx/menu/difficulty%i", y+1));
+               M_DrawPic (0, 180 + y * 40, va(vabuf, sizeof(vabuf), "gfx/menu/difficulty%i", y+1));
        }
-       M_DrawPic (0, 140 + (m_skill_cursor + 1) *40, va("gfx/menu/difficulty%iselected", m_skill_cursor + 1));
+       M_DrawPic (0, 140 + (m_skill_cursor + 1) *40, va(vabuf, sizeof(vabuf), "gfx/menu/difficulty%iselected", m_skill_cursor + 1));
 }
 
 static void M_Transfusion_Skill_Key (int key, int ascii)
@@ -1199,27 +1209,28 @@ static void M_MultiPlayer_Draw (void)
 {
        int             f;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if (gamemode == GAME_TRANSFUSION)
        {
                M_Background(640, 480);
                p = Draw_CachePic ("gfx/menu/tb-online");
-               M_DrawPic (640/2 - p->width/2, 140, "gfx/menu/tb-online");
+               M_DrawPic (640/2 - Draw_GetPicWidth(p)/2, 140, "gfx/menu/tb-online");
                for (f = 1; f <= MULTIPLAYER_ITEMS; f++)
-                       M_DrawPic (0, 180 + f*40, va("gfx/menu/online%i", f));
-               M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va("gfx/menu/online%iselected", m_multiplayer_cursor + 1));
+                       M_DrawPic (0, 180 + f*40, va(vabuf, sizeof(vabuf), "gfx/menu/online%i", f));
+               M_DrawPic (0, 220 + m_multiplayer_cursor * 40, va(vabuf, sizeof(vabuf), "gfx/menu/online%iselected", m_multiplayer_cursor + 1));
                return;
        }
        M_Background(320, 200);
 
        M_DrawPic (16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_multi");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi");
        M_DrawPic (72, 32, "gfx/mp_menu");
 
        f = (int)(realtime * 10)%6;
 
-       M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va("gfx/menudot%i", f+1));
+       M_DrawPic (54, 32 + m_multiplayer_cursor * 20, va(vabuf, sizeof(vabuf), "gfx/menudot%i", f+1));
 }
 
 
@@ -1327,12 +1338,13 @@ static void M_Setup_Draw (void)
 {
        int i, j;
        cachepic_t      *p;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
        M_DrawPic (16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_multi");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi");
 
        M_Print(64, 40, "Your name");
        M_DrawTextBox (160, 32, 16, 1);
@@ -1345,7 +1357,7 @@ static void M_Setup_Draw (void)
        }
 
        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_Print(168, 124, va(vabuf, sizeof(vabuf), "%i (%s)", setup_rate, setup_ratetable[setup_rateindex(setup_rate)].name));
 
        M_DrawTextBox (64, 140-8, 14, 1);
        M_Print(72, 140, "Accept Changes");
@@ -1403,7 +1415,7 @@ static void M_Setup_Draw (void)
                                }
                                menuplyr_translated[i] = palette_bgra_transparent[j];
                        }
-                       Draw_NewPic("gfx/menuplyr", menuplyr_width, menuplyr_height, true, (unsigned char *)menuplyr_translated);
+                       Draw_NewPic("gfx/menuplyr", menuplyr_width, menuplyr_height, (unsigned char *)menuplyr_translated, TEXTYPE_BGRA, TEXF_CLAMP);
                }
                M_DrawPic(160, 48, "gfx/bigbox");
                M_DrawPic(172, 56, "gfx/menuplyr");
@@ -1419,6 +1431,7 @@ static void M_Setup_Draw (void)
 static void M_Setup_Key (int k, int ascii)
 {
        int                     l;
+       char vabuf[1024];
 
        switch (k)
        {
@@ -1483,11 +1496,11 @@ forward:
 
                // setup_cursor == 4 (Accept changes)
                if (strcmp(cl_name.string, setup_myname) != 0)
-                       Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "name \"%s\"\n", setup_myname) );
                if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)
-                       Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "color %i %i\n", setup_top, setup_bottom) );
                if (setup_rate != setup_oldrate)
-                       Cbuf_AddText(va("rate %i\n", setup_rate));
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "rate %i\n", setup_rate));
 
                m_entersound = true;
                M_Menu_MultiPlayer_f ();
@@ -1611,49 +1624,51 @@ static void M_Menu_Options_AdjustSliders (int dir)
        else if (options_cursor == optnum++) Cvar_SetValueQuick(&v_contrast, bound(1, v_contrast.value + dir * 0.0625, 4));
        else if (options_cursor == optnum++) Cvar_SetValueQuick(&v_gamma, bound(0.5, v_gamma.value + dir * 0.0625, 3));
        else if (options_cursor == optnum++) Cvar_SetValueQuick(&volume, bound(0, volume.value + dir * 0.0625, 1));
+#ifdef CONFIG_CD
        else if (options_cursor == optnum++) Cvar_SetValueQuick(&bgmvolume, bound(0, bgmvolume.value + dir * 0.0625, 1));
+#endif
 }
 
-static int optnum;
-static int opty;
-static int optcursor;
+static int m_optnum;
+static int m_opty;
+static int m_optcursor;
 
 static void M_Options_PrintCommand(const char *s, int enabled)
 {
-       if (opty >= 32)
+       if (m_opty >= 32)
        {
-               if (optnum == optcursor)
-                       DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
-               M_ItemPrint(0 + 48, opty, s, enabled);
+               if (m_optnum == m_optcursor)
+                       DrawQ_Fill(menu_x + 48, menu_y + m_opty, 320, 8, m_optnum == m_optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               M_ItemPrint(0 + 48, m_opty, s, enabled);
        }
-       opty += 8;
-       optnum++;
+       m_opty += 8;
+       m_optnum++;
 }
 
 static void M_Options_PrintCheckbox(const char *s, int enabled, int yes)
 {
-       if (opty >= 32)
+       if (m_opty >= 32)
        {
-               if (optnum == optcursor)
-                       DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
-               M_ItemPrint(0 + 48, opty, s, enabled);
-               M_DrawCheckbox(0 + 48 + (int)strlen(s) * 8 + 8, opty, yes);
+               if (m_optnum == m_optcursor)
+                       DrawQ_Fill(menu_x + 48, menu_y + m_opty, 320, 8, m_optnum == m_optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               M_ItemPrint(0 + 48, m_opty, s, enabled);
+               M_DrawCheckbox(0 + 48 + (int)strlen(s) * 8 + 8, m_opty, yes);
        }
-       opty += 8;
-       optnum++;
+       m_opty += 8;
+       m_optnum++;
 }
 
 static void M_Options_PrintSlider(const char *s, int enabled, float value, float minvalue, float maxvalue)
 {
-       if (opty >= 32)
+       if (m_opty >= 32)
        {
-               if (optnum == optcursor)
-                       DrawQ_Fill(menu_x + 48, menu_y + opty, 320, 8, optnum == optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
-               M_ItemPrint(0 + 48, opty, s, enabled);
-               M_DrawSlider(0 + 48 + (int)strlen(s) * 8 + 8, opty, value, minvalue, maxvalue);
+               if (m_optnum == m_optcursor)
+                       DrawQ_Fill(menu_x + 48, menu_y + m_opty, 320, 8, m_optnum == m_optcursor ? (0.5 + 0.2 * sin(realtime * M_PI)) : 0, 0, 0, 0.5, 0);
+               M_ItemPrint(0 + 48, m_opty, s, enabled);
+               M_DrawSlider(0 + 48 + (int)strlen(s) * 8 + 8, m_opty, value, minvalue, maxvalue);
        }
-       opty += 8;
-       optnum++;
+       m_opty += 8;
+       m_optnum++;
 }
 
 static void M_Options_Draw (void)
@@ -1665,12 +1680,12 @@ static void M_Options_Draw (void)
 
        M_DrawPic(16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_option");
-       M_DrawPic((320-p->width)/2, 4, "gfx/p_option");
+       M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option");
 
-       optnum = 0;
-       optcursor = options_cursor;
+       m_optnum = 0;
+       m_optcursor = options_cursor;
        visible = (int)((menu_height - 32) / 8);
-       opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_ITEMS - visible)) * 8;
+       m_opty = 32 - bound(0, m_optcursor - (visible >> 1), max(0, OPTIONS_ITEMS - visible)) * 8;
 
        M_Options_PrintCommand( "    Customize controls", true);
        M_Options_PrintCommand( "         Go to console", true);
@@ -1688,7 +1703,9 @@ static void M_Options_Draw (void)
        M_Options_PrintSlider(  "            Brightness", true, v_contrast.value, 1, 2);
        M_Options_PrintSlider(  "                 Gamma", true, v_gamma.value, 0.5, 3);
        M_Options_PrintSlider(  "          Sound Volume", snd_initialized.integer, volume.value, 0, 1);
+#ifdef CONFIG_CD
        M_Options_PrintSlider(  "          Music Volume", cdaudioinitialized.integer, bgmvolume.value, 0, 1);
+#endif
        M_Options_PrintCommand( "     Customize Effects", true);
        M_Options_PrintCommand( "       Effects:  Quake", true);
        M_Options_PrintCommand( "       Effects: Normal", true);
@@ -1747,16 +1764,16 @@ static void M_Options_Key (int k, int ascii)
                        M_Menu_Options_Graphics_f ();
                        break;
                case 22: // Lighting: Flares
-                       Cbuf_AddText("r_coronas 1;gl_flashblend 1;r_shadow_gloss 0;r_shadow_realtime_dlight 0;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0;r_hdr 0");
+                       Cbuf_AddText("r_coronas 1;gl_flashblend 1;r_shadow_gloss 0;r_shadow_realtime_dlight 0;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0");
                        break;
                case 23: // Lighting: Normal
-                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0;r_hdr 0");
+                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 0;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 0");
                        break;
                case 24: // Lighting: High
-                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1;r_hdr 0");
+                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 0;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1");
                        break;
                case 25: // Lighting: Full
-                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 1;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1;r_hdr 0");
+                       Cbuf_AddText("r_coronas 1;gl_flashblend 0;r_shadow_gloss 1;r_shadow_realtime_dlight 1;r_shadow_realtime_dlight_shadows 1;r_shadow_realtime_world 1;r_shadow_realtime_world_lightmaps 0;r_shadow_realtime_world_shadows 1;r_bloom 1");
                        break;
                case 26:
                        M_Menu_ModList_f ();
@@ -1872,12 +1889,12 @@ static void M_Options_Effects_Draw (void)
 
        M_DrawPic(16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_option");
-       M_DrawPic((320-p->width)/2, 4, "gfx/p_option");
+       M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option");
 
-       optcursor = options_effects_cursor;
-       optnum = 0;
+       m_optcursor = options_effects_cursor;
+       m_optnum = 0;
        visible = (int)((menu_height - 32) / 8);
-       opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_EFFECTS_ITEMS - visible)) * 8;
+       m_opty = 32 - bound(0, m_optcursor - (visible >> 1), max(0, OPTIONS_EFFECTS_ITEMS - visible)) * 8;
 
        M_Options_PrintCheckbox("             Particles", true, cl_particles.integer);
        M_Options_PrintCheckbox(" Quake-style Particles", true, cl_particles_quake.integer);
@@ -1978,10 +1995,8 @@ extern cvar_t r_bloom_colorexponent;
 extern cvar_t r_bloom_blur;
 extern cvar_t r_bloom_brighten;
 extern cvar_t r_bloom_resolution;
-extern cvar_t r_hdr;
 extern cvar_t r_hdr_scenebrightness;
 extern cvar_t r_hdr_glowintensity;
-extern cvar_t r_hdr_range;
 extern cvar_t gl_picmip;
 
 static void M_Menu_Options_Graphics_AdjustSliders (int dir)
@@ -1999,10 +2014,8 @@ static void M_Menu_Options_Graphics_AdjustSliders (int dir)
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_shadow_realtime_world,                                     !r_shadow_realtime_world.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_hdr_scenebrightness,                   bound(0.25, r_hdr_scenebrightness.value + dir * 0.125, 4));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom,                                 !r_bloom.integer);
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr,                                   !r_hdr.integer);
-       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_range,                             bound(1, r_hdr_range.value + dir * 0.25, 16));
+       else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_scenebrightness,                   bound(0.25, r_hdr_scenebrightness.value + dir * 0.125, 4));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_hdr_glowintensity,                     bound(0, r_hdr_glowintensity.value + dir * 0.25, 4));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorscale,                      bound(0.0625, r_bloom_colorscale.value + dir * 0.0625, 1));
        else if (options_graphics_cursor == optnum++) Cvar_SetValueQuick (&r_bloom_colorsubtract,                   bound(0, r_bloom_colorsubtract.value + dir * 0.0625, 1-0.0625));
@@ -2023,12 +2036,12 @@ static void M_Options_Graphics_Draw (void)
 
        M_DrawPic(16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_option");
-       M_DrawPic((320-p->width)/2, 4, "gfx/p_option");
+       M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option");
 
-       optcursor = options_graphics_cursor;
-       optnum = 0;
+       m_optcursor = options_graphics_cursor;
+       m_optnum = 0;
        visible = (int)((menu_height - 32) / 8);
-       opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_GRAPHICS_ITEMS - visible)) * 8;
+       m_opty = 32 - bound(0, m_optcursor - (visible >> 1), max(0, OPTIONS_GRAPHICS_ITEMS - visible)) * 8;
 
        M_Options_PrintSlider(  "      Corona Intensity", true, r_coronas.value, 0, 4);
        M_Options_PrintCheckbox("      Use Only Coronas", true, gl_flashblend.integer);
@@ -2038,17 +2051,15 @@ static void M_Options_Graphics_Draw (void)
        M_Options_PrintCheckbox("              RT World", true, r_shadow_realtime_world.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(  "      Scene Brightness", true, r_hdr_scenebrightness.value, 0.25, 4);
-       M_Options_PrintCheckbox("          Bloom Effect", !r_hdr.integer, r_bloom.integer);
-       M_Options_PrintCheckbox("      HDR Bloom Effect", true, r_hdr.integer);
-       M_Options_PrintSlider(  "     HDR Dynamic Range", r_hdr.integer, r_hdr_range.value, 1, 16);
-       M_Options_PrintSlider(  "    HDR Glow Intensity", r_hdr.integer, r_hdr_glowintensity.value, 0, 4);
-       M_Options_PrintSlider(  "     Bloom Color Scale", r_hdr.integer || r_bloom.integer, r_bloom_colorscale.value, 0.0625, 1);
-       M_Options_PrintSlider(  "  Bloom Color Subtract", r_hdr.integer || r_bloom.integer, r_bloom_colorsubtract.value, 0, 1-0.0625);
-       M_Options_PrintSlider(  "  Bloom Color Exponent", r_hdr.integer || r_bloom.integer, r_bloom_colorexponent.value, 1, 8);
-       M_Options_PrintSlider(  "       Bloom Intensity", r_hdr.integer || r_bloom.integer, r_bloom_brighten.value, 1, 4);
-       M_Options_PrintSlider(  "            Bloom Blur", r_hdr.integer || r_bloom.integer, r_bloom_blur.value, 1, 16);
-       M_Options_PrintSlider(  "      Bloom Resolution", r_hdr.integer || r_bloom.integer, r_bloom_resolution.value, 64, 2048);
+       M_Options_PrintSlider(  "       Glow Brightness", true, r_hdr_glowintensity.value, 0, 4);
+       M_Options_PrintSlider(  "     Bloom Color Scale", r_bloom.integer, r_bloom_colorscale.value, 0.0625, 1);
+       M_Options_PrintSlider(  "  Bloom Color Subtract", r_bloom.integer, r_bloom_colorsubtract.value, 0, 1-0.0625);
+       M_Options_PrintSlider(  "  Bloom Color Exponent", r_bloom.integer, r_bloom_colorexponent.value, 1, 8);
+       M_Options_PrintSlider(  "       Bloom Intensity", r_bloom.integer, r_bloom_brighten.value, 1, 4);
+       M_Options_PrintSlider(  "            Bloom Blur", r_bloom.integer, r_bloom_blur.value, 1, 16);
+       M_Options_PrintSlider(  "      Bloom Resolution", r_bloom.integer, r_bloom_resolution.value, 64, 2048);
        M_Options_PrintCommand( "      Restart Renderer", true);
 }
 
@@ -2113,8 +2124,6 @@ static void M_Menu_Options_ColorControl_AdjustSliders (int dir)
 
        optnum = 1;
        if (options_colorcontrol_cursor == optnum++)
-               Cvar_SetValueQuick (&v_hwgamma, !v_hwgamma.integer);
-       else if (options_colorcontrol_cursor == optnum++)
        {
                Cvar_SetValueQuick (&v_color_enable, 0);
                Cvar_SetValueQuick (&v_gamma, bound(1, v_gamma.value + dir * 0.125, 5));
@@ -2207,7 +2216,8 @@ static void M_Menu_Options_ColorControl_AdjustSliders (int dir)
 static void M_Options_ColorControl_Draw (void)
 {
        int visible;
-       float x, c, s, t, u, v;
+       float x, s, t, u, v;
+       float c[3];
        cachepic_t      *p, *dither;
 
        dither = Draw_CachePic_Flags ("gfx/colorcontrol/ditherpattern", CACHEPICFLAG_NOCLAMP);
@@ -2216,16 +2226,15 @@ static void M_Options_ColorControl_Draw (void)
 
        M_DrawPic(16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_option");
-       M_DrawPic((320-p->width)/2, 4, "gfx/p_option");
+       M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/p_option");
 
-       optcursor = options_colorcontrol_cursor;
-       optnum = 0;
+       m_optcursor = options_colorcontrol_cursor;
+       m_optnum = 0;
        visible = (int)((menu_height - 32) / 8);
-       opty = 32 - bound(0, optcursor - (visible >> 1), max(0, OPTIONS_COLORCONTROL_ITEMS - visible)) * 8;
+       m_opty = 32 - bound(0, m_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.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(  "                 Gamma", !v_color_enable.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);
@@ -2233,50 +2242,53 @@ static 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.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(  "           Grey: Red  ", v_color_enable.integer, v_color_grey_r.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Green", v_color_enable.integer, v_color_grey_g.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Blue ", v_color_enable.integer, v_color_grey_b.value, 0, 0.95);
+       M_Options_PrintSlider(  "           Grey: Grey ", v_color_enable.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);
        M_Options_PrintSlider(  "          White: Grey ", v_color_enable.integer, (v_color_white_r.value + v_color_white_g.value + v_color_white_b.value) / 3, 1, 5);
 
-       opty += 4;
-       DrawQ_Fill(menu_x, menu_y + opty, 320, 4 + 64 + 8 + 64 + 4, 0, 0, 0, 1, 0);opty += 4;
+       m_opty += 4;
+       DrawQ_Fill(menu_x, menu_y + m_opty, 320, 4 + 64 + 8 + 64 + 4, 0, 0, 0, 1, 0);m_opty += 4;
        s = (float) 312 / 2 * vid.width / vid_conwidth.integer;
        t = (float) 4 / 2 * vid.height / vid_conheight.integer;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 1,0,0,1, 0,1, 0,0,0,1, 1,1, 1,0,0,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 0,1,0,1, 0,1, 0,0,0,1, 1,1, 0,1,0,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 0,0,1,1, 0,1, 0,0,0,1, 1,1, 0,0,1,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, dither, 312, 4, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0);opty += 4;
-       DrawQ_SuperPic(menu_x + 4, menu_y + opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 1,1,1,1, 0,1, 0,0,0,1, 1,1, 1,1,1,1, 0);opty += 4;
-
-       c = menu_options_colorcontrol_correctionvalue.value; // intensity value that should be matched up to a 50% dither to 'correct' quake
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 1,0,0,1, 0,1, 0,0,0,1, 1,1, 1,0,0,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 0,1,0,1, 0,1, 0,0,0,1, 1,1, 0,1,0,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 0,0,1,1, 0,1, 0,0,0,1, 1,1, 0,0,1,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, dither, 312, 4, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0);m_opty += 4;
+       DrawQ_SuperPic(menu_x + 4, menu_y + m_opty, NULL  , 312, 4, 0,0, 0,0,0,1, 1,0, 1,1,1,1, 0,1, 0,0,0,1, 1,1, 1,1,1,1, 0);m_opty += 4;
+
+       c[0] = menu_options_colorcontrol_correctionvalue.value; // intensity value that should be matched up to a 50% dither to 'correct' quake
+       c[1] = c[0];
+       c[2] = c[1];
+       VID_ApplyGammaToColor(c, c);
        s = (float) 48 / 2 * vid.width / vid_conwidth.integer;
        t = (float) 48 / 2 * vid.height / vid_conheight.integer;
        u = s * 0.5;
        v = t * 0.5;
-       opty += 8;
+       m_opty += 8;
        x = 4;
-       DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, c, 0, 0, 1, 0);
-       DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);
-       DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 1,0,0,1, u,0, 1,0,0,1, 0,v, 1,0,0,1, u,v, 1,0,0,1, 0);
+       DrawQ_Fill(menu_x + x, menu_y + m_opty, 64, 48, c[0], 0, 0, 1, 0);
+       DrawQ_SuperPic(menu_x + x + 16, menu_y + m_opty + 16, dither, 16, 16, 0,0, 1,0,0,1, s,0, 1,0,0,1, 0,t, 1,0,0,1, s,t, 1,0,0,1, 0);
+       DrawQ_SuperPic(menu_x + x + 32, menu_y + m_opty + 16, dither, 16, 16, 0,0, 1,0,0,1, u,0, 1,0,0,1, 0,v, 1,0,0,1, u,v, 1,0,0,1, 0);
        x += 80;
-       DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, 0, c, 0, 1, 0);
-       DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);
-       DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 0,1,0,1, u,0, 0,1,0,1, 0,v, 0,1,0,1, u,v, 0,1,0,1, 0);
+       DrawQ_Fill(menu_x + x, menu_y + m_opty, 64, 48, 0, c[1], 0, 1, 0);
+       DrawQ_SuperPic(menu_x + x + 16, menu_y + m_opty + 16, dither, 16, 16, 0,0, 0,1,0,1, s,0, 0,1,0,1, 0,t, 0,1,0,1, s,t, 0,1,0,1, 0);
+       DrawQ_SuperPic(menu_x + x + 32, menu_y + m_opty + 16, dither, 16, 16, 0,0, 0,1,0,1, u,0, 0,1,0,1, 0,v, 0,1,0,1, u,v, 0,1,0,1, 0);
        x += 80;
-       DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, 0, 0, c, 1, 0);
-       DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0);
-       DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 0,0,1,1, u,0, 0,0,1,1, 0,v, 0,0,1,1, u,v, 0,0,1,1, 0);
+       DrawQ_Fill(menu_x + x, menu_y + m_opty, 64, 48, 0, 0, c[2], 1, 0);
+       DrawQ_SuperPic(menu_x + x + 16, menu_y + m_opty + 16, dither, 16, 16, 0,0, 0,0,1,1, s,0, 0,0,1,1, 0,t, 0,0,1,1, s,t, 0,0,1,1, 0);
+       DrawQ_SuperPic(menu_x + x + 32, menu_y + m_opty + 16, dither, 16, 16, 0,0, 0,0,1,1, u,0, 0,0,1,1, 0,v, 0,0,1,1, u,v, 0,0,1,1, 0);
        x += 80;
-       DrawQ_Fill(menu_x + x, menu_y + opty, 64, 48, c, c, c, 1, 0);
-       DrawQ_SuperPic(menu_x + x + 16, menu_y + opty + 16, dither, 16, 16, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0);
-       DrawQ_SuperPic(menu_x + x + 32, menu_y + opty + 16, dither, 16, 16, 0,0, 1,1,1,1, u,0, 1,1,1,1, 0,v, 1,1,1,1, u,v, 1,1,1,1, 0);
+       DrawQ_Fill(menu_x + x, menu_y + m_opty, 64, 48, c[0], c[1], c[2], 1, 0);
+       DrawQ_SuperPic(menu_x + x + 16, menu_y + m_opty + 16, dither, 16, 16, 0,0, 1,1,1,1, s,0, 1,1,1,1, 0,t, 1,1,1,1, s,t, 1,1,1,1, 0);
+       DrawQ_SuperPic(menu_x + x + 32, menu_y + m_opty + 16, dither, 16, 16, 0,0, 1,1,1,1, u,0, 1,1,1,1, 0,v, 1,1,1,1, u,v, 1,1,1,1, 0);
 }
 
 
@@ -2293,7 +2305,6 @@ static void M_Options_ColorControl_Key (int k, int ascii)
                switch (options_colorcontrol_cursor)
                {
                case 0:
-                       Cvar_SetValueQuick(&v_hwgamma, 1);
                        Cvar_SetValueQuick(&v_gamma, 1);
                        Cvar_SetValueQuick(&v_contrast, 1);
                        Cvar_SetValueQuick(&v_brightness, 0);
@@ -2606,7 +2617,7 @@ static void M_Keys_Draw (void)
        M_Background(320, 48 + 8 * numcommands);
 
        p = Draw_CachePic ("gfx/ttl_cstm");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/ttl_cstm");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/ttl_cstm");
 
        if (bind_grab)
                M_Print(12, 32, "Press a key or button for this action");
@@ -2635,6 +2646,7 @@ static void M_Keys_Draw (void)
                        strlcpy(keystring, "???", sizeof(keystring));
                else
                {
+                       char tinystr[2];
                        keystring[0] = 0;
                        for (j = 0;j < NUMKEYS;j++)
                        {
@@ -2642,7 +2654,7 @@ static void M_Keys_Draw (void)
                                {
                                        if (j > 0)
                                                strlcat(keystring, " or ", sizeof(keystring));
-                                       strlcat(keystring, Key_KeynumToString (keys[j]), sizeof(keystring));
+                                       strlcat(keystring, Key_KeynumToString (keys[j], tinystr, sizeof(tinystr)), sizeof(keystring));
                                }
                        }
                }
@@ -2660,6 +2672,7 @@ static void M_Keys_Key (int k, int ascii)
 {
        char    cmd[80];
        int             keys[NUMKEYS];
+       char    tinystr[2];
 
        if (bind_grab)
        {       // defining a key
@@ -2670,7 +2683,7 @@ static void M_Keys_Key (int k, int ascii)
                }
                else //if (k != '`')
                {
-                       dpsnprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString (k), bindnames[keys_cursor][0]);
+                       dpsnprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString (k, tinystr, sizeof(tinystr)), bindnames[keys_cursor][0]);
                        Cbuf_InsertText (cmd);
                }
 
@@ -2872,7 +2885,7 @@ static void M_Menu_Video_FindResolution(int w, int h, float a)
                        if (menu_video_resolutions[i].height == h && menu_video_resolutions[menu_video_resolution].height == h)
                        {
                                // if the new mode would be a worse match in pixel aspect, skip it
-                               if (abs(menu_video_resolutions[i].pixelheight - a) > abs(menu_video_resolutions[menu_video_resolution].pixelheight - a))
+                               if (fabs(menu_video_resolutions[i].pixelheight - a) > fabs(menu_video_resolutions[menu_video_resolution].pixelheight - a))
                                        continue;
                                // if it is equal in everything, skip it (prefer earlier modes)
                                if (menu_video_resolutions[i].pixelheight == a && menu_video_resolutions[menu_video_resolution].pixelheight == a)
@@ -2902,6 +2915,7 @@ static void M_Video_Draw (void)
 {
        int t;
        cachepic_t      *p;
+       char vabuf[1024];
 
        if(!!vid_fullscreen.integer != menu_video_resolutions_forfullscreen)
        {
@@ -2914,19 +2928,19 @@ static void M_Video_Draw (void)
 
        M_DrawPic(16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/vidmodes");
-       M_DrawPic((320-p->width)/2, 4, "gfx/vidmodes");
+       M_DrawPic((320-Draw_GetPicWidth(p))/2, 4, "gfx/vidmodes");
 
        t = 0;
 
        // Current and Proposed Resolution
        M_Print(16, video_cursor_table[t] - 12, "    Current Resolution");
        if (vid_supportrefreshrate && vid.userefreshrate && vid.fullscreen)
-               M_Print(220, video_cursor_table[t] - 12, va("%dx%d %.2fhz", vid.width, vid.height, vid.refreshrate));
+               M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d %.2fhz", vid.width, vid.height, vid.refreshrate));
        else
-               M_Print(220, video_cursor_table[t] - 12, va("%dx%d", vid.width, vid.height));
+               M_Print(220, video_cursor_table[t] - 12, va(vabuf, sizeof(vabuf), "%dx%d", vid.width, vid.height));
        M_Print(16, video_cursor_table[t], "        New Resolution");
-       M_Print(220, video_cursor_table[t], va("%dx%d", menu_video_resolutions[menu_video_resolution].width, menu_video_resolutions[menu_video_resolution].height));
-       M_Print(96, video_cursor_table[t] + 8, va("Type: %s", menu_video_resolutions[menu_video_resolution].type));
+       M_Print(220, video_cursor_table[t], va(vabuf, sizeof(vabuf), "%dx%d", menu_video_resolutions[menu_video_resolution].width, menu_video_resolutions[menu_video_resolution].height));
+       M_Print(96, video_cursor_table[t] + 8, va(vabuf, sizeof(vabuf), "Type: %s", menu_video_resolutions[menu_video_resolution].type));
        t++;
 
        // Bits per pixel
@@ -3101,8 +3115,9 @@ void M_Menu_Help_f (void)
 
 static void M_Help_Draw (void)
 {
+       char vabuf[1024];
        M_Background(320, 200);
-       M_DrawPic (0, 0, va("gfx/help%i", help_page));
+       M_DrawPic (0, 0, va(vabuf, sizeof(vabuf), "gfx/help%i", help_page));
 }
 
 
@@ -3193,6 +3208,7 @@ static int M_ChooseQuitMessage(int request)
        case GAME_NORMAL:
        case GAME_HIPNOTIC:
        case GAME_ROGUE:
+       case GAME_QUOTH:
        case GAME_NEHAHRA:
        case GAME_DEFEATINDETAIL2:
                if (request-- == 0) return M_QuitMessage("Are you gonna quit","this game just like","everything else?",NULL,NULL,NULL,NULL,NULL);
@@ -3348,12 +3364,13 @@ static void M_LanConfig_Draw (void)
        int             basex;
        const char      *startJoin;
        const char      *protocol;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
        M_DrawPic (16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_multi");
-       basex = (320-p->width)/2;
+       basex = (320-Draw_GetPicWidth(p))/2;
        M_DrawPic (basex, 4, "gfx/p_multi");
 
        if (StartingGame)
@@ -3361,7 +3378,7 @@ static void M_LanConfig_Draw (void)
        else
                startJoin = "Join Game";
        protocol = "TCP/IP";
-       M_Print(basex, 32, va ("%s - %s", startJoin, protocol));
+       M_Print(basex, 32, va(vabuf, sizeof(vabuf), "%s - %s", startJoin, protocol));
        basex += 8;
 
        M_Print(basex, lanConfig_cursor_table[0], "Port");
@@ -3398,6 +3415,7 @@ static void M_LanConfig_Draw (void)
 static void M_LanConfig_Key (int key, int ascii)
 {
        int             l;
+       char vabuf[1024];
 
        switch (key)
        {
@@ -3447,7 +3465,7 @@ static void M_LanConfig_Key (int key, int ascii)
                }
 
                if (lanConfig_cursor == 3)
-                       Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", lanConfig_joinname) );
                break;
 
        case K_BACKSPACE:
@@ -3926,6 +3944,7 @@ static gameinfo_t gamelist[] =
        {GAME_NORMAL, &sharewarequakegame, &registeredquakegame},
        {GAME_HIPNOTIC, &hipnoticgame, &hipnoticgame},
        {GAME_ROGUE, &roguegame, &roguegame},
+       {GAME_QUOTH, &sharewarequakegame, &registeredquakegame},
        {GAME_NEHAHRA, &nehahragame, &nehahragame},
        {GAME_TRANSFUSION, &transfusiongame, &transfusiongame},
        {GAME_GOODVSBAD2, &goodvsbad2game, &goodvsbad2game},
@@ -3969,18 +3988,19 @@ void M_GameOptions_Draw (void)
 {
        cachepic_t      *p;
        int             x;
+       char vabuf[1024];
 
        M_Background(320, 200);
 
        M_DrawPic (16, 4, "gfx/qplaque");
        p = Draw_CachePic ("gfx/p_multi");
-       M_DrawPic ( (320-p->width)/2, 4, "gfx/p_multi");
+       M_DrawPic ( (320-Draw_GetPicWidth(p))/2, 4, "gfx/p_multi");
 
        M_DrawTextBox (152, 32, 10, 1);
        M_Print(160, 40, "begin game");
 
        M_Print(0, 56, "      Max players");
-       M_Print(160, 56, va("%i", maxplayers) );
+       M_Print(160, 56, va(vabuf, sizeof(vabuf), "%i", maxplayers) );
 
        if (gamemode != GAME_GOODVSBAD2)
        {
@@ -4073,20 +4093,20 @@ void M_GameOptions_Draw (void)
                if (fraglimit.integer == 0)
                        M_Print(160, 88, "none");
                else
-                       M_Print(160, 88, va("%i frags", fraglimit.integer));
+                       M_Print(160, 88, va(vabuf, sizeof(vabuf), "%i frags", fraglimit.integer));
 
                M_Print(0, 96, "       Time Limit");
                if (timelimit.integer == 0)
                        M_Print(160, 96, "none");
                else
-                       M_Print(160, 96, va("%i minutes", timelimit.integer));
+                       M_Print(160, 96, va(vabuf, sizeof(vabuf), "%i minutes", timelimit.integer));
        }
 
        M_Print(0, 104, "    Public server");
        M_Print(160, 104, (sv_public.integer == 0) ? "no" : "yes");
 
        M_Print(0, 112, "   Server maxrate");
-       M_Print(160, 112, va("%i", sv_maxrate.integer));
+       M_Print(160, 112, va(vabuf, sizeof(vabuf), "%i", sv_maxrate.integer));
 
        M_Print(0, 128, "      Server name");
        M_DrawTextBox (0, 132, 38, 1);
@@ -4118,7 +4138,7 @@ void M_GameOptions_Draw (void)
                        M_Print(x, 146, " More than 255 players??");
                        M_Print(x, 154, "  First, question your  ");
                        M_Print(x, 162, "   sanity, then email   ");
-                       M_Print(x, 170, " lordhavoc@ghdigital.com");
+                       M_Print(x, 170, "darkplacesengine@gmail.com");
                }
                else
                        m_serverInfoMessage = false;
@@ -4290,6 +4310,7 @@ static void M_GameOptions_Key (int key, int ascii)
 {
        int l;
        char hostnamebuf[128];
+       char vabuf[1024];
 
        switch (key)
        {
@@ -4330,10 +4351,10 @@ static void M_GameOptions_Key (int key, int ascii)
                if (gameoptions_cursor == 0)
                {
                        if (sv.active)
-                               Cbuf_AddText ("disconnect\n");
-                       Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) );
+                               Cbuf_AddText("disconnect\n");
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "maxplayers %u\n", maxplayers) );
 
-                       Cbuf_AddText ( va ("map %s\n", gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name) );
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "map %s\n", gameoptions_levels->levels[gameoptions_levels->episodes[startepisode].firstLevel + startlevel].name) );
                        return;
                }
 
@@ -4392,9 +4413,10 @@ void M_Menu_ServerList_f (void)
 
 static void M_ServerList_Draw (void)
 {
-       int n, y, visible, start, end, numplayers, maxplayers;
+       int n, y, visible, start, end, statnumplayers, statmaxplayers;
        cachepic_t *p;
        const char *s;
+       char vabuf[1024];
 
        // use as much vertical space as available
        if (gamemode == GAME_TRANSFUSION)
@@ -4402,8 +4424,8 @@ static void M_ServerList_Draw (void)
        else
                M_Background(640, vid_conheight.integer);
        // scroll the list as the cursor moves
-       ServerList_GetPlayerStatistics(&numplayers, &maxplayers);
-       s = va("%i/%i masters %i/%i servers %i/%i players", masterreplycount, masterquerycount, serverreplycount, serverquerycount, numplayers, maxplayers);
+       ServerList_GetPlayerStatistics(&statnumplayers, &statmaxplayers);
+       s = va(vabuf, sizeof(vabuf), "%i/%i masters %i/%i servers %i/%i players", masterreplycount, masterquerycount, serverreplycount, serverquerycount, statnumplayers, statmaxplayers);
        M_PrintRed((640 - strlen(s) * 8) / 2, 32, s);
        if (*m_return_reason)
                M_Print(16, menu_height - 8, m_return_reason);
@@ -4413,7 +4435,7 @@ static void M_ServerList_Draw (void)
        end = min(start + visible, serverlist_viewcount);
 
        p = Draw_CachePic ("gfx/p_multi");
-       M_DrawPic((640 - p->width) / 2, 4, "gfx/p_multi");
+       M_DrawPic((640 - Draw_GetPicWidth(p)) / 2, 4, "gfx/p_multi");
        if (end > start)
        {
                for (n = start;n < end;n++)
@@ -4443,6 +4465,7 @@ static void M_ServerList_Draw (void)
 
 static void M_ServerList_Key(int k, int ascii)
 {
+       char vabuf[1024];
        switch (k)
        {
        case K_ESCAPE:
@@ -4475,7 +4498,7 @@ static void M_ServerList_Key(int k, int ascii)
        case K_ENTER:
                S_LocalSound ("sound/misc/menu2.wav");
                if (serverlist_viewcount)
-                       Cbuf_AddText(va("connect \"%s\"\n", ServerList_GetViewEntry(slist_cursor)->info.cname));
+                       Cbuf_AddText(va(vabuf, sizeof(vabuf), "connect \"%s\"\n", ServerList_GetViewEntry(slist_cursor)->info.cname));
                break;
 
        default:
@@ -4508,25 +4531,31 @@ static int modlist_cursor;
 static int modlist_count = 0;
 static modlist_entry_t modlist[MODLIST_TOTALSIZE];
 
-void ModList_RebuildList(void)
+static void ModList_RebuildList(void)
 {
        int i,j;
        stringlist_t list;
+       const char *description;
 
        stringlistinit(&list);
        listdirectory(&list, fs_basedir, "");
-       stringlistsort(&list);
+       stringlistsort(&list, true);
        modlist_count = 0;
        modlist_numenabled = fs_numgamedirs;
-       for (i = 0;i < list.numstrings;i++)
+       for (i = 0;i < list.numstrings && modlist_count < MODLIST_TOTALSIZE;i++)
        {
-               if (modlist_count >= MODLIST_TOTALSIZE) break;
-               // check all dirs to see if they "appear" to be mods
+               // quickly skip names with dot characters - generally these are files, not directories
+               if (strchr(list.strings[i], '.')) continue;
+
                // reject any dirs that are part of the base game
                if (gamedirname1 && !strcasecmp(gamedirname1, list.strings[i])) continue;
                //if (gamedirname2 && !strcasecmp(gamedirname2, list.strings[i])) continue;
-               if (FS_CheckNastyPath (list.strings[i], true)) continue;
-               if (!FS_CheckGameDir(list.strings[i])) continue;
+
+               // check if we can get a description of the gamedir (from modinfo.txt),
+               // or if the directory is valid but has no description (fs_checkgamedir_missing)
+               // otherwise this isn't a valid gamedir
+               description = FS_CheckGameDir(list.strings[i]);
+               if (description == NULL || description == fs_checkgamedir_missing) continue;
 
                strlcpy (modlist[modlist_count].dir, list.strings[i], sizeof(modlist[modlist_count].dir));
                //check currently loaded mods
@@ -4545,7 +4574,7 @@ void ModList_RebuildList(void)
        stringlistfreecontents(&list);
 }
 
-void ModList_Enable (void)
+static void ModList_Enable (void)
 {
        int i;
        int numgamedirs;
@@ -4642,7 +4671,7 @@ static void M_ModList_Draw (void)
        end = min(start + visible, modlist_count);
 
        p = Draw_CachePic ("gfx/p_option");
-       M_DrawPic((640 - p->width) / 2, 4, "gfx/p_option");
+       M_DrawPic((640 - Draw_GetPicWidth(p)) / 2, 4, "gfx/p_option");
        if (end > start)
        {
                for (n = start;n < end;n++)
@@ -4714,7 +4743,7 @@ static void M_Draw(void);
 void M_ToggleMenu(int mode);
 static void M_Shutdown(void);
 
-void M_Init (void)
+static void M_Init (void)
 {
        menuplyr_load = true;
        menuplyr_pixels = NULL;
@@ -4742,6 +4771,7 @@ void M_Init (void)
 
 void M_Draw (void)
 {
+       char vabuf[1024];
        if (key_dest != key_menu && key_dest != key_menu_grabbed)
                m_state = m_none;
 
@@ -4855,11 +4885,11 @@ void M_Draw (void)
                        g = (int)(realtime * 64)%96;
                        scale_y_rate = (float)(g+1) / 96;
                        top_offset = (g+12)/12;
-                       p = Draw_CachePic (va("gfx/menu/blooddrip%i", top_offset));
+                       p = Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/menu/blooddrip%i", top_offset));
                        drop1 = Draw_CachePic ("gfx/menu/blooddrop1");
                        drop2 = Draw_CachePic ("gfx/menu/blooddrop2");
                        drop3 = Draw_CachePic ("gfx/menu/blooddrop3");
-                       for (scale_x = 0; scale_x <= vid_conwidth.integer; scale_x += p->width) {
+                       for (scale_x = 0; scale_x <= vid_conwidth.integer; scale_x += Draw_GetPicWidth(p)) {
                                for (scale_y = -scale_y_repeat; scale_y <= vid_conheight.integer; scale_y += scale_y_repeat) {
                                        DrawQ_Pic (scale_x + 21, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop3, 0, 0, 1, 1, 1, 1, 0);
                                        DrawQ_Pic (scale_x +  116, scale_y_repeat + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0);
@@ -4873,7 +4903,7 @@ void M_Draw (void)
                                        DrawQ_Pic (scale_x + 557, scale_y_repeat * .9425 + scale_y + scale_y_rate * scale_y_repeat, drop1, 0, 0, 1, 1, 1, 1, 0);
                                        DrawQ_Pic (scale_x + 606, scale_y_repeat * .5 + scale_y + scale_y_rate * scale_y_repeat, drop2, 0, 0, 1, 1, 1, 1, 0);
                                }
-                               DrawQ_Pic (scale_x, -1, Draw_CachePic (va("gfx/menu/blooddrip%i", top_offset)), 0, 0, 1, 1, 1, 1, 0);
+                               DrawQ_Pic (scale_x, -1, Draw_CachePic (va(vabuf, sizeof(vabuf), "gfx/menu/blooddrip%i", top_offset)), 0, 0, 1, 1, 1, 1, 0);
                        }
                }
        }
@@ -4992,8 +5022,13 @@ void M_KeyEvent (int key, int ascii, qboolean downevent)
 
 }
 
-void M_NewMap(void)
+static void M_NewMap(void)
+{
+}
+
+static int M_GetServerListEntryCategory(const serverlist_entry_t *entry)
 {
+       return 0;
 }
 
 void M_Shutdown(void)
@@ -5015,11 +5050,170 @@ static const char *m_required_func[] = {
 
 static int m_numrequiredfunc = sizeof(m_required_func) / sizeof(char*);
 
+static prvm_required_field_t m_required_fields[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x)
+#define PRVM_DECLARE_menuglobalvector(x)
+#define PRVM_DECLARE_menuglobalstring(x)
+#define PRVM_DECLARE_menuglobaledict(x)
+#define PRVM_DECLARE_menuglobalfunction(x)
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_menufieldvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_menufieldstring(x) {ev_string, #x},
+#define PRVM_DECLARE_menufieldedict(x) {ev_entity, #x},
+#define PRVM_DECLARE_menufieldfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+static int m_numrequiredfields = sizeof(m_required_fields) / sizeof(m_required_fields[0]);
+
+static prvm_required_field_t m_required_globals[] =
+{
+#define PRVM_DECLARE_serverglobalfloat(x)
+#define PRVM_DECLARE_serverglobalvector(x)
+#define PRVM_DECLARE_serverglobalstring(x)
+#define PRVM_DECLARE_serverglobaledict(x)
+#define PRVM_DECLARE_serverglobalfunction(x)
+#define PRVM_DECLARE_clientglobalfloat(x)
+#define PRVM_DECLARE_clientglobalvector(x)
+#define PRVM_DECLARE_clientglobalstring(x)
+#define PRVM_DECLARE_clientglobaledict(x)
+#define PRVM_DECLARE_clientglobalfunction(x)
+#define PRVM_DECLARE_menuglobalfloat(x) {ev_float, #x},
+#define PRVM_DECLARE_menuglobalvector(x) {ev_vector, #x},
+#define PRVM_DECLARE_menuglobalstring(x) {ev_string, #x},
+#define PRVM_DECLARE_menuglobaledict(x) {ev_entity, #x},
+#define PRVM_DECLARE_menuglobalfunction(x) {ev_function, #x},
+#define PRVM_DECLARE_serverfieldfloat(x)
+#define PRVM_DECLARE_serverfieldvector(x)
+#define PRVM_DECLARE_serverfieldstring(x)
+#define PRVM_DECLARE_serverfieldedict(x)
+#define PRVM_DECLARE_serverfieldfunction(x)
+#define PRVM_DECLARE_clientfieldfloat(x)
+#define PRVM_DECLARE_clientfieldvector(x)
+#define PRVM_DECLARE_clientfieldstring(x)
+#define PRVM_DECLARE_clientfieldedict(x)
+#define PRVM_DECLARE_clientfieldfunction(x)
+#define PRVM_DECLARE_menufieldfloat(x)
+#define PRVM_DECLARE_menufieldvector(x)
+#define PRVM_DECLARE_menufieldstring(x)
+#define PRVM_DECLARE_menufieldedict(x)
+#define PRVM_DECLARE_menufieldfunction(x)
+#define PRVM_DECLARE_serverfunction(x)
+#define PRVM_DECLARE_clientfunction(x)
+#define PRVM_DECLARE_menufunction(x)
+#define PRVM_DECLARE_field(x)
+#define PRVM_DECLARE_global(x)
+#define PRVM_DECLARE_function(x)
+#include "prvm_offsets.h"
+#undef PRVM_DECLARE_serverglobalfloat
+#undef PRVM_DECLARE_serverglobalvector
+#undef PRVM_DECLARE_serverglobalstring
+#undef PRVM_DECLARE_serverglobaledict
+#undef PRVM_DECLARE_serverglobalfunction
+#undef PRVM_DECLARE_clientglobalfloat
+#undef PRVM_DECLARE_clientglobalvector
+#undef PRVM_DECLARE_clientglobalstring
+#undef PRVM_DECLARE_clientglobaledict
+#undef PRVM_DECLARE_clientglobalfunction
+#undef PRVM_DECLARE_menuglobalfloat
+#undef PRVM_DECLARE_menuglobalvector
+#undef PRVM_DECLARE_menuglobalstring
+#undef PRVM_DECLARE_menuglobaledict
+#undef PRVM_DECLARE_menuglobalfunction
+#undef PRVM_DECLARE_serverfieldfloat
+#undef PRVM_DECLARE_serverfieldvector
+#undef PRVM_DECLARE_serverfieldstring
+#undef PRVM_DECLARE_serverfieldedict
+#undef PRVM_DECLARE_serverfieldfunction
+#undef PRVM_DECLARE_clientfieldfloat
+#undef PRVM_DECLARE_clientfieldvector
+#undef PRVM_DECLARE_clientfieldstring
+#undef PRVM_DECLARE_clientfieldedict
+#undef PRVM_DECLARE_clientfieldfunction
+#undef PRVM_DECLARE_menufieldfloat
+#undef PRVM_DECLARE_menufieldvector
+#undef PRVM_DECLARE_menufieldstring
+#undef PRVM_DECLARE_menufieldedict
+#undef PRVM_DECLARE_menufieldfunction
+#undef PRVM_DECLARE_serverfunction
+#undef PRVM_DECLARE_clientfunction
+#undef PRVM_DECLARE_menufunction
+#undef PRVM_DECLARE_field
+#undef PRVM_DECLARE_global
+#undef PRVM_DECLARE_function
+};
+
+static int m_numrequiredglobals = sizeof(m_required_globals) / sizeof(m_required_globals[0]);
+
 void MR_SetRouting (qboolean forceold);
 
-void MP_Error(const char *format, ...) DP_FUNC_PRINTF(1);
-void MP_Error(const char *format, ...)
+void MVM_error_cmd(const char *format, ...) DP_FUNC_PRINTF(1);
+void MVM_error_cmd(const char *format, ...)
 {
+       prvm_prog_t *prog = MVM_prog;
        static qboolean processingError = false;
        char errorstring[MAX_INPUTLINE];
        va_list argptr;
@@ -5031,10 +5225,10 @@ void MP_Error(const char *format, ...)
 
        if( !processingError ) {
                processingError = true;
-               PRVM_Crash();
+               PRVM_Crash(prog);
                processingError = false;
        } else {
-               Con_Printf( "Menu_Error: Recursive call to MP_Error (from PRVM_Crash)!\n" );
+               Con_Printf( "Menu_Error: Recursive call to MVM_error_cmd (from PRVM_Crash)!\n" );
        }
 
        // fall back to the normal menu
@@ -5053,24 +5247,62 @@ void MP_Error(const char *format, ...)
        Host_AbortCurrentFrame();
 }
 
-void MP_KeyEvent (int key, int ascii, qboolean downevent)
+static void MVM_begin_increase_edicts(prvm_prog_t *prog)
+{
+}
+
+static void MVM_end_increase_edicts(prvm_prog_t *prog)
+{
+}
+
+static void MVM_init_edict(prvm_prog_t *prog, prvm_edict_t *edict)
+{
+}
+
+static void MVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed)
+{
+}
+
+static void MVM_count_edicts(prvm_prog_t *prog)
+{
+       int i;
+       prvm_edict_t *ent;
+       int active;
+
+       active = 0;
+       for (i=0 ; i<prog->num_edicts ; i++)
+       {
+               ent = PRVM_EDICT_NUM(i);
+               if (ent->priv.required->free)
+                       continue;
+               active++;
+       }
+
+       Con_Printf("num_edicts:%3i\n", prog->num_edicts);
+       Con_Printf("active    :%3i\n", active);
+}
+
+static qboolean MVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent)
+{
+       return true;
+}
+
+static void MP_KeyEvent (int key, int ascii, qboolean downevent)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
 
        // pass key
-       prog->globals.generic[OFS_PARM0] = (float) key;
-       prog->globals.generic[OFS_PARM1] = (float) ascii;
+       prog->globals.fp[OFS_PARM0] = (prvm_vec_t) key;
+       prog->globals.fp[OFS_PARM1] = (prvm_vec_t) ascii;
        if (downevent)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_keydown,"m_keydown(float key, float ascii) required");
-       else if (prog->funcoffsets.m_keyup)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_keyup,"m_keyup(float key, float ascii) required");
-
-       PRVM_End;
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_keydown),"m_keydown(float key, float ascii) required");
+       else if (PRVM_menufunction(m_keyup))
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_keyup),"m_keyup(float key, float ascii) required");
 }
 
-void MP_Draw (void)
+static void MP_Draw (void)
 {
+       prvm_prog_t *prog = MVM_prog;
        // declarations that are needed right now
 
        float oldquality;
@@ -5086,14 +5318,11 @@ void MP_Draw (void)
        // TODO: this needs to be exposed to R_SetView (or something similar) ASAP [2/5/2008 Andreas]
        r_refdef.scene.time = realtime;
 
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
-
        // FIXME: this really shouldnt error out lest we have a very broken refdef state...?
        // or does it kill the server too?
-       PRVM_ExecuteProgram(prog->funcoffsets.m_draw,"m_draw() required");
-
-       PRVM_End;
+       PRVM_G_FLOAT(OFS_PARM0) = vid.width;
+       PRVM_G_FLOAT(OFS_PARM1) = vid.height;
+       prog->ExecuteProgram(prog, PRVM_menufunction(m_draw),"m_draw() required");
 
        // TODO: imo this should be moved into scene, too [1/27/2008 Andreas]
        r_refdef.view.quality = oldquality;
@@ -5101,64 +5330,81 @@ void MP_Draw (void)
        R_SelectScene( RST_CLIENT );
 }
 
-void MP_ToggleMenu(int mode)
+static void MP_ToggleMenu(int mode)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
 
-       prog->globals.generic[OFS_PARM0] = (float) mode;
-       PRVM_ExecuteProgram(prog->funcoffsets.m_toggle,"m_toggle() required");
-
-       PRVM_End;
+       prog->globals.fp[OFS_PARM0] = (prvm_vec_t) mode;
+       prog->ExecuteProgram(prog, PRVM_menufunction(m_toggle),"m_toggle(float mode) required");
 }
 
-void MP_NewMap(void)
+static void MP_NewMap(void)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
-       if (prog->funcoffsets.m_newmap)
-               PRVM_ExecuteProgram(prog->funcoffsets.m_newmap,"m_newmap() required");
-       PRVM_End;
+       prvm_prog_t *prog = MVM_prog;
+       if (PRVM_menufunction(m_newmap))
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_newmap),"m_newmap() required");
 }
 
-void MP_Shutdown (void)
+const serverlist_entry_t *serverlist_callbackentry = NULL;
+static int MP_GetServerListEntryCategory(const serverlist_entry_t *entry)
 {
-       PRVM_Begin;
-       PRVM_SetProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
+       serverlist_callbackentry = entry;
+       if (PRVM_menufunction(m_gethostcachecategory))
+       {
+               prog->globals.fp[OFS_PARM0] = (prvm_vec_t) -1;
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_gethostcachecategory),"m_gethostcachecategory(float entry) required");
+               serverlist_callbackentry = NULL;
+               return prog->globals.fp[OFS_RETURN];
+       }
+       else
+       {
+               return 0;
+       }
+}
 
-       PRVM_ExecuteProgram(prog->funcoffsets.m_shutdown,"m_shutdown() required");
+static void MP_Shutdown (void)
+{
+       prvm_prog_t *prog = MVM_prog;
+       if (prog->loaded)
+               prog->ExecuteProgram(prog, PRVM_menufunction(m_shutdown),"m_shutdown() required");
 
        // reset key_dest
        key_dest = key_game;
 
        // AK not using this cause Im not sure whether this is useful at all instead :
-       PRVM_ResetProg();
-
-       PRVM_End;
+       PRVM_Prog_Reset(prog);
 }
 
-void MP_Init (void)
+static void MP_Init (void)
 {
-       PRVM_Begin;
-       PRVM_InitProg(PRVM_MENUPROG);
+       prvm_prog_t *prog = MVM_prog;
+       PRVM_Prog_Init(prog);
 
-       prog->headercrc = M_PROGHEADER_CRC;
        prog->edictprivate_size = 0; // no private struct used
-       prog->name = M_NAME;
+       prog->name = "menu";
        prog->num_edicts = 1;
        prog->limit_edicts = M_MAX_EDICTS;
        prog->extensionstring = vm_m_extensions;
        prog->builtins = vm_m_builtins;
        prog->numbuiltins = vm_m_numbuiltins;
-       prog->init_cmd = VM_M_Cmd_Init;
-       prog->reset_cmd = VM_M_Cmd_Reset;
-       prog->error_cmd = MP_Error;
-       prog->ExecuteProgram = MVM_ExecuteProgram;
+
+       // all callbacks must be defined (pointers are not checked before calling)
+       prog->begin_increase_edicts = MVM_begin_increase_edicts;
+       prog->end_increase_edicts   = MVM_end_increase_edicts;
+       prog->init_edict            = MVM_init_edict;
+       prog->free_edict            = MVM_free_edict;
+       prog->count_edicts          = MVM_count_edicts;
+       prog->load_edict            = MVM_load_edict;
+       prog->init_cmd              = MVM_init_cmd;
+       prog->reset_cmd             = MVM_reset_cmd;
+       prog->error_cmd             = MVM_error_cmd;
+       prog->ExecuteProgram        = MVM_ExecuteProgram;
 
        // allocate the mempools
-       prog->progs_mempool = Mem_AllocPool(M_PROG_FILENAME, 0, NULL);
+       prog->progs_mempool = Mem_AllocPool(menu_progs.string, 0, NULL);
 
-       PRVM_LoadProgs(M_PROG_FILENAME, m_numrequiredfunc, m_required_func, 0, NULL, 0, NULL);
+       PRVM_Prog_Load(prog, menu_progs.string, NULL, 0, m_numrequiredfunc, m_required_func, m_numrequiredfields, m_required_fields, m_numrequiredglobals, m_required_globals);
 
        // note: OP_STATE is not supported by menu qc, we don't even try to detect
        // it here
@@ -5166,9 +5412,10 @@ void MP_Init (void)
        in_client_mouse = true;
 
        // call the prog init
-       PRVM_ExecuteProgram(prog->funcoffsets.m_init,"m_init() required");
+       prog->ExecuteProgram(prog, PRVM_menufunction(m_init),"m_init() required");
 
-       PRVM_End;
+       // Once m_init was called, we consider menuqc code fully initialized.
+       prog->inittime = realtime;
 }
 
 //============================================================================
@@ -5179,11 +5426,12 @@ void (*MR_Draw) (void);
 void (*MR_ToggleMenu) (int mode);
 void (*MR_Shutdown) (void);
 void (*MR_NewMap) (void);
+int (*MR_GetServerListEntryCategory) (const serverlist_entry_t *entry);
 
 void MR_SetRouting(qboolean forceold)
 {
        // if the menu prog isnt available or forceqmenu ist set, use the old menu
-       if(!FS_FileExists(M_PROG_FILENAME) || forceqmenu.integer || forceold)
+       if(!FS_FileExists(menu_progs.string) || forceqmenu.integer || forceold)
        {
                // set menu router function pointers
                MR_KeyEvent = M_KeyEvent;
@@ -5191,6 +5439,7 @@ void MR_SetRouting(qboolean forceold)
                MR_ToggleMenu = M_ToggleMenu;
                MR_Shutdown = M_Shutdown;
                MR_NewMap = M_NewMap;
+               MR_GetServerListEntryCategory = M_GetServerListEntryCategory;
                M_Init();
        }
        else
@@ -5201,17 +5450,19 @@ void MR_SetRouting(qboolean forceold)
                MR_ToggleMenu = MP_ToggleMenu;
                MR_Shutdown = MP_Shutdown;
                MR_NewMap = MP_NewMap;
+               MR_GetServerListEntryCategory = MP_GetServerListEntryCategory;
                MP_Init();
        }
 }
 
 void MR_Restart(void)
 {
-       MR_Shutdown ();
+       if(MR_Shutdown)
+               MR_Shutdown ();
        MR_SetRouting (FALSE);
 }
 
-void Call_MR_ToggleMenu_f(void)
+static void Call_MR_ToggleMenu_f(void)
 {
        int m;
        m = ((Cmd_Argc() < 2) ? -1 : atoi(Cmd_Argv(1)));
@@ -5225,6 +5476,7 @@ void MR_Init_Commands(void)
        // set router console commands
        Cvar_RegisterVariable (&forceqmenu);
        Cvar_RegisterVariable (&menu_options_colorcontrol_correctionvalue);
+       Cvar_RegisterVariable (&menu_progs);
        Cmd_AddCommand ("menu_restart",MR_Restart, "restart menu system (reloads menu.dat)");
        Cmd_AddCommand ("togglemenu", Call_MR_ToggleMenu_f, "opens or closes menu");
 }
@@ -5238,7 +5490,7 @@ void MR_Init(void)
        res_count = VID_SortModes(res, res_count, false, false, true);
        if(res_count)
        {
-               video_resolutions_count = res_count;
+               video_resolutions_count = (int)res_count;
                video_resolutions = (video_resolution_t *) Mem_Alloc(cls.permanentmempool, sizeof(*video_resolutions) * (video_resolutions_count + 1));
                memset(&video_resolutions[video_resolutions_count], 0, sizeof(video_resolutions[video_resolutions_count]));
                for(i = 0; i < res_count; ++i)