]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - svvm_cmds.c
Fix some warnings found by cppcheck
[xonotic/darkplaces.git] / svvm_cmds.c
index de270a2aae2ba329d2d95834c4464d0f7644875b..12ef69dab455c345729fb55c0bcb73a7f5e81adb 100644 (file)
@@ -19,6 +19,7 @@ const char *vm_sv_extensions =
 "DP_CON_SET "
 "DP_CON_SETA "
 "DP_CON_STARTMAP "
+"DP_COVERAGE "
 "DP_CRYPTO "
 "DP_CSQC_BINDMAPS "
 "DP_CSQC_ENTITYWORLDOBJECT "
@@ -167,6 +168,7 @@ const char *vm_sv_extensions =
 "DP_SV_CLIENTNAME "
 "DP_SV_CMD "
 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
+"DP_SV_DISABLECLIENTPREDICTION "
 "DP_SV_DISCARDABLEDEMO "
 "DP_SV_DRAWONLYTOCLIENT "
 "DP_SV_DROPCLIENT "
@@ -209,6 +211,7 @@ const char *vm_sv_extensions =
 "DP_TE_SPARK "
 "DP_TE_STANDARDEFFECTBUILTINS "
 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
+"DP_USERMOVETYPES "
 "DP_VIEWZOOM "
 "EXT_BITSHIFT "
 "FRIK_FILE "
@@ -224,6 +227,7 @@ const char *vm_sv_extensions =
 "TENEBRAE_GFX_DLIGHTS "
 "TW_SV_STEPCONTROL "
 "ZQ_PAUSE "
+"DP_RM_CLIPGROUP "
 //"EXT_CSQC " // not ready yet
 ;
 
@@ -240,7 +244,7 @@ static void VM_SV_setorigin(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
 
-       VM_SAFEPARMCOUNT(2, VM_setorigin);
+       VM_SAFEPARMCOUNT(2, VM_SV_setorigin);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
@@ -281,7 +285,7 @@ static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, float *min, float
 VM_SV_setsize
 
 the size box is rotated by the current angle
-LordHavoc: no it isn't...
+LadyHavoc: no it isn't...
 
 setsize (entity, minvector, maxvector)
 =================
@@ -291,7 +295,7 @@ static void VM_SV_setsize(prvm_prog_t *prog)
        prvm_edict_t    *e;
        vec3_t mins, maxs;
 
-       VM_SAFEPARMCOUNT(3, VM_setsize);
+       VM_SAFEPARMCOUNT(3, VM_SV_setsize);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
@@ -324,7 +328,7 @@ static void VM_SV_setmodel(prvm_prog_t *prog)
        dp_model_t      *mod;
        int             i;
 
-       VM_SAFEPARMCOUNT(2, VM_setmodel);
+       VM_SAFEPARMCOUNT(2, VM_SV_setmodel);
 
        e = PRVM_G_EDICT(OFS_PARM0);
        if (e == prog->edicts)
@@ -374,7 +378,7 @@ static void VM_SV_sprint(prvm_prog_t *prog)
        VM_VarString(prog, 1, string, sizeof(string));
 
        entnum = PRVM_G_EDICTNUM(OFS_PARM0);
-       // LordHavoc: div0 requested that sprintto world  operate like print
+       // LadyHavoc: div0 requested that sprintto world  operate like print
        if (entnum == 0)
        {
                Con_Print(string);
@@ -521,7 +525,7 @@ static void VM_SV_sound(prvm_prog_t *prog)
        const char      *sample;
        int                     channel;
        prvm_edict_t            *entity;
-       int             volume;
+       int             nvolume;
        int flags;
        float attenuation;
        float pitchchange;
@@ -531,7 +535,7 @@ static void VM_SV_sound(prvm_prog_t *prog)
        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);
+       nvolume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255);
        if (prog->argc < 5)
        {
                Con_DPrintf("VM_SV_sound: given only 4 parameters, expected 5, assuming attenuation = ATTN_NORMAL\n");
@@ -549,14 +553,17 @@ static void VM_SV_sound(prvm_prog_t *prog)
                flags = 0;
                if(channel >= 8 && channel <= 15) // weird QW feature
                {
-                       flags |= CHANFLAG_RELIABLE;
+                       flags |= CHANNELFLAG_RELIABLE;
                        channel -= 8;
                }
        }
        else
-               flags = PRVM_G_FLOAT(OFS_PARM6);
+       {
+               // LadyHavoc: we only let the qc set certain flags, others are off-limits
+               flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
+       }
 
-       if (volume < 0 || volume > 255)
+       if (nvolume < 0 || nvolume > 255)
        {
                VM_Warning(prog, "SV_StartSound: volume must be in range 0-1\n");
                return;
@@ -576,7 +583,7 @@ static void VM_SV_sound(prvm_prog_t *prog)
                return;
        }
 
-       SV_StartSound (entity, channel, sample, volume, attenuation, flags & CHANFLAG_RELIABLE, pitchchange);
+       SV_StartSound (entity, channel, sample, nvolume, attenuation, flags & CHANNELFLAG_RELIABLE, pitchchange);
 }
 
 /*
@@ -592,7 +599,7 @@ is omitted (since no entity is being tracked).
 static void VM_SV_pointsound(prvm_prog_t *prog)
 {
        const char      *sample;
-       int             volume;
+       int             nvolume;
        float           attenuation;
        float           pitchchange;
        vec3_t          org;
@@ -601,11 +608,11 @@ static void VM_SV_pointsound(prvm_prog_t *prog)
 
        VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
        sample = PRVM_G_STRING(OFS_PARM1);
-       volume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
+       nvolume = (int)(PRVM_G_FLOAT(OFS_PARM2) * 255);
        attenuation = PRVM_G_FLOAT(OFS_PARM3);
        pitchchange = prog->argc < 5 ? 0 : PRVM_G_FLOAT(OFS_PARM4) * 0.01f;
 
-       if (volume < 0 || volume > 255)
+       if (nvolume < 0 || nvolume > 255)
        {
                VM_Warning(prog, "SV_StartPointSound: volume must be in range 0-1\n");
                return;
@@ -617,7 +624,7 @@ static void VM_SV_pointsound(prvm_prog_t *prog)
                return;
        }
 
-       SV_StartPointSound (org, sample, volume, attenuation, pitchchange);
+       SV_StartPointSound (org, sample, nvolume, attenuation, pitchchange);
 }
 
 /*
@@ -650,7 +657,7 @@ static void VM_SV_traceline(prvm_prog_t *prog)
        if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
                prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
-       trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
+       trace = SV_TraceLine(v1, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value);
 
        VM_SetTraceGlobals(prog, &trace);
 }
@@ -667,7 +674,7 @@ if the tryents flag is set.
 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
 =================
 */
-// LordHavoc: added this for my own use, VERY useful, similar to traceline
+// LadyHavoc: added this for my own use, VERY useful, similar to traceline
 static void VM_SV_tracebox(prvm_prog_t *prog)
 {
        vec3_t v1, v2, m1, m2;
@@ -689,7 +696,7 @@ static void VM_SV_tracebox(prvm_prog_t *prog)
        if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
                prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
 
-       trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent));
+       trace = SV_TraceBox(v1, m1, m2, v2, move, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value);
 
        VM_SetTraceGlobals(prog, &trace);
 }
@@ -715,7 +722,7 @@ static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edic
                gravity = 1.0f;
        gravity *= sv_gravity.value * 0.025;
 
-       for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
+       for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
        {
                SV_CheckVelocity (tossent);
                PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
@@ -725,7 +732,7 @@ static trace_t SV_Trace_Toss(prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edic
                VectorCopy(PRVM_serveredictvector(tossent, origin), tossentorigin);
                VectorCopy(PRVM_serveredictvector(tossent, mins), tossentmins);
                VectorCopy(PRVM_serveredictvector(tossent, maxs), tossentmaxs);
-               trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent));
+               trace = SV_TraceBox(tossentorigin, tossentmins, tossentmaxs, end, MOVE_NORMAL, tossent, SV_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value);
                VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
                PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
 
@@ -962,7 +969,7 @@ static void VM_SV_stuffcmd(prvm_prog_t *prog)
 
        old = host_client;
        host_client = svs.clients + entnum-1;
-       Host_ClientCommands ("%s", string);
+       SV_ClientCommands ("%s", string);
        host_client = old;
 }
 
@@ -1021,7 +1028,7 @@ static void VM_SV_findradius(prvm_prog_t *prog)
                // (note: this is the reason you can't blow up fallen zombies)
                if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
                        continue;
-               // LordHavoc: compare against bounding box rather than center so it
+               // LadyHavoc: compare against bounding box rather than center so it
                // doesn't miss large objects, and use DotProduct instead of Length
                // for a major speedup
                VectorSubtract(org, PRVM_serveredictvector(ent, origin), eorg);
@@ -1148,25 +1155,22 @@ static void VM_SV_droptofloor(prvm_prog_t *prog)
        end[2] -= 256;
 
        if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
-               if (sv_gameplayfix_unstickentities.integer)
-                       SV_UnstickEntity(ent);
+               SV_NudgeOutOfSolid(ent);
 
        VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
        VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
        VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
-       trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+       trace = SV_TraceBox(entorigin, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
        if (trace.startsolid && sv_gameplayfix_droptofloorstartsolid.integer)
        {
                vec3_t offset, org;
                VectorSet(offset, 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]), 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]), PRVM_serveredictvector(ent, mins)[2]);
                VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
-               trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+               trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
                VectorSubtract(trace.endpos, offset, trace.endpos);
                if (trace.startsolid)
                {
                        Con_DPrintf("droptofloor at %f %f %f - COULD NOT FIX BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
-                       if (sv_gameplayfix_unstickentities.integer)
-                               SV_UnstickEntity(ent);
                        SV_LinkEdict(ent);
                        PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
                        PRVM_serveredictedict(ent, groundentity) = 0;
@@ -1176,8 +1180,8 @@ static void VM_SV_droptofloor(prvm_prog_t *prog)
                {
                        Con_DPrintf("droptofloor at %f %f %f - FIXED BADLY PLACED ENTITY\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
                        VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
-                       if (sv_gameplayfix_unstickentities.integer)
-                               SV_UnstickEntity(ent);
+                       if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
+                               SV_NudgeOutOfSolid(ent);
                        SV_LinkEdict(ent);
                        PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
                        PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
@@ -1188,10 +1192,9 @@ static void VM_SV_droptofloor(prvm_prog_t *prog)
        }
        else
        {
-               if (trace.fraction != 1)
+               if (!trace.allsolid && trace.fraction < 1)
                {
-                       if (trace.fraction < 1)
-                               VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
+                       VectorCopy (trace.endpos, PRVM_serveredictvector(ent, origin));
                        SV_LinkEdict(ent);
                        PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
                        PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
@@ -1264,7 +1267,7 @@ static void VM_SV_pointcontents(prvm_prog_t *prog)
        vec3_t point;
        VM_SAFEPARMCOUNT(1, VM_SV_pointcontents);
        VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
-       PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(point));
+       PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(point));
 }
 
 /*
@@ -1311,7 +1314,7 @@ static void VM_SV_aim(prvm_prog_t *prog)
 // try sending a trace straight
        VectorCopy (PRVM_serverglobalvector(v_forward), dir);
        VectorMA (start, 2048, dir, end);
-       tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+       tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
        if (tr.ent && PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), takedamage) == DAMAGE_AIM
        && (!teamplay.integer || PRVM_serveredictfloat(ent, team) <=0 || PRVM_serveredictfloat(ent, team) != PRVM_serveredictfloat(((prvm_edict_t *)tr.ent), team)) )
        {
@@ -1343,7 +1346,7 @@ static void VM_SV_aim(prvm_prog_t *prog)
                dist = DotProduct (dir, PRVM_serverglobalvector(v_forward));
                if (dist < bestdist)
                        continue;       // to far to turn
-               tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY);
+               tr = SV_TraceLine(start, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY, 0, 0, collision_extendmovelength.value);
                if (tr.ent == check)
                {       // can shoot at this one
                        bestdist = dist;
@@ -1496,8 +1499,8 @@ static void VM_SV_WritePicture(prvm_prog_t *prog)
        if(Image_Compress(imgname, size, &buf, &size))
        {
                // actual picture
-               MSG_WriteShort(WriteDest(prog), size);
-               SZ_Write(WriteDest(prog), (unsigned char *) buf, size);
+               MSG_WriteShort(WriteDest(prog), (int)size);
+               SZ_Write(WriteDest(prog), (unsigned char *) buf, (int)size);
        }
        else
        {
@@ -1624,21 +1627,17 @@ static void VM_SV_getlight(prvm_prog_t *prog)
 
 typedef struct
 {
-       unsigned char   type;   // 1/2/8 or other value if isn't used
+       unsigned char   type;   // 1/2/8 or 0 to indicate unused
        int             fieldoffset;
 }customstat_t;
 
-static customstat_t *vm_customstats = NULL;    //[515]: it starts from 0, not 32
+static customstat_t vm_customstats[MAX_CL_STATS]; // matches the regular stat numbers, but only MIN_VM_STAT to MAX_VM_STAT range is used if things are working properly (can register stats from MAX_VM_STAT to MAX_CL_STATS but will warn)
 static int vm_customstats_last;
 
 void VM_CustomStats_Clear (void)
 {
-       if(vm_customstats)
-       {
-               Z_Free(vm_customstats);
-               vm_customstats = NULL;
-               vm_customstats_last = -1;
-       }
+       memset(vm_customstats, 0, sizeof(vm_customstats));
+       vm_customstats_last = -1;
 }
 
 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
@@ -1646,11 +1645,12 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
        prvm_prog_t *prog = SVVM_prog;
        int                     i;
        char            s[17];
+       union {
+               int i;
+               float f;
+       } u;
 
-       if(!vm_customstats)
-               return;
-
-       for(i=0; i<vm_customstats_last+1 ;i++)
+       for(i=MIN_VM_STAT; i<=vm_customstats_last ;i++)
        {
                if(!vm_customstats[i].type)
                        continue;
@@ -1660,18 +1660,20 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
                case 1:
                        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;
+                       stats[i] = s[ 0] + s[ 1] * 256 + s[ 2] * 65536 + s[ 3] * 16777216;
+                       stats[i+1] = s[ 4] + s[ 5] * 256 + s[ 6] * 65536 + s[ 7] * 16777216;
+                       stats[i+2] = s[ 8] + s[ 9] * 256 + s[10] * 65536 + s[11] * 16777216;
+                       stats[i+3] = s[12] + s[13] * 256 + s[14] * 65536 + s[15] * 16777216;
                        break;
                //float field sent as-is
                case 8:
-                       stats[i+32] = PRVM_E_INT(ent, vm_customstats[i].fieldoffset);
+                       // can't directly use PRVM_E_INT on the field because it may be PRVM_64 and a double is not the representation we want to send
+                       u.f = PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
+                       stats[i] = u.i;
                        break;
                //integer value of float field
                case 2:
-                       stats[i+32] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
+                       stats[i] = (int)PRVM_E_FLOAT(ent, vm_customstats[i].fieldoffset);
                        break;
                default:
                        break;
@@ -1679,6 +1681,8 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
        }
 }
 
+extern cvar_t sv_gameplayfix_customstats;
+
 // void(float index, float type, .void field) SV_AddStat = #232;
 // Set up an auto-sent player stat.
 // Client's get thier own fields sent to them. Index may not be less than 32.
@@ -1688,40 +1692,51 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
 static void VM_SV_AddStat(prvm_prog_t *prog)
 {
-       int             off, i;
-       unsigned char   type;
+       int             off, i, type;
 
        VM_SAFEPARMCOUNT(3, VM_SV_AddStat);
 
-       if(!vm_customstats)
-       {
-               vm_customstats = (customstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(customstat_t));
-               if(!vm_customstats)
-               {
-                       VM_Warning(prog, "PF_SV_AddStat: not enough memory\n");
-                       return;
-               }
-       }
        i               = (int)PRVM_G_FLOAT(OFS_PARM0);
        type    = (int)PRVM_G_FLOAT(OFS_PARM1);
        off             = PRVM_G_INT  (OFS_PARM2);
-       i -= 32;
 
-       if(i < 0)
+       switch (type)
        {
-               VM_Warning(prog, "PF_SV_AddStat: index may not be less than 32\n");
+       case 1:
+       case 2:
+       case 8:
+               break;
+       default:
+               VM_Warning(prog, "PF_SV_AddStat: unrecognized type %i - supported types are 1 (string up to 16 bytes, takes 4 stat slots), 2 (truncate to int32), 8 (send as float)", type);
+               return;
+       }
+
+       if (i < 0)
+       {
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) may not be less than %i\n", i, MIN_VM_STAT);
                return;
        }
-       if(i >= (MAX_CL_STATS-32))
+
+       if (i >= MAX_CL_STATS)
        {
-               VM_Warning(prog, "PF_SV_AddStat: index >= MAX_CL_STATS\n");
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_CL_STATS (%i), not supported by protocol, and AddStat beyond MAX_VM_STAT (%i) conflicts with engine MOVEVARS\n", i, MAX_CL_STATS, MAX_VM_STAT);
                return;
        }
-       if(i > (MAX_CL_STATS-32-4) && type == 1)
+
+       if (i > (MAX_CL_STATS - 4) && type == 1)
        {
-               VM_Warning(prog, "PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) > (MAX_CL_STATS (%i) - 4) with string type won't fit in the protocol, and AddStat beyond MAX_VM_STAT conflicts with engine MOVEVARS\n", i, MAX_CL_STATS);
                return;
        }
+
+       // these are hazardous to override but sort of allowed if one wants to be adventurous...  and enjoys warnings.
+       if (i < MIN_VM_STAT)
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) < MIN_VM_STAT (%i) may conflict with engine stats - allowed, but this may break things\n", i, MIN_VM_STAT);
+       else if (i >= MAX_VM_STAT && !sv_gameplayfix_customstats.integer)
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_VM_STAT (%i) conflicts with engine stats - allowed, but this may break slowmo and stuff\n", i, MAX_VM_STAT);
+       else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_gameplayfix_customstats.integer)
+               VM_Warning(prog, "PF_SV_AddStat: index (%i) >= MAX_VM_STAT (%i) - 4 with string type won't fit within MAX_VM_STAT, thus conflicting with engine stats - allowed, but this may break slowmo and stuff\n", i, MAX_VM_STAT);
+
        vm_customstats[i].type          = type;
        vm_customstats[i].fieldoffset   = off;
        if(vm_customstats_last < i)
@@ -1764,6 +1779,8 @@ static void VM_SV_copyentity(prvm_prog_t *prog)
                return;
        }
        memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
+       if (VectorCompare(PRVM_serveredictvector(out, absmin), PRVM_serveredictvector(out, absmax)))
+               return;
        SV_LinkEdict(out);
 }
 
@@ -2319,7 +2336,7 @@ static void VM_SV_te_flamejet(prvm_prog_t *prog)
 }
 
 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
-//this function originally written by KrimZon, made shorter by LordHavoc
+//this function originally written by KrimZon, made shorter by LadyHavoc
 static void VM_SV_clientcommand(prvm_prog_t *prog)
 {
        client_t *temp_client;
@@ -2336,7 +2353,7 @@ static void VM_SV_clientcommand(prvm_prog_t *prog)
 
        temp_client = host_client;
        host_client = svs.clients + i;
-       Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client, true);
+       Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
        host_client = temp_client;
 }
 
@@ -2525,9 +2542,9 @@ static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *e
                if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
                {
                        double bob, cycle;
-                       // LordHavoc: this code is *weird*, but not replacable (I think it
+                       // LadyHavoc: this code is *weird*, but not replacable (I think it
                        // should be done in QC on the server, but oh well, quake is quake)
-                       // LordHavoc: figured out bobup: the time at which the sin is at 180
+                       // LadyHavoc: figured out bobup: the time at which the sin is at 180
                        // degrees (which allows lengthening or squishing the peak or valley)
                        cycle = sv.time/cl_bobcycle.value;
                        cycle -= (int)cycle;
@@ -2859,7 +2876,7 @@ static void VM_SV_setpause(prvm_prog_t *prog) {
        pauseValue = (int)PRVM_G_FLOAT(OFS_PARM0);
        if (pauseValue != 0) { //pause the game
                sv.paused = 1;
-               sv.pausedstart = realtime;
+               sv.pausedstart = host.realtime;
        } else { //disable pause, in case it was enabled
                if (sv.paused != 0) {
                        sv.paused = 0;
@@ -3225,7 +3242,7 @@ NULL,                                                     // #42 (QUAKE)
 VM_fabs,                                               // #43 float(float f) fabs (QUAKE)
 VM_SV_aim,                                             // #44 vector(entity e, float speed) aim (QUAKE)
 VM_cvar,                                               // #45 float(string s) cvar (QUAKE)
-VM_localcmd,                                   // #46 void(string s) localcmd (QUAKE)
+VM_localcmd_server,                            // #46 void(string s) localcmd (QUAKE)
 VM_nextent,                                            // #47 entity(entity e) nextent (QUAKE)
 VM_SV_particle,                                        // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
 VM_changeyaw,                                  // #49 void() ChangeYaw (QUAKE)
@@ -3582,7 +3599,7 @@ NULL,                                                     // #396
 NULL,                                                  // #397
 NULL,                                                  // #398
 NULL,                                                  // #399
-// LordHavoc's range #400-#499
+// LadyHavoc's range #400-#499
 VM_SV_copyentity,                              // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
 VM_SV_setcolor,                                        // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
 VM_findchain,                                  // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
@@ -3824,6 +3841,9 @@ NULL,                                                     // #637
 NULL,                                                  // #638
 VM_digest_hex,                                         // #639
 NULL,                                                  // #640
+NULL,                                                  // #641
+VM_coverage,                                           // #642
+NULL,                                                  // #643
 };
 
 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
@@ -3836,7 +3856,8 @@ void SVVM_init_cmd(prvm_prog_t *prog)
 void SVVM_reset_cmd(prvm_prog_t *prog)
 {
        World_End(&sv.world);
-       if(PRVM_serverfunction(SV_Shutdown))
+
+       if(prog->loaded && PRVM_serverfunction(SV_Shutdown))
        {
                func_t s = PRVM_serverfunction(SV_Shutdown);
                PRVM_serverglobalfloat(time) = sv.time;