]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - svvm_cmds.c
logarithm
[xonotic/darkplaces.git] / svvm_cmds.c
index 9be2ed7177462246757d76794166ff3ea82b7f9e..030bb92bf3bdc6ff478ea24f78de3cce97de2dd7 100644 (file)
@@ -1,9 +1,11 @@
+#include "quakedef.h"
+
 #include "prvm_cmds.h"
+#include "jpeg.h"
 
 //============================================================================
 // Server
 
-cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"}; //"0.93"}; // LordHavoc: disabled autoaim by default
 
 
 char *vm_sv_extensions =
@@ -12,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 "
@@ -23,23 +27,29 @@ char *vm_sv_extensions =
 "DP_EF_FULLBRIGHT "
 "DP_EF_NODEPTHTEST "
 "DP_EF_NODRAW "
+"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 "
 "DP_ENT_EXTERIORMODELTOCLIENT "
 "DP_ENT_GLOW "
+"DP_ENT_GLOWMOD "
 "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 "
@@ -49,12 +59,23 @@ 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_DESCRIPTION "
 "DP_QC_CVAR_STRING "
+"DP_QC_CVAR_TYPE "
+"DP_QC_EDICT_NUM "
+"DP_QC_ENTITYDATA "
+"DP_QC_ENTITYSTRING "
 "DP_QC_ETOS "
+"DP_QC_EXTRESPONSEPACKET "
 "DP_QC_FINDCHAIN "
+"DP_QC_FINDCHAIN_TOFIELD "
 "DP_QC_FINDCHAINFLAGS "
 "DP_QC_FINDCHAINFLOAT "
 "DP_QC_FINDFLAGS "
@@ -62,20 +83,35 @@ 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_LOG "
 "DP_QC_MINMAXBOUND "
 "DP_QC_MULTIPLETEMPSTRINGS "
+"DP_QC_NUM_FOR_EDICT "
 "DP_QC_RANDOMVEC "
 "DP_QC_SINCOSSQRTPOW "
 "DP_QC_STRFTIME "
 "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 "
@@ -88,22 +124,35 @@ char *vm_sv_extensions =
 "DP_SOLIDCORPSE "
 "DP_SPRITE32 "
 "DP_SV_BOTCLIENT "
+"DP_SV_BOUNCEFACTOR "
 "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_ONENTITYPREPOSTSPAWNFUNCTION "
 "DP_SV_PING "
 "DP_SV_PLAYERPHYSICS "
+"DP_SV_POINTPARTICLES "
+"DP_SV_POINTSOUND "
 "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 "
@@ -120,9 +169,11 @@ char *vm_sv_extensions =
 "DP_TE_STANDARDEFFECTBUILTINS "
 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
 "DP_VIEWZOOM "
+"DP_LIGHTSTYLE_STATICVALUE "
 "EXT_BITSHIFT "
-//"EXT_CSQC " // not ready yet
 "FRIK_FILE "
+"FTE_QC_CHECKPVS "
+"FTE_STRINGS "
 "KRIMZON_SV_PARSECLIENTCOMMAND "
 "NEH_CMD_PLAY2 "
 "NEH_RESTOREGAME "
@@ -131,6 +182,11 @@ char *vm_sv_extensions =
 "PRYDON_CLIENTCURSOR "
 "TENEBRAE_GFX_DLIGHTS "
 "TW_SV_STEPCONTROL "
+"ZQ_PAUSE "
+"DP_CSQC_SPAWNPARTICLE "
+"DP_CSQC_ENTITYTRANSPARENTSORTING_OFFSET "
+"DP_CSQC_ENTITYNOCULL "
+//"EXT_CSQC " // not ready yet
 ;
 
 /*
@@ -162,11 +218,11 @@ static void VM_SV_setorigin (void)
        }
        org = PRVM_G_VECTOR(OFS_PARM1);
        VectorCopy (org, e->fields.server->origin);
-       SV_LinkEdict (e, false);
+       SV_LinkEdict(e);
 }
 
-
-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;
 
@@ -179,7 +235,7 @@ void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
        VectorCopy (max, e->fields.server->maxs);
        VectorSubtract (max, min, e->fields.server->size);
 
-       SV_LinkEdict (e, false);
+       SV_LinkEdict(e);
 }
 
 /*
@@ -227,7 +283,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);
@@ -275,9 +331,17 @@ static void VM_SV_sprint (void)
        int                     entnum;
        char string[VM_STRINGTEMP_LENGTH];
 
+       VM_VarString(1, string, sizeof(string));
+
        VM_SAFEPARMCOUNTRANGE(2, 8, VM_SV_sprint);
 
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
+       // LordHavoc: div0 requested that sprintto world  operate like print
+       if (entnum == 0)
+       {
+               Con_Print(string);
+               return;
+       }
 
        if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
        {
@@ -289,7 +353,6 @@ static void VM_SV_sprint (void)
        if (!client->netconnection)
                return;
 
-       VM_VarString(1, string, sizeof(string));
        MSG_WriteChar(&client->netconnection->message,svc_print);
        MSG_WriteString(&client->netconnection->message, string);
 }
@@ -390,7 +453,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);
@@ -423,13 +486,18 @@ static void VM_SV_sound (void)
        int             volume;
        float attenuation;
 
-       VM_SAFEPARMCOUNT(5, VM_SV_sound);
+       VM_SAFEPARMCOUNTRANGE(4, 5, VM_SV_sound);
 
        entity = PRVM_G_EDICT(OFS_PARM0);
        channel = (int)PRVM_G_FLOAT(OFS_PARM1);
        sample = PRVM_G_STRING(OFS_PARM2);
        volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
        attenuation = PRVM_G_FLOAT(OFS_PARM4);
+       if (prog->argc < 5)
+       {
+               Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
+               attenuation = 1;
+       }
 
        if (volume < 0 || volume > 255)
        {
@@ -452,6 +520,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
@@ -479,10 +586,10 @@ 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));
+       trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
 
        VM_SetTraceGlobals(&trace);
 }
@@ -518,10 +625,10 @@ 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));
+       trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
 
        VM_SetTraceGlobals(&trace);
 }
@@ -548,7 +655,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
        {
@@ -557,8 +664,9 @@ static trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
                VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles);
                VectorScale (tossent->fields.server->velocity, 0.05, move);
                VectorAdd (tossent->fields.server->origin, move, end);
-               trace = SV_Move (tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
+               trace = SV_TraceBox(tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
                VectorCopy (trace.endpos, tossent->fields.server->origin);
+               tossent->fields.server->velocity[2] -= gravity;
 
                if (trace.fraction < 1)
                        break;
@@ -634,7 +742,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;
 }
@@ -694,6 +802,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
+}
+
 
 /*
 =================
@@ -744,8 +918,16 @@ static void VM_SV_findradius (void)
        int i;
        int numtouchedicts;
        prvm_edict_t *touchedicts[MAX_EDICTS];
+       int chainfield;
 
-       VM_SAFEPARMCOUNT(2, VM_SV_findradius);
+       VM_SAFEPARMCOUNTRANGE(2, 3, 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;
 
@@ -785,10 +967,10 @@ 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);
+                       PRVM_EDICTFIELDVALUE(ent,chainfield)->edict = PRVM_EDICT_TO_PROG(chain);
                        chain = ent;
                }
        }
@@ -799,8 +981,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)
@@ -900,18 +1081,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))
+       trace = SV_TraceBox(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)
        {
-               if (trace.fraction < 1)
+               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_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+               VectorSubtract(trace.endpos, offset, trace.endpos);
+               if (trace.startsolid)
+               {
+                       Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2]);
+                       SV_UnstickEntity(ent);
+                       SV_LinkEdict(ent);
+                       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);
+                       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);
+                       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;
+               }
        }
 }
 
@@ -1022,7 +1237,7 @@ static void VM_SV_aim (void)
 // try sending a trace straight
        VectorCopy (prog->globals.server->v_forward, dir);
        VectorMA (start, 2048, dir, end);
-       tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+       tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
        if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
        && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
        {
@@ -1054,7 +1269,7 @@ static void VM_SV_aim (void)
                dist = DotProduct (dir, prog->globals.server->v_forward);
                if (dist < bestdist)
                        continue;       // to far to turn
-               tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+               tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
                if (tr.ent == check)
                {       // can shoot at this one
                        bestdist = dist;
@@ -1096,7 +1311,6 @@ sizebuf_t *WriteDest (void)
        int             entnum;
        int             dest;
        prvm_edict_t    *ent;
-       extern sizebuf_t *sv2csqcbuf;
 
        dest = (int)PRVM_G_FLOAT(OFS_PARM0);
        switch (dest)
@@ -1124,7 +1338,7 @@ sizebuf_t *WriteDest (void)
                return &sv.signon;
 
        case MSG_ENTITY:
-               return sv2csqcbuf;
+               return sv.writeentitiestoclient_msg;
        }
 
        return NULL;
@@ -1185,6 +1399,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)
@@ -1192,9 +1439,14 @@ static void VM_SV_makestatic (void)
        prvm_edict_t *ent;
        int i, large;
 
-       VM_SAFEPARMCOUNT(1, VM_SV_makestatic);
+       // allow 0 parameters due to an id1 qc bug in which this function is used
+       // with no parameters (but directly after setmodel with self in OFS_PARM0)
+       VM_SAFEPARMCOUNTRANGE(0, 1, VM_SV_makestatic);
 
-       ent = PRVM_G_EDICT(OFS_PARM0);
+       if (prog->argc >= 1)
+               ent = PRVM_G_EDICT(OFS_PARM0);
+       else
+               ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
        if (ent == prog->edicts)
        {
                VM_Warning("makestatic: can not modify world entity\n");
@@ -1216,6 +1468,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);
@@ -1248,7 +1506,7 @@ static void VM_SV_setspawnparms (void)
        int             i;
        client_t        *client;
 
-       VM_SAFEPARMCOUNT(0, VM_SV_setspawnparms);
+       VM_SAFEPARMCOUNT(1, VM_SV_setspawnparms);
 
        ent = PRVM_G_EDICT(OFS_PARM0);
        i = PRVM_NUM_FOR_EDICT(ent);
@@ -1294,102 +1552,51 @@ typedef struct
 {
        unsigned char   type;   // 1/2/8 or other value if isn't used
        int             fieldoffset;
-}autosentstat_t;
+}customstat_t;
 
-static autosentstat_t *vm_autosentstats = NULL;        //[515]: it starts from 0, not 32
-static int vm_autosentstats_last;
+static customstat_t *vm_customstats = NULL;    //[515]: it starts from 0, not 32
+static int vm_customstats_last;
 
-void VM_AutoSentStats_Clear (void)
+void VM_CustomStats_Clear (void)
 {
-       if(vm_autosentstats)
+       if(vm_customstats)
        {
-               Z_Free(vm_autosentstats);
-               vm_autosentstats = NULL;
-               vm_autosentstats_last = -1;
+               Z_Free(vm_customstats);
+               vm_customstats = NULL;
+               vm_customstats_last = -1;
        }
 }
 
-//[515]: add check if even bigger ? "try to use two stats, cause it's too big" ?
-#define VM_SENDSTAT(a,b,c)\
-{\
-/*     if((c))*/\
-       if((c)==(unsigned char)(c))\
-       {\
-               MSG_WriteByte((a), svc_updatestatubyte);\
-               MSG_WriteByte((a), (b));\
-               MSG_WriteByte((a), (c));\
-       }\
-       else\
-       {\
-               MSG_WriteByte((a), svc_updatestat);\
-               MSG_WriteByte((a), (b));\
-               MSG_WriteLong((a), (c));\
-       }\
-}\
-
-void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
+void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
 {
-       int                     i, v, *si;
+       int                     i;
        char            s[17];
-       const char      *t;
-       qboolean        send;
-       union
-       {
-               float   f;
-               int             i;
-       }k;
 
-       if(!vm_autosentstats)
+       if(!vm_customstats)
                return;
 
-       send = (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5);
-
-       for(i=0; i<vm_autosentstats_last+1 ;i++)
+       for(i=0; i<vm_customstats_last+1 ;i++)
        {
-               if(!vm_autosentstats[i].type)
+               if(!vm_customstats[i].type)
                        continue;
-               switch(vm_autosentstats[i].type)
+               switch(vm_customstats[i].type)
                {
-               //string
+               //string as 16 bytes
                case 1:
-                       t = PRVM_E_STRING(ent, vm_autosentstats[i].fieldoffset);
-                       if(t && t[0])
-                       {
-                               memset(s, 0, 17);
-                               strlcpy(s, t, 16);
-                               si = (int*)s;
-                               if (!send)
-                               {
-                                       stats[i+32] = si[0];
-                                       stats[i+33] = si[1];
-                                       stats[i+34] = si[2];
-                                       stats[i+35] = si[3];
-                               }
-                               else
-                               {
-                                       VM_SENDSTAT(msg, i+32, si[0]);
-                                       VM_SENDSTAT(msg, i+33, si[1]);
-                                       VM_SENDSTAT(msg, i+34, si[2]);
-                                       VM_SENDSTAT(msg, i+35, si[3]);
-                               }
-                       }
-                       break;
-               //float
-               case 2:
-                       k.f = PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset);       //[515]: use PRVM_E_INT ?
-                       k.i = LittleLong (k.i);
-                       if (!send)
-                               stats[i+32] = k.i;
-                       else
-                               VM_SENDSTAT(msg, i+32, k.i);
+                       memset(s, 0, 17);
+                       strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
+                       stats[i+32] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
+                       stats[i+33] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
+                       stats[i+34] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
+                       stats[i+35] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
                        break;
-               //integer
+               //float field sent as-is
                case 8:
-                       v = (int)PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset);    //[515]: use PRVM_E_INT ?
-                       if (!send)
-                               stats[i+32] = v;
-                       else
-                               VM_SENDSTAT(msg, i+32, v);
+                       stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
+                       break;
+               //integer value of float field
+               case 2:
+                       stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
                        break;
                default:
                        break;
@@ -1411,10 +1618,10 @@ static void VM_SV_AddStat (void)
 
        VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
 
-       if(!vm_autosentstats)
+       if(!vm_customstats)
        {
-               vm_autosentstats = (autosentstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(autosentstat_t));
-               if(!vm_autosentstats)
+               vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
+               if(!vm_customstats)
                {
                        VM_Warning("PF_SV_AddStat: not enough memory\n");
                        return;
@@ -1440,10 +1647,10 @@ static void VM_SV_AddStat (void)
                VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
                return;
        }
-       vm_autosentstats[i].type                = type;
-       vm_autosentstats[i].fieldoffset = off;
-       if(vm_autosentstats_last < i)
-               vm_autosentstats_last = i;
+       vm_customstats[i].type          = type;
+       vm_customstats[i].fieldoffset   = off;
+       if(vm_customstats_last < i)
+               vm_customstats_last = i;
 }
 
 /*
@@ -1482,7 +1689,7 @@ static void VM_SV_copyentity (void)
                return;
        }
        memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
-       SV_LinkEdict(out, false);
+       SV_LinkEdict(out);
 }
 
 
@@ -1582,11 +1789,12 @@ 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();
 }
 
 static void VM_SV_te_bloodshower (void)
@@ -1608,6 +1816,7 @@ static void VM_SV_te_bloodshower (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
        // count
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_explosionrgb (void)
@@ -1623,6 +1832,7 @@ static void VM_SV_te_explosionrgb (void)
        MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
        MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
        MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_particlecube (void)
@@ -1652,6 +1862,7 @@ static void VM_SV_te_particlecube (void)
        MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
        // randomvel
        MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_particlerain (void)
@@ -1677,6 +1888,7 @@ static void VM_SV_te_particlerain (void)
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        // color
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_particlesnow (void)
@@ -1702,6 +1914,7 @@ static void VM_SV_te_particlesnow (void)
        MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
        // color
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_spark (void)
@@ -1716,11 +1929,12 @@ 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();
 }
 
 static void VM_SV_te_gunshotquad (void)
@@ -1732,6 +1946,7 @@ static void VM_SV_te_gunshotquad (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_spikequad (void)
@@ -1743,6 +1958,7 @@ static void VM_SV_te_spikequad (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_superspikequad (void)
@@ -1754,6 +1970,7 @@ static void VM_SV_te_superspikequad (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_explosionquad (void)
@@ -1765,6 +1982,7 @@ static void VM_SV_te_explosionquad (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_smallflash (void)
@@ -1776,6 +1994,7 @@ static void VM_SV_te_smallflash (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_customflash (void)
@@ -1797,6 +2016,7 @@ static void VM_SV_te_customflash (void)
        MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
        MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
        MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_gunshot (void)
@@ -1808,6 +2028,7 @@ static void VM_SV_te_gunshot (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_spike (void)
@@ -1819,6 +2040,7 @@ static void VM_SV_te_spike (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_superspike (void)
@@ -1830,6 +2052,7 @@ static void VM_SV_te_superspike (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_explosion (void)
@@ -1841,6 +2064,7 @@ static void VM_SV_te_explosion (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_tarexplosion (void)
@@ -1852,6 +2076,7 @@ static void VM_SV_te_tarexplosion (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_wizspike (void)
@@ -1863,6 +2088,7 @@ static void VM_SV_te_wizspike (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_knightspike (void)
@@ -1874,6 +2100,7 @@ static void VM_SV_te_knightspike (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_lavasplash (void)
@@ -1885,6 +2112,7 @@ static void VM_SV_te_lavasplash (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_teleport (void)
@@ -1896,6 +2124,7 @@ static void VM_SV_te_teleport (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_explosion2 (void)
@@ -1910,6 +2139,7 @@ static void VM_SV_te_explosion2 (void)
        // color
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_lightning1 (void)
@@ -1927,6 +2157,7 @@ static void VM_SV_te_lightning1 (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_lightning2 (void)
@@ -1944,6 +2175,7 @@ static void VM_SV_te_lightning2 (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_lightning3 (void)
@@ -1961,6 +2193,7 @@ static void VM_SV_te_lightning3 (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_beam (void)
@@ -1978,6 +2211,7 @@ static void VM_SV_te_beam (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_plasmaburn (void)
@@ -1988,6 +2222,7 @@ static void VM_SV_te_plasmaburn (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 static void VM_SV_te_flamejet (void)
@@ -2005,9 +2240,10 @@ static void VM_SV_te_flamejet (void)
        MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
        // count
        MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
+       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;
@@ -2043,7 +2279,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)
@@ -2054,7 +2290,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;
@@ -2065,7 +2301,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
@@ -2082,7 +2318,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);
@@ -2097,10 +2333,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);
@@ -2118,7 +2427,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;
@@ -2133,7 +2442,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);
@@ -2179,7 +2488,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);
@@ -2224,7 +2533,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)
@@ -2268,7 +2577,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)
@@ -2276,24 +2585,64 @@ 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 = 1;
+
+       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 = SV_GetPitchSign(ent);
+               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])
@@ -2325,7 +2674,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
 
@@ -2335,7 +2684,7 @@ int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
                return 2;
 
        modelindex = (int)ent->fields.server->modelindex;
-       if (modelindex <= 0 || modelindex > MAX_MODELS)
+       if (modelindex <= 0 || modelindex >= MAX_MODELS)
                return 3;
 
        model = sv.models[modelindex];
@@ -2352,9 +2701,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)
                {
@@ -2427,16 +2776,17 @@ static void VM_SV_gettagindex (void)
 
        modelindex = (int)ent->fields.server->modelindex;
        tag_index = 0;
-       if (modelindex <= 0 || modelindex > MAX_MODELS)
+       if (modelindex <= 0 || modelindex >= MAX_MODELS)
                Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
        else
        {
                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;
-};
+}
 
 //vector(entity ent, float tagindex) gettaginfo;
 static void VM_SV_gettaginfo (void)
@@ -2444,7 +2794,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);
 
@@ -2452,7 +2807,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)
        {
@@ -2556,7 +2927,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);
 
@@ -2572,7 +2943,7 @@ static void VM_SV_setmodelindex (void)
                return;
        }
        i = (int)PRVM_G_FLOAT(OFS_PARM1);
-       if (i <= 0 || i > MAX_MODELS)
+       if (i <= 0 || i >= MAX_MODELS)
        {
                VM_Warning("setmodelindex: invalid modelindex\n");
                return;
@@ -2608,7 +2979,7 @@ static void VM_SV_modelnameforindex (void)
        PRVM_G_INT(OFS_RETURN) = OFS_NULL;
 
        i = (int)PRVM_G_FLOAT(OFS_PARM0);
-       if (i <= 0 || i > MAX_MODELS)
+       if (i <= 0 || i >= MAX_MODELS)
        {
                VM_Warning("modelnameforindex: invalid modelindex\n");
                return;
@@ -2638,23 +3009,67 @@ 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));
        MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2), sv.protocol);
        MSG_WriteVector(&sv.datagram, PRVM_G_VECTOR(OFS_PARM3), sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 //#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);
 
-       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));
+       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);
+       }
+
+       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[] = {
@@ -2674,7 +3089,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)
@@ -2881,16 +3296,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
@@ -2900,7 +3315,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
@@ -3106,10 +3521,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)
@@ -3141,14 +3556,14 @@ VM_tan,                                                 // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
 VM_strlennocol,                                        // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
 VM_strdecolorize,                              // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
 VM_strftime,                                   // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
-NULL,                                                  // #479
-NULL,                                                  // #480
-NULL,                                                  // #481
-NULL,                                                  // #482
-NULL,                                                  // #483
-NULL,                                                  // #484
-NULL,                                                  // #485
-NULL,                                                  // #486
+VM_tokenizebyseparator,                        // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
+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
@@ -3156,12 +3571,138 @@ 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)
+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
+VM_loadfromdata,                               // #529
+VM_loadfromfile,                               // #530
+VM_SV_setpause,                                        // #531 void(float pause) setpause = #531;
+VM_log,                                                        // #532
+NULL,                                                  // #533
+NULL,                                                  // #534
+NULL,                                                  // #535
+NULL,                                                  // #536
+NULL,                                                  // #537
+NULL,                                                  // #538
+NULL,                                                  // #539
+NULL,                                                  // #540
+NULL,                                                  // #541
+NULL,                                                  // #542
+NULL,                                                  // #543
+NULL,                                                  // #544
+NULL,                                                  // #545
+NULL,                                                  // #546
+NULL,                                                  // #547
+NULL,                                                  // #548
+NULL,                                                  // #549
+NULL,                                                  // #550
+NULL,                                                  // #551
+NULL,                                                  // #552
+NULL,                                                  // #553
+NULL,                                                  // #554
+NULL,                                                  // #555
+NULL,                                                  // #556
+NULL,                                                  // #557
+NULL,                                                  // #558
+NULL,                                                  // #559
+NULL,                                                  // #560
+NULL,                                                  // #561
+NULL,                                                  // #562
+NULL,                                                  // #563
+NULL,                                                  // #564
+NULL,                                                  // #565
+NULL,                                                  // #566
+NULL,                                                  // #567
+NULL,                                                  // #568
+NULL,                                                  // #569
+NULL,                                                  // #570
+NULL,                                                  // #571
+NULL,                                                  // #572
+NULL,                                                  // #573
+NULL,                                                  // #574
+NULL,                                                  // #575
+NULL,                                                  // #576
+NULL,                                                  // #577
+NULL,                                                  // #578
+NULL,                                                  // #579
+NULL,                                                  // #580
+NULL,                                                  // #581
+NULL,                                                  // #582
+NULL,                                                  // #583
+NULL,                                                  // #584
+NULL,                                                  // #585
+NULL,                                                  // #586
+NULL,                                                  // #587
+NULL,                                                  // #588
+NULL,                                                  // #589
+NULL,                                                  // #590
+NULL,                                                  // #591
+NULL,                                                  // #592
+NULL,                                                  // #593
+NULL,                                                  // #594
+NULL,                                                  // #595
+NULL,                                                  // #596
+NULL,                                                  // #597
+NULL,                                                  // #598
+NULL,                                                  // #599
+NULL,                                                  // #600
+NULL,                                                  // #601
+NULL,                                                  // #602
+NULL,                                                  // #603
+NULL,                                                  // #604
+VM_callfunction,                               // #605
+VM_writetofile,                                        // #606
+VM_isfunction,                                 // #607
+NULL,                                                  // #608
+NULL,                                                  // #609
+NULL,                                                  // #610
+NULL,                                                  // #611
+NULL,                                                  // #612
+VM_parseentitydata,                            // #613
+NULL,                                                  // #614
+NULL,                                                  // #615
+NULL,                                                  // #616
+NULL,                                                  // #617
+NULL,                                                  // #618
+NULL,                                                  // #619
+NULL,                                                  // #620
+NULL,                                                  // #621
+NULL,                                                  // #622
+NULL,                                                  // #623
+VM_getextresponse,                             // #624 string getextresponse(void)
+NULL,                                                  // #625
 };
 
 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
@@ -3173,6 +3714,14 @@ void VM_SV_Cmd_Init(void)
 
 void VM_SV_Cmd_Reset(void)
 {
+       World_End(&sv.world);
+       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();
 }