/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

// menu_game.c -- the options menu

#include <ctype.h>
#ifdef _WIN32
#include <io.h>
#endif
#include "client.h"
#include "../client/qmenu.h"

static char *menu_in_sound		= "misc/menu1.wav";
static char *menu_move_sound	= "misc/menu2.wav";
static char *menu_out_sound		= "misc/menu3.wav";

cvar_t	*options_menu;

/*
=======================================================================

KEYS MENU

=======================================================================
*/
char *bindnames[][2] =
{
{"+attack", 		"attack"},

// Knightmare added
{"+attack2", 		"alternate attack"},
{"+use", 			"activate"},
// end Knightmare

{"weapnext", 		"next weapon"},
{"weapprev", 		"previous weapon"},
{"+forward", 		"walk forward"},
{"+back", 			"backpedal"},
{"+left", 			"turn left"},
{"+right", 			"turn right"},
{"+speed", 			"run"},
{"+moveleft", 		"step left"},
{"+moveright", 		"step right"},
{"+strafe", 		"sidestep"},
{"+lookup", 		"look up"},
{"+lookdown", 		"look down"},
{"centerview", 		"center view"},
{"+mlook", 			"mouse look"},
{"+klook", 			"keyboard look"},
{"+moveup",			"up / jump"},
{"+movedown",		"down / crouch"},
{"inven",			"inventory"},
{"invuse",			"use item"},
{"invdrop",			"drop item"},
{"invprev",			"prev item"},
{"invnext",			"next item"},
{"cmd help", 		"help computer" }, 
{ 0, 0 }
};

int				keys_cursor;
static int		bind_grab;

static menuframework_s	s_keys_menu;
static menuaction_s s_keys_binds[64];
static menuaction_s		s_keys_back_action;

static void M_UnbindCommand (char *command)
{
	int		j;
	int		l;
	char	*b;

	l = strlen(command);

	for (j=0 ; j<256 ; j++)
	{
		b = keybindings[j];
		if (!b)
			continue;
		// Knightmare- fix bug with key bound to +attack2 being confused with +attack
		if (!strncmp (b, "+attack2", 8) && strncmp (command, "+attack2", 8))
			continue;
		if (!strncmp (b, command, l) )
			Key_SetBinding (j, "");
	}
}

static void M_FindKeysForCommand (char *command, int *twokeys)
{
	int		count;
	int		j;
	int	 	l;
	char	*b;

	twokeys[0] = twokeys[1] = -1;
	l = strlen(command);
	count = 0;

	for (j=0 ; j<256 ; j++)
	{
		b = keybindings[j];
		if (!b)
			continue;
		// Knightmare- fix bug with key bound to +attack2 being confused with +attack
		if (!strncmp (b, "+attack2", 8) && strncmp (command, "+attack2", 8))
			continue;
		if (!strncmp (b, command, l))
		{
			twokeys[count] = j;
			count++;
			if (count == 2)
				break;
		}
	}
}

int listSize (char* list[][2])
{
	int i=0;
	while (list[i][1])
		i++;

	return i;	
}


static void KeysBackCursorDrawFunc ( menuaction_s *self ) // back action
{
	R_DrawScaledChar ( viddef.width * 0.50 - scaledVideo(24),
					s_keys_menu.y + scaledVideo(self->generic.y),
					12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1),
					videoScale(), 255,255,255,255, false);
}

static void KeyCursorDrawFunc( menuframework_s *menu )
{

	if ( bind_grab )
		R_DrawScaledChar ( menu->x, menu->y + scaledVideo(menu->cursor * (MENU_FONT_SIZE+2) ),
							'=', videoScale(), 255,255,255,255, false);
		/*R_DrawChar(
		menu->x, menu->y + scaledVideo(menu->cursor * 9),
		'=', 255 );*/
	else
		R_DrawScaledChar ( menu->x, menu->y + scaledVideo(menu->cursor * (MENU_FONT_SIZE+2) ),
							12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ),
							videoScale(), 255,255,255,255, false);
		/*R_DrawChar(
		menu->x, menu->y + scaledVideo(menu->cursor * 9),
		12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ), 255 );*/
}

static void DrawKeyBindingFunc( void *self )
{
	int keys[2];
	menuaction_s *a = ( menuaction_s * ) self;

	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys);
		
	if (keys[0] == -1)
	{
		Menu_DrawString(
			scaledVideo(a->generic.x + 16) + a->generic.parent->x,
			scaledVideo(a->generic.y) + a->generic.parent->y,
			"???", 255 );
	}
	else
	{
		int x;
		const char *name;

		name = Key_KeynumToString (keys[0]);

		Menu_DrawString(
			scaledVideo(a->generic.x + 16) + a->generic.parent->x,
			scaledVideo(a->generic.y) + a->generic.parent->y,
			name , 255);

		x = scaledVideo(strlen(name) * MENU_FONT_SIZE);

		if (keys[1] != -1)
		{
			Menu_DrawString(
				scaledVideo(a->generic.x + MENU_FONT_SIZE*3 + x) + a->generic.parent->x,
				scaledVideo(a->generic.y) + a->generic.parent->y,
				"or", 255 );
			Menu_DrawString(
				scaledVideo(a->generic.x + MENU_FONT_SIZE*6 + x) + a->generic.parent->x,
				scaledVideo(a->generic.y) + a->generic.parent->y,
				Key_KeynumToString (keys[1]), 255 );
		}
	}
}

static void KeyBindingFunc( void *self )
{
	menuaction_s *a = ( menuaction_s * ) self;
	int keys[2];

	M_FindKeysForCommand( bindnames[a->generic.localdata[0]][0], keys );

	if (keys[1] != -1)
		M_UnbindCommand( bindnames[a->generic.localdata[0]][0]);

	bind_grab = true;

	Menu_SetStatusBar( &s_keys_menu, "press a key or button for this action" );
}

void addBindOption (int i, char* list[][2])
{		
	s_keys_binds[i].generic.type	= MTYPE_ACTION;
	s_keys_binds[i].generic.flags  = QMF_GRAYED;
	s_keys_binds[i].generic.x		= 0;
	s_keys_binds[i].generic.y		= i*(MENU_FONT_SIZE+2);
	s_keys_binds[i].generic.ownerdraw = DrawKeyBindingFunc;
	s_keys_binds[i].generic.localdata[0] = i;
	s_keys_binds[i].generic.name	= list[s_keys_binds[i].generic.localdata[0]][1];
	s_keys_binds[i].generic.callback = KeyBindingFunc;

	if (strstr ("MENUSPACE", list[i][0]))
		s_keys_binds[i].generic.type	= MTYPE_SEPARATOR;
}

static void Keys_MenuInit( void )
{
	int BINDS_MAX;
	int i = 0;

	s_keys_menu.x = viddef.width * 0.50;
	s_keys_menu.y = viddef.height * 0.50 - scaledVideo(9 * MENU_FONT_SIZE); //was 7.25
	s_keys_menu.nitems = 0;
	s_keys_menu.cursordraw = KeyCursorDrawFunc;

	BINDS_MAX = listSize(bindnames);
	for (i=0;i<BINDS_MAX;i++)
		addBindOption(i, bindnames);

	s_keys_back_action.generic.type = MTYPE_ACTION;
	s_keys_back_action.generic.flags = QMF_LEFT_JUSTIFY;
	s_keys_back_action.generic.x	= 0;
	s_keys_back_action.generic.y	= (BINDS_MAX+2)*(MENU_FONT_SIZE+2);
	s_keys_back_action.generic.name	= " back";
	s_keys_back_action.generic.callback = M_BackMenu;
	s_keys_back_action.generic.cursordraw = (void *)KeysBackCursorDrawFunc;

	for (i=0;i<BINDS_MAX;i++)
		Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_binds[i] );

	Menu_AddItem( &s_keys_menu, ( void * ) &s_keys_back_action );

	Menu_SetStatusBar( &s_keys_menu, "enter or mouse1 to change, backspace to clear" );
	// Don't center it- it's too large
	//Menu_Center( &s_keys_menu );
}

static void Keys_MenuDraw (void)
{
	M_Banner( "m_banner_customize" ); // Knightmare added
	Menu_AdjustCursor( &s_keys_menu, 1 );
	Menu_Draw( &s_keys_menu );
}

static const char *Keys_MenuKey( int key )
{
	menuaction_s *item = ( menuaction_s * ) Menu_ItemAtCursor( &s_keys_menu );

	//pressing mouse1 to pick a new bind wont force bind/unbind itself - spaz
	if ( bind_grab && !(cursor.buttonused[MOUSEBUTTON1]&&key==K_MOUSE1))
	{	
		if ( key != K_ESCAPE && key != '`' )
		{
			char cmd[1024];

			Com_sprintf (cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item->generic.localdata[0]][0]);
			Cbuf_InsertText (cmd);
		}
		
		// Knightmare- added Psychospaz's mouse support
		//dont let selecting with mouse buttons screw everything up
		refreshCursorButtons();
		if (key==K_MOUSE1)
			cursor.buttonclicks[MOUSEBUTTON1] = -1;

		Menu_SetStatusBar( &s_keys_menu, "enter to change, backspace to clear" );
		bind_grab = false;
		return menu_out_sound;
	}

	switch ( key )
	{
	case K_KP_ENTER:
	case K_ENTER:
		if (item == &s_keys_back_action) { // back action hack
			M_BackMenu(item); return NULL; }
		KeyBindingFunc( item );
		return menu_in_sound;
	case K_BACKSPACE:		// delete bindings
	case K_DEL:				// delete bindings
	case K_KP_DEL:
		M_UnbindCommand( bindnames[item->generic.localdata[0]][0] );
		return menu_out_sound;
	default:
		return Default_MenuKey( &s_keys_menu, key );
	}
}

void M_Menu_Keys_f (void)
{
	Keys_MenuInit();
	M_PushMenu( Keys_MenuDraw, Keys_MenuKey );
}


/*
=======================================================================

OPTIONS MENU

=======================================================================
*/
static cvar_t *win_noalttab;
extern cvar_t *in_joystick;

static menuframework_s	s_options_menu;
static menuframework_s	s_options_sound_menu;
static menuframework_s	s_options_controls_menu;
static menuframework_s	s_options_interface_menu;
static menuframework_s	s_options_ingame_menu;

static menuaction_s		s_options_sound_section;
static menuaction_s		s_options_controls_section;
static menuaction_s		s_options_ingame_section;
static menuaction_s		s_options_interface_section;
static menuaction_s		s_options_back_action;

static menuseparator_s		s_options_sound_header;
static menuseparator_s		s_options_controls_header;
static menuseparator_s		s_options_ingame_header;
static menuseparator_s		s_options_interface_header;

static menulist_s		s_options_noalttab_box;
static menuaction_s		s_options_defaults_action;
static menulist_s		s_options_backmain_action;

//sound
static menuslider_s		s_options_sfxvolume_slider;
static menuslider_s		s_options_musicvolume_slider;
static menulist_s		s_options_oggmusic_box;
#ifdef OGGVORBIS
static menuslider_s		s_options_oggvolume_slider;
#endif
static menulist_s		s_options_cdvolume_box;
static menulist_s		s_options_quality_list;
static menulist_s		s_options_compatibility_list;

// controls
static menuslider_s		s_options_sensitivity_slider;
static menulist_s		s_options_alwaysrun_box;
// Knightmare- added Psychospaz's chaseam
static menulist_s		s_options_thirdperson_box;
static menuslider_s		s_options_thirdperson_distance_slider;
static menuslider_s		s_options_thirdperson_angle_slider;
//end Knightmare
static menulist_s		s_options_invertmouse_box;
static menulist_s		s_options_lookspring_box;
static menulist_s		s_options_lookstrafe_box;
static menulist_s		s_options_freelook_box;
static menulist_s		s_options_joystick_box;
static menuaction_s		s_options_customize_options_action;

//ingame
static menulist_s		s_options_blood_box;
static menulist_s		s_options_crosshair_box;
// Knightmare- Psychospaz's changeable size crosshair
static menuslider_s		s_options_crosshairscale_slider;
static menuslider_s		s_options_hudscale_slider;
static menuslider_s		s_options_hudalpha_slider;
// Knightmare- particle effect complexity option
static menulist_s		s_options_fps_box;
#if defined (__unix__)
static menulist_s		s_options_clock_box;
#endif
// Knightmare- foostep override option
static menulist_s		s_options_footstep_box;
// Knightmare- Psychospaz's changeable rail trail
static menulist_s		s_options_railtrail_box;
static menuslider_s		s_options_railcolor_box[3];
static menuaction_s		s_options_ingame_defaults_action;
//static menulist_s		s_options_ingame_console_action;
static menulist_s		s_options_ingame_backmain_action;

// interface
static menuslider_s		s_options_conalpha_slider;
static menuslider_s		s_options_conheight_slider;
static menuslider_s		s_options_menumouse_slider;
//static menulist_s		s_options_menuscale_box;
static menuslider_s		s_options_menualpha_slider;
static menulist_s		s_options_font_box;
static menuslider_s		s_options_fontsize_slider;
static menulist_s		s_options_alt_text_color_box;

static void BloodFunc( void *unused )
{
	Cvar_SetValue( "cl_blood", s_options_blood_box.curvalue );
}

//Knightmare- Psychospaz's changeable size crosshair
static void CrosshairSizeFunc( void *unused )
{
	Cvar_SetValue( "crosshair_scale", s_options_crosshairscale_slider.curvalue*0.25);
}

// Knightmare- hud scaling option
static void HudScaleFunc( void *unused )
{
	Cvar_SetValue( "hud_scale", s_options_hudscale_slider.curvalue-1);
}

// Knightmare- hud trans option
static void HudAlphaFunc( void *unused )
{
	Cvar_SetValue( "hud_alpha", (s_options_hudalpha_slider.curvalue-1)/10);
}

// Knightmare- FPS counter option
static void FPSFunc( void *unused )
{
	Cvar_SetValue( "cl_drawfps", s_options_fps_box.curvalue);
}

#if defined (__unix__)
static void ClockFunc( void *unused )
{
	Cvar_SetValue( "cl_drawclock", s_options_clock_box.curvalue);
}
#endif

// Knightmare- foostep override option
static void FootStepFunc( void *unused )
{
	Cvar_SetValue( "cl_footstep_override", s_options_footstep_box.curvalue );
}

//Knightmare- Psychospaz's changeable rail trail
static void RailTrailFunc( void *unused )
{
	Cvar_SetValue( "cl_railtype", s_options_railtrail_box.curvalue );
}
static void RailColorRedFunc( void *unused )
{
	Cvar_SetValue( "cl_railred", s_options_railcolor_box[0].curvalue*16 );
}
static void RailColorGreenFunc( void *unused )
{
	Cvar_SetValue( "cl_railgreen", s_options_railcolor_box[1].curvalue*16 );
}
static void RailColorBlueFunc( void *unused )
{
	Cvar_SetValue( "cl_railblue", s_options_railcolor_box[2].curvalue*16 );
}
//end Knightmare

static void JoystickFunc( void *unused )
{
	Cvar_SetValue( "in_joystick", s_options_joystick_box.curvalue );
}

static void CustomizeControlsFunc( void *unused )
{
	M_Menu_Keys_f();
}

static void AlwaysRunFunc( void *unused )
{
	Cvar_SetValue( "cl_run", s_options_alwaysrun_box.curvalue );
}

// Knigntmare- added Psychospaz's chaseam
static void ThirdPersonFunc( void *unused )
{
	Cvar_SetValue( "cl_3dcam", s_options_thirdperson_box.curvalue );
}

static void ThirdPersonDistFunc( void *unused )
{
	Cvar_SetValue( "cl_3dcam_dist", (int)(s_options_thirdperson_distance_slider.curvalue * 25) );
}

static void ThirdPersonAngleFunc( void *unused )
{
	Cvar_SetValue( "cl_3dcam_angle", (int)(s_options_thirdperson_angle_slider.curvalue * 10) );
}

//end Knightmare

static void FreeLookFunc( void *unused )
{
	Cvar_SetValue( "freelook", s_options_freelook_box.curvalue );
}

static void MouseSpeedFunc( void *unused )
{
	Cvar_SetValue( "sensitivity", s_options_sensitivity_slider.curvalue / 2.0F );
}

// Knightmare- Psychospaz's menu mouse support
static void MouseMenuFunc( void *unused )
{
	Cvar_SetValue( "menu_sensitivity", s_options_menumouse_slider.curvalue / 4.0F );
}

// Knightmare- menu scaling option
/*static void MenuScaleFunc( void *unused )
{
	Cvar_SetValue( "menu_scale", s_options_menuscale_box.curvalue);
}*/

// Knightmare- menu scaling option
static void MenuAlphaFunc( void *unused )
{
	Cvar_SetValue( "menu_alpha", s_options_menualpha_slider.curvalue / 20.0F);
}

static void AltTextColorFunc( void *unused )
{
	Cvar_SetValue( "alt_text_color", s_options_alt_text_color_box.curvalue);
}

// Knightmare- Psychospaz's transparent console
static void ConAlphaFunc( void *unused )
{
	Cvar_SetValue( "con_alpha", s_options_conalpha_slider.curvalue * 0.05 );
}
// Kngihtmare- variable console height
static void ConHeightFunc( void *unused )
{
	Cvar_SetValue( "con_height", 0.25 + (s_options_conheight_slider.curvalue * 0.05) );
}
// end Knightmare

static void NoAltTabFunc( void *unused )
{
	Cvar_SetValue( "win_noalttab", s_options_noalttab_box.curvalue );
}

static float ClampCvar( float min, float max, float value )
{
	if ( value < min ) return min;
	if ( value > max ) return max;
	return value;
}

/*
=======================================================================
Font loading
=======================================================================
*/

static void FreeFileList( char **list, int n )
{
	int i;

	for ( i = 0; i < n; i++ )
	{
		if ( list && list[i] )
		{
			free( list[i] );
			list[i] = 0;
		}
	}
	free( list );
}

cvar_t *con_font;
#define MAX_FONTS 32
char **font_names;
int	numfonts;

static void FontSizeFunc( void *unused )
{
	Cvar_SetValue( "con_font_size", s_options_fontsize_slider.curvalue * 4 );
}

static void FontFunc( void *unused )
{
	Cvar_Set( "con_font", font_names[s_options_font_box.curvalue] );
}

void SetFontCursor (void)
{
	int i;
	s_options_font_box.curvalue = 0;

	if (!con_font)
		con_font = Cvar_Get ("con_font", "default", CVAR_ARCHIVE);

	if (numfonts>1)
		for (i=0; font_names[i]; i++)
		{
			if (!Q_strcasecmp(con_font->string, font_names[i]))
			{
				s_options_font_box.curvalue = i;
				return;
			}
		}
}

qboolean fontInList (char *check, int num, char **list)
{
	int i;
	for (i=0;i<num;i++)
		if (!Q_strcasecmp(check, list[i]))
			return true;
	return false;
}

void insertFont (char ** list, char *insert, int len )
{
	int i, j;

	if (!list)
		return;

	//i=1 so default stays first!
	for (i=1; i<len; i++)
	{
		if (!list[i])
			break;

		if (strcmp( list[i], insert ))
		{
			for (j=len; j>i ;j--)
				list[j] = list[j-1];

			list[i] = strdup(insert);

			return;
		}
	}

	list[len] = strdup(insert);
}

char **SetFontNames (void)
{
	char *curFont;
	char **list = 0, *p;//, *s;
	char findname[1024];
	int nfonts = 0, nfontnames;
	char **fontfiles;
	char *path = NULL;
	int i;//, j;
	extern char **FS_ListFiles( char *, int *, unsigned, unsigned );

	list = malloc( sizeof( char * ) * MAX_FONTS );
	memset( list, 0, sizeof( char * ) * MAX_FONTS );

	list[0] = strdup("default");

	nfontnames = 1;

	path = FS_NextPath( path );
	while (path) 
	{
		Com_sprintf( findname, sizeof(findname), "%s/fonts/*.*", path );
		fontfiles = FS_ListFiles( findname, &nfonts, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );

		for (i=0;i<nfonts && nfontnames<MAX_FONTS;i++)
		{
			int num;

			if (!fontfiles || !fontfiles[i])	// Knightmare added array base check
				continue;

			p = strstr(fontfiles[i], "/fonts/"); p++;
			p = strstr(p, "/"); p++;

			if (	!strstr(p, ".tga")
				&&	!strstr(p, ".jpg")
				&&	!strstr(p, ".pcx")
				)
				continue;

			num = strlen(p)-4;
			p[num] = 0;//NULL;

			curFont = p;

			if (!fontInList(curFont, nfontnames, list))
			{
				insertFont(list, strdup(curFont),nfontnames);
				nfontnames++;
			}
			
			//set back so whole string get deleted.
			p[num] = '.';
		}
		if (nfonts)
			FreeFileList( fontfiles, nfonts );
		
		path = FS_NextPath( path );
	}

	//check pak after
	if ((fontfiles = FS_ListPak("fonts/", &nfonts)))
	{
		for (i=0;i<nfonts && nfontnames<MAX_FONTS;i++)
		{

			int num;

			if (!fontfiles || !fontfiles[i])	// Knightmare added array base check
				continue;

			p = strstr(fontfiles[i], "/"); p++;

			if (	!strstr(p, ".tga")
				&&	!strstr(p, ".jpg")
				&&	!strstr(p, ".pcx")
				)
				continue;

			num = strlen(p)-4;
			p[num] = 0; //NULL;

			curFont = p;

			if (!fontInList(curFont, nfontnames, list))
			{
				insertFont(list, strdup(curFont),nfontnames);
				nfontnames++;
			}
			
			//set back so whole string get deleted.
			p[num] = '.';

		}
	}
	if (nfonts)
		FreeFileList( fontfiles, nfonts );

	numfonts = nfontnames;

	return list;		
}

/*
=======================================================================
Crosshair loading
=======================================================================
*/

#define MAX_CROSSHAIRS 100
char **crosshair_names;
int	numcrosshairs;

/*static void OldCrosshairFunc( void *unused )
{
	Cvar_SetValue( "crosshair", s_options_crosshair_box.curvalue );
}*/

static void CrosshairFunc( void *unused )
{
	if (s_options_crosshair_box.curvalue == 0) {
		Cvar_SetValue( "crosshair", 0); return; }
	else
		Cvar_SetValue( "crosshair", atoi(strdup(crosshair_names[s_options_crosshair_box.curvalue]+2)) );
}

void SetCrosshairCursor (void)
{
	int i;
	s_options_crosshair_box.curvalue = 0;

	if (numcrosshairs > 1)
		for (i=0; crosshair_names[i]; i++)
		{
			if (!Q_strcasecmp(va("ch%i", (int)Cvar_VariableValue("crosshair")), crosshair_names[i]))
			{
				s_options_crosshair_box.curvalue = i;
				return;
			}
		}
}

qboolean crosshairInList (char *check, int num, char **list)
{
	int i;
	for (i=0; i<num; i++)
		if (!Q_strcasecmp(check, list[i]))
			return true;
	return false;
}

void insertCrosshair (char ** list, char *insert, int len )
{
	int i;
	if (!list) return;

	//i=1 so none stays first!
	for (i=1; i<len; i++)
	{
		if (!list[i])
		{
			list[i] = strdup(insert);
			return;
		}
	}
	list[len] = strdup(insert);
}

void sortCrosshairs (char ** list, int len )
{
	int i, j;
	char *temp;
	qboolean moved;

	if (!list || len < 2)
		return;

	for (i=(len-1); i>0; i--)
	{
		moved = false;
		for (j=0; j<i; j++)
		{
			if (!list[j]) break;
			if ( atoi(strdup(list[j]+2)) > atoi(strdup(list[j+1]+2)) )
			{
				temp = list[j];
				list[j] = list[j+1];
				list[j+1] = temp;
				moved = true;
			}
		}
		if (!moved) break; //done sorting
	}
}

qboolean isNumeric (char ch)
{
	if (ch >= '0' && ch <= '9')
		return true;
	else return false;
}

char **SetCrosshairNames (void)
{
	char *curCrosshair;
	char **list = 0, *p;
	char findname[1024];
	int ncrosshairs = 0, ncrosshairnames;
	char **crosshairfiles;
	char *path = NULL;
	int i;
	extern char **FS_ListFiles( char *, int *, unsigned, unsigned );

	list = malloc( sizeof( char * ) * MAX_CROSSHAIRS+1 );
	memset( list, 0, sizeof( char * ) * MAX_CROSSHAIRS+1 );

	list[0] = strdup("none"); //was default
	ncrosshairnames = 1;

	path = FS_NextPath( path );
	while (path) 
	{
		Com_sprintf( findname, sizeof(findname), "%s/pics/ch*.*", path );
		crosshairfiles = FS_ListFiles( findname, &ncrosshairs, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );

		for (i=0; i < ncrosshairs && ncrosshairnames < MAX_CROSSHAIRS; i++)
		{
			int num, namelen;

			if (!crosshairfiles || !crosshairfiles[i])
				continue;

			p = strstr(crosshairfiles[i], "/pics/"); p++;
			p = strstr(p, "/"); p++;

			if (	!strstr(p, ".tga")
				&&	!strstr(p, ".jpg")
				&&	!strstr(p, ".pcx")
				)
				continue;

			// filename must be chxxx
			if (strncmp(p, "ch", 2)) 
				continue;
			namelen = strlen(strdup(p));
			if (namelen < 7 || namelen > 9)
				continue;
			if (!isNumeric(p[2]))
				continue;
			if (namelen >= 8 && !isNumeric(p[3]))
				continue;
			// ch100 is only valid 5-char name
			if (namelen == 9 && (p[2] != '1' || p[3] != '0' || p[4] != '0'))
				continue;

			num = strlen(p)-4;
			p[num] = 0; //NULL;

			curCrosshair = p;

			if (!fontInList(curCrosshair, ncrosshairnames, list))
			{
				insertCrosshair(list, strdup(curCrosshair), ncrosshairnames);
				ncrosshairnames++;
			}
			
			//set back so whole string get deleted.
			p[num] = '.';
		}
		if (ncrosshairs)
			FreeFileList( crosshairfiles, ncrosshairs );
		
		path = FS_NextPath( path );
	}

	//check pak after
	if ((crosshairfiles = FS_ListPak("pics/", &ncrosshairs)))
	{
		for (i=0; i<ncrosshairs && ncrosshairnames < MAX_CROSSHAIRS; i++)
		{
			int num, namelen;

			if (!crosshairfiles || !crosshairfiles[i])
				continue;

			p = strstr(crosshairfiles[i], "/"); p++;

			if (	!strstr(p, ".tga")
				&&	!strstr(p, ".jpg")
				&&	!strstr(p, ".pcx")
				)
				continue;

			// filename must be chxxx
			if (strncmp(p, "ch", 2))
				continue;
			namelen = strlen(strdup(p));
			if (namelen < 7 || namelen > 9)
				continue;
			if (!isNumeric(p[2]))
				continue;
			if (namelen >= 8 && !isNumeric(p[3]))
				continue;
			// ch100 is only valid 5-char name
			if (namelen == 9 && (p[2] != '1' || p[3] != '0' || p[4] != '0'))
				continue;

			num = strlen(p)-4;
			p[num] = 0; //NULL;

			curCrosshair = p;

			if (!crosshairInList(curCrosshair, ncrosshairnames, list))
			{
				insertCrosshair(list, strdup(curCrosshair), ncrosshairnames);
				ncrosshairnames++;
			}
			
			//set back so whole string get deleted.
			p[num] = '.';
		}
	}
	// sort the list
	sortCrosshairs (list, ncrosshairnames);

	if (ncrosshairs)
		FreeFileList( crosshairfiles, ncrosshairs );

	numcrosshairs = ncrosshairnames;

	return list;		
}

//=======================================================================

static void ControlsSetMenuItemValues( void )
{
	// sound
	s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;
	s_options_musicvolume_slider.curvalue		= Cvar_VariableValue( "s_musicvolume" ) * 10;
	s_options_oggmusic_box.curvalue			= (Cvar_VariableValue("cl_ogg_music") > 0);
#ifdef OGGVORBIS
	s_options_oggvolume_slider.curvalue		= Cvar_VariableValue( "ogg_volume" ) * 20;
#endif
	s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");
	//s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );
	//**  DMP convert setting into index for option display text
	switch((int)Cvar_VariableValue("s_khz"))
	{
	case 48:  s_options_quality_list.curvalue = 3;  break;
	case 44:  s_options_quality_list.curvalue = 2;  break;
	case 22:  s_options_quality_list.curvalue = 1;  break;
	default:  s_options_quality_list.curvalue = 0;  break;
	}
	//** DMP end sound menu changes
	s_options_compatibility_list.curvalue = Cvar_VariableValue( "s_primary");


	// controls
	s_options_sensitivity_slider.curvalue	= ( Cvar_VariableValue("sensitivity") ) * 2;
	s_options_invertmouse_box.curvalue		= Cvar_VariableValue("m_pitch") < 0;

	// Knightmare- added Psychospaz's chasecam
	Cvar_SetValue( "cl_3dcam", ClampCvar( 0, 1, Cvar_VariableValue("cl_3dcam") ) );
	s_options_thirdperson_box.curvalue		= Cvar_VariableValue("cl_3dcam");
	s_options_thirdperson_distance_slider.curvalue	= Cvar_VariableValue("cl_3dcam_dist") / 25;
	s_options_thirdperson_angle_slider.curvalue	= Cvar_VariableValue("cl_3dcam_angle") / 10;
	// end Knightmare

	Cvar_SetValue( "cl_run", ClampCvar( 0, 1, Cvar_VariableValue("cl_run") ) );
	s_options_alwaysrun_box.curvalue		= Cvar_VariableValue("cl_run");

	Cvar_SetValue( "lookspring", ClampCvar( 0, 1, Cvar_VariableValue("lookspring") ) );
	s_options_lookspring_box.curvalue		= Cvar_VariableValue("lookspring");

	Cvar_SetValue( "lookstrafe", ClampCvar( 0, 1, Cvar_VariableValue("lookstrafe") ) );
	s_options_lookstrafe_box.curvalue		= Cvar_VariableValue("lookstrafe");

	Cvar_SetValue( "freelook", ClampCvar( 0, 1, Cvar_VariableValue("freelook") ) );
	s_options_freelook_box.curvalue			= Cvar_VariableValue("freelook");

	Cvar_SetValue( "in_joystick", ClampCvar( 0, 1, Cvar_VariableValue("in_joystick") ) );
	s_options_joystick_box.curvalue		= Cvar_VariableValue("in_joystick");


	// ingame
	SetFontCursor();
	SetCrosshairCursor();

	Cvar_SetValue( "crosshair", ClampCvar( 0, 100, Cvar_VariableValue("crosshair") ) );
	//s_options_crosshair_box.curvalue			= Cvar_VariableValue("crosshair");
	s_options_crosshairscale_slider.curvalue	= Cvar_VariableValue("crosshair_scale")*4;

	Cvar_SetValue( "hud_scale", ClampCvar( 0, 7, Cvar_VariableValue("hud_scale") ) );
	s_options_hudscale_slider.curvalue		= Cvar_VariableValue("hud_scale")+1;

	Cvar_SetValue( "hud_alpha", ClampCvar( 0, 1, Cvar_VariableValue("hud_alpha") ) );
	s_options_hudalpha_slider.curvalue		= Cvar_VariableValue("hud_alpha")*10 + 1;

	Cvar_SetValue( "cl_drawfps", ClampCvar( 0, 1, Cvar_VariableValue("cl_drawfps") ) );
	s_options_fps_box.curvalue				= Cvar_VariableValue("cl_drawfps");

#if defined (__unix__)	
	Cvar_SetValue( "cl_drawclock", ClampCvar( 0, 2, cl_drawclock->value ) );
	s_options_clock_box.curvalue				= Cvar_VariableValue("cl_drawclock");
#endif

	Cvar_SetValue( "cl_footstep_override", ClampCvar( 0, 1, Cvar_VariableValue("cl_footstep_override") ) );
	s_options_footstep_box.curvalue			= Cvar_VariableValue("cl_footstep_override");

	Cvar_SetValue( "cl_blood", ClampCvar( 0, 4, Cvar_VariableValue("cl_blood") ) );
	s_options_blood_box.curvalue			= Cvar_VariableValue("cl_blood");

	Cvar_SetValue( "cl_railtype", ClampCvar( 0, 2, Cvar_VariableValue("cl_railtype") ) );
	s_options_railtrail_box.curvalue		= Cvar_VariableValue("cl_railtype");
	s_options_railcolor_box[0].curvalue		= Cvar_VariableValue("cl_railred")/16;
	s_options_railcolor_box[1].curvalue		= Cvar_VariableValue("cl_railgreen")/16;
	s_options_railcolor_box[2].curvalue		= Cvar_VariableValue("cl_railblue")/16;


	// interface
	s_options_menumouse_slider.curvalue		= ( Cvar_VariableValue("menu_sensitivity") ) * 4;
	//s_options_menuscale_box.curvalue		= Cvar_VariableValue("menu_scale");
	s_options_menualpha_slider.curvalue		= ( Cvar_VariableValue("menu_alpha") ) * 20;
	s_options_fontsize_slider.curvalue		= ( Cvar_VariableValue("con_font_size") ) * 0.25;

	Cvar_SetValue( "alt_text_color", ClampCvar( 0, 9, Cvar_VariableValue("alt_text_color") ) );
	s_options_alt_text_color_box.curvalue	= Cvar_VariableValue("alt_text_color");

	Cvar_SetValue( "con_alpha", ClampCvar( 0, 1, Cvar_VariableValue("con_alpha") ) );
	s_options_conalpha_slider.curvalue		= ( Cvar_VariableValue("con_alpha") ) * 20;

	Cvar_SetValue( "con_height", ClampCvar( 0.25, 0.75, Cvar_VariableValue("con_height") ) );
	s_options_conheight_slider.curvalue		= 20 * (Cvar_VariableValue("con_height") - 0.25);

	s_options_noalttab_box.curvalue			= Cvar_VariableValue("win_noalttab");
}


static void ControlsResetDefaultsFunc( void *unused )
{
	// set cvar defaults for current menu
	if (options_menu->value==1) // sound
	{
		Cvar_SetToDefault ("s_volume");
		Cvar_SetToDefault ("cd_nocd");
		Cvar_SetToDefault ("cd_loopcount");
		Cvar_SetToDefault ("s_khz");
		Cvar_SetToDefault ("s_loadas8bit");
		Cvar_SetToDefault ("s_primary");

		M_DrawTextBox( 8, 120 - 48, 36, 3 );
		M_Print( 28, 120 - 48 + MENU_FONT_SIZE,  "Restarting the sound system. This" );
		M_Print( 28, 120 - 48 + MENU_FONT_SIZE*2, "could take up to a minute, so" );
		M_Print( 28, 120 - 48 + MENU_FONT_SIZE*3, "please be patient." );

		// the text box won't show up unless we do a buffer swap
		GLimp_EndFrame();

		CL_Snd_Restart_f();
	}
	else if (options_menu->value==2) // controls
	{
		//Cvar_SetToDefault ("sensitivity");
		//Cvar_SetToDefault ("m_pitch");
		Cvar_SetToDefault ("cl_3dcam");
		Cvar_SetToDefault ("cl_3dcam_dist");
		Cvar_SetToDefault ("scl_3dcam_angle");
		//Cvar_SetToDefault ("cl_run");
		//Cvar_SetToDefault ("lookspring");
		//Cvar_SetToDefault ("lookstrafe");
		//Cvar_SetToDefault ("freelook");
		Cvar_SetToDefault ("in_joystick");

		Cbuf_AddText ("exec defaultbinds.cfg\n"); // reset default binds
		Cbuf_Execute();
	}
	else if (options_menu->value==3) // ingame
	{
		Cvar_SetToDefault ("crosshair");
		Cvar_SetToDefault ("crosshair_scale");
		Cvar_SetToDefault ("hud_scale");
		Cvar_SetToDefault ("hud_alpha");
		Cvar_SetToDefault ("cl_drawfps");
		Cvar_SetToDefault ("cl_footstep_override");
		Cvar_SetToDefault ("cl_blood");
		Cvar_SetToDefault ("cl_railtype");
		Cvar_SetToDefault ("cl_railred");
		Cvar_SetToDefault ("cl_railgreen");
		Cvar_SetToDefault ("cl_railblue");	
	}
	else if (options_menu->value==4) // interface
	{
		Cvar_SetToDefault ("menu_sensitivity");	
		Cvar_SetToDefault ("menu_alpha");	
		Cvar_SetToDefault ("con_font");	
		Cvar_SetToDefault ("con_font_size");	
		Cvar_SetToDefault ("alt_text_color");	
		Cvar_SetToDefault ("con_alpha");	
		Cvar_SetToDefault ("con_height");	
		Cvar_SetToDefault ("win_noalttab");	
	}

	ControlsSetMenuItemValues();
}


static void InvertMouseFunc( void *unused )
{
	Cvar_SetValue( "m_pitch", -m_pitch->value );
}

static void LookspringFunc( void *unused )
{
	Cvar_SetValue( "lookspring", !lookspring->value );
}

static void LookstrafeFunc( void *unused )
{
	Cvar_SetValue( "lookstrafe", !lookstrafe->value );
}

static void UpdateVolumeFunc( void *unused )
{
	Cvar_SetValue( "s_volume", s_options_sfxvolume_slider.curvalue / 10 );
}

static void UpdateMusicVolumeFunc( void *unused )
{
	Cvar_SetValue( "s_musicvolume", s_options_musicvolume_slider.curvalue / 10 );
}

static void UpdateOggMusicFunc( void *unused )
{
	Cvar_SetValue( "cl_ogg_music", s_options_oggmusic_box.curvalue );
}

#ifdef OGGVORBIS
static void UpdateOGGVolumeFunc( void *unused )
{
	Cvar_SetValue( "ogg_volume", s_options_oggvolume_slider.curvalue / 10 );
}
#endif

static void UpdateCDVolumeFunc( void *unused )
{
	Cvar_SetValue( "cd_nocd", !s_options_cdvolume_box.curvalue );
}

//Knightmare- Psychospaz's menu select box
static void setMenuOptionsMain ( void *unused )
{
	Cvar_SetValue( "options_menu", 0 );
	refreshCursorLink();
}

static void setMenuSound ( void *unused )
{
	Cvar_SetValue( "options_menu", 1 );
	refreshCursorLink();
	// release mouse button 1 to not inadvertently affect sliders
	cursor.buttondown[MOUSEBUTTON1] = false;
}

static void setMenuControls ( void *unused )
{
	Cvar_SetValue( "options_menu", 2 );
	refreshCursorLink();
	// release mouse button 1 to not inadvertently affect sliders
	cursor.buttondown[MOUSEBUTTON1] = false; 
}

static void setMenuIngame ( void *unused )
{
	Cvar_SetValue( "options_menu", 3 );
	refreshCursorLink();
	// release mouse button 1 to not inadvertently affect sliders
	cursor.buttondown[MOUSEBUTTON1] = false;
	// set clicks to 0 to not inadvertently affect crosshair selector
	cursor.buttonclicks[MOUSEBUTTON1] = 0;
}

static void setMenuInterface ( void *unused )
{
	Cvar_SetValue( "options_menu", 4 );
	refreshCursorLink();
	// release mouse button 1 to not inadvertently affect sliders
	cursor.buttondown[MOUSEBUTTON1] = false; 
}
//end Knightmare
#if 0
static void ConsoleFunc( void *unused )
{
	/*
	** the proper way to do this is probably to have ToggleConsole_f accept a parameter
	*/
	extern void Key_ClearTyping( void );

	if ( cl.attractloop )
	{
		Cbuf_AddText ("killserver\n");
		return;
	}

	Key_ClearTyping ();
	Con_ClearNotify ();

	//M_ForceMenuOff ();
	cls.consoleActive = true; // Knigthmare changed
	//cls.key_dest = key_console;
}
#endif

static void UpdateSoundQualityFunc( void *unused )
{
	//Knightmare- added DMP's 44/48 KHz sound support
	//** DMP check the newly added sound quality menu options
	switch (s_options_quality_list.curvalue)
	{
	case 1:
		Cvar_SetValue( "s_khz", 22 );
		Cvar_SetValue( "s_loadas8bit", false );
		break;
	case 2:
		Cvar_SetValue( "s_khz", 44 );
		Cvar_SetValue( "s_loadas8bit", false );
		break;
	case 3:
		Cvar_SetValue( "s_khz", 48 );
		Cvar_SetValue( "s_loadas8bit", false );
		break;
	default:
		Cvar_SetValue( "s_khz", 11 );
		Cvar_SetValue( "s_loadas8bit", true );
		break;
	}
	//** DMP end sound menu changes

	Cvar_SetValue( "s_primary", s_options_compatibility_list.curvalue );

	//viddef.width/2 - scaledVideo(38*MENU_FONT_SIZE)/2,

	M_DrawTextBox( 8, 120 - 48, 36, 3 );
	M_Print( 28, 120 - 48 + MENU_FONT_SIZE,  "Restarting the sound system. This" );
	M_Print( 28, 120 - 48 + MENU_FONT_SIZE*2, "could take up to a minute, so" );
	M_Print( 28, 120 - 48 + MENU_FONT_SIZE*3, "please be patient." );

	// the text box won't show up unless we do a buffer swap
	GLimp_EndFrame();

	CL_Snd_Restart_f();
}

void Options_MenuInit( void )
{
	//Knightmare- Psychospaz's menu select box
/*
	static const char *menu_names[] =
	{
		"sound",
		"controls",
		"ingame",
		"interface",
		0
	};
*/
	static const char *cd_music_items[] =
	{
		"disabled",
		"enabled",
		0
	};

	static const char *quality_items[] =
	{
		"low (11KHz/8-bit)",			//** DMP - changed text
		"normal (22KHz/16-bit)",		//** DMP - changed text
		"high (44KHz/16-bit)",			//** DMP - added 44 Khz menu item
		"highest (48KHz/16-bit)",		//** DMP - added 48 Khz menu item
		0
	};

	static const char *compatibility_items[] =
	{
		"max compatibility", "max performance", 0
	};

	static const char *yesno_names[] =
	{
		"no",
		"yes",
		0
	};

	static const char *textcolor_names[] =
	{
		"gray",
		"red",
		"green",
		"yellow",
		"blue",
		"teal",
		"pink",
		"white",
		"black",
		"orange",
		0
	};

	/*static const char *old_crosshair_names[] =
	{
		"none",
		"cross 1",
		"dot",
		"angle",
		"cross 2",
		"cross 3",
		"cross 4",
		"trans disc",
		"trans circle",
		0
	};*/

	//Knightmare- Psychospaz's changeable rail trail
	static const char *railtrail_names[] =
	{
		"colored spiral",
		"colored beam", //laser
		"colored devrail",
		0
	};

	static const char *blood_names[] =
	{
		"none",
		"puff",
		"splat",
		"bleed",
		"gore",
		0
	};

#if defined (__unix__)
	static const char *clock_names[] =
	{
		"disabled",
		"24 H Format",
		"12 H Format",
		0
	};
#endif

	int y;

	if (!options_menu)
		options_menu = Cvar_Get ("options_menu", "0", 0);

	win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE);

	/*
	** configure controls menu and menu items
	*/
	/*
	s_options_menu.x = viddef.width / 2;
	s_options_menu.y = viddef.height / 2 - 58;
	s_options_menu.nitems = 0;
	*/
	s_options_menu.x = viddef.width * 0.50 - scaledVideo(3*MENU_FONT_SIZE);
	s_options_ingame_menu.x = s_options_menu.x;
	s_options_sound_menu.x = s_options_menu.x;
	s_options_controls_menu.x = s_options_menu.x;
	s_options_interface_menu.x = s_options_menu.x;

	s_options_menu.y = viddef.height * 0.50 - scaledVideo(7.25*MENU_FONT_SIZE); //58
	s_options_ingame_menu.y = s_options_menu.y;
	s_options_sound_menu.y = s_options_menu.y;
	s_options_controls_menu.y = s_options_menu.y;
	s_options_interface_menu.y = s_options_menu.y;

	s_options_menu.nitems = 0;
	s_options_sound_menu.nitems = 0;
	s_options_controls_menu.nitems = 0;
	s_options_ingame_menu.nitems = 0;
	s_options_interface_menu.nitems = 0;

	//SECTION SELECTORS
	{
		s_options_sound_section.generic.type	= MTYPE_ACTION;
		s_options_sound_section.generic.flags  = QMF_LEFT_JUSTIFY;
		s_options_sound_section.generic.name	= " sound";
		s_options_sound_section.generic.x		= 0; //MENU_FONT_SIZE*0.5*strlen(s_options_sound_section.generic.name);
		s_options_sound_section.generic.y		= MENU_FONT_SIZE * 2;
		s_options_sound_section.generic.callback = setMenuSound;
		//s_options_sound_section.generic.cursor_offset = -(MENU_FONT_SIZE*10);
		
		s_options_controls_section.generic.type	= MTYPE_ACTION;
		s_options_controls_section.generic.flags  = QMF_LEFT_JUSTIFY;
		s_options_controls_section.generic.name	= " controls";
		s_options_controls_section.generic.x		= 0; //MENU_FONT_SIZE*0.5*strlen(s_options_controls_section.generic.name);
		s_options_controls_section.generic.y		= MENU_FONT_SIZE * 4;
		s_options_controls_section.generic.callback = setMenuControls;
		//s_options_controls_section.generic.cursor_offset = -(MENU_FONT_SIZE*10);
		
		s_options_ingame_section.generic.type	= MTYPE_ACTION;
		s_options_ingame_section.generic.flags  = QMF_LEFT_JUSTIFY;
		s_options_ingame_section.generic.name	= " ingame";
		s_options_ingame_section.generic.x		= 0; //MENU_FONT_SIZE*0.5*strlen(s_options_ingame_section.generic.name);
		s_options_ingame_section.generic.y		= MENU_FONT_SIZE * 6;
		s_options_ingame_section.generic.callback = setMenuIngame;
		//s_options_ingame_section.generic.cursor_offset = -(MENU_FONT_SIZE*10);

		s_options_interface_section.generic.type	= MTYPE_ACTION;
		s_options_interface_section.generic.flags  = QMF_LEFT_JUSTIFY;
		s_options_interface_section.generic.name	= " interface";
		s_options_interface_section.generic.x		= 0; //MENU_FONT_SIZE*0.5*strlen(s_options_interface_section.generic.name);
		s_options_interface_section.generic.y		= MENU_FONT_SIZE * 8;
		s_options_interface_section.generic.callback = setMenuInterface;
		//s_options_interface_section.generic.cursor_offset = -(MENU_FONT_SIZE*10);

		s_options_back_action.generic.type	= MTYPE_ACTION;
		s_options_back_action.generic.flags  = QMF_LEFT_JUSTIFY;
		s_options_back_action.generic.name	= " back to main";
		s_options_back_action.generic.x		= 0; //MENU_FONT_SIZE*0.5*strlen(s_options_back_action.generic.name);
		s_options_back_action.generic.y		= MENU_FONT_SIZE * 11;
		s_options_back_action.generic.callback = M_BackMenu;
		//s_options_back_action.generic.cursor_offset = -(MENU_FONT_SIZE*10);
	}
	//SECTION HEADERS
	{
		s_options_sound_header.generic.type	= MTYPE_SEPARATOR;
		s_options_sound_header.generic.name	= "sound";
		s_options_sound_header.generic.x	= MENU_FONT_SIZE/2 * strlen(s_options_sound_header.generic.name);
		s_options_sound_header.generic.y	= 0;

		s_options_controls_header.generic.type	= MTYPE_SEPARATOR;
		s_options_controls_header.generic.name	= "controls";
		s_options_controls_header.generic.x	= MENU_FONT_SIZE/2 * strlen(s_options_controls_header.generic.name);
		s_options_controls_header.generic.y	= 0;

		s_options_ingame_header.generic.type	= MTYPE_SEPARATOR;
		s_options_ingame_header.generic.name	= "ingame";
		s_options_ingame_header.generic.x	= MENU_FONT_SIZE/2 * strlen(s_options_ingame_header.generic.name);
		s_options_ingame_header.generic.y	= 0;

		s_options_interface_header.generic.type	= MTYPE_SEPARATOR;
		s_options_interface_header.generic.name	= "interface";
		s_options_interface_header.generic.x	= MENU_FONT_SIZE/2 * strlen(s_options_interface_header.generic.name);
		s_options_interface_header.generic.y	= 0;
	}
	//BEGIN SOUND OPTIONS
	{
		y = 3*(MENU_FONT_SIZE+2);

		s_options_sfxvolume_slider.generic.type	= MTYPE_SLIDER;
		s_options_sfxvolume_slider.generic.x	= 0;
		s_options_sfxvolume_slider.generic.y	= y; //30
		s_options_sfxvolume_slider.generic.name	= "effects volume";
		s_options_sfxvolume_slider.generic.callback	= UpdateVolumeFunc;
		s_options_sfxvolume_slider.minvalue		= 0;
		s_options_sfxvolume_slider.maxvalue		= 10;
		s_options_sfxvolume_slider.curvalue		= Cvar_VariableValue( "s_volume" ) * 10;

		s_options_musicvolume_slider.generic.type	= MTYPE_SLIDER;
		s_options_musicvolume_slider.generic.x		= 0;
		s_options_musicvolume_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //40
		s_options_musicvolume_slider.generic.name	= "music volume";
		s_options_musicvolume_slider.generic.callback	= UpdateMusicVolumeFunc;
		s_options_musicvolume_slider.minvalue		= 0;
		s_options_musicvolume_slider.maxvalue		= 10;
		s_options_musicvolume_slider.curvalue		= Cvar_VariableValue( "s_musicvolume" ) * 10;
		s_options_musicvolume_slider.generic.statusbar = "volume of ogg vorbis music";

		s_options_oggmusic_box.generic.type		= MTYPE_SPINCONTROL;
		s_options_oggmusic_box.generic.x		= 0;
		s_options_oggmusic_box.generic.y		= y+=(MENU_FONT_SIZE+2); //50
		s_options_oggmusic_box.generic.name		= "ogg vorbis music";
		s_options_oggmusic_box.generic.callback	= UpdateOggMusicFunc;
		s_options_oggmusic_box.itemnames		= cd_music_items;
		s_options_oggmusic_box.curvalue 		= (Cvar_VariableValue("cl_ogg_music") > 0);
		s_options_oggmusic_box.generic.statusbar = "override of CD music with ogg vorbis tracks";

#ifdef OGGVORBIS
		s_options_oggvolume_slider.generic.type	= MTYPE_SLIDER;
		s_options_oggvolume_slider.generic.x		= 0;
		s_options_oggvolume_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //40
		s_options_oggvolume_slider.generic.name		= "Ogg volume";
		s_options_oggvolume_slider.generic.callback	= UpdateOGGVolumeFunc;
		s_options_oggvolume_slider.minvalue		= 0;
		s_options_oggvolume_slider.maxvalue		= 25;
		s_options_oggvolume_slider.curvalue		= Cvar_VariableValue( "ogg_volume" ) * 10;
		s_options_oggvolume_slider.generic.statusbar 	= "volume of ogg vorbis files";
#endif

		s_options_cdvolume_box.generic.type	= MTYPE_SPINCONTROL;
		s_options_cdvolume_box.generic.x		= 0;
		s_options_cdvolume_box.generic.y		= y+=(MENU_FONT_SIZE+2); //60
		s_options_cdvolume_box.generic.name	= "CD music";
		s_options_cdvolume_box.generic.callback	= UpdateCDVolumeFunc;
		s_options_cdvolume_box.itemnames		= cd_music_items;
		s_options_cdvolume_box.curvalue 		= !Cvar_VariableValue("cd_nocd");

		s_options_quality_list.generic.type	= MTYPE_SPINCONTROL;
		s_options_quality_list.generic.x		= 0;
		s_options_quality_list.generic.y		= y+=(MENU_FONT_SIZE+2); //70
		s_options_quality_list.generic.name		= "sound quality";
		s_options_quality_list.generic.callback = UpdateSoundQualityFunc;
		s_options_quality_list.itemnames		= quality_items;
		s_options_quality_list.curvalue			= !Cvar_VariableValue( "s_loadas8bit" );

		s_options_compatibility_list.generic.type	= MTYPE_SPINCONTROL;
		s_options_compatibility_list.generic.x		= 0;
		s_options_compatibility_list.generic.y		= y+=(MENU_FONT_SIZE+2); //80
		s_options_compatibility_list.generic.name	= "sound compatibility";
		s_options_compatibility_list.generic.callback = UpdateSoundQualityFunc;
		s_options_compatibility_list.itemnames		= compatibility_items;
		s_options_compatibility_list.curvalue		= Cvar_VariableValue( "s_primary" );
	}
	//BEGIN CONTROL OPTIONS
	{
		y = 3*(MENU_FONT_SIZE+2);

		s_options_sensitivity_slider.generic.type	= MTYPE_SLIDER;
		s_options_sensitivity_slider.generic.x		= 0;
		s_options_sensitivity_slider.generic.y		= y; //30
		s_options_sensitivity_slider.generic.name	= "mouse speed";
		s_options_sensitivity_slider.generic.callback = MouseSpeedFunc;
		s_options_sensitivity_slider.minvalue		= 2;
		s_options_sensitivity_slider.maxvalue		= 22;

		s_options_invertmouse_box.generic.type = MTYPE_SPINCONTROL;
		s_options_invertmouse_box.generic.x	= 0;
		s_options_invertmouse_box.generic.y	= y+=(MENU_FONT_SIZE+2); //40
		s_options_invertmouse_box.generic.name	= "invert mouse";
		s_options_invertmouse_box.generic.callback = InvertMouseFunc;
		s_options_invertmouse_box.itemnames = yesno_names;

		s_options_thirdperson_box.generic.type = MTYPE_SPINCONTROL;
		s_options_thirdperson_box.generic.x	= 0;
		s_options_thirdperson_box.generic.y	= y+=2*(MENU_FONT_SIZE+2); //60
		s_options_thirdperson_box.generic.name	= "third person";
		s_options_thirdperson_box.generic.callback = ThirdPersonFunc;
		s_options_thirdperson_box.itemnames = yesno_names;

		s_options_thirdperson_distance_slider.generic.type	= MTYPE_SLIDER;
		s_options_thirdperson_distance_slider.generic.x		= 0;
		s_options_thirdperson_distance_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //70
		s_options_thirdperson_distance_slider.generic.name	= "camera distance";
		s_options_thirdperson_distance_slider.generic.callback = ThirdPersonDistFunc;
		s_options_thirdperson_distance_slider.minvalue		= 1;
		s_options_thirdperson_distance_slider.maxvalue		= 5;

		s_options_thirdperson_angle_slider.generic.type	= MTYPE_SLIDER;
		s_options_thirdperson_angle_slider.generic.x		= 0;
		s_options_thirdperson_angle_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //80
		s_options_thirdperson_angle_slider.generic.name	= "camera angle";
		s_options_thirdperson_angle_slider.generic.callback = ThirdPersonAngleFunc;
		s_options_thirdperson_angle_slider.minvalue		= 0;
		s_options_thirdperson_angle_slider.maxvalue		= 4;

		s_options_alwaysrun_box.generic.type = MTYPE_SPINCONTROL;
		s_options_alwaysrun_box.generic.x	= 0;
		s_options_alwaysrun_box.generic.y	= y+=2*(MENU_FONT_SIZE+2); //100
		s_options_alwaysrun_box.generic.name	= "always run";
		s_options_alwaysrun_box.generic.callback = AlwaysRunFunc;
		s_options_alwaysrun_box.itemnames = yesno_names;

		s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL;
		s_options_lookspring_box.generic.x	= 0;
		s_options_lookspring_box.generic.y	= y+=(MENU_FONT_SIZE+2); //110
		s_options_lookspring_box.generic.name	= "lookspring";
		s_options_lookspring_box.generic.callback = LookspringFunc;
		s_options_lookspring_box.itemnames = yesno_names;

		s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL;
		s_options_lookstrafe_box.generic.x	= 0;
		s_options_lookstrafe_box.generic.y	= y+=(MENU_FONT_SIZE+2); //120
		s_options_lookstrafe_box.generic.name	= "lookstrafe";
		s_options_lookstrafe_box.generic.callback = LookstrafeFunc;
		s_options_lookstrafe_box.itemnames = yesno_names;

		s_options_freelook_box.generic.type = MTYPE_SPINCONTROL;
		s_options_freelook_box.generic.x	= 0;
		s_options_freelook_box.generic.y	= y+=(MENU_FONT_SIZE+2); //130
		s_options_freelook_box.generic.name	= "free look";
		s_options_freelook_box.generic.callback = FreeLookFunc;
		s_options_freelook_box.itemnames = yesno_names;

		s_options_joystick_box.generic.type = MTYPE_SPINCONTROL;
		s_options_joystick_box.generic.x	= 0;
		s_options_joystick_box.generic.y	= y+=(MENU_FONT_SIZE+2); //140
		s_options_joystick_box.generic.name	= "use joystick";
		s_options_joystick_box.generic.callback = JoystickFunc;
		s_options_joystick_box.itemnames = yesno_names;

		s_options_customize_options_action.generic.type	= MTYPE_ACTION;
		s_options_customize_options_action.generic.x		= MENU_FONT_SIZE;
		s_options_customize_options_action.generic.y		= y+=2*(MENU_FONT_SIZE+2); //160
		s_options_customize_options_action.generic.name	= "customize controls";
		s_options_customize_options_action.generic.callback = CustomizeControlsFunc;
	}
	//BEGIN INGAME OPTIONS
	{
		y = 3*(MENU_FONT_SIZE+2);

		crosshair_names = SetCrosshairNames ();
		s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL;
		s_options_crosshair_box.generic.x	= 0;
		s_options_crosshair_box.generic.y	= y; //30
		s_options_crosshair_box.generic.name	= "crosshair";
		s_options_crosshair_box.generic.callback = CrosshairFunc;
		s_options_crosshair_box.itemnames = (const char **)crosshair_names;

		//Knightmare- Psychospaz's changeable size crosshair
		s_options_crosshairscale_slider.generic.type	= MTYPE_SLIDER;
		s_options_crosshairscale_slider.generic.x		= 0;
		s_options_crosshairscale_slider.generic.y		= y+=5*(MENU_FONT_SIZE+2); //80
		s_options_crosshairscale_slider.generic.name	= "crosshair scale";
		s_options_crosshairscale_slider.generic.callback = CrosshairSizeFunc;
		s_options_crosshairscale_slider.minvalue		= 1;
		s_options_crosshairscale_slider.maxvalue		= 12;

		// Knightmare- hud scaling option
		s_options_hudscale_slider.generic.type			= MTYPE_SLIDER;
		s_options_hudscale_slider.generic.x				= 0;
		s_options_hudscale_slider.generic.y				= y+=(MENU_FONT_SIZE+2); //90
		s_options_hudscale_slider.generic.name			= "status bar scale";
		s_options_hudscale_slider.generic.callback		= HudScaleFunc;
		s_options_hudscale_slider.minvalue				= 1;
		s_options_hudscale_slider.maxvalue				= 7;

		// Knightmare- hud trans option
		s_options_hudalpha_slider.generic.type			= MTYPE_SLIDER;
		s_options_hudalpha_slider.generic.x				= 0;
		s_options_hudalpha_slider.generic.y				= y+=(MENU_FONT_SIZE+2); //100
		s_options_hudalpha_slider.generic.name			= "status bar transparency";
		s_options_hudalpha_slider.generic.callback		= HudAlphaFunc;
		s_options_hudalpha_slider.minvalue				= 1;
		s_options_hudalpha_slider.maxvalue				= 11;

		s_options_fps_box.generic.type = MTYPE_SPINCONTROL;
		s_options_fps_box.generic.x	= 0;
		s_options_fps_box.generic.y	= y +=(MENU_FONT_SIZE+2); //110
		s_options_fps_box.generic.name	= "FPS counter";
		s_options_fps_box.generic.callback = FPSFunc;
		s_options_fps_box.itemnames = yesno_names;
		
#if defined (__unix__)
		s_options_clock_box.generic.type     = MTYPE_SPINCONTROL;
		s_options_clock_box.generic.x	     = 0;
		s_options_clock_box.generic.y	     = y +=(MENU_FONT_SIZE+2);
		s_options_clock_box.generic.name     = "Clock Screen";
		s_options_clock_box.generic.callback = ClockFunc;
		s_options_clock_box.itemnames        = clock_names;
#endif

		// Knightmare- foostep override option
		s_options_footstep_box.generic.type = MTYPE_SPINCONTROL;
		s_options_footstep_box.generic.x	= 0;
		s_options_footstep_box.generic.y	= y += 2*(MENU_FONT_SIZE+2); //130
		s_options_footstep_box.generic.name	= "override footstep sounds";
		s_options_footstep_box.generic.callback = FootStepFunc;
		s_options_footstep_box.generic.statusbar = "sets footstep sounds with definitions in texsurfs.txt";
		s_options_footstep_box.itemnames = yesno_names;
		
		s_options_blood_box.generic.type = MTYPE_SPINCONTROL;
		s_options_blood_box.generic.x	= 0;
		s_options_blood_box.generic.y	= y += (MENU_FONT_SIZE+2); //140
		s_options_blood_box.generic.name	= "blood";
		s_options_blood_box.generic.callback = BloodFunc;
		s_options_blood_box.itemnames = blood_names;

		//Knightmare- Psychospaz's changeable rail trail
		s_options_railtrail_box.generic.type = MTYPE_SPINCONTROL;
		s_options_railtrail_box.generic.x	= 0;
		s_options_railtrail_box.generic.y	= y += (MENU_FONT_SIZE+2); //150
		s_options_railtrail_box.generic.name	= "railtrail type";
		s_options_railtrail_box.generic.callback = RailTrailFunc;
		s_options_railtrail_box.itemnames = railtrail_names;

		s_options_railcolor_box[0].generic.type	= MTYPE_SLIDER;
		s_options_railcolor_box[0].generic.x		= 0;
		s_options_railcolor_box[0].generic.y		= y+=(MENU_FONT_SIZE+2); //160
		s_options_railcolor_box[0].generic.name	= "red - railtrail";
		s_options_railcolor_box[0].generic.callback = RailColorRedFunc;
		s_options_railcolor_box[0].minvalue		= 0;
		s_options_railcolor_box[0].maxvalue		= 16;

		s_options_railcolor_box[1].generic.type	= MTYPE_SLIDER;
		s_options_railcolor_box[1].generic.x		= 0;
		s_options_railcolor_box[1].generic.y		= y+=(MENU_FONT_SIZE+2); //170
		s_options_railcolor_box[1].generic.name	= "green - railtrail";
		s_options_railcolor_box[1].generic.callback = RailColorGreenFunc;
		s_options_railcolor_box[1].minvalue		= 0;
		s_options_railcolor_box[1].maxvalue		= 16;

		s_options_railcolor_box[2].generic.type	= MTYPE_SLIDER;
		s_options_railcolor_box[2].generic.x		= 0;
		s_options_railcolor_box[2].generic.y		= y+=(MENU_FONT_SIZE+2); //180
		s_options_railcolor_box[2].generic.name	= "blue - railtrail";
		s_options_railcolor_box[2].generic.callback = RailColorBlueFunc;
		s_options_railcolor_box[2].minvalue		= 0;
		s_options_railcolor_box[2].maxvalue		= 16;

		s_options_ingame_defaults_action.generic.type	= MTYPE_ACTION;
		s_options_ingame_defaults_action.generic.x		= MENU_FONT_SIZE;
		s_options_ingame_defaults_action.generic.y		= y+=2*(MENU_FONT_SIZE+2); //200;
		s_options_ingame_defaults_action.generic.name	= "reset defaults";
		s_options_ingame_defaults_action.generic.callback = ControlsResetDefaultsFunc;

		/* Removed because console can be opened over menus
		s_options_ingame_console_action.generic.type	= MTYPE_ACTION;
		s_options_ingame_console_action.generic.x		= MENU_FONT_SIZE;
		s_options_ingame_console_action.generic.y		= y+=(MENU_FONT_SIZE+2); //210;
		s_options_ingame_console_action.generic.name	= "go to console";
		s_options_ingame_console_action.generic.callback = ConsoleFunc;
		*/

		s_options_ingame_backmain_action.generic.type	= MTYPE_ACTION;
		s_options_ingame_backmain_action.generic.x		= MENU_FONT_SIZE;
		s_options_ingame_backmain_action.generic.y		= y+=2*(MENU_FONT_SIZE+2); //220;
		s_options_ingame_backmain_action.generic.name	= "back to options";
		s_options_ingame_backmain_action.generic.callback = setMenuOptionsMain;
	}
	//BEGIN INTERFACE
	{	
		y = 3*(MENU_FONT_SIZE+2);

		// Knightmare- Psychospaz's menu mouse support
		s_options_menumouse_slider.generic.type		= MTYPE_SLIDER;
		s_options_menumouse_slider.generic.x		= 0;
		s_options_menumouse_slider.generic.y		= y; //30
		s_options_menumouse_slider.generic.name		= "mouse speed";
		s_options_menumouse_slider.generic.callback = MouseMenuFunc;
		s_options_menumouse_slider.minvalue			= 1;
		s_options_menumouse_slider.maxvalue			= 8;

		// Knightmare- menu scaling option
		/*s_options_menuscale_box.generic.type		= MTYPE_SPINCONTROL;
		s_options_menuscale_box.generic.x			= 0;
		s_options_menuscale_box.generic.y			= y+=(MENU_FONT_SIZE+2); //40
		s_options_menuscale_box.generic.name		= "scaled menus";
		s_options_menuscale_box.generic.callback	= MenuScaleFunc;
		s_options_menuscale_box.itemnames			= yesno_names;*/

		// Knightmare- menu alpha option
		s_options_menualpha_slider.generic.type		= MTYPE_SLIDER;
		s_options_menualpha_slider.generic.x		= 0;
		s_options_menualpha_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //50
		s_options_menualpha_slider.generic.name		= "ingame menu transparency";
		s_options_menualpha_slider.generic.callback	= MenuAlphaFunc;
		s_options_menualpha_slider.minvalue			= 0;
		s_options_menualpha_slider.maxvalue			= 20;

		font_names = SetFontNames ();
		s_options_font_box.generic.type = MTYPE_SPINCONTROL;
		s_options_font_box.generic.x	= 0;
		s_options_font_box.generic.y	= y+=2*(MENU_FONT_SIZE+2); //70
		s_options_font_box.generic.name	= "font";
		s_options_font_box.generic.callback = FontFunc;
		s_options_font_box.itemnames = (const char **)font_names;

		s_options_fontsize_slider.generic.type		= MTYPE_SLIDER;
		s_options_fontsize_slider.generic.x			= 0;
		s_options_fontsize_slider.generic.y			= y+=(MENU_FONT_SIZE+2); //80
		s_options_fontsize_slider.generic.name		= "console font size";
		s_options_fontsize_slider.generic.callback	= FontSizeFunc;
		s_options_fontsize_slider.minvalue			= 2;
		s_options_fontsize_slider.maxvalue			= 6;

		// Knightmare- text color option
		s_options_alt_text_color_box.generic.type = MTYPE_SPINCONTROL;
		s_options_alt_text_color_box.generic.x	= 0;
		s_options_alt_text_color_box.generic.y	= y+=(MENU_FONT_SIZE+2); //90
		s_options_alt_text_color_box.generic.name	= "alt text color";
		s_options_alt_text_color_box.generic.callback = AltTextColorFunc;
		s_options_alt_text_color_box.itemnames = textcolor_names;

		// Knightmare- Psychospaz's transparent console cvar
		s_options_conalpha_slider.generic.type	= MTYPE_SLIDER;
		s_options_conalpha_slider.generic.x		= 0;
		s_options_conalpha_slider.generic.y		= y+=2*(MENU_FONT_SIZE+2); //110
		s_options_conalpha_slider.generic.name	= "console transparency";
		s_options_conalpha_slider.generic.callback = ConAlphaFunc;
		s_options_conalpha_slider.minvalue		= 0;
		s_options_conalpha_slider.maxvalue		= 20;

		// Knightmare- variable console height
		s_options_conheight_slider.generic.type	= MTYPE_SLIDER;
		s_options_conheight_slider.generic.x		= 0;
		s_options_conheight_slider.generic.y		= y+=(MENU_FONT_SIZE+2); //120
		s_options_conheight_slider.generic.name	= "console height";
		s_options_conheight_slider.generic.callback = ConHeightFunc;
		s_options_conheight_slider.minvalue		= 0;
		s_options_conheight_slider.maxvalue		= 10;

		s_options_noalttab_box.generic.type = MTYPE_SPINCONTROL;
		s_options_noalttab_box.generic.x	= 0;
		s_options_noalttab_box.generic.y	= y+=2*(MENU_FONT_SIZE+2); //140;
		s_options_noalttab_box.generic.name	= "disable alt-tab";
		s_options_noalttab_box.generic.callback = NoAltTabFunc;
		s_options_noalttab_box.itemnames = yesno_names;

	} // end Knightmare

	s_options_defaults_action.generic.type	= MTYPE_ACTION;
	s_options_defaults_action.generic.x		= MENU_FONT_SIZE;
	s_options_defaults_action.generic.y		= 18*(MENU_FONT_SIZE+2); //180;
	s_options_defaults_action.generic.name	= "reset defaults";
	s_options_defaults_action.generic.callback = ControlsResetDefaultsFunc;

	s_options_backmain_action.generic.type	= MTYPE_ACTION;
	s_options_backmain_action.generic.x		= MENU_FONT_SIZE;
	s_options_backmain_action.generic.y		= 20*(MENU_FONT_SIZE+2); //200;
	s_options_backmain_action.generic.name	= "back to options";
	s_options_backmain_action.generic.callback = setMenuOptionsMain;

	ControlsSetMenuItemValues();

	//Knightmare- Psychospaz's menu select box
		Menu_AddItem( &s_options_menu,			( void * ) &s_options_sound_section );
		Menu_AddItem( &s_options_menu,			( void * ) &s_options_controls_section );
		Menu_AddItem( &s_options_menu,			( void * ) &s_options_ingame_section );
		Menu_AddItem( &s_options_menu,			( void * ) &s_options_interface_section );
		Menu_AddItem( &s_options_menu,			( void * ) &s_options_back_action );

	//sound
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_sound_header );
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_sfxvolume_slider );
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_musicvolume_slider );
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_oggmusic_box );
#ifdef OGGVORBIS
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_oggvolume_slider );
#endif
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_cdvolume_box );
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_quality_list );
		Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_compatibility_list );

	//controls
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_controls_header );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_sensitivity_slider );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_invertmouse_box );
		// Knightmare- added Psychospaz's chasecam
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_thirdperson_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_thirdperson_distance_slider );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_thirdperson_angle_slider );
		// end Knightmare
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_alwaysrun_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_lookspring_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_lookstrafe_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_freelook_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_joystick_box );
		Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_customize_options_action );

	//ingame
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_ingame_header );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_crosshair_box );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_crosshairscale_slider );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_hudscale_slider );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_hudalpha_slider );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_fps_box );
#if defined (__unix__)
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_clock_box );
#endif

		// Knightmare- foostep override option
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_footstep_box );

		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_blood_box );

		//Knightmare- Psychospaz's changeable rail trail
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_railtrail_box );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_railcolor_box[0] );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_railcolor_box[1] );
		Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_railcolor_box[2] );

	//interface
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_interface_header );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_menumouse_slider );
		//Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_menuscale_box );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_menualpha_slider );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_font_box );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_fontsize_slider );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_alt_text_color_box );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_conalpha_slider );
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_conheight_slider );
#ifdef _WIN32
		Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_noalttab_box );
#endif

	Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_defaults_action );
	Menu_AddItem( &s_options_sound_menu, ( void * ) &s_options_backmain_action );

	Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_defaults_action );
	Menu_AddItem( &s_options_controls_menu, ( void * ) &s_options_backmain_action );

	Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_ingame_defaults_action );
	Menu_AddItem( &s_options_ingame_menu, ( void * ) &s_options_ingame_backmain_action );

	Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_defaults_action );
	Menu_AddItem( &s_options_interface_menu, ( void * ) &s_options_backmain_action );
}

void MenuCrosshair_MouseClick( void )
{
	char *sound = NULL;
	buttonmenuobject_t crosshairbutton;
	int button_x, button_y;
	int button_size;

	button_size = 36;

	button_x = viddef.width/2 - scaledVideo(32)/2 + scaledVideo(MENU_FONT_SIZE/2-2);
	button_y = s_options_ingame_menu.y + scaledVideo(42);

	addPlayerButton (&crosshairbutton, 0, 
		button_x, button_y,
		scaledVideo(button_size), 
		scaledVideo(button_size));

	if (cursor.x>=crosshairbutton.min[0] && cursor.x<=crosshairbutton.max[0] &&
		cursor.y>=crosshairbutton.min[1] && cursor.y<=crosshairbutton.max[1])
	{
		if (!cursor.buttonused[MOUSEBUTTON1] && cursor.buttonclicks[MOUSEBUTTON1]==1)
		{
			s_options_crosshair_box.curvalue++;
			if (s_options_crosshair_box.curvalue > numcrosshairs-1)
				s_options_crosshair_box.curvalue = 0; // wrap around
			CrosshairFunc(NULL);

			cursor.buttonused[MOUSEBUTTON1] = true;
			cursor.buttonclicks[MOUSEBUTTON1] = 0;
			sound = menu_move_sound;
			if ( sound )
				S_StartLocalSound( sound );
		}
		if (!cursor.buttonused[MOUSEBUTTON2] && cursor.buttonclicks[MOUSEBUTTON2]==1)
		{
			s_options_crosshair_box.curvalue--;
			if (s_options_crosshair_box.curvalue < 0)
				s_options_crosshair_box.curvalue = numcrosshairs-1; // wrap around
			CrosshairFunc(NULL);

			cursor.buttonused[MOUSEBUTTON2] = true;
			cursor.buttonclicks[MOUSEBUTTON2] = 0;
			sound = menu_move_sound;
			if ( sound )
				S_StartLocalSound( sound );
		}
	}
}

void DrawMenuCrosshair (void)
{

	R_DrawFill (
		viddef.width/2 - scaledVideo(32)/2 + scaledVideo(MENU_FONT_SIZE/2-2),
		s_options_ingame_menu.y + scaledVideo(42),
		scaledVideo(36), scaledVideo(36), 3);

	R_DrawFill (
		viddef.width/2 - scaledVideo(32)/2 + scaledVideo(MENU_FONT_SIZE/2-1),
		s_options_ingame_menu.y + scaledVideo(43),
		scaledVideo(34), scaledVideo(34), 0);

	if (s_options_crosshair_box.curvalue < 1)
		return;

	R_DrawStretchPic (
		viddef.width/2 - scaledVideo(32)/2 + scaledVideo(MENU_FONT_SIZE/2),
		s_options_ingame_menu.y + scaledVideo(44),
		scaledVideo(32), scaledVideo(32), crosshair_names[s_options_crosshair_box.curvalue], 1.0);
}

void Options_MenuDraw (void)
{
	M_Banner( "m_banner_options" );

	if (options_menu->value==1)
	{
		Menu_AdjustCursor( &s_options_sound_menu, 1 );
		Menu_Draw( &s_options_sound_menu );
	}
	else if (options_menu->value==2)
	{
		Menu_AdjustCursor( &s_options_controls_menu, 1 );
		Menu_Draw( &s_options_controls_menu );
	}
	else if (options_menu->value==3)
	{
		Menu_AdjustCursor( &s_options_ingame_menu, 1 );
		Menu_Draw( &s_options_ingame_menu );
		DrawMenuCrosshair();
	}
	else if (options_menu->value==4)
	{
		Menu_AdjustCursor( &s_options_interface_menu, 1 );
		Menu_Draw( &s_options_interface_menu );
	}
	else
	{
		Menu_AdjustCursor( &s_options_menu, 1 );
		Menu_Draw( &s_options_menu );
	}

}

const char *Options_MenuKey( int key )
{
	if (options_menu->value==1)
		return Default_MenuKey( &s_options_sound_menu, key );
	else if (options_menu->value==2)
		return Default_MenuKey( &s_options_controls_menu, key );
	else if  (options_menu->value==3)
		return Default_MenuKey( &s_options_ingame_menu, key );
	else if  (options_menu->value==4)
		return Default_MenuKey( &s_options_interface_menu, key );
	else
		return Default_MenuKey( &s_options_menu, key );
}

void M_Menu_Options_f (void)
{
	Options_MenuInit();
	M_PushMenu ( Options_MenuDraw, Options_MenuKey );
}
