]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - prvm_cmds.c
Fixed findkeysforcommand hopefully.
[xonotic/darkplaces.git] / prvm_cmds.c
index 4b0afb0d7efbc72015824ad4eab01dd345a162bb..f6a92d2b640bc5d47f782e4a3ffd32555c31e639 100644 (file)
@@ -1,7 +1,7 @@
 // AK
 // Basically every vm builtin cmd should be in here.
-// All 3 builtin list and extension lists can be found here
-// cause large (I think they will) are from pr_cmds the same copyright like in pr_cms
+// All 3 builtin and extension lists can be found here
+// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds
 // also applies here
 
 
@@ -82,6 +82,20 @@ float        clientstate()
                changelevel(string map)
                localsound(string sample)
 vector getmousepos()
+float  gettime()
+               loadfromdata(string data)
+               loadfromfile(string file)
+float  mod(float val, float m)
+const string   str_cvar (string)
+               crash()
+               stackdump()
+               
+float  search_begin(string pattern, float caseinsensitive, float quiet)
+void   search_end(float handle)
+float  search_getsize(float handle)
+string search_getfilename(float handle, float num)
+
+string chr(float ascii)
                
 perhaps only : Menu : WriteMsg 
 ===============================
@@ -105,7 +119,10 @@ float      drawcharacter(vector position, float character, vector scale, vector rgb,
 float  drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
 float  drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
 float  drawfill(vector position, vector size, vector rgb, float alpha, float flag)
-
+               drawsetcliparea(float x, float y, float width, float height)
+               drawresetcliparea()
+vector getimagesize(string pic)
+               
 
 ==============================================================================
 menu cmd list:
@@ -115,6 +132,15 @@ menu cmd list:
 float  getkeydest
                setmousetarget(float target)
 float  getmousetarget(void)
+
+               callfunction(...,string function_name)
+               writetofile(float fhandle, entity ent)
+float  isfunction(string function_name)
+vector getresolution(float number)
+string keynumtostring(float keynum)
+string findkeysforcommand(string command)
+
+
 */
 
 #include "quakedef.h"
@@ -147,9 +173,9 @@ mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
 
 // temp string handling
 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
-#define STRINGTEMP_BUFFERS 16
-#define STRINGTEMP_LENGTH 4096
-static char vm_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
+#define VM_STRINGTEMP_BUFFERS 16
+#define VM_STRINGTEMP_LENGTH 4096
+static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
 static int vm_string_tempindex = 0;
 
 // qc cvar 
@@ -164,11 +190,18 @@ int vm_currentqc_cvar;
 
 qfile_t *vm_files[MAX_PRVMFILES];
 
+// qc fs search handling
+#define MAX_VMSEARCHES 128
+#define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
+#define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
+
+fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
+
 static char *VM_GetTempString(void)
 {
        char *s;
        s = vm_string_temp[vm_string_tempindex];
-       vm_string_tempindex = (vm_string_tempindex + 1) % STRINGTEMP_BUFFERS;
+       vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
        return s;
 }
 
@@ -252,7 +285,7 @@ error(value)
 void VM_error (void)
 {
        prvm_edict_t    *ed;
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
@@ -278,7 +311,7 @@ objerror(value)
 void VM_objerror (void)
 {
        prvm_edict_t    *ed;
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
@@ -305,10 +338,10 @@ print(string)
 */
 void VM_print (void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        VM_VarString(0, string, sizeof(string));
-       Con_Print(string);
+       Con_Printf(string);
 }
 
 /*
@@ -322,7 +355,7 @@ bprint(...[string])
 */
 void VM_bprint (void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        if(!sv.active)
        {
@@ -347,7 +380,7 @@ void VM_sprint (void)
 {
        client_t        *client;
        int                     clientnum;
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        //find client for this entity
        clientnum = PRVM_G_FLOAT(OFS_PARM0);
@@ -376,7 +409,7 @@ centerprint(clientent, value)
 */
 void VM_centerprint (void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        VM_VarString(0, string, sizeof(string));
        SCR_CenterPrint(string);
@@ -650,6 +683,35 @@ void VM_cvar (void)
        PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
 }
 
+/*
+=================
+VM_str_cvar
+
+const string   str_cvar (string)
+=================
+*/
+void VM_str_cvar(void) 
+{
+       char *out, *name;
+       const char *cvar_string;
+       VM_SAFEPARMCOUNT(1,VM_str_cvar);
+
+       name = PRVM_G_STRING(OFS_PARM0);
+
+       if(!name)
+               PRVM_ERROR("VM_str_cvar: %s: null string\n", PRVM_NAME);
+
+       VM_CheckEmptyString(name);
+
+       out = VM_GetTempString(); 
+
+       cvar_string = Cvar_VariableString(name);
+       
+       strcpy(out, cvar_string);
+
+       PRVM_G_INT(OFS_PARM0) = PRVM_SetString(out);
+}
+
 /*
 =================
 VM_cvar_set
@@ -673,7 +735,7 @@ dprint(...[string])
 */
 void VM_dprint (void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
        if (developer.integer)
        {
                VM_VarString(0, string, sizeof(string));
@@ -771,7 +833,7 @@ float stof(...[string])
 */
 void VM_stof(void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
        VM_VarString(0, string, sizeof(string));
        PRVM_G_FLOAT(OFS_RETURN) = atof(string);
 }
@@ -859,7 +921,7 @@ void VM_find (void)
                }
        }
 
-       VM_RETURN_EDICT(sv.edicts);
+       VM_RETURN_EDICT(prog->edicts);
 }
 
 /*
@@ -1066,7 +1128,39 @@ void VM_coredump (void)
 {
        VM_SAFEPARMCOUNT(0,VM_coredump);
 
-       PRVM_ED_PrintEdicts_f ();
+       Cbuf_AddText("prvm_edicts ");
+       Cbuf_AddText(PRVM_NAME);
+       Cbuf_AddText("\n");
+}
+
+/*
+=========
+VM_stackdump
+
+stackdump()
+=========
+*/
+void PRVM_StackTrace(void);
+void VM_stackdump (void)
+{
+       VM_SAFEPARMCOUNT(0, VM_stackdump);
+
+       PRVM_StackTrace();
+}
+
+/*
+=========
+VM_crash
+
+crash()
+=========
+*/
+
+void VM_crash(void) 
+{
+       VM_SAFEPARMCOUNT(0, VM_crash);
+
+       PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
 }
 
 /*
@@ -1224,8 +1318,8 @@ sizebuf_t *VM_WriteDest (void)
 
        case MSG_ONE:
                destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
-               if (!sv.active  || destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
-                       PRVM_ERROR("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
+               if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
+                       PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
 
                return &svs.clients[destclient].message;
 
@@ -1638,7 +1732,7 @@ void VM_fopen(void)
        // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
        if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
        {
-               Con_Printf("VM_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
+               Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
                PRVM_G_FLOAT(OFS_RETURN) = -4;
                return;
        }
@@ -1689,7 +1783,7 @@ string    fgets(float fhandle)
 void VM_fgets(void)
 {
        int c, end;
-       static char string[STRINGTEMP_LENGTH];
+       static char string[VM_STRINGTEMP_LENGTH];
        int filenum;
 
        VM_SAFEPARMCOUNT(1,VM_fgets);
@@ -1711,7 +1805,7 @@ void VM_fgets(void)
                c = FS_Getc(VM_FILES[filenum]);
                if (c == '\r' || c == '\n' || c < 0)
                        break;
-               if (end < STRINGTEMP_LENGTH - 1)
+               if (end < VM_STRINGTEMP_LENGTH - 1)
                        string[end++] = c;
        }
        string[end] = 0;
@@ -1737,7 +1831,7 @@ fputs(float fhandle, string s)
 void VM_fputs(void)
 {
        int stringlength;
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
        int filenum;
 
        VM_SAFEPARMCOUNT(2,VM_fputs);
@@ -1795,11 +1889,11 @@ void VM_strcat(void)
 {
        char *s;
 
-       if(prog->argc <= 2) 
+       if(prog->argc < 2) 
                PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
        
        s = VM_GetTempString();
-       VM_VarString(0, s, STRINGTEMP_LENGTH);
+       VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
        PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
 }
 
@@ -1826,7 +1920,7 @@ void VM_substring(void)
        if (!s)
                s = "";
        for (i = 0;i < start && *s;i++, s++);
-       for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
+       for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
                string[i] = *s;
        string[i] = 0;
        PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
@@ -1842,7 +1936,7 @@ vector    stov(string s)
 //vector(string s) stov = #117; // returns vector value from a string
 void VM_stov(void)
 {
-       char string[STRINGTEMP_LENGTH];
+       char string[VM_STRINGTEMP_LENGTH];
 
        VM_SAFEPARMCOUNT(1,VM_stov);
 
@@ -2065,6 +2159,301 @@ void VM_clientstate(void)
        PRVM_G_FLOAT(OFS_RETURN) = cls.state;
 }
 
+/*
+=========
+VM_getostype
+
+float  getostype(void)
+=========
+*/ // not used at the moment -> not included in the common list
+void VM_getostype(void)
+{
+       VM_SAFEPARMCOUNT(0,VM_getostype);
+
+       /*
+       OS_WINDOWS
+       OS_LINUX
+       OS_MAC - not supported
+       */
+
+#ifdef _WIN32
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+#elif defined _MAC
+       PRVM_G_FLOAT(OFS_RETURN) = 2;
+#else
+       PRVM_G_FLOAT(OFS_RETURN) = 1;
+#endif
+}
+
+/*
+=========
+VM_getmousepos
+
+vector getmousepos()
+=========
+*/
+void VM_getmousepos(void)
+{
+
+       VM_SAFEPARMCOUNT(0,VM_getmousepos);
+       
+       PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
+       PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
+       PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
+}
+
+/*
+=========
+VM_gettime
+
+float  gettime(void)
+=========
+*/
+void VM_gettime(void)
+{
+       VM_SAFEPARMCOUNT(0,VM_gettime);
+
+       PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
+}
+
+/*
+=========
+VM_loadfromdata
+
+loadfromdata(string data)
+=========
+*/
+void VM_loadfromdata(void)
+{
+       VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
+
+       PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
+}
+
+/*
+=========
+VM_loadfromfile
+
+loadfromfile(string file)
+=========
+*/
+void VM_loadfromfile(void)
+{
+       char *filename;
+       qbyte *data;
+       
+       VM_SAFEPARMCOUNT(1,VM_loadfromfile);
+       
+       filename = PRVM_G_STRING(OFS_PARM0);
+       // .. is parent directory on many platforms
+       // / is parent directory on Amiga
+       // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
+       // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
+       if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
+       {
+               Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
+               PRVM_G_FLOAT(OFS_RETURN) = -4;
+               return;
+       }
+
+       // not conform with VM_fopen
+       data = FS_LoadFile(filename, false);
+       if (data == NULL)
+               PRVM_G_FLOAT(OFS_RETURN) = -1;
+       
+       PRVM_ED_LoadFromFile(data);
+
+       if(data)
+               Mem_Free(data);
+}
+
+
+/*
+=========
+VM_modulo
+
+float  mod(float val, float m)
+=========
+*/
+void VM_modulo(void)
+{
+       int val, m;
+       VM_SAFEPARMCOUNT(2,VM_module);
+
+       val = (int) PRVM_G_FLOAT(OFS_PARM0);
+       m       = (int) PRVM_G_FLOAT(OFS_PARM1);
+
+       PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
+}
+
+void VM_Search_Init(void)
+{
+       memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
+}
+
+void VM_Search_Reset(void)
+{
+       int i;
+       // reset the fssearch list
+       for(i = 0; i < MAX_VMSEARCHES; i++)
+               if(VM_SEARCHLIST[i])
+                       FS_FreeSearch(VM_SEARCHLIST[i]);
+       memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
+}
+
+/*
+=========
+VM_search_begin
+
+float search_begin(string pattern, float caseinsensitive, float quiet)
+=========
+*/
+void VM_search_begin(void)
+{
+       int handle;
+       char *pattern;
+       int caseinsens, quiet;
+
+       VM_SAFEPARMCOUNT(3, VM_search_begin);
+
+       pattern = PRVM_G_STRING(OFS_PARM0);
+
+       VM_CheckEmptyString(pattern);
+
+       caseinsens = PRVM_G_FLOAT(OFS_PARM1);
+       quiet = PRVM_G_FLOAT(OFS_PARM2);
+       
+       for(handle = 0; handle < MAX_VMSEARCHES; handle++)
+               if(!VM_SEARCHLIST[handle])
+                       break;
+
+       if(handle >= MAX_VMSEARCHES)
+       {
+               Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
+               PRVM_G_FLOAT(OFS_RETURN) = -2;
+               return;
+       }
+
+       if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
+               PRVM_G_FLOAT(OFS_RETURN) = -1;
+       else
+               PRVM_G_FLOAT(OFS_RETURN) = handle;
+}
+
+/*
+=========
+VM_search_end
+
+void   search_end(float handle)
+=========
+*/
+void VM_search_end(void)
+{
+       int handle;
+       VM_SAFEPARMCOUNT(1, VM_search_end);
+
+       handle = PRVM_G_FLOAT(OFS_PARM0);
+       
+       if(handle < 0 || handle >= MAX_VMSEARCHES)
+       {
+               Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               return;
+       }
+       if(VM_SEARCHLIST[handle] == NULL)
+       {
+               Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
+               return;
+       }
+
+       FS_FreeSearch(VM_SEARCHLIST[handle]);
+       VM_SEARCHLIST[handle] = NULL;
+}
+
+/*
+=========
+VM_search_getsize
+
+float  search_getsize(float handle)
+=========
+*/
+void VM_search_getsize(void)
+{
+       int handle;
+       VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
+
+       handle = PRVM_G_FLOAT(OFS_PARM0);
+
+       if(handle < 0 || handle >= MAX_VMSEARCHES)
+       {
+               Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               return;
+       }
+       if(VM_SEARCHLIST[handle] == NULL)
+       {
+               Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
+               return;
+       }
+       
+       PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
+}
+
+/*
+=========
+VM_search_getfilename
+
+string search_getfilename(float handle, float num)
+=========
+*/
+void VM_search_getfilename(void)
+{
+       int handle, filenum;
+       char *tmp;
+       VM_SAFEPARMCOUNT(2, VM_search_getfilename);
+
+       handle = PRVM_G_FLOAT(OFS_PARM0);
+       filenum = PRVM_G_FLOAT(OFS_PARM1);
+
+       if(handle < 0 || handle >= MAX_VMSEARCHES)
+       {
+               Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
+               return;
+       }
+       if(VM_SEARCHLIST[handle] == NULL)
+       {
+               Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
+               return;
+       }
+       if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
+       {
+               Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
+               return;
+       }
+       
+       tmp = VM_GetTempString();
+       strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
+}
+
+/*
+=========
+VM_chr
+
+string chr(float ascii)
+=========
+*/
+void VM_chr(void)
+{
+       char *tmp;
+       VM_SAFEPARMCOUNT(1, VM_chr);
+
+       tmp = VM_GetTempString();
+       tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
+       tmp[1] = 0;
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
+}
+
 //=============================================================================
 // Draw builtins (client & menu)
 
@@ -2100,11 +2489,12 @@ void VM_precache_pic(void)
        PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
        
        if(!s)
-               PRVM_ERROR ("VM_precache_pic: %s: NULL\n");
+               PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
 
        VM_CheckEmptyString (s);
        
-       Draw_CachePic(s); 
+       if(!Draw_CachePic(s))
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetString(""); 
 }
 
 /*
@@ -2253,7 +2643,7 @@ void VM_drawpic(void)
 
        VM_CheckEmptyString (pic);
 
-       // is pic cached ?
+       // is pic cached ? no function yet for that
        if(!1)
        {
                Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
@@ -2316,31 +2706,79 @@ void VM_drawfill(void)
 
 /*
 =========
-VM_getmousepos
+VM_drawsetcliparea
 
-vector getmousepos()
+drawsetcliparea(float x, float y, float width, float height)
 =========
 */
-void VM_getmousepos(void)
+void VM_drawsetcliparea(void)
 {
+       float x,y,w,h;
+       VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
 
-       VM_SAFEPARMCOUNT(0,VM_getmousepos);
+       x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
+       y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
+       w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth  - x));
+       h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y)); 
+
+       DrawQ_SetClipArea(x,y,w,h);
+}
+
+/*
+=========
+VM_drawresetcliparea
+
+drawresetcliparea()
+=========
+*/
+void VM_drawresetcliparea(void)
+{
+       VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
+
+       DrawQ_ResetClipArea();
+}
+
+/*
+=========
+VM_getimagesize
+
+vector getimagesize(string pic)
+=========
+*/
+void VM_getimagesize(void)
+{
+       char *p;
+       cachepic_t *pic;
+
+       VM_SAFEPARMCOUNT(1,VM_getimagesize);
        
-       PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
-       PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
-       PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
+       p = PRVM_G_STRING(OFS_PARM0);
+
+       if(!p)
+               PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
+       
+       VM_CheckEmptyString (p);
+
+       pic = Draw_CachePic (p);
+
+       PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
+       PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
+       PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
 }
 
 void VM_Cmd_Init(void)
 {
        // only init the stuff for the current prog
        VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
-       VM_Files_Init();                
+       VM_Files_Init();
+       VM_Search_Init();
 }
 
 void VM_Cmd_Reset(void)
 {
-       Mem_EmptyPool(VM_STRINGS_MEMPOOL);
+       //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
+       Mem_FreePool(&VM_STRINGS_MEMPOOL);
+       VM_Search_Reset();
        VM_Files_CloseAll();
 }
 
@@ -2492,6 +2930,194 @@ void VM_M_getkeydest(void)
        }
 }
 
+/*
+=========
+VM_M_callfunction
+
+       callfunction(...,string function_name)
+=========
+*/
+mfunction_t *PRVM_ED_FindFunction (const char *name);
+void VM_M_callfunction(void)
+{
+       mfunction_t *func;
+       char *s;
+
+       if(prog->argc == 0)
+               PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
+
+       s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
+
+       if(!s)
+               PRVM_ERROR("VM_M_callfunction: null string !\n");
+
+       VM_CheckEmptyString(s); 
+
+       func = PRVM_ED_FindFunction(s);
+
+       if(!func)
+               PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
+       else if (func->first_statement < 0)
+       {
+               // negative statements are built in functions
+               int builtinnumber = -func->first_statement;
+               prog->xfunction->builtinsprofile++;
+               if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
+                       prog->builtins[builtinnumber]();
+               else
+                       PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
+       }
+       else if(func > 0)
+       {
+               prog->argc--;
+               PRVM_ExecuteProgram(func - prog->functions,"");
+               prog->argc++;
+       }
+}      
+
+/*
+=========
+VM_M_isfunction
+
+float  isfunction(string function_name)
+=========
+*/
+mfunction_t *PRVM_ED_FindFunction (const char *name);
+void VM_M_isfunction(void)
+{
+       mfunction_t *func;
+       char *s;
+       
+       VM_SAFEPARMCOUNT(1, VM_M_isfunction);
+       
+       s = PRVM_G_STRING(OFS_PARM0);
+       
+       if(!s)
+               PRVM_ERROR("VM_M_isfunction: null string !\n");
+       
+       VM_CheckEmptyString(s); 
+       
+       func = PRVM_ED_FindFunction(s);
+
+       if(!func)
+               PRVM_G_FLOAT(OFS_RETURN) = false;
+       else
+               PRVM_G_FLOAT(OFS_RETURN) = true;
+}
+
+/*
+=========
+VM_M_writetofile
+
+       writetofile(float fhandle, entity ent)
+=========
+*/
+void VM_M_writetofile(void)
+{
+       prvm_edict_t * ent;
+       int filenum;
+
+       VM_SAFEPARMCOUNT(2, VM_M_writetofile);
+
+       filenum = PRVM_G_FLOAT(OFS_PARM0);
+       if (filenum < 0 || filenum >= MAX_VMFILES)
+       {
+               Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
+               return;
+       }
+       if (VM_FILES[filenum] == NULL)
+       {
+               Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
+               return;
+       }
+
+       ent = PRVM_G_EDICT(OFS_PARM1);  
+       if(ent->e->free)
+       {
+               Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
+               return;
+       }
+
+       PRVM_ED_Write (VM_FILES[filenum], ent);
+}
+
+/*
+=========
+VM_M_getresolution
+
+vector getresolution(float number)
+=========
+*/
+extern unsigned short video_resolutions[][2];
+void VM_M_getresolution(void)
+{
+       int nr;
+       VM_SAFEPARMCOUNT(1, VM_getresolution);
+
+       nr = PRVM_G_FLOAT(OFS_PARM0);
+
+
+       PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
+       PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
+       PRVM_G_VECTOR(OFS_RETURN)[2] = 0;       
+}
+
+/*
+=========
+VM_M_keynumtostring
+
+string keynumtostring(float keynum)
+=========
+*/
+void VM_M_keynumtostring(void)
+{
+       int keynum;
+       char *tmp;
+       VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
+
+       keynum = PRVM_G_FLOAT(OFS_PARM0);
+
+       tmp = VM_GetTempString();
+       
+       strcpy(tmp, Key_KeynumToString(keynum));
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
+}
+
+/*
+=========
+VM_M_findkeysforcommand
+
+string findkeysforcommand(string command)
+
+the returned string is an altstring
+=========
+*/
+#define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
+
+void M_FindKeysForCommand(char *command, int *keys);
+void VM_M_findkeysforcommand(void)
+{
+       char *cmd, *ret;
+       int keys[NUMKEYS];
+       int i;
+
+       VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
+
+       cmd = PRVM_G_STRING(OFS_PARM0);
+       
+       VM_CheckEmptyString(cmd);
+
+       (ret = VM_GetTempString())[0] = 0;
+       
+       M_FindKeysForCommand(cmd, keys);
+
+       for(i = 0; i < NUMKEYS; i++)
+               ret = strcat(ret, va(" \'%i\'", keys[i]));
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
+}
+
 prvm_builtin_t vm_m_builtins[] = {
        0, // to be consistent with the old vm
        // common builtings (mostly)
@@ -2560,12 +3186,20 @@ prvm_builtin_t vm_m_builtins[] = {
        VM_clcommand,
        VM_changelevel,
        VM_localsound,  
-       VM_getmousepos, // 66
-       0,
-       0,
-       0,
-       0,                              // 70
-       e10,                    // 80
+       VM_getmousepos,
+       VM_gettime,
+       VM_loadfromdata,
+       VM_loadfromfile,
+       VM_modulo,              // 70
+       VM_str_cvar,    
+       VM_crash,
+       VM_stackdump,   // 73
+       VM_search_begin,
+       VM_search_end,
+       VM_search_getsize,
+       VM_search_getfilename, // 77
+       VM_chr, //78
+       0,0,// 80
        e10,                    // 90
        e10,                    // 100
        e100,                   // 200
@@ -2593,10 +3227,10 @@ prvm_builtin_t vm_m_builtins[] = {
        VM_drawcharacter,
        VM_drawstring,
        VM_drawpic,
-       VM_drawfill,    // 457
-       0,
-       0,
-       0,                              // 460
+       VM_drawfill,    
+       VM_drawsetcliparea,
+       VM_drawresetcliparea,
+       VM_getimagesize,// 460
        e10,                    // 470
        e10,                    // 480
        e10,                    // 490
@@ -2606,7 +3240,13 @@ prvm_builtin_t vm_m_builtins[] = {
        VM_M_setkeydest,
        VM_M_getkeydest,
        VM_M_setmousetarget,
-       VM_M_getmousetarget
+       VM_M_getmousetarget,
+       VM_M_callfunction,
+       VM_M_writetofile,
+       VM_M_isfunction,
+       VM_M_getresolution,
+       VM_M_keynumtostring,
+       VM_M_findkeysforcommand// 610
 };
 
 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
@@ -2618,6 +3258,6 @@ void VM_M_Cmd_Init(void)
 
 void VM_M_Cmd_Reset(void)
 {
-       VM_Cmd_Init();
+       //VM_Cmd_Init();
+       VM_Cmd_Reset();
 }
-