]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - prvm_edict.c
-Split prvm_cmds.c into prvm_cmds.c, prvm_cmds.h and mvm_cmds.c (clvm_cmds.c
[xonotic/darkplaces.git] / prvm_edict.c
index 4cc5872462fa426560f1dc3d9eb9a50e0acfe070..e38e07825b74b6412b6cda130f21dae57b467cfd 100644 (file)
@@ -17,9 +17,10 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */
-// AK new vm 
+// AK new vm
 
 #include "quakedef.h"
+#include "progsvm.h"
 
 prvm_prog_t *prog;
 
@@ -53,25 +54,25 @@ void PRVM_MEM_Alloc()
        // reserve space for the null entity aka world
        // check bound of max_edicts
        prog->max_edicts = bound(1, prog->max_edicts, prog->limit_edicts);
-       prog->num_edicts = bound(1, prog->num_edicts, prog->max_edicts);        
+       prog->num_edicts = bound(1, prog->num_edicts, prog->max_edicts);
 
        // edictprivate_size has to be min as big prvm_edict_private_t
-       prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t)); 
+       prog->edictprivate_size = max(prog->edictprivate_size,(int)sizeof(prvm_edict_private_t));
 
        // alloc edicts
-       prog->edicts = Mem_Alloc(prog->edicts_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
-       
+       prog->edicts = Mem_Alloc(prog->progs_mempool,prog->limit_edicts * sizeof(prvm_edict_t));
+
        // alloc edict private space
-       prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
-       
+       prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
+
        // alloc edict fields
-       prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
+       prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
 
        // set edict pointers
        for(i = 0; i < prog->max_edicts; i++)
        {
-               prog->edicts[i].e = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
-               prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
+               prog->edicts[i].priv.required = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
+               prog->edicts[i].fields.vp = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
        }
 }
 
@@ -83,20 +84,20 @@ PRVM_MEM_IncreaseEdicts
 void PRVM_MEM_IncreaseEdicts()
 {
        int             i;
-       int             oldmaxedicts = prog->max_edicts; 
+       int             oldmaxedicts = prog->max_edicts;
        void    *oldedictsfields = prog->edictsfields;
        void    *oldedictprivate = prog->edictprivate;
-       
+
        if(prog->max_edicts >= prog->limit_edicts)
                return;
-       
+
        PRVM_GCALL(begin_increase_edicts)();
 
        // increase edicts
        prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts);
 
-       prog->edictsfields = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edict_size);
-       prog->edictprivate = Mem_Alloc(prog->edicts_mempool, prog->max_edicts * prog->edictprivate_size);
+       prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size);
+       prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size);
 
        memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size);
        memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size);
@@ -104,8 +105,8 @@ void PRVM_MEM_IncreaseEdicts()
        //set e and v pointers
        for(i = 0; i < prog->max_edicts; i++)
        {
-               prog->edicts[i].e = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
-               prog->edicts[i].v = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
+               prog->edicts[i].priv.required  = (prvm_edict_private_t *)((qbyte  *)prog->edictprivate + i * prog->edictprivate_size);
+               prog->edicts[i].fields.vp = (void*)((qbyte *)prog->edictsfields + i * prog->edict_size);
        }
 
        PRVM_GCALL(end_increase_edicts)();
@@ -170,7 +171,7 @@ PRVM_SetProg
 void PRVM_SetProg(int prognr)
 {
        if(prognr && prognr < PRVM_MAXPROGS)
-       {       
+       {
                if(prog_list[prognr].loaded)
                        prog = &prog_list[prognr];
                else
@@ -190,13 +191,13 @@ Sets everything to NULL
 void PRVM_ED_ClearEdict (prvm_edict_t *e)
 {
        int num;
-       memset (e->v, 0, prog->progs->entityfields * 4);
-       e->e->free = false;
+       memset (e->fields.vp, 0, prog->progs->entityfields * 4);
+       e->priv.required->free = false;
        // LordHavoc: for consistency set these here
        num = PRVM_NUM_FOR_EDICT(e) - 1;
 
        // AK: Let the init_edict function determine if something needs to be initialized
-       PRVM_GCALL(init_edict)(num);    
+       PRVM_GCALL(init_edict)(num);
 }
 
 /*
@@ -225,7 +226,7 @@ prvm_edict_t *PRVM_ED_Alloc (void)
                e = PRVM_EDICT_NUM(i);
                // the first couple seconds of server time can involve a lot of
                // freeing and allocating, so relax the replacement policy
-               if (e->e->free && ( e->e->freetime < 2 || (*prog->time - e->e->freetime) > 0.5 ) )
+               if (e->priv.required->free && ( e->priv.required->freetime < 2 || (*prog->time - e->priv.required->freetime) > 0.5 ) )
                {
                        PRVM_ED_ClearEdict (e);
                        return e;
@@ -261,8 +262,8 @@ void PRVM_ED_Free (prvm_edict_t *ed)
 
        PRVM_GCALL(free_edict)(ed);
 
-       ed->e->free = true;
-       ed->e->freetime = *prog->time;
+       ed->priv.required->free = true;
+       ed->priv.required->freetime = *prog->time;
 }
 
 //===========================================================================
@@ -383,7 +384,7 @@ char *PRVM_ValueString (etype_t type, prvm_eval_t *val)
        switch (type)
        {
        case ev_string:
-               strncpy(line, PRVM_GetString(val->string), sizeof(line));
+               strlcpy (line, PRVM_GetString (val->string), sizeof (line));
                break;
        case ev_entity:
                n = val->edict;
@@ -434,12 +435,12 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
 {
        static char line[4096];
        int i;
-       char *s;
+       const char *s;
        ddef_t *def;
        mfunction_t *f;
-       
+
        type &= ~DEF_SAVEGLOBAL;
-       
+
        switch (type)
        {
        case ev_string:
@@ -466,30 +467,30 @@ char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val)
                line[i] = '\0';
                break;
        case ev_entity:
-               snprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
+               dpsnprintf (line, sizeof (line), "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict)));
                break;
        case ev_function:
                f = pr_functions + val->function;
-               strncpy(line, PRVM_GetString(f->s_name), sizeof(line));
+               strlcpy (line, PRVM_GetString (f->s_name), sizeof (line));
                break;
        case ev_field:
                def = PRVM_ED_FieldAtOfs ( val->_int );
-               snprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
+               dpsnprintf (line, sizeof (line), ".%s", PRVM_GetString(def->s_name));
                break;
        case ev_void:
-               snprintf (line, sizeof (line), "void");
+               dpsnprintf (line, sizeof (line), "void");
                break;
        case ev_float:
-               snprintf (line, sizeof (line), "%f", val->_float);
+               dpsnprintf (line, sizeof (line), "%f", val->_float);
                break;
        case ev_vector:
-               snprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
+               dpsnprintf (line, sizeof (line), "%f %f %f", val->vector[0], val->vector[1], val->vector[2]);
                break;
        default:
-               snprintf (line, sizeof (line), "bad type %i", type);
+               dpsnprintf (line, sizeof (line), "bad type %i", type);
                break;
        }
-       
+
        return line;
 }
 
@@ -563,11 +564,11 @@ void PRVM_ED_Print(prvm_edict_t *ed)
        ddef_t  *d;
        int             *v;
        int             i, j;
-       char    *name;
+       const char      *name;
        int             type;
        char    tempstring[8192], tempstring2[260]; // temporary string buffers
 
-       if (ed->e->free)
+       if (ed->priv.required->free)
        {
                Con_Printf("%s: FREE\n",PRVM_NAME);
                return;
@@ -582,7 +583,7 @@ void PRVM_ED_Print(prvm_edict_t *ed)
                if (name[strlen(name)-2] == '_')
                        continue;       // skip _x, _y, _z vars
 
-               v = (int *)((char *)ed->v + d->ofs*4);
+               v = (int *)((char *)ed->fields.vp + d->ofs*4);
 
        // if the value is still all 0, skip the field
                type = d->type & ~DEF_SAVEGLOBAL;
@@ -595,7 +596,7 @@ void PRVM_ED_Print(prvm_edict_t *ed)
 
                if (strlen(name) > 256)
                {
-                       strncpy(tempstring2, name, 256);
+                       memcpy (tempstring2, name, 256);
                        tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
                        tempstring2[259] = 0;
                        name = tempstring2;
@@ -608,7 +609,7 @@ void PRVM_ED_Print(prvm_edict_t *ed)
                name = PRVM_ValueString(d->type, (prvm_eval_t *)v);
                if (strlen(name) > 256)
                {
-                       strncpy(tempstring2, name, 256);
+                       memcpy (tempstring2, name, 256);
                        tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
                        tempstring2[259] = 0;
                        name = tempstring2;
@@ -637,12 +638,12 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
        ddef_t  *d;
        int             *v;
        int             i, j;
-       char    *name;
+       const char      *name;
        int             type;
 
        FS_Print(f, "{\n");
 
-       if (ed->e->free)
+       if (ed->priv.required->free)
        {
                FS_Print(f, "}\n");
                return;
@@ -655,7 +656,7 @@ void PRVM_ED_Write (qfile_t *f, prvm_edict_t *ed)
                if (name[strlen(name)-2] == '_')
                        continue;       // skip _x, _y, _z vars
 
-               v = (int *)((char *)ed->v + d->ofs*4);
+               v = (int *)((char *)ed->fields.vp + d->ofs*4);
 
        // if the value is still all 0, skip the field
                type = d->type & ~DEF_SAVEGLOBAL;
@@ -693,7 +694,7 @@ void PRVM_ED_PrintEdicts_f (void)
                Con_Print("prvm_edicts <program name>\n");
                return;
        }
-       
+
        PRVM_Begin;
        if(!PRVM_SetProgFromString(Cmd_Argv(1)))
                return;
@@ -771,11 +772,11 @@ void PRVM_ED_Count_f (void)
                for (i=0 ; i<prog->num_edicts ; i++)
                {
                        ent = PRVM_EDICT_NUM(i);
-                       if (ent->e->free)
+                       if (ent->priv.required->free)
                                continue;
                        active++;
                }
-               
+
                Con_Printf("num_edicts:%3i\n", prog->num_edicts);
                Con_Printf("active    :%3i\n", active);
        }
@@ -801,7 +802,7 @@ void PRVM_ED_WriteGlobals (qfile_t *f)
 {
        ddef_t          *def;
        int                     i;
-       char            *name;
+       const char              *name;
        int                     type;
 
        FS_Print(f,"{\n");
@@ -865,37 +866,6 @@ void PRVM_ED_ParseGlobals (const char *data)
 //============================================================================
 
 
-/*
-=============
-PRVM_ED_NewString
-=============
-*/
-char *PRVM_ED_NewString (const char *string)
-{
-       char *new, *new_p;
-       int i,l;
-
-       l = strlen(string) + 1;
-       new = Mem_Alloc(prog->edictstring_mempool, l);
-       new_p = new;
-
-       for (i=0 ; i< l ; i++)
-       {
-               if (string[i] == '\\' && i < l-1)
-               {
-                       i++;
-                       if (string[i] == 'n')
-                               *new_p++ = '\n';
-                       else
-                               *new_p++ = '\\';
-               }
-               else
-                       *new_p++ = string[i];
-       }
-
-       return new;
-}
-
 /*
 =============
 PRVM_ED_ParseEval
@@ -906,19 +876,37 @@ returns false if error
 */
 qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
 {
-       int i;
+       int i, l;
+       char *new_p;
        ddef_t *def;
        prvm_eval_t *val;
        mfunction_t *func;
 
        if (ent)
-               val = (prvm_eval_t *)((int *)ent->v + key->ofs);
+               val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
        else
-               val = (prvm_eval_t *)((int *)pr_globals + key->ofs);
+               val = (prvm_eval_t *)((int *)prog->globals + key->ofs);
        switch (key->type & ~DEF_SAVEGLOBAL)
        {
        case ev_string:
-               val->string = PRVM_SetString(PRVM_ED_NewString(s));
+               l = strlen(s) + 1;
+               new_p = PRVM_AllocString(l);
+               val->string = PRVM_SetQCString(new_p);
+               for (i = 0;i < l;i++)
+               {
+                       if (s[i] == '\\' && i < l-1)
+                       {
+                               i++;
+                               if (s[i] == 'n')
+                                       *new_p++ = '\n';
+                               else if (s[i] == 'r')
+                                       *new_p++ = '\r';
+                               else
+                                       *new_p++ = s[i];
+                       }
+                       else
+                               *new_p++ = s[i];
+               }
                break;
 
        case ev_float:
@@ -953,7 +941,7 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
                        //SV_IncreaseEdicts();
                // if SV_IncreaseEdicts was called the base pointer needs to be updated
                if (ent)
-                       val = (prvm_eval_t *)((int *)ent->v + key->ofs);
+                       val = (prvm_eval_t *)((int *)ent->fields.vp + key->ofs);
                val->edict = PRVM_EDICT_TO_PROG(EDICT_NUM(i));
                break;
 
@@ -964,7 +952,7 @@ qboolean PRVM_ED_ParseEpair(prvm_edict_t *ent, ddef_t *key, const char *s)
                        Con_DPrintf("PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME);
                        return false;
                }
-               val->_int = PRVM_G_INT(def->ofs);
+               val->_int = def->ofs;
                break;
 
        case ev_function:
@@ -1012,12 +1000,9 @@ void PRVM_ED_EdictSet_f(void)
        ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2)));
 
        if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0)
-       {
                Con_Printf("Key %s not found !\n", Cmd_Argv(3));
-               return;
-       }
-
-       PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
+       else
+               PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4));
 
        PRVM_End;
 }
@@ -1041,10 +1026,6 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
 
        init = false;
 
-// clear it
-       if (ent != prog->edicts)        // hack
-               memset (ent->v, 0, prog->progs->entityfields * 4);
-
 // go through all the dictionary pairs
        while (1)
        {
@@ -1111,7 +1092,7 @@ const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent)
        }
 
        if (!init)
-               ent->e->free = true;
+               ent->priv.required->free = true;
 
        return data;
 }
@@ -1154,11 +1135,15 @@ void PRVM_ED_LoadFromFile (const char *data)
                        PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, com_token);
 
                // CHANGED: this is not conform to ED_LoadFromFile
-               if(!prog->num_edicts) 
+               if(!prog->num_edicts)
                        ent = PRVM_EDICT_NUM(0);
-               else 
+               else
                        ent = PRVM_ED_Alloc();
 
+               // clear it
+               if (ent != prog->edicts)        // hack
+                       memset (ent->fields.vp, 0, prog->progs->entityfields * 4);
+
                data = PRVM_ED_ParseEdict (data, ent);
                parsed++;
 
@@ -1175,7 +1160,7 @@ void PRVM_ED_LoadFromFile (const char *data)
 //
                if(prog->self && prog->flag & PRVM_FE_CLASSNAME)
                {
-                       string_t handle =  *(string_t*)&((float*)ent->v)[PRVM_ED_FindFieldOffset("classname")];
+                       string_t handle =  *(string_t*)&((float*)ent->fields.vp)[PRVM_ED_FindFieldOffset("classname")];
                        if (!handle)
                        {
                                Con_Print("No classname for:\n");
@@ -1183,10 +1168,10 @@ void PRVM_ED_LoadFromFile (const char *data)
                                PRVM_ED_Free (ent);
                                continue;
                        }
-                       
+
                        // look for the spawn function
                        func = PRVM_ED_FindFunction (PRVM_GetString(handle));
-                       
+
                        if (!func)
                        {
                                if (developer.integer) // don't confuse non-developers with errors
@@ -1197,19 +1182,19 @@ void PRVM_ED_LoadFromFile (const char *data)
                                PRVM_ED_Free (ent);
                                continue;
                        }
-                       
+
                        // self = ent
                        PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent);
                        PRVM_ExecuteProgram (func - prog->functions, "");
                }
-       
+
                spawned++;
-               if (ent->e->free)
+               if (ent->priv.required->free)
                        died++;
        }
 
        Con_DPrintf("%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died);
-}      
+}
 
 // not used
 /*
@@ -1235,27 +1220,8 @@ PRVM_ResetProg
 
 void PRVM_ResetProg()
 {
-       /*mempool_t *t1, *t2, *t3;
-
-       t1 = prog->progs_mempool;
-       t2 = prog->edictstring_mempool;
-       t3 = prog->edicts_mempool;
-       
-       Mem_EmptyPool(prog->progs_mempool);
-       Mem_EmptyPool(prog->edictstring_mempool);
-       Mem_EmptyPool(prog->edicts_mempool);*/
        Mem_FreePool(&prog->progs_mempool);
-       Mem_FreePool(&prog->edictstring_mempool);
-       Mem_FreePool(&prog->edicts_mempool);
-       
        memset(prog,0,sizeof(prvm_prog_t));
-       
-       /*prog->time = &prog->_time;
-       
-       prog->progs_mempool = t1;
-       prog->edictstring_mempool = t2;
-       prog->edicts_mempool = t3;*/
-
        PRVM_GCALL(reset_cmd)();
 }
 
@@ -1272,7 +1238,6 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required
        dfunction_t *dfunctions;
 
        Mem_EmptyPool(prog->progs_mempool);
-       Mem_EmptyPool(prog->edictstring_mempool);
 
        prog->progs = (dprograms_t *)FS_LoadFile (filename, prog->progs_mempool, false);
        if (prog->progs == NULL)
@@ -1293,7 +1258,19 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required
 
        //pr_functions = (dfunction_t *)((qbyte *)progs + progs->ofs_functions);
        dfunctions = (dfunction_t *)((qbyte *)prog->progs + prog->progs->ofs_functions);
+
        prog->strings = (char *)prog->progs + prog->progs->ofs_strings;
+       prog->stringssize = 0;
+       for (i = 0;i < prog->progs->numstrings;i++)
+       {
+               if (prog->progs->ofs_strings + prog->stringssize >= fs_filesize)
+                       PRVM_ERROR ("%s: %s strings go past end of file\n", PRVM_NAME, filename);
+               prog->stringssize += strlen (prog->strings + prog->stringssize) + 1;
+       }
+       prog->numknownstrings = 0;
+       prog->maxknownstrings = 0;
+       prog->knownstrings = NULL;
+
        prog->globaldefs = (ddef_t *)((qbyte *)prog->progs + prog->progs->ofs_globaldefs);
 
        // we need to expand the fielddefs list to include all the engine fields,
@@ -1352,7 +1329,7 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required
        {
                pr_fielddefs[progs->numfielddefs].type = dpfields[i].type;
                pr_fielddefs[progs->numfielddefs].ofs = progs->entityfields;
-               pr_fielddefs[progs->numfielddefs].s_name = PR_SetString(dpfields[i].string);
+               pr_fielddefs[progs->numfielddefs].s_name = PR_SetEngineString(dpfields[i].string);
                if (pr_fielddefs[progs->numfielddefs].type == ev_vector)
                        progs->entityfields += 3;
                else
@@ -1475,27 +1452,30 @@ void PRVM_LoadProgs (const char * filename, int numrequiredfunc, char **required
        PRVM_Init_Exec();
 
        prog->loaded = TRUE;
-       
+
        // set flags & ddef_ts in prog
-       
+
        prog->flag = 0;
-       
+
        prog->self = PRVM_ED_FindGlobal("self");
 
-       if(PRVM_ED_FindGlobal("time"))
+       if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float )
                prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs);
 
        if(PRVM_ED_FindField ("chain"))
                prog->flag |= PRVM_FE_CHAIN;
 
        if(PRVM_ED_FindField ("classname"))
-               prog->flag |= PRVM_FE_CLASSNAME; 
+               prog->flag |= PRVM_FE_CLASSNAME;
 
-       if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think") 
-               && prog->flag && prog->self) 
+       if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think")
+               && prog->flag && prog->self)
                prog->flag |= PRVM_OP_STATE;
-       
-       PRVM_GCALL(reset_cmd)();
+
+       if( prog->loaded ) {
+               PRVM_GCALL(reset_cmd)();
+       }
+       prog->loaded = TRUE;
        PRVM_GCALL(init_cmd)();
 
        // init mempools
@@ -1507,7 +1487,8 @@ void PRVM_Fields_f (void)
 {
        int i, j, ednum, used, usedamount;
        int *counts;
-       char tempstring[5000], tempstring2[260], *name;
+       char tempstring[5000], tempstring2[260];
+       const char *name;
        prvm_edict_t *ed;
        ddef_t *d;
        int *v;
@@ -1535,7 +1516,7 @@ void PRVM_Fields_f (void)
        for (ednum = 0;ednum < prog->max_edicts;ednum++)
        {
                ed = PRVM_EDICT_NUM(ednum);
-               if (ed->e->free)
+               if (ed->priv.required->free)
                        continue;
                for (i = 1;i < prog->progs->numfielddefs;i++)
                {
@@ -1543,7 +1524,7 @@ void PRVM_Fields_f (void)
                        name = PRVM_GetString(d->s_name);
                        if (name[strlen(name)-2] == '_')
                                continue;       // skip _x, _y, _z vars
-                       v = (int *)((char *)ed->v + d->ofs*4);
+                       v = (int *)((char *)ed->fields.vp + d->ofs*4);
                        // if the value is still all 0, skip the field
                        for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++)
                        {
@@ -1597,7 +1578,7 @@ void PRVM_Fields_f (void)
                }
                if (strlen(name) > 256)
                {
-                       strncpy(tempstring2, name, 256);
+                       memcpy (tempstring2, name, 256);
                        tempstring2[256] = tempstring2[257] = tempstring2[258] = '.';
                        tempstring2[259] = 0;
                        name = tempstring2;
@@ -1653,6 +1634,56 @@ void PRVM_Globals_f (void)
        PRVM_End;
 }
 
+/*
+===============
+PRVM_Global
+===============
+*/
+void PRVM_Global_f(void)
+{
+       ddef_t *global;
+       if( Cmd_Argc() != 3 ) {
+               Con_Printf( "prvm_global <program name> <global name>\n" );
+               return;
+       }
+
+       PRVM_Begin;
+       if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
+               return;
+
+       global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
+       if( !global )
+               Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
+       else
+               Con_Printf( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( global->type, (prvm_eval_t *) &prog->globals[ global->ofs ] ) );
+       PRVM_End;
+}
+
+/*
+===============
+PRVM_GlobalSet
+===============
+*/
+void PRVM_GlobalSet_f(void)
+{
+       ddef_t *global;
+       if( Cmd_Argc() != 4 ) {
+               Con_Printf( "prvm_globalset <program name> <global name> <value>\n" );
+               return;
+       }
+
+       PRVM_Begin;
+       if( !PRVM_SetProgFromString( Cmd_Argv(1) ) )
+               return;
+
+       global = PRVM_ED_FindGlobal( Cmd_Argv(2) );
+       if( !global )
+               Con_Printf( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) );
+       else
+               PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) );
+       PRVM_End;
+}
+
 /*
 ===============
 PRVM_Init
@@ -1666,6 +1697,8 @@ void PRVM_Init (void)
        Cmd_AddCommand ("prvm_profile", PRVM_Profile_f);
        Cmd_AddCommand ("prvm_fields", PRVM_Fields_f);
        Cmd_AddCommand ("prvm_globals", PRVM_Globals_f);
+       Cmd_AddCommand ("prvm_global", PRVM_Global_f);
+       Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f);
        Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f);
        // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others))
        Cvar_RegisterVariable (&prvm_boundscheck);
@@ -1699,6 +1732,24 @@ int PRVM_GetProgNr()
        return prog - prog_list;
 }
 
+void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline)
+{
+       return _Mem_Alloc(prog->progs_mempool, buffersize, filename, fileline);
+}
+
+void _PRVM_Free(void *buffer, const char *filename, int fileline)
+{
+       _Mem_Free(buffer, filename, fileline);
+}
+
+void _PRVM_FreeAll(const char *filename, int fileline)
+{
+       prog->progs = NULL;
+       prog->fielddefs = NULL;
+       prog->functions = NULL;
+       _Mem_EmptyPool(prog->progs_mempool, filename, fileline);
+}
+
 // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons
 prvm_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline)
 {
@@ -1753,3 +1804,107 @@ edict_t *PROG_TO_EDICT(int n)
 }
 */
 
+
+const char *PRVM_GetString(int num)
+{
+       if (num >= 0 && num < prog->stringssize)
+               return prog->strings + num;
+       else if (num < 0 && num >= -prog->numknownstrings)
+       {
+               num = -1 - num;
+               if (!prog->knownstrings[num])
+                       Host_Error("PRVM_GetString: attempt to get string that is already freed\n");
+               return prog->knownstrings[num];
+       }
+       else
+       {
+               Host_Error("PRVM_GetString: invalid string offset %i\n", num);
+               return "";
+       }
+}
+
+int PRVM_SetQCString(const char *s)
+{
+       int i;
+       if (!s)
+               return 0;
+       if (s >= prog->strings && s <= prog->strings + prog->stringssize)
+               return s - prog->strings;
+       for (i = 0;i < prog->numknownstrings;i++)
+               if (prog->knownstrings[i] == s)
+                       return -1 - i;
+       Host_Error("PRVM_SetQCString: unknown string\n");
+       return -1 - i;
+}
+
+int PRVM_SetEngineString(const char *s)
+{
+       int i;
+       if (!s)
+               return 0;
+       if (s >= prog->strings && s <= prog->strings + prog->stringssize)
+               Host_Error("PRVM_SetEngineString: s in prog->strings area\n");
+       for (i = 0;i < prog->numknownstrings;i++)
+               if (prog->knownstrings[i] == s)
+                       return -1 - i;
+       // new unknown engine string
+       if (developer.integer >= 3)
+               Con_Printf("new engine string %p\n", s);
+       for (i = 0;i < prog->numknownstrings;i++)
+               if (!prog->knownstrings[i])
+                       break;
+       if (i >= prog->numknownstrings)
+       {
+               if (i >= prog->maxknownstrings)
+               {
+                       const char **oldstrings = prog->knownstrings;
+                       prog->maxknownstrings += 128;
+                       prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
+                       if (prog->numknownstrings)
+                               memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
+               }
+               prog->numknownstrings++;
+       }
+       prog->knownstrings[i] = s;
+       return -1 - i;
+}
+
+char *PRVM_AllocString(int bufferlength)
+{
+       int i;
+       if (!bufferlength)
+               return 0;
+       for (i = 0;i < prog->numknownstrings;i++)
+               if (!prog->knownstrings[i])
+                       break;
+       if (i >= prog->numknownstrings)
+       {
+               if (i >= prog->maxknownstrings)
+               {
+                       const char **oldstrings = prog->knownstrings;
+                       prog->maxknownstrings += 128;
+                       prog->knownstrings = PRVM_Alloc(prog->maxknownstrings * sizeof(char *));
+                       if (prog->numknownstrings)
+                               memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *));
+               }
+               prog->numknownstrings++;
+       }
+       return (char *)(prog->knownstrings[i] = PRVM_Alloc(bufferlength));
+}
+
+void PRVM_FreeString(char *s)
+{
+       int i;
+       if (!s)
+               Host_Error("PRVM_FreeString: attempt to free a NULL string\n");
+       if (s >= prog->strings && s <= prog->strings + prog->stringssize)
+               Host_Error("PRVM_FreeString: attempt to free a constant string\n");
+       for (i = 0;i < prog->numknownstrings;i++)
+               if (prog->knownstrings[i] == s)
+                       break;
+       if (i == prog->numknownstrings)
+               Host_Error("PRVM_FreeString: attempt to free a non-existent or already freed string\n");
+       PRVM_Free((char *)prog->knownstrings[i]);
+       prog->knownstrings[i] = NULL;
+}
+