]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - clvm_cmds.c
ZQ_PAUSE extension patch from GreEn`mArine
[xonotic/darkplaces.git] / clvm_cmds.c
index 430aec87c70dc4ae2a791569611f2d97e75a32b7..7849ffe2a29b846d032a1704bc334a798904f8dd 100644 (file)
@@ -4,6 +4,8 @@
 #include "csprogs.h"
 #include "cl_collision.h"
 #include "r_shadow.h"
+#include "jpeg.h"
+#include "image.h"
 
 //============================================================================
 // Client
@@ -18,6 +20,8 @@
 //4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
 
+extern cvar_t v_flipped;
+
 sfx_t *S_FindName(const char *name);
 int Sbar_GetSortedPlayerIndex (int index);
 void Sbar_SortFrags (void);
@@ -226,12 +230,23 @@ static void VM_CL_spawn (void)
        VM_RETURN_EDICT(ed);
 }
 
+void CL_VM_SetTraceGlobals(const trace_t *trace, int svent)
+{
+       prvm_eval_t *val;
+       VM_SetTraceGlobals(trace);
+       if ((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.trace_networkentity)))
+               val->_float = svent;
+}
+
+#define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
+#define CL_HitNetworkPlayers(move)     !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS)
+
 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
 static void VM_CL_traceline (void)
 {
        float   *v1, *v2;
        trace_t trace;
-       int             move;
+       int             move, svent;
        prvm_edict_t    *ent;
 
        VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
@@ -246,9 +261,9 @@ static void VM_CL_traceline (void)
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || 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));
 
-       trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
 
-       VM_SetTraceGlobals(&trace);
+       CL_VM_SetTraceGlobals(&trace, svent);
 }
 
 /*
@@ -267,7 +282,7 @@ static void VM_CL_tracebox (void)
 {
        float   *v1, *v2, *m1, *m2;
        trace_t trace;
-       int             move;
+       int             move, svent;
        prvm_edict_t    *ent;
 
        VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
@@ -284,12 +299,12 @@ static void VM_CL_tracebox (void)
        if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || 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));
 
-       trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
 
-       VM_SetTraceGlobals(&trace);
+       CL_VM_SetTraceGlobals(&trace, svent);
 }
 
-trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
+trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
 {
        int i;
        float gravity;
@@ -339,6 +354,7 @@ static void VM_CL_tracetoss (void)
        trace_t trace;
        prvm_edict_t    *ent;
        prvm_edict_t    *ignore;
+       int svent;
 
        prog->xfunction->builtinsprofile += 600;
 
@@ -352,9 +368,9 @@ static void VM_CL_tracetoss (void)
        }
        ignore = PRVM_G_EDICT(OFS_PARM1);
 
-       trace = CL_Trace_Toss (ent, ignore);
+       trace = CL_Trace_Toss (ent, ignore, &svent);
 
-       VM_SetTraceGlobals(&trace);
+       CL_VM_SetTraceGlobals(&trace, svent);
 }
 
 
@@ -751,31 +767,31 @@ void VM_CL_R_SetView (void)
        switch(c)
        {
        case VF_MIN:
-               r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.x = (int)(f[0]);
+               r_refdef.view.y = (int)(f[1]);
                break;
        case VF_MIN_X:
-               r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
+               r_refdef.view.x = (int)(k);
                break;
        case VF_MIN_Y:
-               r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
+               r_refdef.view.y = (int)(k);
                break;
        case VF_SIZE:
-               r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.width = (int)(f[0]);
+               r_refdef.view.height = (int)(f[1]);
                break;
        case VF_SIZE_X:
-               r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
+               r_refdef.view.width = (int)(k);
                break;
        case VF_SIZE_Y:
-               r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
+               r_refdef.view.height = (int)(k);
                break;
        case VF_VIEWPORT:
-               r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.x = (int)(f[0]);
+               r_refdef.view.y = (int)(f[1]);
                f = PRVM_G_VECTOR(OFS_PARM2);
-               r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
-               r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
+               r_refdef.view.width = (int)(f[0]);
+               r_refdef.view.height = (int)(f[1]);
                break;
        case VF_FOV:
                r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
@@ -901,7 +917,8 @@ void VM_CL_R_AddDynamicLight (void)
        VectorScale(prog->globals.client->v_up, radius, up);
        Matrix4x4_FromVectors(&matrix, forward, left, up, org);
 
-       R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
+       r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights++];
 }
 
 //============================================================================
@@ -914,7 +931,9 @@ static void VM_CL_unproject (void)
 
        VM_SAFEPARMCOUNT(1, VM_CL_unproject);
        f = PRVM_G_VECTOR(OFS_PARM0);
-       VectorSet(temp, f[2], f[0] * f[2] * -r_refdef.view.frustum_x * 2.0 / r_refdef.view.width, f[1] * f[2] * -r_refdef.view.frustum_y * 2.0 / r_refdef.view.height);
+       if(v_flipped.integer)
+               f[0] = r_refdef.view.x + r_refdef.view.width - f[0];
+       VectorSet(temp, f[2], (-1.0 + 2.0 * (f[0] - r_refdef.view.x)) / r_refdef.view.width * f[2] * -r_refdef.view.frustum_x, (-1.0 + 2.0 * (f[1] - r_refdef.view.y))  / r_refdef.view.height * f[2] * -r_refdef.view.frustum_y);
        Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
 }
 
@@ -929,7 +948,9 @@ static void VM_CL_project (void)
        f = PRVM_G_VECTOR(OFS_PARM0);
        Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
        Matrix4x4_Transform(&m, f, v);
-       VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_refdef.view.frustum_x*0.5*r_refdef.view.width, v[2]/v[0]/-r_refdef.view.frustum_y*r_refdef.view.height*0.5, v[0]);
+       if(v_flipped.integer)
+               v[1] = -v[1];
+       VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x + r_refdef.view.width*0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x), r_refdef.view.y + r_refdef.view.height*0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y), v[0]);
 }
 
 //#330 float(float stnum) getstatf (EXT_CSQC)
@@ -1308,6 +1329,55 @@ static void VM_CL_ReadFloat (void)
        PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
 }
 
+//#501 string() readpicture (DP_CSQC_READWRITEPICTURE)
+extern cvar_t cl_readpicture_force;
+static void VM_CL_ReadPicture (void)
+{
+       const char *name;
+       unsigned char *data;
+       unsigned char *buf;
+       int size;
+       int i;
+       cachepic_t *pic;
+
+       VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
+
+       name = MSG_ReadString();
+       size = MSG_ReadShort();
+
+       // check if a texture of that name exists
+       // if yes, it is used and the data is discarded
+       // if not, the (low quality) data is used to build a new texture, whose name will get returned
+
+       pic = Draw_CachePic_Flags (name, CACHEPICFLAG_NOTPERSISTENT);
+
+       if(size)
+       {
+               if(pic->tex == r_texture_notexture)
+                       pic->tex = NULL; // don't overwrite the notexture by Draw_NewPic
+               if(pic->tex && !cl_readpicture_force.integer)
+               {
+                       // texture found and loaded
+                       // skip over the jpeg as we don't need it
+                       for(i = 0; i < size; ++i)
+                               MSG_ReadByte();
+               }
+               else
+               {
+                       // texture not found
+                       // use the attached jpeg as texture
+                       buf = (unsigned char *) Mem_Alloc(tempmempool, size);
+                       MSG_ReadBytes(size, buf);
+                       data = JPEG_LoadImage_BGRA(buf, size);
+                       Mem_Free(buf);
+                       Draw_NewPic(name, image_width, image_height, false, data);
+                       Mem_Free(data);
+               }
+       }
+
+       PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(name);
+}
+
 //////////////////////////////////////////////////////////
 
 static void VM_CL_makestatic (void)
@@ -2095,6 +2165,35 @@ void VM_CL_setattachment (void)
 /////////////////////////////////////////
 // DP_MD3_TAGINFO extension coded by VorteX
 
+int CL_GetExtendedTagInfo (prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
+{
+       int r;
+       dp_model_t *model;
+       int frame;
+
+       *tagname = NULL;
+       *parentindex = 0;
+       Matrix4x4_CreateIdentity(tag_localmatrix);
+
+       if (tagindex >= 0
+        && (model = CL_GetModelFromEdict(e))
+        && model->animscenes)
+       {
+               frame = (int)e->fields.client->frame;
+               if (frame < 0 || frame >= model->numframes)
+                       frame = 0;
+
+               r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)e->fields.client->skin, model->animscenes[frame].firstframe, tagindex - 1, parentindex, tagname, tag_localmatrix);
+
+               if(!r) // success?
+                       *parentindex += 1;
+
+               return r;
+       }
+
+       return 1;
+}
+
 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
 {
        dp_model_t *model = CL_GetModelFromEdict(e);
@@ -2192,6 +2291,7 @@ int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        if (val && val->_float != 0)
                scale = val->_float;
        // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
+       // FIXME: support RF_USEAXIS
        Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
        Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
 
@@ -2274,7 +2374,12 @@ void VM_CL_gettaginfo (void)
        prvm_edict_t *e;
        int tagindex;
        matrix4x4_t tag_matrix;
+       matrix4x4_t tag_localmatrix;
+       int parentindex;
+       const char *tagname;
        int returncode;
+       prvm_eval_t *val;
+       vec3_t fo, ri, up, trans;
 
        VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
 
@@ -2282,6 +2387,21 @@ void VM_CL_gettaginfo (void)
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
        returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
        Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
+       CL_GetExtendedTagInfo(e, tagindex, &parentindex, &tagname, &tag_localmatrix);
+       Matrix4x4_ToVectors(&tag_localmatrix, fo, ri, 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)))
+               VectorCopy(ri, val->vector);
+       if((val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.gettaginfo_up)))
+               VectorCopy(up, val->vector);
 
        switch(returncode)
        {
@@ -2322,6 +2442,7 @@ typedef struct vmpolygons_s
 {
        mempool_t               *pool;
        qboolean                initialized;
+       double          progstarttime;
 
        int                             max_vertices;
        int                             num_vertices;
@@ -2361,6 +2482,7 @@ void VM_CL_R_RenderScene (void)
        R_RenderView();
 
        polys->num_vertices = polys->num_triangles = 0;
+       polys->progstarttime = prog->starttime;
 }
 
 static void VM_ResizePolygons(vmpolygons_t *polys)
@@ -2412,23 +2534,31 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t
 {
        int surfacelistindex;
        vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       if(polys->progstarttime != prog->starttime) // from other progs? won't draw these (this can cause crashes!)
+               return;
+       R_Mesh_ResetTextureState();
        R_Mesh_Matrix(&identitymatrix);
        GL_CullFace(GL_NONE);
        R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
        R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
        R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
        R_SetupGenericShader(true);
+
        for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
        {
                int numtriangles = 0;
                rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
                int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
+               // this can't call _DrawQ_ProcessDrawFlag, but should be in sync with it
+               // FIXME factor this out
                if(drawflag == DRAWFLAG_ADDITIVE)
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
                else if(drawflag == DRAWFLAG_MODULATE)
                        GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
                else if(drawflag == DRAWFLAG_2XMODULATE)
                        GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
+               else if(drawflag == DRAWFLAG_SCREEN)
+                       GL_BlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ONE);
                else
                        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                R_Mesh_TexBind(0, R_GetTexture(tex));
@@ -2521,20 +2651,53 @@ void VM_CL_AddPolygonsToMeshQueue (void)
 void VM_CL_R_PolygonBegin (void)
 {
        const char              *picname;
+       skinframe_t     *sf;
        vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
+       int tf;
+
+       // TODO instead of using skinframes here (which provides the benefit of
+       // better management of flags, and is more suited for 3D rendering), what
+       // about supporting Q3 shaders?
 
        VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
 
        if (!polys->initialized)
                VM_InitPolygons(polys);
+       if(polys->progstarttime != prog->starttime)
+       {
+               // from another progs? then reset the polys first (fixes crashes on map change, because that can make skinframe textures invalid)
+               polys->num_vertices = polys->num_triangles = 0;
+               polys->progstarttime = prog->starttime;
+       }
        if (polys->begin_active)
        {
                VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
                return;
        }
        picname = PRVM_G_STRING(OFS_PARM0);
-       polys->begin_texture = picname[0] ? Draw_CachePic (picname)->tex : r_texture_white;
-       polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
+
+       sf = NULL;
+       if(*picname)
+       {
+               tf = TEXF_ALPHA;
+               if((int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MIPMAP)
+                       tf |= TEXF_MIPMAP;
+
+               do
+               {
+                       sf = R_SkinFrame_FindNextByName(sf, picname);
+               }
+               while(sf && sf->textureflags != tf);
+
+               if(!sf || !sf->base)
+                       sf = R_SkinFrame_LoadExternal(picname, tf, true);
+
+               if(sf)
+                       R_SkinFrame_MarkUsed(sf);
+       }
+
+       polys->begin_texture = (sf && sf->base) ? sf->base : r_texture_white;
+       polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1) & DRAWFLAG_MASK;
        polys->begin_vertices = 0;
        polys->begin_active = true;
 }
@@ -2689,7 +2852,7 @@ realcheck:
        start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
        start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
        stop[2] = start[2] - 2*sv_stepheight.value;
-       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
 
        if (trace.fraction == 1.0)
                return false;
@@ -2702,7 +2865,7 @@ realcheck:
                        start[0] = stop[0] = x ? maxs[0] : mins[0];
                        start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-                       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+                       trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true);
 
                        if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
                                bottom = trace.endpos[2];
@@ -2727,7 +2890,7 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        float           dz;
        vec3_t          oldorg, neworg, end, traceendpos;
        trace_t         trace;
-       int                     i;
+       int                     i, svent;
        prvm_edict_t            *enemy;
        prvm_eval_t     *val;
 
@@ -2751,9 +2914,9 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
                                if (dz < 30)
                                        neworg[2] += 8;
                        }
-                       trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+                       trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                        if (settrace)
-                               VM_SetTraceGlobals(&trace);
+                               CL_VM_SetTraceGlobals(&trace, svent);
 
                        if (trace.fraction == 1)
                        {
@@ -2779,16 +2942,16 @@ qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
        VectorCopy (neworg, end);
        end[2] -= sv_stepheight.value*2;
 
-       trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+       trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
        if (settrace)
-               VM_SetTraceGlobals(&trace);
+               CL_VM_SetTraceGlobals(&trace, svent);
 
        if (trace.startsolid)
        {
                neworg[2] -= sv_stepheight.value;
-               trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+               trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
                if (settrace)
-                       VM_SetTraceGlobals(&trace);
+                       CL_VM_SetTraceGlobals(&trace, svent);
                if (trace.startsolid)
                        return false;
        }
@@ -3247,8 +3410,8 @@ VM_drawfill,                                      // #323 float(vector position, vector size, vector rgb, float a
 VM_drawsetcliparea,                            // #324 void(float x, float y, float width, float height) drawsetcliparea
 VM_drawresetcliparea,                  // #325 void(void) drawresetcliparea
 VM_drawcolorcodedstring,               // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
-NULL,                                                  // #327 // FIXME add stringwidth() here?
-NULL,                                                  // #328 // FIXME add drawsubpic() here?
+VM_stringwidth,                 // #327 // FIXME is this okay?
+VM_drawsubpic,                                 // #328 // FIXME is this okay?
 NULL,                                                  // #329
 VM_CL_getstatf,                                        // #330 float(float stnum) getstatf (EXT_CSQC)
 VM_CL_getstati,                                        // #331 float(float stnum) getstati (EXT_CSQC)
@@ -3417,14 +3580,14 @@ VM_gecko_resize,                                        // #492 void gecko_resize( string name, float w, float h )
 VM_gecko_get_texture_extent,   // #493 vector gecko_get_texture_extent( string name )
 VM_crc16,                                              // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
 VM_cvar_type,                                  // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
-NULL,                                                  // #496
-NULL,                                                  // #497
-NULL,                                                  // #498
-NULL,                                                  // #499
-NULL,                                                  // #500
-NULL,                                                  // #501
+VM_numentityfields,                            // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA)
+VM_entityfieldname,                            // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
+VM_entityfieldtype,                            // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
+VM_getentityfieldstring,               // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
+VM_putentityfieldstring,               // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
+VM_CL_ReadPicture,                             // #501 string() ReadPicture = #501;
 NULL,                                                  // #502
-NULL,                                                  // #503
+VM_whichpack,                                  // #503 string(string) whichpack = #503;
 NULL,                                                  // #504
 NULL,                                                  // #505
 NULL,                                                  // #506
@@ -3434,13 +3597,26 @@ 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)
-NULL,                                                  // #513
-NULL,                                                  // #514
-NULL,                                                  // #515
-NULL,                                                  // #516
-NULL,                                                  // #517
-NULL,                                                  // #518
+VM_uri_get,                                            // #513 float(string uril, float id) uri_get = #512; (DP_QC_URI_GET)
+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)
+VM_buf_cvarlist,                                               // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
+VM_cvar_description,                                   // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
 NULL,                                                  // #519
+VM_keynumtostring,                             // #520 string keynumtostring(float keynum)
+VM_findkeysforcommand,         // #521 string findkeysforcommand(string command)
+NULL,                                                  // #522
+NULL,                                                  // #523
+NULL,                                                  // #524
+NULL,                                                  // #525
+NULL,                                                  // #526
+NULL,                                                  // #527
+NULL,                                                  // #528
+NULL,                                                  // #529
+NULL,                                                  // #530
+NULL,                                  // #531
+NULL,                                                  // #532
 };
 
 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);