]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - svvm_cmds.c
com: rename BSD strlcpy and strlcat
[xonotic/darkplaces.git] / svvm_cmds.c
index 634de8147fe65a72a8a18bd2e5a10a97ab6a4c7b..90ee0787b6073eb44cc91ae6a3f17132b7a81263 100644 (file)
@@ -100,6 +100,7 @@ const char *vm_sv_extensions[] = {
 "DP_QC_ENTITYSTRING",
 "DP_QC_ETOS",
 "DP_QC_EXTRESPONSEPACKET",
+"DP_QC_FINDBOX",
 "DP_QC_FINDCHAIN",
 "DP_QC_FINDCHAINFLAGS",
 "DP_QC_FINDCHAINFLOAT",
@@ -107,6 +108,7 @@ const char *vm_sv_extensions[] = {
 "DP_QC_FINDFLAGS",
 "DP_QC_FINDFLOAT",
 "DP_QC_FS_SEARCH",
+"DP_QC_FS_SEARCH_PACKFILE",
 "DP_QC_GETLIGHT",
 "DP_QC_GETSURFACE",
 "DP_QC_GETSURFACETRIANGLE",
@@ -119,6 +121,7 @@ const char *vm_sv_extensions[] = {
 "DP_QC_LOG",
 "DP_QC_MINMAXBOUND",
 "DP_QC_MULTIPLETEMPSTRINGS",
+"DP_QC_NUDGEOUTOFSOLID",
 "DP_QC_NUM_FOR_EDICT",
 "DP_QC_RANDOMVEC",
 "DP_QC_SINCOSSQRTPOW",
@@ -228,7 +231,6 @@ const char *vm_sv_extensions[] = {
 "TW_SV_STEPCONTROL",
 "ZQ_PAUSE",
 "DP_RM_CLIPGROUP",
-"DP_QC_FS_SEARCH_PACKFILE",
 NULL
 //"EXT_CSQC" // not ready yet
 };
@@ -254,7 +256,7 @@ static void VM_SV_setorigin(prvm_prog_t *prog)
                VM_Warning(prog, "setorigin: can not modify world entity\n");
                return;
        }
-       if (e->priv.server->free)
+       if (e->free)
        {
                VM_Warning(prog, "setorigin: can not modify free entity\n");
                return;
@@ -305,7 +307,7 @@ static void VM_SV_setsize(prvm_prog_t *prog)
                VM_Warning(prog, "setsize: can not modify world entity\n");
                return;
        }
-       if (e->priv.server->free)
+       if (e->free)
        {
                VM_Warning(prog, "setsize: can not modify free entity\n");
                return;
@@ -327,7 +329,7 @@ static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
 static void VM_SV_setmodel(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
-       dp_model_t      *mod;
+       model_t *mod;
        int             i;
 
        VM_SAFEPARMCOUNT(2, VM_SV_setmodel);
@@ -338,7 +340,7 @@ static void VM_SV_setmodel(prvm_prog_t *prog)
                VM_Warning(prog, "setmodel: can not modify world entity\n");
                return;
        }
-       if (e->priv.server->free)
+       if (e->free)
        {
                VM_Warning(prog, "setmodel: can not modify free entity\n");
                return;
@@ -488,6 +490,9 @@ static void VM_SV_ambientsound(prvm_prog_t *prog)
        if (soundnum >= 256)
                large = true;
 
+       if(sv.protocol == PROTOCOL_NEHAHRABJP)
+               large = false;
+
        // add an svc_spawnambient command to the level signon packet
 
        if (large)
@@ -497,7 +502,7 @@ static void VM_SV_ambientsound(prvm_prog_t *prog)
 
        MSG_WriteVector(&sv.signon, pos, sv.protocol);
 
-       if (large || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       if (large || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
                MSG_WriteShort (&sv.signon, soundnum);
        else
                MSG_WriteByte (&sv.signon, soundnum);
@@ -657,7 +662,7 @@ static void VM_SV_traceline(prvm_prog_t *prog)
        move = (int)PRVM_G_FLOAT(OFS_PARM2);
        ent = PRVM_G_EDICT(OFS_PARM3);
 
-       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]))
+       if (isnan(v1[0]) || isnan(v1[1]) || isnan(v1[2]) || isnan(v2[0]) || isnan(v2[1]) || isnan(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), 0, 0, collision_extendtracelinelength.value);
@@ -696,7 +701,7 @@ static void VM_SV_tracebox(prvm_prog_t *prog)
        move = (int)PRVM_G_FLOAT(OFS_PARM4);
        ent = PRVM_G_EDICT(OFS_PARM5);
 
-       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]))
+       if (isnan(v1[0]) || isnan(v1[1]) || isnan(v1[2]) || isnan(v2[0]) || isnan(v2[1]) || isnan(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), 0, 0, collision_extendtraceboxlength.value);
@@ -803,7 +808,7 @@ static int VM_SV_newcheckclient(prvm_prog_t *prog, int check)
                // look up the client's edict
                ent = PRVM_EDICT_NUM(i);
                // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
-               if (i != check && (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
+               if (i != check && (ent->free || PRVM_serveredictfloat(ent, health) <= 0 || ((int)PRVM_serveredictfloat(ent, flags) & FL_NOTARGET)))
                        continue;
                // found a valid client (possibly the same one again)
                break;
@@ -850,7 +855,7 @@ static void VM_SV_checkclient(prvm_prog_t *prog)
 
        // return check if it might be visible
        ent = PRVM_EDICT_NUM(sv.lastcheck);
-       if (ent->priv.server->free || PRVM_serveredictfloat(ent, health) <= 0)
+       if (ent->free || PRVM_serveredictfloat(ent, health) <= 0)
        {
                VM_RETURN_EDICT(prog->edicts);
                return;
@@ -898,7 +903,7 @@ static void VM_SV_checkpvs(prvm_prog_t *prog)
        VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
        viewee = PRVM_G_EDICT(OFS_PARM1);
 
-       if(viewee->priv.server->free)
+       if(viewee->free)
        {
                VM_Warning(prog, "checkpvs: can not check free entity\n");
                PRVM_G_FLOAT(OFS_RETURN) = 4;
@@ -1002,7 +1007,7 @@ static void VM_SV_findradius(prvm_prog_t *prog)
        else
                chainfield = prog->fieldoffsets.chain;
        if (chainfield < 0)
-               prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
+               prog->error_cmd("VM_SV_findradius: %s doesnt have the specified chain field !", prog->name);
 
        chain = (prvm_edict_t *)prog->edicts;
 
@@ -1053,6 +1058,50 @@ static void VM_SV_findradius(prvm_prog_t *prog)
        VM_RETURN_EDICT(chain);
 }
 
+/*
+=================
+VM_SV_findbox
+
+Returns a chain of entities that are touching a box (a simpler findradius); supports DP_QC_FINDCHAIN_TOFIELD
+
+findbox (mins, maxs)
+=================
+*/
+static void VM_SV_findbox(prvm_prog_t *prog)
+{
+       prvm_edict_t *chain;
+       int i, numtouchedicts;
+       static prvm_edict_t *touchedicts[MAX_EDICTS];
+       int chainfield;
+
+       VM_SAFEPARMCOUNTRANGE(2, 3, VM_SV_findbox);
+
+       if(prog->argc == 3)
+               chainfield = PRVM_G_INT(OFS_PARM2);
+       else
+               chainfield = prog->fieldoffsets.chain;
+       if (chainfield < 0)
+               prog->error_cmd("VM_SV_findbox: %s doesnt have the specified chain field !", prog->name);
+
+       chain = (prvm_edict_t *)prog->edicts;
+
+       numtouchedicts = SV_EntitiesInBox(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), MAX_EDICTS, touchedicts);
+       if (numtouchedicts > MAX_EDICTS)
+       {
+               // this never happens
+               Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
+               numtouchedicts = MAX_EDICTS;
+       }
+       for (i = 0; i < numtouchedicts; ++i)
+       {
+               prog->xfunction->builtinsprofile++;
+               PRVM_EDICTFIELDEDICT(touchedicts[i], chainfield) = PRVM_EDICT_TO_PROG(chain);
+               chain = touchedicts[i];
+       }
+
+       VM_RETURN_EDICT(chain);
+}
+
 static void VM_SV_precache_sound(prvm_prog_t *prog)
 {
        VM_SAFEPARMCOUNT(1, VM_SV_precache_sound);
@@ -1093,7 +1142,7 @@ static void VM_SV_walkmove(prvm_prog_t *prog)
                VM_Warning(prog, "walkmove: can not modify world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "walkmove: can not modify free entity\n");
                return;
@@ -1130,12 +1179,18 @@ VM_SV_droptofloor
 void() droptofloor
 ===============
 */
-
+inline static qbool droptofloor_bsp_failcond(trace_t *trace)
+{
+       if (sv.worldmodel->brush.isq3bsp || sv.worldmodel->brush.isq2bsp)
+               return trace->startsolid;
+       else
+               return trace->allsolid || trace->fraction == 1;
+}
 static void VM_SV_droptofloor(prvm_prog_t *prog)
 {
-       prvm_edict_t            *ent;
-       vec3_t          end, entorigin, entmins, entmaxs;
-       trace_t         trace;
+       prvm_edict_t *ent;
+       vec3_t        end;
+       trace_t       trace;
 
        VM_SAFEPARMCOUNTRANGE(0, 2, VM_SV_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
 
@@ -1148,64 +1203,77 @@ static void VM_SV_droptofloor(prvm_prog_t *prog)
                VM_Warning(prog, "droptofloor: can not modify world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "droptofloor: can not modify free entity\n");
                return;
        }
 
-       VectorCopy (PRVM_serveredictvector(ent, origin), end);
-       end[2] -= 256;
-
        if (sv_gameplayfix_droptofloorstartsolid_nudgetocorrect.integer)
-               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), 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), 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]);
-                       SV_LinkEdict(ent);
-                       PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
-                       PRVM_serveredictedict(ent, groundentity) = 0;
-                       PRVM_G_FLOAT(OFS_RETURN) = 1;
-               }
-               else if (trace.fraction < 1)
+       {
+               int n = PHYS_NudgeOutOfSolid(prog, ent);
+               if (!n)
+                       VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect COULD NOT FIX badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+               else if (n > 0)
+                       VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid_nudgetocorrect FIXED badly placed entity \"%s\" before drop\n", PRVM_gameedictvector(ent, origin)[0], PRVM_gameedictvector(ent, origin)[1], PRVM_gameedictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+       }
+
+       VectorCopy (PRVM_serveredictvector(ent, origin), end);
+       if (sv.worldmodel->brush.isq3bsp)
+               end[2] -= 4096;
+       else if (sv.worldmodel->brush.isq2bsp)
+               end[2] -= 128;
+       else
+               end[2] -= 256; // Quake, QuakeWorld
+
+       /* bones_was_here: not using SV_GenericHitSuperContentsMask(ent) anymore because it was setting:
+        * items:    SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY
+        * monsters: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP
+        * explobox: SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE
+        * which caused (startsolid == true) when, for example, a health was touching a monster.
+        * Changing MOVE_NORMAL also fixes that, but other engines are using MOVE_NORMAL here.
+        */
+       trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
+       if (droptofloor_bsp_failcond(&trace))
+       {
+               if (sv_gameplayfix_droptofloorstartsolid.integer)
                {
-                       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));
+                       vec3_t offset, org;
+
+                       offset[0] = 0.5f * (PRVM_serveredictvector(ent, mins)[0] + PRVM_serveredictvector(ent, maxs)[0]);
+                       offset[1] = 0.5f * (PRVM_serveredictvector(ent, mins)[1] + PRVM_serveredictvector(ent, maxs)[1]);
+                       offset[2] = PRVM_serveredictvector(ent, mins)[2];
+                       VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
+                       VectorAdd(end, offset, end);
+
+                       trace = SV_TraceLine(org, end, MOVE_NORMAL, ent, SUPERCONTENTS_SOLID, 0, 0, collision_extendmovelength.value);
+                       if (droptofloor_bsp_failcond(&trace))
+                       {
+                               VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid COULD NOT FIX badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+                               return;
+                       }
+                       VM_Warning(prog, "droptofloor at \"%f %f %f\": sv_gameplayfix_droptofloorstartsolid FIXED badly placed entity \"%s\"\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)));
+                       VectorSubtract(trace.endpos, offset, PRVM_serveredictvector(ent, origin));
+
+                       // only because we dropped it without considering its bbox
                        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);
-                       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;
+                               PHYS_NudgeOutOfSolid(prog, ent);
                }
-       }
-       else
-       {
-               if (!trace.allsolid && trace.fraction < 1)
+               else
                {
-                       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);
-                       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;
+                       VM_Warning(prog, "droptofloor at \"%f %f %f\": badly placed entity \"%s\", startsolid: %d allsolid: %d\n", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2], PRVM_GetString(prog, PRVM_gameedictstring(ent, classname)), trace.startsolid, trace.allsolid);
+                       return;
                }
        }
+       else
+               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);
+       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;
 }
 
 /*
@@ -1232,7 +1300,7 @@ static void VM_SV_lightstyle(prvm_prog_t *prog)
        }
 
 // change the string in sv
-       strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
+       dp_strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
 
 // send message to all clients on this server
        if (sv.state != ss_active)
@@ -1304,7 +1372,7 @@ static void VM_SV_aim(prvm_prog_t *prog)
                VM_Warning(prog, "aim: can not use world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "aim: can not use free entity\n");
                return;
@@ -1401,11 +1469,21 @@ static sizebuf_t *WriteDest(prvm_prog_t *prog)
        case MSG_ONE:
                ent = PRVM_PROG_TO_EDICT(PRVM_serverglobaledict(msg_entity));
                entnum = PRVM_NUM_FOR_EDICT(ent);
-               if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
+               if (entnum < 1 || entnum > svs.maxclients)
                {
                        VM_Warning(prog, "WriteDest: tried to write to non-client\n");
                        return &sv.reliable_datagram;
                }
+               else if (!svs.clients[entnum-1].active)
+               {
+                       VM_Warning(prog, "WriteDest: tried to write to a disconnected client\n");
+                       return &sv.reliable_datagram;
+               }
+               else if (!svs.clients[entnum-1].netconnection)
+               {
+                       VM_Warning(prog, "WriteDest: tried to write to a bot client\n");
+                       return &sv.reliable_datagram;
+               }
                else
                        return &svs.clients[entnum-1].netconnection->message;
 
@@ -1532,7 +1610,7 @@ static void VM_SV_makestatic(prvm_prog_t *prog)
                VM_Warning(prog, "makestatic: can not modify world entity\n");
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "makestatic: can not modify free entity\n");
                return;
@@ -1542,17 +1620,17 @@ static void VM_SV_makestatic(prvm_prog_t *prog)
        if (PRVM_serveredictfloat(ent, modelindex) >= 256 || PRVM_serveredictfloat(ent, frame) >= 256)
                large = true;
 
-       if (large)
+       if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
        {
-               MSG_WriteByte (&sv.signon,svc_spawnstatic2);
+               MSG_WriteByte (&sv.signon,svc_spawnstatic);
                MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
-               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
+               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
-       else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
+       else if (large)
        {
-               MSG_WriteByte (&sv.signon,svc_spawnstatic);
+               MSG_WriteByte (&sv.signon,svc_spawnstatic2);
                MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, modelindex));
-               MSG_WriteByte (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
+               MSG_WriteShort (&sv.signon, (int)PRVM_serveredictfloat(ent, frame));
        }
        else
        {
@@ -1662,7 +1740,7 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
                //string as 16 bytes
                case 1:
                        memset(s, 0, 17);
-                       strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
+                       dp_strlcpy(s, PRVM_E_STRING(ent, vm_customstats[i].fieldoffset), 16);
                        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;
@@ -1684,7 +1762,7 @@ void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *ms
        }
 }
 
-extern cvar_t sv_gameplayfix_customstats;
+extern cvar_t sv_qcstats;
 
 // void(float index, float type, .void field) SV_AddStat = #232;
 // Set up an auto-sent player stat.
@@ -1735,9 +1813,9 @@ static void VM_SV_AddStat(prvm_prog_t *prog)
        // 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)
+       else if (i >= MAX_VM_STAT && !sv_qcstats.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)
+       else if (i > (MAX_VM_STAT - 4) && type == 1 && !sv_qcstats.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;
@@ -1765,7 +1843,7 @@ static void VM_SV_copyentity(prvm_prog_t *prog)
                VM_Warning(prog, "copyentity: can not read world entity\n");
                return;
        }
-       if (in->priv.server->free)
+       if (in->free)
        {
                VM_Warning(prog, "copyentity: can not read free entity\n");
                return;
@@ -1776,14 +1854,13 @@ static void VM_SV_copyentity(prvm_prog_t *prog)
                VM_Warning(prog, "copyentity: can not modify world entity\n");
                return;
        }
-       if (out->priv.server->free)
+       if (out->free)
        {
                VM_Warning(prog, "copyentity: can not modify free entity\n");
                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);
 }
 
@@ -2356,7 +2433,7 @@ static void VM_SV_clientcommand(prvm_prog_t *prog)
 
        temp_client = host_client;
        host_client = svs.clients + i;
-       Cmd_ExecuteString(&cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
+       Cmd_ExecuteString(cmd_serverfromclient, PRVM_G_STRING(OFS_PARM1), src_client, true);
        host_client = temp_client;
 }
 
@@ -2366,7 +2443,7 @@ static void VM_SV_setattachment(prvm_prog_t *prog)
        prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
        prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
        const char *tagname = PRVM_G_STRING(OFS_PARM2);
-       dp_model_t *model;
+       model_t *model;
        int tagindex;
        VM_SAFEPARMCOUNT(3, VM_SV_setattachment);
 
@@ -2375,7 +2452,7 @@ static void VM_SV_setattachment(prvm_prog_t *prog)
                VM_Warning(prog, "setattachment: can not modify world entity\n");
                return;
        }
-       if (e->priv.server->free)
+       if (e->free)
        {
                VM_Warning(prog, "setattachment: can not modify free entity\n");
                return;
@@ -2420,7 +2497,7 @@ static int SV_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagna
 static int SV_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
 {
        int r;
-       dp_model_t *model;
+       model_t *model;
 
        *tagname = NULL;
        *parentindex = 0;
@@ -2459,7 +2536,7 @@ void SV_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out,
 
 static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
 {
-       dp_model_t *model;
+       model_t *model;
        if (tagindex >= 0 && (model = SV_GetModelFromEdict(ent)) && model->animscenes)
        {
                VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
@@ -2478,21 +2555,18 @@ static int SV_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int
 // 3 - null or non-precached model
 // 4 - no tags with requested index
 // 5 - runaway loop at attachment chain
-extern cvar_t cl_bob;
-extern cvar_t cl_bobcycle;
-extern cvar_t cl_bobup;
 static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
 {
        int ret;
        int modelindex, attachloop;
        matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
-       dp_model_t *model;
+       model_t *model;
 
        *out = identitymatrix; // warnings and errors return identical matrix
 
        if (ent == prog->edicts)
                return 1;
-       if (ent->priv.server->free)
+       if (ent->free)
                return 2;
 
        modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
@@ -2539,29 +2613,6 @@ static int SV_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *e
 
                SV_GetEntityMatrix(prog, ent, &entitymatrix, true);
                Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
-
-               /*
-               // Cl_bob, ported from rendering code
-               if (PRVM_serveredictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
-               {
-                       double bob, cycle;
-                       // 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)
-                       // 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;
-                       if (cycle < cl_bobup.value)
-                               cycle = sin(M_PI * cycle / cl_bobup.value);
-                       else
-                               cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
-                       // bob is proportional to velocity in the xy plane
-                       // (don't count Z, or jumping messes it up)
-                       bob = sqrt(PRVM_serveredictvector(ent, velocity)[0]*PRVM_serveredictvector(ent, velocity)[0] + PRVM_serveredictvector(ent, velocity)[1]*PRVM_serveredictvector(ent, velocity)[1])*cl_bob.value;
-                       bob = bob*0.3 + bob*0.7*cycle;
-                       Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
-               }
-               */
        }
        return 0;
 }
@@ -2584,7 +2635,7 @@ static void VM_SV_gettagindex(prvm_prog_t *prog)
                VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
        }
-       if (ent->priv.server->free)
+       if (ent->free)
        {
                VM_Warning(prog, "VM_SV_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
                return;
@@ -2614,7 +2665,7 @@ static void VM_SV_gettaginfo(prvm_prog_t *prog)
        const char *tagname;
        int returncode;
        vec3_t forward, left, up, origin;
-       const dp_model_t *model;
+       const model_t *model;
 
        VM_SAFEPARMCOUNT(2, VM_SV_gettaginfo);
 
@@ -2680,7 +2731,7 @@ static void VM_SV_dropclient(prvm_prog_t *prog)
        }
        oldhostclient = host_client;
        host_client = svs.clients + clientnum;
-       SV_DropClient(false);
+       SV_DropClient(false, "Client dropped");
        host_client = oldhostclient;
 }
 
@@ -2715,13 +2766,13 @@ static void VM_SV_clienttype(prvm_prog_t *prog)
        VM_SAFEPARMCOUNT(1, VM_SV_clienttype);
        clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
        if (clientnum < 0 || clientnum >= svs.maxclients)
-               PRVM_G_FLOAT(OFS_RETURN) = 3;
+               PRVM_G_FLOAT(OFS_RETURN) = 3; // CLIENTTYPE_NOTACLIENT
        else if (!svs.clients[clientnum].active)
-               PRVM_G_FLOAT(OFS_RETURN) = 0;
+               PRVM_G_FLOAT(OFS_RETURN) = 0; // CLIENTTYPE_DISCONNECTED
        else if (svs.clients[clientnum].netconnection)
-               PRVM_G_FLOAT(OFS_RETURN) = 1;
+               PRVM_G_FLOAT(OFS_RETURN) = 1; // CLIENTTYPE_REAL
        else
-               PRVM_G_FLOAT(OFS_RETURN) = 2;
+               PRVM_G_FLOAT(OFS_RETURN) = 2; // CLIENTTYPE_BOT
 }
 
 /*
@@ -2743,7 +2794,7 @@ static void VM_SV_serverkey(prvm_prog_t *prog)
 static void VM_SV_setmodelindex(prvm_prog_t *prog)
 {
        prvm_edict_t    *e;
-       dp_model_t      *mod;
+       model_t *mod;
        int             i;
        VM_SAFEPARMCOUNT(2, VM_SV_setmodelindex);
 
@@ -2753,7 +2804,7 @@ static void VM_SV_setmodelindex(prvm_prog_t *prog)
                VM_Warning(prog, "setmodelindex: can not modify world entity\n");
                return;
        }
-       if (e->priv.server->free)
+       if (e->free)
        {
                VM_Warning(prog, "setmodelindex: can not modify free entity\n");
                return;
@@ -2873,6 +2924,19 @@ static void VM_SV_pointparticles(prvm_prog_t *prog)
        SV_FlushBroadcastMessages();
 }
 
+qbool SV_VM_ConsoleCommand (const char *text)
+{
+       prvm_prog_t *prog = SVVM_prog;
+       return PRVM_ConsoleCommand(prog, text, &prog->funcoffsets.ConsoleCmd, true, PRVM_EDICT_TO_PROG(sv.world.prog->edicts), sv.time,  !(!sv.active || !prog || !prog->loaded), "QC function ConsoleCmd is missing"); 
+}
+
+// #352 void(string cmdname) registercommand (EXT_CSQC)
+static void VM_SV_registercommand (prvm_prog_t *prog)
+{
+       VM_SAFEPARMCOUNT(1, VM_SV_registercmd);
+       Cmd_AddCommand(CF_SERVER, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
+}
+
 //PF_setpause,    // void(float pause) setpause        = #531;
 static void VM_SV_setpause(prvm_prog_t *prog) {
        int pauseValue;
@@ -2895,7 +2959,7 @@ static void VM_SV_setpause(prvm_prog_t *prog) {
 static void VM_SV_skel_create(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
-       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       model_t *model = SV_GetModelByIndex(modelindex);
        skeleton_t *skeleton;
        int i;
        PRVM_G_FLOAT(OFS_RETURN) = 0;
@@ -2925,7 +2989,7 @@ static void VM_SV_skel_build(prvm_prog_t *prog)
        float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
        int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
        int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
-       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       model_t *model = SV_GetModelByIndex(modelindex);
        int numblends;
        int bonenum;
        int blendindex;
@@ -3168,7 +3232,7 @@ static void VM_SV_skel_delete(prvm_prog_t *prog)
 static void VM_SV_frameforname(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
-       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       model_t *model = SV_GetModelByIndex(modelindex);
        const char *name = PRVM_G_STRING(OFS_PARM1);
        int i;
        PRVM_G_FLOAT(OFS_RETURN) = -1;
@@ -3188,7 +3252,7 @@ static void VM_SV_frameforname(prvm_prog_t *prog)
 static void VM_SV_frameduration(prvm_prog_t *prog)
 {
        int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
-       dp_model_t *model = SV_GetModelByIndex(modelindex);
+       model_t *model = SV_GetModelByIndex(modelindex);
        int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
        PRVM_G_FLOAT(OFS_RETURN) = 0;
        if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
@@ -3315,7 +3379,7 @@ VM_fclose,                                                // #111 void(float fhandle) fclose (FRIK_FILE)
 VM_fgets,                                              // #112 string(float fhandle) fgets (FRIK_FILE)
 VM_fputs,                                              // #113 void(float fhandle, string s) fputs (FRIK_FILE)
 VM_strlen,                                             // #114 float(string s) strlen (FRIK_FILE)
-VM_strcat,                                             // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
+VM_strcat,                                             // #115 string(string s, string...) strcat (FRIK_FILE)
 VM_substring,                                  // #116 string(string s, float start, float length) substring (FRIK_FILE)
 VM_stov,                                               // #117 vector(string) stov (FRIK_FILE)
 VM_strzone,                                            // #118 string(string s) strzone (FRIK_FILE)
@@ -3446,7 +3510,7 @@ NULL,                                                     // #241
 NULL,                                                  // #242
 NULL,                                                  // #243
 NULL,                                                  // #244
-NULL,                                                  // #245
+VM_modulo,                                             // #245
 NULL,                                                  // #246
 NULL,                                                  // #247
 NULL,                                                  // #248
@@ -3554,7 +3618,7 @@ NULL,                                                     // #348 string(float playernum, string keyname) getplayerkeyvalue (E
 NULL,                                                  // #349 float() isdemo (EXT_CSQC)
 VM_isserver,                                   // #350 float() isserver (EXT_CSQC)
 NULL,                                                  // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
-NULL,                                                  // #352 void(string cmdname) registercommand (EXT_CSQC)
+VM_SV_registercommand,                 // #352 void(string cmdname) registercommand (EXT_CSQC)
 VM_wasfreed,                                   // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
 VM_SV_serverkey,                               // #354 string(string key) serverkey (EXT_CSQC)
 NULL,                                                  // #355
@@ -3769,8 +3833,8 @@ NULL,                                                     // #562
 NULL,                                                  // #563
 NULL,                                                  // #564
 NULL,                                                  // #565
-NULL,                                                  // #566
-NULL,                                                  // #567
+VM_SV_findbox,                                 // #566 entity(vector mins, vector maxs) findbox = #566; (DP_QC_FINDBOX)
+VM_nudgeoutofsolid,                            // #567 float(entity ent) nudgeoutofsolid = #567; (DP_QC_NUDGEOUTOFSOLID)
 NULL,                                                  // #568
 NULL,                                                  // #569
 NULL,                                                  // #570