From 62364be9495c4c996cd5aa6a7b3b1d5a1a73d0bd Mon Sep 17 00:00:00 2001
From: Rudolf Polzer <divverent@xonotic.org>
Date: Fri, 3 Jan 2014 12:47:37 +0100
Subject: [PATCH] Implemented.

---
 server.h  |  1 +
 sv_phys.c | 18 +++++++++++++++++-
 world.c   | 21 +++++++++++++++++++--
 world.h   |  1 +
 4 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/server.h b/server.h
index 0dfaf034..b7714cd6 100644
--- a/server.h
+++ b/server.h
@@ -581,6 +581,7 @@ trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, co
 trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask);
 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);
+int SV_EntitiesInBoxNearLine(const vec3_t mins, const vec3_t maxs, const vec3_t start, const vec3_t end, vec_t distance, int maxedicts, prvm_edict_t **resultedicts);
 
 qboolean SV_CanSeeBox(int numsamples, vec_t enlarge, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs);
 
diff --git a/sv_phys.c b/sv_phys.c
index e88baa25..37d63575 100644
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -350,7 +350,7 @@ trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_
 	// clip to entities
 	// because this uses World_EntitiestoBox, we know all entity boxes overlap
 	// the clip region, so we can skip culling checks in the loop below
-	numtouchedicts = SV_EntitiesInBox(clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
+	numtouchedicts = SV_EntitiesInBoxNearLine(clipboxmins, clipboxmaxs, clipstart, clipend, 0, MAX_EDICTS, touchedicts);
 	if (numtouchedicts > MAX_EDICTS)
 	{
 		// this never happens
@@ -749,6 +749,22 @@ int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_e
 		return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts);
 }
 
+int SV_EntitiesInBoxNearLine(const vec3_t mins, const vec3_t maxs, const vec3_t start, const vec3_t end, vec_t distance, int maxedicts, prvm_edict_t **resultedicts)
+{
+	prvm_prog_t *prog = SVVM_prog;
+	vec3_t paddedmins, paddedmaxs;
+	if (sv_areadebug.integer)
+		return SV_EntitiesInBox(mins, maxs, maxedicts, resultedicts);
+	if (maxedicts < 1 || resultedicts == NULL)
+		return 0;
+	// LordHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination)
+	//VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
+	//VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
+	VectorCopy(mins, paddedmins);
+	VectorCopy(maxs, paddedmaxs);
+	return World_EntitiesInBoxNearLine(&sv.world, paddedmins, paddedmaxs, start, end, distance, maxedicts, resultedicts);
+}
+
 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
 {
 	prvm_prog_t *prog = SVVM_prog;
diff --git a/world.c b/world.c
index 553cabef..376fc997 100644
--- a/world.c
+++ b/world.c
@@ -263,15 +263,32 @@ int World_EntitiesInBox(world_t *world, const vec3_t requestmins, const vec3_t r
 	return numlist;
 }
 
-qboolean IsNearLine(vec3_t mins, vec3_t maxs, vec3_t linestart, vec3_t lineend, vec_t distance)
+static qboolean IsNearLine(const vec3_t mins, const vec3_t maxs, const vec3_t linestart, const vec3_t lineend, vec_t distance)
 {
+	vec3_t center, linedirection, center_to_start, center_to_start_projection;
+	vec_t radius, center_to_start_projection_length, line_center_distance;
 	// This tests only the infinite length line - linestart and lineend
 	// themselves don't matter as long as they are on the line.
 	// Also, we approximate even more:
 	// we just test whether distance between center of mins, maxs is and
 	// the line is smaller or equal the distance + the radius of the mins,
 	// maxs.
-	return true;
+	VectorMAM(0.5, mins, 0.5, maxs, center);
+
+	radius = VectorDistance(center, mins) + distance;
+
+	VectorSubtract(lineend, linestart, linedirection);
+	VectorNormalize(linedirection);
+
+	VectorSubtract(linestart, center, center_to_start);
+
+	center_to_start_projection_length = DotProduct(center_to_start, linedirection);
+
+	VectorScale(linedirection, center_to_start_projection_length, center_to_start_projection);
+
+	line_center_distance = VectorDistance(center_to_start_projection, center_to_start);
+
+	return line_center_distance <= radius;
 }
 
 int World_EntitiesInBoxNearLine(world_t *world, const vec3_t requestmins, const vec3_t requestmaxs, const vec3_t requeststart, const vec3_t requestend, vec_t requestdistance, int maxlist, prvm_edict_t **list)
diff --git a/world.h b/world.h
index e43ebd14..afbe57cf 100644
--- a/world.h
+++ b/world.h
@@ -115,6 +115,7 @@ void World_LinkEdict(world_t *world, struct prvm_edict_s *ent, const vec3_t mins
 
 /// \returns list of entities touching a box
 int World_EntitiesInBox(world_t *world, const vec3_t mins, const vec3_t maxs, int maxlist, struct prvm_edict_s **list);
+int World_EntitiesInBoxNearLine(world_t *world, const vec3_t mins, const vec3_t maxs, const vec3_t start, const vec3_t end, vec_t distance, int maxlist, struct prvm_edict_s **list);
 
 void World_Start(world_t *world);
 void World_End(world_t *world);
-- 
2.39.5