#include "quakedef.h"

#ifdef MENU_DAT

#ifdef RGLQUAKE
#include "glquake.h"
#endif

int MP_TranslateFTEtoDPCodes(int code);

typedef struct menuedict_s
{
	qboolean	isfree;
	float		freetime; // sv.time when the object was freed
	int			entnum;
	qboolean	readonly;	//world
} menuedict_t;

#define	RETURN_SSTRING(s) (*(char **)&((int *)pr_globals)[OFS_RETURN] = PR_SetString(prinst, s))	//static - exe will not change it.
char *PF_TempStr(void);

int menuentsize;

//pr_cmds.c builtins that need to be moved to a common.
void VARGS PR_BIError(progfuncs_t *progfuncs, char *format, ...);
void PF_cvar_string (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_cvar_set (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_dprint (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_error (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_rint (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_floor (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_ceil (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_Tokenize  (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_ArgV  (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_FindString (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_FindFloat (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_nextent (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_randomvec (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_Sin (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_Cos (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_Sqrt (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_bound (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_strlen(progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_strcat (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_ftos (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_fabs (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_vtos (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_etos (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_stof (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_mod (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_substring (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_stov (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_dupstring(progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_forgetstring(progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_Spawn (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_min (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_max (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_registercvar (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_pow (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_chr2str (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_localcmd (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_random (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_fopen (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_fclose (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_fputs (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_fgets (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_normalize (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_vlen (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_vectoyaw (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_vectoangles (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchain (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_findchainfloat (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_coredump (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_traceon (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_traceoff (progfuncs_t *prinst, struct globalvars_s *pr_globals);
void PF_eprint (progfuncs_t *prinst, struct globalvars_s *pr_globals);

void PF_fclose_progs (progfuncs_t *prinst);
char *PF_VarString (progfuncs_t *prinst, int	first, struct globalvars_s *pr_globals);

//new generic functions.

//float	isfunction(string function_name) = #607;
void PF_isfunction (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*name = PR_GetStringOfs(prinst, OFS_PARM0);
	G_FLOAT(OFS_RETURN) = !!PR_FindFunction(prinst, name, PR_CURRENT);
}

//void	callfunction(...) = #605;
void PF_callfunction (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*name;
	func_t f;
	if (*prinst->callargc < 1)
		PR_BIError(prinst, "callfunction needs at least one argument\n");
	name = PR_GetStringOfs(prinst, OFS_PARM0+(*prinst->callargc-1)*3);
	f = PR_FindFunction(prinst, name, PR_CURRENT);
	if (f)
		PR_ExecuteProgram(prinst, f);
}

//void	loadfromfile(string file) = #69;
void PF_loadfromfile (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*filename = PR_GetStringOfs(prinst, OFS_PARM0);
	char *file = COM_LoadTempFile(filename);

	int size;

	if (!file)
	{
		G_FLOAT(OFS_RETURN) = -1;
		return;
	}

	while(prinst->restoreent(prinst, file, &size, NULL))
	{
		file += size;
	}

	G_FLOAT(OFS_RETURN) = 0;
}

void PF_loadfromdata (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*file = PR_GetStringOfs(prinst, OFS_PARM0);

	int size;

	if (!*file)
	{
		G_FLOAT(OFS_RETURN) = -1;
		return;
	}

	while(prinst->restoreent(prinst, file, &size, NULL))
	{
		file += size;
	}

	G_FLOAT(OFS_RETURN) = 0;
}

void PF_mod (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = (float)(((int)G_FLOAT(OFS_PARM0))%((int)G_FLOAT(OFS_PARM1)));
}

typedef struct prvmsearch_s {
	int handle;
	progfuncs_t *fromprogs;	//share across menu/server
	int entries;
	char **names;
	int *sizes;

	struct prvmsearch_s *next;
} prvmsearch_t;
prvmsearch_t *prvmsearches;
int prvm_nextsearchhandle;

void search_close (progfuncs_t *prinst, int handle)
{
	int i;
	prvmsearch_t *prev, *s;

	prev = NULL;
	for (s = prvmsearches; s; )
	{
		if (s->handle == handle)
		{	//close it down.
			if (s->fromprogs != prinst)
			{
				Con_Printf("Handle wasn't valid with that progs\n");
				return;
			}
			if (prev)
				prev->next = s->next;
			else
				prvmsearches = s->next;

			for (i = 0; i < s->entries; i++)
			{
				BZ_Free(s->names[i]);
			}
			BZ_Free(s->names);
			BZ_Free(s->sizes);
			BZ_Free(s);

			return;
		}

		prev = s;
		s = s->next;
	}
}
//a progs was closed... hunt down it's searches, and warn about any searches left open.
void search_close_progs(progfuncs_t *prinst, qboolean complain)
{
	int i;
	prvmsearch_t *prev, *s;

	prev = NULL;
	for (s = prvmsearches; s; )
	{
		if (s->fromprogs == prinst)
		{	//close it down.

			if (complain)
				Con_Printf("Warning: Progs search was still active\n");
			if (prev)
				prev->next = s->next;
			else
				prvmsearches = s->next;

			for (i = 0; i < s->entries; i++)
			{
				BZ_Free(s->names[i]);
			}
			BZ_Free(s->names);
			BZ_Free(s->sizes);
			BZ_Free(s);

			if (prev)
				s = prev->next;
			else
				s = prvmsearches;
			continue;
		}

		prev = s;
		s = s->next;
	}

	if (!prvmsearches)
		prvm_nextsearchhandle = 0;	//might as well.
}

int search_enumerate(char *name, int fsize, void *parm)
{
	prvmsearch_t *s = parm;

	s->names = BZ_Realloc(s->names, ((s->entries+64)&~63) * sizeof(char*));
	s->sizes = BZ_Realloc(s->sizes, ((s->entries+64)&~63) * sizeof(int));
	s->names[s->entries] = BZ_Malloc(strlen(name)+1);
	strcpy(s->names[s->entries], name);
	s->sizes[s->entries] = fsize;

	s->entries++;
	return true;
}

//float	search_begin(string pattern, float caseinsensitive, float quiet) = #74;
void PF_search_begin (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{	//< 0 for error, > 0 for handle.
	char *pattern = PR_GetStringOfs(prinst, OFS_PARM0);
	qboolean caseinsensative = G_FLOAT(OFS_PARM1);
	qboolean quiet = G_FLOAT(OFS_PARM2);
	prvmsearch_t *s;

	s = BZ_Malloc(sizeof(*s));
	s->fromprogs = prinst;
	s->handle = prvm_nextsearchhandle++;

	COM_EnumerateFiles(pattern, search_enumerate, s);

	if (s->entries==0)
	{
		BZ_Free(s);
		G_FLOAT(OFS_RETURN) = -1;
		return;
	}
	s->next = prvmsearches;
	prvmsearches = s;
	G_FLOAT(OFS_RETURN) = s->handle;
}
//void	search_end(float handle) = #75;
void PF_search_end (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int handle = G_FLOAT(OFS_PARM0);
	search_close(prinst, handle);
}
//float	search_getsize(float handle) = #76;
void PF_search_getsize (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int handle = G_FLOAT(OFS_PARM0);
	prvmsearch_t *s;
	G_FLOAT(OFS_RETURN) = -1;
	for (s = prvmsearches; s; s = s->next)
	{
		if (s->handle == handle)
		{	//close it down.
			if (s->fromprogs != prinst)
			{
				Con_Printf("Handle wasn't valid with that progs\n");
				return;
			}

			G_FLOAT(OFS_RETURN) = s->entries;
			return;
		}
	}
}
//string	search_getfilename(float handle, float num) = #77;
void PF_search_getfilename (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int handle = G_FLOAT(OFS_PARM0);
	int num = G_FLOAT(OFS_PARM1);
	prvmsearch_t *s;
	G_INT(OFS_RETURN) = 0;

	for (s = prvmsearches; s; s = s->next)
	{
		if (s->handle == handle)
		{	//close it down.
			if (s->fromprogs != prinst)
			{
				Con_Printf("Search handle wasn't valid with that progs\n");
				return;
			}

			if (num < 0 || num >= s->entries)
				return;
			G_INT(OFS_RETURN) = (int)(s->names[num] - prinst->stringtable);
			return;
		}
	}

	Con_Printf("Search handle wasn't valid\n");
}






void PF_developerprint (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *s;
	if (!developer.value)
		return;
	s = PF_VarString(prinst, 0, pr_globals);
	Con_Printf("%s", s);
}
void PF_print (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *s;
	s = PF_VarString(prinst, 0, pr_globals);
	Con_Printf("%s", s);
}




static void PF_cvar (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*str;
	
	str = PR_GetStringOfs(prinst, OFS_PARM0);
	if (!strcmp("vid_conwidth", str))
		G_FLOAT(OFS_RETURN) = vid.conwidth;
	else if (!strcmp("vid_conheight", str))
		G_FLOAT(OFS_RETURN) = vid.conheight;
	else
		G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str);
}
void PF_getresolution (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float mode = G_FLOAT(OFS_PARM0);
	float *ret = G_VECTOR(OFS_RETURN);

	if (mode > 0)
	{
		ret[0] = 0;
		ret[1] = 0;
		ret[2] = 0;
	}
	else
	{
		ret[0] = vid.conwidth;
		ret[1] = vid.conheight;
		ret[2] = 0;
	}
}




void PF_nonfatalobjerror (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*s;
	struct edict_s	*ed;
	eval_t *selfp;
	
	s = PF_VarString(prinst, 0, pr_globals);

	prinst->PR_StackTrace(prinst);

	selfp = prinst->FindGlobal(prinst, "self", PR_CURRENT);
	if (selfp && selfp->_int)
	{
		ed = PROG_TO_EDICT(prinst, selfp->_int);

		prinst->PR_PrintEdict(prinst, ed);


		if (developer.value)
			*prinst->pr_trace = 2;
		else
		{
			ED_Free (prinst, ed);
		}
	}

	Con_Printf ("======OBJECT ERROR======\n%s\n", s);
}






//float	isserver(void)  = #60;
void PF_isserver (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = sv.state != ss_dead;
}

//float	clientstate(void)  = #62;
void PF_clientstate (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = cls.state >= ca_connected ? 2 : 1;	//fit in with netquake	 (we never run a menu.dat dedicated)
}

//too specific to the prinst's builtins.
static void PF_Fixme (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	progfuncs_t *progfuncs = prinst;
	qboolean printedheader = false;

	Con_Printf("\n");

	prinst->PR_RunError(prinst, "\nBuiltin %i not implemented.\nMenu is not compatable.", prinst->lastcalledbuiltinnumber);
	PR_BIError (prinst, "bulitin not implemented");
}



void PF_CL_precache_sound (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*str;
	
	str = PR_GetStringOfs(prinst, OFS_PARM0);

	if (S_PrecacheSound(str))
		G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
	else
		G_INT(OFS_RETURN) = 0;
}


void PF_CL_is_cached_pic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*str;
	
	str = PR_GetStringOfs(prinst, OFS_PARM0);

//	if (Draw_IsCached)
//		G_FLOAT(OFS_RETURN) = !!Draw_IsCached(str);
//	else
		G_FLOAT(OFS_RETURN) = 1;
}

void PF_CL_precache_pic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*str;
	qpic_t	*pic;
	
	str = PR_GetStringOfs(prinst, OFS_PARM0);

	pic = Draw_SafeCachePic(str);

	if (pic)
		G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
	else
		G_INT(OFS_RETURN) = 0;
}

void PF_CL_free_pic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char	*str;
	
	str = PR_GetStringOfs(prinst, OFS_PARM0);

	//we don't support this.
}


//float	drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) = #454;
void PF_CL_drawcharacter (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float *pos = G_VECTOR(OFS_PARM0);
	int chara = G_FLOAT(OFS_PARM1);
	float *size = G_VECTOR(OFS_PARM2);
	float *rgb = G_VECTOR(OFS_PARM3);
	float alpha = G_FLOAT(OFS_PARM4);
	float flag = G_FLOAT(OFS_PARM5);

	const float fsize = 0.0625;
	float frow, fcol;

	if (!chara)
	{
		G_FLOAT(OFS_RETURN) = -1;	//was null..
		return;
	}

	chara &= 255;
	frow = (chara>>4)*fsize;
	fcol = (chara&15)*fsize;

	if (Draw_ImageColours)
		Draw_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
	if (Draw_Image)
		Draw_Image(pos[0], pos[1], size[0], size[1], fcol, frow, fcol+fsize, frow+fsize, Draw_CachePic("conchars"));

	G_FLOAT(OFS_RETURN) = 1;
}
//float	drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) = #455;
void PF_CL_drawstring (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float *pos = G_VECTOR(OFS_PARM0);
	char *text = PR_GetStringOfs(prinst, OFS_PARM1);
	float *size = G_VECTOR(OFS_PARM2);
//	float *rgb = G_VECTOR(OFS_PARM3);
//	float alpha = G_FLOAT(OFS_PARM4);
//	float flag = G_FLOAT(OFS_PARM5);

	if (!text)
	{
		G_FLOAT(OFS_RETURN) = -1;	//was null..
		return;
	}

	while(*text)
	{
		G_FLOAT(OFS_PARM1) = *text++;
		PF_CL_drawcharacter(prinst, pr_globals);
		pos[0] += size[0];
	}
}
//float	drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) = #456;
void PF_CL_drawpic (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float *pos = G_VECTOR(OFS_PARM0);
	char *picname = PR_GetStringOfs(prinst, OFS_PARM1);
	qpic_t *p = Draw_SafeCachePic(picname);
	float *size = G_VECTOR(OFS_PARM2);
	float *rgb = G_VECTOR(OFS_PARM3);
	float alpha = G_FLOAT(OFS_PARM4);
	float flag = G_FLOAT(OFS_PARM5);

	if (Draw_ImageColours)
		Draw_ImageColours(rgb[0], rgb[1], rgb[2], alpha);
	if (Draw_Image)
		Draw_Image(pos[0], pos[1], size[0], size[1], 0, 0, 1, 1, p);

	G_FLOAT(OFS_RETURN) = 1;
}
//float	drawfill(vector position, vector size, vector rgb, float alpha, float flag) = #457;
void PF_CL_drawfill (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float *pos = G_VECTOR(OFS_PARM0);
	float *size = G_VECTOR(OFS_PARM1);
	float *rgb = G_VECTOR(OFS_PARM2);
	float alpha = G_FLOAT(OFS_PARM3);
#ifdef RGLQUAKE
	if (qrenderer == QR_OPENGL)
	{
		glColor4f(rgb[0], rgb[1], rgb[2], alpha);

		glDisable(GL_TEXTURE_2D);

		glBegin(GL_QUADS);
		glVertex2f(pos[0],			pos[1]);
		glVertex2f(pos[0]+size[0],	pos[1]);
		glVertex2f(pos[0]+size[0],	pos[1]+size[1]);
		glVertex2f(pos[0],			pos[1]+size[1]);
		glEnd();

		glEnable(GL_TEXTURE_2D);
	}
#endif
	G_FLOAT(OFS_RETURN) = 1;
}
//void	drawsetcliparea(float x, float y, float width, float height) = #458;
void PF_CL_drawsetcliparea (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
		G_FLOAT(OFS_RETURN) = 1;
}
//void	drawresetcliparea(void) = #459;
void PF_CL_drawresetcliparea (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
		G_FLOAT(OFS_RETURN) = 1;
}
//vector  drawgetimagesize(string pic) = #460;
void PF_CL_drawgetimagesize (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *picname = PR_GetStringOfs(prinst, OFS_PARM0);
	qpic_t *p = Draw_SafeCachePic(picname);

	float *ret = G_VECTOR(OFS_RETURN);

	if (p)
	{
		ret[0] = p->width;
		ret[1] = p->height;
		ret[2] = 0;
	}
	else
	{
		ret[0] = 0;
		ret[1] = 0;
		ret[2] = 0;
	}
}

//void	setkeydest(float dest) 	= #601;
void PF_setkeydest (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	switch((int)G_FLOAT(OFS_PARM0))
	{
	case 0:
		// key_game
		key_dest = key_game;
		break;
	case 2:
		// key_menu
		key_dest = key_menu;
		m_state = m_menu_dat;
		break;
	case 1:
		// key_message
		// key_dest = key_message
		// break;
	default:
		PR_BIError (prinst, "PF_setkeydest: wrong destination %i !\n",(int)G_FLOAT(OFS_PARM0));
	}
}
//float	getkeydest(void)	= #602;
void PF_getkeydest (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	switch(key_dest)
	{
	case key_game:
		G_FLOAT(OFS_RETURN) = 0;
		break;
	case key_menu:
		if (m_state == m_menu_dat)
			G_FLOAT(OFS_RETURN) = 2;
		else
			G_FLOAT(OFS_RETURN) = 3;
		break;
	case 1:
		// key_message
		// key_dest = key_message
		// break;
	default:
		G_FLOAT(OFS_RETURN) = 3;
	}
}

//void	setmousetarget(float trg) = #603;
void PF_setmousetarget (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	extern int mouseusedforgui;
	switch ((int)G_FLOAT(OFS_PARM0))
	{
	case 1:
		mouseusedforgui = true;
		break;
	case 2:
		mouseusedforgui = false;
		break;
	default:
		PR_BIError(prinst, "PF_setmousetarget: not a valid destination\n");
	}
}

//float	getmousetarget(void)	  = #604;
void PF_getmousetarget (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
}

int MP_TranslateDPtoFTECodes(int code);
//string	keynumtostring(float keynum) = #609;
void PF_CL_keynumtostring (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int code = G_FLOAT(OFS_PARM0);
	char *keyname = PF_TempStr();

	code = MP_TranslateDPtoFTECodes (code);

	strcpy(keyname, Key_KeynumToString(code));
	RETURN_SSTRING(keyname);
}

int MP_TranslateDPtoFTECodes(int code);
//string	findkeysforcommand(string command) = #610;
void PF_CL_findkeysforcommand (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *cmdname = PR_GetStringOfs(prinst, OFS_PARM0);
	int keynums[2];
	char *keyname = PF_TempStr();

	M_FindKeysForCommand(cmdname, keynums);

	keyname[0] = '\0';

	strcat (keyname, va(" \'%i\'", MP_TranslateFTEtoDPCodes(keynums[0])));
	strcat (keyname, va(" \'%i\'", MP_TranslateFTEtoDPCodes(keynums[1])));

	RETURN_SSTRING(keyname);
}

//vector	getmousepos(void)  	= #66;
void PF_getmousepos (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	float *ret = G_VECTOR(OFS_RETURN);
	extern int mousemove_x, mousemove_y;

	ret[0] = mousemove_x;
	ret[1] = mousemove_y;

	mousemove_x=0;
	mousemove_y=0;

/*	ret[0] = mousecursor_x;
	ret[1] = mousecursor_y;*/
	ret[2] = 0;
}


void PF_Remove_ (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	void *ed;
	
	ed = G_EDICT(prinst, OFS_PARM0);
/*
	if (ed->isfree)
	{
		Con_DPrintf("Tried removing free entity\n");
		return;
	}
*/
	ED_Free (prinst, ed);
}

static void PF_CopyEntity (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	void *in, *out;

	in = G_EDICT(prinst, OFS_PARM0);
	out = G_EDICT(prinst, OFS_PARM1);

	memcpy((char*)out+prinst->parms->edictsize, (char*)in+prinst->parms->edictsize, menuentsize-prinst->parms->edictsize);
}

void PF_gethostcachevalue (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	#pragma message ("PF_gethostcachevalue: stub")
	G_FLOAT(OFS_RETURN) = 0;
}

void PF_gethostcachestring (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	#pragma message ("PF_gethostcachestring: stub")
	G_INT(OFS_RETURN) = 0;
}

void PF_localsound (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	char *soundname = PR_GetStringOfs(prinst, OFS_PARM0);
	S_LocalSound (soundname);
}

#define skip1 PF_Fixme,
#define skip5 skip1 skip1 skip1 skip1 skip1
#define skip10 skip5 skip5
#define skip50 skip10 skip10 skip10 skip10 skip10
#define skip100 skip50 skip50

void PF_menu_checkextension (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	//yeah, this is a stub... not sure what form extex
	G_FLOAT(OFS_RETURN) = 0;
}

void PF_gettime (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = *prinst->parms->gametime;
}

void PF_CL_precache_file (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
}

//entity	findchainstring(.string _field, string match) = #26;
void PF_menu_findchain (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int i, f;
	char *s, *t;
	edict_t *ent, *chain;	//note, all edicts share the common header, but don't use it's fields!
	eval_t *val;

	chain = (edict_t *) *prinst->parms->sv_edicts;

	f = G_INT(OFS_PARM0)+prinst->fieldadjust;
	f += prinst->parms->edictsize/4;
	s = PR_GetStringOfs(prinst, OFS_PARM1);

	for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
	{
		ent = EDICT_NUM(prinst, i);
		if (ent->isfree)
			continue;
		t = *(string_t *)&((float*)ent)[f] + prinst->stringtable;
		if (!t)
			continue;
		if (strcmp(t, s))
			continue;

		val = prinst->GetEdictFieldValue(prinst, ent, "chain", NULL);
		if (val)
			val->edict = EDICT_TO_PROG(prinst, chain);
		chain = ent;
	}

	RETURN_EDICT(prinst, chain);
}
//entity	findchainfloat(.float _field, float match) = #27;
void PF_menu_findchainfloat (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	int i, f;
	float s;
	edict_t	*ent, *chain;	//note, all edicts share the common header, but don't use it's fields!
	eval_t *val;

	chain = (edict_t *) *prinst->parms->sv_edicts;

	f = G_INT(OFS_PARM0)+prinst->fieldadjust;
	f += prinst->parms->edictsize/4;
	s = G_FLOAT(OFS_PARM1);

	for (i = 1; i < *prinst->parms->sv_num_edicts; i++)
	{
		ent = EDICT_NUM(prinst, i);
		if (ent->isfree)
			continue;
		if (((float *)ent)[f] != s)
			continue;

		val = prinst->GetEdictFieldValue(prinst, ent, "chain", NULL);
		if (val)
			val->edict = EDICT_TO_PROG(prinst, chain);
		chain = ent;
	}

	RETURN_EDICT(prinst, chain);
}

void PF_etof(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
	G_FLOAT(OFS_RETURN) = G_EDICTNUM(prinst, OFS_PARM0);
}

builtin_t menu_builtins[] = {
//0
	PF_Fixme,
	PF_menu_checkextension,				//void 	checkextension(string ext) = #1;
	PF_error,
	PF_nonfatalobjerror,
	PF_print,
	skip1				//void 	bprint(string text,...)	= #5;
	skip1				//void	sprint(float clientnum, string text,...) = #6;
	skip1				//void 	centerprint(string text,...) = #7;
	PF_normalize,		//vector	normalize(vector v) 	= #8;
	PF_vlen,			//float 	vlen(vector v)			= #9;
//10
	PF_vectoyaw,//10		//float  	vectoyaw(vector v)		= #10;
	PF_vectoangles,//11		//vector 	vectoangles(vector v)	= #11;
	PF_random,//12
	PF_localcmd,//13
	PF_cvar,//14
	PF_cvar_set,//15
	PF_developerprint,//16
	PF_ftos,//17
	PF_fabs,//18
	PF_vtos,//19

	PF_etos,//20
	PF_stof,//21
	PF_Spawn,//22
	PF_Remove_,//23
	PF_FindString,//24
	PF_FindFloat,//25
	PF_menu_findchain,//26			//entity	findchainstring(.string _field, string match) = #26;
	PF_menu_findchainfloat,//27		//entity	findchainfloat(.float _field, float match) = #27;
	PF_CL_precache_file,//28
	PF_CL_precache_sound,//29

//30
	PF_coredump,				//void	coredump(void) = #30;
	PF_traceon,				//void	traceon(void) = #31;
	PF_traceoff,				//void	traceoff(void) = #32;
	PF_eprint,				//void	eprint(entity e)  = #33;
	PF_rint,
	PF_floor,
	PF_ceil,
	PF_nextent,
	PF_Sin,
	PF_Cos,
//40
	PF_Sqrt,
	PF_randomvec,
	PF_registercvar,
	PF_min,
	PF_max,
	PF_bound,
	PF_pow,
	PF_CopyEntity,
	PF_fopen,
	PF_fclose,
//50
	PF_fgets,
	PF_fputs,
	PF_strlen,
	PF_strcat,
	PF_substring,
	PF_stov,
	PF_dupstring,
	PF_forgetstring,
	PF_Tokenize,
	PF_ArgV,
//60
	PF_isserver,
	skip1						//float	clientcount(void)  = #61;
	PF_clientstate,
	skip1						//void	clientcommand(float client, string s)  = #63;
	skip1						//void	changelevel(string map)  = #64;
	PF_localsound,
	PF_getmousepos,
	PF_gettime,
	PF_loadfromdata,
	PF_loadfromfile,
//70
	PF_mod,//0
	PF_cvar_string,//1
	PF_Fixme,//2				//void	crash(void)	= #72;
	PF_Fixme,//3				//void	stackdump(void) = #73;
	PF_search_begin,//4
	PF_search_end,//5
	PF_search_getsize ,//6
	PF_search_getfilename,//7
	PF_chr2str,//8
	PF_etof,//9				//float 	etof(entity ent) = #79;
//80
	skip10
//90
	skip10
//100
	skip100
//200
	skip100
//300
	skip100
//400
	skip50
//450
	PF_Fixme,//0
	PF_CL_is_cached_pic,//1
	PF_CL_precache_pic,//2
	PF_CL_free_pic,//3
	PF_CL_drawcharacter,//4
	PF_CL_drawstring,//5
	PF_CL_drawpic,//6
	PF_CL_drawfill,//7
	PF_CL_drawsetcliparea,//8
	PF_CL_drawresetcliparea,//9

//460
	PF_CL_drawgetimagesize,//10
	skip1
	skip1
	skip1
	skip1
	skip1
	skip1
	skip1
	skip1
	skip1
//470
	skip10
//480
	skip10
//490
	skip10
//500
	skip100
//600
	skip1
	PF_setkeydest,
	PF_getkeydest,
	PF_setmousetarget,
	PF_getmousetarget,
	PF_callfunction,
	skip1				//void	writetofile(float fhandle, entity ent) = #606;
	PF_isfunction,
	PF_getresolution,
	PF_CL_keynumtostring,
	PF_CL_findkeysforcommand,
	PF_gethostcachevalue,
	PF_gethostcachestring,
	PF_Fixme			//void 	parseentitydata(entity ent, string data) = #613;
};
int menu_numbuiltins = sizeof(menu_builtins)/sizeof(menu_builtins[0]);




void M_Init_Internal (void);
void M_DeInit_Internal (void);

int inmenuprogs;
progfuncs_t *menuprogs;
progparms_t menuprogparms;
menuedict_t *menu_edicts;
int num_menu_edicts;

func_t mp_init_function;
func_t mp_shutdown_function;
func_t mp_draw_function;
func_t mp_keydown_function;
func_t mp_keyup_function;
func_t mp_toggle_function;

float *mp_time;

jmp_buf mp_abort;


void MP_Shutdown (void)
{
	extern int mouseusedforgui;
	func_t temp;
	if (!menuprogs)
		return;

	temp = mp_shutdown_function;
	mp_shutdown_function = 0;
	if (temp && !inmenuprogs)
		PR_ExecuteProgram(menuprogs, temp);

	PF_fclose_progs(menuprogs);
	search_close_progs(menuprogs, true);

	CloseProgs(menuprogs);
	menuprogs = NULL;

	key_dest = key_game;
	m_state = 0;

	mouseusedforgui = false;

	if (inmenuprogs)	//something in the menu caused the problem, so...
	{
		inmenuprogs = 0;
		longjmp(mp_abort, 1);
	}
}

int COM_FileSize(char *path);
pbool QC_WriteFile(char *name, void *data, int len);
void *VARGS PR_Malloc(int size);	//these functions should be tracked by the library reliably, so there should be no need to track them ourselves.
void VARGS PR_Free(void *mem);

//Any menu builtin error or anything like that will come here.
void VARGS Menu_Abort (char *format, ...)
{
	va_list		argptr;
	char		string[1024];

	va_start (argptr, format);
	_vsnprintf (string,sizeof(string)-1, format,argptr);
	va_end (argptr);

	Con_Printf("Menu_Abort: %s\nShutting down menu.dat\n", string);

	MP_Shutdown();
}

double  menutime;
void MP_Init (void)
{
	if (!qrenderer)
	{
		return;
	}

	M_DeInit_Internal();


	menuprogparms.progsversion = PROGSTRUCT_VERSION;
	menuprogparms.ReadFile = COM_LoadStackFile;//char *(*ReadFile) (char *fname, void *buffer, int *len);
	menuprogparms.FileSize = COM_FileSize;//int (*FileSize) (char *fname);	//-1 if file does not exist
	menuprogparms.WriteFile = QC_WriteFile;//bool (*WriteFile) (char *name, void *data, int len);
	menuprogparms.printf = (void *)Con_Printf;//Con_Printf;//void (*printf) (char *, ...);
	menuprogparms.Sys_Error = Sys_Error;
	menuprogparms.Abort = Menu_Abort;
	menuprogparms.edictsize = sizeof(menuedict_t);

	menuprogparms.entspawn = NULL;//void (*entspawn) (struct edict_s *ent);	//ent has been spawned, but may not have all the extra variables (that may need to be set) set
	menuprogparms.entcanfree = NULL;//bool (*entcanfree) (struct edict_s *ent);	//return true to stop ent from being freed
	menuprogparms.stateop = NULL;//StateOp;//void (*stateop) (float var, func_t func);
	menuprogparms.cstateop = NULL;//CStateOp;
	menuprogparms.cwstateop = NULL;//CWStateOp;
	menuprogparms.thinktimeop = NULL;//ThinkTimeOp;

	//used when loading a game
	menuprogparms.builtinsfor = NULL;//builtin_t *(*builtinsfor) (int num);	//must return a pointer to the builtins that were used before the state was saved.
	menuprogparms.loadcompleate = NULL;//void (*loadcompleate) (int edictsize);	//notification to reset any pointers.

	menuprogparms.memalloc = PR_Malloc;//void *(*memalloc) (int size);	//small string allocation	malloced and freed randomly
	menuprogparms.memfree = PR_Free;//void (*memfree) (void * mem);


	menuprogparms.globalbuiltins = menu_builtins;//builtin_t *globalbuiltins;	//these are available to all progs
	menuprogparms.numglobalbuiltins = menu_numbuiltins;

	menuprogparms.autocompile = PR_COMPILECHANGED;//enum {PR_NOCOMPILE, PR_COMPILENEXIST, PR_COMPILECHANGED, PR_COMPILEALWAYS} autocompile;

	menuprogparms.gametime = &menutime;

	menuprogparms.sv_edicts = (edict_t **)&menu_edicts;
	menuprogparms.sv_num_edicts = &num_menu_edicts;

	menuprogparms.useeditor = NULL;//sorry... QCEditor;//void (*useeditor) (char *filename, int line, int nump, char **parms);

	menutime = Sys_DoubleTime();
	if (!menuprogs)
	{
		menuprogs = InitProgs(&menuprogparms);
		PR_Configure(menuprogs, NULL, -1, 1);
		if (PR_LoadProgs(menuprogs, "menu.dat", 10020, NULL, 0) < 0) //no per-progs builtins.
		{
			//failed to load or something
			M_Init_Internal();
			return;
		}
		if (setjmp(mp_abort))
		{
			M_Init_Internal();
			return;
		}
		inmenuprogs++;

		mp_time = (float*)PR_FindGlobal(menuprogs, "time", 0);
		if (mp_time)
			*mp_time = Sys_DoubleTime();

		menuentsize = PR_InitEnts(menuprogs, 512);


		//'world' edict
		EDICT_NUM(menuprogs, 0)->readonly = true;
		EDICT_NUM(menuprogs, 0)->isfree = false;


		mp_init_function = PR_FindFunction(menuprogs, "m_init", PR_ANY);
		mp_shutdown_function = PR_FindFunction(menuprogs, "m_shutdown", PR_ANY);
		mp_draw_function = PR_FindFunction(menuprogs, "m_draw", PR_ANY);
		mp_keydown_function = PR_FindFunction(menuprogs, "m_keydown", PR_ANY);
		mp_keyup_function = PR_FindFunction(menuprogs, "m_keyup", PR_ANY);
		mp_toggle_function = PR_FindFunction(menuprogs, "m_toggle", PR_ANY);

		if (mp_init_function)
			PR_ExecuteProgram(menuprogs, mp_init_function);
		inmenuprogs--;
	}
}

void MP_Draw(void)
{
	if (setjmp(mp_abort))
		return;

#ifdef RGLQUAKE
	if (qrenderer == QR_OPENGL)
	{
		GL_TexEnv(GL_MODULATE);
		glDisable(GL_ALPHA_TEST);
		glEnable(GL_BLEND);
	}
#endif

	menutime = Sys_DoubleTime();
	if (mp_time)
		*mp_time = menutime;

	inmenuprogs++;
	if (mp_draw_function)
		PR_ExecuteProgram(menuprogs, mp_draw_function);
	inmenuprogs--;
}

int MP_TranslateFTEtoDPCodes(int code)
{
	switch(code)
	{
	case K_TAB:				return 9;
	case K_ENTER:			return 13;
	case K_ESCAPE:			return 27;
	case K_SPACE:			return 32;
	case K_BACKSPACE:		return 127;
	case K_UPARROW:			return 128;
	case K_DOWNARROW:		return 129;
	case K_LEFTARROW:		return 130;
	case K_RIGHTARROW:		return 131;
	case K_ALT:				return 132;
	case K_CTRL:			return 133;
	case K_SHIFT:			return 134;
	case K_F1:				return 135;
	case K_F2:				return 136;
	case K_F3:				return 137;
	case K_F4:				return 138;
	case K_F5:				return 139;
	case K_F6:				return 140;
	case K_F7:				return 141;
	case K_F8:				return 142;
	case K_F9:				return 143;
	case K_F10:				return 144;
	case K_F11:				return 145;
	case K_F12:				return 146;
	case K_INS:				return 147;
	case K_DEL:				return 148;
	case K_PGDN:			return 149;
	case K_PGUP:			return 150;
	case K_HOME:			return 151;
	case K_END:				return 152;
	case K_KP_HOME:			return 160;
	case K_KP_UPARROW:		return 161;
	case K_KP_PGUP:			return 162;
	case K_KP_LEFTARROW:	return 163;
	case K_KP_5:			return 164;
	case K_KP_RIGHTARROW:	return 165;
	case K_KP_END:			return 166;
	case K_KP_DOWNARROW:	return 167;
	case K_KP_PGDN:			return 168;
	case K_KP_ENTER:		return 169;
	case K_KP_INS:			return 170;
	case K_KP_DEL:			return 171;
	case K_KP_SLASH:		return 172;
	case K_KP_MINUS:		return 173;
	case K_KP_PLUS:			return 174;
	case K_PAUSE:			return 255;
	case K_JOY1:			return 768;
	case K_JOY2:			return 769;
	case K_JOY3:			return 770;
	case K_JOY4:			return 771;
	case K_AUX1:			return 772;
	case K_AUX2:			return 773;
	case K_AUX3:			return 774;
	case K_AUX4:			return 775;
	case K_AUX5:			return 776;
	case K_AUX6:			return 777;
	case K_AUX7:			return 778;
	case K_AUX8:			return 779;
	case K_AUX9:			return 780;
	case K_AUX10:			return 781;
	case K_AUX11:			return 782;
	case K_AUX12:			return 783;
	case K_AUX13:			return 784;
	case K_AUX14:			return 785;
	case K_AUX15:			return 786;
	case K_AUX16:			return 787;
	case K_AUX17:			return 788;
	case K_AUX18:			return 789;
	case K_AUX19:			return 790;
	case K_AUX20:			return 791;
	case K_AUX21:			return 792;
	case K_AUX22:			return 793;
	case K_AUX23:			return 794;
	case K_AUX24:			return 795;
	case K_AUX25:			return 796;
	case K_AUX26:			return 797;
	case K_AUX27:			return 798;
	case K_AUX28:			return 799;
	case K_AUX29:			return 800;
	case K_AUX30:			return 801;
	case K_AUX31:			return 802;
	case K_AUX32:			return 803;
	case K_MOUSE1:			return 512;
	case K_MOUSE2:			return 513;
	case K_MOUSE3:			return 514;
	case K_MOUSE4:			return 515;
	case K_MOUSE5:			return 516;
//	case K_MOUSE6:			return 517;
//	case K_MOUSE7:			return 518;
//	case K_MOUSE8:			return 519;
//	case K_MOUSE9:			return 520;
//	case K_MOUSE10:			return 521;
	case K_MWHEELDOWN:		return 515;//K_MOUSE4;
	case K_MWHEELUP:		return 516;//K_MOUSE5;
	default:				return code;
	}
}

int MP_TranslateDPtoFTECodes(int code)
{
	switch(code)
	{
	case 9:			return K_TAB;
	case 13:		return K_ENTER;
	case 27:		return K_ESCAPE;
	case 32:		return K_SPACE;
	case 127:		return K_BACKSPACE;
	case 128:		return K_UPARROW;
	case 129:		return K_DOWNARROW;
	case 130:		return K_LEFTARROW;
	case 131:		return K_RIGHTARROW;
	case 132:		return K_ALT;
	case 133:		return K_CTRL;
	case 134:		return K_SHIFT;
	case 135:		return K_F1;
	case 136:		return K_F2;
	case 137:		return K_F3;
	case 138:		return K_F4;
	case 139:		return K_F5;
	case 140:		return K_F6;
	case 141:		return K_F7;
	case 142:		return K_F8;
	case 143:		return K_F9;
	case 144:		return K_F10;
	case 145:		return K_F11;
	case 146:		return K_F12;
	case 147:		return K_INS;
	case 148:		return K_DEL;
	case 149:		return K_PGDN;
	case 150:		return K_PGUP;
	case 151:		return K_HOME;
	case 152:		return K_END;
	case 160:		return K_KP_HOME;
	case 161:		return K_KP_UPARROW;
	case 162:		return K_KP_PGUP;
	case 163:		return K_KP_LEFTARROW;
	case 164:		return K_KP_5;
	case 165:		return K_KP_RIGHTARROW;
	case 166:		return K_KP_END;
	case 167:		return K_KP_DOWNARROW;
	case 168:		return K_KP_PGDN;
	case 169:		return K_KP_ENTER;
	case 170:		return K_KP_INS;
	case 171:		return K_KP_DEL;
	case 172:		return K_KP_SLASH;
	case 173:		return K_KP_MINUS;
	case 174:		return K_KP_PLUS;
	case 255:		return K_PAUSE;

	case 768:		return K_JOY1;
	case 769:		return K_JOY2;
	case 770:		return K_JOY3;
	case 771:		return K_JOY4;
	case 772:		return K_AUX1;
	case 773:		return K_AUX2;
	case 774:		return K_AUX3;
	case 775:		return K_AUX4;
	case 776:		return K_AUX5;
	case 777:		return K_AUX6;
	case 778:		return K_AUX7;
	case 779:		return K_AUX8;
	case 780:		return K_AUX9;
	case 781:		return K_AUX10;
	case 782:		return K_AUX11;
	case 783:		return K_AUX12;
	case 784:		return K_AUX13;
	case 785:		return K_AUX14;
	case 786:		return K_AUX15;
	case 787:		return K_AUX16;
	case 788:		return K_AUX17;
	case 789:		return K_AUX18;
	case 790:		return K_AUX19;
	case 791:		return K_AUX20;
	case 792:		return K_AUX21;
	case 793:		return K_AUX22;
	case 794:		return K_AUX23;
	case 795:		return K_AUX24;
	case 796:		return K_AUX25;
	case 797:		return K_AUX26;
	case 798:		return K_AUX27;
	case 799:		return K_AUX28;
	case 800:		return K_AUX29;
	case 801:		return K_AUX30;
	case 802:		return K_AUX31;
	case 803:		return K_AUX32;
	case 512:		return K_MOUSE1;
	case 513:		return K_MOUSE2;
	case 514:		return K_MOUSE3;
//	case 515:		return K_MOUSE4;
//	case 516:		return K_MOUSE5;
	case 517:		return K_MOUSE6;
	case 518:		return K_MOUSE7;
	case 519:		return K_MOUSE8;
//	case 520:		return K_MOUSE9;
//	case 521:		return K_MOUSE10;
	case 515:		return K_MWHEELDOWN;//K_MOUSE4;
	case 516:		return K_MWHEELUP;//K_MOUSE5;
	default:		return code;
	}
}

void MP_Keydown(int key)
{
	if (setjmp(mp_abort))
		return;

	if (key == 'c')
	{
		extern keydown[];
		if (keydown[K_CTRL])
		{
			MP_Shutdown();
			return;
		}
	}

	menutime = Sys_DoubleTime();
	if (mp_time)
		*mp_time = menutime;

	inmenuprogs++;
	if (mp_keydown_function)
	{
		void *pr_globals = PR_globals(menuprogs, PR_CURRENT);
		G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoDPCodes(key);
		if (G_FLOAT(OFS_PARM0) > 127)
			G_FLOAT(OFS_PARM1) = 0;
		else
			G_FLOAT(OFS_PARM1) = G_FLOAT(OFS_PARM0);
		PR_ExecuteProgram(menuprogs, mp_keydown_function);
	}
	inmenuprogs--;
}

void MP_Keyup(int key)
{
	if (setjmp(mp_abort))
		return;

	menutime = Sys_DoubleTime();
	if (mp_time)
		*mp_time = menutime;

	inmenuprogs++;
	if (mp_keyup_function)
	{
		void *pr_globals = PR_globals(menuprogs, PR_CURRENT);
		G_FLOAT(OFS_PARM0) = MP_TranslateFTEtoDPCodes(key);
		if (G_FLOAT(OFS_PARM0) > 127)
			G_FLOAT(OFS_PARM1) = 0;
		else
			G_FLOAT(OFS_PARM1) = G_FLOAT(OFS_PARM0);
		PR_ExecuteProgram(menuprogs, mp_keyup_function);
	}
	inmenuprogs--;
}

qboolean MP_Toggle(void)
{
	if (!menuprogs)
		return false;

	if (setjmp(mp_abort))
		return false;

	menutime = Sys_DoubleTime();
	if (mp_time)
		*mp_time = menutime;

	inmenuprogs++;
	if (mp_toggle_function)
		PR_ExecuteProgram(menuprogs, mp_toggle_function);
	inmenuprogs--;

	return true;
}
#endif