]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - svvm_cmds.c
DP_QC_GETTIME_CDTRACK: extension to query the playing time of the current cd track.
[xonotic/darkplaces.git] / svvm_cmds.c
index ecdd3ef426561c171279b86d928b7a363f4c185e..bb689358c7f1357c97da7a9c915f61f554a58882 100644 (file)
@@ -1,6 +1,7 @@
 #include "quakedef.h"
 
 #include "prvm_cmds.h"
+#include "jpeg.h"
 
 //============================================================================
 // Server
@@ -13,10 +14,12 @@ char *vm_sv_extensions =
 "DP_BUTTONUSE "
 "DP_CL_LOADSKY "
 "DP_CON_ALIASPARAMETERS "
+"DP_CON_BESTWEAPON "
 "DP_CON_EXPANDCVAR "
 "DP_CON_SET "
 "DP_CON_SETA "
 "DP_CON_STARTMAP "
+"DP_CSQC_MULTIFRAME_INTERPOLATION "
 "DP_EF_ADDITIVE "
 "DP_EF_BLUE "
 "DP_EF_DOUBLESIDED "
@@ -24,10 +27,12 @@ char *vm_sv_extensions =
 "DP_EF_FULLBRIGHT "
 "DP_EF_NODEPTHTEST "
 "DP_EF_NODRAW "
-"DP_EF_NOSHADOW "
 "DP_EF_NOGUNBOB "
+"DP_EF_NOSELFSHADOW "
+"DP_EF_NOSHADOW "
 "DP_EF_RED "
 "DP_EF_STARDUST "
+"DP_EF_TELEPORT_BIT "
 "DP_ENT_ALPHA "
 "DP_ENT_COLORMOD "
 "DP_ENT_CUSTOMCOLORMAP "
@@ -36,12 +41,14 @@ char *vm_sv_extensions =
 "DP_ENT_LOWPRECISION "
 "DP_ENT_SCALE "
 "DP_ENT_VIEWMODEL "
+"DP_GECKO_SUPPORT "
 "DP_GFX_EXTERNALTEXTURES "
 "DP_GFX_EXTERNALTEXTURES_PERMAP "
 "DP_GFX_FOG "
 "DP_GFX_QUAKE3MODELTAGS "
 "DP_GFX_SKINFILES "
 "DP_GFX_SKYBOX "
+"DP_GFX_MODEL_INTERPOLATION "
 "DP_HALFLIFE_MAP "
 "DP_HALFLIFE_MAP_CVAR "
 "DP_HALFLIFE_SPRITE "
@@ -51,15 +58,21 @@ char *vm_sv_extensions =
 "DP_MONSTERWALK "
 "DP_MOVETYPEBOUNCEMISSILE "
 "DP_MOVETYPEFOLLOW "
+"DP_NULL_MODEL "
 "DP_QC_ASINACOSATANATAN2TAN "
 "DP_QC_CHANGEPITCH "
+"DP_QC_CMD "
 "DP_QC_COPYENTITY "
+"DP_QC_CRC16 "
 "DP_QC_CVAR_DEFSTRING "
-"DP_QC_CVAR_TYPE "
+"DP_QC_CVAR_DESCRIPTION "
 "DP_QC_CVAR_STRING "
+"DP_QC_CVAR_TYPE "
 "DP_QC_EDICT_NUM "
+"DP_QC_ENTITYDATA "
 "DP_QC_ETOS "
 "DP_QC_FINDCHAIN "
+"DP_QC_FINDCHAIN_TOFIELD "
 "DP_QC_FINDCHAINFLAGS "
 "DP_QC_FINDCHAINFLOAT "
 "DP_QC_FINDFLAGS "
@@ -67,23 +80,34 @@ char *vm_sv_extensions =
 "DP_QC_FS_SEARCH "
 "DP_QC_GETLIGHT "
 "DP_QC_GETSURFACE "
+"DP_QC_GETSURFACEPOINTATTRIBUTE "
 "DP_QC_GETTAGINFO "
+"DP_QC_GETTAGINFO_BONEPROPERTIES "
+"DP_QC_GETTIME "
+"DP_QC_GETTIME_CDTRACK "
 "DP_QC_MINMAXBOUND "
 "DP_QC_MULTIPLETEMPSTRINGS "
+"DP_QC_NUM_FOR_EDICT "
 "DP_QC_RANDOMVEC "
 "DP_QC_SINCOSSQRTPOW "
 "DP_QC_STRFTIME "
-"DP_QC_STRING_CASE_FUNCTIONS "
 "DP_QC_STRINGBUFFERS "
+"DP_QC_STRINGBUFFERS_CVARLIST "
 "DP_QC_STRINGCOLORFUNCTIONS "
+"DP_QC_STRING_CASE_FUNCTIONS "
+"DP_QC_STRREPLACE "
 "DP_QC_TOKENIZEBYSEPARATOR "
+"DP_QC_TOKENIZE_CONSOLE "
 "DP_QC_TRACEBOX "
 "DP_QC_TRACETOSS "
 "DP_QC_TRACE_MOVETYPE_HITMODEL "
 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
 "DP_QC_UNLIMITEDTEMPSTRINGS "
+"DP_QC_URI_ESCAPE "
+"DP_QC_URI_GET "
 "DP_QC_VECTOANGLES_WITH_ROLL "
 "DP_QC_VECTORVECTORS "
+"DP_QC_WHICHPACK "
 "DP_QUAKE2_MODEL "
 "DP_QUAKE2_SPRITE "
 "DP_QUAKE3_MAP "
@@ -98,15 +122,18 @@ char *vm_sv_extensions =
 "DP_SV_BOTCLIENT "
 "DP_SV_CLIENTCOLORS "
 "DP_SV_CLIENTNAME "
+"DP_SV_CMD "
 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
 "DP_SV_DRAWONLYTOCLIENT "
 "DP_SV_DROPCLIENT "
 "DP_SV_EFFECT "
 "DP_SV_ENTITYCONTENTSTRANSITION "
-"DP_SV_ONENTITYNOSPAWNFUNCTION "
 "DP_SV_MODELFLAGS_AS_EFFECTS "
+"DP_SV_MOVETYPESTEP_LANDEVENT "
 "DP_SV_NETADDRESS "
 "DP_SV_NODRAWTOCLIENT "
+"DP_SV_ONENTITYNOSPAWNFUNCTION "
+"DP_SV_ONENTITYPREPOSTSPAWNFUNCTION "
 "DP_SV_PING "
 "DP_SV_PLAYERPHYSICS "
 "DP_SV_POINTPARTICLES "
@@ -114,9 +141,13 @@ char *vm_sv_extensions =
 "DP_SV_PRECACHEANYTIME "
 "DP_SV_PRINT "
 "DP_SV_PUNCHVECTOR "
+"DP_SV_QCSTATUS "
 "DP_SV_ROTATINGBMODEL "
 "DP_SV_SETCOLOR "
+"DP_SV_SHUTDOWN "
 "DP_SV_SLOWMO "
+"DP_SV_SPAWNFUNC_PREFIX "
+"DP_SV_WRITEPICTURE "
 "DP_SV_WRITEUNTERMINATEDSTRING "
 "DP_TE_BLOOD "
 "DP_TE_BLOODSHOWER "
@@ -134,8 +165,9 @@ char *vm_sv_extensions =
 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
 "DP_VIEWZOOM "
 "EXT_BITSHIFT "
-//"EXT_CSQC " // not ready yet
 "FRIK_FILE "
+"FTE_QC_CHECKPVS "
+"FTE_STRINGS "
 "KRIMZON_SV_PARSECLIENTCOMMAND "
 "NEH_CMD_PLAY2 "
 "NEH_RESTOREGAME "
@@ -144,17 +176,8 @@ char *vm_sv_extensions =
 "PRYDON_CLIENTCURSOR "
 "TENEBRAE_GFX_DLIGHTS "
 "TW_SV_STEPCONTROL "
-"DP_SV_CMD "
-"DP_QC_CMD "
-"FTE_STRINGS "
-"DP_CON_BESTWEAPON "
-"DP_QC_STRREPLACE "
-"DP_QC_CRC16 "
-"DP_SV_SHUTDOWN "
-"DP_GECKO_SUPPORT "
-"DP_QC_GETSURFACEPOINTATTRIBUTE "
-"DP_QC_URI_ESCAPE "
-"DP_QC_NUM_FOR_EDICT "
+"ZQ_PAUSE "
+//"EXT_CSQC " // not ready yet
 ;
 
 /*
@@ -251,7 +274,7 @@ static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
 static void VM_SV_setmodel (void)
 {
        prvm_edict_t    *e;
-       model_t *mod;
+       dp_model_t      *mod;
        int             i;
 
        VM_SAFEPARMCOUNT(2, VM_setmodel);
@@ -554,7 +577,7 @@ static void VM_SV_traceline (void)
        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(v1[2]) || IS_NAN(v2[2]))
+       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));
 
        trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
@@ -593,7 +616,7 @@ static void VM_SV_tracebox (void)
        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(v1[2]) || IS_NAN(v2[2]))
+       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));
 
        trace = SV_Move (v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
@@ -623,7 +646,7 @@ static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
                gravity = val->_float;
        else
                gravity = 1.0;
-       gravity *= sv_gravity.value * 0.05;
+       gravity *= sv_gravity.value * 0.025;
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
@@ -634,6 +657,7 @@ static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
                VectorAdd (tossent->fields.server->origin, move, end);
                trace = SV_Move (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;
 
                if (trace.fraction < 1)
                        break;
@@ -769,6 +793,72 @@ static void VM_SV_checkclient (void)
 
 //============================================================================
 
+/*
+=================
+VM_SV_checkpvs
+
+Checks if an entity is in a point's PVS.
+Should be fast but can be inexact.
+
+float checkpvs(vector viewpos, entity viewee) = #240;
+=================
+*/
+static void VM_SV_checkpvs (void)
+{
+       vec3_t viewpos;
+       prvm_edict_t *viewee;
+#if 1
+       unsigned char *pvs;
+#else
+       static int fatpvsbytes;
+       static unsigned char fatpvs[MAX_MAP_LEAFS/8];
+#endif
+
+       VM_SAFEPARMCOUNT(2, VM_SV_checkpvs);
+       VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
+       viewee = PRVM_G_EDICT(OFS_PARM1);
+
+       if(viewee->priv.server->free)
+       {
+               VM_Warning("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)
+       {
+               // no PVS support on this worldmodel... darn
+               PRVM_G_FLOAT(OFS_RETURN) = 3;
+               return;
+       }
+       pvs = sv.worldmodel->brush.GetPVS(sv.worldmodel, viewpos);
+       if(!pvs)
+       {
+               // viewpos isn't in any PVS... darn
+               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);
+#else
+       // using fat PVS like FTEQW does (slow)
+       if(!sv.worldmodel->brush.FatPVS || !sv.worldmodel->brush.BoxTouchingPVS)
+       {
+               // no PVS support on this worldmodel... darn
+               PRVM_G_FLOAT(OFS_RETURN) = 3;
+               return;
+       }
+       fatpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
+       if(!fatpvsbytes)
+       {
+               // viewpos isn't in any PVS... darn
+               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);
+#endif
+}
+
 
 /*
 =================
@@ -819,8 +909,16 @@ static void VM_SV_findradius (void)
        int i;
        int numtouchedicts;
        prvm_edict_t *touchedicts[MAX_EDICTS];
+       int chainfield;
+
+       VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findradius);
 
-       VM_SAFEPARMCOUNT(2, VM_SV_findradius);
+       if(prog->argc == 3)
+               chainfield = PRVM_G_INT(OFS_PARM2);
+       else
+               chainfield = prog->fieldoffsets.chain;
+       if (chainfield < 0)
+               PRVM_ERROR("VM_findchain: %s doesnt have the specified chain field !", PRVM_NAME);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -863,7 +961,7 @@ static void VM_SV_findradius (void)
                        VectorMAMAM(1, eorg, -0.5f, ent->fields.server->mins, -0.5f, ent->fields.server->maxs, eorg);
                if (DotProduct(eorg, eorg) < radius2)
                {
-                       ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
+                       PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
                        chain = ent;
                }
        }
@@ -1292,6 +1390,39 @@ static void VM_SV_WriteEntity (void)
        MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
 }
 
+// writes a picture as at most size bytes of data
+// message:
+//   IMGNAME \0 SIZE(short) IMGDATA
+// 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)
+{
+       const char *imgname;
+       void *buf;
+       size_t size;
+
+       VM_SAFEPARMCOUNT(3, VM_SV_WritePicture);
+
+       imgname = PRVM_G_STRING(OFS_PARM1);
+       size = (int) PRVM_G_FLOAT(OFS_PARM2);
+       if(size > 65535)
+               size = 65535;
+
+       MSG_WriteString(WriteDest(), imgname);
+       if(Image_Compress(imgname, size, &buf, &size))
+       {
+               // actual picture
+               MSG_WriteShort(WriteDest(), size);
+               SZ_Write(WriteDest(), (unsigned char *) buf, size);
+       }
+       else
+       {
+               // placeholder
+               MSG_WriteShort(WriteDest(), 0);
+       }
+}
+
 //////////////////////////////////////////////////////////
 
 static void VM_SV_makestatic (void)
@@ -1649,9 +1780,9 @@ static void VM_SV_te_blood (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // velocity
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
        // count
        MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
        SV_FlushBroadcastMessages();
@@ -1789,9 +1920,9 @@ static void VM_SV_te_spark (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
        // velocity
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
-       MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
+       MSG_WriteChar(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
        // count
        MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
        SV_FlushBroadcastMessages();
@@ -2103,7 +2234,7 @@ static void VM_SV_te_flamejet (void)
        SV_FlushBroadcastMessages();
 }
 
-void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
+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;
@@ -2139,7 +2270,7 @@ void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t ou
        }
 }
 
-static model_t *getmodel(prvm_edict_t *ed)
+static dp_model_t *getmodel(prvm_edict_t *ed)
 {
        int modelindex;
        if (!ed || ed->priv.server->free)
@@ -2150,7 +2281,7 @@ static model_t *getmodel(prvm_edict_t *ed)
        return sv.models[modelindex];
 }
 
-static msurface_t *getsurface(model_t *model, int surfacenum)
+static msurface_t *getsurface(dp_model_t *model, int surfacenum)
 {
        if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
                return NULL;
@@ -2161,7 +2292,7 @@ static msurface_t *getsurface(model_t *model, int surfacenum)
 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
 static void VM_SV_getsurfacenumpoints(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenumpoints);
        // return 0 if no such surface
@@ -2178,7 +2309,7 @@ static void VM_SV_getsurfacenumpoints(void)
 static void VM_SV_getsurfacepoint(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        int pointnum;
        VM_SAFEPARMCOUNT(3, VM_SV_getsurfacepoint);
@@ -2204,7 +2335,7 @@ static void VM_SV_getsurfacepoint(void)
 static void VM_SV_getsurfacepointattribute(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        int pointnum;
        int attributetype;
@@ -2269,7 +2400,7 @@ static void VM_SV_getsurfacepointattribute(void)
 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
 static void VM_SV_getsurfacenormal(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec3_t normal;
        VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
@@ -2287,7 +2418,7 @@ static void VM_SV_getsurfacenormal(void)
 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
 static void VM_SV_getsurfacetexture(void)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        VM_SAFEPARMCOUNT(2, VM_SV_getsurfacetexture);
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
@@ -2302,7 +2433,7 @@ static void VM_SV_getsurfacenearpoint(void)
        vec3_t clipped, p;
        vec_t dist, bestdist;
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec_t *point;
        VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenearpoint);
@@ -2348,7 +2479,7 @@ static void VM_SV_getsurfacenearpoint(void)
 static void VM_SV_getsurfaceclippedpoint(void)
 {
        prvm_edict_t *ed;
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec3_t p, out;
        VM_SAFEPARMCOUNT(3, VM_SV_te_getsurfaceclippedpoint);
@@ -2393,7 +2524,7 @@ static void VM_SV_setattachment (void)
        const char *tagname = PRVM_G_STRING(OFS_PARM2);
        prvm_eval_t *v;
        int modelindex;
-       model_t *model;
+       dp_model_t *model;
        VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
 
        if (e == prog->edicts)
@@ -2437,7 +2568,7 @@ static void VM_SV_setattachment (void)
 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
 {
        int i;
-       model_t *model;
+       dp_model_t *model;
 
        i = (int)e->fields.server->modelindex;
        if (i < 1 || i >= MAX_MODELS)
@@ -2445,24 +2576,78 @@ int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
        model = sv.models[i];
 
        return Mod_Alias_GetTagIndexForName(model, (int)e->fields.server->skin, tagname);
-};
+}
+
+int SV_GetExtendedTagInfo (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)
+       {
+               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);
+
+               if(!r) // success?
+                       *parentindex += 1;
+
+               return r;
+       }
+
+       return 1;
+}
 
 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
 {
-       float scale = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float;
-       if (scale == 0)
-               scale = 1;
+       prvm_eval_t *val;
+       float scale;
+       float pitchsign;
+       int modelindex;
+       dp_model_t *model;
+
+       scale = 1;
+       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
+       if (val && val->_float != 0)
+               scale = val->_float;
+       
        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);
+               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);
        else
-               Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale * cl_viewmodel_scale.value);
+       {
+               pitchsign = 1;
+               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);
+       }
 }
 
 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
 {
        int modelindex;
        int frame;
-       model_t *model;
+       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])
@@ -2494,7 +2679,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
        prvm_eval_t *val;
        int modelindex, attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
-       model_t *model;
+       dp_model_t *model;
 
        *out = identitymatrix; // warnings and errors return identical matrix
 
@@ -2521,9 +2706,9 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
                if (ret && attachloop == 0)
                        return ret;
-               Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
                SV_GetEntityMatrix(ent, &entitymatrix, false);
-               Matrix4x4_Concat(&tagmatrix, &entitymatrix, out);
+               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)
                {
@@ -2614,7 +2799,12 @@ static void VM_SV_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, le, up, trans;
 
        VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
 
@@ -2622,7 +2812,23 @@ static void VM_SV_gettaginfo (void)
        tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
 
        returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
-       Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
+       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);
 
        switch(returncode)
        {
@@ -2726,7 +2932,7 @@ void VM_SV_serverkey(void)
 static void VM_SV_setmodelindex (void)
 {
        prvm_edict_t    *e;
-       model_t *mod;
+       dp_model_t      *mod;
        int             i;
        VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
 
@@ -2808,6 +3014,9 @@ static void VM_SV_trailparticles (void)
 {
        VM_SAFEPARMCOUNT(4, VM_SV_trailparticles);
 
+       if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
+               return;
+
        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));
@@ -2822,6 +3031,10 @@ static void VM_SV_pointparticles (void)
        int effectnum, count;
        vec3_t org, vel;
        VM_SAFEPARMCOUNTRANGE(4, 8, VM_SV_pointparticles);
+
+       if ((int)PRVM_G_FLOAT(OFS_PARM0) < 0)
+               return;
+
        effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM1), org);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
@@ -2846,6 +3059,24 @@ static void VM_SV_pointparticles (void)
        SV_FlushBroadcastMessages();
 }
 
+//PF_setpause,    // void(float pause) setpause        = #531;
+static void VM_SV_setpause(void) {
+       int pauseValue;
+       pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
+       if (pauseValue != 0) { //pause the game
+               sv.paused = 1;
+               sv.pausedstart = Sys_DoubleTime();
+       } else { //disable pause, in case it was enabled
+               if (sv.paused != 0) {
+                       sv.paused = 0;
+                       sv.pausedstart = 0;
+               }
+       }
+       // send notification to all clients
+       MSG_WriteByte(&sv.reliable_datagram, svc_setpause);
+       MSG_WriteByte(&sv.reliable_datagram, sv.paused);
+}
+
 prvm_builtin_t vm_sv_builtins[] = {
 NULL,                                                  // #0 NULL function (not callable) (QUAKE)
 VM_makevectors,                                        // #1 void(vector ang) makevectors (QUAKE)
@@ -2863,7 +3094,7 @@ VM_vlen,                                          // #12 float(vector v) vlen (QUAKE)
 VM_vectoyaw,                                   // #13 float(vector v) vectoyaw (QUAKE)
 VM_spawn,                                              // #14 entity() spawn (QUAKE)
 VM_remove,                                             // #15 void(entity e) remove (QUAKE)
-VM_SV_traceline,                               // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
+VM_SV_traceline,                               // #16 void(vector v1, vector v2, float tryents) traceline (QUAKE)
 VM_SV_checkclient,                             // #17 entity() checkclient (QUAKE)
 VM_find,                                               // #18 entity(entity start, .string fld, string match) find (QUAKE)
 VM_SV_precache_sound,                  // #19 void(string s) precache_sound (QUAKE)
@@ -3089,7 +3320,7 @@ NULL,                                                     // #236
 NULL,                                                  // #237
 NULL,                                                  // #238
 NULL,                                                  // #239
-NULL,                                                  // #240
+VM_SV_checkpvs,                                        // #240 float(vector viewpos, entity viewee) checkpvs;
 NULL,                                                  // #241
 NULL,                                                  // #242
 NULL,                                                  // #243
@@ -3347,14 +3578,14 @@ NULL,                                                   // #492
 NULL,                                                  // #493
 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; (DP_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_SV_WritePicture,                            // #501
 NULL,                                                  // #502
-NULL,                                                  // #503
+VM_whichpack,                                  // #503 string(string) whichpack = #503;
 NULL,                                                  // #504
 NULL,                                                  // #505
 NULL,                                                  // #506
@@ -3364,13 +3595,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
-NULL,                                                  // #519
+VM_uri_get,                                            // #513 float(string uril, float id) uri_get = #513; (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)
+VM_gettime,                                            // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
+NULL,                                                  // #520
+NULL,                                                  // #521
+NULL,                                                  // #522
+NULL,                                                  // #523
+NULL,                                                  // #524
+NULL,                                                  // #525
+NULL,                                                  // #526
+NULL,                                                  // #527
+NULL,                                                  // #528
+NULL,                                                  // #529
+NULL,                                                  // #530
+VM_SV_setpause,                                        // #531 void(float pause) setpause = #531;
+NULL,                                                  // #532
 };
 
 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);