From 308cc5726c01b24dd3280c3387b27ad2d5b11675 Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Thu, 8 May 2014 03:10:57 +0000
Subject: [PATCH] Overhauled the tracebox extending code, it now lives in
 collision.c rather than cl_collision.c/sv_phys.c and has 3 cvars controlling
 it: collision_extendmovelength - affects ALL engine traces (physics, etc),
 this has a higher value because of how important it is to not get stuck in
 things. collision_extendtraceboxlength - affects only the qc tracebox
 builtin. collision_extendtracelinelength - affects only the qc traceline
 builtin (in particular it is a bad idea to set this to a high value because
 it can interfere with trace_inwater/trace_inair reporting). Changed
 collision_enternudge/collision_leavenudge to behave more like Quake2/Quake3,
 this means that you can not sink into a brush (assuming the brush is detected
 - see collision_extendmovelength). Some beautification on the
 RecursiveHullCheck and RecursiveLightPoint code.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12072 d7cf8633-e32d-0410-b094-e92efae38249
::stable-branch::merge=05441557527d65d14e141fbf7ae50c9bf11ae486
---
 cl_collision.c | 134 ++----------------
 cl_collision.h |   4 +-
 cl_input.c     |  16 +--
 cl_main.c      |   2 +-
 cl_particles.c |   8 +-
 clvm_cmds.c    |  22 +--
 collision.c    | 177 ++++++++++++++++--------
 collision.h    |  22 ++-
 model_brush.c  | 367 ++++++++++++++++++++++++++-----------------------
 r_explosion.c  |   4 +-
 r_shadow.c     |  16 +--
 sbar.c         |   2 +-
 server.h       |   4 +-
 sv_move.c      |  10 +-
 sv_phys.c      | 104 +++-----------
 sv_user.c      |   4 +-
 svvm_cmds.c    |  14 +-
 view.c         |  10 +-
 18 files changed, 414 insertions(+), 506 deletions(-)

diff --git a/cl_collision.c b/cl_collision.c
index 713522d3..eb316f72 100644
--- a/cl_collision.c
+++ b/cl_collision.c
@@ -2,11 +2,7 @@
 #include "quakedef.h"
 #include "cl_collision.h"
 
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-float CL_SelectTraceLine(const vec3_t start, const vec3_t pEnd, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
-#else
 float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, vec3_t normal, int *hitent, entity_render_t *ignoreent)
-#endif
 {
 	float maxfrac, maxrealfrac;
 	int n;
@@ -14,20 +10,6 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
 	vec_t tracemins[3], tracemaxs[3];
 	trace_t trace;
 	vec_t tempnormal[3], starttransformed[3], endtransformed[3];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#endif
 
 	memset (&trace, 0 , sizeof(trace_t));
 	trace.fraction = 1;
@@ -71,10 +53,6 @@ float CL_SelectTraceLine(const vec3_t start, const vec3_t end, vec3_t impact, ve
 		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);
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-		if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-			Collision_ShortenTrace(&trace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 		if (maxrealfrac < trace.realfraction)
 			continue;
 
@@ -423,7 +401,7 @@ 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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, 0.0f);
 		else
 			Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
 
@@ -441,11 +419,7 @@ finished:
 CL_TraceLine
 ==================
 */
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-trace_t CL_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces)
-#else
-trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces)
-#endif
+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)
 {
 	prvm_prog_t *prog = CLVM_prog;
 	int i, bodysupercontents;
@@ -469,26 +443,8 @@ trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 	// list of entities to test for collisions
 	int numtouchedicts;
 	static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if (VectorCompare(start, pEnd))
-		return CL_TracePoint(start, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
-
-	if(collision_endposnudge.value > 0)
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#else
 	if (VectorCompare(start, end))
 		return CL_TracePoint(start, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
-#endif
 
 	if (hitnetworkentity)
 		*hitnetworkentity = 0;
@@ -502,7 +458,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, hitsurfaces);
+	Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask, extend, hitsurfaces);
 	cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
 	if (cliptrace.startsolid || cliptrace.fraction < 1)
 		cliptrace.ent = prog ? prog->edicts : NULL;
@@ -551,7 +507,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, hitsurfaces);
+			Collision_ClipLineToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, end, hitsupercontentsmask, extend, hitsurfaces);
 			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 				*hitnetworkentity = cl.brushmodel_entities[i];
 			Collision_CombineTraces(&cliptrace, &trace, NULL, true);
@@ -597,7 +553,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, hitsurfaces);
+			Collision_ClipLineToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, end, hitsupercontentsmask, extend, hitsurfaces);
 			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 				*hitnetworkentity = i;
 			Collision_CombineTraces(&cliptrace, &trace, NULL, false);
@@ -661,9 +617,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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
 		else
-			Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, hitsurfaces);
+			Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, extend, hitsurfaces);
 
 		if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 			*hitnetworkentity = 0;
@@ -671,10 +627,6 @@ skipnetworkplayers:
 	}
 
 finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 	return cliptrace;
 }
 
@@ -683,11 +635,7 @@ finished:
 CL_Move
 ==================
 */
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
-#else
-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, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities)
-#endif
+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)
 {
 	prvm_prog_t *prog = CLVM_prog;
 	vec3_t hullmins, hullmaxs;
@@ -715,33 +663,6 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 	// list of entities to test for collisions
 	int numtouchedicts;
 	static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if (VectorCompare(mins, maxs))
-	{
-		vec3_t shiftstart, shiftend;
-		VectorAdd(start, mins, shiftstart);
-		VectorAdd(pEnd, mins, shiftend);
-		if (VectorCompare(start, pEnd))
-			trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
-		else
-			trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
-		VectorSubtract(trace.endpos, mins, trace.endpos);
-		return trace;
-	}
-
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#else
 	if (VectorCompare(mins, maxs))
 	{
 		vec3_t shiftstart, shiftend;
@@ -750,11 +671,10 @@ trace_t CL_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 		if (VectorCompare(start, end))
 			trace = CL_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities);
 		else
-			trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
+			trace = CL_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, extend, hitnetworkbrushmodels, hitnetworkplayers, hitnetworkentity, hitcsqcentities, false);
 		VectorSubtract(trace.endpos, mins, trace.endpos);
 		return trace;
 	}
-#endif
 
 	if (hitnetworkentity)
 		*hitnetworkentity = 0;
@@ -770,7 +690,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);
+	Collision_ClipToWorld(&cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
 	cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
 	if (cliptrace.startsolid || cliptrace.fraction < 1)
 		cliptrace.ent = prog ? prog->edicts : NULL;
@@ -830,7 +750,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);
+			Collision_ClipToGenericEntity(&trace, ent->model, ent->frameblend, ent->skeleton, vec3_origin, vec3_origin, 0, &ent->matrix, &ent->inversematrix, start, mins, maxs, end, hitsupercontentsmask, extend);
 			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 				*hitnetworkentity = cl.brushmodel_entities[i];
 			Collision_CombineTraces(&cliptrace, &trace, NULL, true);
@@ -876,7 +796,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);
+			Collision_ClipToGenericEntity(&trace, NULL, NULL, NULL, cl.playerstandmins, cl.playerstandmaxs, SUPERCONTENTS_BODY, &entmatrix, &entinversematrix, start, mins, maxs, end, hitsupercontentsmask, extend);
 			if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 				*hitnetworkentity = i;
 			Collision_CombineTraces(&cliptrace, &trace, NULL, false);
@@ -940,9 +860,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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
 		else
-			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
 
 		if (cliptrace.realfraction > trace.realfraction && hitnetworkentity)
 			*hitnetworkentity = 0;
@@ -950,10 +870,6 @@ skipnetworkplayers:
 	}
 
 finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 	return cliptrace;
 }
 
@@ -962,11 +878,7 @@ finished:
 CL_Cache_TraceLine
 ==================
 */
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t pEnd, int type, int hitsupercontentsmask)
-#else
 trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask)
-#endif
 {
 	prvm_prog_t *prog = CLVM_prog;
 	int i;
@@ -985,20 +897,6 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
 	// list of entities to test for collisions
 	int numtouchedicts;
 	static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if(collision_endposnudge.value > 0 && !VectorCompare(start, pEnd))
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#endif
 
 	VectorCopy(start, clipstart);
 	VectorCopy(end, clipend);
@@ -1070,10 +968,6 @@ trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int typ
 	}
 
 finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 	return cliptrace;
 }
 
diff --git a/cl_collision.h b/cl_collision.h
index 851502cf..fb9e87ed 100644
--- a/cl_collision.h
+++ b/cl_collision.h
@@ -10,8 +10,8 @@ dp_model_t *CL_GetModelFromEdict(prvm_edict_t *ed);
 
 void CL_LinkEdict(prvm_edict_t *ent);
 int CL_GenericHitSuperContentsMask(const prvm_edict_t *edict);
-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, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities);
-trace_t CL_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities, qboolean hitsurfaces);
+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_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_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, qboolean hitnetworkbrushmodels, qboolean hitnetworkplayers, int *hitnetworkentity, qboolean hitcsqcentities);
 trace_t CL_Cache_TraceLineSurfaces(const vec3_t start, const vec3_t end, int type, int hitsupercontentsmask);
 #define CL_PointSuperContents(point) (CL_TracePoint((point), sv_gameplayfix_swiminbmodels.integer ? MOVE_NOMONSTERS : MOVE_WORLDONLY, NULL, 0, true, false, NULL, false).startsupercontents)
diff --git a/cl_input.c b/cl_input.c
index ecebd716..e5d2726f 100644
--- a/cl_input.c
+++ b/cl_input.c
@@ -836,7 +836,7 @@ static qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s)
 	for (i = 0;i < NUMOFFSETS;i++)
 	{
 		VectorAdd(offsets[i], s->origin, neworigin);
-		if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid)
+		if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true).startsolid)
 		{
 			VectorCopy(neworigin, s->origin);
 			return true;
@@ -868,7 +868,7 @@ static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
 		// low ceiling first
 		if (s->crouched)
 		{
-			trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+			trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 			if (!trace.startsolid)
 				s->crouched = false;
 		}
@@ -887,7 +887,7 @@ static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
 	// set onground
 	VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1);
 	VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 1); // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :)
-	trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+	trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 	if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
 	{
 		s->onground = true;
@@ -939,20 +939,20 @@ static void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
 	for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++)
 	{
 		VectorMA(s->origin, t, s->velocity, neworigin);
-		trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+		trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 		if (trace.fraction < 1 && trace.plane.normal[2] == 0)
 		{
 			// may be a step or wall, try stepping up
 			// first move forward at a higher level
 			VectorSet(currentorigin2, s->origin[0], s->origin[1], s->origin[2] + cl.movevars_stepheight);
 			VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + cl.movevars_stepheight);
-			trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+			trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 			if (!trace2.startsolid)
 			{
 				// then move down from there
 				VectorCopy(trace2.endpos, currentorigin2);
 				VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], s->origin[2]);
-				trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+				trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 				//Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]);
 				// accept the new trace if it made some progress
 				if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
@@ -1352,9 +1352,9 @@ static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
 				VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]);
 				VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34);
 				if (cls.protocol == PROTOCOL_QUAKEWORLD)
-					trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+					trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true);
 				else
-					trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false);
+					trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, s->self, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, collision_extendmovelength.value, true, true, NULL, true, false);
 				if (trace.fraction == 1 && !trace.startsolid)
 					friction *= cl.movevars_edgefriction;
 			}
diff --git a/cl_main.c b/cl_main.c
index 509608b2..9ae5e69c 100644
--- a/cl_main.c
+++ b/cl_main.c
@@ -1490,7 +1490,7 @@ static void CL_LinkNetworkEntity(entity_t *e)
 		trace_t trace;
 		matrix4x4_t tempmatrix;
 		Matrix4x4_Transform(&e->render.matrix, muzzleflashorigin, v2);
-		trace = CL_TraceLine(origin, v2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, NULL, false, false);
+		trace = CL_TraceLine(origin, v2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, false);
 		Matrix4x4_Normalize(&tempmatrix, &e->render.matrix);
 		Matrix4x4_SetOrigin(&tempmatrix, trace.endpos[0], trace.endpos[1], trace.endpos[2]);
 		Matrix4x4_Scale(&tempmatrix, 150, 1);
diff --git a/cl_particles.c b/cl_particles.c
index 83639ade..04ff9fb8 100644
--- a/cl_particles.c
+++ b/cl_particles.c
@@ -772,7 +772,7 @@ particle_t *CL_NewParticle(const vec3_t sortorigin, unsigned short ptypeindex, i
 		part->typeindex = pt_spark;
 		part->bounce = 0;
 		VectorMA(part->org, lifetime, part->vel, endvec);
-		trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, true, false, NULL, false, false);
+		trace = CL_TraceLine(part->org, endvec, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK, collision_extendmovelength.value, true, false, NULL, false, false);
 		part->die = cl.time + lifetime * trace.fraction;
 		part2 = CL_NewParticle(endvec, pt_raindecal, pcolor1, pcolor2, tex_rainsplash, part->size, part->size * 20, part->alpha, part->alpha / 0.4, 0, 0, trace.endpos[0] + trace.plane.normal[0], trace.endpos[1] + trace.plane.normal[1], trace.endpos[2] + trace.plane.normal[2], trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2], 0, 0, 0, 0, pqualityreduction, 0, 1, PBLEND_ADD, PARTICLE_ORIENTED_DOUBLESIDED, -1, -1, -1, 1, 1, 0, 0, NULL);
 		if (part2)
@@ -913,7 +913,7 @@ void CL_SpawnDecalParticleForPoint(const vec3_t org, float maxdist, float size,
 	{
 		VectorRandom(org2);
 		VectorMA(org, maxdist, org2, org2);
-		trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, true, false, &hitent, false, true);
+		trace = CL_TraceLine(org, org2, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, &hitent, false, true);
 		// take the closest trace result that doesn't end up hitting a NOMARKS
 		// surface (sky for example)
 		if (bestfrac > trace.fraction && !(trace.hitq3surfaceflags & Q3SURFACEFLAG_NOMARKS))
@@ -1870,7 +1870,7 @@ void CL_ParticleExplosion (const vec3_t org)
 					{
 						VectorRandom(v2);
 						VectorMA(org, 128, v2, v);
-						trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false);
+						trace = CL_TraceLine(org, v, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, false);
 					}
 					while (k < 16 && trace.fraction < 0.1f);
 					VectorSubtract(trace.endpos, org, v2);
@@ -2979,7 +2979,7 @@ void R_DrawParticles (void)
 //				if (p->bounce && cl.time >= p->delayedcollisions)
 				if (p->bounce && cl_particles_collisions.integer && VectorLength(p->vel))
 				{
-					trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), true, false, &hitent, false, false);
+					trace = CL_TraceLine(oldorg, p->org, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | ((p->typeindex == pt_rain || p->typeindex == pt_snow) ? SUPERCONTENTS_LIQUIDSMASK : 0), collision_extendmovelength.value, true, false, &hitent, false, false);
 					// if the trace started in or hit something of SUPERCONTENTS_NODROP
 					// or if the trace hit something flagged as NOIMPACT
 					// then remove the particle
diff --git a/clvm_cmds.c b/clvm_cmds.c
index 0099933a..c9cecff3 100644
--- a/clvm_cmds.c
+++ b/clvm_cmds.c
@@ -302,7 +302,7 @@ static void VM_CL_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 = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false);
+	trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), collision_extendtracelinelength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false);
 
 	CL_VM_SetTraceGlobals(prog, &trace, svent);
 //	R_TimeReport("traceline");
@@ -342,7 +342,7 @@ static void VM_CL_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 = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
+	trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), collision_extendtraceboxlength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
 
 	CL_VM_SetTraceGlobals(prog, &trace, svent);
 //	R_TimeReport("tracebox");
@@ -378,7 +378,7 @@ static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edi
 		VectorCopy(PRVM_clientedictvector(tossent, origin), start);
 		VectorCopy(PRVM_clientedictvector(tossent, mins), mins);
 		VectorCopy(PRVM_clientedictvector(tossent, maxs), maxs);
-		trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
+		trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), collision_extendmovelength.value, true, true, NULL, true);
 		VectorCopy (trace.endpos, PRVM_clientedictvector(tossent, origin));
 
 		if (trace.fraction < 1)
@@ -552,7 +552,7 @@ static void VM_CL_droptofloor (prvm_prog_t *prog)
 	VectorCopy(PRVM_clientedictvector(ent, origin), end);
 	end[2] -= 256;
 
-	trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
+	trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, NULL, true);
 
 	if (trace.fraction != 1)
 	{
@@ -630,7 +630,7 @@ realcheck:
 	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
 	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
 	stop[2] = start[2] - 2*sv_stepheight.value;
-	trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false);
+	trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, NULL, true, false);
 
 	if (trace.fraction == 1.0)
 		return;
@@ -644,7 +644,7 @@ realcheck:
 			start[0] = stop[0] = x ? maxs[0] : mins[0];
 			start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-			trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true, false);
+			trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, NULL, true, false);
 
 			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
 				bottom = trace.endpos[2];
@@ -3637,7 +3637,7 @@ realcheck:
 	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
 	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
 	stop[2] = start[2] - 2*sv_stepheight.value;
-	trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false);
+	trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, false, NULL, true, false);
 
 	if (trace.fraction == 1.0)
 		return false;
@@ -3650,7 +3650,7 @@ realcheck:
 			start[0] = stop[0] = x ? maxs[0] : mins[0];
 			start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-			trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, false, NULL, true, false);
+			trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, false, NULL, true, false);
 
 			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
 				bottom = trace.endpos[2];
@@ -3703,7 +3703,7 @@ static qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qb
 					neworg[2] += 8;
 			}
 			VectorCopy(PRVM_clientedictvector(ent, origin), start);
-			trace = CL_TraceBox(start, mins, maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+			trace = CL_TraceBox(start, mins, maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, &svent, true);
 			if (settrace)
 				CL_VM_SetTraceGlobals(prog, &trace, svent);
 
@@ -3731,14 +3731,14 @@ static qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qb
 	VectorCopy (neworg, end);
 	end[2] -= sv_stepheight.value*2;
 
-	trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+	trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, &svent, true);
 	if (settrace)
 		CL_VM_SetTraceGlobals(prog, &trace, svent);
 
 	if (trace.startsolid)
 	{
 		neworg[2] -= sv_stepheight.value;
-		trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, &svent, true);
+		trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), collision_extendmovelength.value, true, true, &svent, true);
 		if (settrace)
 			CL_VM_SetTraceGlobals(prog, &trace, svent);
 		if (trace.startsolid)
diff --git a/collision.c b/collision.c
index ef237e92..cdcd08da 100644
--- a/collision.c
+++ b/collision.c
@@ -12,16 +12,16 @@
 cvar_t collision_impactnudge = {0, "collision_impactnudge", "0.03125", "how much to back off from the impact"};
 cvar_t collision_startnudge = {0, "collision_startnudge", "0", "how much to bias collision trace start"};
 cvar_t collision_endnudge = {0, "collision_endnudge", "0", "how much to bias collision trace end"};
-cvar_t collision_enternudge = {0, "collision_enternudge", "0", "how much to bias collision entry fraction"};
-cvar_t collision_leavenudge = {0, "collision_leavenudge", "0", "how much to bias collision exit fraction"};
+cvar_t collision_enternudge = {0, "collision_enternudge", "0.03125", "how much to bias collision entry fraction"};
+cvar_t collision_leavenudge = {0, "collision_leavenudge", "0.03125", "how much to bias collision exit fraction"};
 cvar_t collision_prefernudgedfraction = {0, "collision_prefernudgedfraction", "1", "whether to sort collision events by nudged fraction (1) or real fraction (0)"};
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-cvar_t collision_endposnudge = {0, "collision_endposnudge", "0", "workaround to fix trace_endpos sometimes being returned where it would be inside solid by making that collision hit (recommended: values like 1)"};
-#endif
+cvar_t collision_extendmovelength = {0, "collision_extendmovelength", "16", "internal bias on trace length to ensure detection of collisions within the collision_impactnudge/collision_enternudge/collision_leavenudge distance so that short moves do not degrade across frames (this does not alter the final trace length)"};
+cvar_t collision_extendtraceboxlength = {0, "collision_extendtraceboxlength", "1", "internal bias for tracebox() qc builtin to account for collision_impactnudge/collision_enternudge/collision_leavenudge (this does not alter the final trace length)"};
+cvar_t collision_extendtracelinelength = {0, "collision_extendtracelinelength", "1", "internal bias for traceline() qc builtin to account for collision_impactnudge/collision_enternudge/collision_leavenudge (this does not alter the final trace length)"};
 cvar_t collision_debug_tracelineasbox = {0, "collision_debug_tracelineasbox", "0", "workaround for any bugs in Collision_TraceLineBrushFloat by using Collision_TraceBrushBrushFloat"};
 cvar_t collision_cache = {0, "collision_cache", "1", "store results of collision traces for next frame to reuse if possible (optimization)"};
 //cvar_t collision_triangle_neighborsides = {0, "collision_triangle_neighborsides", "1", "override automatic side generation if triangle has neighbors with face planes that form a convex edge (perfect solution, but can not work for all edges)"};
-cvar_t collision_triangle_bevelsides = {0, "collision_triangle_bevelsides", "1", "generate sloped edge planes on triangles - if 0, see axialedgeplanes"};
+cvar_t collision_triangle_bevelsides = {0, "collision_triangle_bevelsides", "0", "generate sloped edge planes on triangles - if 0, see axialedgeplanes"};
 cvar_t collision_triangle_axialsides = {0, "collision_triangle_axialsides", "1", "generate axially-aligned edge planes on triangles - otherwise use perpendicular edge planes"};
 
 mempool_t *collision_mempool;
@@ -34,9 +34,9 @@ void Collision_Init (void)
 	Cvar_RegisterVariable(&collision_enternudge);
 	Cvar_RegisterVariable(&collision_leavenudge);
 	Cvar_RegisterVariable(&collision_prefernudgedfraction);
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	Cvar_RegisterVariable(&collision_endposnudge);
-#endif
+	Cvar_RegisterVariable(&collision_extendmovelength);
+	Cvar_RegisterVariable(&collision_extendtracelinelength);
+	Cvar_RegisterVariable(&collision_extendtraceboxlength);
 	Cvar_RegisterVariable(&collision_debug_tracelineasbox);
 	Cvar_RegisterVariable(&collision_cache);
 //	Cvar_RegisterVariable(&collision_triangle_neighborsides);
@@ -640,21 +640,15 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *trace_sta
 			if (nplane2 & 1)
 			{
 				CrossProduct(trace_start->edgedirs[nedge1].v, other_start->edgedirs[nedge2].v, startplane);
-				if (VectorLength2(startplane) < COLLISION_EDGECROSS_MINLENGTH2)
-					continue; // degenerate crossproduct
 				CrossProduct(trace_end->edgedirs[nedge1].v, other_end->edgedirs[nedge2].v, endplane);
-				if (VectorLength2(endplane) < COLLISION_EDGECROSS_MINLENGTH2)
-					continue; // degenerate crossproduct
 			}
 			else
 			{
 				CrossProduct(other_start->edgedirs[nedge2].v, trace_start->edgedirs[nedge1].v, startplane);
-				if (VectorLength2(startplane) < COLLISION_EDGECROSS_MINLENGTH2)
-					continue; // degenerate crossproduct
 				CrossProduct(other_end->edgedirs[nedge2].v, trace_end->edgedirs[nedge1].v, endplane);
-				if (VectorLength2(endplane) < COLLISION_EDGECROSS_MINLENGTH2)
-					continue; // degenerate crossproduct
 			}
+			if (VectorLength2(startplane) < COLLISION_EDGECROSS_MINLENGTH2 || VectorLength2(endplane) < COLLISION_EDGECROSS_MINLENGTH2)
+				continue; // degenerate crossproducts
 			VectorNormalize(startplane);
 			VectorNormalize(endplane);
 		}
@@ -665,7 +659,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *trace_sta
 		//Con_Printf("%c%i: startdist = %f, enddist = %f, startdist / (startdist - enddist) = %f\n", nplane2 != nplane ? 'b' : 'a', nplane2, startdist, enddist, startdist / (startdist - enddist));
 
 		// aside from collisions, this is also used for error correction
-		if (startdist < collision_impactnudge.value && nplane < numplanes1 && (startdepth < startdist || startdepth == 1))
+		if (startdist <= collision_impactnudge.value && nplane < numplanes1 && (startdepth < startdist || startdepth == 1))
 		{
 			startdepth = startdist;
 			VectorCopy(startplane, startdepthnormal);
@@ -676,7 +670,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *trace_sta
 			// moving into brush
 			if (enddist >= collision_enternudge.value)
 				return;
-			if (startdist > 0)
+			if (startdist >= 0)
 			{
 				// enter
 				imove = 1 / (startdist - enddist);
@@ -729,7 +723,7 @@ void Collision_TraceBrushBrushFloat(trace_t *trace, const colbrushf_t *trace_sta
 		else
 		{
 			// moving out of brush
-			if (startdist > 0)
+			if (startdist >= 0)
 				return;
 			if (enddist > 0)
 			{
@@ -1782,7 +1776,7 @@ void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t
 		return;
 	}
 
-	Collision_ClipLineToGenericEntity(trace, model, NULL, NULL, vec3_origin, vec3_origin, 0, matrix, inversematrix, start, end, hitsupercontentsmask, true);
+	Collision_ClipLineToGenericEntity(trace, model, NULL, NULL, vec3_origin, vec3_origin, 0, matrix, inversematrix, start, end, hitsupercontentsmask, collision_extendmovelength.value, true);
 
 	cached->result = *trace;
 }
@@ -1796,22 +1790,95 @@ void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model,
 		return;
 	}
 
-	Collision_ClipLineToWorld(trace, model, start, end, hitsupercontents, true);
+	Collision_ClipLineToWorld(trace, model, start, end, hitsupercontents, collision_extendmovelength.value, true);
 
 	cached->result = *trace;
 }
 
-void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask)
+typedef struct extendtraceinfo_s
 {
-	float starttransformed[3], endtransformed[3];
+	trace_t *trace;
+	float realstart[3];
+	float realend[3];
+	float realdelta[3];
+	float extendstart[3];
+	float extendend[3];
+	float extenddelta[3];
+	float reallength;
+	float extendlength;
+	float scaletoextend;
+	float extend;
+}
+extendtraceinfo_t;
 
+static void Collision_ClipExtendPrepare(extendtraceinfo_t *extendtraceinfo, trace_t *trace, const vec3_t tstart, const vec3_t tend, float textend)
+{
 	memset(trace, 0, sizeof(*trace));
 	trace->fraction = trace->realfraction = 1;
 
-	Matrix4x4_Transform(inversematrix, start, starttransformed);
-	Matrix4x4_Transform(inversematrix, end, endtransformed);
+	extendtraceinfo->trace = trace;
+	VectorCopy(tstart, extendtraceinfo->realstart);
+	VectorCopy(tend, extendtraceinfo->realend);
+	VectorSubtract(extendtraceinfo->realend, extendtraceinfo->realstart, extendtraceinfo->realdelta);
+	VectorCopy(extendtraceinfo->realstart, extendtraceinfo->extendstart);
+	VectorCopy(extendtraceinfo->realend, extendtraceinfo->extendend);
+	VectorCopy(extendtraceinfo->realdelta, extendtraceinfo->extenddelta);
+	extendtraceinfo->reallength = VectorLength(extendtraceinfo->realdelta);
+	extendtraceinfo->extendlength = extendtraceinfo->reallength;
+	extendtraceinfo->scaletoextend = 1.0f;
+	extendtraceinfo->extend = textend;
+
+	// make the trace longer according to the extend parameter
+	if (extendtraceinfo->reallength && extendtraceinfo->extend)
+	{
+		extendtraceinfo->extendlength = extendtraceinfo->reallength + extendtraceinfo->extend;
+		extendtraceinfo->scaletoextend = extendtraceinfo->extendlength / extendtraceinfo->reallength;
+		VectorMA(extendtraceinfo->realstart, extendtraceinfo->scaletoextend, extendtraceinfo->realdelta, extendtraceinfo->extendend);
+		VectorSubtract(extendtraceinfo->extendend, extendtraceinfo->extendstart, extendtraceinfo->extenddelta);
+	}
+}
+
+static void Collision_ClipExtendFinish(extendtraceinfo_t *extendtraceinfo)
+{
+	trace_t *trace = extendtraceinfo->trace;
+
+	if (trace->fraction != 1.0f)
+	{
+		// undo the extended trace length
+		trace->fraction *= extendtraceinfo->scaletoextend;
+		trace->realfraction *= extendtraceinfo->scaletoextend;
+
+		// if the extended trace hit something that the unextended trace did not hit (even considering the collision_impactnudge), then we have to clear the hit information
+		if (trace->fraction > 1.0f)
+		{
+			// note that ent may refer to either startsolid or fraction<1, we can't restore the startsolid ent unfortunately
+ 			trace->ent = NULL;
+			trace->hitq3surfaceflags = 0;
+			trace->hitsupercontents = 0;
+			trace->hittexture = NULL;
+			VectorClear(trace->plane.normal);
+			trace->plane.dist = 0.0f;
+		}
+	}
+
+	// clamp things
+	trace->fraction = bound(0, trace->fraction, 1);
+	trace->realfraction = bound(0, trace->realfraction, 1);
+
+	// calculate the end position
+	VectorMA(extendtraceinfo->realstart, trace->fraction, extendtraceinfo->realdelta, trace->endpos);
+}
+
+void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t tstart, const vec3_t mins, const vec3_t maxs, const vec3_t tend, int hitsupercontentsmask, float extend)
+{
+	vec3_t starttransformed, endtransformed;
+	extendtraceinfo_t extendtraceinfo;
+	Collision_ClipExtendPrepare(&extendtraceinfo, trace, tstart, tend, extend);
+
+	Matrix4x4_Transform(inversematrix, extendtraceinfo.extendstart, starttransformed);
+	Matrix4x4_Transform(inversematrix, extendtraceinfo.extendend, endtransformed);
 #if COLLISIONPARANOID >= 3
-	Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]);
+	Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", extendtraceinfo.extendstart[0], extendtraceinfo.extendstart[1], extendtraceinfo.extendstart[2], starttransformed[0], starttransformed[1], starttransformed[2], extendtraceinfo.extendend[0], extendtraceinfo.extendend[1], extendtraceinfo.extendend[2], endtransformed[0], endtransformed[1], endtransformed[2]);
 #endif
 
 	if (model && model->TraceBox)
@@ -1824,8 +1891,8 @@ void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const fram
 			colboxbrushf_t thisbrush_start, thisbrush_end;
 			Collision_BrushForBox(&thisbrush_start, mins, maxs, 0, 0, NULL);
 			Collision_BrushForBox(&thisbrush_end, mins, maxs, 0, 0, NULL);
-			Collision_TranslateBrush(start, &thisbrush_start.brush);
-			Collision_TranslateBrush(end, &thisbrush_end.brush);
+			Collision_TranslateBrush(extendtraceinfo.extendstart, &thisbrush_start.brush);
+			Collision_TranslateBrush(extendtraceinfo.extendend, &thisbrush_end.brush);
 			Collision_TransformBrush(inversematrix, &thisbrush_start.brush);
 			Collision_TransformBrush(inversematrix, &thisbrush_end.brush);
 			//Collision_TranslateBrush(starttransformed, &thisbrush_start.brush);
@@ -1837,37 +1904,34 @@ void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const fram
 	}
 	else // and this requires that the transformation matrix doesn't have angles components, like SV_TraceBox ensures; FIXME may get called if a model is SOLID_BSP but has no TraceBox function
 		Collision_ClipTrace_Box(trace, bodymins, bodymaxs, starttransformed, mins, maxs, endtransformed, hitsupercontentsmask, bodysupercontents, 0, NULL);
-	trace->fraction = bound(0, trace->fraction, 1);
-	trace->realfraction = bound(0, trace->realfraction, 1);
 
-	VectorLerp(start, trace->fraction, end, trace->endpos);
+	Collision_ClipExtendFinish(&extendtraceinfo);
+
 	// transform plane
 	// NOTE: this relies on plane.dist being directly after plane.normal
 	Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal);
 }
 
-void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents)
+void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t tstart, const vec3_t mins, const vec3_t maxs, const vec3_t tend, int hitsupercontents, float extend)
 {
-	memset(trace, 0, sizeof(*trace));
-	trace->fraction = trace->realfraction = 1;
+	extendtraceinfo_t extendtraceinfo;
+	Collision_ClipExtendPrepare(&extendtraceinfo, trace, tstart, tend, extend);
 	// ->TraceBox: TraceBrush not needed here, as worldmodel is never rotated
 	if (model && model->TraceBox)
-		model->TraceBox(model, NULL, NULL, trace, start, mins, maxs, end, hitsupercontents);
-	trace->fraction = bound(0, trace->fraction, 1);
-	trace->realfraction = bound(0, trace->realfraction, 1);
-	VectorLerp(start, trace->fraction, end, trace->endpos);
+		model->TraceBox(model, NULL, NULL, trace, extendtraceinfo.extendstart, mins, maxs, extendtraceinfo.extendend, hitsupercontents);
+	Collision_ClipExtendFinish(&extendtraceinfo);
 }
 
-void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces)
+void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t tstart, const vec3_t tend, int hitsupercontentsmask, float extend, qboolean hitsurfaces)
 {
-	float starttransformed[3], endtransformed[3];
-	memset(trace, 0, sizeof(*trace));
-	trace->fraction = trace->realfraction = 1;
+	vec3_t starttransformed, endtransformed;
+	extendtraceinfo_t extendtraceinfo;
+	Collision_ClipExtendPrepare(&extendtraceinfo, trace, tstart, tend, extend);
 
-	Matrix4x4_Transform(inversematrix, start, starttransformed);
-	Matrix4x4_Transform(inversematrix, end, endtransformed);
+	Matrix4x4_Transform(inversematrix, extendtraceinfo.extendstart, starttransformed);
+	Matrix4x4_Transform(inversematrix, extendtraceinfo.extendend, endtransformed);
 #if COLLISIONPARANOID >= 3
-	Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", start[0], start[1], start[2], starttransformed[0], starttransformed[1], starttransformed[2], end[0], end[1], end[2], endtransformed[0], endtransformed[1], endtransformed[2]);
+	Con_Printf("trans(%f %f %f -> %f %f %f, %f %f %f -> %f %f %f)", extendtraceinfo.extendstart[0], extendtraceinfo.extendstart[1], extendtraceinfo.extendstart[2], starttransformed[0], starttransformed[1], starttransformed[2], extendtraceinfo.extendend[0], extendtraceinfo.extendend[1], extendtraceinfo.extendend[2], endtransformed[0], endtransformed[1], endtransformed[2]);
 #endif
 
 	if (model && model->TraceLineAgainstSurfaces && hitsurfaces)
@@ -1876,26 +1940,25 @@ void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const
 		model->TraceLine(model, frameblend, skeleton, trace, starttransformed, endtransformed, hitsupercontentsmask);
 	else
 		Collision_ClipTrace_Box(trace, bodymins, bodymaxs, starttransformed, vec3_origin, vec3_origin, endtransformed, hitsupercontentsmask, bodysupercontents, 0, NULL);
-	trace->fraction = bound(0, trace->fraction, 1);
-	trace->realfraction = bound(0, trace->realfraction, 1);
 
-	VectorLerp(start, trace->fraction, end, trace->endpos);
+	Collision_ClipExtendFinish(&extendtraceinfo);
+
 	// transform plane
 	// NOTE: this relies on plane.dist being directly after plane.normal
 	Matrix4x4_TransformPositivePlane(matrix, trace->plane.normal[0], trace->plane.normal[1], trace->plane.normal[2], trace->plane.dist, trace->plane.normal);
 }
 
-void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces)
+void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t tstart, const vec3_t tend, int hitsupercontents, float extend, qboolean hitsurfaces)
 {
-	memset(trace, 0, sizeof(*trace));
-	trace->fraction = trace->realfraction = 1;
+	extendtraceinfo_t extendtraceinfo;
+	Collision_ClipExtendPrepare(&extendtraceinfo, trace, tstart, tend, extend);
+
 	if (model && model->TraceLineAgainstSurfaces && hitsurfaces)
-		model->TraceLineAgainstSurfaces(model, NULL, NULL, trace, start, end, hitsupercontents);
+		model->TraceLineAgainstSurfaces(model, NULL, NULL, trace, extendtraceinfo.extendstart, extendtraceinfo.extendend, hitsupercontents);
 	else if (model && model->TraceLine)
-		model->TraceLine(model, NULL, NULL, trace, start, end, hitsupercontents);
-	trace->fraction = bound(0, trace->fraction, 1);
-	trace->realfraction = bound(0, trace->realfraction, 1);
-	VectorLerp(start, trace->fraction, end, trace->endpos);
+		model->TraceLine(model, NULL, NULL, trace, extendtraceinfo.extendstart, extendtraceinfo.extendend, hitsupercontents);
+
+	Collision_ClipExtendFinish(&extendtraceinfo);
 }
 
 void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const frameblend_t *frameblend, const skeleton_t *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask)
diff --git a/collision.h b/collision.h
index 0da12477..afc12bc0 100644
--- a/collision.h
+++ b/collision.h
@@ -155,12 +155,12 @@ void Collision_TraceBrushTriangleFloat(trace_t *trace, const colbrushf_t *thisbr
 // passedict is excluded from clipping checks
 struct frameblend_s;
 struct skeleton_s;
-void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask);
-void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, qboolean hitsurfaces);
+void Collision_ClipToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, float extend);
+void Collision_ClipLineToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask, float extend, qboolean hitsurfaces);
 void Collision_ClipPointToGenericEntity(trace_t *trace, dp_model_t *model, const struct frameblend_s *frameblend, const struct skeleton_s *skeleton, const vec3_t bodymins, const vec3_t bodymaxs, int bodysupercontents, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, int hitsupercontentsmask);
 // like above but does not do a transform and does nothing if model is NULL
-void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents);
-void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, qboolean hitsurfaces);
+void Collision_ClipToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontents, float extend);
+void Collision_ClipLineToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, const vec3_t end, int hitsupercontents, float extend, qboolean hitsurfaces);
 void Collision_ClipPointToWorld(trace_t *trace, dp_model_t *model, const vec3_t start, int hitsupercontents);
 // caching surface trace for renderer (NOT THREAD SAFE)
 void Collision_Cache_ClipLineToGenericEntitySurfaces(trace_t *trace, dp_model_t *model, matrix4x4_t *matrix, matrix4x4_t *inversematrix, const vec3_t start, const vec3_t end, int hitsupercontentsmask);
@@ -170,9 +170,6 @@ void Collision_Cache_ClipLineToWorldSurfaces(trace_t *trace, dp_model_t *model,
 // updates fraction, endpos, plane and surface info if new fraction is shorter
 void Collision_CombineTraces(trace_t *cliptrace, const trace_t *trace, void *touch, qboolean isbmodel);
 
-// shorten a trace by the given factor
-void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t end);
-
 // this enables rather large debugging spew!
 // settings:
 // 0 = no spew
@@ -181,11 +178,10 @@ void Collision_ShortenTrace(trace_t *trace, float shorten_factor, const vec3_t e
 // 3 = spew detailed trace flow (bsp tree recursion info)
 #define COLLISIONPARANOID 0
 
-// make every trace <collision_endposnudge>qu longer, and shorten the result, to work around a stupid bug somewhere
-#define COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-extern cvar_t collision_endposnudge;
-#endif
-
+extern cvar_t collision_impactnudge;
+extern cvar_t collision_extendtracelinelength;
+extern cvar_t collision_extendtraceboxlength;
+extern cvar_t collision_extendmovelength;
+extern cvar_t collision_prefernudgedfraction;
 
 #endif
diff --git a/model_brush.c b/model_brush.c
index 96ea11ea..f4789ced 100644
--- a/model_brush.c
+++ b/model_brush.c
@@ -693,7 +693,6 @@ RecursiveHullCheckTraceInfo_t;
 #define HULLCHECKSTATE_SOLID 1
 #define HULLCHECKSTATE_DONE 2
 
-extern cvar_t collision_prefernudgedfraction;
 static int Mod_Q1BSP_RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3])
 {
 	// status variables, these don't need to be saved on the stack when
@@ -705,156 +704,158 @@ static int Mod_Q1BSP_RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int nu
 
 	// variables that need to be stored on the stack when recursing
 	mclipnode_t *node;
-	int side;
+	int p1side, p2side;
 	double midf, mid[3];
 
-	// LordHavoc: a goto!  everyone flee in terror... :)
-loc0:
-	// check for empty
-	if (num < 0)
-	{
-		num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num);
-		if (!t->trace->startfound)
-		{
-			t->trace->startfound = true;
-			t->trace->startsupercontents |= num;
-		}
-		if (num & SUPERCONTENTS_LIQUIDSMASK)
-			t->trace->inwater = true;
-		if (num == 0)
-			t->trace->inopen = true;
-		if (num & SUPERCONTENTS_SOLID)
-			t->trace->hittexture = &mod_q1bsp_texture_solid;
-		else if (num & SUPERCONTENTS_SKY)
-			t->trace->hittexture = &mod_q1bsp_texture_sky;
-		else if (num & SUPERCONTENTS_LAVA)
-			t->trace->hittexture = &mod_q1bsp_texture_lava;
-		else if (num & SUPERCONTENTS_SLIME)
-			t->trace->hittexture = &mod_q1bsp_texture_slime;
-		else
-			t->trace->hittexture = &mod_q1bsp_texture_water;
-		t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
-		t->trace->hitsupercontents = num;
-		if (num & t->trace->hitsupercontentsmask)
+	// keep looping until we hit a leaf
+	while (num >= 0)
+	{
+		// find the point distances
+		node = t->hull->clipnodes + num;
+		plane = t->hull->planes + node->planenum;
+
+		// axial planes can be calculated more quickly without the DotProduct
+		if (plane->type < 3)
 		{
-			// if the first leaf is solid, set startsolid
-			if (t->trace->allsolid)
-				t->trace->startsolid = true;
-#if COLLISIONPARANOID >= 3
-			Con_Print("S");
-#endif
-			return HULLCHECKSTATE_SOLID;
+			t1 = p1[plane->type] - plane->dist;
+			t2 = p2[plane->type] - plane->dist;
 		}
 		else
 		{
-			t->trace->allsolid = false;
-#if COLLISIONPARANOID >= 3
-			Con_Print("E");
-#endif
-			return HULLCHECKSTATE_EMPTY;
+			t1 = DotProduct (plane->normal, p1) - plane->dist;
+			t2 = DotProduct (plane->normal, p2) - plane->dist;
 		}
-	}
 
-	// find the point distances
-	node = t->hull->clipnodes + num;
+		// negative plane distances indicate children[1] (behind plane)
+		p1side = t1 < 0;
+		p2side = t2 < 0;
 
-	plane = t->hull->planes + node->planenum;
-	if (plane->type < 3)
-	{
-		t1 = p1[plane->type] - plane->dist;
-		t2 = p2[plane->type] - plane->dist;
-	}
-	else
-	{
-		t1 = DotProduct (plane->normal, p1) - plane->dist;
-		t2 = DotProduct (plane->normal, p2) - plane->dist;
-	}
-
-	if (t1 < 0)
-	{
-		if (t2 < 0)
+		// if the line starts and ends on the same side of the plane, recurse
+		// into that child instantly
+		if (p1side == p2side)
 		{
 #if COLLISIONPARANOID >= 3
-			Con_Print("<");
+			if (p1side)
+				Con_Print("<");
+			else
+				Con_Print(">");
 #endif
-			num = node->children[1];
-			goto loc0;
+			// loop back and process the start child
+			num = node->children[p1side];
 		}
-		side = 1;
-	}
-	else
-	{
-		if (t2 >= 0)
+		else
 		{
+			// find the midpoint where the line crosses the plane, use the
+			// original line for best accuracy
 #if COLLISIONPARANOID >= 3
-			Con_Print(">");
+			Con_Print("M");
 #endif
-			num = node->children[0];
-			goto loc0;
-		}
-		side = 0;
-	}
+			if (plane->type < 3)
+			{
+				t1 = t->start[plane->type] - plane->dist;
+				t2 = t->end[plane->type] - plane->dist;
+			}
+			else
+			{
+				t1 = DotProduct (plane->normal, t->start) - plane->dist;
+				t2 = DotProduct (plane->normal, t->end) - plane->dist;
+			}
+			midf = t1 / (t1 - t2);
+			midf = bound(p1f, midf, p2f);
+			VectorMA(t->start, midf, t->dist, mid);
+
+			// we now have a mid point, essentially splitting the line into
+			// the segments in the near child and the far child, we can now
+			// recurse those in order and get their results
+
+			// recurse both sides, front side first
+			ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p1side], p1f, midf, p1, mid);
+			// if this side is not empty, return what it is (solid or done)
+			if (ret != HULLCHECKSTATE_EMPTY)
+				return ret;
+
+			ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p2side], midf, p2f, mid, p2);
+			// if other side is not solid, return what it is (empty or done)
+			if (ret != HULLCHECKSTATE_SOLID)
+				return ret;
+
+			// front is air and back is solid, this is the impact point...
+
+			// copy the plane information, flipping it if needed
+			if (p1side)
+			{
+				t->trace->plane.dist = -plane->dist;
+				VectorNegate (plane->normal, t->trace->plane.normal);
+			}
+			else
+			{
+				t->trace->plane.dist = plane->dist;
+				VectorCopy (plane->normal, t->trace->plane.normal);
+			}
+
+			// calculate the true fraction
+			t1 = DotProduct(t->trace->plane.normal, t->start) - t->trace->plane.dist;
+			t2 = DotProduct(t->trace->plane.normal, t->end) - t->trace->plane.dist;
+			midf = t1 / (t1 - t2);
+			t->trace->realfraction = bound(0, midf, 1);
+
+			// calculate the return fraction which is nudged off the surface a bit
+			midf = (t1 - collision_impactnudge.value) / (t1 - t2);
+			t->trace->fraction = bound(0, midf, 1);
+
+			if (collision_prefernudgedfraction.integer)
+				t->trace->realfraction = t->trace->fraction;
 
-	// the line intersects, find intersection point
-	// LordHavoc: this uses the original trace for maximum accuracy
 #if COLLISIONPARANOID >= 3
-	Con_Print("M");
+			Con_Print("D");
 #endif
-	if (plane->type < 3)
-	{
-		t1 = t->start[plane->type] - plane->dist;
-		t2 = t->end[plane->type] - plane->dist;
-	}
-	else
-	{
-		t1 = DotProduct (plane->normal, t->start) - plane->dist;
-		t2 = DotProduct (plane->normal, t->end) - plane->dist;
+			return HULLCHECKSTATE_DONE;
+		}
 	}
 
-	midf = t1 / (t1 - t2);
-	midf = bound(p1f, midf, p2f);
-	VectorMA(t->start, midf, t->dist, mid);
+	// we reached a leaf contents
 
-	// recurse both sides, front side first
-	ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side], p1f, midf, p1, mid);
-	// if this side is not empty, return what it is (solid or done)
-	if (ret != HULLCHECKSTATE_EMPTY)
-		return ret;
-
-	ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[side ^ 1], midf, p2f, mid, p2);
-	// if other side is not solid, return what it is (empty or done)
-	if (ret != HULLCHECKSTATE_SOLID)
-		return ret;
-
-	// front is air and back is solid, this is the impact point...
-	if (side)
+	// check for empty
+	num = Mod_Q1BSP_SuperContentsFromNativeContents(NULL, num);
+	if (!t->trace->startfound)
 	{
-		t->trace->plane.dist = -plane->dist;
-		VectorNegate (plane->normal, t->trace->plane.normal);
+		t->trace->startfound = true;
+		t->trace->startsupercontents |= num;
 	}
+	if (num & SUPERCONTENTS_LIQUIDSMASK)
+		t->trace->inwater = true;
+	if (num == 0)
+		t->trace->inopen = true;
+	if (num & SUPERCONTENTS_SOLID)
+		t->trace->hittexture = &mod_q1bsp_texture_solid;
+	else if (num & SUPERCONTENTS_SKY)
+		t->trace->hittexture = &mod_q1bsp_texture_sky;
+	else if (num & SUPERCONTENTS_LAVA)
+		t->trace->hittexture = &mod_q1bsp_texture_lava;
+	else if (num & SUPERCONTENTS_SLIME)
+		t->trace->hittexture = &mod_q1bsp_texture_slime;
 	else
+		t->trace->hittexture = &mod_q1bsp_texture_water;
+	t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
+	t->trace->hitsupercontents = num;
+	if (num & t->trace->hitsupercontentsmask)
 	{
-		t->trace->plane.dist = plane->dist;
-		VectorCopy (plane->normal, t->trace->plane.normal);
+		// if the first leaf is solid, set startsolid
+		if (t->trace->allsolid)
+			t->trace->startsolid = true;
+#if COLLISIONPARANOID >= 3
+		Con_Print("S");
+#endif
+		return HULLCHECKSTATE_SOLID;
 	}
-
-	// calculate the true fraction
-	t1 = DotProduct(t->trace->plane.normal, t->start) - t->trace->plane.dist;
-	t2 = DotProduct(t->trace->plane.normal, t->end) - t->trace->plane.dist;
-	midf = t1 / (t1 - t2);
-	t->trace->realfraction = bound(0, midf, 1);
-
-	// calculate the return fraction which is nudged off the surface a bit
-	midf = (t1 - DIST_EPSILON) / (t1 - t2);
-	t->trace->fraction = bound(0, midf, 1);
-
-	if (collision_prefernudgedfraction.integer)
-		t->trace->realfraction = t->trace->fraction;
-
+	else
+	{
+		t->trace->allsolid = false;
 #if COLLISIONPARANOID >= 3
-	Con_Print("D");
+		Con_Print("E");
 #endif
-	return HULLCHECKSTATE_DONE;
+		return HULLCHECKSTATE_EMPTY;
+	}
 }
 
 //#if COLLISIONPARANOID < 2
@@ -1197,48 +1198,45 @@ static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_model_t *model, vec3_t ambie
 	float front, back;
 	float mid, distz = endz - startz;
 
-loc0:
-	if (!node->plane)
-		return false;		// didn't hit anything
-
-	switch (node->plane->type)
+	while (node->plane)
 	{
-	case PLANE_X:
-		node = node->children[x < node->plane->dist];
-		goto loc0;
-	case PLANE_Y:
-		node = node->children[y < node->plane->dist];
-		goto loc0;
-	case PLANE_Z:
-		side = startz < node->plane->dist;
-		if ((endz < node->plane->dist) == side)
-		{
-			node = node->children[side];
-			goto loc0;
-		}
-		// found an intersection
-		mid = node->plane->dist;
-		break;
-	default:
-		back = front = x * node->plane->normal[0] + y * node->plane->normal[1];
-		front += startz * node->plane->normal[2];
-		back += endz * node->plane->normal[2];
-		side = front < node->plane->dist;
-		if ((back < node->plane->dist) == side)
-		{
-			node = node->children[side];
-			goto loc0;
+		switch (node->plane->type)
+		{
+		case PLANE_X:
+			node = node->children[x < node->plane->dist];
+			continue; // loop back and process the new node
+		case PLANE_Y:
+			node = node->children[y < node->plane->dist];
+			continue; // loop back and process the new node
+		case PLANE_Z:
+			side = startz < node->plane->dist;
+			if ((endz < node->plane->dist) == side)
+			{
+				node = node->children[side];
+				continue; // loop back and process the new node
+			}
+			// found an intersection
+			mid = node->plane->dist;
+			break;
+		default:
+			back = front = x * node->plane->normal[0] + y * node->plane->normal[1];
+			front += startz * node->plane->normal[2];
+			back += endz * node->plane->normal[2];
+			side = front < node->plane->dist;
+			if ((back < node->plane->dist) == side)
+			{
+				node = node->children[side];
+				continue; // loop back and process the new node
+			}
+			// found an intersection
+			mid = startz + distz * (front - node->plane->dist) / (front - back);
+			break;
 		}
-		// found an intersection
-		mid = startz + distz * (front - node->plane->dist) / (front - back);
-		break;
-	}
 
-	// go down front side
-	if (node->children[side]->plane && Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid))
-		return true;	// hit something
-	else
-	{
+		// go down front side
+		if (node->children[side]->plane && Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid))
+			return true;	// hit something
+
 		// check for impact on this node
 		if (node->numsurfaces)
 		{
@@ -1329,8 +1327,11 @@ loc0:
 		node = node->children[side ^ 1];
 		startz = mid;
 		distz = endz - startz;
-		goto loc0;
+		// loop back and process the new node
 	}
+
+	// did not hit anything
+	return false;
 }
 
 static void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
@@ -1404,7 +1405,7 @@ static const texture_t *Mod_Q1BSP_TraceLineAgainstSurfacesFindTextureOnNode(Recu
 		t->trace->realfraction = midf;
 
 		// calculate the return fraction which is nudged off the surface a bit
-		midf = (t1 - DIST_EPSILON) / (t1 - t2);
+		midf = (t1 - collision_impactnudge.value) / (t1 - t2);
 		t->trace->fraction = bound(0, midf, 1);
 
 		if (collision_prefernudgedfraction.integer)
@@ -6335,7 +6336,12 @@ static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend
 		node = bih->nodes + nodenum;
 		VectorCopy(nodestackline[nodestackpos], nodestart);
 		VectorCopy(nodestackline[nodestackpos] + 3, nodeend);
-		sweepnodemins[0] = min(nodestart[0], nodeend[0]); sweepnodemins[1] = min(nodestart[1], nodeend[1]); sweepnodemins[2] = min(nodestart[2], nodeend[2]); sweepnodemaxs[0] = max(nodestart[0], nodeend[0]); sweepnodemaxs[1] = max(nodestart[1], nodeend[1]); sweepnodemaxs[2] = max(nodestart[2], nodeend[2]);
+		sweepnodemins[0] = min(nodestart[0], nodeend[0]) - 1;
+		sweepnodemins[1] = min(nodestart[1], nodeend[1]) - 1;
+		sweepnodemins[2] = min(nodestart[2], nodeend[2]) - 1;
+		sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + 1;
+		sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + 1;
+		sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + 1;
 		if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, node->mins, node->maxs))
 			continue;
 		if (node->type <= BIH_SPLITZ && nodestackpos+2 <= 1024)
@@ -6378,7 +6384,12 @@ static void Mod_CollisionBIH_TraceLineShared(dp_model_t *model, const frameblend
 			axis = 2; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); }
 			// some of the line intersected the enlarged node box
 			// calculate sweep bounds for this node
-			sweepnodemins[0] = min(nodestart[0], nodeend[0]); sweepnodemins[1] = min(nodestart[1], nodeend[1]); sweepnodemins[2] = min(nodestart[2], nodeend[2]); sweepnodemaxs[0] = max(nodestart[0], nodeend[0]); sweepnodemaxs[1] = max(nodestart[1], nodeend[1]); sweepnodemaxs[2] = max(nodestart[2], nodeend[2]);
+			sweepnodemins[0] = min(nodestart[0], nodeend[0]) - 1;
+			sweepnodemins[1] = min(nodestart[1], nodeend[1]) - 1;
+			sweepnodemins[2] = min(nodestart[2], nodeend[2]) - 1;
+			sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + 1;
+			sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + 1;
+			sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + 1;
 			for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
 			{
 				leaf = bih->leafs + node->children[axis];
@@ -6479,7 +6490,12 @@ void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameble
 		node = bih->nodes + nodenum;
 		VectorCopy(nodestackline[nodestackpos], nodestart);
 		VectorCopy(nodestackline[nodestackpos] + 3, nodeend);
-		sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0]; sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1]; sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2]; sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0]; sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1]; sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2];
+		sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0] - 1;
+		sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1] - 1;
+		sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2] - 1;
+		sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0] + 1;
+		sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1] + 1;
+		sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2] + 1;
 		if (!BoxesOverlap(sweepnodemins, sweepnodemaxs, node->mins, node->maxs))
 			continue;
 		if (node->type <= BIH_SPLITZ && nodestackpos+2 <= 1024)
@@ -6522,7 +6538,12 @@ void Mod_CollisionBIH_TraceBrush(dp_model_t *model, const frameblend_t *frameble
 			axis = 2; d1 = nodestart[axis] - nodebigmins[axis]; d2 = nodeend[axis] - nodebigmins[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); } d1 = nodebigmaxs[axis] - nodestart[axis]; d2 = nodebigmaxs[axis] - nodeend[axis]; if (d1 < 0) { if (d2 < 0) continue; f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodestart); } else if (d2 < 0) { f = d1 / (d1 - d2); VectorLerp(nodestart, f, nodeend, nodeend); }
 			// some of the line intersected the enlarged node box
 			// calculate sweep bounds for this node
-			sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0]; sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1]; sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2]; sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0]; sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1]; sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2];
+			sweepnodemins[0] = min(nodestart[0], nodeend[0]) + mins[0] - 1;
+			sweepnodemins[1] = min(nodestart[1], nodeend[1]) + mins[1] - 1;
+			sweepnodemins[2] = min(nodestart[2], nodeend[2]) + mins[2] - 1;
+			sweepnodemaxs[0] = max(nodestart[0], nodeend[0]) + maxs[0] + 1;
+			sweepnodemaxs[1] = max(nodestart[1], nodeend[1]) + maxs[1] + 1;
+			sweepnodemaxs[2] = max(nodestart[2], nodeend[2]) + maxs[2] + 1;
 			for (axis = 0;axis < BIH_MAXUNORDEREDCHILDREN && node->children[axis] >= 0;axis++)
 			{
 				leaf = bih->leafs + node->children[axis];
@@ -6911,12 +6932,12 @@ static void Mod_Q3BSP_TraceBrush(dp_model_t *model, const frameblend_t *frameble
 	trace->fraction = 1;
 	trace->realfraction = 1;
 	trace->hitsupercontentsmask = hitsupercontentsmask;
-	segmentmins[0] = min(start->mins[0], end->mins[0]);
-	segmentmins[1] = min(start->mins[1], end->mins[1]);
-	segmentmins[2] = min(start->mins[2], end->mins[2]);
-	segmentmaxs[0] = max(start->maxs[0], end->maxs[0]);
-	segmentmaxs[1] = max(start->maxs[1], end->maxs[1]);
-	segmentmaxs[2] = max(start->maxs[2], end->maxs[2]);
+	segmentmins[0] = min(start->mins[0], end->mins[0]) - 1;
+	segmentmins[1] = min(start->mins[1], end->mins[1]) - 1;
+	segmentmins[2] = min(start->mins[2], end->mins[2]) - 1;
+	segmentmaxs[0] = max(start->maxs[0], end->maxs[0]) + 1;
+	segmentmaxs[1] = max(start->maxs[1], end->maxs[1]) + 1;
+	segmentmaxs[2] = max(start->maxs[2], end->maxs[2]) + 1;
 	if (mod_collision_bih.integer)
 		Mod_CollisionBIH_TraceBrush(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask);
 	else if (model->brush.submodel)
diff --git a/r_explosion.c b/r_explosion.c
index 3c40edbf..afd2fd88 100644
--- a/r_explosion.c
+++ b/r_explosion.c
@@ -189,7 +189,7 @@ void R_NewExplosion(const vec3_t org)
 				// clip start origin
 				if (e->clipping)
 				{
-					trace = CL_TraceLine(e->origin, e->vert[j], MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false);
+					trace = CL_TraceLine(e->origin, e->vert[j], MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, false);
 					VectorCopy(trace.endpos, e->vert[i]);
 				}
 			}
@@ -245,7 +245,7 @@ static void R_MoveExplosion(explosion_t *e)
 			VectorMA(e->vert[i], frametime, e->vertvel[i], end);
 			if (e->clipping)
 			{
-				trace = CL_TraceLine(e->vert[i], end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, false);
+				trace = CL_TraceLine(e->vert[i], end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, false);
 				if (trace.fraction < 1)
 				{
 					// clip velocity against the wall
diff --git a/r_shadow.c b/r_shadow.c
index 2985a6d7..2878de9d 100644
--- a/r_shadow.c
+++ b/r_shadow.c
@@ -2715,7 +2715,7 @@ void R_Shadow_UpdateBounceGridTexture(void)
 				if (settings.staticmode)
 				{
 					// static mode fires a LOT of rays but none of them are identical, so they are not cached
-					cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, true, false, NULL, true, true);
+					cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
 				}
 				else
 				{
@@ -5187,7 +5187,7 @@ static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
 	else
 	{
 		// FIXME: these traces should scan all render entities instead of cl.world
-		if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
+		if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
 			return;
 	}
 	VectorScale(rtlight->currentcolor, cscale, color);
@@ -5520,7 +5520,7 @@ static void R_Shadow_SelectLightInView(void)
 		if (rating >= 0.95)
 		{
 			rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
-			if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
+			if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
 			{
 				bestrating = rating;
 				best = light;
@@ -5970,7 +5970,7 @@ static void R_Shadow_SetCursorLocationForView(void)
 	vec3_t dest, endpos;
 	trace_t trace;
 	VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
-	trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
+	trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
 	if (trace.fraction < 1)
 	{
 		dist = trace.fraction * r_editlights_cursordistance.value;
@@ -6754,7 +6754,7 @@ void R_LightPoint(float *color, const vec3_t p, const int flags)
 			if (f <= 0)
 				continue;
 			// todo: add to both ambient and diffuse
-			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
+			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
 				VectorMA(color, f, light->currentcolor, color);
 		}
 	}
@@ -6775,7 +6775,7 @@ void R_LightPoint(float *color, const vec3_t p, const int flags)
 			if (f <= 0)
 				continue;
 			// todo: add to both ambient and diffuse
-			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1)
+			if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
 				VectorMA(color, f, light->color, color);
 		}
 	}
@@ -6859,7 +6859,7 @@ void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const
 			intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
 			if (intensity <= 0.0f)
 				continue;
-			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
+			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
 				continue;
 			// scale down intensity to add to both ambient and diffuse
 			//intensity *= 0.5f;
@@ -6892,7 +6892,7 @@ void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const
 			intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
 			if (intensity <= 0.0f)
 				continue;
-			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
+			if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
 				continue;
 			// scale down intensity to add to both ambient and diffuse
 			//intensity *= 0.5f;
diff --git a/sbar.c b/sbar.c
index b537bcd3..9cc3b870 100644
--- a/sbar.c
+++ b/sbar.c
@@ -1205,7 +1205,7 @@ void Sbar_ShowFPS(void)
 		trace.hittexture = NULL; // to make sure
 		// TODO change this trace to be stopped by anything "visible" (i.e. with a drawsurface), but not stuff like weapclip
 		// probably needs adding a new SUPERCONTENTS type
-		trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, true, false, NULL, true, true);
+		trace = CL_TraceLine(org, dest, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, true, true);
 		if(trace.hittexture)
 			strlcpy(texstring, trace.hittexture->name, sizeof(texstring));
 		else
diff --git a/server.h b/server.h
index ae32cb24..59d0eca3 100644
--- a/server.h
+++ b/server.h
@@ -575,8 +575,8 @@ qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent);
 /// calculates hitsupercontentsmask for a generic qc entity
 int SV_GenericHitSuperContentsMask(const prvm_edict_t *edict);
 /// traces a box move against worldmodel and all entities in the specified area
-trace_t SV_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);
-trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask);
+trace_t SV_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);
+trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, float extend);
 trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask);
 int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts);
 
diff --git a/sv_move.c b/sv_move.c
index 13b96c7b..6d42e298 100644
--- a/sv_move.c
+++ b/sv_move.c
@@ -71,7 +71,7 @@ realcheck:
 	start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
 	start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
 	stop[2] = start[2] - 2*sv_stepheight.value;
-	trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+	trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 
 	if (trace.fraction == 1.0)
 		return false;
@@ -84,7 +84,7 @@ realcheck:
 			start[0] = stop[0] = x ? maxs[0] : mins[0];
 			start[1] = stop[1] = y ? maxs[1] : mins[1];
 
-			trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+			trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 
 			if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
 				bottom = trace.endpos[2];
@@ -143,7 +143,7 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
 				}
 			}
 			VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
-			trace = SV_TraceBox(entorigin, entmins, entmaxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+			trace = SV_TraceBox(entorigin, entmins, entmaxs, neworg, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 
 			if (trace.fraction == 1)
 			{
@@ -172,12 +172,12 @@ qboolean SV_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean
 	VectorCopy (neworg, end);
 	end[2] -= sv_stepheight.value*2;
 
-	trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+	trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 
 	if (trace.startsolid)
 	{
 		neworg[2] -= sv_stepheight.value;
-		trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent));
+		trace = SV_TraceBox(neworg, entmins, entmaxs, end, MOVE_NORMAL, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 		if (trace.startsolid)
 			return false;
 	}
diff --git a/sv_phys.c b/sv_phys.c
index 7dc65c1a..c84f0c15 100644
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -231,7 +231,7 @@ trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int
 		VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
 		VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
 		if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, 0.0f);
 		else
 			Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
 
@@ -247,11 +247,7 @@ finished:
 SV_TraceLine
 ==================
 */
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#else
-trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#endif
+trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, float extend)
 {
 	prvm_prog_t *prog = SVVM_prog;
 	int i, bodysupercontents;
@@ -276,26 +272,8 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 	// list of entities to test for collisions
 	int numtouchedicts;
 	static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if (VectorCompare(start, pEnd))
-		return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
-
-	if(collision_endposnudge.value > 0)
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#else
 	if (VectorCompare(start, end))
 		return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
-#endif
 
 	//return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
 
@@ -308,7 +286,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 #endif
 
 	// clip to world
-	Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false);
+	Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, extend, false);
 	cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
 	if (cliptrace.startsolid || cliptrace.fraction < 1)
 		cliptrace.ent = prog->edicts;
@@ -402,18 +380,14 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 		VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
 		VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
 		if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
 		else
-			Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
+			Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, extend, false);
 
 		Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
 	}
 
 finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 	return cliptrace;
 }
 
@@ -422,18 +396,10 @@ finished:
 SV_Move
 ==================
 */
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
 #if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#else
-trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#endif
+trace_t SV_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)
 #else
-#if COLLISIONPARANOID >= 1
-trace_t SV_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)
-#else
-trace_t SV_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)
-#endif
+trace_t SV_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)
 #endif
 {
 	prvm_prog_t *prog = SVVM_prog;
@@ -463,33 +429,6 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 	// list of entities to test for collisions
 	int numtouchedicts;
 	static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	vec3_t end;
-	vec_t len = 0;
-
-	if (VectorCompare(mins, maxs))
-	{
-		vec3_t shiftstart, shiftend;
-		VectorAdd(start, mins, shiftstart);
-		VectorAdd(pEnd, mins, shiftend);
-		if (VectorCompare(start, pEnd))
-			trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
-		else
-			trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
-		VectorSubtract(trace.endpos, mins, trace.endpos);
-		return trace;
-	}
-
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-	{
-		// TRICK: make the trace 1 qu longer!
-		VectorSubtract(pEnd, start, end);
-		len = VectorNormalizeLength(end);
-		VectorMA(pEnd, collision_endposnudge.value, end, end);
-	}
-	else
-		VectorCopy(pEnd, end);
-#else
 	if (VectorCompare(mins, maxs))
 	{
 		vec3_t shiftstart, shiftend;
@@ -498,11 +437,10 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 		if (VectorCompare(start, end))
 			trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
 		else
-			trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
+			trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, extend);
 		VectorSubtract(trace.endpos, mins, trace.endpos);
 		return trace;
 	}
-#endif
 
 	VectorCopy(start, clipstart);
 	VectorCopy(end, clipend);
@@ -515,7 +453,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 #endif
 
 	// clip to world
-	Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+	Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
 	cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
 	if (cliptrace.startsolid || cliptrace.fraction < 1)
 		cliptrace.ent = prog->edicts;
@@ -620,18 +558,14 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 		VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
 		VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
 		if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(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);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, extend);
 		else
-			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+			Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, extend);
 
 		Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
 	}
 
 finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-	if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
-		Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
 	return cliptrace;
 }
 
@@ -980,7 +914,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 	VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
 	VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
 	VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
-	trace = SV_TraceBox(org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
+	trace = SV_TraceBox(org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents, collision_extendmovelength.value);
 	if (trace.startsupercontents & contents)
 		return true;
 	else
@@ -1019,7 +953,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 #else
 		// verify if the endpos is REALLY outside solid
 		VectorCopy(trace.endpos, org);
-		trace = SV_TraceBox(org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, contents);
+		trace = SV_TraceBox(org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, contents, collision_extendmovelength.value);
 		if(trace.startsolid)
 			Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
 		else
@@ -1542,7 +1476,7 @@ static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pi
 				testorigin[coord] += stuckmins[coord] - goodmins[coord];
 			}
 
-			stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+			stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 			if (stucktrace.bmodelstartsolid)
 			{
 				// BAD BAD, can't fix that
@@ -1612,7 +1546,7 @@ qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
 		VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
 		for (bump = 0;bump < 10;bump++)
 		{
-			stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+			stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, pass ? MOVE_WORLDONLY : MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 			if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
 			{
 				// found a good location, use it
@@ -1668,7 +1602,7 @@ static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, q
 	else
 		type = MOVE_NORMAL;
 
-	*trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
+	*trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 	// fail the move if stuck in world
 	if (trace->worldstartsolid)
 		return true;
@@ -1894,7 +1828,7 @@ static void SV_PushMove (prvm_edict_t *pusher, float movetime)
 			VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
 			VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
 			VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
-			Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents);
+			Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, collision_extendmovelength.value);
 			//trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
 			if (!trace.startsolid)
 			{
@@ -1961,7 +1895,7 @@ static void SV_PushMove (prvm_edict_t *pusher, float movetime)
 		VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
 		VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
 		VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
-		Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents);
+		Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, collision_extendmovelength.value);
 		if (trace.startsolid)
 		{
 			vec3_t move2;
@@ -2395,7 +2329,7 @@ static void SV_WalkMove (prvm_edict_t *ent)
 			type = MOVE_NORMAL;
 		VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
 		VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
-		trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
+		trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent), collision_extendmovelength.value);
 		if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
 			clip |= 1; // but we HAVE found a floor
 	}
diff --git a/sv_user.c b/sv_user.c
index a65705f4..377472cc 100644
--- a/sv_user.c
+++ b/sv_user.c
@@ -59,7 +59,7 @@ void SV_SetIdealPitch (void)
 		bottom[1] = top[1];
 		bottom[2] = top[2] - 160;
 
-		tr = SV_TraceLine(top, bottom, MOVE_NOMONSTERS, host_client->edict, SUPERCONTENTS_SOLID);
+		tr = SV_TraceLine(top, bottom, MOVE_NOMONSTERS, host_client->edict, SUPERCONTENTS_SOLID, collision_extendmovelength.value);
 		// if looking at a wall, leave ideal the way is was
 		if (tr.startsolid)
 			return;
@@ -126,7 +126,7 @@ static void SV_UserFriction (void)
 	start[2] = PRVM_serveredictvector(host_client->edict, origin)[2] + PRVM_serveredictvector(host_client->edict, mins)[2];
 	stop[2] = start[2] - 34;
 
-	trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, host_client->edict, SV_GenericHitSuperContentsMask(host_client->edict));
+	trace = SV_TraceLine(start, stop, MOVE_NOMONSTERS, host_client->edict, SV_GenericHitSuperContentsMask(host_client->edict), collision_extendmovelength.value);
 
 	if (trace.fraction == 1.0)
 		friction = sv_friction.value*sv_edgefriction.value;
diff --git a/svvm_cmds.c b/svvm_cmds.c
index 11fa9598..cc4d7e11 100644
--- a/svvm_cmds.c
+++ b/svvm_cmds.c
@@ -654,7 +654,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), collision_extendtracelinelength.value);
 
 	VM_SetTraceGlobals(prog, &trace);
 }
@@ -693,7 +693,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), collision_extendtraceboxlength.value);
 
 	VM_SetTraceGlobals(prog, &trace);
 }
@@ -729,7 +729,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), collision_extendmovelength.value);
 		VectorCopy (trace.endpos, PRVM_serveredictvector(tossent, origin));
 		PRVM_serveredictvector(tossent, velocity)[2] -= gravity;
 
@@ -1157,13 +1157,13 @@ static void VM_SV_droptofloor(prvm_prog_t *prog)
 	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), 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), collision_extendmovelength.value);
 		VectorSubtract(trace.endpos, offset, trace.endpos);
 		if (trace.startsolid)
 		{
@@ -1311,7 +1311,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, 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 +1343,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, collision_extendmovelength.value);
 		if (tr.ent == check)
 		{	// can shoot at this one
 			bestdist = dist;
diff --git a/view.c b/view.c
index 16dbcf74..ac9c5f21 100644
--- a/view.c
+++ b/view.c
@@ -591,9 +591,9 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa
 #else
 				// trace from first person view location to our chosen third person view location
 #if 1
-				trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true);
+				trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
 #else
-				trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false);
+				trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false);
 #endif
 				VectorCopy(trace.endpos, bestvieworg);
 				offset[2] = 0;
@@ -606,9 +606,9 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa
 						chase_dest[1] = vieworg[1] - forward[1] * camback + up[1] * camup + offset[1];
 						chase_dest[2] = vieworg[2] - forward[2] * camback + up[2] * camup + offset[2];
 #if 1
-						trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true);
+						trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
 #else
-						trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false);
+						trace = CL_TraceBox(vieworg, camboxmins, camboxmaxs, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false);
 #endif
 						if (bestvieworg[2] > trace.endpos[2])
 							bestvieworg[2] = trace.endpos[2];
@@ -634,7 +634,7 @@ void V_CalcRefdefUsing (const matrix4x4_t *entrendermatrix, const vec3_t clviewa
 				chase_dest[0] = vieworg[0] + forward[0] * dist;
 				chase_dest[1] = vieworg[1] + forward[1] * dist;
 				chase_dest[2] = vieworg[2] + forward[2] * dist + camup;
-				trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, true, false, NULL, false, true);
+				trace = CL_TraceLine(vieworg, chase_dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_SKY, collision_extendmovelength.value, true, false, NULL, false, true);
 				VectorMAMAM(1, trace.endpos, 8, forward, 4, trace.plane.normal, vieworg);
 			}
 		}
-- 
2.39.5