]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - prvm_cmds.c
added prvm_offsets.h which centralizes field/global/function lookups for
[xonotic/darkplaces.git] / prvm_cmds.c
index f2c0e54d57ededb37c9eaef2e0907762448bae42..819bada04d0f639ac96d5def8469fabf972056fe 100644 (file)
@@ -55,7 +55,6 @@ void VM_CheckEmptyString (const char *s)
 
 void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
 {
-       prvm_eval_t *val;
        // self.frame is the interpolation target (new frame)
        // self.frame1time is the animation base time for the interpolation target
        // self.frame2 is the interpolation start (previous frame)
@@ -65,17 +64,17 @@ void VM_GenerateFrameGroupBlend(framegroupblend_t *framegroupblend, const prvm_e
        // self.lerpfrac4 is the interpolation strength for self.frame4
        // pitch angle on a player model where the animator set up 5 sets of
        // animations and the csqc simply lerps between sets)
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame))) framegroupblend[0].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2))) framegroupblend[1].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3))) framegroupblend[2].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4))) framegroupblend[3].frame = (int) val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame1time))) framegroupblend[0].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame2time))) framegroupblend[1].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame3time))) framegroupblend[2].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.frame4time))) framegroupblend[3].start = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac))) framegroupblend[1].lerp = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac3))) framegroupblend[2].lerp = val->_float;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.lerpfrac4))) framegroupblend[3].lerp = val->_float;
+       framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame     );
+       framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2    );
+       framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3    );
+       framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4    );
+       framegroupblend[0].start =       PRVM_gameedictfloat(ed, frame1time);
+       framegroupblend[1].start =       PRVM_gameedictfloat(ed, frame2time);
+       framegroupblend[2].start =       PRVM_gameedictfloat(ed, frame3time);
+       framegroupblend[3].start =       PRVM_gameedictfloat(ed, frame4time);
+       framegroupblend[1].lerp  =       PRVM_gameedictfloat(ed, lerpfrac  );
+       framegroupblend[2].lerp  =       PRVM_gameedictfloat(ed, lerpfrac3 );
+       framegroupblend[3].lerp  =       PRVM_gameedictfloat(ed, lerpfrac4 );
        // assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed
        framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp;
 }
@@ -198,8 +197,7 @@ void VM_UpdateEdictSkeleton(prvm_edict_t *ed, const dp_model_t *edmodel, const f
        {
                int skeletonindex = -1;
                skeleton_t *skeleton;
-               prvm_eval_t *val;
-               if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+               skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
                if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
                {
                        // custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
@@ -312,11 +310,8 @@ void VM_error (void)
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
-       if (prog->globaloffsets.self >= 0)
-       {
-               ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
-               PRVM_ED_Print(ed, NULL);
-       }
+       ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
+       PRVM_ED_Print(ed, NULL);
 
        PRVM_ERROR ("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
 }
@@ -338,16 +333,9 @@ void VM_objerror (void)
 
        VM_VarString(0, string, sizeof(string));
        Con_Printf("======OBJECT ERROR======\n"); // , PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
-       if (prog->globaloffsets.self >= 0)
-       {
-               ed = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
-               PRVM_ED_Print(ed, NULL);
-
-               PRVM_ED_Free (ed);
-       }
-       else
-               // objerror has to display the object fields -> else call
-               PRVM_ERROR ("VM_objecterror: self not defined !");
+       ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
+       PRVM_ED_Print(ed, NULL);
+       PRVM_ED_Free (ed);
        Con_Printf("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
 }
 
@@ -874,7 +862,7 @@ void VM_ftoe(void)
        VM_SAFEPARMCOUNT(1, VM_ftoe);
 
        ent = (int)PRVM_G_FLOAT(OFS_PARM0);
-       if (ent < 0 || ent >= MAX_EDICTS || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
+       if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
                ent = 0; // return world instead of a free or invalid entity
 
        PRVM_G_INT(OFS_RETURN) = ent;
@@ -1115,7 +1103,7 @@ void VM_findchain (void)
                if (strcmp(t,s))
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_NUM_FOR_EDICT(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_NUM_FOR_EDICT(chain);
                chain = ent;
        }
 
@@ -1163,7 +1151,7 @@ void VM_findchainfloat (void)
                if (PRVM_E_FLOAT(ent,f) != s)
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                chain = ent;
        }
 
@@ -1251,7 +1239,7 @@ void VM_findchainflags (void)
                if (!((int)PRVM_E_FLOAT(ent,f) & s))
                        continue;
 
-               PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+               PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                chain = ent;
        }
 
@@ -2019,7 +2007,7 @@ Return the number of entity fields - NOT offsets
 */
 void VM_numentityfields(void)
 {
-       PRVM_G_FLOAT(OFS_RETURN) = prog->progs->numfielddefs;
+       PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs;
 }
 
 // KrimZon - DP_QC_ENTITYDATA
@@ -2036,7 +2024,7 @@ void VM_entityfieldname(void)
        ddef_t *d;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
         VM_Warning("VM_entityfieldname: %s: field index out of bounds\n", PRVM_NAME);
         PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
@@ -2060,7 +2048,7 @@ void VM_entityfieldtype(void)
        ddef_t *d;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
                VM_Warning("VM_entityfieldtype: %s: field index out of bounds\n", PRVM_NAME);
                PRVM_G_FLOAT(OFS_RETURN) = -1.0;
@@ -2088,7 +2076,7 @@ void VM_getentityfieldstring(void)
        prvm_edict_t * ent;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
        
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
         VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
                PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString("");
@@ -2135,7 +2123,7 @@ void VM_putentityfieldstring(void)
        prvm_edict_t * ent;
        int i = (int)PRVM_G_FLOAT(OFS_PARM0);
 
-       if (i < 0 || i >= prog->progs->numfielddefs)
+       if (i < 0 || i >= prog->numfielddefs)
        {
         VM_Warning("VM_entityfielddata: %s: field index out of bounds\n", PRVM_NAME);
                PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
@@ -2382,25 +2370,42 @@ void VM_strreplace(void)
        subject_len = (int)strlen(subject);
 
        si = 0;
-       for (i = 0; i < subject_len; i++)
+       for (i = 0; i <= subject_len - search_len; i++)
        {
-               for (j = 0; j < search_len && i+j < subject_len; j++)
+               for (j = 0; j < search_len; j++) // thus, i+j < subject_len
                        if (subject[i+j] != search[j])
                                break;
-               if (j == search_len || i+j == subject_len)
+               if (j == search_len)
                {
-               // found it at offset 'i'
+                       // NOTE: if search_len == 0, we always hit THIS case, and never the other
+                       // found it at offset 'i'
                        for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
                                string[si++] = replace[j];
-                       i += search_len - 1;
+                       if(search_len > 0)
+                       {
+                               i += search_len - 1;
+                       }
+                       else
+                       {
+                               // the above would subtract 1 from i... so we
+                               // don't do that, but instead output the next
+                               // char
+                               if (si < (int)sizeof(string) - 1)
+                                       string[si++] = subject[i];
+                       }
                }
                else
                {
-               // not found
+                       // in THIS case, we know search_len > 0, thus i < subject_len
+                       // not found
                        if (si < (int)sizeof(string) - 1)
                                string[si++] = subject[i];
                }
        }
+       // remaining chars (these cannot match)
+       for (; i < subject_len; i++)
+               if (si < (int)sizeof(string) - 1)
+                       string[si++] = subject[i];
        string[si] = '\0';
 
        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
@@ -2432,25 +2437,42 @@ void VM_strireplace(void)
        subject_len = (int)strlen(subject);
 
        si = 0;
-       for (i = 0; i < subject_len; i++)
+       for (i = 0; i <= subject_len - search_len; i++)
        {
-               for (j = 0; j < search_len && i+j < subject_len; j++)
+               for (j = 0; j < search_len; j++) // thus, i+j < subject_len
                        if (tolower(subject[i+j]) != tolower(search[j]))
                                break;
-               if (j == search_len || i+j == subject_len)
+               if (j == search_len)
                {
-               // found it at offset 'i'
+                       // NOTE: if search_len == 0, we always hit THIS case, and never the other
+                       // found it at offset 'i'
                        for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
                                string[si++] = replace[j];
-                       i += search_len - 1;
+                       if(search_len > 0)
+                       {
+                               i += search_len - 1;
+                       }
+                       else
+                       {
+                               // the above would subtract 1 from i... so we
+                               // don't do that, but instead output the next
+                               // char
+                               if (si < (int)sizeof(string) - 1)
+                                       string[si++] = subject[i];
+                       }
                }
                else
                {
-               // not found
+                       // in THIS case, we know search_len > 0, thus i < subject_len
+                       // not found
                        if (si < (int)sizeof(string) - 1)
                                string[si++] = subject[i];
                }
        }
+       // remaining chars (these cannot match)
+       for (; i < subject_len; i++)
+               if (si < (int)sizeof(string) - 1)
+                       string[si++] = subject[i];
        string[si] = '\0';
 
        PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
@@ -3262,28 +3284,20 @@ void getdrawfontscale(float *sx, float *sy)
 {
        vec3_t v;
        *sx = *sy = 1;
-       if(prog->globaloffsets.drawfontscale >= 0)
+       VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
+       if(VectorLength2(v) > 0)
        {
-               VectorCopy(PRVM_G_VECTOR(prog->globaloffsets.drawfontscale), v);
-               if(VectorLength2(v) > 0)
-               {
-                       *sx = v[0];
-                       *sy = v[1];
-               }
+               *sx = v[0];
+               *sy = v[1];
        }
 }
 
 dp_font_t *getdrawfont(void)
 {
-       if(prog->globaloffsets.drawfont >= 0)
-       {
-               int f = (int) PRVM_G_FLOAT(prog->globaloffsets.drawfont);
-               if(f < 0 || f >= dp_fonts.maxsize)
-                       return FONT_DEFAULT;
-               return &dp_fonts.f[f];
-       }
-       else
+       int f = (int) PRVM_drawglobalfloat(drawfont);
+       if(f < 0 || f >= dp_fonts.maxsize)
                return FONT_DEFAULT;
+       return &dp_fonts.f[f];
 }
 
 /*
@@ -3385,22 +3399,42 @@ void VM_drawstring(void)
 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(void)
 {
-       float *pos,*scale;
+       float *pos, *scale;
        const char  *string;
        int flag;
-       float sx, sy;
-       VM_SAFEPARMCOUNT(5,VM_drawstring);
+       vec3_t rgb;
+       float sx, sy, alpha;
 
-       string = PRVM_G_STRING(OFS_PARM1);
-       pos = PRVM_G_VECTOR(OFS_PARM0);
-       scale = PRVM_G_VECTOR(OFS_PARM2);
-       flag = (int)PRVM_G_FLOAT(OFS_PARM4);
+       VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
 
-       if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
+       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("VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
@@ -3418,8 +3452,11 @@ void VM_drawcolorcodedstring(void)
                Con_Printf("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(&sx, &sy);
-       DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, 1, 1, 1, PRVM_G_FLOAT(OFS_PARM3), flag, NULL, false, getdrawfont());
-       PRVM_G_FLOAT(OFS_RETURN) = 1;
+       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());
+       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;
 }
 /*
 =========
@@ -4392,17 +4429,8 @@ void makevectors(vector angle)
 */
 void VM_makevectors (void)
 {
-       prvm_eval_t *valforward, *valright, *valup;
-       valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
-       valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
-       valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
-       if (!valforward || !valright || !valup)
-       {
-               VM_Warning("makevectors: could not find v_forward, v_right, or v_up global variables\n");
-               return;
-       }
        VM_SAFEPARMCOUNT(1, VM_makevectors);
-       AngleVectors (PRVM_G_VECTOR(OFS_PARM0), valforward->vector, valright->vector, valup->vector);
+       AngleVectors(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
 }
 
 /*
@@ -4415,18 +4443,9 @@ vectorvectors(vector)
 */
 void VM_vectorvectors (void)
 {
-       prvm_eval_t *valforward, *valright, *valup;
-       valforward = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_forward);
-       valright = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_right);
-       valup = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.v_up);
-       if (!valforward || !valright || !valup)
-       {
-               VM_Warning("vectorvectors: could not find v_forward, v_right, or v_up global variables\n");
-               return;
-       }
        VM_SAFEPARMCOUNT(1, VM_vectorvectors);
-       VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), valforward->vector);
-       VectorVectors(valforward->vector, valright->vector, valup->vector);
+       VectorNormalize2(PRVM_G_VECTOR(OFS_PARM0), PRVM_gameglobalvector(v_forward));
+       VectorVectors(PRVM_gameglobalvector(v_forward), PRVM_gameglobalvector(v_right), PRVM_gameglobalvector(v_up));
 }
 
 /*
@@ -4750,7 +4769,7 @@ void VM_buf_create (void)
        for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
        stringbuffer->origin = PRVM_AllocationOrigin();
        // optional flags parm
-       if(prog->argc == 2)
+       if (prog->argc >= 2)
                stringbuffer->flags = (int)PRVM_G_FLOAT(OFS_PARM1) & 0xFF;
        PRVM_G_FLOAT(OFS_RETURN) = i;
 }
@@ -4964,7 +4983,7 @@ void VM_bufstr_get (void)
        strindex = (int)PRVM_G_FLOAT(OFS_PARM1);
        if (strindex < 0)
        {
-               VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
+               // VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
                return;
        }
        if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex])
@@ -5206,7 +5225,7 @@ void VM_changeyaw (void)
        // parameters because they are the parameters to SV_MoveToGoal, not this
        //VM_SAFEPARMCOUNT(0, VM_changeyaw);
 
-       ent = PRVM_PROG_TO_EDICT(PRVM_GLOBALFIELDVALUE(prog->globaloffsets.self)->edict);
+       ent = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self));
        if (ent == prog->edicts)
        {
                VM_Warning("changeyaw: can not modify world entity\n");
@@ -5217,14 +5236,10 @@ void VM_changeyaw (void)
                VM_Warning("changeyaw: can not modify free entity\n");
                return;
        }
-       if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.ideal_yaw < 0 || prog->fieldoffsets.yaw_speed < 0)
-       {
-               VM_Warning("changeyaw: angles, ideal_yaw, or yaw_speed field(s) not found\n");
-               return;
-       }
-       current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1]);
-       ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.ideal_yaw)->_float;
-       speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.yaw_speed)->_float;
+       current = PRVM_gameedictvector(ent, angles)[1];
+       current = ANGLEMOD(current);
+       ideal = PRVM_gameedictfloat(ent, ideal_yaw);
+       speed = PRVM_gameedictfloat(ent, yaw_speed);
 
        if (current == ideal)
                return;
@@ -5250,7 +5265,8 @@ void VM_changeyaw (void)
                        move = -speed;
        }
 
-       PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[1] = ANGLEMOD (current + move);
+       current += move;
+       PRVM_gameedictvector(ent, angles)[1] = ANGLEMOD(current);
 }
 
 /*
@@ -5276,14 +5292,10 @@ void VM_changepitch (void)
                VM_Warning("changepitch: can not modify free entity\n");
                return;
        }
-       if (prog->fieldoffsets.angles < 0 || prog->fieldoffsets.idealpitch < 0 || prog->fieldoffsets.pitch_speed < 0)
-       {
-               VM_Warning("changepitch: angles, idealpitch, or pitch_speed field(s) not found\n");
-               return;
-       }
-       current = ANGLEMOD(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0]);
-       ideal = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.idealpitch)->_float;
-       speed = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pitch_speed)->_float;
+       current = PRVM_gameedictvector(ent, angles)[0];
+       current = ANGLEMOD(current);
+       ideal = PRVM_gameedictfloat(ent, idealpitch);
+       speed = PRVM_gameedictfloat(ent, pitch_speed);
 
        if (current == ideal)
                return;
@@ -5309,7 +5321,8 @@ void VM_changepitch (void)
                        move = -speed;
        }
 
-       PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.angles)->vector[0] = ANGLEMOD (current + move);
+       current += move;
+       PRVM_gameedictvector(ent, angles)[0] = ANGLEMOD(current);
 }
 
 
@@ -5632,65 +5645,37 @@ void VM_wasfreed (void)
 
 void VM_SetTraceGlobals(const trace_t *trace)
 {
-       prvm_eval_t *val;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
-               val->_float = trace->allsolid;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
-               val->_float = trace->startsolid;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
-               val->_float = trace->fraction;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
-               val->_float = trace->inwater;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
-               val->_float = trace->inopen;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
-               VectorCopy(trace->endpos, val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
-               VectorCopy(trace->plane.normal, val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
-               val->_float = trace->plane.dist;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
-               val->edict = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-               val->_float = trace->startsupercontents;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-               val->_float = trace->hitsupercontents;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-               val->_float = trace->hitq3surfaceflags;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-               val->string = trace->hittexture ? PRVM_SetTempString(trace->hittexture->name) : 0;
+       PRVM_gameglobalfloat(trace_allsolid) = trace->allsolid;
+       PRVM_gameglobalfloat(trace_startsolid) = trace->startsolid;
+       PRVM_gameglobalfloat(trace_fraction) = trace->fraction;
+       PRVM_gameglobalfloat(trace_inwater) = trace->inwater;
+       PRVM_gameglobalfloat(trace_inopen) = trace->inopen;
+       VectorCopy(trace->endpos, PRVM_gameglobalvector(trace_endpos));
+       VectorCopy(trace->plane.normal, PRVM_gameglobalvector(trace_plane_normal));
+       PRVM_gameglobalfloat(trace_plane_dist) = trace->plane.dist;
+       PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(trace->ent ? trace->ent : prog->edicts);
+       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(trace->hittexture->name) : 0;
 }
 
 void VM_ClearTraceGlobals(void)
 {
        // clean up all trace globals when leaving the VM (anti-triggerbot safeguard)
-       prvm_eval_t *val;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_allsolid)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_startsolid)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_fraction)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inwater)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_inopen)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_endpos)))
-               VectorClear(val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_normal)))
-               VectorClear(val->vector);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_plane_dist)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_ent)))
-               val->edict = PRVM_EDICT_TO_PROG(prog->edicts);
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dpstartcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitcontents)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphitq3surfaceflags)))
-               val->_float = 0;
-       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_dphittexturename)))
-               val->string = 0;
+       PRVM_gameglobalfloat(trace_allsolid) = 0;
+       PRVM_gameglobalfloat(trace_startsolid) = 0;
+       PRVM_gameglobalfloat(trace_fraction) = 0;
+       PRVM_gameglobalfloat(trace_inwater) = 0;
+       PRVM_gameglobalfloat(trace_inopen) = 0;
+       VectorClear(PRVM_gameglobalvector(trace_endpos));
+       VectorClear(PRVM_gameglobalvector(trace_plane_normal));
+       PRVM_gameglobalfloat(trace_plane_dist) = 0;
+       PRVM_gameglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(prog->edicts);
+       PRVM_gameglobalfloat(trace_dpstartcontents) = 0;
+       PRVM_gameglobalfloat(trace_dphitcontents) = 0;
+       PRVM_gameglobalfloat(trace_dphitq3surfaceflags) = 0;
+       PRVM_gameglobalstring(trace_dphittexturename) = 0;
 }
 
 //=============
@@ -5836,7 +5821,7 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
                
        PRVM_SetProg(handle->prognr);
        PRVM_Begin;
-               if((prog->starttime == handle->starttime) && (prog->funcoffsets.URI_Get_Callback))
+               if((prog->starttime == handle->starttime) && (PRVM_allfunction(URI_Get_Callback)))
                {
                        if(length_received >= sizeof(handle->buffer))
                                length_received = sizeof(handle->buffer) - 1;
@@ -5845,7 +5830,7 @@ static void uri_to_string_callback(int status, size_t length_received, unsigned
                        PRVM_G_FLOAT(OFS_PARM0) = handle->id;
                        PRVM_G_FLOAT(OFS_PARM1) = status;
                        PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(handle->buffer);
-                       PRVM_ExecuteProgram(prog->funcoffsets.URI_Get_Callback, "QC function URI_Get_Callback is missing");
+                       PRVM_ExecuteProgram(PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
                }
        PRVM_End;
        
@@ -5871,7 +5856,7 @@ void VM_uri_get (void)
        const char *query_string = NULL;
        size_t lq;
 
-       if(!prog->funcoffsets.URI_Get_Callback)
+       if(!PRVM_allfunction(URI_Get_Callback))
                PRVM_ERROR("uri_get called by %s without URI_Get_Callback defined", PRVM_NAME);
 
        VM_SAFEPARMCOUNTRANGE(2, 6, VM_uri_get);
@@ -6379,8 +6364,11 @@ nolength:
                                        if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' ';
                                        if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+';
                                        *f++ = '*';
-                                       *f++ = '.';
-                                       *f++ = '*';
+                                       if(precision >= 0)
+                                       {
+                                               *f++ = '.';
+                                               *f++ = '*';
+                                       }
                                        *f++ = *s;
                                        *f++ = 0;
 
@@ -6391,50 +6379,70 @@ nolength:
                                        {
                                                case 'd': case 'i':
                                                        if(precision < 0) // not set
-                                                               precision = 1;
-                                                       o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
+                                                       else
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (int) GETARG_FLOAT(thisarg) : (int) GETARG_INT(thisarg)));
                                                        break;
                                                case 'o': case 'u': case 'x': case 'X':
                                                        if(precision < 0) // not set
-                                                               precision = 1;
-                                                       o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+                                                       else
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
                                                        break;
                                                case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
                                                        if(precision < 0) // not set
-                                                               precision = 6;
-                                                       o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
+                                                       else
+                                                               o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
                                                        break;
                                                case 'v': case 'V':
                                                        f[-2] += 'g' - 'v';
                                                        if(precision < 0) // not set
-                                                               precision = 6;
-                                                       o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
-                                                               width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
-                                                               width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
-                                                               width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
-                                                       );
+                                                               o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+                                                                       width, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
+                                                                       width, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
+                                                                       width, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
+                                                               );
+                                                       else
+                                                               o += dpsnprintf(o, end - o, va("%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
+                                                                       width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
+                                                                       width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
+                                                                       width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
+                                                               );
                                                        break;
                                                case 'c':
-                                                       if(precision < 0) // not set
-                                                               precision = end - o - 1;
                                                        if(flags & PRINTF_ALTERNATE)
-                                                               o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+                                                       {
+                                                               if(precision < 0) // not set
+                                                                       o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+                                                               else
+                                                                       o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
+                                                       }
                                                        else
                                                        {
                                                                unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg));
                                                                const char *buf = u8_encodech(c, NULL);
                                                                if(!buf)
                                                                        buf = "";
+                                                               if(precision < 0) // not set
+                                                                       precision = end - o - 1;
                                                                o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision);
                                                        }
                                                        break;
                                                case 's':
-                                                       if(precision < 0) // not set
-                                                               precision = end - o - 1;
                                                        if(flags & PRINTF_ALTERNATE)
-                                                               o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
+                                                       {
+                                                               if(precision < 0) // not set
+                                                                       o += dpsnprintf(o, end - o, formatbuf, width, GETARG_STRING(thisarg));
+                                                               else
+                                                                       o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
+                                                       }
                                                        else
+                                                       {
+                                                               if(precision < 0) // not set
+                                                                       precision = end - o - 1;
                                                                o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision);
+                                                       }
                                                        break;
                                                default:
                                                        VM_Warning("VM_sprintf: invalid directive in %s: %s\n", PRVM_NAME, s0);
@@ -6493,7 +6501,6 @@ static animatemodel_cache_t animatemodel_cache;
 
 void animatemodel(dp_model_t *model, prvm_edict_t *ed)
 {
-       prvm_eval_t *val;
        skeleton_t *skeleton;
        int skeletonindex = -1;
        qboolean need = false;
@@ -6511,7 +6518,7 @@ void animatemodel(dp_model_t *model, prvm_edict_t *ed)
        VM_GenerateFrameGroupBlend(ed->priv.server->framegroupblend, ed);
        VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model);
        need |= (memcmp(&animatemodel_cache.frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend))) != 0;
-       if ((val = PRVM_EDICTFIELDVALUE(ed, prog->fieldoffsets.skeletonindex))) skeletonindex = (int)val->_float - 1;
+       skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
        if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones))
                skeleton = NULL;
        need |= (animatemodel_cache.skeleton_p != skeleton);