added PRVM_64 define which upgrades the QC VM to double precision
[xonotic/darkplaces.git] / svvm_cmds.c
index ede31ff..a68a525 100644 (file)
@@ -8,7 +8,7 @@
 
 
 
-char *vm_sv_extensions =
+const char *vm_sv_extensions =
 "BX_WAL_SUPPORT "
 "DP_BUTTONCHAT "
 "DP_BUTTONUSE "
@@ -19,10 +19,25 @@ char *vm_sv_extensions =
 "DP_CON_SET "
 "DP_CON_SETA "
 "DP_CON_STARTMAP "
+"DP_CRYPTO "
+"DP_CSQC_BINDMAPS "
+"DP_CSQC_ENTITYWORLDOBJECT "
+"DP_CSQC_ENTITYMODELLIGHT "
+"DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
+"DP_CSQC_MAINVIEW "
+"DP_CSQC_MINFPS_QUALITY "
 "DP_CSQC_MULTIFRAME_INTERPOLATION "
+"DP_CSQC_BOXPARTICLES "
+"DP_CSQC_SPAWNPARTICLE "
+"DP_CSQC_QUERYRENDERENTITY "
+"DP_CSQC_ROTATEMOVES "
+"DP_CSQC_SETPAUSE "
+"DP_CSQC_V_CALCREFDEF_WIP1 "
+"DP_CSQC_V_CALCREFDEF_WIP2 "
 "DP_EF_ADDITIVE "
 "DP_EF_BLUE "
 "DP_EF_DOUBLESIDED "
+"DP_EF_DYNAMICMODELLIGHT "
 "DP_EF_FLAME "
 "DP_EF_FULLBRIGHT "
 "DP_EF_NODEPTHTEST "
@@ -31,6 +46,7 @@ char *vm_sv_extensions =
 "DP_EF_NOSELFSHADOW "
 "DP_EF_NOSHADOW "
 "DP_EF_RED "
+"DP_EF_RESTARTANIM_BIT "
 "DP_EF_STARDUST "
 "DP_EF_TELEPORT_BIT "
 "DP_ENT_ALPHA "
@@ -41,26 +57,33 @@ char *vm_sv_extensions =
 "DP_ENT_GLOWMOD "
 "DP_ENT_LOWPRECISION "
 "DP_ENT_SCALE "
+"DP_ENT_TRAILEFFECTNUM "
 "DP_ENT_VIEWMODEL "
-"DP_GECKO_SUPPORT "
 "DP_GFX_EXTERNALTEXTURES "
 "DP_GFX_EXTERNALTEXTURES_PERMAP "
 "DP_GFX_FOG "
+"DP_GFX_MODEL_INTERPOLATION "
 "DP_GFX_QUAKE3MODELTAGS "
 "DP_GFX_SKINFILES "
 "DP_GFX_SKYBOX "
-"DP_GFX_MODEL_INTERPOLATION "
+"DP_GFX_FONTS "
+"DP_GFX_FONTS_FREETYPE "
+"DP_UTF8 "
+"DP_FONT_VARIABLEWIDTH "
 "DP_HALFLIFE_MAP "
 "DP_HALFLIFE_MAP_CVAR "
 "DP_HALFLIFE_SPRITE "
 "DP_INPUTBUTTONS "
+"DP_LIGHTSTYLE_STATICVALUE "
 "DP_LITSPRITES "
 "DP_LITSUPPORT "
 "DP_MONSTERWALK "
 "DP_MOVETYPEBOUNCEMISSILE "
+"DP_MOVETYPEFLYWORLDONLY "
 "DP_MOVETYPEFOLLOW "
 "DP_NULL_MODEL "
 "DP_QC_ASINACOSATANATAN2TAN "
+"DP_QC_AUTOCVARS "
 "DP_QC_CHANGEPITCH "
 "DP_QC_CMD "
 "DP_QC_COPYENTITY "
@@ -69,32 +92,40 @@ char *vm_sv_extensions =
 "DP_QC_CVAR_DESCRIPTION "
 "DP_QC_CVAR_STRING "
 "DP_QC_CVAR_TYPE "
+"DP_QC_DIGEST "
+"DP_QC_DIGEST_SHA256 "
 "DP_QC_EDICT_NUM "
 "DP_QC_ENTITYDATA "
+"DP_QC_ENTITYSTRING "
 "DP_QC_ETOS "
 "DP_QC_EXTRESPONSEPACKET "
 "DP_QC_FINDCHAIN "
-"DP_QC_FINDCHAIN_TOFIELD "
 "DP_QC_FINDCHAINFLAGS "
 "DP_QC_FINDCHAINFLOAT "
+"DP_QC_FINDCHAIN_TOFIELD "
 "DP_QC_FINDFLAGS "
 "DP_QC_FINDFLOAT "
 "DP_QC_FS_SEARCH "
 "DP_QC_GETLIGHT "
 "DP_QC_GETSURFACE "
+"DP_QC_GETSURFACETRIANGLE "
 "DP_QC_GETSURFACEPOINTATTRIBUTE "
 "DP_QC_GETTAGINFO "
 "DP_QC_GETTAGINFO_BONEPROPERTIES "
 "DP_QC_GETTIME "
 "DP_QC_GETTIME_CDTRACK "
+"DP_QC_I18N "
+"DP_QC_LOG "
 "DP_QC_MINMAXBOUND "
 "DP_QC_MULTIPLETEMPSTRINGS "
 "DP_QC_NUM_FOR_EDICT "
 "DP_QC_RANDOMVEC "
 "DP_QC_SINCOSSQRTPOW "
+"DP_QC_SPRINTF "
 "DP_QC_STRFTIME "
 "DP_QC_STRINGBUFFERS "
 "DP_QC_STRINGBUFFERS_CVARLIST "
+"DP_QC_STRINGBUFFERS_EXT_WIP "
 "DP_QC_STRINGCOLORFUNCTIONS "
 "DP_QC_STRING_CASE_FUNCTIONS "
 "DP_QC_STRREPLACE "
@@ -107,6 +138,7 @@ char *vm_sv_extensions =
 "DP_QC_UNLIMITEDTEMPSTRINGS "
 "DP_QC_URI_ESCAPE "
 "DP_QC_URI_GET "
+"DP_QC_URI_POST "
 "DP_QC_VECTOANGLES_WITH_ROLL "
 "DP_QC_VECTORVECTORS "
 "DP_QC_WHICHPACK "
@@ -115,18 +147,27 @@ char *vm_sv_extensions =
 "DP_QUAKE3_MAP "
 "DP_QUAKE3_MODEL "
 "DP_REGISTERCVAR "
+"DP_SKELETONOBJECTS "
 "DP_SND_DIRECTIONLESSATTNNONE "
 "DP_SND_FAKETRACKS "
+"DP_SND_SOUND7_WIP1 "
+"DP_SND_SOUND7_WIP2 "
 "DP_SND_OGGVORBIS "
+"DP_SND_SETPARAMS "
 "DP_SND_STEREOWAV "
+"DP_SND_GETSOUNDTIME "
+"DP_VIDEO_DPV "
+"DP_VIDEO_SUBTITLES "
 "DP_SOLIDCORPSE "
 "DP_SPRITE32 "
 "DP_SV_BOTCLIENT "
 "DP_SV_BOUNCEFACTOR "
+"DP_SV_CLIENTCAMERA "
 "DP_SV_CLIENTCOLORS "
 "DP_SV_CLIENTNAME "
 "DP_SV_CMD "
 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
+"DP_SV_DISCARDABLEDEMO "
 "DP_SV_DRAWONLYTOCLIENT "
 "DP_SV_DROPCLIENT "
 "DP_SV_EFFECT "
@@ -138,7 +179,9 @@ char *vm_sv_extensions =
 "DP_SV_ONENTITYNOSPAWNFUNCTION "
 "DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
 "DP_SV_PING "
+"DP_SV_PING_PACKETLOSS "
 "DP_SV_PLAYERPHYSICS "
+"DP_PHYSICS_ODE "
 "DP_SV_POINTPARTICLES "
 "DP_SV_POINTSOUND "
 "DP_SV_PRECACHEANYTIME "
@@ -169,6 +212,7 @@ char *vm_sv_extensions =
 "DP_VIEWZOOM "
 "EXT_BITSHIFT "
 "FRIK_FILE "
+"FTE_CSQC_SKELETONOBJECTS "
 "FTE_QC_CHECKPVS "
 "FTE_STRINGS "
 "KRIMZON_SV_PARSECLIENTCOMMAND "
@@ -192,42 +236,42 @@ This is the only valid way to move an object without using the physics of the wo
 setorigin (entity, origin)
 =================
 */
-static void VM_SV_setorigin (void)
+static void VM_SV_setorigin(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
-       float   *org;
 
        VM_SAFEPARMCOUNT(2, VM_setorigin);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setorigin: can not modify world entity\n");
+               VM_Warning(prog, "setorigin: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setorigin: can not modify free entity\n");
+               VM_Warning(prog, "setorigin: can not modify free entity\n");
                return;
        }
-       org = PRVM_G_VECTOR(OFS_PARM1);
-       VectorCopy (org, e->fields.server->origin);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), PRVM_serveredictvector(e, origin));
+       if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
+               e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
        SV_LinkEdict(e);
 }
 
 // TODO: rotate param isnt used.. could be a bug. please check this and remove it if possible [1/10/2008 Black]
-static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
+static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float *max, qboolean rotate)
 {
        int             i;
 
        for (i=0 ; i<3 ; i++)
                if (min[i] > max[i])
-                       PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
+                       prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
 
 // set derived values
-       VectorCopy (min, e->fields.server->mins);
-       VectorCopy (max, e->fields.server->maxs);
-       VectorSubtract (max, min, e->fields.server->size);
+       VectorCopy (min, PRVM_serveredictvector(e, mins));
+       VectorCopy (max, PRVM_serveredictvector(e, maxs));
+       VectorSubtract (max, min, PRVM_serveredictvector(e, size));
 
        SV_LinkEdict(e);
 }
@@ -242,27 +286,27 @@ LordHavoc: no it isn't...
 setsize (entity, minvector, maxvector)
 =================
 */
-static void VM_SV_setsize (void)
+static void VM_SV_setsize(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
-       float   *min, *max;
+       vec3_t mins, maxs;
 
        VM_SAFEPARMCOUNT(3, VM_setsize);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setsize: can not modify world entity\n");
+               VM_Warning(prog, "setsize: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setsize: can not modify free entity\n");
+               VM_Warning(prog, "setsize: can not modify free entity\n");
                return;
        }
-       min = PRVM_G_VECTOR(OFS_PARM1);
-       max = PRVM_G_VECTOR(OFS_PARM2);
-       SetMinMaxSize (e, min, max, false);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
+       SetMinMaxSize(prog, e, mins, maxs, false);
 }
 
 
@@ -274,7 +318,7 @@ setmodel(entity, model)
 =================
 */
 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
-static void VM_SV_setmodel (void)
+static void VM_SV_setmodel(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        dp_model_t      *mod;
@@ -285,29 +329,29 @@ static void VM_SV_setmodel (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setmodel: can not modify world entity\n");
+               VM_Warning(prog, "setmodel: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setmodel: can not modify free entity\n");
+               VM_Warning(prog, "setmodel: can not modify free entity\n");
                return;
        }
        i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
-       e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
-       e->fields.server->modelindex = i;
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
+       PRVM_serveredictfloat(e, modelindex) = i;
 
-       mod = sv.models[i];
+       mod = SV_GetModelByIndex(i);
 
        if (mod)
        {
                if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
-                       SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
+                       SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
                else
-                       SetMinMaxSize (e, quakemins, quakemaxs, true);
+                       SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
        }
        else
-               SetMinMaxSize (e, vec3_origin, vec3_origin, true);
+               SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
 }
 
 /*
@@ -319,16 +363,16 @@ single print to a specific client
 sprint(clientent, value)
 =================
 */
-static void VM_SV_sprint (void)
+static void VM_SV_sprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     entnum;
        char string[VM_STRINGTEMP_LENGTH];
 
-       VM_VarString(1, string, sizeof(string));
-
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
 
+       VM_VarString(prog, 1, string, sizeof(string));
+
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
        // LordHavoc: div0 requested that sprintto world  operate like print
        if (entnum == 0)
@@ -339,7 +383,7 @@ static void VM_SV_sprint (void)
 
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("tried to centerprint to a non-client\n");
+               VM_Warning(prog, "tried to centerprint to a non-client\n");
                return;
        }
 
@@ -361,7 +405,7 @@ single print to a specific client
 centerprint(clientent, value)
 =================
 */
-static void VM_SV_centerprint (void)
+static void VM_SV_centerprint(prvm_prog_t *prog)
 {
        client_t        *client;
        int                     entnum;
@@ -373,7 +417,7 @@ static void VM_SV_centerprint (void)
 
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("tried to centerprint to a non-client\n");
+               VM_Warning(prog, "tried to centerprint to a non-client\n");
                return;
        }
 
@@ -381,7 +425,7 @@ static void VM_SV_centerprint (void)
        if (!client->netconnection)
                return;
 
-       VM_VarString(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
        MSG_WriteChar(&client->netconnection->message,svc_centerprint);
        MSG_WriteString(&client->netconnection->message, string);
 }
@@ -393,16 +437,16 @@ VM_SV_particle
 particle(origin, color, count)
 =================
 */
-static void VM_SV_particle (void)
+static void VM_SV_particle(prvm_prog_t *prog)
 {
-       float           *org, *dir;
+       vec3_t          org, dir;
        float           color;
        float           count;
 
        VM_SAFEPARMCOUNT(4, VM_SV_particle);
 
-       org = PRVM_G_VECTOR(OFS_PARM0);
-       dir = PRVM_G_VECTOR(OFS_PARM1);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
        color = PRVM_G_FLOAT(OFS_PARM2);
        count = PRVM_G_FLOAT(OFS_PARM3);
        SV_StartParticle (org, dir, (int)color, (int)count);
@@ -415,16 +459,16 @@ VM_SV_ambientsound
 
 =================
 */
-static void VM_SV_ambientsound (void)
+static void VM_SV_ambientsound(prvm_prog_t *prog)
 {
        const char      *samp;
-       float           *pos;
+       vec3_t          pos;
        float           vol, attenuation;
        int                     soundnum, large;
 
        VM_SAFEPARMCOUNT(4, VM_SV_ambientsound);
 
-       pos = PRVM_G_VECTOR (OFS_PARM0);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
        samp = PRVM_G_STRING(OFS_PARM1);
        vol = PRVM_G_FLOAT(OFS_PARM2);
        attenuation = PRVM_G_FLOAT(OFS_PARM3);
@@ -472,46 +516,67 @@ Larger attenuations will drop off.
 
 =================
 */
-static void VM_SV_sound (void)
+static void VM_SV_sound(prvm_prog_t *prog)
 {
        const char      *sample;
        int                     channel;
        prvm_edict_t            *entity;
        int             volume;
+       int flags;
        float attenuation;
+       float pitchchange;
 
-       VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
+       VM_SAFEPARMCOUNTRANGE(4, 7, VM_SV_sound);
 
        entity = PRVM_G_EDICT(OFS_PARM0);
        channel = (int)PRVM_G_FLOAT(OFS_PARM1);
        sample = PRVM_G_STRING(OFS_PARM2);
        volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
-       attenuation = PRVM_G_FLOAT(OFS_PARM4);
        if (prog->argc < 5)
        {
                Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
                attenuation = 1;
        }
+       else
+               attenuation = PRVM_G_FLOAT(OFS_PARM4);
+       if (prog->argc < 6)
+               pitchchange = 0;
+       else
+               pitchchange = PRVM_G_FLOAT(OFS_PARM5) * 0.01f;
+
+       if (prog->argc < 7)
+       {
+               flags = 0;
+               if(channel >= 8 && channel <= 15) // weird QW feature
+               {
+                       flags |= CHANFLAG_RELIABLE;
+                       channel -= 8;
+               }
+       }
+       else
+               flags = PRVM_G_FLOAT(OFS_PARM6);
 
        if (volume < 0 || volume > 255)
        {
-               VM_Warning("SV_StartSound: volume must be in range 0-1\n");
+               VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("SV_StartSound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "SV_StartSound: attenuation must be in range 0-4\n");
                return;
        }
 
-       if (channel < 0 || channel > 7)
+       channel = CHAN_USER2ENGINE(channel);
+
+       if (!IS_CHAN(channel))
        {
-               VM_Warning("SV_StartSound: channel must be in range 0-7\n");
+               VM_Warning(prog, "SV_StartSound: channel must be in range 0-127\n");
                return;
        }
 
-       SV_StartSound (entity, channel, sample, volume, attenuation);
+       SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE, pitchchange);
 }
 
 /*
@@ -524,33 +589,35 @@ is omitted (since no entity is being tracked).
 
 =================
 */
-static void VM_SV_pointsound(void)
+static void VM_SV_pointsound(prvm_prog_t *prog)
 {
        const char      *sample;
        int             volume;
        float           attenuation;
+       float           pitchchange;
        vec3_t          org;
 
-       VM_SAFEPARMCOUNT(4, VM_SV_pointsound);
+       VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_pointsound);
 
        VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
        sample = PRVM_G_STRING(OFS_PARM1);
        volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
        attenuation = PRVM_G_FLOAT(OFS_PARM3);
+       pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
 
        if (volume < 0 || volume > 255)
        {
-               VM_Warning("SV_StartPointSound: volume must be in range 0-1\n");
+               VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
                return;
        }
 
        if (attenuation < 0 || attenuation > 4)
        {
-               VM_Warning("SV_StartPointSound: attenuation must be in range 0-4\n");
+               VM_Warning(prog, "SV_StartPointSound: attenuation must be in range 0-4\n");
                return;
        }
 
-       SV_StartPointSound (org, sample, volume, attenuation);
+       SV_StartPointSound (org, sample, volume, attenuation, pitchchange);
 }
 
 /*
@@ -564,9 +631,9 @@ if the tryents flag is set.
 traceline (vector1, vector2, movetype, ignore)
 =================
 */
-static void VM_SV_traceline (void)
+static void VM_SV_traceline(prvm_prog_t *prog)
 {
-       float   *v1, *v2;
+       vec3_t  v1, v2;
        trace_t trace;
        int             move;
        prvm_edict_t    *ent;
@@ -575,17 +642,17 @@ static void VM_SV_traceline (void)
 
        prog->xfunction->builtinsprofile += 30;
 
-       v1 = PRVM_G_VECTOR(OFS_PARM0);
-       v2 = PRVM_G_VECTOR(OFS_PARM1);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
        move = (int)PRVM_G_FLOAT(OFS_PARM2);
        ent = PRVM_G_EDICT(OFS_PARM3);
 
-       if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
+       if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
+               prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
        trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
 
-       VM_SetTraceGlobals(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
 
@@ -601,9 +668,9 @@ tracebox (vector1, vector mins, vector maxs, vector2, tryents)
 =================
 */
 // LordHavoc: added this for my own use, VERY useful, similar to traceline
-static void VM_SV_tracebox (void)
+static void VM_SV_tracebox(prvm_prog_t *prog)
 {
-       float   *v1, *v2, *m1, *m2;
+       vec3_t v1, v2, m1, m2;
        trace_t trace;
        int             move;
        prvm_edict_t    *ent;
@@ -612,69 +679,69 @@ static void VM_SV_tracebox (void)
 
        prog->xfunction->builtinsprofile += 30;
 
-       v1 = PRVM_G_VECTOR(OFS_PARM0);
-       m1 = PRVM_G_VECTOR(OFS_PARM1);
-       m2 = PRVM_G_VECTOR(OFS_PARM2);
-       v2 = PRVM_G_VECTOR(OFS_PARM3);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
        move = (int)PRVM_G_FLOAT(OFS_PARM4);
        ent = PRVM_G_EDICT(OFS_PARM5);
 
-       if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v2[1]) || IS_NAN(v2[2]))
-               PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
+       if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
+               prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
        trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
 
-       VM_SetTraceGlobals(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
-static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
+static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore)
 {
        int i;
        float gravity;
-       vec3_t move, end;
+       vec3_t move, end, tossentorigin, tossentmins, tossentmaxs;
        vec3_t original_origin;
        vec3_t original_velocity;
        vec3_t original_angles;
        vec3_t original_avelocity;
-       prvm_eval_t *val;
        trace_t trace;
 
-       VectorCopy(tossent->fields.server->origin   , original_origin   );
-       VectorCopy(tossent->fields.server->velocity , original_velocity );
-       VectorCopy(tossent->fields.server->angles   , original_angles   );
-       VectorCopy(tossent->fields.server->avelocity, original_avelocity);
+       VectorCopy(PRVM_serveredictvector(tossent, origin)   , original_origin   );
+       VectorCopy(PRVM_serveredictvector(tossent, velocity) , original_velocity );
+       VectorCopy(PRVM_serveredictvector(tossent, angles)   , original_angles   );
+       VectorCopy(PRVM_serveredictvector(tossent, avelocity), original_avelocity);
 
-       val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
-       if (val != NULL && val->_float != 0)
-               gravity = val->_float;
-       else
-               gravity = 1.0;
+       gravity = PRVM_serveredictfloat(tossent, gravity);
+       if (!gravity)
+               gravity = 1.0f;
        gravity *= sv_gravity.value * 0.025;
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
                SV_CheckVelocity (tossent);
-               tossent->fields.server->velocity[2] -= gravity;
-               VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
-               VectorScale (tossent->fields.server->velocity, 0.05, move);
-               VectorAdd (tossent->fields.server->origin, move, end);
-               trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
-               VectorCopy (trace.endpos, tossent->fields.server->origin);
-               tossent->fields.server->velocity[2] -= gravity;
+               PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
+               VectorMA (PRVM_serveredictvector(tossent, angles), 0.05, PRVM_serveredictvector(tossent, avelocity), PRVM_serveredictvector(tossent, angles));
+               VectorScale (PRVM_serveredictvector(tossent, velocity), 0.05, move);
+               VectorAdd (PRVM_serveredictvector(tossent, origin), move, end);
+               VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
+               VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
+               VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
+               trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
+               VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
+               PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
 
                if (trace.fraction < 1)
                        break;
        }
 
-       VectorCopy(original_origin   , tossent->fields.server->origin   );
-       VectorCopy(original_velocity , tossent->fields.server->velocity );
-       VectorCopy(original_angles   , tossent->fields.server->angles   );
-       VectorCopy(original_avelocity, tossent->fields.server->avelocity);
+       VectorCopy(original_origin   , PRVM_serveredictvector(tossent, origin)   );
+       VectorCopy(original_velocity , PRVM_serveredictvector(tossent, velocity) );
+       VectorCopy(original_angles   , PRVM_serveredictvector(tossent, angles)   );
+       VectorCopy(original_avelocity, PRVM_serveredictvector(tossent, avelocity));
 
        return trace;
 }
 
-static void VM_SV_tracetoss (void)
+static void VM_SV_tracetoss(prvm_prog_t *prog)
 {
        trace_t trace;
        prvm_edict_t    *ent;
@@ -687,14 +754,14 @@ static void VM_SV_tracetoss (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("tracetoss: can not use world entity\n");
+               VM_Warning(prog, "tracetoss: can not use world entity\n");
                return;
        }
        ignore = PRVM_G_EDICT(OFS_PARM1);
 
-       trace = SV_Trace_Toss (ent, ignore);
+       trace = SV_Trace_Toss(prog, ent, ignore);
 
-       VM_SetTraceGlobals(&trace);
+       VM_SetTraceGlobals(prog, &trace);
 }
 
 //============================================================================
@@ -702,7 +769,7 @@ static void VM_SV_tracetoss (void)
 static int checkpvsbytes;
 static unsigned char checkpvs[MAX_MAP_LEAFS/8];
 
-static int VM_SV_newcheckclient (int check)
+static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
 {
        int             i;
        prvm_edict_t    *ent;
@@ -726,14 +793,14 @@ static int VM_SV_newcheckclient (int check)
                // look up the client's edict
                ent = PRVM_EDICT_NUM(i);
                // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
-               if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
+               if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
                        continue;
                // found a valid client (possibly the same one again)
                break;
        }
 
 // get the PVS for the entity
-       VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
+       VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, view_ofs), org);
        checkpvsbytes = 0;
        if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
                checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
@@ -757,7 +824,7 @@ name checkclient ()
 =================
 */
 int c_invis, c_notvis;
-static void VM_SV_checkclient (void)
+static void VM_SV_checkclient(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent, *self;
        vec3_t  view;
@@ -767,21 +834,21 @@ static void VM_SV_checkclient (void)
        // find a new check if on a new frame
        if (sv.time - sv.lastchecktime >= 0.1)
        {
-               sv.lastcheck = VM_SV_newcheckclient (sv.lastcheck);
+               sv.lastcheck = VM_SV_newcheckclient(prog, sv.lastcheck);
                sv.lastchecktime = sv.time;
        }
 
        // return check if it might be visible
        ent = PRVM_EDICT_NUM(sv.lastcheck);
-       if (ent->priv.server->free || ent->fields.server->health <= 0)
+       if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
        {
                VM_RETURN_EDICT(prog->edicts);
                return;
        }
 
        // if current entity can't possibly see the check entity, return 0
-       self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
-       VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
+       self = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
+       VectorAdd(PRVM_serveredictvector(self, origin), PRVM_serveredictvector(self, view_ofs), view);
        if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
        {
                c_notvis++;
@@ -806,15 +873,15 @@ Should be fast but can be inexact.
 float checkpvs(vector viewpos, entity viewee) = #240;
 =================
 */
-static void VM_SV_checkpvs (void)
+static void VM_SV_checkpvs(prvm_prog_t *prog)
 {
-       vec3_t viewpos;
+       vec3_t viewpos, absmin, absmax;
        prvm_edict_t *viewee;
 #if 1
        unsigned char *pvs;
 #else
-       static int fatpvsbytes;
-       static unsigned char fatpvs[MAX_MAP_LEAFS/8];
+       int fatpvsbytes;
+       unsigned char fatpvs[MAX_MAP_LEAFS/8];
 #endif
 
        VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
@@ -823,13 +890,13 @@ static void VM_SV_checkpvs (void)
 
        if(viewee->priv.server->free)
        {
-               VM_Warning("checkpvs: can not check free entity\n");
+               VM_Warning(prog, "checkpvs: can not check free entity\n");
                PRVM_G_FLOAT(OFS_RETURN) = 4;
                return;
        }
 
 #if 1
-       if(!sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+       if(!sv.worldmodel || !sv.worldmodel->brush.GetPVS || !sv.worldmodel->brush.BoxTouchingPVS)
        {
                // no PVS support on this worldmodel... darn
                PRVM_G_FLOAT(OFS_RETURN) = 3;
@@ -842,10 +909,12 @@ static void VM_SV_checkpvs (void)
                PRVM_G_FLOAT(OFS_RETURN) = 2;
                return;
        }
-       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
+       VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
+       VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
+       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, pvs, absmin, absmax);
 #else
        // using fat PVS like FTEQW does (slow)
-       if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+       if(!sv.worldmodel || !sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
        {
                // no PVS support on this worldmodel... darn
                PRVM_G_FLOAT(OFS_RETURN) = 3;
@@ -858,7 +927,9 @@ static void VM_SV_checkpvs (void)
                PRVM_G_FLOAT(OFS_RETURN) = 2;
                return;
        }
-       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, viewee->fields.server->absmin, viewee->fields.server->absmax);
+       VectorCopy(PRVM_serveredictvector(viewee, absmin), absmin);
+       VectorCopy(PRVM_serveredictvector(viewee, absmax), absmax);
+       PRVM_G_FLOAT(OFS_RETURN) = sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, fatpvs, absmin, absmax);
 #endif
 }
 
@@ -872,7 +943,7 @@ Sends text over to the client's execution buffer
 stuffcmd (clientent, value, ...)
 =================
 */
-static void VM_SV_stuffcmd (void)
+static void VM_SV_stuffcmd(prvm_prog_t *prog)
 {
        int             entnum;
        client_t        *old;
@@ -883,11 +954,11 @@ static void VM_SV_stuffcmd (void)
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
-               VM_Warning("Can't stuffcmd to a non-client\n");
+               VM_Warning(prog, "Can't stuffcmd to a non-client\n");
                return;
        }
 
-       VM_VarString(1, string, sizeof(string));
+       VM_VarString(prog, 1, string, sizeof(string));
 
        old = host_client;
        host_client = svs.clients + entnum-1;
@@ -904,14 +975,14 @@ Returns a chain of entities that have origins within a spherical area
 findradius (origin, radius)
 =================
 */
-static void VM_SV_findradius (void)
+static void VM_SV_findradius(prvm_prog_t *prog)
 {
        prvm_edict_t *ent, *chain;
        vec_t radius, radius2;
        vec3_t org, eorg, mins, maxs;
        int i;
        int numtouchedicts;
-       prvm_edict_t *touchedicts[MAX_EDICTS];
+       static prvm_edict_t *touchedicts[MAX_EDICTS];
        int chainfield;
 
        VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
@@ -921,7 +992,7 @@ static void VM_SV_findradius (void)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
+               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -935,7 +1006,7 @@ static void VM_SV_findradius (void)
        maxs[0] = org[0] + (radius + 1);
        maxs[1] = org[1] + (radius + 1);
        maxs[2] = org[2] + (radius + 1);
-       numtouchedicts = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, touchedicts);
+       numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
        if (numtouchedicts > MAX_EDICTS)
        {
                // this never happens
@@ -948,23 +1019,23 @@ static void VM_SV_findradius (void)
                prog->xfunction->builtinsprofile++;
                // Quake did not return non-solid entities but darkplaces does
                // (note: this is the reason you can't blow up fallen zombies)
-               if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
+               if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
                        continue;
                // LordHavoc: compare against bounding box rather than center so it
                // doesn't miss large objects, and use DotProduct instead of Length
                // for a major speedup
-               VectorSubtract(org, ent->fields.server->origin, eorg);
+               VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
                if (sv_gameplayfix_findradiusdistancetobox.integer)
                {
-                       eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
-                       eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
-                       eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
+                       eorg[0] -= bound(PRVM_serveredictvector(ent, mins)[0], eorg[0], PRVM_serveredictvector(ent, maxs)[0]);
+                       eorg[1] -= bound(PRVM_serveredictvector(ent, mins)[1], eorg[1], PRVM_serveredictvector(ent, maxs)[1]);
+                       eorg[2] -= bound(PRVM_serveredictvector(ent, mins)[2], eorg[2], PRVM_serveredictvector(ent, maxs)[2]);
                }
                else
-                       VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
+                       VectorMAMAM(1, eorg, -0.5f, PRVM_serveredictvector(ent, mins), -0.5f, PRVM_serveredictvector(ent, maxs), eorg);
                if (DotProduct(eorg, eorg) < radius2)
                {
-                       PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
+                       PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
                        chain = ent;
                }
        }
@@ -972,13 +1043,13 @@ static void VM_SV_findradius (void)
        VM_RETURN_EDICT(chain);
 }
 
-static void VM_SV_precache_sound (void)
+static void VM_SV_precache_sound(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
        PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
 }
 
-static void VM_SV_precache_model (void)
+static void VM_SV_precache_model(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_precache_model);
        SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
@@ -992,7 +1063,7 @@ VM_SV_walkmove
 float(float yaw, float dist[, settrace]) walkmove
 ===============
 */
-static void VM_SV_walkmove (void)
+static void VM_SV_walkmove(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent;
        float   yaw, dist;
@@ -1006,22 +1077,22 @@ static void VM_SV_walkmove (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("walkmove: can not modify world entity\n");
+               VM_Warning(prog, "walkmove: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("walkmove: can not modify free entity\n");
+               VM_Warning(prog, "walkmove: can not modify free entity\n");
                return;
        }
        yaw = PRVM_G_FLOAT(OFS_PARM0);
        dist = PRVM_G_FLOAT(OFS_PARM1);
        settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
 
-       if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
+       if ( !( (int)PRVM_serveredictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
                return;
 
        yaw = yaw*M_PI*2 / 360;
@@ -1032,14 +1103,14 @@ static void VM_SV_walkmove (void)
 
 // save program state, because SV_movestep may call other progs
        oldf = prog->xfunction;
-       oldself = prog->globals.server->self;
+       oldself = PRVM_serverglobaledict(self);
 
        PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
 
 
 // restore program state
        prog->xfunction = oldf;
-       prog->globals.server->self = oldself;
+       PRVM_serverglobaledict(self) = oldself;
 }
 
 /*
@@ -1049,10 +1120,11 @@ VM_SV_droptofloor
 void() droptofloor
 ===============
 */
-static void VM_SV_droptofloor (void)
+
+static void VM_SV_droptofloor(prvm_prog_t *prog)
 {
        prvm_edict_t            *ent;
-       vec3_t          end;
+       vec3_t          end, entorigin, entmins, entmaxs;
        trace_t         trace;
 
        VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
@@ -1060,49 +1132,55 @@ static void VM_SV_droptofloor (void)
        // assume failure if it returns early
        PRVM_G_FLOAT(OFS_RETURN) = 0;
 
-       ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+       ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("droptofloor: can not modify world entity\n");
+               VM_Warning(prog, "droptofloor: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("droptofloor: can not modify free entity\n");
+               VM_Warning(prog, "droptofloor: can not modify free entity\n");
                return;
        }
 
-       VectorCopy (ent->fields.server->origin, end);
+       VectorCopy (PRVM_serveredictvector(ent, origin), end);
        end[2] -= 256;
 
        if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
-               SV_UnstickEntity(ent);
+               if (sv_gameplayfix_unstickentities.integer)
+                       SV_UnstickEntity(ent);
 
-       trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+       VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
+       VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
+       VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
+       trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
        if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
        {
                vec3_t offset, org;
-               VectorSet(offset, 0.5f * (ent->fields.server->mins[0] + ent->fields.server->maxs[0]), 0.5f * (ent->fields.server->mins[1] + ent->fields.server->maxs[1]), ent->fields.server->mins[2]);
-               VectorAdd(ent->fields.server->origin, offset, org);
+               VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
+               VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
                trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
                VectorSubtract(trace.endpos, offset, trace.endpos);
                if (trace.startsolid)
                {
-                       Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
-                       SV_UnstickEntity(ent);
+                       Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+                       if (sv_gameplayfix_unstickentities.integer)
+                               SV_UnstickEntity(ent);
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = 0;
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = 0;
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                }
                else if (trace.fraction < 1)
                {
-                       Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
-                       VectorCopy (trace.endpos, ent->fields.server->origin);
-                       SV_UnstickEntity(ent);
+                       Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+                       VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
+                       if (sv_gameplayfix_unstickentities.integer)
+                               SV_UnstickEntity(ent);
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                        // if support is destroyed, keep suspended (gross hack for floating items in various maps)
                        ent->priv.server->suspendedinairflag = true;
@@ -1113,10 +1191,10 @@ static void VM_SV_droptofloor (void)
                if (trace.fraction != 1)
                {
                        if (trace.fraction < 1)
-                               VectorCopy (trace.endpos, ent->fields.server->origin);
+                               VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
                        SV_LinkEdict(ent);
-                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-                       ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
+                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+                       PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
                        PRVM_G_FLOAT(OFS_RETURN) = 1;
                        // if support is destroyed, keep suspended (gross hack for floating items in various maps)
                        ent->priv.server->suspendedinairflag = true;
@@ -1131,7 +1209,7 @@ VM_SV_lightstyle
 void(float style, string value) lightstyle
 ===============
 */
-static void VM_SV_lightstyle (void)
+static void VM_SV_lightstyle(prvm_prog_t *prog)
 {
        int             style;
        const char      *val;
@@ -1144,7 +1222,7 @@ static void VM_SV_lightstyle (void)
        val = PRVM_G_STRING(OFS_PARM1);
 
        if( (unsigned) style >= MAX_LIGHTSTYLES ) {
-               PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
+               prog->error_cmd( "PF_lightstyle: style: %i >= 64", style );
        }
 
 // change the string in sv
@@ -1170,7 +1248,7 @@ static void VM_SV_lightstyle (void)
 VM_SV_checkbottom
 =============
 */
-static void VM_SV_checkbottom (void)
+static void VM_SV_checkbottom(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_checkbottom);
        PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
@@ -1181,10 +1259,12 @@ static void VM_SV_checkbottom (void)
 VM_SV_pointcontents
 =============
 */
-static void VM_SV_pointcontents (void)
+static void VM_SV_pointcontents(prvm_prog_t *prog)
 {
+       vec3_t point;
        VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
-       PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
+       PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(point));
 }
 
 /*
@@ -1195,19 +1275,19 @@ Pick a vector for the player to shoot along
 vector aim(entity, missilespeed)
 =============
 */
-static void VM_SV_aim (void)
+static void VM_SV_aim(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent, *check, *bestent;
        vec3_t  start, dir, end, bestdir;
        int             i, j;
        trace_t tr;
        float   dist, bestdist;
-       float   speed;
+       //float speed;
 
        VM_SAFEPARMCOUNT(2, VM_SV_aim);
 
        // assume failure if it returns early
-       VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
+       VectorCopy(PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
        // if sv_aim is so high it can't possibly accept anything, skip out early
        if (sv_aim.value >= 1)
                return;
@@ -1215,27 +1295,27 @@ static void VM_SV_aim (void)
        ent = PRVM_G_EDICT(OFS_PARM0);
        if (ent == prog->edicts)
        {
-               VM_Warning("aim: can not use world entity\n");
+               VM_Warning(prog, "aim: can not use world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("aim: can not use free entity\n");
+               VM_Warning(prog, "aim: can not use free entity\n");
                return;
        }
-       speed = PRVM_G_FLOAT(OFS_PARM1);
+       //speed = PRVM_G_FLOAT(OFS_PARM1);
 
-       VectorCopy (ent->fields.server->origin, start);
+       VectorCopy (PRVM_serveredictvector(ent, origin), start);
        start[2] += 20;
 
 // try sending a trace straight
-       VectorCopy (prog->globals.server->v_forward, dir);
+       VectorCopy (PRVM_serverglobalvector(v_forward), dir);
        VectorMA (start, 2048, dir, end);
        tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
-       if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
-       && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
+       if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
+       && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
        {
-               VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
+               VectorCopy (PRVM_serverglobalvector(v_forward), PRVM_G_VECTOR(OFS_RETURN));
                return;
        }
 
@@ -1249,18 +1329,18 @@ static void VM_SV_aim (void)
        for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
        {
                prog->xfunction->builtinsprofile++;
-               if (check->fields.server->takedamage != DAMAGE_AIM)
+               if (PRVM_serveredictfloat(check, takedamage) != DAMAGE_AIM)
                        continue;
                if (check == ent)
                        continue;
-               if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
+               if (teamplay.integer && PRVM_serveredictfloat(ent, team) > 0 && PRVM_serveredictfloat(ent, team) == PRVM_serveredictfloat(check, team))
                        continue;       // don't aim at teammate
                for (j=0 ; j<3 ; j++)
-                       end[j] = check->fields.server->origin[j]
-                       + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
+                       end[j] = PRVM_serveredictvector(check, origin)[j]
+                       + 0.5*(PRVM_serveredictvector(check, mins)[j] + PRVM_serveredictvector(check, maxs)[j]);
                VectorSubtract (end, start, dir);
                VectorNormalize (dir);
-               dist = DotProduct (dir, prog->globals.server->v_forward);
+               dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
                if (dist < bestdist)
                        continue;       // to far to turn
                tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
@@ -1273,9 +1353,9 @@ static void VM_SV_aim (void)
 
        if (bestent)
        {
-               VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
-               dist = DotProduct (dir, prog->globals.server->v_forward);
-               VectorScale (prog->globals.server->v_forward, dist, end);
+               VectorSubtract (PRVM_serveredictvector(bestent, origin), PRVM_serveredictvector(ent, origin), dir);
+               dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
+               VectorScale (PRVM_serverglobalvector(v_forward), dist, end);
                end[2] = dir[2];
                VectorNormalize (end);
                VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
@@ -1300,7 +1380,7 @@ MESSAGE WRITING
 #define        MSG_INIT                3               // write to the init string
 #define        MSG_ENTITY              5
 
-sizebuf_t *WriteDest (void)
+static sizebuf_t *WriteDest(prvm_prog_t *prog)
 {
        int             entnum;
        int             dest;
@@ -1313,18 +1393,18 @@ sizebuf_t *WriteDest (void)
                return &sv.datagram;
 
        case MSG_ONE:
-               ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
+               ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
                entnum = PRVM_NUM_FOR_EDICT(ent);
                if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
                {
-                       VM_Warning ("WriteDest: tried to write to non-client\n");
+                       VM_Warning(prog, "WriteDest: tried to write to non-client\n");
                        return &sv.reliable_datagram;
                }
                else
                        return &svs.clients[entnum-1].netconnection->message;
 
        default:
-               VM_Warning ("WriteDest: bad destination\n");
+               VM_Warning(prog, "WriteDest: bad destination\n");
        case MSG_ALL:
                return &sv.reliable_datagram;
 
@@ -1335,62 +1415,62 @@ sizebuf_t *WriteDest (void)
                return sv.writeentitiestoclient_msg;
        }
 
-       return NULL;
+       //return NULL;
 }
 
-static void VM_SV_WriteByte (void)
+static void VM_SV_WriteByte(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteByte);
-       MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteByte (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteChar (void)
+static void VM_SV_WriteChar(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteChar);
-       MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteChar (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteShort (void)
+static void VM_SV_WriteShort(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteShort);
-       MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteShort (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteLong (void)
+static void VM_SV_WriteLong(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteLong);
-       MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
+       MSG_WriteLong (WriteDest(prog), (int)PRVM_G_FLOAT(OFS_PARM1));
 }
 
-static void VM_SV_WriteAngle (void)
+static void VM_SV_WriteAngle(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteAngle);
-       MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       MSG_WriteAngle (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
 }
 
-static void VM_SV_WriteCoord (void)
+static void VM_SV_WriteCoord(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteCoord);
-       MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
+       MSG_WriteCoord (WriteDest(prog), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
 }
 
-static void VM_SV_WriteString (void)
+static void VM_SV_WriteString(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteString);
-       MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
+       MSG_WriteString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
 }
 
-static void VM_SV_WriteUnterminatedString (void)
+static void VM_SV_WriteUnterminatedString(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteUnterminatedString);
-       MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
+       MSG_WriteUnterminatedString (WriteDest(prog), PRVM_G_STRING(OFS_PARM1));
 }
 
 
-static void VM_SV_WriteEntity (void)
+static void VM_SV_WriteEntity(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_WriteEntity);
-       MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
+       MSG_WriteShort (WriteDest(prog), PRVM_G_EDICTNUM(OFS_PARM1));
 }
 
 // writes a picture as at most size bytes of data
@@ -1399,7 +1479,7 @@ static void VM_SV_WriteEntity (void)
 // if failed to read/compress:
 //   IMGNAME \0 \0 \0
 //#501 void(float dest, string name, float maxsize) WritePicture (DP_SV_WRITEPICTURE))
-static void VM_SV_WritePicture (void)
+static void VM_SV_WritePicture(prvm_prog_t *prog)
 {
        const char *imgname;
        void *buf;
@@ -1412,23 +1492,23 @@ static void VM_SV_WritePicture (void)
        if(size > 65535)
                size = 65535;
 
-       MSG_WriteString(WriteDest(), imgname);
+       MSG_WriteString(WriteDest(prog), imgname);
        if(Image_Compress(imgname, size, &buf, &size))
        {
                // actual picture
-               MSG_WriteShort(WriteDest(), size);
-               SZ_Write(WriteDest(), (unsigned char *) buf, size);
+               MSG_WriteShort(WriteDest(prog), size);
+               SZ_Write(WriteDest(prog), (unsigned char *) buf, size);
        }
        else
        {
                // placeholder
-               MSG_WriteShort(WriteDest(), 0);
+               MSG_WriteShort(WriteDest(prog), 0);
        }
 }
 
 //////////////////////////////////////////////////////////
 
-static void VM_SV_makestatic (void)
+static void VM_SV_makestatic(prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        int i, large;
@@ -1440,51 +1520,51 @@ static void VM_SV_makestatic (void)
        if (prog->argc >= 1)
                ent = PRVM_G_EDICT(OFS_PARM0);
        else
-               ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
+               ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(self));
        if (ent == prog->edicts)
        {
-               VM_Warning("makestatic: can not modify world entity\n");
+               VM_Warning(prog, "makestatic: can not modify world entity\n");
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("makestatic: can not modify free entity\n");
+               VM_Warning(prog, "makestatic: can not modify free entity\n");
                return;
        }
 
        large = false;
-       if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
+       if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
                large = true;
 
        if (large)
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic2);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
        else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
-               MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
        else
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
-               MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
 
-       MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
-       MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
+       MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, colormap));
+       MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, skin));
        for (i=0 ; i<3 ; i++)
        {
-               MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
-               MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
+               MSG_WriteCoord(&sv.signon, PRVM_serveredictvector(ent, origin)[i], sv.protocol);
+               MSG_WriteAngle(&sv.signon, PRVM_serveredictvector(ent, angles)[i], sv.protocol);
        }
 
 // throw the entity away now
-       PRVM_ED_Free (ent);
+       PRVM_ED_Free(prog, ent);
 }
 
 //=============================================================================
@@ -1494,7 +1574,7 @@ static void VM_SV_makestatic (void)
 VM_SV_setspawnparms
 ==============
 */
-static void VM_SV_setspawnparms (void)
+static void VM_SV_setspawnparms(prvm_prog_t *prog)
 {
        prvm_edict_t    *ent;
        int             i;
@@ -1513,7 +1593,7 @@ static void VM_SV_setspawnparms (void)
        // copy spawn parms out of the client_t
        client = svs.clients + i-1;
        for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
-               (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
+               (&PRVM_serverglobalfloat(parm1))[i] = client->spawn_parms[i];
 }
 
 /*
@@ -1528,12 +1608,12 @@ Returns a color vector indicating the lighting at the requested point.
 getlight(vector)
 =================
 */
-static void VM_SV_getlight (void)
+static void VM_SV_getlight(prvm_prog_t *prog)
 {
        vec3_t ambientcolor, diffusecolor, diffusenormal;
-       vec_t *p;
+       vec3_t p;
        VM_SAFEPARMCOUNT(1, VM_SV_getlight);
-       p = PRVM_G_VECTOR(OFS_PARM0);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
        VectorClear(ambientcolor);
        VectorClear(diffusecolor);
        VectorClear(diffusenormal);
@@ -1563,6 +1643,7 @@ void VM_CustomStats_Clear (void)
 
 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
 {
+       prvm_prog_t *prog = SVVM_prog;
        int                     i;
        char            s[17];
 
@@ -1605,7 +1686,7 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
 //          1: string (4 stats carrying a total of 16 charactures)
 //          2: float (one stat, float converted to an integer for transportation)
 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
-static void VM_SV_AddStat (void)
+static void VM_SV_AddStat(prvm_prog_t *prog)
 {
        int             off, i;
        unsigned char   type;
@@ -1617,7 +1698,7 @@ static void VM_SV_AddStat (void)
                vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
                if(!vm_customstats)
                {
-                       VM_Warning("PF_SV_AddStat: not enough memory\n");
+                       VM_Warning(prog, "PF_SV_AddStat: not enough memory\n");
                        return;
                }
        }
@@ -1628,17 +1709,17 @@ static void VM_SV_AddStat (void)
 
        if(i < 0)
        {
-               VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
+               VM_Warning(prog, "PF_SV_AddStat: index may not be less than 32\n");
                return;
        }
        if(i >= (MAX_CL_STATS-32))
        {
-               VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
+               VM_Warning(prog, "PF_SV_AddStat: index >= MAX_CL_STATS\n");
                return;
        }
        if(i > (MAX_CL_STATS-32-4) && type == 1)
        {
-               VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
+               VM_Warning(prog, "PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
                return;
        }
        vm_customstats[i].type          = type;
@@ -1656,33 +1737,33 @@ copies data from one entity to another
 copyentity(src, dst)
 =================
 */
-static void VM_SV_copyentity (void)
+static void VM_SV_copyentity(prvm_prog_t *prog)
 {
        prvm_edict_t *in, *out;
        VM_SAFEPARMCOUNT(2, VM_SV_copyentity);
        in = PRVM_G_EDICT(OFS_PARM0);
        if (in == prog->edicts)
        {
-               VM_Warning("copyentity: can not read world entity\n");
+               VM_Warning(prog, "copyentity: can not read world entity\n");
                return;
        }
        if (in->priv.server->free)
        {
-               VM_Warning("copyentity: can not read free entity\n");
+               VM_Warning(prog, "copyentity: can not read free entity\n");
                return;
        }
        out = PRVM_G_EDICT(OFS_PARM1);
        if (out == prog->edicts)
        {
-               VM_Warning("copyentity: can not modify world entity\n");
+               VM_Warning(prog, "copyentity: can not modify world entity\n");
                return;
        }
        if (out->priv.server->free)
        {
-               VM_Warning("copyentity: can not modify free entity\n");
+               VM_Warning(prog, "copyentity: can not modify free entity\n");
                return;
        }
-       memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
+       memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
        SV_LinkEdict(out);
 }
 
@@ -1696,11 +1777,10 @@ sets the color of a client and broadcasts the update to all connected clients
 setcolor(clientent, value)
 =================
 */
-static void VM_SV_setcolor (void)
+static void VM_SV_setcolor(prvm_prog_t *prog)
 {
        client_t *client;
        int entnum, i;
-       prvm_eval_t *val;
 
        VM_SAFEPARMCOUNT(2, VM_SV_setcolor);
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
@@ -1715,9 +1795,8 @@ static void VM_SV_setcolor (void)
        client = svs.clients + entnum-1;
        if (client->edict)
        {
-               if ((val = PRVM_EDICTFIELDVALUE(client->edict, prog->fieldoffsets.clientcolors)))
-                       val->_float = i;
-               client->edict->fields.server->team = (i & 15) + 1;
+               PRVM_serveredictfloat(client->edict, clientcolors) = i;
+               PRVM_serveredictfloat(client->edict, team) = (i & 15) + 1;
        }
        client->colors = i;
        if (client->old_colors != client->colors)
@@ -1737,41 +1816,43 @@ VM_SV_effect
 effect(origin, modelname, startframe, framecount, framerate)
 =================
 */
-static void VM_SV_effect (void)
+static void VM_SV_effect(prvm_prog_t *prog)
 {
        int i;
        const char *s;
+       vec3_t org;
        VM_SAFEPARMCOUNT(5, VM_SV_effect);
        s = PRVM_G_STRING(OFS_PARM1);
        if (!s[0])
        {
-               VM_Warning("effect: no model specified\n");
+               VM_Warning(prog, "effect: no model specified\n");
                return;
        }
 
        i = SV_ModelIndex(s, 1);
        if (!i)
        {
-               VM_Warning("effect: model not precached\n");
+               VM_Warning(prog, "effect: model not precached\n");
                return;
        }
 
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
        {
-               VM_Warning("effect: framecount < 1\n");
+               VM_Warning(prog, "effect: framecount < 1\n");
                return;
        }
 
        if (PRVM_G_FLOAT(OFS_PARM4) < 1)
        {
-               VM_Warning("effect: framerate < 1\n");
+               VM_Warning(prog, "effect: framerate < 1\n");
                return;
        }
 
-       SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
+       SV_StartEffect(org, i, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4));
 }
 
-static void VM_SV_te_blood (void)
+static void VM_SV_te_blood(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_blood);
        if (PRVM_G_FLOAT(OFS_PARM2) < 1)
@@ -1791,7 +1872,7 @@ static void VM_SV_te_blood (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_bloodshower (void)
+static void VM_SV_te_bloodshower(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(4, VM_SV_te_bloodshower);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1813,7 +1894,7 @@ static void VM_SV_te_bloodshower (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosionrgb (void)
+static void VM_SV_te_explosionrgb(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(2, VM_SV_te_explosionrgb);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1829,7 +1910,7 @@ static void VM_SV_te_explosionrgb (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlecube (void)
+static void VM_SV_te_particlecube(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(7, VM_SV_te_particlecube);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1859,7 +1940,7 @@ static void VM_SV_te_particlecube (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlerain (void)
+static void VM_SV_te_particlerain(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_SV_te_particlerain);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1885,7 +1966,7 @@ static void VM_SV_te_particlerain (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_particlesnow (void)
+static void VM_SV_te_particlesnow(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(5, VM_SV_te_particlesnow);
        if (PRVM_G_FLOAT(OFS_PARM3) < 1)
@@ -1911,7 +1992,7 @@ static void VM_SV_te_particlesnow (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spark (void)
+static void VM_SV_te_spark(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_spark);
        if (PRVM_G_FLOAT(OFS_PARM2) < 1)
@@ -1931,7 +2012,7 @@ static void VM_SV_te_spark (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_gunshotquad (void)
+static void VM_SV_te_gunshotquad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_gunshotquad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1943,7 +2024,7 @@ static void VM_SV_te_gunshotquad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spikequad (void)
+static void VM_SV_te_spikequad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_spikequad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1955,7 +2036,7 @@ static void VM_SV_te_spikequad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_superspikequad (void)
+static void VM_SV_te_superspikequad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_superspikequad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1967,7 +2048,7 @@ static void VM_SV_te_superspikequad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosionquad (void)
+static void VM_SV_te_explosionquad(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_explosionquad);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1979,7 +2060,7 @@ static void VM_SV_te_explosionquad (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_smallflash (void)
+static void VM_SV_te_smallflash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_smallflash);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -1991,7 +2072,7 @@ static void VM_SV_te_smallflash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_customflash (void)
+static void VM_SV_te_customflash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(4, VM_SV_te_customflash);
        if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
@@ -2013,7 +2094,7 @@ static void VM_SV_te_customflash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_gunshot (void)
+static void VM_SV_te_gunshot(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_gunshot);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2025,7 +2106,7 @@ static void VM_SV_te_gunshot (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_spike (void)
+static void VM_SV_te_spike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_spike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2037,7 +2118,7 @@ static void VM_SV_te_spike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_superspike (void)
+static void VM_SV_te_superspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_superspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2049,7 +2130,7 @@ static void VM_SV_te_superspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosion (void)
+static void VM_SV_te_explosion(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_explosion);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2061,7 +2142,7 @@ static void VM_SV_te_explosion (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_tarexplosion (void)
+static void VM_SV_te_tarexplosion(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_tarexplosion);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2073,7 +2154,7 @@ static void VM_SV_te_tarexplosion (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_wizspike (void)
+static void VM_SV_te_wizspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_wizspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2085,7 +2166,7 @@ static void VM_SV_te_wizspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_knightspike (void)
+static void VM_SV_te_knightspike(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_knightspike);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2097,7 +2178,7 @@ static void VM_SV_te_knightspike (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lavasplash (void)
+static void VM_SV_te_lavasplash(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_lavasplash);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2109,7 +2190,7 @@ static void VM_SV_te_lavasplash (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_teleport (void)
+static void VM_SV_te_teleport(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_teleport);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2121,7 +2202,7 @@ static void VM_SV_te_teleport (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_explosion2 (void)
+static void VM_SV_te_explosion2(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_explosion2);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2136,7 +2217,7 @@ static void VM_SV_te_explosion2 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning1 (void)
+static void VM_SV_te_lightning1(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning1);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2154,7 +2235,7 @@ static void VM_SV_te_lightning1 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning2 (void)
+static void VM_SV_te_lightning2(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning2);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2172,7 +2253,7 @@ static void VM_SV_te_lightning2 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_lightning3 (void)
+static void VM_SV_te_lightning3(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_lightning3);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2190,7 +2271,7 @@ static void VM_SV_te_lightning3 (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_beam (void)
+static void VM_SV_te_beam(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_beam);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2208,7 +2289,7 @@ static void VM_SV_te_beam (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_plasmaburn (void)
+static void VM_SV_te_plasmaburn(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_te_plasmaburn);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2219,7 +2300,7 @@ static void VM_SV_te_plasmaburn (void)
        SV_FlushBroadcastMessages();
 }
 
-static void VM_SV_te_flamejet (void)
+static void VM_SV_te_flamejet(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(3, VM_SV_te_flamejet);
        MSG_WriteByte(&sv.datagram, svc_temp_entity);
@@ -2237,269 +2318,9 @@ static void VM_SV_te_flamejet (void)
        SV_FlushBroadcastMessages();
 }
 
-void clippointtosurface(dp_model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
-{
-       int i, j, k;
-       float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
-       const int *e;
-       bestdist = 1000000000;
-       VectorCopy(p, out);
-       for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
-       {
-               // clip original point to each triangle of the surface and find the
-               // triangle that is closest
-               v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
-               v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
-               v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
-               TriangleNormal(v[0], v[1], v[2], facenormal);
-               VectorNormalize(facenormal);
-               offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
-               VectorMA(p, offsetdist, facenormal, temp);
-               for (j = 0, k = 2;j < 3;k = j, j++)
-               {
-                       VectorSubtract(v[k], v[j], edgenormal);
-                       CrossProduct(edgenormal, facenormal, sidenormal);
-                       VectorNormalize(sidenormal);
-                       offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
-                       if (offsetdist < 0)
-                               VectorMA(temp, offsetdist, sidenormal, temp);
-               }
-               dist = VectorDistance2(temp, p);
-               if (bestdist > dist)
-               {
-                       bestdist = dist;
-                       VectorCopy(temp, out);
-               }
-       }
-}
-
-static dp_model_t *getmodel(prvm_edict_t *ed)
-{
-       int modelindex;
-       if (!ed || ed->priv.server->free)
-               return NULL;
-       modelindex = (int)ed->fields.server->modelindex;
-       if (modelindex < 1 || modelindex >= MAX_MODELS)
-               return NULL;
-       return sv.models[modelindex];
-}
-
-static msurface_t *getsurface(dp_model_t *model, int surfacenum)
-{
-       if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
-               return NULL;
-       return model->data_surfaces + surfacenum + model->firstmodelsurface;
-}
-
-
-//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
-static void VM_SV_getsurfacenumpoints(void)
-{
-       dp_model_t *model;
-       msurface_t *surface;
-       VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
-       // return 0 if no such surface
-       if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-       {
-               PRVM_G_FLOAT(OFS_RETURN) = 0;
-               return;
-       }
-
-       // note: this (incorrectly) assumes it is a simple polygon
-       PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
-}
-//PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
-static void VM_SV_getsurfacepoint(void)
-{
-       prvm_edict_t *ed;
-       dp_model_t *model;
-       msurface_t *surface;
-       int pointnum;
-       VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
-       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-               return;
-       // note: this (incorrectly) assumes it is a simple polygon
-       pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
-       if (pointnum < 0 || pointnum >= surface->num_vertices)
-               return;
-       // FIXME: implement rotation/scaling
-       VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
-}
-//PF_getsurfacepointattribute,     // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
-// float SPA_POSITION = 0;
-// float SPA_S_AXIS = 1;
-// float SPA_T_AXIS = 2;
-// float SPA_R_AXIS = 3; // same as SPA_NORMAL
-// float SPA_TEXCOORDS0 = 4;
-// float SPA_LIGHTMAP0_TEXCOORDS = 5;
-// float SPA_LIGHTMAP0_COLOR = 6;
-static void VM_SV_getsurfacepointattribute(void)
-{
-       prvm_edict_t *ed;
-       dp_model_t *model;
-       msurface_t *surface;
-       int pointnum;
-       int attributetype;
-
-       VM_SAFEPARMCOUNT(4, VM_SV_getsurfacepoint);
-       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-               return;
-       // note: this (incorrectly) assumes it is a simple polygon
-       pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
-       if (pointnum < 0 || pointnum >= surface->num_vertices)
-               return;
-       // FIXME: implement rotation/scaling
-       attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
-
-       switch( attributetype ) {
-               // float SPA_POSITION = 0;
-               case 0:
-                       VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
-                       break;
-               // float SPA_S_AXIS = 1;
-               case 1:
-                       VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
-                       break;
-               // float SPA_T_AXIS = 2;
-               case 2:
-                       VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
-                       break;
-               // float SPA_R_AXIS = 3; // same as SPA_NORMAL
-               case 3:
-                       VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
-                       break;
-               // float SPA_TEXCOORDS0 = 4;
-               case 4: {
-                       float *ret = PRVM_G_VECTOR(OFS_RETURN);
-                       float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
-                       ret[0] = texcoord[0];
-                       ret[1] = texcoord[1];
-                       ret[2] = 0.0f;
-                       break;
-               }
-               // float SPA_LIGHTMAP0_TEXCOORDS = 5;
-               case 5: {
-                       float *ret = PRVM_G_VECTOR(OFS_RETURN);
-                       float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
-                       ret[0] = texcoord[0];
-                       ret[1] = texcoord[1];
-                       ret[2] = 0.0f;
-                       break;
-               }
-               // float SPA_LIGHTMAP0_COLOR = 6;
-               case 6:
-                       // ignore alpha for now..
-                       VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
-                       break;
-               default:
-                       VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
-                       break;
-       }
-}
-//PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
-static void VM_SV_getsurfacenormal(void)
-{
-       dp_model_t *model;
-       msurface_t *surface;
-       vec3_t normal;
-       VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
-       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-               return;
-       // FIXME: implement rotation/scaling
-       // note: this (incorrectly) assumes it is a simple polygon
-       // note: this only returns the first triangle, so it doesn't work very
-       // well for curved surfaces or arbitrary meshes
-       TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
-       VectorNormalize(normal);
-       VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
-}
-//PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
-static void VM_SV_getsurfacetexture(void)
-{
-       dp_model_t *model;
-       msurface_t *surface;
-       VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
-       PRVM_G_INT(OFS_RETURN) = OFS_NULL;
-       if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-               return;
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
-}
-//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
-static void VM_SV_getsurfacenearpoint(void)
-{
-       int surfacenum, best;
-       vec3_t clipped, p;
-       vec_t dist, bestdist;
-       prvm_edict_t *ed;
-       dp_model_t *model;
-       msurface_t *surface;
-       vec_t *point;
-       VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
-       PRVM_G_FLOAT(OFS_RETURN) = -1;
-       ed = PRVM_G_EDICT(OFS_PARM0);
-       point = PRVM_G_VECTOR(OFS_PARM1);
-
-       if (!ed || ed->priv.server->free)
-               return;
-       model = getmodel(ed);
-       if (!model || !model->num_surfaces)
-               return;
-
-       // FIXME: implement rotation/scaling
-       VectorSubtract(point, ed->fields.server->origin, p);
-       best = -1;
-       bestdist = 1000000000;
-       for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
-       {
-               surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
-               // 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];
-               clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
-               dist = VectorLength2(clipped);
-               if (dist < bestdist)
-               {
-                       // it is, check the nearest point on the actual geometry
-                       clippointtosurface(model, surface, p, clipped);
-                       VectorSubtract(clipped, p, clipped);
-                       dist += VectorLength2(clipped);
-                       if (dist < bestdist)
-                       {
-                               // that's closer too, store it as the best match
-                               best = surfacenum;
-                               bestdist = dist;
-                       }
-               }
-       }
-       PRVM_G_FLOAT(OFS_RETURN) = best;
-}
-//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
-static void VM_SV_getsurfaceclippedpoint(void)
-{
-       prvm_edict_t *ed;
-       dp_model_t *model;
-       msurface_t *surface;
-       vec3_t p, out;
-       VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
-       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
-       ed = PRVM_G_EDICT(OFS_PARM0);
-       if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
-               return;
-       // FIXME: implement rotation/scaling
-       VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
-       clippointtosurface(model, surface, p, out);
-       // FIXME: implement rotation/scaling
-       VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
-}
-
 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
 //this function originally written by KrimZon, made shorter by LordHavoc
-static void VM_SV_clientcommand (void)
+static void VM_SV_clientcommand(prvm_prog_t *prog)
 {
        client_t *temp_client;
        int i;
@@ -2515,93 +2336,79 @@ static void VM_SV_clientcommand (void)
 
        temp_client = host_client;
        host_client = svs.clients + i;
-       Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
+       Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true);
        host_client = temp_client;
 }
 
 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
-static void VM_SV_setattachment (void)
+static void VM_SV_setattachment(prvm_prog_t *prog)
 {
        prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
        prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
        const char *tagname = PRVM_G_STRING(OFS_PARM2);
-       prvm_eval_t *v;
-       int modelindex;
        dp_model_t *model;
+       int tagindex;
        VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
 
        if (e == prog->edicts)
        {
-               VM_Warning("setattachment: can not modify world entity\n");
+               VM_Warning(prog, "setattachment: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setattachment: can not modify free entity\n");
+               VM_Warning(prog, "setattachment: can not modify free entity\n");
                return;
        }
 
        if (tagentity == NULL)
                tagentity = prog->edicts;
 
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
-       if (v)
-               v->edict = PRVM_EDICT_TO_PROG(tagentity);
+       tagindex = 0;
 
-       v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
-       if (v)
-               v->_float = 0;
        if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
        {
-               modelindex = (int)tagentity->fields.server->modelindex;
-               if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
+               model = SV_GetModelFromEdict(tagentity);
+               if (model)
                {
-                       v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
-                       if (v->_float == 0)
+                       tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_serveredictfloat(tagentity, skin), tagname);
+                       if (tagindex == 0)
                                Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
                }
                else
                        Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
        }
+
+       PRVM_serveredictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
+       PRVM_serveredictfloat(e, tag_index) = tagindex;
 }
 
 /////////////////////////////////////////
 // DP_MD3_TAGINFO extension coded by VorteX
 
-int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
+static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
 {
        int i;
-       dp_model_t *model;
 
-       i = (int)e->fields.server->modelindex;
+       i = (int)PRVM_serveredictfloat(e, modelindex);
        if (i < 1 || i >= MAX_MODELS)
                return -1;
-       model = sv.models[i];
 
-       return Mod_Alias_GetTagIndexForName(model, (int)e->fields.server->skin, tagname);
+       return Mod_Alias_GetTagIndexForName(SV_GetModelByIndex(i), (int)PRVM_serveredictfloat(e, skin), tagname);
 }
 
-int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
 {
        int r;
        dp_model_t *model;
-       int frame;
-       int modelindex;
 
        *tagname = NULL;
        *parentindex = 0;
        Matrix4x4_CreateIdentity(tag_localmatrix);
 
-       if (tagindex >= 0
-        && (modelindex = (int)e->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
-        && (model = sv.models[(int)e->fields.server->modelindex])
-        && model->animscenes)
+       if (tagindex >= 0 && (model = SV_GetModelFromEdict(e)) && model->num_bones)
        {
-               frame = (int)e->fields.server->frame;
-               if (frame < 0 || frame >= model->numframes)
-                       frame = 0;
-
-               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.server->skin, model->animscenes[frame].firstframe, tagindex - 1, parentindex, tagname, tag_localmatrix);
+               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_serveredictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
 
                if(!r) // success?
                        *parentindex += 1;
@@ -2612,54 +2419,33 @@ int SV_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, cons
        return 1;
 }
 
-void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
+void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
-       prvm_eval_t *val;
        float scale;
        float pitchsign = 1;
-       int modelindex;
-       dp_model_t *model;
 
-       scale = 1;
-       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
-       if (val && val->_float != 0)
-               scale = val->_float;
+       scale = PRVM_serveredictfloat(ent, scale);
+       if (!scale)
+               scale = 1.0f;
        
        if (viewmatrix)
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], scale * cl_viewmodel_scale.value);
+               Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2], PRVM_serveredictvector(ent, v_angle)[0], PRVM_serveredictvector(ent, v_angle)[1], PRVM_serveredictvector(ent, v_angle)[2], scale * cl_viewmodel_scale.value);
        else
        {
-               if (
-                       ((modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)ent->fields.server->modelindex]))
-                       ?
-                               model->type == mod_alias
-                       :
-                               (
-                                       (((unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
-                                       ||
-                                       ((gamemode == GAME_TENEBRAE) && ((unsigned int)ent->fields.server->effects & (16 | 32)))
-                               )
-               )
-                       pitchsign = -1;
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], pitchsign * ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale);
+               pitchsign = SV_GetPitchSign(prog, ent);
+               Matrix4x4_CreateFromQuakeEntity(out, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], pitchsign * PRVM_serveredictvector(ent, angles)[0], PRVM_serveredictvector(ent, angles)[1], PRVM_serveredictvector(ent, angles)[2], scale);
        }
 }
 
-int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
+static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
 {
-       int modelindex;
-       int frame;
        dp_model_t *model;
-       if (tagindex >= 0
-        && (modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
-        && (model = sv.models[(int)ent->fields.server->modelindex])
-        && model->animscenes)
+       if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
        {
-               // if model has wrong frame, engine automatically switches to model first frame
-               frame = (int)ent->fields.server->frame;
-               if (frame < 0 || frame >= model->numframes)
-                       frame = 0;
-               return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
+               VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
+               VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
+               VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
+               return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
        }
        *out = identitymatrix;
        return 0;
@@ -2675,10 +2461,9 @@ int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out
 extern cvar_t cl_bob;
 extern cvar_t cl_bobcycle;
 extern cvar_t cl_bobup;
-int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
+static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
-       prvm_eval_t *val;
        int modelindex, attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
        dp_model_t *model;
@@ -2690,11 +2475,15 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        if (ent->priv.server->free)
                return 2;
 
-       modelindex = (int)ent->fields.server->modelindex;
+       modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
        if (modelindex <= 0 || modelindex >= MAX_MODELS)
                return 3;
 
-       model = sv.models[modelindex];
+       model = SV_GetModelByIndex(modelindex);
+
+       VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
+       VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
+       VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
 
        tagmatrix = identitymatrix;
        // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
@@ -2705,17 +2494,17 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                        return 5;
                // apply transformation by child's tagindex on parent entity and then
                // by parent entity itself
-               ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
+               ret = SV_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
                if (ret && attachloop == 0)
                        return ret;
-               SV_GetEntityMatrix(ent, &entitymatrix, false);
+               SV_GetEntityMatrix(prog, ent, &entitymatrix, false);
                Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
                // next iteration we process the parent entity
-               if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
+               if (PRVM_serveredictedict(ent, tag_entity))
                {
-                       tagindex = (int)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
-                       ent = PRVM_EDICT_NUM(val->edict);
+                       tagindex = (int)PRVM_serveredictfloat(ent, tag_index);
+                       ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, tag_entity));
                }
                else
                        break;
@@ -2723,17 +2512,17 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        }
 
        // RENDER_VIEWMODEL magic
-       if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)) && val->edict)
+       if (PRVM_serveredictedict(ent, viewmodelforclient))
        {
                Matrix4x4_Copy(&tagmatrix, out);
-               ent = PRVM_EDICT_NUM(val->edict);
+               ent = PRVM_EDICT_NUM(PRVM_serveredictedict(ent, viewmodelforclient));
 
-               SV_GetEntityMatrix(ent, &entitymatrix, true);
+               SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
                /*
                // Cl_bob, ported from rendering code
-               if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
+               if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
                {
                        double bob, cycle;
                        // LordHavoc: this code is *weird*, but not replacable (I think it
@@ -2748,7 +2537,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                                cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
                        // bob is proportional to velocity in the xy plane
                        // (don't count Z, or jumping messes it up)
-                       bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
+                       bob = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value;
                        bob = bob*0.3 + bob*0.7*cycle;
                        Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
                }
@@ -2759,11 +2548,11 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 
 //float(entity ent, string tagname) gettagindex;
 
-static void VM_SV_gettagindex (void)
+static void VM_SV_gettagindex(prvm_prog_t *prog)
 {
        prvm_edict_t *ent;
        const char *tag_name;
-       int modelindex, tag_index;
+       int tag_index;
 
        VM_SAFEPARMCOUNT(2, VM_SV_gettagindex);
 
@@ -2772,31 +2561,30 @@ static void VM_SV_gettagindex (void)
 
        if (ent == prog->edicts)
        {
-               VM_Warning("gettagindex: can't affect world entity\n");
+               VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
        }
        if (ent->priv.server->free)
        {
-               VM_Warning("gettagindex: can't affect free entity\n");
+               VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
        }
 
-       modelindex = (int)ent->fields.server->modelindex;
        tag_index = 0;
-       if (modelindex <= 0 || modelindex >= MAX_MODELS)
-               Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
+       if (!SV_GetModelFromEdict(ent))
+               Con_DPrintf("VM_SV_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
        else
        {
-               tag_index = SV_GetTagIndex(ent, tag_name);
+               tag_index = SV_GetTagIndex(prog, ent, tag_name);
                if (tag_index == 0)
-                       if(developer.integer >= 100)
-                               Con_Printf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
+                       if(developer_extra.integer)
+                               Con_DPrintf("VM_SV_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
        }
        PRVM_G_FLOAT(OFS_RETURN) = tag_index;
 }
 
 //vector(entity ent, float tagindex) gettaginfo;
-static void VM_SV_gettaginfo (void)
+static void VM_SV_gettaginfo(prvm_prog_t *prog)
 {
        prvm_edict_t *e;
        int tagindex;
@@ -2805,40 +2593,41 @@ static void VM_SV_gettaginfo (void)
        int parentindex;
        const char *tagname;
        int returncode;
-       prvm_eval_t *val;
-       vec3_t fo, le, up, trans;
+       vec3_t forward, left, up, origin;
+       const dp_model_t *model;
 
        VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
 
-       returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
-       Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, le, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
-       VectorScale(le, -1, prog->globals.server->v_right);
-       SV_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
-       Matrix4x4_ToVectors(&tag_localmatrix, fo, le, up, trans);
-
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_parent)))
-               val->_float = parentindex;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_name)))
-               val->string = tagname ? PRVM_SetTempString(tagname) : 0;
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_offset)))
-               VectorCopy(trans, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_forward)))
-               VectorCopy(fo, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_right)))
-               VectorScale(le, -1, val->vector);
-       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
-               VectorCopy(up, val->vector);
+       returncode = SV_GetTagMatrix(prog, &tag_matrix, e, tagindex);
+       Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
+       VectorCopy(forward, PRVM_serverglobalvector(v_forward));
+       VectorNegate(left, PRVM_serverglobalvector(v_right));
+       VectorCopy(up, PRVM_serverglobalvector(v_up));
+       VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
+       model = SV_GetModelFromEdict(e);
+       VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
+       VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, sv.time);
+       VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
+       SV_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
+       Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
+
+       PRVM_serverglobalfloat(gettaginfo_parent) = parentindex;
+       PRVM_serverglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
+       VectorCopy(forward, PRVM_serverglobalvector(gettaginfo_forward));
+       VectorNegate(left, PRVM_serverglobalvector(gettaginfo_right));
+       VectorCopy(up, PRVM_serverglobalvector(gettaginfo_up));
+       VectorCopy(origin, PRVM_serverglobalvector(gettaginfo_offset));
 
        switch(returncode)
        {
                case 1:
-                       VM_Warning("gettagindex: can't affect world entity\n");
+                       VM_Warning(prog, "gettagindex: can't affect world entity\n");
                        break;
                case 2:
-                       VM_Warning("gettagindex: can't affect free entity\n");
+                       VM_Warning(prog, "gettagindex: can't affect free entity\n");
                        break;
                case 3:
                        Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
@@ -2853,7 +2642,7 @@ static void VM_SV_gettaginfo (void)
 }
 
 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
-static void VM_SV_dropclient (void)
+static void VM_SV_dropclient(prvm_prog_t *prog)
 {
        int clientnum;
        client_t *oldhostclient;
@@ -2861,12 +2650,12 @@ static void VM_SV_dropclient (void)
        clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
        if (clientnum < 0 || clientnum >= svs.maxclients)
        {
-               VM_Warning("dropclient: not a client\n");
+               VM_Warning(prog, "dropclient: not a client\n");
                return;
        }
        if (!svs.clients[clientnum].active)
        {
-               VM_Warning("dropclient: that client slot is not connected\n");
+               VM_Warning(prog, "dropclient: that client slot is not connected\n");
                return;
        }
        oldhostclient = host_client;
@@ -2876,7 +2665,7 @@ static void VM_SV_dropclient (void)
 }
 
 //entity() spawnclient (DP_SV_BOTCLIENT)
-static void VM_SV_spawnclient (void)
+static void VM_SV_spawnclient(prvm_prog_t *prog)
 {
        int i;
        prvm_edict_t    *ed;
@@ -2900,7 +2689,7 @@ static void VM_SV_spawnclient (void)
 }
 
 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
-static void VM_SV_clienttype (void)
+static void VM_SV_clienttype(prvm_prog_t *prog)
 {
        int clientnum;
        VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
@@ -2922,16 +2711,16 @@ VM_SV_serverkey
 string(string key) serverkey
 ===============
 */
-void VM_SV_serverkey(void)
+static void VM_SV_serverkey(prvm_prog_t *prog)
 {
        char string[VM_STRINGTEMP_LENGTH];
        VM_SAFEPARMCOUNT(1, VM_SV_serverkey);
        InfoString_GetValue(svs.serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
 }
 
 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
-static void VM_SV_setmodelindex (void)
+static void VM_SV_setmodelindex(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
        dp_model_t      *mod;
@@ -2941,44 +2730,44 @@ static void VM_SV_setmodelindex (void)
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
        {
-               VM_Warning("setmodelindex: can not modify world entity\n");
+               VM_Warning(prog, "setmodelindex: can not modify world entity\n");
                return;
        }
        if (e->priv.server->free)
        {
-               VM_Warning("setmodelindex: can not modify free entity\n");
+               VM_Warning(prog, "setmodelindex: can not modify free entity\n");
                return;
        }
        i = (int)PRVM_G_FLOAT(OFS_PARM1);
        if (i <= 0 || i >= MAX_MODELS)
        {
-               VM_Warning("setmodelindex: invalid modelindex\n");
+               VM_Warning(prog, "setmodelindex: invalid modelindex\n");
                return;
        }
        if (!sv.model_precache[i][0])
        {
-               VM_Warning("setmodelindex: model not precached\n");
+               VM_Warning(prog, "setmodelindex: model not precached\n");
                return;
        }
 
-       e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
-       e->fields.server->modelindex = i;
+       PRVM_serveredictstring(e, model) = PRVM_SetEngineString(prog, sv.model_precache[i]);
+       PRVM_serveredictfloat(e, modelindex) = i;
 
-       mod = sv.models[i];
+       mod = SV_GetModelByIndex(i);
 
        if (mod)
        {
                if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
-                       SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
+                       SetMinMaxSize(prog, e, mod->normalmins, mod->normalmaxs, true);
                else
-                       SetMinMaxSize (e, quakemins, quakemaxs, true);
+                       SetMinMaxSize(prog, e, quakemins, quakemaxs, true);
        }
        else
-               SetMinMaxSize (e, vec3_origin, vec3_origin, true);
+               SetMinMaxSize(prog, e, vec3_origin, vec3_origin, true);
 }
 
 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
-static void VM_SV_modelnameforindex (void)
+static void VM_SV_modelnameforindex(prvm_prog_t *prog)
 {
        int i;
        VM_SAFEPARMCOUNT(1, VM_SV_modelnameforindex);
@@ -2988,20 +2777,20 @@ static void VM_SV_modelnameforindex (void)
        i = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (i <= 0 || i >= MAX_MODELS)
        {
-               VM_Warning("modelnameforindex: invalid modelindex\n");
+               VM_Warning(prog, "modelnameforindex: invalid modelindex\n");
                return;
        }
        if (!sv.model_precache[i][0])
        {
-               VM_Warning("modelnameforindex: model not precached\n");
+               VM_Warning(prog, "modelnameforindex: model not precached\n");
                return;
        }
 
-       PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(sv.model_precache[i]);
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(prog, sv.model_precache[i]);
 }
 
 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
-static void VM_SV_particleeffectnum (void)
+static void VM_SV_particleeffectnum(prvm_prog_t *prog)
 {
        int                     i;
        VM_SAFEPARMCOUNT(1, VM_SV_particleeffectnum);
@@ -3012,8 +2801,9 @@ static void VM_SV_particleeffectnum (void)
 }
 
 // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
-static void VM_SV_trailparticles (void)
+static void VM_SV_trailparticles(prvm_prog_t *prog)
 {
+       vec3_t start, end;
        VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
 
        if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
@@ -3022,13 +2812,15 @@ static void VM_SV_trailparticles (void)
        MSG_WriteByte(&sv.datagram, svc_trailparticles);
        MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
        MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
-       MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
-       MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
+       MSG_WriteVector(&sv.datagram, start, sv.protocol);
+       MSG_WriteVector(&sv.datagram, end, sv.protocol);
        SV_FlushBroadcastMessages();
 }
 
 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
-static void VM_SV_pointparticles (void)
+static void VM_SV_pointparticles(prvm_prog_t *prog)
 {
        int effectnum, count;
        vec3_t org, vel;
@@ -3062,12 +2854,12 @@ static void VM_SV_pointparticles (void)
 }
 
 //PF_setpause,    // void(float pause) setpause        = #531;
-static void VM_SV_setpause(void) {
+static void VM_SV_setpause(prvm_prog_t *prog) {
        int pauseValue;
        pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (pauseValue != 0) { //pause the game
                sv.paused = 1;
-               sv.pausedstart = Sys_DoubleTime();
+               sv.pausedstart = realtime;
        } else { //disable pause, in case it was enabled
                if (sv.paused != 0) {
                        sv.paused = 0;
@@ -3079,6 +2871,315 @@ static void VM_SV_setpause(void) {
        MSG_WriteByte(&sv.reliable_datagram, sv.paused);
 }
 
+// #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure  (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
+static void VM_SV_skel_create(prvm_prog_t *prog)
+{
+       int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
+       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       skeleton_t *skeleton;
+       int i;
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (!model || !model->num_bones)
+               return;
+       for (i = 0;i < MAX_EDICTS;i++)
+               if (!prog->skeletons[i])
+                       break;
+       if (i == MAX_EDICTS)
+               return;
+       prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(prog->progs_mempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
+       PRVM_G_FLOAT(OFS_RETURN) = i + 1;
+       skeleton->model = model;
+       skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
+       // initialize to identity matrices
+       for (i = 0;i < skeleton->model->num_bones;i++)
+               skeleton->relativetransforms[i] = identitymatrix;
+}
+
+// #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
+static void VM_SV_skel_build(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       skeleton_t *skeleton;
+       prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
+       int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
+       float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
+       int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
+       int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
+       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       float blendfrac;
+       int numblends;
+       int bonenum;
+       int blendindex;
+       framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
+       frameblend_t frameblend[MAX_FRAMEBLENDS];
+       matrix4x4_t blendedmatrix;
+       matrix4x4_t matrix;
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       firstbone = max(0, firstbone);
+       lastbone = min(lastbone, model->num_bones - 1);
+       lastbone = min(lastbone, skeleton->model->num_bones - 1);
+       VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
+       VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, sv.time);
+       blendfrac = 1.0f - retainfrac;
+       for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
+               frameblend[numblends].lerp *= blendfrac;
+       for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
+       {
+               memset(&blendedmatrix, 0, sizeof(blendedmatrix));
+               Matrix4x4_Accumulate(&blendedmatrix, &skeleton->relativetransforms[bonenum], retainfrac);
+               for (blendindex = 0;blendindex < numblends;blendindex++)
+               {
+                       Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
+                       Matrix4x4_Accumulate(&blendedmatrix, &matrix, frameblend[blendindex].lerp);
+               }
+               skeleton->relativetransforms[bonenum] = blendedmatrix;
+       }
+       PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
+}
+
+// #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
+static void VM_SV_skel_get_numbones(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       skeleton_t *skeleton;
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
+}
+
+// #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
+static void VM_SV_skel_get_bonename(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       skeleton_t *skeleton;
+       PRVM_G_INT(OFS_RETURN) = 0;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
+}
+
+// #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
+static void VM_SV_skel_get_boneparent(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       skeleton_t *skeleton;
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
+}
+
+// #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
+static void VM_SV_skel_find_bone(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       const char *tagname = PRVM_G_STRING(OFS_PARM1);
+       skeleton_t *skeleton;
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname) + 1;
+}
+
+// #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
+static void VM_SV_skel_get_bonerel(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       skeleton_t *skeleton;
+       matrix4x4_t matrix;
+       vec3_t forward, left, up, origin;
+       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       matrix = skeleton->relativetransforms[bonenum];
+       Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
+       VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
+}
+
+// #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
+static void VM_SV_skel_get_boneabs(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       skeleton_t *skeleton;
+       matrix4x4_t matrix;
+       matrix4x4_t temp;
+       vec3_t forward, left, up, origin;
+       VectorClear(PRVM_G_VECTOR(OFS_RETURN));
+       VectorClear(PRVM_clientglobalvector(v_forward));
+       VectorClear(PRVM_clientglobalvector(v_right));
+       VectorClear(PRVM_clientglobalvector(v_up));
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       matrix = skeleton->relativetransforms[bonenum];
+       // convert to absolute
+       while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
+       {
+               temp = matrix;
+               Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
+       }
+       Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
+       VectorCopy(forward, PRVM_clientglobalvector(v_forward));
+       VectorNegate(left, PRVM_clientglobalvector(v_right));
+       VectorCopy(up, PRVM_clientglobalvector(v_up));
+       VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
+}
+
+// #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+static void VM_SV_skel_set_bone(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       vec3_t forward, left, up, origin;
+       skeleton_t *skeleton;
+       matrix4x4_t matrix;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
+       Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
+       skeleton->relativetransforms[bonenum] = matrix;
+}
+
+// #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+static void VM_SV_skel_mul_bone(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       vec3_t forward, left, up, origin;
+       skeleton_t *skeleton;
+       matrix4x4_t matrix;
+       matrix4x4_t temp;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
+               return;
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
+       Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
+       temp = skeleton->relativetransforms[bonenum];
+       Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
+}
+
+// #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
+static void VM_SV_skel_mul_bones(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
+       int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
+       int bonenum;
+       vec3_t forward, left, up, origin;
+       skeleton_t *skeleton;
+       matrix4x4_t matrix;
+       matrix4x4_t temp;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
+       VectorCopy(PRVM_clientglobalvector(v_forward), forward);
+       VectorNegate(PRVM_clientglobalvector(v_right), left);
+       VectorCopy(PRVM_clientglobalvector(v_up), up);
+       Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
+       firstbone = max(0, firstbone);
+       lastbone = min(lastbone, skeleton->model->num_bones - 1);
+       for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
+       {
+               temp = skeleton->relativetransforms[bonenum];
+               Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
+       }
+}
+
+// #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
+static void VM_SV_skel_copybones(prvm_prog_t *prog)
+{
+       int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
+       int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
+       int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
+       int bonenum;
+       skeleton_t *skeletondst;
+       skeleton_t *skeletonsrc;
+       if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
+               return;
+       if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
+               return;
+       firstbone = max(0, firstbone);
+       lastbone = min(lastbone, skeletondst->model->num_bones - 1);
+       lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
+       for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
+               skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
+}
+
+// #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
+static void VM_SV_skel_delete(prvm_prog_t *prog)
+{
+       int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
+       skeleton_t *skeleton;
+       if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
+               return;
+       Mem_Free(skeleton);
+       prog->skeletons[skeletonindex] = NULL;
+}
+
+// #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
+static void VM_SV_frameforname(prvm_prog_t *prog)
+{
+       int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
+       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       const char *name = PRVM_G_STRING(OFS_PARM1);
+       int i;
+       PRVM_G_FLOAT(OFS_RETURN) = -1;
+       if (!model || !model->animscenes)
+               return;
+       for (i = 0;i < model->numframes;i++)
+       {
+               if (!strcasecmp(model->animscenes[i].name, name))
+               {
+                       PRVM_G_FLOAT(OFS_RETURN) = i;
+                       break;
+               }
+       }
+}
+
+// #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
+static void VM_SV_frameduration(prvm_prog_t *prog)
+{
+       int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
+       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
+       PRVM_G_FLOAT(OFS_RETURN) = 0;
+       if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
+               return;
+       if (model->animscenes[framenum].framerate)
+               PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
+}
+
+
 prvm_builtin_t vm_sv_builtins[] = {
 NULL,                                                  // #0 NULL function (not callable) (QUAKE)
 VM_makevectors,                                        // #1 void(vector ang) makevectors (QUAKE)
@@ -3147,7 +3248,7 @@ VM_changepitch,                                   // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH) (QUA
 VM_SV_tracetoss,                               // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) (QUAKE)
 VM_etos,                                               // #65 string(entity ent) etos (DP_QC_ETOS) (QUAKE)
 NULL,                                                  // #66 (QUAKE)
-SV_MoveToGoal,                                 // #67 void(float step) movetogoal (QUAKE)
+VM_SV_MoveToGoal,                              // #67 void(float step) movetogoal (QUAKE)
 VM_precache_file,                              // #68 string(string s) precache_file (QUAKE)
 VM_SV_makestatic,                              // #69 void(entity e) makestatic (QUAKE)
 VM_changelevel,                                        // #70 void(string s) changelevel (QUAKE)
@@ -3345,21 +3446,21 @@ NULL,                                                   // #259
 NULL,                                                  // #260
 NULL,                                                  // #261
 NULL,                                                  // #262
-NULL,                                                  // #263
-NULL,                                                  // #264
-NULL,                                                  // #265
-NULL,                                                  // #266
-NULL,                                                  // #267
-NULL,                                                  // #268
-NULL,                                                  // #269
-NULL,                                                  // #270
-NULL,                                                  // #271
-NULL,                                                  // #272
-NULL,                                                  // #273
-NULL,                                                  // #274
-NULL,                                                  // #275
-NULL,                                                  // #276
-NULL,                                                  // #277
+VM_SV_skel_create,                             // #263 float(float modlindex) skel_create = #263; // (DP_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure  (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
+VM_SV_skel_build,                              // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (DP_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
+VM_SV_skel_get_numbones,               // #265 float(float skel) skel_get_numbones = #265; // (DP_SKELETONOBJECTS) returns how many bones exist in the created skeleton
+VM_SV_skel_get_bonename,               // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (DP_SKELETONOBJECTS) returns name of bone (as a tempstring)
+VM_SV_skel_get_boneparent,             // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (DP_SKELETONOBJECTS) returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
+VM_SV_skel_find_bone,                  // #268 float(float skel, string tagname) skel_find_bone = #268; // (DP_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
+VM_SV_skel_get_bonerel,                        // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (DP_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
+VM_SV_skel_get_boneabs,                        // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (DP_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
+VM_SV_skel_set_bone,                   // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (DP_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+VM_SV_skel_mul_bone,                   // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (DP_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
+VM_SV_skel_mul_bones,                  // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (DP_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
+VM_SV_skel_copybones,                  // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (DP_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
+VM_SV_skel_delete,                             // #275 void(float skel) skel_delete = #275; // (DP_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
+VM_SV_frameforname,                            // #276 float(float modlindex, string framename) frameforname = #276; // (DP_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
+VM_SV_frameduration,                   // #277 float(float modlindex, float framenum) frameduration = #277; // (DP_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
 NULL,                                                  // #278
 NULL,                                                  // #279
 NULL,                                                  // #280
@@ -3518,12 +3619,12 @@ VM_SV_te_lightning3,                    // #430 void(entity own, vector start, vector end) te_lig
 VM_SV_te_beam,                                 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
 VM_vectorvectors,                              // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
 VM_SV_te_plasmaburn,                   // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
-VM_SV_getsurfacenumpoints,             // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
-VM_SV_getsurfacepoint,                 // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
-VM_SV_getsurfacenormal,                        // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
-VM_SV_getsurfacetexture,               // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
-VM_SV_getsurfacenearpoint,             // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
-VM_SV_getsurfaceclippedpoint,  // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
+VM_getsurfacenumpoints,                // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
+VM_getsurfacepoint,                    // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
+VM_getsurfacenormal,                   // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
+VM_getsurfacetexture,          // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
+VM_getsurfacenearpoint,                // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
+VM_getsurfaceclippedpoint,     // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
 VM_SV_clientcommand,                   // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
 VM_tokenize,                                   // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
 VM_argv,                                               // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
@@ -3570,7 +3671,7 @@ VM_cvar_defstring,                                // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTR
 VM_SV_pointsound,                              // #483 void(vector origin, string sample, float volume, float attenuation) (DP_SV_POINTSOUND)
 VM_strreplace,                                 // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
 VM_strireplace,                                        // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
-VM_SV_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
+VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
 NULL,                                                  // #487
 NULL,                                                  // #488
 NULL,                                                  // #489
@@ -3597,7 +3698,7 @@ NULL,                                                     // #509
 VM_uri_escape,                                 // #510 string(string in) uri_escape = #510;
 VM_uri_unescape,                               // #511 string(string in) uri_unescape = #511;
 VM_etof,                                       // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
-VM_uri_get,                                            // #513 float(string uril, float id) uri_get = #513; (DP_QC_URI_GET)
+VM_uri_get,                                            // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST)
 VM_tokenize_console,                                   // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
 VM_argv_start_index,                                   // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
 VM_argv_end_index,                                             // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
@@ -3613,20 +3714,20 @@ NULL,                                                   // #525
 NULL,                                                  // #526
 NULL,                                                  // #527
 NULL,                                                  // #528
-NULL,                                                  // #529
-NULL,                                                  // #530
+VM_loadfromdata,                               // #529
+VM_loadfromfile,                               // #530
 VM_SV_setpause,                                        // #531 void(float pause) setpause = #531;
-NULL,                                                  // #532
-NULL,                                                  // #533
-NULL,                                                  // #534
-NULL,                                                  // #535
-NULL,                                                  // #536
-NULL,                                                  // #537
-NULL,                                                  // #538
+VM_log,                                                        // #532
+VM_getsoundtime,                               // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
+VM_soundlength,                                        // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
+VM_buf_loadfile,                // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_buf_writefile,               // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_bufstr_find,                 // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
+VM_matchpattern,                // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
 NULL,                                                  // #539
-NULL,                                                  // #540
-NULL,                                                  // #541
-NULL,                                                  // #542
+VM_physics_enable,                             // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
+VM_physics_addforce,                   // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
+VM_physics_addtorque,                  // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
 NULL,                                                  // #543
 NULL,                                                  // #544
 NULL,                                                  // #545
@@ -3689,15 +3790,15 @@ NULL,                                                   // #601
 NULL,                                                  // #602
 NULL,                                                  // #603
 NULL,                                                  // #604
-NULL,                                                  // #605
-NULL,                                                  // #606
-NULL,                                                  // #607
+VM_callfunction,                               // #605
+VM_writetofile,                                        // #606
+VM_isfunction,                                 // #607
 NULL,                                                  // #608
 NULL,                                                  // #609
 NULL,                                                  // #610
 NULL,                                                  // #611
 NULL,                                                  // #612
-NULL,                                                  // #613
+VM_parseentitydata,                            // #613
 NULL,                                                  // #614
 NULL,                                                  // #615
 NULL,                                                  // #616
@@ -3708,26 +3809,42 @@ NULL,                                                   // #620
 NULL,                                                  // #621
 NULL,                                                  // #622
 NULL,                                                  // #623
-VM_getextresponse,                             // #624 string getextresponse(void)
+VM_SV_getextresponse,                  // #624 string getextresponse(void)
 NULL,                                                  // #625
+NULL,                                                  // #626
+VM_sprintf,                     // #627 string sprintf(string format, ...)
+VM_getsurfacenumtriangles,             // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
+VM_getsurfacetriangle,                 // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
+NULL,                                                  // #630
+NULL,                                                  // #631
+NULL,                                                  // #632
+NULL,                                                  // #633
+NULL,                                                  // #634
+NULL,                                                  // #635
+NULL,                                                  // #636
+NULL,                                                  // #637
+NULL,                                                  // #638
+VM_digest_hex,                                         // #639
+NULL,                                                  // #640
 };
 
 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
 
-void VM_SV_Cmd_Init(void)
+void SVVM_init_cmd(prvm_prog_t *prog)
 {
-       VM_Cmd_Init();
+       VM_Cmd_Init(prog);
 }
 
-void VM_SV_Cmd_Reset(void)
+void SVVM_reset_cmd(prvm_prog_t *prog)
 {
-       if(prog->funcoffsets.SV_Shutdown)
+       World_End(&sv.world);
+       if(PRVM_serverfunction(SV_Shutdown))
        {
-               func_t s = prog->funcoffsets.SV_Shutdown;
-               prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
-               PRVM_ExecuteProgram(s,"SV_Shutdown() required");
+               func_t s = PRVM_serverfunction(SV_Shutdown);
+               PRVM_serverglobalfloat(time) = sv.time;
+               PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again
+               prog->ExecuteProgram(prog, s,"SV_Shutdown() required");
        }
 
-       VM_Cmd_Reset();
+       VM_Cmd_Reset(prog);
 }
-