]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - prvm_cmds.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / prvm_cmds.c
index 980aff25d43eeb85e38443ced5feb1c6c0791819..1fb432c9824d4db3f4727924035e7c910df685ad 100644 (file)
@@ -27,12 +27,16 @@ void VM_Warning(prvm_prog_t *prog, const char *fmt, ...)
        va_list argptr;
        char msg[MAX_INPUTLINE];
        static double recursive = -1;
+       int outfd = sys.outfd;
+
+       // set output to stderr
+       sys.outfd = fileno(stderr);
 
        va_start(argptr,fmt);
        dpvsnprintf(msg,sizeof(msg),fmt,argptr);
        va_end(argptr);
 
-       Con_Printf(CON_WARN "%s", msg);
+       Con_Printf(CON_WARN "%s VM warning: %s", prog->name, msg);
 
        // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black]
        if(prvm_backtraceforwarnings.integer && recursive != host.realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set
@@ -41,6 +45,9 @@ void VM_Warning(prvm_prog_t *prog, const char *fmt, ...)
                PRVM_PrintState(prog, 0);
                recursive = -1;
        }
+
+       // restore configured outfd
+       sys.outfd = outfd;
 }
 
 
@@ -58,6 +65,34 @@ void VM_CheckEmptyString(prvm_prog_t *prog, const char *s)
                prog->error_cmd("%s: Bad string", prog->name);
 }
 
+qbool PRVM_ConsoleCommand(prvm_prog_t *prog, const char *text, size_t textlen, int *func, qbool preserve_self, int curself, double ptime, const char *error_message)
+{
+       int restorevm_tempstringsbuf_cursize;
+       int save_self = 0; // hush compiler warning
+       qbool r = false;
+
+       if(!prog->loaded)
+               return false;
+
+       if(func)
+       {
+               if(preserve_self)
+                       save_self = PRVM_gameglobaledict(self);
+               if(ptime)
+                       PRVM_gameglobalfloat(time) = ptime;
+               PRVM_gameglobaledict(self) = curself;
+               restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
+               PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, text, textlen);
+               prog->ExecuteProgram(prog, *func, error_message);
+               prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+               if(preserve_self)
+                       PRVM_gameglobaledict(self) = save_self;
+               r = (int) PRVM_G_FLOAT(OFS_RETURN) != 0;
+       }
+
+       return r;
+}
+
 void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
 {
        // self.frame is the interpolation target (new frame)
@@ -236,20 +271,42 @@ void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed)
 //============================================================================
 //BUILT-IN FUNCTIONS
 
-void VM_VarString(prvm_prog_t *prog, int first, char *out, int outlength)
+#ifdef WIN32
+       // memccpy() is standard in POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD, C23.
+       // Microsoft supports it, but apparently complains if we use it.
+       #undef memccpy
+       #define memccpy _memccpy
+#endif
+size_t VM_VarString(prvm_prog_t *prog, int first, char *out, size_t outsize)
 {
        int i;
        const char *s;
-       char *outend;
+       char *p;
+       char *outend = out + outsize - 1;
 
-       outend = out + outlength - 1;
+       // bones_was_here: && out < outend improves perf significantly in some tests that don't trigger the warning,
+       // which seems odd, surely it would only help when the warning is printed?
        for (i = first;i < prog->argc && out < outend;i++)
        {
                s = PRVM_G_STRING((OFS_PARM0+i*3));
-               while (out < outend && *s)
-                       *out++ = *s++;
+               if (*s)
+               {
+                       // like dp_stpecpy but with a VM_Warning for use with `prvm_backtraceforwarnings 1`
+                       p = (char *)memccpy(out, s, '\0', (outend + 1) - out);
+                       if (p)
+                               out = p - 1;
+                       else
+                       {
+                               VM_Warning(prog, "%lu of %lu bytes available, will truncate %lu byte string \"%s\"\n", (unsigned long)(outend - out), (unsigned long)outsize - 1, (unsigned long)strlen(s), s);
+                               out = outend;
+                               *out = '\0';
+                       }
+               }
+               else
+                       *out = '\0';
        }
-       *out++ = 0;
+
+       return outsize - ((outend + 1) - out);
 }
 
 /*
@@ -293,6 +350,10 @@ static qbool checkextension(prvm_prog_t *prog, const char *name)
                        if (!strcasecmp("DP_QC_DIGEST_SHA256", name))
                                return Crypto_Available();
 
+                       // special shreck for libcurl
+                       if (!strcasecmp("DP_QC_URI_GET", name) || !strcasecmp("DP_QC_URI_POST", name))
+                               return Curl_Available();
+
                        return true;
                }
        }
@@ -319,7 +380,7 @@ error(value)
 void VM_error(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_VarString(prog, 0, string, sizeof(string));
        Con_Printf(CON_ERROR "======%s ERROR in %s:\n%s\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
@@ -342,7 +403,7 @@ objerror(value)
 void VM_objerror(prvm_prog_t *prog)
 {
        prvm_edict_t    *ed;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_VarString(prog, 0, string, sizeof(string));
        Con_Printf(CON_ERROR "======OBJECT ERROR======\n"); // , prog->name, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
@@ -363,7 +424,7 @@ print(...[string])
 */
 void VM_print(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_VarString(prog, 0, string, sizeof(string));
        Con_Print(string);
@@ -380,7 +441,7 @@ bprint(...[string])
 */
 void VM_bprint(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        if(!sv.active)
        {
@@ -405,7 +466,7 @@ void VM_sprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     clientnum;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_sprint);
 
@@ -437,7 +498,7 @@ centerprint(value)
 */
 void VM_centerprint(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_centerprint);
        VM_VarString(prog, 0, string, sizeof(string));
@@ -542,7 +603,7 @@ void VM_vectoangles(prvm_prog_t *prog)
 =================
 VM_random
 
-Returns a number from 0<= num < 1
+Returns a random number > 0 and < 1
 
 float random()
 =================
@@ -558,18 +619,29 @@ void VM_random(prvm_prog_t *prog)
 =========
 VM_localsound
 
-localsound(string sample)
+localsound(string sample, float chan, float vol)
 =========
 */
 void VM_localsound(prvm_prog_t *prog)
 {
        const char *s;
+       float chan, vol;
 
-       VM_SAFEPARMCOUNT(1,VM_localsound);
+       VM_SAFEPARMCOUNTRANGE(1, 3,VM_localsound);
 
        s = PRVM_G_STRING(OFS_PARM0);
-
-       if(!S_LocalSound (s))
+       if(prog->argc == 3)
+       {
+               chan = PRVM_G_FLOAT(OFS_PARM1);
+               vol = PRVM_G_FLOAT(OFS_PARM2) == 0 ? 1 : PRVM_G_FLOAT(OFS_PARM2);
+               if(!S_LocalSoundEx(s, chan, vol))
+               {
+                       PRVM_G_FLOAT(OFS_RETURN) = -4;
+                       VM_Warning(prog, "VM_localsound: Failed to play %s for %s !\n", s, prog->name);
+                       return;
+               }
+       }
+       else if(!S_LocalSound (s))
        {
                PRVM_G_FLOAT(OFS_RETURN) = -4;
                VM_Warning(prog, "VM_localsound: Failed to play %s for %s !\n", s, prog->name);
@@ -595,38 +667,20 @@ void VM_break(prvm_prog_t *prog)
 
 /*
 =================
-VM_localcmd_client
+VM_localcmd
 
-Sends text over to the client's execution buffer
+Appends text to the command buffer
 
 [localcmd (string, ...) or]
 cmd (string, ...)
 =================
 */
-void VM_localcmd_client(prvm_prog_t *prog)
+void VM_localcmd(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
-       VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd_client);
+       char string[VM_TEMPSTRING_MAXSIZE];
+       VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd);
        VM_VarString(prog, 0, string, sizeof(string));
-       Cbuf_AddText(&cmd_client, string);
-}
-
-/*
-=================
-VM_localcmd_server
-
-Sends text over to the server's execution buffer
-
-[localcmd (string, ...) or]
-cmd (string, ...)
-=================
-*/
-void VM_localcmd_server(prvm_prog_t *prog)
-{
-       char string[VM_STRINGTEMP_LENGTH];
-       VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd_server);
-       VM_VarString(prog, 0, string, sizeof(string));
-       Cbuf_AddText(&cmd_server, string);
+       Cbuf_AddText(cmd_local, string);
 }
 
 static qbool PRVM_Cvar_ReadOk(prvm_prog_t *prog, const char *string)
@@ -645,7 +699,7 @@ float cvar (string)
 */
 void VM_cvar(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar);
        VM_VarString(prog, 0, string, sizeof(string));
        VM_CheckEmptyString(prog, string);
@@ -667,7 +721,7 @@ float CVAR_TYPEFLAG_READONLY = 32;
 */
 void VM_cvar_type(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        cvar_t *cvar;
        int ret;
 
@@ -707,11 +761,18 @@ const string      VM_cvar_string (string, ...)
 */
 void VM_cvar_string(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char cvar_name[VM_TEMPSTRING_MAXSIZE];
+
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_string);
-       VM_VarString(prog, 0, string, sizeof(string));
-       VM_CheckEmptyString(prog, string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_Cvar_ReadOk(prog, string) ? Cvar_VariableString(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask) : "");
+       VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
+       VM_CheckEmptyString(prog, cvar_name);
+       if (PRVM_Cvar_ReadOk(prog, cvar_name))
+       {
+               const char *cvar_string = Cvar_VariableString(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cvar_string, strlen(cvar_string));
+       }
+       else
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
 }
 
 
@@ -724,11 +785,14 @@ const string      VM_cvar_defstring (string, ...)
 */
 void VM_cvar_defstring(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char cvar_name[VM_TEMPSTRING_MAXSIZE];
+       const char *cvar_defstring;
+
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_defstring);
-       VM_VarString(prog, 0, string, sizeof(string));
-       VM_CheckEmptyString(prog, string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDefString(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask));
+       VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
+       VM_CheckEmptyString(prog, cvar_name);
+       cvar_defstring = Cvar_VariableDefString(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cvar_defstring, strlen(cvar_defstring));
 }
 
 /*
@@ -740,11 +804,14 @@ const string      VM_cvar_description (string, ...)
 */
 void VM_cvar_description(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char cvar_name[VM_TEMPSTRING_MAXSIZE];
+       const char *cvar_desc;
+
        VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_description);
-       VM_VarString(prog, 0, string, sizeof(string));
-       VM_CheckEmptyString(prog, string);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDescription(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask));
+       VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
+       VM_CheckEmptyString(prog, cvar_name);
+       cvar_desc = Cvar_VariableDescription(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cvar_desc, strlen(cvar_desc));
 }
 /*
 =================
@@ -756,12 +823,25 @@ void cvar_set (string,string, ...)
 void VM_cvar_set(prvm_prog_t *prog)
 {
        const char *name;
-       char string[VM_STRINGTEMP_LENGTH];
+       char value[VM_TEMPSTRING_MAXSIZE];
+       cvar_t *cvar;
+
        VM_SAFEPARMCOUNTRANGE(2,8,VM_cvar_set);
-       VM_VarString(prog, 1, string, sizeof(string));
        name = PRVM_G_STRING(OFS_PARM0);
        VM_CheckEmptyString(prog, name);
-       Cvar_Set(prog->console_cmd->cvars, name, string);
+       cvar = Cvar_FindVar(prog->console_cmd->cvars, name, prog->console_cmd->cvars_flagsmask);
+       if (!cvar)
+       {
+               VM_Warning(prog, "VM_cvar_set: variable %s not found\n", name);
+               return;
+       }
+       if (cvar->flags & CF_READONLY)
+       {
+               VM_Warning(prog, "VM_cvar_set: variable %s is read-only\n", cvar->name);
+               return;
+       }
+       VM_VarString(prog, 1, value, sizeof(value));
+       Cvar_SetQuick(cvar, value);
 }
 
 /*
@@ -773,7 +853,7 @@ dprint(...[string])
 */
 void VM_dprint(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_dprint);
        VM_VarString(prog, 0, string, sizeof(string));
 #if 1
@@ -795,16 +875,17 @@ void VM_ftos(prvm_prog_t *prog)
 {
        prvm_vec_t v;
        char s[128];
+       size_t slen;
 
        VM_SAFEPARMCOUNT(1, VM_ftos);
 
        v = PRVM_G_FLOAT(OFS_PARM0);
 
        if ((prvm_vec_t)((prvm_int_t)v) == v)
-               dpsnprintf(s, sizeof(s), "%.0f", v);
+               slen = dpsnprintf(s, sizeof(s), "%.0f", v);
        else
-               dpsnprintf(s, sizeof(s), "%f", v);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
+               slen = dpsnprintf(s, sizeof(s), "%f", v);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
 }
 
 /*
@@ -836,11 +917,12 @@ string    vtos(vector)
 void VM_vtos(prvm_prog_t *prog)
 {
        char s[512];
+       size_t slen;
 
        VM_SAFEPARMCOUNT(1,VM_vtos);
 
-       dpsnprintf (s, sizeof(s), "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
+       slen = dpsnprintf(s, sizeof(s), "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
 }
 
 /*
@@ -854,11 +936,12 @@ string    etos(entity)
 void VM_etos(prvm_prog_t *prog)
 {
        char s[128];
+       size_t slen;
 
        VM_SAFEPARMCOUNT(1, VM_etos);
 
-       dpsnprintf (s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
+       slen = dpsnprintf(s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
 }
 
 /*
@@ -870,7 +953,7 @@ float stof(...[string])
 */
 void VM_stof(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_stof);
        VM_VarString(prog, 0, string, sizeof(string));
        PRVM_G_FLOAT(OFS_RETURN) = atof(string);
@@ -902,7 +985,7 @@ void VM_ftoe(prvm_prog_t *prog)
        VM_SAFEPARMCOUNT(1, VM_ftoe);
 
        ent = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM0);
-       if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
+       if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->free)
                ent = 0; // return world instead of a free or invalid entity
 
        PRVM_G_INT(OFS_RETURN) = ent;
@@ -937,8 +1020,10 @@ void VM_strftime(prvm_prog_t *prog)
 #else
        struct tm *tm;
 #endif
-       char fmt[VM_STRINGTEMP_LENGTH];
-       char result[VM_STRINGTEMP_LENGTH];
+       char fmt[VM_TEMPSTRING_MAXSIZE];
+       char result[VM_TEMPSTRING_MAXSIZE];
+       size_t result_len;
+
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_strftime);
        VM_VarString(prog, 1, fmt, sizeof(fmt));
        t = time(NULL);
@@ -960,11 +1045,11 @@ void VM_strftime(prvm_prog_t *prog)
                return;
        }
 #if _MSC_VER >= 1400
-       strftime(result, sizeof(result), fmt, &tm);
+       result_len = strftime(result, sizeof(result), fmt, &tm);
 #else
-       strftime(result, sizeof(result), fmt, tm);
+       result_len = strftime(result, sizeof(result), fmt, tm);
 #endif
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result, result_len);
 }
 
 /*
@@ -1005,7 +1090,7 @@ void VM_remove(prvm_prog_t *prog)
                if (developer.integer > 0)
                        VM_Warning(prog, "VM_remove: tried to remove the null entity or a reserved entity!\n" );
        }
-       else if( ed->priv.required->free )
+       else if( ed->free )
        {
                if (developer.integer > 0)
                        VM_Warning(prog, "VM_remove: tried to remove an already freed entity!\n" );
@@ -1043,7 +1128,7 @@ void VM_find(prvm_prog_t *prog)
        {
                prog->xfunction->builtinsprofile++;
                ed = PRVM_EDICT_NUM(e);
-               if (ed->priv.required->free)
+               if (ed->free)
                        continue;
                t = PRVM_E_STRING(ed,f);
                if (!t)
@@ -1084,7 +1169,7 @@ void VM_findfloat(prvm_prog_t *prog)
        {
                prog->xfunction->builtinsprofile++;
                ed = PRVM_EDICT_NUM(e);
-               if (ed->priv.required->free)
+               if (ed->free)
                        continue;
                if (PRVM_E_FLOAT(ed,f) == s)
                {
@@ -1135,7 +1220,7 @@ void VM_findchain(prvm_prog_t *prog)
        for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
        {
                prog->xfunction->builtinsprofile++;
-               if (ent->priv.required->free)
+               if (ent->free)
                        continue;
                t = PRVM_E_STRING(ent,f);
                if (!t)
@@ -1175,7 +1260,7 @@ void VM_findchainfloat(prvm_prog_t *prog)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
+               prog->error_cmd("VM_findchainfloat: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -1186,7 +1271,7 @@ void VM_findchainfloat(prvm_prog_t *prog)
        for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
        {
                prog->xfunction->builtinsprofile++;
-               if (ent->priv.required->free)
+               if (ent->free)
                        continue;
                if (PRVM_E_FLOAT(ent,f) != s)
                        continue;
@@ -1224,7 +1309,7 @@ void VM_findflags(prvm_prog_t *prog)
        {
                prog->xfunction->builtinsprofile++;
                ed = PRVM_EDICT_NUM(e);
-               if (ed->priv.required->free)
+               if (ed->free)
                        continue;
                if (!PRVM_E_FLOAT(ed,f))
                        continue;
@@ -1261,7 +1346,7 @@ void VM_findchainflags(prvm_prog_t *prog)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
+               prog->error_cmd("VM_findchainflags: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -1272,7 +1357,7 @@ void VM_findchainflags(prvm_prog_t *prog)
        for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
        {
                prog->xfunction->builtinsprofile++;
-               if (ent->priv.required->free)
+               if (ent->free)
                        continue;
                if (!PRVM_E_FLOAT(ent,f))
                        continue;
@@ -1335,12 +1420,11 @@ coredump()
 */
 void VM_coredump(prvm_prog_t *prog)
 {
-       cmd_state_t *cmd =      !host_isclient.integer ? &cmd_server : &cmd_client;
        VM_SAFEPARMCOUNT(0,VM_coredump);
 
-       Cbuf_AddText(cmd, "prvm_edicts ");
-       Cbuf_AddText(cmd, prog->name);
-       Cbuf_AddText(cmd, "\n");
+       Cbuf_AddText(cmd_local, "prvm_edicts ");
+       Cbuf_AddText(cmd_local, prog->name);
+       Cbuf_AddText(cmd_local, "\n");
 }
 
 /*
@@ -1487,7 +1571,7 @@ void VM_nextent(prvm_prog_t *prog)
                        return;
                }
                ent = PRVM_EDICT_NUM(i);
-               if (!ent->priv.required->free)
+               if (!ent->free)
                {
                        VM_RETURN_EDICT(ent);
                        return;
@@ -1521,7 +1605,7 @@ void VM_changelevel(prvm_prog_t *prog)
                return;
        svs.changelevel_issued = true;
 
-       Cbuf_AddText(&cmd_server, va(vabuf, sizeof(vabuf), "changelevel %s\n", PRVM_G_STRING(OFS_PARM0)));
+       Cbuf_AddText(cmd_local, va(vabuf, sizeof(vabuf), "changelevel %s\n", PRVM_G_STRING(OFS_PARM0)));
 }
 
 /*
@@ -1652,7 +1736,7 @@ float     registercvar (string name, string value[, float flags])
 void VM_registercvar(prvm_prog_t *prog)
 {
        const char *name, *value;
-       int     flags;
+       unsigned flags;
 
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_registercvar);
 
@@ -1669,7 +1753,7 @@ void VM_registercvar(prvm_prog_t *prog)
                return;
 
 // check for overlap with a command
-       if (Cmd_Exists(&cmd_client, name) || Cmd_Exists(&cmd_server, name))
+       if (Cmd_Exists(cmd_local, name))
        {
                VM_Warning(prog, "VM_registercvar: %s is a command\n", name);
                return;
@@ -1912,7 +1996,7 @@ string    fgets(float fhandle)
 void VM_fgets(prvm_prog_t *prog)
 {
        int c, end;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int filenum;
 
        VM_SAFEPARMCOUNT(1,VM_fgets);
@@ -1937,10 +2021,10 @@ void VM_fgets(prvm_prog_t *prog)
                c = FS_Getc(prog->openfiles[filenum]);
                if (c == '\r' || c == '\n' || c < 0)
                        break;
-               if (end < VM_STRINGTEMP_LENGTH - 1)
+               if (end < VM_TEMPSTRING_MAXSIZE - 1)
                        string[end++] = c;
        }
-       string[end] = 0;
+       string[end] = '\0';
        // remove \n following \r
        if (c == '\r')
        {
@@ -1951,7 +2035,7 @@ void VM_fgets(prvm_prog_t *prog)
        if (developer_extra.integer)
                Con_DPrintf("fgets: %s: %s\n", prog->name, string);
        if (c >= 0 || end)
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, end);
 }
 
 /*
@@ -1964,8 +2048,8 @@ fputs(float fhandle, string s)
 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
 void VM_fputs(prvm_prog_t *prog)
 {
-       int stringlength;
-       char string[VM_STRINGTEMP_LENGTH];
+       size_t stringlength;
+       char string[VM_TEMPSTRING_MAXSIZE];
        int filenum;
 
        VM_SAFEPARMCOUNT(2,VM_fputs);
@@ -1981,8 +2065,8 @@ void VM_fputs(prvm_prog_t *prog)
                VM_Warning(prog, "VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
                return;
        }
-       VM_VarString(prog, 1, string, sizeof(string));
-       if ((stringlength = (int)strlen(string)))
+       stringlength = VM_VarString(prog, 1, string, sizeof(string));
+       if (stringlength)
                FS_Write(prog->openfiles[filenum], string, stringlength);
        if (developer_extra.integer)
                Con_DPrintf("fputs: %s: %s\n", prog->name, string);
@@ -2010,7 +2094,7 @@ void VM_writetofile(prvm_prog_t *prog)
        }
 
        ent = PRVM_G_EDICT(OFS_PARM1);
-       if(ent->priv.required->free)
+       if(ent->free)
        {
                VM_Warning(prog, "VM_writetofile: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
                return;
@@ -2050,7 +2134,7 @@ void VM_entityfieldname(prvm_prog_t *prog)
        if (i < 0 || i >= prog->numfielddefs)
        {
                VM_Warning(prog, "VM_entityfieldname: %s: field index out of bounds\n", prog->name);
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
                return;
        }
 
@@ -2102,8 +2186,8 @@ void VM_getentityfieldstring(prvm_prog_t *prog)
        
        if (i < 0 || i >= prog->numfielddefs)
        {
-        VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
                return;
        }
        
@@ -2111,9 +2195,9 @@ void VM_getentityfieldstring(prvm_prog_t *prog)
        
        // get the entity
        ent = PRVM_G_EDICT(OFS_PARM1);
-       if(ent->priv.required->free)
+       if(ent->free)
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
                VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
                return;
        }
@@ -2126,11 +2210,12 @@ void VM_getentityfieldstring(prvm_prog_t *prog)
                        break;
        if (j == prvm_type_size[type])
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
                return;
        }
-               
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)));
+
+       PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, valuebuf, strlen(valuebuf));
 }
 
 // KrimZon - DP_QC_ENTITYDATA
@@ -2158,7 +2243,7 @@ void VM_putentityfieldstring(prvm_prog_t *prog)
 
        // get the entity
        ent = PRVM_G_EDICT(OFS_PARM1);
-       if(ent->priv.required->free)
+       if(ent->free)
        {
                VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
                PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
@@ -2196,14 +2281,15 @@ string  strdecolorize(string s)
 // string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped
 void VM_strdecolorize(prvm_prog_t *prog)
 {
-       char szNewString[VM_STRINGTEMP_LENGTH];
+       char szNewString[VM_TEMPSTRING_MAXSIZE];
+       size_t szNewString_len;
        const char *szString;
 
        // Prepare Strings
        VM_SAFEPARMCOUNT(1,VM_strdecolorize);
        szString = PRVM_G_STRING(OFS_PARM0);
-       COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
+       szNewString_len = COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
 }
 
 // DRESK - String Length (not counting color codes)
@@ -2242,16 +2328,17 @@ string  strtolower(string s)
 // string (string s) strtolower = #480; // returns passed in string in lowercase form
 void VM_strtolower(prvm_prog_t *prog)
 {
-       char szNewString[VM_STRINGTEMP_LENGTH];
+       char szNewString[VM_TEMPSTRING_MAXSIZE];
+       size_t szNewString_len;
        const char *szString;
 
        // Prepare Strings
        VM_SAFEPARMCOUNT(1,VM_strtolower);
        szString = PRVM_G_STRING(OFS_PARM0);
 
-       COM_ToLowerString(szString, szNewString, sizeof(szNewString) );
+       szNewString_len = COM_ToLowerString(szString, szNewString, sizeof(szNewString) );
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
 }
 
 /*
@@ -2264,35 +2351,38 @@ string  strtoupper(string s)
 // string (string s) strtoupper = #481; // returns passed in string in uppercase form
 void VM_strtoupper(prvm_prog_t *prog)
 {
-       char szNewString[VM_STRINGTEMP_LENGTH];
+       char szNewString[VM_TEMPSTRING_MAXSIZE];
+       size_t szNewString_len;
        const char *szString;
 
        // Prepare Strings
        VM_SAFEPARMCOUNT(1,VM_strtoupper);
        szString = PRVM_G_STRING(OFS_PARM0);
 
-       COM_ToUpperString(szString, szNewString, sizeof(szNewString) );
+       szNewString_len = COM_ToUpperString(szString, szNewString, sizeof(szNewString) );
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
 }
 
 /*
 =========
 VM_strcat
 
-string strcat(string,string,...[string])
+string strcat(string s, string...)
 =========
 */
-//string(string s1, string s2) strcat = #115;
-// concatenates two strings (for example "abc", "def" would return "abcdef")
+//string(string s, string...) strcat = #115;
+// concatenates strings (for example "abc", "def" would return "abcdef")
 // and returns as a tempstring
 void VM_strcat(prvm_prog_t *prog)
 {
-       char s[VM_STRINGTEMP_LENGTH];
+       char s[VM_TEMPSTRING_MAXSIZE];
+       size_t slen;
+
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_strcat);
 
-       VM_VarString(prog, 0, s, sizeof(s));
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
+       slen = VM_VarString(prog, 0, s, sizeof(s));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
 }
 
 /*
@@ -2310,7 +2400,7 @@ void VM_substring(prvm_prog_t *prog)
        int u_slength = 0, u_start;
        size_t u_length;
        const char *s;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT(3,VM_substring);
 
@@ -2356,7 +2446,7 @@ void VM_substring(prvm_prog_t *prog)
        u_start = u8_byteofs(s, start, NULL);
        if (u_start < 0)
        {
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
                return;
        }
        u_length = u8_bytelen(s + u_start, length);
@@ -2364,8 +2454,8 @@ void VM_substring(prvm_prog_t *prog)
                u_length = sizeof(string)-1;
        
        memcpy(string, s + u_start, u_length);
-       string[u_length] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
+       string[u_length] = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, u_length);
 }
 
 /*
@@ -2380,7 +2470,7 @@ void VM_strreplace(prvm_prog_t *prog)
 {
        int i, j, si;
        const char *search, *replace, *subject;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int search_len, replace_len, subject_len;
 
        VM_SAFEPARMCOUNT(3,VM_strreplace);
@@ -2432,7 +2522,7 @@ void VM_strreplace(prvm_prog_t *prog)
                        string[si++] = subject[i];
        string[si] = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, si);
 }
 
 /*
@@ -2447,7 +2537,7 @@ void VM_strireplace(prvm_prog_t *prog)
 {
        int i, j, si;
        const char *search, *replace, *subject;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int search_len, replace_len, subject_len;
 
        VM_SAFEPARMCOUNT(3, VM_strireplace);
@@ -2499,7 +2589,7 @@ void VM_strireplace(prvm_prog_t *prog)
                        string[si++] = subject[i];
        string[si] = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, si);
 }
 
 /*
@@ -2512,7 +2602,7 @@ vector    stov(string s)
 //vector(string s) stov = #117; // returns vector value from a string
 void VM_stov(prvm_prog_t *prog)
 {
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT(1,VM_stov);
 
@@ -2531,13 +2621,12 @@ string  strzone(string s)
 void VM_strzone(prvm_prog_t *prog)
 {
        char *out;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        size_t alloclen;
 
        VM_SAFEPARMCOUNT(1,VM_strzone);
 
-       VM_VarString(prog, 0, string, sizeof(string));
-       alloclen = strlen(string) + 1;
+       alloclen = VM_VarString(prog, 0, string, sizeof(string)) + 1;
        PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(prog, alloclen, &out);
        memcpy(out, string, alloclen);
 }
@@ -2567,17 +2656,17 @@ float tokenize(string s)
 //this function originally written by KrimZon, made shorter by LadyHavoc
 //20040203: rewritten by LadyHavoc (no longer uses allocations)
 static int num_tokens = 0;
-static int tokens[VM_STRINGTEMP_LENGTH / 2];
-static int tokens_startpos[VM_STRINGTEMP_LENGTH / 2];
-static int tokens_endpos[VM_STRINGTEMP_LENGTH / 2];
-static char tokenize_string[VM_STRINGTEMP_LENGTH];
+static int tokens[VM_TEMPSTRING_MAXSIZE / 2];
+static int tokens_startpos[VM_TEMPSTRING_MAXSIZE / 2];
+static int tokens_endpos[VM_TEMPSTRING_MAXSIZE / 2];
+static char tokenize_string[VM_TEMPSTRING_MAXSIZE];
 void VM_tokenize (prvm_prog_t *prog)
 {
        const char *p;
 
        VM_SAFEPARMCOUNT(1,VM_tokenize);
 
-       strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
+       dp_strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
        p = tokenize_string;
 
        num_tokens = 0;
@@ -2594,7 +2683,7 @@ void VM_tokenize (prvm_prog_t *prog)
                if(!COM_ParseToken_VM_Tokenize(&p, false))
                        break;
                tokens_endpos[num_tokens] = p - tokenize_string;
-               tokens[num_tokens] = PRVM_SetTempString(prog, com_token);
+               tokens[num_tokens] = PRVM_SetTempString(prog, com_token, com_token_len);
                ++num_tokens;
        }
 
@@ -2608,7 +2697,7 @@ void VM_tokenize_console (prvm_prog_t *prog)
 
        VM_SAFEPARMCOUNT(1, VM_tokenize_console);
 
-       strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
+       dp_strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
        p = tokenize_string;
 
        num_tokens = 0;
@@ -2625,7 +2714,7 @@ void VM_tokenize_console (prvm_prog_t *prog)
                if(!COM_ParseToken_Console(&p))
                        break;
                tokens_endpos[num_tokens] = p - tokenize_string;
-               tokens[num_tokens] = PRVM_SetTempString(prog, com_token);
+               tokens[num_tokens] = PRVM_SetTempString(prog, com_token, com_token_len);
                ++num_tokens;
        }
 
@@ -2658,7 +2747,7 @@ void VM_tokenizebyseparator (prvm_prog_t *prog)
 
        VM_SAFEPARMCOUNTRANGE(2, 8,VM_tokenizebyseparator);
 
-       strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
+       dp_strlcpy(tokenize_string, PRVM_G_STRING(OFS_PARM0), sizeof(tokenize_string));
        p = tokenize_string;
 
        numseparators = 0;
@@ -2701,8 +2790,8 @@ void VM_tokenizebyseparator (prvm_prog_t *prog)
                tokens_endpos[num_tokens] = p0 - tokenize_string;
                if (j >= (int)sizeof(tokentext))
                        break;
-               tokentext[j++] = 0;
-               tokens[num_tokens++] = PRVM_SetTempString(prog, token);
+               tokentext[j++] = '\0';
+               tokens[num_tokens++] = PRVM_SetTempString(prog, token, j - 1);
                if (!*p)
                        break;
        }
@@ -2971,7 +3060,7 @@ void VM_parseentitydata(prvm_prog_t *prog)
 
        // get edict and test it
        ent = PRVM_G_EDICT(OFS_PARM0);
-       if (ent->priv.required->free)
+       if (ent->free)
                prog->error_cmd("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", prog->name, PRVM_NUM_FOR_EDICT(ent));
 
        data = PRVM_G_STRING(OFS_PARM1);
@@ -3026,13 +3115,21 @@ float   mod(float val, float m)
 */
 void VM_modulo(prvm_prog_t *prog)
 {
-       prvm_int_t val, m;
+       vec_t val, m;
+
        VM_SAFEPARMCOUNT(2, VM_modulo);
 
-       val = (prvm_int_t) PRVM_G_FLOAT(OFS_PARM0);
-       m       = (prvm_int_t) PRVM_G_FLOAT(OFS_PARM1);
+       val = PRVM_G_FLOAT(OFS_PARM0);
+       m   = PRVM_G_FLOAT(OFS_PARM1);
 
-       PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t) (val % m);
+       // matches how gmqcc implements % when mod() builtin isn't defined, and FTEQW mod()
+       if (m)
+               PRVM_G_FLOAT(OFS_RETURN) = val - m * (prvm_int_t)(val / m);
+       else
+       {
+               VM_Warning(prog, "Attempted modulo of %f by zero\n", val);
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+       }
 }
 
 static void VM_Search_Init(prvm_prog_t *prog)
@@ -3058,915 +3155,170 @@ static void VM_Search_Reset(prvm_prog_t *prog)
 =========
 VM_search_begin
 
-float search_begin(string pattern, float caseinsensitive, float quiet[, string packfile])
-=========
-*/
-void VM_search_begin(prvm_prog_t *prog)
-{
-       int handle;
-       const char *packfile = NULL, *pattern;
-       int caseinsens, quiet;
-
-       VM_SAFEPARMCOUNTRANGE(3, 4, VM_search_begin);
-
-       pattern = PRVM_G_STRING(OFS_PARM0);
-
-       VM_CheckEmptyString(prog, pattern);
-
-       caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1);
-       quiet = (int)PRVM_G_FLOAT(OFS_PARM2);
-
-       // optional packfile parameter (DP_QC_FS_SEARCH_PACKFILE)
-       if(prog->argc >= 4)
-               packfile = PRVM_G_STRING(OFS_PARM3);
-
-       for(handle = 0; handle < PRVM_MAX_OPENSEARCHES; handle++)
-               if(!prog->opensearches[handle])
-                       break;
-
-       if(handle >= PRVM_MAX_OPENSEARCHES)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_search_begin: %s ran out of search handles (%i)\n", prog->name, PRVM_MAX_OPENSEARCHES);
-               return;
-       }
-
-       if(!(prog->opensearches[handle] = FS_Search(pattern,caseinsens, quiet, packfile)))
-               PRVM_G_FLOAT(OFS_RETURN) = -1;
-       else
-       {
-               prog->opensearches_origin[handle] = PRVM_AllocationOrigin(prog);
-               PRVM_G_FLOAT(OFS_RETURN) = handle;
-       }
-}
-
-/*
-=========
-VM_search_end
-
-void   search_end(float handle)
-=========
-*/
-void VM_search_end(prvm_prog_t *prog)
-{
-       int handle;
-       VM_SAFEPARMCOUNT(1, VM_search_end);
-
-       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
-
-       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
-       {
-               VM_Warning(prog, "VM_search_end: invalid handle %i used in %s\n", handle, prog->name);
-               return;
-       }
-       if(prog->opensearches[handle] == NULL)
-       {
-               VM_Warning(prog, "VM_search_end: no such handle %i in %s\n", handle, prog->name);
-               return;
-       }
-
-       FS_FreeSearch(prog->opensearches[handle]);
-       prog->opensearches[handle] = NULL;
-       if(prog->opensearches_origin[handle])
-               PRVM_Free((char *)prog->opensearches_origin[handle]);
-}
-
-/*
-=========
-VM_search_getsize
-
-float  search_getsize(float handle)
-=========
-*/
-void VM_search_getsize(prvm_prog_t *prog)
-{
-       int handle;
-       VM_SAFEPARMCOUNT(1, VM_search_getsize);
-
-       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
-
-       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
-       {
-               VM_Warning(prog, "VM_search_getsize: invalid handle %i used in %s\n", handle, prog->name);
-               return;
-       }
-       if(prog->opensearches[handle] == NULL)
-       {
-               VM_Warning(prog, "VM_search_getsize: no such handle %i in %s\n", handle, prog->name);
-               return;
-       }
-
-       PRVM_G_FLOAT(OFS_RETURN) = prog->opensearches[handle]->numfilenames;
-}
-
-/*
-=========
-VM_search_getfilename
-
-string search_getfilename(float handle, float num)
-=========
-*/
-void VM_search_getfilename(prvm_prog_t *prog)
-{
-       int handle, filenum;
-       VM_SAFEPARMCOUNT(2, VM_search_getfilename);
-
-       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
-       filenum = (int)PRVM_G_FLOAT(OFS_PARM1);
-
-       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
-       {
-               VM_Warning(prog, "VM_search_getfilename: invalid handle %i used in %s\n", handle, prog->name);
-               return;
-       }
-       if(prog->opensearches[handle] == NULL)
-       {
-               VM_Warning(prog, "VM_search_getfilename: no such handle %i in %s\n", handle, prog->name);
-               return;
-       }
-       if(filenum < 0 || filenum >= prog->opensearches[handle]->numfilenames)
-       {
-               VM_Warning(prog, "VM_search_getfilename: invalid filenum %i in %s\n", filenum, prog->name);
-               return;
-       }
-
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, prog->opensearches[handle]->filenames[filenum]);
-}
-
-/*
-=========
-VM_chr
-
-string chr(float ascii)
-=========
-*/
-void VM_chr(prvm_prog_t *prog)
-{
-       /*
-       char tmp[2];
-       VM_SAFEPARMCOUNT(1, VM_chr);
-
-       tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
-       tmp[1] = 0;
-
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
-       */
-       
-       char tmp[8];
-       int len;
-       VM_SAFEPARMCOUNT(1, VM_chr);
-
-       len = u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0), tmp, sizeof(tmp));
-       tmp[len] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
-}
-
-//=============================================================================
-// Draw builtins (client & menu)
-
-/*
-=========
-VM_iscachedpic
-
-float  iscachedpic(string pic)
-=========
-*/
-void VM_iscachedpic(prvm_prog_t *prog)
-{
-       VM_SAFEPARMCOUNT(1,VM_iscachedpic);
-
-       // drawq hasnt such a function, thus always return true
-       PRVM_G_FLOAT(OFS_RETURN) = false;
-}
-
-/*
-=========
-VM_precache_pic
-
-string precache_pic(string pic)
-=========
-*/
-#define PRECACHE_PIC_FROMWAD 1 /* FTEQW, not supported here */
-#define PRECACHE_PIC_NOTPERSISTENT 2
-//#define PRECACHE_PIC_NOCLAMP 4
-#define PRECACHE_PIC_MIPMAP 8
-void VM_precache_pic(prvm_prog_t *prog)
-{
-       const char      *s;
-       int flags = CACHEPICFLAG_FAILONMISSING;
-
-       VM_SAFEPARMCOUNTRANGE(1, 2, VM_precache_pic);
-
-       s = PRVM_G_STRING(OFS_PARM0);
-       PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
-       VM_CheckEmptyString(prog, s);
-
-       if(prog->argc >= 2)
-       {
-               int f = PRVM_G_FLOAT(OFS_PARM1);
-               if(f & PRECACHE_PIC_NOTPERSISTENT)
-                       flags |= CACHEPICFLAG_NOTPERSISTENT;
-               //if(f & PRECACHE_PIC_NOCLAMP)
-               //      flags |= CACHEPICFLAG_NOCLAMP;
-               if(f & PRECACHE_PIC_MIPMAP)
-                       flags |= CACHEPICFLAG_MIPMAP;
-       }
-
-       if( !Draw_IsPicLoaded(Draw_CachePic_Flags(s, flags | CACHEPICFLAG_QUIET)) )
-               PRVM_G_INT(OFS_RETURN) = OFS_NULL;
-}
-
-/*
-=========
-VM_freepic
-
-freepic(string s)
-=========
-*/
-void VM_freepic(prvm_prog_t *prog)
-{
-       const char *s;
-
-       VM_SAFEPARMCOUNT(1,VM_freepic);
-
-       s = PRVM_G_STRING(OFS_PARM0);
-       VM_CheckEmptyString(prog, s);
-
-       Draw_FreePic(s);
-}
-
-static void getdrawfontscale(prvm_prog_t *prog, float *sx, float *sy)
-{
-       vec3_t v;
-       *sx = *sy = 1;
-       VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
-       if(VectorLength2(v) > 0)
-       {
-               *sx = v[0];
-               *sy = v[1];
-       }
-}
-
-static dp_font_t *getdrawfont(prvm_prog_t *prog)
-{
-       int f = (int) PRVM_drawglobalfloat(drawfont);
-       if(f < 0 || f >= dp_fonts.maxsize)
-               return FONT_DEFAULT;
-       return &dp_fonts.f[f];
-}
-
-/*
-=========
-VM_drawcharacter
-
-float  drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
-=========
-*/
-void VM_drawcharacter(prvm_prog_t *prog)
-{
-       prvm_vec_t *pos,*scale,*rgb;
-       char   character;
-       int flag;
-       float sx, sy;
-       VM_SAFEPARMCOUNT(6,VM_drawcharacter);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       character = (char) PRVM_G_FLOAT(OFS_PARM1);
-       if(character == 0)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -1;
-               VM_Warning(prog, "VM_drawcharacter: %s passed null character !\n",prog->name);
-               return;
-       }
-
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       scale = PRVM_G_VECTOR(OFS_PARM2);
-       rgb = PRVM_G_VECTOR(OFS_PARM3);
-       flag = (int)PRVM_G_FLOAT(OFS_PARM5);
-
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
-               return;
-       }
-
-       if(pos[2] || scale[2])
-               VM_Warning(prog, "VM_drawcharacter: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
-
-       if(!scale[0] || !scale[1])
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -3;
-               VM_Warning(prog, "VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
-               return;
-       }
-
-       getdrawfontscale(prog, &sx, &sy);
-       DrawQ_String_Scale(pos[0], pos[1], &character, 1, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
-}
-
-/*
-=========
-VM_drawstring
-
-float  drawstring(vector position, string text, vector scale, vector rgb, float alpha[, float flag])
-=========
-*/
-void VM_drawstring(prvm_prog_t *prog)
-{
-       prvm_vec_t *pos,*scale,*rgb;
-       const char  *string;
-       int flag = 0;
-       float sx, sy;
-       VM_SAFEPARMCOUNTRANGE(5,6,VM_drawstring);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       string = PRVM_G_STRING(OFS_PARM1);
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       scale = PRVM_G_VECTOR(OFS_PARM2);
-       rgb = PRVM_G_VECTOR(OFS_PARM3);
-       if (prog->argc >= 6)
-               flag = (int)PRVM_G_FLOAT(OFS_PARM5);
-
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
-               return;
-       }
-
-       if(!scale[0] || !scale[1])
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -3;
-               VM_Warning(prog, "VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
-               return;
-       }
-
-       if(pos[2] || scale[2])
-               VM_Warning(prog, "VM_drawstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
-
-       getdrawfontscale(prog, &sx, &sy);
-       DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
-       //Font_DrawString(pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true);
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
-}
-
-/*
-=========
-VM_drawcolorcodedstring
-
-float  drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag)
-/
-float  drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
-=========
-*/
-void VM_drawcolorcodedstring(prvm_prog_t *prog)
-{
-       prvm_vec_t *pos, *scale;
-       const char  *string;
-       int flag;
-       vec3_t rgb;
-       float sx, sy, alpha;
-
-       VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       if (prog->argc == 6) // full 6 parms, like normal drawstring
-       {
-               pos = PRVM_G_VECTOR(OFS_PARM0);
-               string = PRVM_G_STRING(OFS_PARM1);
-               scale = PRVM_G_VECTOR(OFS_PARM2);
-               VectorCopy(PRVM_G_VECTOR(OFS_PARM3), rgb); 
-               alpha = PRVM_G_FLOAT(OFS_PARM4);
-               flag = (int)PRVM_G_FLOAT(OFS_PARM5);
-       }
-       else
-       {
-               pos = PRVM_G_VECTOR(OFS_PARM0);
-               string = PRVM_G_STRING(OFS_PARM1);
-               scale = PRVM_G_VECTOR(OFS_PARM2);
-               rgb[0] = 1.0;
-               rgb[1] = 1.0;
-               rgb[2] = 1.0;
-               alpha = PRVM_G_FLOAT(OFS_PARM3);
-               flag = (int)PRVM_G_FLOAT(OFS_PARM4);
-       }
-
-       if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
-               return;
-       }
-
-       if(!scale[0] || !scale[1])
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -3;
-               VM_Warning(prog, "VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
-               return;
-       }
-
-       if(pos[2] || scale[2])
-               VM_Warning(prog, "VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
-
-       getdrawfontscale(prog, &sx, &sy);
-       DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], alpha, flag, NULL, false, getdrawfont(prog));
-       if (prog->argc == 6) // also return vector of last color
-               VectorCopy(DrawQ_Color, PRVM_G_VECTOR(OFS_RETURN));
-       else
-               PRVM_G_FLOAT(OFS_RETURN) = 1;
-}
-/*
-=========
-VM_stringwidth
-
-float  stringwidth(string text, float allowColorCodes, float size)
-=========
-*/
-void VM_stringwidth(prvm_prog_t *prog)
-{
-       const char  *string;
-       vec2_t szv;
-       float mult; // sz is intended font size so we can later add freetype support, mult is font size multiplier in pixels per character cell
-       int colors;
-       float sx, sy;
-       size_t maxlen = 0;
-       VM_SAFEPARMCOUNTRANGE(2, 3, VM_stringwidth);
-
-       getdrawfontscale(prog, &sx, &sy);
-       if(prog->argc == 3)
-       {
-               Vector2Copy(PRVM_G_VECTOR(OFS_PARM2), szv);
-               mult = 1;
-       }
-       else
-       {
-               // we want the width for 8x8 font size, divided by 8
-               Vector2Set(szv, 8, 8);
-               mult = 0.125;
-               // to make sure snapping is turned off, ALWAYS use a nontrivial scale in this case
-               if(sx >= 0.9 && sx <= 1.1)
-               {
-                       mult *= 2;
-                       sx /= 2;
-                       sy /= 2;
-               }
-       }
-
-       string = PRVM_G_STRING(OFS_PARM0);
-       colors = (int)PRVM_G_FLOAT(OFS_PARM1);
-
-       PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth_UntilWidth_TrackColors_Scale(string, &maxlen, szv[0], szv[1], sx, sy, NULL, !colors, getdrawfont(prog), 1000000000) * mult;
-/*
-       if(prog->argc == 3)
-       {
-               mult = sz = PRVM_G_FLOAT(OFS_PARM2);
-       }
-       else
-       {
-               sz = 8;
-               mult = 1;
-       }
-
-       string = PRVM_G_STRING(OFS_PARM0);
-       colors = (int)PRVM_G_FLOAT(OFS_PARM1);
-
-       PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw
-*/
-}
-
-/*
-=========
-VM_findfont
-
-float findfont(string s)
-=========
-*/
-
-static float getdrawfontnum(const char *fontname)
-{
-       int i;
-
-       for(i = 0; i < dp_fonts.maxsize; ++i)
-               if(!strcmp(dp_fonts.f[i].title, fontname))
-                       return i;
-       return -1;
-}
-
-void VM_findfont(prvm_prog_t *prog)
-{
-       VM_SAFEPARMCOUNT(1,VM_findfont);
-       PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
-}
-
-/*
-=========
-VM_loadfont
-
-float loadfont(string fontname, string fontmaps, string sizes, float slot)
-=========
-*/
-
-void VM_loadfont(prvm_prog_t *prog)
-{
-       const char *fontname, *filelist, *sizes, *c, *cm;
-       char mainfont[MAX_QPATH];
-       int i, numsizes;
-       float sz, scale, voffset;
-       dp_font_t *f;
-
-       VM_SAFEPARMCOUNTRANGE(3,6,VM_loadfont);
-
-       fontname = PRVM_G_STRING(OFS_PARM0);
-       if (!fontname[0])
-               fontname = "default";
-
-       filelist = PRVM_G_STRING(OFS_PARM1);
-       if (!filelist[0])
-               filelist = "gfx/conchars";
-
-       sizes = PRVM_G_STRING(OFS_PARM2);
-       if (!sizes[0])
-               sizes = "10";
-
-       // find a font
-       f = NULL;
-       if (prog->argc >= 4)
-       {
-               i = PRVM_G_FLOAT(OFS_PARM3);
-               if (i >= 0 && i < dp_fonts.maxsize)
-               {
-                       f = &dp_fonts.f[i];
-                       strlcpy(f->title, fontname, sizeof(f->title)); // replace name
-               }
-       }
-       if (!f)
-               f = FindFont(fontname, true);
-       if (!f)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -1;
-               return; // something go wrong
-       }
-
-       memset(f->fallbacks, 0, sizeof(f->fallbacks));
-       memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
-
-       // first font is handled "normally"
-       c = strchr(filelist, ':');
-       cm = strchr(filelist, ',');
-       if(c && (!cm || c < cm))
-               f->req_face = atoi(c+1);
-       else
-       {
-               f->req_face = 0;
-               c = cm;
-       }
-       if(!c || (c - filelist) > MAX_QPATH)
-               strlcpy(mainfont, filelist, sizeof(mainfont));
-       else
-       {
-               memcpy(mainfont, filelist, c - filelist);
-               mainfont[c - filelist] = 0;
-       }
-
-       // handle fallbacks
-       for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
-       {
-               c = strchr(filelist, ',');
-               if(!c)
-                       break;
-               filelist = c + 1;
-               if(!*filelist)
-                       break;
-               c = strchr(filelist, ':');
-               cm = strchr(filelist, ',');
-               if(c && (!cm || c < cm))
-                       f->fallback_faces[i] = atoi(c+1);
-               else
-               {
-                       f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
-                       c = cm;
-               }
-               if(!c || (c-filelist) > MAX_QPATH)
-               {
-                       strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
-               }
-               else
-               {
-                       memcpy(f->fallbacks[i], filelist, c - filelist);
-                       f->fallbacks[i][c - filelist] = 0;
-               }
-       }
-
-       // handle sizes
-       for(i = 0; i < MAX_FONT_SIZES; ++i)
-               f->req_sizes[i] = -1;
-       for (numsizes = 0,c = sizes;;)
-       {
-               if (!COM_ParseToken_VM_Tokenize(&c, 0))
-                       break;
-               sz = atof(com_token);
-               // detect crap size
-               if (sz < 0.001f || sz > 1000.0f)
-               {
-                       VM_Warning(prog, "VM_loadfont: crap size %s", com_token);
-                       continue;
-               }
-               // check overflow
-               if (numsizes == MAX_FONT_SIZES)
-               {
-                       VM_Warning(prog, "VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
-                       break;
-               }
-               f->req_sizes[numsizes] = sz;
-               numsizes++;
-       }
-
-       // additional scale/hoffset parms
-       scale = 1;
-       voffset = 0;
-       if (prog->argc >= 5)
-       {
-               scale = PRVM_G_FLOAT(OFS_PARM4);
-               if (scale <= 0)
-                       scale = 1;
-       }
-       if (prog->argc >= 6)
-               voffset = PRVM_G_FLOAT(OFS_PARM5);
-
-       // load
-       LoadFont(true, mainfont, f, scale, voffset);
-
-       // return index of loaded font
-       PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f);
-}
-
-/*
-=========
-VM_drawpic
-
-float  drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
-=========
-*/
-void VM_drawpic(prvm_prog_t *prog)
-{
-       const char *picname;
-       prvm_vec_t *size, *pos, *rgb;
-       int flag = 0;
-
-       VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       picname = PRVM_G_STRING(OFS_PARM1);
-       VM_CheckEmptyString(prog, picname);
-
-       // is pic cached ? no function yet for that
-       if(!1)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning(prog, "VM_drawpic: %s: %s not cached !\n", prog->name, picname);
-               return;
-       }
-
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       size = PRVM_G_VECTOR(OFS_PARM2);
-       rgb = PRVM_G_VECTOR(OFS_PARM3);
-       if (prog->argc >= 6)
-               flag = (int) PRVM_G_FLOAT(OFS_PARM5);
-
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
-               return;
-       }
-
-       if(pos[2] || size[2])
-               VM_Warning(prog, "VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
-
-       DrawQ_Pic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
-}
-/*
-=========
-VM_drawrotpic
-
-float  drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag)
+float search_begin(string pattern, float caseinsensitive, float quiet[, string packfile])
 =========
 */
-void VM_drawrotpic(prvm_prog_t *prog)
+void VM_search_begin(prvm_prog_t *prog)
 {
-       const char *picname;
-       prvm_vec_t *size, *pos, *org, *rgb;
-       int flag;
+       int handle;
+       const char *packfile = NULL, *pattern;
+       int caseinsens, quiet;
+
+       VM_SAFEPARMCOUNTRANGE(3, 4, VM_search_begin);
 
-       VM_SAFEPARMCOUNT(8,VM_drawrotpic);
+       pattern = PRVM_G_STRING(OFS_PARM0);
 
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
+       VM_CheckEmptyString(prog, pattern);
 
-       picname = PRVM_G_STRING(OFS_PARM1);
-       VM_CheckEmptyString(prog, picname);
+       caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1);
+       quiet = (int)PRVM_G_FLOAT(OFS_PARM2);
 
-       // is pic cached ? no function yet for that
-       if(!1)
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning(prog, "VM_drawrotpic: %s: %s not cached !\n", prog->name, picname);
-               return;
-       }
+       // optional packfile parameter (DP_QC_FS_SEARCH_PACKFILE)
+       if(prog->argc >= 4)
+               packfile = PRVM_G_STRING(OFS_PARM3);
 
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       size = PRVM_G_VECTOR(OFS_PARM2);
-       org = PRVM_G_VECTOR(OFS_PARM3);
-       rgb = PRVM_G_VECTOR(OFS_PARM5);
-       flag = (int) PRVM_G_FLOAT(OFS_PARM7);
+       for(handle = 0; handle < PRVM_MAX_OPENSEARCHES; handle++)
+               if(!prog->opensearches[handle])
+                       break;
 
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
+       if(handle >= PRVM_MAX_OPENSEARCHES)
        {
                PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
+               VM_Warning(prog, "VM_search_begin: %s ran out of search handles (%i)\n", prog->name, PRVM_MAX_OPENSEARCHES);
                return;
        }
 
-       if(pos[2] || size[2] || org[2])
-               VM_Warning(prog, "VM_drawrotpic: z value from pos/size/org discarded\n");
-
-       DrawQ_RotPic(pos[0], pos[1], Draw_CachePic_Flags(picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag);
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
+       if(!(prog->opensearches[handle] = FS_Search(pattern,caseinsens, quiet, packfile)))
+               PRVM_G_FLOAT(OFS_RETURN) = -1;
+       else
+       {
+               prog->opensearches_origin[handle] = PRVM_AllocationOrigin(prog);
+               PRVM_G_FLOAT(OFS_RETURN) = handle;
+       }
 }
+
 /*
 =========
-VM_drawsubpic
-
-float  drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag)
+VM_search_end
 
+void   search_end(float handle)
 =========
 */
-void VM_drawsubpic(prvm_prog_t *prog)
+void VM_search_end(prvm_prog_t *prog)
 {
-       const char *picname;
-       prvm_vec_t *size, *pos, *rgb, *srcPos, *srcSize, alpha;
-       int flag;
-
-       VM_SAFEPARMCOUNT(8,VM_drawsubpic);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
+       int handle;
+       VM_SAFEPARMCOUNT(1, VM_search_end);
 
-       picname = PRVM_G_STRING(OFS_PARM2);
-       VM_CheckEmptyString(prog, picname);
+       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
 
-       // is pic cached ? no function yet for that
-       if(!1)
+       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
        {
-               PRVM_G_FLOAT(OFS_RETURN) = -4;
-               VM_Warning(prog, "VM_drawsubpic: %s: %s not cached !\n", prog->name, picname);
+               VM_Warning(prog, "VM_search_end: invalid handle %i used in %s\n", handle, prog->name);
                return;
        }
-
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       size = PRVM_G_VECTOR(OFS_PARM1);
-       srcPos = PRVM_G_VECTOR(OFS_PARM3);
-       srcSize = PRVM_G_VECTOR(OFS_PARM4);
-       rgb = PRVM_G_VECTOR(OFS_PARM5);
-       alpha = PRVM_G_FLOAT(OFS_PARM6);
-       flag = (int) PRVM_G_FLOAT(OFS_PARM7);
-
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
+       if(prog->opensearches[handle] == NULL)
        {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
+               VM_Warning(prog, "VM_search_end: no such handle %i in %s\n", handle, prog->name);
                return;
        }
 
-       if(pos[2] || size[2])
-               VM_Warning(prog, "VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
-
-       DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT),
-               size[0], size[1],
-               srcPos[0],              srcPos[1],              rgb[0], rgb[1], rgb[2], alpha,
-               srcPos[0] + srcSize[0], srcPos[1],              rgb[0], rgb[1], rgb[2], alpha,
-               srcPos[0],              srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
-               srcPos[0] + srcSize[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
-               flag);
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
+       FS_FreeSearch(prog->opensearches[handle]);
+       prog->opensearches[handle] = NULL;
+       if(prog->opensearches_origin[handle])
+               PRVM_Free((char *)prog->opensearches_origin[handle]);
 }
 
 /*
 =========
-VM_drawfill
+VM_search_getsize
 
-float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
+float  search_getsize(float handle)
 =========
 */
-void VM_drawfill(prvm_prog_t *prog)
+void VM_search_getsize(prvm_prog_t *prog)
 {
-       prvm_vec_t *size, *pos, *rgb;
-       int flag;
-
-       VM_SAFEPARMCOUNT(5,VM_drawfill);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
+       int handle;
+       VM_SAFEPARMCOUNT(1, VM_search_getsize);
 
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       size = PRVM_G_VECTOR(OFS_PARM1);
-       rgb = PRVM_G_VECTOR(OFS_PARM2);
-       flag = (int) PRVM_G_FLOAT(OFS_PARM4);
+       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
 
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
+       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
        {
-               PRVM_G_FLOAT(OFS_RETURN) = -2;
-               VM_Warning(prog, "VM_drawfill: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
+               VM_Warning(prog, "VM_search_getsize: invalid handle %i used in %s\n", handle, prog->name);
+               return;
+       }
+       if(prog->opensearches[handle] == NULL)
+       {
+               VM_Warning(prog, "VM_search_getsize: no such handle %i in %s\n", handle, prog->name);
                return;
        }
 
-       if(pos[2] || size[2])
-               VM_Warning(prog, "VM_drawfill: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
-
-       DrawQ_Fill(pos[0], pos[1], size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
+       PRVM_G_FLOAT(OFS_RETURN) = prog->opensearches[handle]->numfilenames;
 }
 
 /*
 =========
-VM_drawsetcliparea
+VM_search_getfilename
 
-drawsetcliparea(float x, float y, float width, float height)
+string search_getfilename(float handle, float num)
 =========
 */
-void VM_drawsetcliparea(prvm_prog_t *prog)
+void VM_search_getfilename(prvm_prog_t *prog)
 {
-       float x,y,w,h;
-       VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid_conwidth.integer);
-       y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid_conheight.integer);
-       w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid_conwidth.integer  - x));
-       h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid_conheight.integer - y));
-
-       DrawQ_SetClipArea(x, y, w, h);
-}
+       int handle, filenum;
 
-/*
-=========
-VM_drawresetcliparea
+       VM_SAFEPARMCOUNT(2, VM_search_getfilename);
 
-drawresetcliparea()
-=========
-*/
-void VM_drawresetcliparea(prvm_prog_t *prog)
-{
-       VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
+       handle = (int)PRVM_G_FLOAT(OFS_PARM0);
+       filenum = (int)PRVM_G_FLOAT(OFS_PARM1);
 
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
+       if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
+       {
+               VM_Warning(prog, "VM_search_getfilename: invalid handle %i used in %s\n", handle, prog->name);
+               return;
+       }
+       if(prog->opensearches[handle] == NULL)
+       {
+               VM_Warning(prog, "VM_search_getfilename: no such handle %i in %s\n", handle, prog->name);
+               return;
+       }
+       if(filenum < 0 || filenum >= prog->opensearches[handle]->numfilenames)
+       {
+               VM_Warning(prog, "VM_search_getfilename: invalid filenum %i in %s\n", filenum, prog->name);
+               return;
+       }
 
-       DrawQ_ResetClipArea();
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog,
+                                                   prog->opensearches[handle]->filenames[filenum],
+                                                   strlen(prog->opensearches[handle]->filenames[filenum]));
 }
 
 /*
 =========
-VM_getimagesize
+VM_chr
 
-vector getimagesize(string pic)
+string chr(float ascii)
 =========
 */
-void VM_getimagesize(prvm_prog_t *prog)
+void VM_chr(prvm_prog_t *prog)
 {
-       const char *p;
-       cachepic_t *pic;
+       /*
+       char tmp[2];
+       VM_SAFEPARMCOUNT(1, VM_chr);
 
-       VM_SAFEPARMCOUNT(1,VM_getimagesize);
+       tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
+       tmp[1] = 0;
 
-       p = PRVM_G_STRING(OFS_PARM0);
-       VM_CheckEmptyString(prog, p);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
+       */
+       
+       char tmp[8];
+       int len;
 
-       pic = Draw_CachePic_Flags (p, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOTPERSISTENT);
-       if (!Draw_IsPicLoaded(pic))
-       {
-               PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
-               PRVM_G_VECTOR(OFS_RETURN)[1] = 0;
-       }
-       else
-       {
-               PRVM_G_VECTOR(OFS_RETURN)[0] = Draw_GetPicWidth(pic);
-               PRVM_G_VECTOR(OFS_RETURN)[1] = Draw_GetPicHeight(pic);
-       }
-       PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
+       VM_SAFEPARMCOUNT(1, VM_chr);
+       len = u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0), tmp, sizeof(tmp));
+       tmp[len] = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp, len);
 }
 
 /*
@@ -3978,10 +3330,12 @@ string keynumtostring(float keynum)
 */
 void VM_keynumtostring (prvm_prog_t *prog)
 {
-       char tinystr[2];
-       VM_SAFEPARMCOUNT(1, VM_keynumtostring);
+       char tinystr[TINYSTR_LEN];
+       const char *str; // Key_KeynumToString doesn't always return tinystr
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0), tinystr, sizeof(tinystr)));
+       VM_SAFEPARMCOUNT(1, VM_keynumtostring);
+       str = Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0), tinystr, sizeof(tinystr));
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, str, strlen(str));
 }
 
 /*
@@ -3998,7 +3352,8 @@ void M_FindKeysForCommand(const char *command, int *keys);
 void VM_findkeysforcommand(prvm_prog_t *prog)
 {
        const char *cmd;
-       char ret[VM_STRINGTEMP_LENGTH];
+       char ret[VM_TEMPSTRING_MAXSIZE];
+       size_t ret_len;
        int keys[FKFC_NUMKEYS];
        int i;
        int bindmap;
@@ -4018,9 +3373,9 @@ void VM_findkeysforcommand(prvm_prog_t *prog)
 
        ret[0] = 0;
        for(i = 0; i < FKFC_NUMKEYS; i++)
-               strlcat(ret, va(vabuf, sizeof(vabuf), " \'%i\'", keys[i]), sizeof(ret));
+               ret_len = dp_strlcat(ret, va(vabuf, sizeof(vabuf), " \'%i\'", keys[i]), sizeof(ret));
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ret);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ret, ret_len);
 }
 
 /*
@@ -4047,13 +3402,15 @@ string getkeybind(float key, float bindmap)
 void VM_getkeybind (prvm_prog_t *prog)
 {
        int bindmap;
+       const char *bind;
+
        VM_SAFEPARMCOUNTRANGE(1, 2, VM_getkeybind);
        if(prog->argc == 2)
                bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1);
        else
                bindmap = 0; // consistent to "bind"
-
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap));
+       bind = Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap);
+       PRVM_G_INT(OFS_RETURN) = bind ? PRVM_SetTempString(prog, bind, strlen(bind)) : 0;
 }
 
 /*
@@ -4110,123 +3467,6 @@ void VM_setbindmaps (prvm_prog_t *prog)
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
 }
 
-// CL_Video interface functions
-
-/*
-========================
-VM_cin_open
-
-float cin_open(string file, string name)
-========================
-*/
-void VM_cin_open(prvm_prog_t *prog)
-{
-       const char *file;
-       const char *name;
-
-       VM_SAFEPARMCOUNT( 2, VM_cin_open );
-
-       file = PRVM_G_STRING( OFS_PARM0 );
-       name = PRVM_G_STRING( OFS_PARM1 );
-
-       VM_CheckEmptyString(prog,  file );
-    VM_CheckEmptyString(prog,  name );
-
-       if( CL_OpenVideo( file, name, MENUOWNER, "" ) )
-               PRVM_G_FLOAT( OFS_RETURN ) = 1;
-       else
-               PRVM_G_FLOAT( OFS_RETURN ) = 0;
-}
-
-/*
-========================
-VM_cin_close
-
-void cin_close(string name)
-========================
-*/
-void VM_cin_close(prvm_prog_t *prog)
-{
-       const char *name;
-
-       VM_SAFEPARMCOUNT( 1, VM_cin_close );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString(prog,  name );
-
-       CL_CloseVideo( CL_GetVideoByName( name ) );
-}
-
-/*
-========================
-VM_cin_setstate
-void cin_setstate(string name, float type)
-========================
-*/
-void VM_cin_setstate(prvm_prog_t *prog)
-{
-       const char *name;
-       clvideostate_t  state;
-       clvideo_t               *video;
-
-       VM_SAFEPARMCOUNT( 2, VM_cin_setstate );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString(prog,  name );
-
-       state = (clvideostate_t)((int)PRVM_G_FLOAT( OFS_PARM1 ));
-
-       video = CL_GetVideoByName( name );
-       if( video && state > CLVIDEO_UNUSED && state < CLVIDEO_STATECOUNT )
-               CL_SetVideoState( video, state );
-}
-
-/*
-========================
-VM_cin_getstate
-
-float cin_getstate(string name)
-========================
-*/
-void VM_cin_getstate(prvm_prog_t *prog)
-{
-       const char *name;
-       clvideo_t               *video;
-
-       VM_SAFEPARMCOUNT( 1, VM_cin_getstate );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString(prog,  name );
-
-       video = CL_GetVideoByName( name );
-       if( video )
-               PRVM_G_FLOAT( OFS_RETURN ) = (int)video->state;
-       else
-               PRVM_G_FLOAT( OFS_RETURN ) = 0;
-}
-
-/*
-========================
-VM_cin_restart
-
-void cin_restart(string name)
-========================
-*/
-void VM_cin_restart(prvm_prog_t *prog)
-{
-       const char *name;
-       clvideo_t               *video;
-
-       VM_SAFEPARMCOUNT( 1, VM_cin_restart );
-
-       name = PRVM_G_STRING( OFS_PARM0 );
-       VM_CheckEmptyString(prog,  name );
-
-       video = CL_GetVideoByName( name );
-       if( video )
-               CL_RestartVideo( video );
-}
-
 /*
 ========================
 VM_gecko_create
@@ -4350,33 +3590,6 @@ void VM_vectorvectors (prvm_prog_t *prog)
        VectorCopy(up, PRVM_gameglobalvector(v_up));
 }
 
-/*
-========================
-VM_drawline
-
-void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags)
-========================
-*/
-void VM_drawline (prvm_prog_t *prog)
-{
-       prvm_vec_t      *c1, *c2, *rgb;
-       float   alpha, width;
-       unsigned char   flags;
-
-       VM_SAFEPARMCOUNT(6, VM_drawline);
-
-       // polygonbegin without draw2d arg has to guess
-       prog->polygonbegin_guess2d = true;
-
-       width   = PRVM_G_FLOAT(OFS_PARM0);
-       c1              = PRVM_G_VECTOR(OFS_PARM1);
-       c2              = PRVM_G_VECTOR(OFS_PARM2);
-       rgb             = PRVM_G_VECTOR(OFS_PARM3);
-       alpha   = PRVM_G_FLOAT(OFS_PARM4);
-       flags   = (int)PRVM_G_FLOAT(OFS_PARM5);
-       DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags);
-}
-
 // float(float number, float quantity) bitshift (EXT_BITSHIFT)
 void VM_bitshift (prvm_prog_t *prog)
 {
@@ -4438,7 +3651,7 @@ string altstr_prepare(string)
 void VM_altstr_prepare(prvm_prog_t *prog)
 {
        const char *instr, *in;
-       char outstr[VM_STRINGTEMP_LENGTH];
+       char outstr[VM_TEMPSTRING_MAXSIZE];
        size_t outpos;
 
        VM_SAFEPARMCOUNT( 1, VM_altstr_prepare );
@@ -4455,9 +3668,9 @@ void VM_altstr_prepare(prvm_prog_t *prog)
                else
                        outstr[outpos++] = *in;
        }
-       outstr[outpos] = 0;
 
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
+       outstr[outpos] = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, outpos);
 }
 
 /*
@@ -4472,7 +3685,7 @@ void VM_altstr_get(prvm_prog_t *prog)
        const char *altstr, *pos;
        char *out;
        int count, size;
-       char outstr[VM_STRINGTEMP_LENGTH];
+       char outstr[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT( 2, VM_altstr_get );
 
@@ -4504,8 +3717,8 @@ void VM_altstr_get(prvm_prog_t *prog)
                else
                        *out = *pos;
 
-       *out = 0;
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
+       *out = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
 }
 
 /*
@@ -4521,7 +3734,7 @@ void VM_altstr_set(prvm_prog_t *prog)
        const char *altstr, *str;
        const char *in;
        char *out;
-       char outstr[VM_STRINGTEMP_LENGTH];
+       char outstr[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT( 3, VM_altstr_set );
 
@@ -4548,8 +3761,8 @@ void VM_altstr_set(prvm_prog_t *prog)
                if( *in == '\'' || (*in == '\\' && !*++in) )
                        break;
 
-       strlcpy(out, in, outstr + sizeof(outstr) - out);
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
+       out += dp_strlcpy(out, in, outstr + sizeof(outstr) - out);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
 }
 
 /*
@@ -4565,7 +3778,7 @@ void VM_altstr_ins(prvm_prog_t *prog)
        const char *set;
        const char *in;
        char *out;
-       char outstr[VM_STRINGTEMP_LENGTH];
+       char outstr[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT(3, VM_altstr_ins);
 
@@ -4587,8 +3800,8 @@ void VM_altstr_ins(prvm_prog_t *prog)
        for( ; *set ; *out++ = *set++ );
        *out++ = '\'';
 
-       strlcpy(out, in, outstr + sizeof(outstr) - out);
-       PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog,  outstr );
+       out += dp_strlcpy(out, in, outstr + sizeof(outstr) - out);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
 }
 
 
@@ -4651,7 +3864,7 @@ static int BufStr_SortStringsDOWN (const void *in1, const void *in2)
        return strncmp(b, a, stringbuffers_sortlength);
 }
 
-prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, int flags, const char *format)
+prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, unsigned flags, const char *format)
 {
        prvm_stringbuffer_t *stringbuffer;
        int i;
@@ -4915,10 +4128,12 @@ string buf_implode(float bufhandle, string glue) = #465;
 void VM_buf_implode (prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
-       char                    k[VM_STRINGTEMP_LENGTH];
-       const char              *sep;
-       int                             i;
-       size_t                  l;
+       char k[VM_TEMPSTRING_MAXSIZE];
+       size_t k_len;
+       const char *sep;
+       int i;
+       size_t l;
+
        VM_SAFEPARMCOUNT(2, VM_buf_implode);
 
        stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, (int)PRVM_G_FLOAT(OFS_PARM0));
@@ -4931,7 +4146,8 @@ void VM_buf_implode (prvm_prog_t *prog)
        if(!stringbuffer->num_strings)
                return;
        sep = PRVM_G_STRING(OFS_PARM1);
-       k[0] = 0;
+       k[0] = '\0';
+       k_len = 0;
        for(l = i = 0;i < stringbuffer->num_strings;i++)
        {
                if(stringbuffer->strings[i])
@@ -4939,11 +4155,11 @@ void VM_buf_implode (prvm_prog_t *prog)
                        l += (i > 0 ? strlen(sep) : 0) + strlen(stringbuffer->strings[i]);
                        if (l >= sizeof(k) - 1)
                                break;
-                       strlcat(k, sep, sizeof(k));
-                       strlcat(k, stringbuffer->strings[i], sizeof(k));
+                       dp_strlcat(k, sep, sizeof(k));
+                       k_len = dp_strlcat(k, stringbuffer->strings[i], sizeof(k));
                }
        }
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, k);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, k, k_len);
 }
 
 /*
@@ -4973,7 +4189,7 @@ void VM_bufstr_get (prvm_prog_t *prog)
                return;
        }
        if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex])
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, stringbuffer->strings[strindex]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, stringbuffer->strings[strindex], strlen(stringbuffer->strings[strindex]));
 }
 
 /*
@@ -5103,7 +4319,7 @@ void VM_buf_loadfile(prvm_prog_t *prog)
 {
        size_t alloclen;
        prvm_stringbuffer_t *stringbuffer;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int strindex, c, end;
        const char *filename;
        char vabuf[1024];
@@ -5144,7 +4360,7 @@ void VM_buf_loadfile(prvm_prog_t *prog)
                        c = FS_Getc(file);
                        if (c == '\r' || c == '\n' || c < 0)
                                break;
-                       if (end < VM_STRINGTEMP_LENGTH - 1)
+                       if (end < VM_TEMPSTRING_MAXSIZE - 1)
                                string[end++] = c;
                }
                string[end] = 0;
@@ -5348,7 +4564,7 @@ float bufstr_find(float bufhandle, string match, float matchrule, float startpos
 void VM_bufstr_find(prvm_prog_t *prog)
 {
        prvm_stringbuffer_t *stringbuffer;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int matchrule, matchlen, i, step;
        const char *match;
 
@@ -5375,7 +4591,7 @@ void VM_bufstr_find(prvm_prog_t *prog)
                match = PRVM_G_STRING(OFS_PARM1);
        else
        {
-               strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
+               dp_strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
                match = detect_match_rule(string, &matchrule);
        }
        matchlen = (int)strlen(match);
@@ -5385,7 +4601,7 @@ void VM_bufstr_find(prvm_prog_t *prog)
        step = (prog->argc > 4) ? (int)PRVM_G_FLOAT(OFS_PARM4) : 1;
        while(i < stringbuffer->num_strings)
        {
-               if (stringbuffer->strings[i] && match_rule(stringbuffer->strings[i], VM_STRINGTEMP_LENGTH, match, matchlen, matchrule))
+               if (stringbuffer->strings[i] && match_rule(stringbuffer->strings[i], VM_TEMPSTRING_MAXSIZE, match, matchlen, matchrule))
                {
                        PRVM_G_FLOAT(OFS_RETURN) = i;
                        break;
@@ -5403,7 +4619,7 @@ float matchpattern(string s, string pattern, float matchrule, float startpos) =
 void VM_matchpattern(prvm_prog_t *prog)
 {
        const char *s, *match;
-       char string[VM_STRINGTEMP_LENGTH];
+       char string[VM_TEMPSTRING_MAXSIZE];
        int matchrule, l;
 
        VM_SAFEPARMCOUNTRANGE(2, 4, VM_matchpattern);
@@ -5421,7 +4637,7 @@ void VM_matchpattern(prvm_prog_t *prog)
                match = PRVM_G_STRING(OFS_PARM1);
        else
        {
-               strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
+               dp_strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
                match = detect_match_rule(string, &matchrule);
        }
 
@@ -5431,7 +4647,7 @@ void VM_matchpattern(prvm_prog_t *prog)
                s += max(0, min((unsigned int)PRVM_G_FLOAT(OFS_PARM3), strlen(s)-1));
 
        // match
-       PRVM_G_FLOAT(OFS_RETURN) = match_rule(s, VM_STRINGTEMP_LENGTH, match, l, matchrule);
+       PRVM_G_FLOAT(OFS_RETURN) = match_rule(s, VM_TEMPSTRING_MAXSIZE, match, l, matchrule);
 }
 
 /*
@@ -5543,7 +4759,7 @@ void VM_changeyaw (prvm_prog_t *prog)
                VM_Warning(prog, "changeyaw: can not modify world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "changeyaw: can not modify free entity\n");
                return;
@@ -5599,7 +4815,7 @@ void VM_changepitch (prvm_prog_t *prog)
                VM_Warning(prog, "changepitch: can not modify world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "changepitch: can not modify free entity\n");
                return;
@@ -5640,15 +4856,15 @@ void VM_changepitch (prvm_prog_t *prog)
 
 void VM_uncolorstring (prvm_prog_t *prog)
 {
-       char szNewString[VM_STRINGTEMP_LENGTH];
+       char szNewString[VM_TEMPSTRING_MAXSIZE];
+       size_t szNewString_len;
        const char *szString;
 
        // Prepare Strings
        VM_SAFEPARMCOUNT(1, VM_uncolorstring);
        szString = PRVM_G_STRING(OFS_PARM0);
-       COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
-       
+       szNewString_len = COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
 }
 
 // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
@@ -5713,11 +4929,12 @@ void VM_chr2str (prvm_prog_t *prog)
        char t[9 * 4 + 1];
        int i;
        size_t len = 0;
+
        VM_SAFEPARMCOUNTRANGE(0, 8, VM_chr2str);
        for(i = 0; i < prog->argc && len < sizeof(t)-1; ++i)
                len += u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0+i*3), t + len, sizeof(t)-1);
-       t[len] = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
+       t[len] = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t, len);
 }
 
 static int chrconv_number(int i, int base, int conv)
@@ -5804,8 +5021,10 @@ static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int
 //bulk convert a string. change case or colouring.
 void VM_strconv (prvm_prog_t *prog)
 {
-       int ccase, redalpha, rednum, len, i;
-       unsigned char resbuf[VM_STRINGTEMP_LENGTH];
+       int ccase, redalpha, rednum;
+       unsigned i;
+       size_t resbuf_len;
+       unsigned char resbuf[VM_TEMPSTRING_MAXSIZE];
        unsigned char *result = resbuf;
 
        VM_SAFEPARMCOUNTRANGE(3, 8, VM_strconv);
@@ -5813,10 +5032,9 @@ void VM_strconv (prvm_prog_t *prog)
        ccase = (int) PRVM_G_FLOAT(OFS_PARM0);  //0 same, 1 lower, 2 upper
        redalpha = (int) PRVM_G_FLOAT(OFS_PARM1);       //0 same, 1 white, 2 red,  5 alternate, 6 alternate-alternate
        rednum = (int) PRVM_G_FLOAT(OFS_PARM2); //0 same, 1 white, 2 red, 3 redspecial, 4 whitespecial, 5 alternate, 6 alternate-alternate
-       VM_VarString(prog, 3, (char *) resbuf, sizeof(resbuf));
-       len = (int)strlen((char *) resbuf);
+       resbuf_len = VM_VarString(prog, 3, (char *) resbuf, sizeof(resbuf));
 
-       for (i = 0; i < len; i++, result++)     //should this be done backwards?
+       for (i = 0; i < resbuf_len; i++, result++)      //should this be done backwards?
        {
                if (*result >= '0' && *result <= '9')   //normal numbers...
                        *result = chrconv_number(*result, '0', rednum);
@@ -5845,24 +5063,26 @@ void VM_strconv (prvm_prog_t *prog)
        }
        *result = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, (char *) resbuf);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, (char *)resbuf, result - resbuf);
 }
 
 // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
 void VM_strpad (prvm_prog_t *prog)
 {
-       char src[VM_STRINGTEMP_LENGTH];
-       char destbuf[VM_STRINGTEMP_LENGTH];
+       char src[VM_TEMPSTRING_MAXSIZE];
+       char destbuf[VM_TEMPSTRING_MAXSIZE];
+       size_t destbuf_len;
        int pad;
+
        VM_SAFEPARMCOUNTRANGE(1, 8, VM_strpad);
        pad = (int) PRVM_G_FLOAT(OFS_PARM0);
        VM_VarString(prog, 1, src, sizeof(src));
 
        // note: < 0 = left padding, > 0 = right padding,
        // this is reverse logic of printf!
-       dpsnprintf(destbuf, sizeof(destbuf), "%*s", -pad, src);
+       destbuf_len = dpsnprintf(destbuf, sizeof(destbuf), "%*s", -pad, src);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, destbuf);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, destbuf, destbuf_len);
 }
 
 // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
@@ -5870,19 +5090,19 @@ void VM_strpad (prvm_prog_t *prog)
 void VM_infoadd (prvm_prog_t *prog)
 {
        const char *info, *key;
-       char value[VM_STRINGTEMP_LENGTH];
-       char temp[VM_STRINGTEMP_LENGTH];
+       char value[VM_TEMPSTRING_MAXSIZE];
+       char temp[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_infoadd);
        info = PRVM_G_STRING(OFS_PARM0);
        key = PRVM_G_STRING(OFS_PARM1);
        VM_VarString(prog, 2, value, sizeof(value));
 
-       strlcpy(temp, info, VM_STRINGTEMP_LENGTH);
+       dp_strlcpy(temp, info, VM_TEMPSTRING_MAXSIZE);
 
-       InfoString_SetValue(temp, VM_STRINGTEMP_LENGTH, key, value);
+       InfoString_SetValue(temp, VM_TEMPSTRING_MAXSIZE, key, value);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, temp);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, temp, strlen(temp));
 }
 
 // #227 string(string info, string key) infoget (FTE_STRINGS)
@@ -5891,15 +5111,15 @@ void VM_infoget (prvm_prog_t *prog)
 {
        const char *info;
        const char *key;
-       char value[VM_STRINGTEMP_LENGTH];
+       char value[VM_TEMPSTRING_MAXSIZE];
 
        VM_SAFEPARMCOUNT(2, VM_infoget);
        info = PRVM_G_STRING(OFS_PARM0);
        key = PRVM_G_STRING(OFS_PARM1);
 
-       InfoString_GetValue(info, key, value, VM_STRINGTEMP_LENGTH);
+       InfoString_GetValue(info, key, value, VM_TEMPSTRING_MAXSIZE);
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, value);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, value, strlen(value));
 }
 
 //#228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
@@ -5942,11 +5162,13 @@ void VM_strncasecmp (prvm_prog_t *prog)
 void VM_crc16(prvm_prog_t *prog)
 {
        float insensitive;
-       char s[VM_STRINGTEMP_LENGTH];
+       char s[VM_TEMPSTRING_MAXSIZE];
+       size_t slen;
+
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_crc16);
        insensitive = PRVM_G_FLOAT(OFS_PARM0);
-       VM_VarString(prog, 1, s, sizeof(s));
-       PRVM_G_FLOAT(OFS_RETURN) = (unsigned short) ((insensitive ? CRC_Block_CaseInsensitive : CRC_Block) ((unsigned char *) s, strlen(s)));
+       slen = VM_VarString(prog, 1, s, sizeof(s));
+       PRVM_G_FLOAT(OFS_RETURN) = (unsigned short) ((insensitive ? CRC_Block_CaseInsensitive : CRC_Block) ((unsigned char *) s, slen));
 }
 
 // #639 float(string digest, string data, ...) digest_hex
@@ -5958,15 +5180,14 @@ void VM_digest_hex(prvm_prog_t *prog)
        char outhex[65];
        int outlen;
 
-       char s[VM_STRINGTEMP_LENGTH];
-       int len;
+       char s[VM_TEMPSTRING_MAXSIZE];
+       size_t len;
 
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_digest_hex);
        digest = PRVM_G_STRING(OFS_PARM0);
        if(!digest)
                digest = "";
-       VM_VarString(prog, 1, s, sizeof(s));
-       len = (int)strlen(s);
+       len = VM_VarString(prog, 1, s, sizeof(s));
 
        outlen = 0;
 
@@ -5991,8 +5212,8 @@ void VM_digest_hex(prvm_prog_t *prog)
                        outhex[2*i]   = hexmap[(out[i] >> 4) & 15];
                        outhex[2*i+1] = hexmap[(out[i] >> 0) & 15];
                }
-               outhex[2*i] = 0;
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outhex);
+               outhex[2*i] = '\0';
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outhex, 2*i);
        }
        else
                PRVM_G_INT(OFS_RETURN) = 0;
@@ -6001,7 +5222,7 @@ void VM_digest_hex(prvm_prog_t *prog)
 void VM_wasfreed (prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_wasfreed);
-       PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICT(OFS_PARM0)->priv.required->free;
+       PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICT(OFS_PARM0)->free;
 }
 
 void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace)
@@ -6018,7 +5239,7 @@ void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace)
        PRVM_gameglobalfloat(trace_dpstartcontents) = trace->startsupercontents;
        PRVM_gameglobalfloat(trace_dphitcontents) = trace->hitsupercontents;
        PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = trace->hitq3surfaceflags;
-       PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(prog, trace->hittexture->name) : 0;
+       PRVM_gameglobalstring(trace_dphittexturename) = trace->hittexture ? PRVM_SetTempString(prog, trace->hittexture->name, strlen(trace->hittexture->name)) : 0;
 }
 
 void VM_ClearTraceGlobals(prvm_prog_t *prog)
@@ -6062,8 +5283,8 @@ void VM_Cmd_Reset(prvm_prog_t *prog)
 // does URI escaping on a string (replace evil stuff by %AB escapes)
 void VM_uri_escape (prvm_prog_t *prog)
 {
-       char src[VM_STRINGTEMP_LENGTH];
-       char dest[VM_STRINGTEMP_LENGTH];
+       char src[VM_TEMPSTRING_MAXSIZE];
+       char dest[VM_TEMPSTRING_MAXSIZE];
        char *p, *q;
        static const char *hex = "0123456789ABCDEF";
 
@@ -6086,17 +5307,17 @@ void VM_uri_escape (prvm_prog_t *prog)
                        *q++ = hex[ *(unsigned char *)p       & 0xF];
                }
        }
-       *q++ = 0;
+       *q = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest, q - dest);
 }
 
 // #510 string(string input, ...) uri_unescape (DP_QC_URI_ESCAPE)
 // does URI unescaping on a string (get back the evil stuff)
 void VM_uri_unescape (prvm_prog_t *prog)
 {
-       char src[VM_STRINGTEMP_LENGTH];
-       char dest[VM_STRINGTEMP_LENGTH];
+       char src[VM_TEMPSTRING_MAXSIZE];
+       char dest[VM_TEMPSTRING_MAXSIZE];
        char *p, *q;
        int hi, lo;
 
@@ -6133,9 +5354,9 @@ nohex:
                // otherwise:
                *q++ = *p++;
        }
-       *q++ = 0;
+       *q = '\0';
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest, q - dest);
 }
 
 // #502 string(string filename) whichpack (DP_QC_WHICHPACK)
@@ -6148,7 +5369,7 @@ void VM_whichpack (prvm_prog_t *prog)
        fn = PRVM_G_STRING(OFS_PARM0);
        pack = FS_WhichPack(fn);
 
-       PRVM_G_INT(OFS_RETURN) = pack ? PRVM_SetTempString(prog, pack) : 0;
+       PRVM_G_INT(OFS_RETURN) = pack ? PRVM_SetTempString(prog, pack, strlen(pack)) : 0;
 }
 
 typedef struct
@@ -6186,11 +5407,11 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
        {
                if(length_received >= sizeof(handle->buffer))
                        length_received = sizeof(handle->buffer) - 1;
-               handle->buffer[length_received] = 0;
+               handle->buffer[length_received] = '\0';
 
                PRVM_G_FLOAT(OFS_PARM0) = handle->id;
                PRVM_G_FLOAT(OFS_PARM1) = status;
-               PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(prog, handle->buffer);
+               PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(prog, handle->buffer, length_received);
                prog->ExecuteProgram(prog, PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
        }
 
@@ -6297,7 +5518,7 @@ void VM_uri_get (prvm_prog_t *prog)
                        // POST: we sign postdata \0 query string
                        size_t ll;
                        handle->sigdata = (char *)Z_Malloc(8192);
-                       strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
+                       dp_strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
                        l = strlen(handle->sigdata);
                        handle->siglen = Crypto_SignDataDetached(handle->postdata, handle->postlen + 1 + lq, postkeyid, handle->sigdata + l, 8192 - l);
                        if(!handle->siglen)
@@ -6317,7 +5538,7 @@ void VM_uri_get (prvm_prog_t *prog)
                        handle->sigdata[handle->siglen] = 0;
                }
 out1:
-               strlcpy(handle->posttype, posttype, sizeof(handle->posttype));
+               dp_strlcpy(handle->posttype, posttype, sizeof(handle->posttype));
                ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, handle->posttype, handle->postdata, handle->postlen, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
        }
        else
@@ -6327,7 +5548,7 @@ out1:
                        // GET: we sign JUST the query string
                        size_t l, ll;
                        handle->sigdata = (char *)Z_Malloc(8192);
-                       strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
+                       dp_strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
                        l = strlen(handle->sigdata);
                        handle->siglen = Crypto_SignDataDetached(query_string, lq, postkeyid, handle->sigdata + l, 8192 - l);
                        if(!handle->siglen)
@@ -6370,6 +5591,7 @@ void VM_netaddress_resolve (prvm_prog_t *prog)
 {
        const char *ip;
        char normalized[128];
+       size_t normalized_len;
        int port;
        lhnetaddress_t addr;
 
@@ -6380,10 +5602,10 @@ void VM_netaddress_resolve (prvm_prog_t *prog)
        if(prog->argc > 1)
                port = (int) PRVM_G_FLOAT(OFS_PARM1);
 
-       if(LHNETADDRESS_FromString(&addr, ip, port) && LHNETADDRESS_ToString(&addr, normalized, sizeof(normalized), prog->argc > 1))
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, normalized);
+       if(LHNETADDRESS_FromString(&addr, ip, port) && (normalized_len = LHNETADDRESS_ToString(&addr, normalized, sizeof(normalized), prog->argc > 1)))
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, normalized, normalized_len);
        else
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "", 0);
 }
 
 //string(prvm_prog_t *prog) getextresponse = #624; // returns the next extResponse packet that was sent to this client
@@ -6398,7 +5620,7 @@ void VM_CL_getextresponse (prvm_prog_t *prog)
                int first;
                --cl_net_extresponse_count;
                first = (cl_net_extresponse_last + NET_EXTRESPONSE_MAX - cl_net_extresponse_count) % NET_EXTRESPONSE_MAX;
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cl_net_extresponse[first]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cl_net_extresponse[first], strlen(cl_net_extresponse[first]));
        }
 }
 
@@ -6413,7 +5635,42 @@ void VM_SV_getextresponse (prvm_prog_t *prog)
                int first;
                --sv_net_extresponse_count;
                first = (sv_net_extresponse_last + NET_EXTRESPONSE_MAX - sv_net_extresponse_count) % NET_EXTRESPONSE_MAX;
-               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, sv_net_extresponse[first]);
+               PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, sv_net_extresponse[first], strlen(sv_net_extresponse[first]));
+       }
+}
+
+// DP_QC_NUDGEOUTOFSOLID
+// float(entity ent) nudgeoutofsolid = #567;
+void VM_nudgeoutofsolid(prvm_prog_t *prog)
+{
+       prvm_edict_t *ent;
+
+       VM_SAFEPARMCOUNTRANGE(1, 1, VM_nudgeoutofsolid);
+
+       ent = PRVM_G_EDICT(OFS_PARM0);
+       if (ent == prog->edicts)
+       {
+               VM_Warning(prog, "nudgeoutofsolid: can not modify world entity\n");
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
+       if (ent->free)
+       {
+               VM_Warning(prog, "nudgeoutofsolid: can not modify free entity\n");
+               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               return;
+       }
+
+       PRVM_G_FLOAT(OFS_RETURN) = PHYS_NudgeOutOfSolid(prog, ent);
+
+       if (PRVM_G_FLOAT(OFS_RETURN) > 0)
+       {
+               if (prog == SVVM_prog)
+                       SV_LinkEdict(ent);
+               else if (prog == CLVM_prog)
+                       CL_LinkEdict(ent);
+               else
+                       Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
        }
 }
 
@@ -6831,9 +6088,10 @@ verbatim:
                                break;
                }
        }
+
 finished:
-       *o = 0;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outbuf);
+       *o = '\0';
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outbuf, o - outbuf);
 }
 
 
@@ -7014,9 +6272,9 @@ static void clippointtosurface(prvm_prog_t *prog, prvm_edict_t *ed, model_t *mod
 
 static msurface_t *getsurface(model_t *model, int surfacenum)
 {
-       if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
+       if (surfacenum < 0 || surfacenum >= model->submodelsurfaces_end - model->submodelsurfaces_start)
                return NULL;
-       return model->data_surfaces + surfacenum + model->firstmodelsurface;
+       return model->data_surfaces + surfacenum + model->submodelsurfaces_start;
 }
 
 
@@ -7159,11 +6417,12 @@ void VM_getsurfacetexture(prvm_prog_t *prog)
 {
        model_t *model;
        msurface_t *surface;
+
        VM_SAFEPARMCOUNT(2, VM_getsurfacetexture);
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
        if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
                return;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, surface->texture->name);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, surface->texture->name, strlen(surface->texture->name));
 }
 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
 void VM_getsurfacenearpoint(prvm_prog_t *prog)
@@ -7180,7 +6439,7 @@ void VM_getsurfacenearpoint(prvm_prog_t *prog)
        ed = PRVM_G_EDICT(OFS_PARM0);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM1), point);
 
-       if (!ed || ed->priv.server->free)
+       if (!ed || ed->free)
                return;
        model = getmodel(prog, ed);
        if (!model || !model->num_surfaces)
@@ -7191,9 +6450,9 @@ void VM_getsurfacenearpoint(prvm_prog_t *prog)
        applytransform_inverted(prog, point, ed, p);
        best = -1;
        bestdist = 1000000000;
-       for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
+       for (surfacenum = model->submodelsurfaces_start;surfacenum < model->submodelsurfaces_end;surfacenum++)
        {
-               surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
+               surface = model->data_surfaces + surfacenum;
                // first see if the nearest point on the surface's box is closer than the previous match
                clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
                clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
@@ -7208,7 +6467,7 @@ void VM_getsurfacenearpoint(prvm_prog_t *prog)
                        if (dist < bestdist)
                        {
                                // that's closer too, store it as the best match
-                               best = surfacenum;
+                               best = surfacenum - model->submodelsurfaces_start;
                                bestdist = dist;
                        }
                }
@@ -7273,6 +6532,7 @@ void VM_getsurfacetriangle(prvm_prog_t *prog)
 // physics builtins
 //
 
+#ifdef USEODE
 #define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(prog, ed, f); else World_Physics_ApplyCmd(ed, f)
 
 static edict_odefunc_t *VM_physics_newstackfunction(prvm_prog_t *prog, prvm_edict_t *ed, edict_odefunc_t *f)
@@ -7291,14 +6551,17 @@ static edict_odefunc_t *VM_physics_newstackfunction(prvm_prog_t *prog, prvm_edic
        }
        return newfunc;
 }
+#endif
 
 // void(entity e, float physics_enabled) physics_enable = #;
 void VM_physics_enable(prvm_prog_t *prog)
 {
+#ifdef USEODE
        prvm_edict_t *ed;
        edict_odefunc_t f;
-       
+#endif
        VM_SAFEPARMCOUNT(2, VM_physics_enable);
+#ifdef USEODE
        ed = PRVM_G_EDICT(OFS_PARM0);
        if (!ed)
        {
@@ -7314,15 +6577,18 @@ void VM_physics_enable(prvm_prog_t *prog)
        }
        f.type = PRVM_G_FLOAT(OFS_PARM1) == 0 ? ODEFUNC_DISABLE : ODEFUNC_ENABLE;
        VM_physics_ApplyCmd(ed, &f);
+#endif
 }
 
 // void(entity e, vector force, vector relative_ofs) physics_addforce = #;
 void VM_physics_addforce(prvm_prog_t *prog)
 {
+#ifdef USEODE
        prvm_edict_t *ed;
        edict_odefunc_t f;
-       
+#endif
        VM_SAFEPARMCOUNT(3, VM_physics_addforce);
+#ifdef USEODE
        ed = PRVM_G_EDICT(OFS_PARM0);
        if (!ed)
        {
@@ -7340,15 +6606,18 @@ void VM_physics_addforce(prvm_prog_t *prog)
        VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), f.v2);
        VM_physics_ApplyCmd(ed, &f);
+#endif
 }
 
 // void(entity e, vector torque) physics_addtorque = #;
 void VM_physics_addtorque(prvm_prog_t *prog)
 {
+#ifdef USEODE
        prvm_edict_t *ed;
        edict_odefunc_t f;
-       
+#endif
        VM_SAFEPARMCOUNT(2, VM_physics_addtorque);
+#ifdef USEODE
        ed = PRVM_G_EDICT(OFS_PARM0);
        if (!ed)
        {
@@ -7365,6 +6634,7 @@ void VM_physics_addtorque(prvm_prog_t *prog)
        f.type = ODEFUNC_TORQUE;
        VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f.v1);
        VM_physics_ApplyCmd(ed, &f);
+#endif
 }
 
 extern cvar_t prvm_coverage;