]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - svvm_cmds.c
adding two new extensions: DP_QC_WHICHPACK (identify a pk3 containing a file), and...
[xonotic/darkplaces.git] / svvm_cmds.c
index 23a7524e0a4e9a583e5d9856e0d75673474dcbbf..d979e2fbad35e382c5bb496a789db7940b1fce5d 100644 (file)
@@ -1,4 +1,7 @@
+#include "quakedef.h"
+
 #include "prvm_cmds.h"
+#include "jpeg.h"
 
 //============================================================================
 // Server
@@ -11,6 +14,7 @@ char *vm_sv_extensions =
 "DP_BUTTONUSE "
 "DP_CL_LOADSKY "
 "DP_CON_ALIASPARAMETERS "
+"DP_CON_BESTWEAPON "
 "DP_CON_EXPANDCVAR "
 "DP_CON_SET "
 "DP_CON_SETA "
@@ -22,6 +26,7 @@ char *vm_sv_extensions =
 "DP_EF_FULLBRIGHT "
 "DP_EF_NODEPTHTEST "
 "DP_EF_NODRAW "
+"DP_EF_NOGUNBOB "
 "DP_EF_NOSHADOW "
 "DP_EF_RED "
 "DP_EF_STARDUST "
@@ -33,6 +38,7 @@ 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 "
@@ -50,8 +56,14 @@ char *vm_sv_extensions =
 "DP_MOVETYPEFOLLOW "
 "DP_QC_ASINACOSATANATAN2TAN "
 "DP_QC_CHANGEPITCH "
+"DP_QC_CMD "
 "DP_QC_COPYENTITY "
+"DP_QC_CRC16 "
+"DP_QC_CVAR_DEFSTRING "
 "DP_QC_CVAR_STRING "
+"DP_QC_CVAR_TYPE "
+"DP_QC_EDICT_NUM "
+"DP_QC_ENTITYDATA "
 "DP_QC_ETOS "
 "DP_QC_FINDCHAIN "
 "DP_QC_FINDCHAINFLAGS "
@@ -61,22 +73,28 @@ char *vm_sv_extensions =
 "DP_QC_FS_SEARCH "
 "DP_QC_GETLIGHT "
 "DP_QC_GETSURFACE "
+"DP_QC_GETSURFACEPOINTATTRIBUTE "
 "DP_QC_GETTAGINFO "
 "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_STRINGCOLORFUNCTIONS "
+"DP_QC_STRING_CASE_FUNCTIONS "
+"DP_QC_STRREPLACE "
 "DP_QC_TOKENIZEBYSEPARATOR "
 "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_VECTOANGLES_WITH_ROLL "
 "DP_QC_VECTORVECTORS "
+"DP_QC_WHICHPACK "
 "DP_QUAKE2_MODEL "
 "DP_QUAKE2_SPRITE "
 "DP_QUAKE3_MAP "
@@ -91,22 +109,30 @@ 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_MODELFLAGS_AS_EFFECTS "
+"DP_SV_MOVETYPESTEP_LANDEVENT "
 "DP_SV_NETADDRESS "
 "DP_SV_NODRAWTOCLIENT "
+"DP_SV_ONENTITYNOSPAWNFUNCTION "
 "DP_SV_PING "
 "DP_SV_PLAYERPHYSICS "
+"DP_SV_POINTPARTICLES "
+"DP_SV_POINTSOUND "
 "DP_SV_PRECACHEANYTIME "
 "DP_SV_PRINT "
 "DP_SV_PUNCHVECTOR "
 "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 "
@@ -124,8 +150,8 @@ char *vm_sv_extensions =
 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
 "DP_VIEWZOOM "
 "EXT_BITSHIFT "
-//"EXT_CSQC " // not ready yet
 "FRIK_FILE "
+"FTE_STRINGS "
 "KRIMZON_SV_PARSECLIENTCOMMAND "
 "NEH_CMD_PLAY2 "
 "NEH_RESTOREGAME "
@@ -134,8 +160,7 @@ char *vm_sv_extensions =
 "PRYDON_CLIENTCURSOR "
 "TENEBRAE_GFX_DLIGHTS "
 "TW_SV_STEPCONTROL "
-"DP_SV_CMD "
-"DP_QC_CMD "
+//"EXT_CSQC " // not ready yet
 ;
 
 /*
@@ -170,8 +195,8 @@ static void VM_SV_setorigin (void)
        SV_LinkEdict (e, false);
 }
 
-
-void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
+// 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)
 {
        int             i;
 
@@ -232,7 +257,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);
@@ -402,7 +427,7 @@ static void VM_SV_ambientsound (void)
 
        MSG_WriteVector(&sv.signon, pos, sv.protocol);
 
-       if (large)
+       if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
                MSG_WriteShort (&sv.signon, soundnum);
        else
                MSG_WriteByte (&sv.signon, soundnum);
@@ -469,6 +494,45 @@ static void VM_SV_sound (void)
        SV_StartSound (entity, channel, sample, volume, attenuation);
 }
 
+/*
+=================
+VM_SV_pointsound
+
+Follows the same logic as VM_SV_sound, except instead of
+an entity, an origin for the sound is provided, and channel
+is omitted (since no entity is being tracked).
+
+=================
+*/
+static void VM_SV_pointsound(void)
+{
+       const char      *sample;
+       int             volume;
+       float           attenuation;
+       vec3_t          org;
+
+       VM_SAFEPARMCOUNT(4, 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);
+
+       if (volume < 0 || volume > 255)
+       {
+               VM_Warning("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");
+               return;
+       }
+
+       SV_StartPointSound (org, sample, volume, attenuation);
+}
+
 /*
 =================
 VM_SV_traceline
@@ -651,7 +715,7 @@ static int VM_SV_newcheckclient (int check)
        VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
        checkpvsbytes = 0;
        if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
-               checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
+               checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs), false);
 
        return i;
 }
@@ -802,7 +866,7 @@ static void VM_SV_findradius (void)
                        eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
                }
                else
-                       VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
+                       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);
@@ -816,8 +880,7 @@ static void VM_SV_findradius (void)
 static void VM_SV_precache_sound (void)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
-       SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
-       PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
+       PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
 }
 
 static void VM_SV_precache_model (void)
@@ -917,18 +980,52 @@ static void VM_SV_droptofloor (void)
        VectorCopy (ent->fields.server->origin, end);
        end[2] -= 256;
 
-       trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+       if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
+               SV_UnstickEntity(ent);
 
-       if (trace.fraction != 1 || (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer))
-       {
-               if (trace.fraction < 1)
+       trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, 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);
+               trace = SV_Move (org, vec3_origin, vec3_origin, 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);
+                       SV_LinkEdict (ent, false);
+                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
+                       ent->fields.server->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_LinkEdict (ent, false);
-               ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
-               ent->fields.server->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;
+                       SV_UnstickEntity(ent);
+                       SV_LinkEdict (ent, false);
+                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
+                       ent->fields.server->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;
+               }
+       }
+       else
+       {
+               if (trace.fraction != 1)
+               {
+                       if (trace.fraction < 1)
+                               VectorCopy (trace.endpos, ent->fields.server->origin);
+                       SV_LinkEdict (ent, false);
+                       ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
+                       ent->fields.server->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;
+               }
        }
 }
 
@@ -1201,6 +1298,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 = 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(), buf, size);
+       }
+       else
+       {
+               // placeholder
+               MSG_WriteShort(WriteDest(), 0);
+       }
+}
+
 //////////////////////////////////////////////////////////
 
 static void VM_SV_makestatic (void)
@@ -1237,6 +1367,12 @@ static void VM_SV_makestatic (void)
                MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
                MSG_WriteShort (&sv.signon, (int)ent->fields.server->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);
+       }
        else
        {
                MSG_WriteByte (&sv.signon,svc_spawnstatic);
@@ -1354,11 +1490,11 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
                        stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
                        break;
                //float field sent as-is
-               case 2:
+               case 8:
                        stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
                        break;
                //integer value of float field
-               case 8:
+               case 2:
                        stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
                        break;
                default:
@@ -2006,7 +2142,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;
@@ -2042,7 +2178,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)
@@ -2053,7 +2189,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;
@@ -2064,7 +2200,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
@@ -2081,7 +2217,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);
@@ -2096,10 +2232,83 @@ static void VM_SV_getsurfacepoint(void)
        // 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)
 {
-       model_t *model;
+       dp_model_t *model;
        msurface_t *surface;
        vec3_t normal;
        VM_SAFEPARMCOUNT(2, VM_SV_getsurfacenormal);
@@ -2117,7 +2326,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;
@@ -2132,7 +2341,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);
@@ -2178,7 +2387,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);
@@ -2223,7 +2432,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)
@@ -2267,7 +2476,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)
@@ -2292,7 +2501,7 @@ 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])
@@ -2324,7 +2533,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
 
@@ -2432,7 +2641,8 @@ static void VM_SV_gettagindex (void)
        {
                tag_index = SV_GetTagIndex(ent, tag_name);
                if (tag_index == 0)
-                       Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
+                       if(developer.integer >= 100)
+                               Con_Printf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
        }
        PRVM_G_FLOAT(OFS_RETURN) = tag_index;
 };
@@ -2555,7 +2765,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);
 
@@ -2637,6 +2847,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));
@@ -2648,13 +2861,34 @@ static void VM_SV_trailparticles (void)
 //#337 void(float effectnum, vector origin, vector dir, float count) pointparticles (EXT_CSQC)
 static void VM_SV_pointparticles (void)
 {
-       VM_SAFEPARMCOUNT(4, VM_SV_pointparticles);
+       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);
+       count = bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535);
+       if (count == 1 && !VectorLength2(vel))
+       {
+               // 1+2+12=15 bytes
+               MSG_WriteByte(&sv.datagram, svc_pointparticles1);
+               MSG_WriteShort(&sv.datagram, effectnum);
+               MSG_WriteVector(&sv.datagram, org, sv.protocol);
+       }
+       else
+       {
+               // 1+2+12+12+2=29 bytes
+               MSG_WriteByte(&sv.datagram, svc_pointparticles);
+               MSG_WriteShort(&sv.datagram, effectnum);
+               MSG_WriteVector(&sv.datagram, org, sv.protocol);
+               MSG_WriteVector(&sv.datagram, vel, sv.protocol);
+               MSG_WriteShort(&sv.datagram, count);
+       }
 
-       MSG_WriteByte(&sv.datagram, svc_pointparticles);
-       MSG_WriteShort(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM0));
-       MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1), sv.protocol);
-       MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
-       MSG_WriteShort(&sv.datagram, bound(0, (int)PRVM_G_FLOAT(OFS_PARM3), 65535));
        SV_FlushBroadcastMessages();
 }
 
@@ -2882,16 +3116,16 @@ NULL,                                                   // #217
 VM_bitshift,                                   // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
 NULL,                                                  // #219
 NULL,                                                  // #220
-NULL,                                                  // #221
+VM_strstrofs,                                  // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
 VM_str2chr,                                            // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
 VM_chr2str,                                            // #223 string(float c, ...) chr2str (FTE_STRINGS)
-NULL,                                                  // #224
-NULL,                                                  // #225
-NULL,                                                  // #226
-NULL,                                                  // #227
+VM_strconv,                                            // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
+VM_strpad,                                             // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
+VM_infoadd,                                            // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
+VM_infoget,                                            // #227 string(string info, string key) infoget (FTE_STRINGS)
 VM_strncmp,                                            // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
-NULL,                                                  // #229
-NULL,                                                  // #230
+VM_strncasecmp,                                        // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
+VM_strncasecmp,                                        // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
 NULL,                                                  // #231
 VM_SV_AddStat,                                 // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
 NULL,                                                  // #233
@@ -3107,10 +3341,10 @@ VM_SV_clientcommand,                    // #440 void(entity e, string s) clientcommand (KRIMZON_S
 VM_tokenize,                                   // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
 VM_argv,                                               // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
 VM_SV_setattachment,                   // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
-VM_search_begin,                               // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
-VM_search_end,                                 // #445 void(float handle) search_end (DP_FS_SEARCH)
-VM_search_getsize,                             // #446 float(float handle) search_getsize (DP_FS_SEARCH)
-VM_search_getfilename,                 // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
+VM_search_begin,                               // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
+VM_search_end,                                 // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
+VM_search_getsize,                             // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
+VM_search_getfilename,                 // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
 VM_cvar_string,                                        // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
 VM_findflags,                                  // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
 VM_findchainflags,                             // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
@@ -3143,13 +3377,13 @@ VM_strlennocol,                                 // #476 float(string s) : DRESK - String Length (not countin
 VM_strdecolorize,                              // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
 VM_strftime,                                   // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
 VM_tokenizebyseparator,                        // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
-VM_strtolower,                                 // #480 string(string s) VM_strtolower : DRESK - Return string as lowercase
-VM_strtoupper,                                 // #481 string(string s) VM_strtoupper : DRESK - Return string as uppercase
-NULL,                                                  // #482
-NULL,                                                  // #483
-NULL,                                                  // #484
-NULL,                                                  // #485
-NULL,                                                  // #486
+VM_strtolower,                                 // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
+VM_strtoupper,                                 // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
+VM_cvar_defstring,                             // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
+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;
 NULL,                                                  // #487
 NULL,                                                  // #488
 NULL,                                                  // #489
@@ -3157,12 +3391,32 @@ NULL,                                                   // #490
 NULL,                                                  // #491
 NULL,                                                  // #492
 NULL,                                                  // #493
-NULL,                                                  // #494
-NULL,                                                  // #495
-NULL,                                                  // #496
-NULL,                                                  // #497
-NULL,                                                  // #498
-NULL,                                                  // #499
+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)
+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
+VM_whichpack,                                  // #503 string(string) whichpack = #503;
+NULL,                                                  // #504
+NULL,                                                  // #505
+NULL,                                                  // #506
+NULL,                                                  // #507
+NULL,                                                  // #508
+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
 };
 
 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
@@ -3174,6 +3428,13 @@ void VM_SV_Cmd_Init(void)
 
 void VM_SV_Cmd_Reset(void)
 {
+       if(prog->funcoffsets.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");
+       }
+
        VM_Cmd_Reset();
 }