From 23866f0196ee0058c7c25ac51f7922d8cbb00413 Mon Sep 17 00:00:00 2001
From: Spoike <acceptthis@users.sourceforge.net>
Date: Sun, 17 Aug 2014 03:18:43 +0000
Subject: [PATCH] attempt to remember menu selections for when the menu is next
 opened. for keyboard users that don't realise that the mouse works.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4723 fc73d0e0-1445-4013-8a0c-d673dee63da5
---
 engine/client/m_items.c   | 80 +++++++++++++++++++++++++++++++++++----
 engine/client/m_multi.c   | 70 +++++++++++++++-------------------
 engine/client/m_options.c | 32 +++++++++-------
 engine/client/m_single.c  |  7 ++--
 engine/client/menu.h      | 12 +++++-
 engine/client/pr_csqc.c   |  2 +-
 6 files changed, 135 insertions(+), 68 deletions(-)

diff --git a/engine/client/m_items.c b/engine/client/m_items.c
index 8fbd7512e..3011a9b6a 100644
--- a/engine/client/m_items.c
+++ b/engine/client/m_items.c
@@ -13,6 +13,7 @@ extern cvar_t cl_cursorbias;
 extern cvar_t m_preset_chosen;
 menu_t *currentmenu;
 menu_t *firstmenu;
+menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old);
 
 void Draw_TextBox (int x, int y, int width, int lines)
 {
@@ -409,9 +410,13 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu
 		if (!option->common.ishidden)
 		switch(option->common.type)
 		{
+		case mt_menucursor:
+			if ((int)(realtime*4)&1)
+				Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d");
+			break;
 		case mt_text:
 			if (!option->text.text)
-			{	//blinking cursor image hack
+			{	//blinking cursor image hack (FIXME)
 				if ((int)(realtime*4)&1)
 					Draw_FunString(xpos+option->common.posx, ypos+option->common.posy, "^Ue00d");
 			}
@@ -809,10 +814,45 @@ menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, int height, char *picnam
 	return MC_AddPicture(menu, x, y, width, height, picname);
 }
 
-menupicture_t *MC_AddCursor(menu_t *menu, int x, int y)
+menuoption_t *MC_AddCursorSmall(menu_t *menu, menuresel_t *reselection, int x, int y)
+{
+	menuoption_t *n = Z_Malloc(sizeof(menucommon_t));
+	if (reselection)
+		menu->reselection = reselection;
+	n->common.type = mt_menucursor;
+	n->common.iszone = true;
+	n->common.posx = x;
+	n->common.posy = y;
+
+	n->common.next = menu->options;
+	menu->options = (menuoption_t *)n;
+
+
+	if (menu->reselection)
+	{
+		menuoption_t *sel, *firstsel = M_NextSelectableItem(menu, NULL);
+		for (sel = firstsel; sel; )
+		{
+			if (sel->common.posx == menu->reselection->x && sel->common.posy == menu->reselection->y)
+			{
+				menu->selecteditem = sel;
+				n->common.posy = sel->common.posy;
+				break;
+			}
+			sel = M_NextSelectableItem(menu, sel);
+			if (sel == firstsel)
+				break;
+		}
+	}
+	return n;
+}
+
+menupicture_t *MC_AddCursor(menu_t *menu, menuresel_t *reselection, int x, int y)
 {
 	int mgt;
 	menupicture_t *n = Z_Malloc(sizeof(menupicture_t));
+	if (reselection)
+		menu->reselection = reselection;
 	n->common.type = mt_menudot;
 	n->common.iszone = true;
 	n->common.posx = x;
@@ -844,6 +884,23 @@ menupicture_t *MC_AddCursor(menu_t *menu, int x, int y)
 		maxdots = 6;
 		dotofs=0;
 	}
+
+	if (menu->reselection)
+	{
+		menuoption_t *sel, *firstsel = M_NextSelectableItem(menu, NULL);
+		for (sel = firstsel; sel; )
+		{
+			if (sel->common.posx == menu->reselection->x && sel->common.posy == menu->reselection->y)
+			{
+				menu->selecteditem = sel;
+				n->common.posy = sel->common.posy;
+				break;
+			}
+			sel = M_NextSelectableItem(menu, sel);
+			if (sel == firstsel)
+				break;
+		}
+	}
 	return n;
 }
 
@@ -1462,6 +1519,12 @@ void M_HideMenu (menu_t *menu)
 void M_RemoveMenu (menu_t *menu)
 {
 	menuoption_t *op, *oop;
+	if (menu->reselection)
+	{
+		menu->reselection->x = menu->selecteditem->common.posx;
+		menu->reselection->y = menu->selecteditem->common.posy;
+	}
+
 	if (menu->remove)
 		menu->remove(menu);
 	if (menu == firstmenu)
@@ -1869,6 +1932,7 @@ void M_Menu_Main_f (void)
 	menubutton_t *b;
 	menu_t *mainm;
 	mpic_t *p;
+	static menuresel_t resel;
 
 	int mgt;
 
@@ -1957,7 +2021,7 @@ void M_Menu_Main_f (void)
 			b->common.width = 12*20;
 			b->common.height = 32;
 
-			mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 42, mainm->selecteditem->common.posy);
+			mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 42, mainm->selecteditem->common.posy);
 		}
 	}
 	else if (mgt == MGT_HEXEN2)
@@ -1998,7 +2062,7 @@ void M_Menu_Main_f (void)
 		b->common.width = 12*20;
 		b->common.height = 20;
 
-		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 56, mainm->selecteditem->common.posy);
+		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 56, mainm->selecteditem->common.posy);
 	}
 	else if (QBigFontWorks())
 	{
@@ -2032,7 +2096,7 @@ void M_Menu_Main_f (void)
 			MC_AddConsoleCommandQBigFont(mainm, 72, 92,	"Help       ", "help\n");
 		MC_AddConsoleCommandQBigFont	(mainm, 72, 112,"Quit       ", "menu_quit\n");
 
-		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 54, 32);
+		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32);
 	}
 	else
 	{
@@ -2090,14 +2154,14 @@ void M_Menu_Main_f (void)
 		b->common.width = p->width;
 		b->common.height = 20;
 
-		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 54, 32);
+		mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, &resel, 54, 32);
 	}
 
 	if (!m_preset_chosen.ival)
 		M_Menu_Preset_f();
 }
 
-int MC_AddBulk(struct menu_s *menu, menubulk_t *bulk, int xstart, int xtextend, int y)
+int MC_AddBulk(struct menu_s *menu, menuresel_t *resel, menubulk_t *bulk, int xstart, int xtextend, int y)
 {
 	int selectedy = y;
 	menuoption_t *selected = NULL;
@@ -2202,6 +2266,6 @@ int MC_AddBulk(struct menu_s *menu, menubulk_t *bulk, int xstart, int xtextend,
 	menu->selecteditem = selected;
 	if (selected)
 		selectedy = selected->common.posy;
-	menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, xtextend + 8, 0, selectedy, NULL, false);
+	menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, resel, xtextend + 8, selectedy);
 	return y;
 }
diff --git a/engine/client/m_multi.c b/engine/client/m_multi.c
index 750d65741..d8381906e 100644
--- a/engine/client/m_multi.c
+++ b/engine/client/m_multi.c
@@ -13,6 +13,7 @@ void M_Menu_MultiPlayer_f (void)
 	menu_t *menu;
 	mpic_t *p;
 	int mgt;
+	static menuresel_t resel;
 
 	p = NULL;
 	Key_Dest_Add(kdm_menu);
@@ -47,7 +48,7 @@ void M_Menu_MultiPlayer_f (void)
 		MC_AddConsoleCommandHexen2BigFont	(menu, 80, mgt,	"Player Setup",	"menu_setup\n");mgt+=20;
 		MC_AddConsoleCommandHexen2BigFont	(menu, 80, mgt,	"Demos       ",	"menu_demo\n");mgt+=20;
 
-		menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, 48, 64);
+		menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 48, 64);
 		return;
 	}
 	else if (QBigFontWorks())
@@ -63,7 +64,7 @@ void M_Menu_MultiPlayer_f (void)
 		MC_AddConsoleCommandQBigFont	(menu, 72, mgt,	"Player Setup",	"menu_setup\n");mgt+=20;
 		MC_AddConsoleCommandQBigFont	(menu, 72, mgt,	"Demos       ",	"menu_demo\n");mgt+=20;
 
-		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
+		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
 		return;
 	}
 	else
@@ -98,7 +99,7 @@ void M_Menu_MultiPlayer_f (void)
 		b->common.width = p?p->width:320;
 	}
 
-	menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
+	menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
 }
 
 extern cvar_t	team, skin;
@@ -324,11 +325,12 @@ void M_Menu_Setup_f (void)
 	menu_t *menu;
 	menucustom_t *ci;
 	menubutton_t *b;
+	static menuresel_t resel;
 
 	mgt = M_GameType();
 	if (mgt == MGT_QUAKE2)	//quake2 main menu.
 	{
-		if (R2D_SafeCachePic("pics/m_banner_plauer_setup"))
+		if (R2D_SafeCachePic("pics/m_banner_player_setup"))
 		{
 			static const char *modeloptions[] =
 			{
@@ -359,30 +361,7 @@ void M_Menu_Setup_f (void)
 			cu->draw = MSetupQ2_TransDraw;
 			cu->key = MSetupQ2_ChangeSkin;
 
-/*			MC_AddSelectablePicture(mainm, 68, 13, "pics/m_main_game");
-			MC_AddSelectablePicture(mainm, 68, 53, "pics/m_main_multiplayer");
-			MC_AddSelectablePicture(mainm, 68, 93, "pics/m_main_options");
-			MC_AddSelectablePicture(mainm, 68, 133, "pics/m_main_video");
-			MC_AddSelectablePicture(mainm, 68, 173, "pics/m_main_quit");
-
-			b = MC_AddConsoleCommand	(mainm, 68, 13,	"", "menu_single\n");
-			mainm->selecteditem = (menuoption_t *)b;
-			b->common.width = 12*20;
-			b->common.height = 20;
-			b = MC_AddConsoleCommand	(mainm, 68, 53,	"", "menu_multi\n");
-			b->common.width = 12*20;
-			b->common.height = 20;
-			b = MC_AddConsoleCommand	(mainm, 68, 93,	"", "menu_options\n");
-			b->common.width = 12*20;
-			b->common.height = 20;
-			b = MC_AddConsoleCommand	(mainm, 68, 133,	"", "menu_video\n");
-			b->common.width = 12*20;
-			b->common.height = 20;
-			b = MC_AddConsoleCommand	(mainm, 68, 173,	"", "menu_quit\n");
-			b->common.width = 12*20;
-			b->common.height = 20;
-*/
-			menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, 32, NULL, false);
+			menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, &resel, 54, 32);
 		}
 		return;
 	}
@@ -431,7 +410,7 @@ void M_Menu_Setup_f (void)
 	b->common.tooltip = "Change network and client prediction settings.";
 	b = MC_AddConsoleCommand(menu, 64, 160, 176, "Teamplay Settings", "menu_teamplay\n");
 	b->common.tooltip = "Change teamplay macro settings.";
-	menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, 32, NULL, false);
+	menu->cursoritem = (menuoption_t*)MC_AddCursorSmall(menu, &resel, 54, 32);
 
 
 	info->lowercolour = bottomcolor.value;
@@ -672,8 +651,9 @@ void M_Menu_Teamplay_f (void)
 		MB_CONSOLECMD("Item Names", "menu_teamplay_items\n", "Modify messages for items in team play macros."),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu_t *menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Locations_f (void)
@@ -706,8 +686,9 @@ void M_Menu_Teamplay_Locations_f (void)
 		//MB_CONSOLECMD("\x7f Teamplay", "menu_teamplay\n", "Return to the teamplay menu."),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Needs_f (void)
@@ -732,8 +713,9 @@ void M_Menu_Teamplay_Needs_f (void)
 		MB_EDITCVARSLIM("Weapon", "tp_need_weapon", "Need weapon preference order:\n8 = Lightning Gun\n7 = Rocket Launcher\n6 = Grenade Launcher\n5 = Super Nailgun\n4 = Nailgun\n3 = Super Shotgun\n2 = Shotgun\n1 = Axe"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_f (void)
@@ -752,8 +734,9 @@ void M_Menu_Teamplay_Items_f (void)
 		MB_CONSOLECMD("Status/Location/Misc", "menu_teamplay_status_location_misc\n", "Modify status, location, and miscellaneous team play macro names."),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 224, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 224, y);
 }
 
 void M_Menu_Teamplay_Items_Armor_f (void)
@@ -774,8 +757,9 @@ void M_Menu_Teamplay_Items_Armor_f (void)
 		MB_EDITCVARSLIM("Red Armor", "tp_name_ra", "Short name for Red Armor"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_Weapons_f (void)
@@ -798,8 +782,9 @@ void M_Menu_Teamplay_Items_Weapons_f (void)
 		MB_EDITCVARSLIM("Lightning Gun", "tp_name_lg", "Short name for Lightning Gun"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_Powerups_f (void)
@@ -825,8 +810,9 @@ void M_Menu_Teamplay_Items_Powerups_f (void)
 		MB_EDITCVARSLIM("Regen Rune", "tp_name_rune_4", "Short name for Regeneration Rune"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_Ammo_Health_f (void)
@@ -847,8 +833,9 @@ void M_Menu_Teamplay_Items_Ammo_Health_f (void)
 		MB_EDITCVARSLIM("Mega Health", "tp_name_mh", "Short name for Mega Health"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_Team_Fortress_f (void)
@@ -864,8 +851,9 @@ void M_Menu_Teamplay_Items_Team_Fortress_f (void)
 		MB_EDITCVARSLIM("Flag", "tp_name_flag", "Short name for Flag"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Teamplay_Items_Status_Location_Misc_f (void)
@@ -891,8 +879,9 @@ void M_Menu_Teamplay_Items_Status_Location_Misc_f (void)
 		MB_EDITCVARSLIM("Yellow Status", "tp_name_status_yellow", "Macro for Status Yellow in teamplay 'status' & 'location' reports"),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 void M_Menu_Network_f (void)
@@ -915,6 +904,7 @@ void M_Menu_Network_f (void)
 	extern cvar_t cl_download_csprogs, cl_download_redirection, requiredownloads, cl_solid_players;
 	extern cvar_t cl_splitscreen, cl_predict_players, cl_predict_smooth, cl_predict_extrapolate;
 	menu_t *menu;
+	static menuresel_t resel;
 	int y;
 	menubulk_t bulk[] =
 	{
@@ -936,5 +926,5 @@ void M_Menu_Network_f (void)
 		MB_END()
 	};
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
diff --git a/engine/client/m_options.c b/engine/client/m_options.c
index 77eda10b1..b0fe06c9e 100644
--- a/engine/client/m_options.c
+++ b/engine/client/m_options.c
@@ -122,8 +122,8 @@ void M_Menu_Options_f (void)
 		MB_END()
 	};
 	menu_t *menu = M_Options_Title(&y, 0);
-
-	MC_AddBulk(menu, bulk, 16, 216, y);
+	static menuresel_t resel;
+	MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 }
 
 #ifndef __CYGWIN__
@@ -425,8 +425,8 @@ void M_Menu_Audio_f (void)
 		//MB_CONSOLECMD("Speaker Test", "menu_speakers\n", "Test speaker setup output."),
 		MB_END()
 	};
-
-	MC_AddBulk(menu, bulk, 16, 216, y);
+	static menuresel_t resel;
+	MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 }
 
 #else
@@ -520,10 +520,10 @@ void M_Menu_Particles_f (void)
 		// removed particle beams
 		MB_END()
 	};
+	static menuresel_t resel;
 
 	menu = M_Options_Title(&y, 0);
-
-	MC_AddBulk(menu, bulk, 16, 200, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 }
 
 const char *presetname[] =
@@ -697,8 +697,9 @@ void M_Menu_Preset_f (void)
 		MB_CONSOLECMD("realtime    (all on)",	"fps_preset realtime;menupop\n",	"For people who value pretty over fast/smooth. Not viable for deathmatch."),
 		MB_END()
 	};
+	static menuresel_t resel;
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 216, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 	//bottoms up! highlight 'normal' as the default option
 	menu->selecteditem = menu->options->common.next->common.next->common.next;
 	menu->cursoritem->common.posy = menu->selecteditem->common.posy;
@@ -797,7 +798,7 @@ void M_Menu_FPS_f (void)
 	fpsmenuinfo_t *info;
 
 	extern cvar_t v_contentblend, show_fps, cl_r2g, cl_gibfilter, cl_expsprite, cl_deadbodyfilter, cl_lerp_players, cl_nolerp;
-
+	static menuresel_t resel;
 	int y;
 	menu = M_Options_Title(&y, sizeof(fpsmenuinfo_t));
 	info = (fpsmenuinfo_t *)menu->data;
@@ -823,7 +824,7 @@ void M_Menu_FPS_f (void)
 			MB_EDITCVAR("Skybox", "r_skybox"),
 			MB_END()
 		};
-		MC_AddBulk(menu, bulk, 16, 216, y);
+		MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 	}
 }
 
@@ -849,6 +850,7 @@ void M_Menu_Render_f (void)
 #ifdef GLQUAKE
 	extern cvar_t r_bloom;
 #endif
+	static menuresel_t resel;
 
 	int y;
 	menubulk_t bulk[] =
@@ -872,7 +874,7 @@ void M_Menu_Render_f (void)
 		MB_END()
 	};
 	menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 216, y);
+	MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 }
 
 #ifdef GLQUAKE
@@ -967,7 +969,8 @@ void M_Menu_Textures_f (void)
 		MB_END()
 	};
 	menu_t *menu = M_Options_Title(&y, 0);
-	MC_AddBulk(menu, bulk, 16, 216, y);
+	static menuresel_t resel;
+	MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 }
 #endif
 
@@ -1202,7 +1205,8 @@ void M_Menu_Lighting_f (void)
 			MB_COMBOCVAR("Model Fullbrights", r_fb_models, fb_models_opts, fb_models_values, "Affects loading of fullbrights on models/polymeshes."),
 			MB_END()
 		};
-		MC_AddBulk(menu, bulk, 16, 216, y);
+		static menuresel_t resel;
+		MC_AddBulk(menu, &resel, bulk, 16, 216, y);
 	}
 }
 
@@ -2389,7 +2393,7 @@ void M_Menu_Video_f (void)
 	videomenuinfo_t *info;
 	static char current3dres[32]; // enough to fit 1920x1200
 
-
+	static menuresel_t resel;
 	int y;
 	int resmodechoice, res2dmodechoice;
 	int reschoices[ASPECT_RATIOS], res2dchoices[ASPECT_RATIOS];
@@ -2463,7 +2467,7 @@ void M_Menu_Video_f (void)
 			MB_SLIDER("Contrast", v_contrast, 0.8, 3, 0.05, NULL),
 			MB_END()
 		};
-		MC_AddBulk(menu, bulk, 16, 200, y);
+		MC_AddBulk(menu, &resel, bulk, 16, 200, y);
 	}
 
 	/*
diff --git a/engine/client/m_single.c b/engine/client/m_single.c
index db8fded4a..4bcc1c13d 100644
--- a/engine/client/m_single.c
+++ b/engine/client/m_single.c
@@ -129,6 +129,7 @@ void M_Menu_SinglePlayer_f (void)
 	menubutton_t *b;
 	mpic_t *p;
 #endif
+	static menuresel_t resel;
 
 	Key_Dest_Add(kdm_menu);
 	m_state = m_complex;
@@ -305,7 +306,7 @@ void M_Menu_SinglePlayer_f (void)
 		MC_AddConsoleCommand	(menu, 64, y+=8,	"Save Game", "menu_save\n");
 		*/
 
-		menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
+		menu->cursoritem = (menuoption_t *)MC_AddCursor(menu, &resel, 56, menu->selecteditem?menu->selecteditem->common.posy:0);
 
 		return;
 	}
@@ -320,7 +321,7 @@ void M_Menu_SinglePlayer_f (void)
 		MC_AddConsoleCommandQBigFont	(menu, 72, 52,	"Load Game", "menu_load\n");
 		MC_AddConsoleCommandQBigFont	(menu, 72, 72,	"Save Game", "menu_save\n");
 
-		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
+		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
 		return;
 	}
 	else
@@ -353,7 +354,7 @@ void M_Menu_SinglePlayer_f (void)
 		b->common.width = p->width;
 		b->common.height = 20;
 
-		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, 54, 32);
+		menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
 	}
 #endif
 }
diff --git a/engine/client/menu.h b/engine/client/menu.h
index 81ee79570..26ac60138 100644
--- a/engine/client/menu.h
+++ b/engine/client/menu.h
@@ -136,6 +136,7 @@ typedef enum {
 	mt_picture,
 	mt_picturesel,
 	mt_menudot,
+	mt_menucursor,
 	mt_custom
 } menutype_t;
 
@@ -260,6 +261,11 @@ typedef struct menutooltip_s {
 	int columns;
 } menutooltip_t;
 
+typedef struct menuresel_s	//THIS STRUCT MUST BE STATICALLY ALLOCATED.
+{
+	int x, y;
+} menuresel_t;
+
 typedef struct menu_s {
 	int xpos;
 	int ypos;
@@ -267,6 +273,7 @@ typedef struct menu_s {
 	int height;
 	qboolean dontexpand;
 	int numoptions;
+	menuresel_t *reselection;	//stores some info to restore selection properly.
 
 	qboolean iszone;
 	qboolean exclusive;
@@ -298,7 +305,8 @@ menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height);
 menupicture_t *MC_AddPicture(menu_t *menu, int x, int y, int width, int height, char *picname);
 menupicture_t *MC_AddSelectablePicture(menu_t *menu, int x, int y, char *picname);
 menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, int height, char *picname);
-menupicture_t *MC_AddCursor(menu_t *menu, int x, int y);
+menupicture_t *MC_AddCursor(menu_t *menu, menuresel_t *resel, int x, int y);
+menuoption_t *MC_AddCursorSmall(menu_t *menu, menuresel_t *reselection, int x, int y);
 menuslider_t *MC_AddSlider(menu_t *menu, int tx, int sx, int y, const char *text, cvar_t *var, float min, float max, float delta);
 menucheck_t *MC_AddCheckBox(menu_t *menu, int tx, int cx, int y, const char *text, cvar_t *var, int cvarbitmask);
 menucheck_t *MC_AddCheckBoxFunc(menu_t *menu, int tx, int cx, int y, const char *text, qboolean (*func) (menucheck_t *option, menu_t *menu, chk_set_t set), int bits);
@@ -355,7 +363,7 @@ typedef struct menubulk_s {
 #define MB_SPACING(space) 											{mt_text, 2, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, 0, false, NULL, NULL, NULL, NULL, 0, NULL, space}
 #define MB_END() 													{mt_text, -1}
 
-int MC_AddBulk(struct menu_s *menu, menubulk_t *bulk, int xstart, int xtextend, int y);
+int MC_AddBulk(struct menu_s *menu, menuresel_t *resel, menubulk_t *bulk, int xstart, int xtextend, int y);
 
 
 
diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c
index 3f8e23aad..47248007d 100644
--- a/engine/client/pr_csqc.c
+++ b/engine/client/pr_csqc.c
@@ -5084,7 +5084,7 @@ void CSQC_Event_Think(world_t *w, wedict_t *s)
 		PR_ExecuteProgram (w->progs, s->v->think);
 }
 
-void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, char *sample, int volume, float attenuation, int pitchadj)
+void CSQC_Event_Sound (float *origin, wedict_t *wentity, int channel, const char *sample, int volume, float attenuation, int pitchadj)
 {
 	int i;
 	vec3_t originbuf;