]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_collision.c
.gitignore: Update to ignore .cache directory created by clangd and build directory...
[xonotic/darkplaces.git] / cl_collision.c
index d6637a5d128bae1f469e91fbbc79701b1eb55639..97303e7a92a9775678e2b5b5c7eefaaeba384cb2 100644 (file)
@@ -18,7 +18,7 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
        if (hitent)
                *hitent = 0;
        if (cl.worldmodel && cl.worldmodel->TraceLine)
-               cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID);
+               cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, start, end, SUPERCONTENTS_SOLID, 0, 0);
 
        if (normal)
                VectorCopy(trace.plane.normal, normal);
@@ -50,11 +50,11 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
                        continue;
                Matrix4x4_Transform(&ent->inversematrix, start, starttransformed);
                Matrix4x4_Transform(&ent->inversematrix, end, endtransformed);
-               Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, SUPERCONTENTS_SOLID, 0, NULL);
+               Collision_ClipTrace_Box(&trace, ent->model->normalmins, ent->model->normalmaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, SUPERCONTENTS_SOLID, 0, 0, SUPERCONTENTS_SOLID, 0, NULL);
                if (maxfrac < trace.fraction)
                        continue;
 
-               ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID);
+               ent->model->TraceLine(ent->model, ent->frameblend, ent->skeleton, &trace, starttransformed, endtransformed, SUPERCONTENTS_SOLID, 0, 0);
 
                if (maxfrac > trace.fraction)
                {
@@ -83,7 +83,7 @@ void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius)
                cl.worldmodel->brush.FindNonSolidLocation(cl.worldmodel, in, out, radius);
 }
 
-dp_model_t *CL_GetModelByIndex(int modelindex)
+model_t *CL_GetModelByIndex(int modelindex)
 {
        if(!modelindex)
                return NULL;
@@ -101,10 +101,10 @@ dp_model_t *CL_GetModelByIndex(int modelindex)
        return NULL;
 }
 
-dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed)
+model_t *CL_GetModelFromEdict(prvm_edict_t *ed)
 {
        prvm_prog_t *prog = CLVM_prog;
-       if (!ed || ed->priv.server->free)
+       if (!ed || ed->free)
                return NULL;
        return CL_GetModelByIndex((int)PRVM_clientedictfloat(ed, modelindex));
 }
@@ -117,14 +117,14 @@ void CL_LinkEdict(prvm_edict_t *ent)
        if (ent == prog->edicts)
                return;         // don't add the world
 
-       if (ent->priv.server->free)
+       if (ent->free)
                return;
 
        // set the abs box
 
        if (PRVM_clientedictfloat(ent, solid) == SOLID_BSP)
        {
-               dp_model_t *model = CL_GetModelByIndex( (int)PRVM_clientedictfloat(ent, modelindex) );
+               model_t *model = CL_GetModelByIndex( (int)PRVM_clientedictfloat(ent, modelindex) );
                if (model == NULL)
                {
                        Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
@@ -203,7 +203,7 @@ int CL_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
 CL_Move
 ==================
 */
-trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
+trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities)
 {
        prvm_prog_t *prog = CLVM_prog;
        int i, bodysupercontents;
@@ -223,10 +223,11 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // matrices to transform into/out of other entity's space
        matrix4x4_t matrix, imatrix;
        // model of other entity
-       dp_model_t *model;
+       model_t *model;
        // list of entities to test for collisions
        int numtouchedicts;
        static prvm_edict_t *touchedicts[MAX_EDICTS];
+       int clipgroup;
 
        if (hitnetworkentity)
                *hitnetworkentity = 0;
@@ -239,7 +240,7 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
 #endif
 
        // clip to world
-       Collision_ClipPointToWorld(&cliptrace, cl.worldmodel, clipstart, hitsupercontentsmask);
+       Collision_ClipPointToWorld(&cliptrace, cl.worldmodel, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
        cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog ? prog->edicts : NULL;
@@ -248,7 +249,7 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
 
        if (type == MOVE_MISSILE)
        {
-               // LordHavoc: modified this, was = -15, now -= 15
+               // LadyHavoc: modified this, was = -15, now -= 15
                for (i = 0;i < 3;i++)
                {
                        clipmins2[i] -= 15;
@@ -266,8 +267,8 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // debug override to test against everything
        if (sv_debugmove.integer)
        {
-               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
-               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
+               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  (vec_t)999999999;
        }
 
        // if the passedict is world, make it NULL (to avoid two checks each time)
@@ -280,6 +281,8 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
        // precalculate passedict's owner edict pointer for comparisons
        traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
+       clipgroup = passedict ? (int)PRVM_clientedictfloat(passedict, clipgroup) : 0;
+
        // collide against network entities
        if (hitnetworkbrushmodels)
        {
@@ -288,7 +291,7 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                        entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
                        if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
                                continue;
-                       Collision_ClipPointToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, hitsupercontentsmask);
+                       Collision_ClipPointToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = cl.brushmodel_entities[i];
                        Collision_CombineTraces(&cliptrace, &trace, NULL, true);
@@ -317,6 +320,8 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                                continue;
 
                        // don't hit players that don't exist
+                       if (!cl.entities_active[i])
+                               continue;
                        if (!cl.scores[i-1].name[0])
                                continue;
 
@@ -334,7 +339,7 @@ trace_t CL_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
                                continue;
                        Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]);
                        Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]);
-                       Collision_ClipPointToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, hitsupercontentsmask);
+                       Collision_ClipPointToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = i;
                        Collision_CombineTraces(&cliptrace, &trace, NULL, false);
@@ -379,6 +384,9 @@ skipnetworkplayers:
                        // don't clip owner against owned entities
                        if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
+                       // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+                       if (clipgroup && clipgroup == (int)PRVM_clientedictfloat(touch, clipgroup))
+                               continue;
                        // don't clip points against points (they can't collide)
                        if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
@@ -398,9 +406,9 @@ skipnetworkplayers:
                VectorCopy(PRVM_clientedictvector(touch, mins), touchmins);
                VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs);
                if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, 0.0f);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, 0.0f);
                else
-                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
+                       Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
 
                if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                        *hitnetworkentity = 0;
@@ -416,7 +424,7 @@ finished:
 CL_TraceLine
 ==================
 */
-trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, float extend, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces)
+trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities, qbool hitsurfaces)
 {
        prvm_prog_t *prog = CLVM_prog;
        int i, bodysupercontents;
@@ -436,12 +444,13 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // matrices to transform into/out of other entity's space
        matrix4x4_t matrix, imatrix;
        // model of other entity
-       dp_model_t *model;
+       model_t *model;
        // list of entities to test for collisions
        int numtouchedicts;
        static prvm_edict_t *touchedicts[MAX_EDICTS];
+       int clipgroup;
        if (VectorCompare(start, end))
-               return CL_TracePoint(start, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
+               return CL_TracePoint(start, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
 
        if (hitnetworkentity)
                *hitnetworkentity = 0;
@@ -455,7 +464,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 #endif
 
        // clip to world
-       Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, extend, hitsurfaces);
+       Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitsurfaces);
        cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog ? prog->edicts : NULL;
@@ -464,7 +473,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 
        if (type == MOVE_MISSILE)
        {
-               // LordHavoc: modified this, was = -15, now -= 15
+               // LadyHavoc: modified this, was = -15, now -= 15
                for (i = 0;i < 3;i++)
                {
                        clipmins2[i] -= 15;
@@ -482,8 +491,8 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // debug override to test against everything
        if (sv_debugmove.integer)
        {
-               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
-               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
+               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  (vec_t)999999999;
        }
 
        // if the passedict is world, make it NULL (to avoid two checks each time)
@@ -496,6 +505,8 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
        // precalculate passedict's owner edict pointer for comparisons
        traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
+       clipgroup = passedict ? (int)PRVM_clientedictfloat(passedict, clipgroup) : 0;
+
        // collide against network entities
        if (hitnetworkbrushmodels)
        {
@@ -504,7 +515,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                        entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
                        if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
                                continue;
-                       Collision_ClipLineToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask, extend, hitsurfaces);
+                       Collision_ClipLineToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitsurfaces);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = cl.brushmodel_entities[i];
                        Collision_CombineTraces(&cliptrace, &trace, NULL, true);
@@ -533,6 +544,8 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                                continue;
 
                        // don't hit players that don't exist
+                       if (!cl.entities_active[i])
+                               continue;
                        if (!cl.scores[i-1].name[0])
                                continue;
 
@@ -550,7 +563,7 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
                                continue;
                        Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]);
                        Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]);
-                       Collision_ClipLineToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, end, hitsupercontentsmask, extend, hitsurfaces);
+                       Collision_ClipLineToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitsurfaces);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = i;
                        Collision_CombineTraces(&cliptrace, &trace, NULL, false);
@@ -595,6 +608,9 @@ skipnetworkplayers:
                        // don't clip owner against owned entities
                        if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
+                       // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+                       if (clipgroup && clipgroup == (int)PRVM_clientedictfloat(touch, clipgroup))
+                               continue;
                        // don't clip points against points (they can't collide)
                        if (VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
@@ -614,9 +630,9 @@ skipnetworkplayers:
                VectorCopy(PRVM_clientedictvector(touch, mins), touchmins);
                VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs);
                if (type == MOVE_MISSILE && (int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
                else
-                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, extend, hitsurfaces);
+                       Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitsurfaces);
 
                if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                        *hitnetworkentity = 0;
@@ -632,13 +648,13 @@ finished:
 CL_Move
 ==================
 */
-trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, float extend, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
+trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend, qbool hitnetworkbrushmodels, qbool hitnetworkplayers, int *hitnetworkentity, qbool hitcsqcentities)
 {
        prvm_prog_t *prog = CLVM_prog;
        vec3_t hullmins, hullmaxs;
        int i, bodysupercontents;
        int passedictprog;
-       qboolean pointtrace;
+       qbool pointtrace;
        prvm_edict_t *traceowner, *touch;
        trace_t trace;
        // temporary storage because prvm_vec_t may need conversion
@@ -656,19 +672,20 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // matrices to transform into/out of other entity's space
        matrix4x4_t matrix, imatrix;
        // model of other entity
-       dp_model_t *model;
+       model_t *model;
        // list of entities to test for collisions
        int numtouchedicts;
        static prvm_edict_t *touchedicts[MAX_EDICTS];
+       int clipgroup;
        if (VectorCompare(mins, maxs))
        {
                vec3_t shiftstart, shiftend;
                VectorAdd(start, mins, shiftstart);
                VectorAdd(end, mins, shiftend);
                if (VectorCompare(start, end))
-                       trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
+                       trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
                else
-                       trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, extend, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
+                       trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
                VectorSubtract(trace.endpos, mins, trace.endpos);
                return trace;
        }
@@ -687,7 +704,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 #endif
 
        // clip to world
-       Collision_ClipToWorld(&cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
+       Collision_ClipToWorld(&cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
        cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog ? prog->edicts : NULL;
@@ -696,7 +713,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 
        if (type == MOVE_MISSILE)
        {
-               // LordHavoc: modified this, was = -15, now -= 15
+               // LadyHavoc: modified this, was = -15, now -= 15
                for (i = 0;i < 3;i++)
                {
                        clipmins2[i] -= 15;
@@ -723,8 +740,8 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // debug override to test against everything
        if (sv_debugmove.integer)
        {
-               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
-               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
+               clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+               clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  (vec_t)999999999;
        }
 
        // if the passedict is world, make it NULL (to avoid two checks each time)
@@ -739,6 +756,8 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
        // precalculate passedict's owner edict pointer for comparisons
        traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_clientedictedict(passedict, owner)) : NULL;
 
+       clipgroup = passedict ? (int)PRVM_clientedictfloat(passedict, clipgroup) : 0;
+
        // collide against network entities
        if (hitnetworkbrushmodels)
        {
@@ -747,7 +766,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                        entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
                        if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
                                continue;
-                       Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask, extend);
+                       Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = cl.brushmodel_entities[i];
                        Collision_CombineTraces(&cliptrace, &trace, NULL, true);
@@ -776,6 +795,8 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                                continue;
 
                        // don't hit players that don't exist
+                       if (!cl.entities_active[i])
+                               continue;
                        if (!cl.scores[i-1].name[0])
                                continue;
 
@@ -793,7 +814,7 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
                                continue;
                        Matrix4x4_CreateTranslate(&entmatrix, origin[0], origin[1], origin[2]);
                        Matrix4x4_CreateTranslate(&entinversematrix, -origin[0], -origin[1], -origin[2]);
-                       Collision_ClipToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, mins, maxs, end, hitsupercontentsmask, extend);
+                       Collision_ClipToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, mins, maxs, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
                        if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                                *hitnetworkentity = i;
                        Collision_CombineTraces(&cliptrace, &trace, NULL, false);
@@ -838,6 +859,9 @@ skipnetworkplayers:
                        // don't clip owner against owned entities
                        if (passedictprog == PRVM_clientedictedict(touch, owner))
                                continue;
+                       // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+                       if (clipgroup && clipgroup == (int)PRVM_clientedictfloat(touch, clipgroup))
+                               continue;
                        // don't clip points against points (they can't collide)
                        if (pointtrace && VectorCompare(PRVM_clientedictvector(touch, mins), PRVM_clientedictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)))
                                continue;
@@ -857,9 +881,9 @@ skipnetworkplayers:
                VectorCopy(PRVM_clientedictvector(touch, mins), touchmins);
                VectorCopy(PRVM_clientedictvector(touch, maxs), touchmaxs);
                if ((int)PRVM_clientedictfloat(touch, flags) & FL_MONSTER)
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
                else
-                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
+                       Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
 
                if (cliptrace.fraction > trace.fraction && hitnetworkentity)
                        *hitnetworkentity = 0;
@@ -875,7 +899,7 @@ finished:
 CL_Cache_TraceLine
 ==================
 */
-trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask)
+trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
 {
        prvm_prog_t *prog = CLVM_prog;
        int i;
@@ -890,7 +914,7 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
        // matrices to transform into/out of other entity's space
        matrix4x4_t matrix, imatrix;
        // model of other entity
-       dp_model_t *model;
+       model_t *model;
        // list of entities to test for collisions
        int numtouchedicts;
        static prvm_edict_t *touchedicts[MAX_EDICTS];
@@ -902,7 +926,7 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
 #endif
 
        // clip to world
-       Collision_Cache_ClipLineToWorldSurfaces(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
+       Collision_Cache_ClipLineToWorldSurfaces(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
        cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
        if (cliptrace.startsolid || cliptrace.fraction < 1)
                cliptrace.ent = prog ? prog->edicts : NULL;
@@ -926,7 +950,7 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
                entity_render_t *ent = &cl.entities[cl.brushmodel_entities[i]].render;
                if (!BoxesOverlap(clipboxmins, clipboxmaxs, ent->mins, ent->maxs))
                        continue;
-               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, ent->model, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask);
+               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, ent->model, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
                Collision_CombineTraces(&cliptrace, &trace, NULL, true);
        }
 
@@ -953,14 +977,14 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
                model = CL_GetModelFromEdict(touch);
                if (!model)
                        continue;
-               // animated models are too slow to collide against and can't be cached
-               if (touch->priv.server->frameblend || touch->priv.server->skeleton.relativetransforms)
+               // animated models are not suitable for caching
+               if ((&touch->priv.server->frameblend[0] && (touch->priv.server->frameblend[0].lerp != 1.0 || touch->priv.server->frameblend[0].subframe != 0)) || touch->priv.server->skeleton.relativetransforms)
                        continue;
                if (type == MOVE_NOMONSTERS && PRVM_clientedictfloat(touch, solid) != SOLID_BSP)
                        continue;
                Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_clientedictvector(touch, origin)[0], PRVM_clientedictvector(touch, origin)[1], PRVM_clientedictvector(touch, origin)[2], PRVM_clientedictvector(touch, angles)[0], PRVM_clientedictvector(touch, angles)[1], PRVM_clientedictvector(touch, angles)[2], 1);
                Matrix4x4_Invert_Simple(&imatrix, &matrix);
-               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, model, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask);
+               Collision_Cache_ClipLineToGenericEntitySurfaces(&trace, model, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
                Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_clientedictfloat(touch, solid) == SOLID_BSP);
        }