diff --git a/src/p_map.c b/src/p_map.c
index e0d73721ddb7eb4907fe4b6d1f3230883f6c8c2b..d6514f8fc1925916d5c751b411c149c32bc40cdd 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1921,7 +1921,7 @@ static boolean PIT_CheckLine(line_t *ld)
 	|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
 		return true;
 
-	if (P_BoxOnLineSide(tmbbox, ld) != -1)
+	if (P_CircleOnLineSide(tmx, tmy, tmthing->radius, ld) != -1)
 		return true;
 
 	if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag.
@@ -1933,13 +1933,6 @@ static boolean PIT_CheckLine(line_t *ld)
 		== P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld))
 			return true; // the line doesn't cross between collider's start or end
 	}
-	else 
-	{
-		vertex_t closestpoint;
-		P_ClosestPointOnLine(tmthing->x, tmthing->y, ld, &closestpoint);
-		if (abs(R_PointToDist2(closestpoint.x, closestpoint.y, tmthing->x, tmthing->y)) >= tmthing->radius)
-			return true; // close enough for corners of square bounding boxes to touch, but not close enough for cylindrical collision
-	}
 
 	// A line has been hit
 
@@ -3223,13 +3216,26 @@ isblocking:
 //
 // PTR_SlideTraverse
 //
-static boolean PTR_SlideTraverse(intercept_t *in)
+static boolean PTR_SlideTraverse(line_t *li)
 {
-	line_t *li;
+	fixed_t mmomx, mmomy, x, y;
+	// Kludgy redo of previous work, should optimize later
+	if (slidemo->player)
+	{
+		mmomx = slidemo->player->rmomx = slidemo->momx - slidemo->player->cmomx;
+		mmomy = slidemo->player->rmomy = slidemo->momy - slidemo->player->cmomy;
+	}
+	else
+	{
+		mmomx = slidemo->momx;
+		mmomy = slidemo->momy;
+	}
 
-	I_Assert(in->isaline);
+	x = slidemo->x + mmomx;
+	y = slidemo->y + mmomy;
 
-	li = in->d.line;
+//	if (P_CircleOnLineSide(x, y, slidemo->radius, li) != -1)
+//		return true; // Not inside the line, non-blocking
 
 	// one-sided linedefs are always solid to sliding movement.
 	// one-sided linedef
@@ -3273,15 +3279,20 @@ isblocking:
 			P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector);
 	}
 
-	if (in->frac < bestslidefrac)
+	vertex_t closestpoint;	
+	P_ClosestPointOnLineWithinLine(x, y, li, &closestpoint);
+	fixed_t dist = abs(R_PointToDist2(closestpoint.x, closestpoint.y, x, y));
+
+
+	if (dist < bestslidefrac)
 	{
 		secondslidefrac = bestslidefrac;
 		secondslideline = bestslideline;
-		bestslidefrac = in->frac;
+		bestslidefrac = dist;
 		bestslideline = li;
 	}
 
-	return false; // stop
+	return true;
 }
 
 //
@@ -3394,7 +3405,12 @@ stairstep:
 //
 void P_SlideMove(mobj_t *mo, boolean forceslide)
 {
-	fixed_t leadx, leady, trailx, traily, newx, newy;
+	fixed_t leadx, leady, newx, newy;
+	fixed_t leftx, lefty, lefttracerx, lefttracery;
+	fixed_t rightx, righty, righttracerx, righttracery;
+	fixed_t mmomx, mmomy;
+	fixed_t maxslidefrac;
+	angle_t momang;
 	INT16 hitcount = 0;
 	boolean success = false;
 
@@ -3437,37 +3453,21 @@ retry:
 	if (++hitcount == 3)
 		goto stairstep; // don't loop forever
 
-	// trace along the three leading corners
-	if (mo->momx > 0)
+	if (mo->player)
 	{
-		leadx = mo->x + mo->radius;
-		trailx = mo->x - mo->radius;
+		mmomx = mo->player->rmomx = mo->momx - mo->player->cmomx;
+		mmomy = mo->player->rmomy = mo->momy - mo->player->cmomy;
 	}
 	else
 	{
-		leadx = mo->x - mo->radius;
-		trailx = mo->x + mo->radius;
+		mmomx = mo->momx;
+		mmomy = mo->momy;
 	}
 
-	if (mo->momy > 0)
-	{
-		leady = mo->y + mo->radius;
-		traily = mo->y - mo->radius;
-	}
-	else
-	{
-		leady = mo->y - mo->radius;
-		traily = mo->y + mo->radius;
-	}
+	maxslidefrac = mo->radius + FixedHypot(mmomx, mmomy);
+	bestslidefrac = maxslidefrac;
 
-	bestslidefrac = FRACUNIT+1;
-
-	P_PathTraverse(leadx, leady, leadx + mo->momx, leady + mo->momy,
-		PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(trailx, leady, trailx + mo->momx, leady + mo->momy,
-		PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(leadx, traily, leadx + mo->momx, traily + mo->momy,
-		PT_ADDLINES, PTR_SlideTraverse);
+	P_RadiusLinesCheck(mo->radius, mo->x + mmomx, mo->y + mmomy, PTR_SlideTraverse);
 
 	// Some walls are bouncy even if you're not
 	if (!forceslide && bestslideline && !(bestslideline->flags & ML_BOUNCY)) // SRB2kart - All walls are bouncy unless specified otherwise
@@ -3477,7 +3477,7 @@ retry:
 	}
 
 	// move up to the wall
-	if (bestslidefrac == FRACUNIT+1)
+	if (bestslidefrac == maxslidefrac)
 	{
 		// the move must have hit the middle, so stairstep
 stairstep:
@@ -3562,10 +3562,13 @@ stairstep:
 
 void P_BouncePlayerMove(mobj_t *mo)
 {
+	angle_t momang;
 	fixed_t leadx, leady;
-	fixed_t trailx, traily;
+	fixed_t leftx, lefty, lefttracerx, lefttracery;
+	fixed_t rightx, righty, righttracerx, righttracery;
 	fixed_t mmomx = 0, mmomy = 0;
 	fixed_t oldmomx = mo->momx, oldmomy = mo->momy;
+	fixed_t maxslidefrac;
 
 	if (!mo->player)
 		return;
@@ -3585,38 +3588,14 @@ void P_BouncePlayerMove(mobj_t *mo)
 	mo->player->kartstuff[k_driftcharge] = 0;
 	mo->player->kartstuff[k_pogospring] = 0;
 
-	// trace along the three leading corners
-	if (mo->momx > 0)
-	{
-		leadx = mo->x + mo->radius;
-		trailx = mo->x - mo->radius;
-	}
-	else
-	{
-		leadx = mo->x - mo->radius;
-		trailx = mo->x + mo->radius;
-	}
-
-	if (mo->momy > 0)
-	{
-		leady = mo->y + mo->radius;
-		traily = mo->y - mo->radius;
-	}
-	else
-	{
-		leady = mo->y - mo->radius;
-		traily = mo->y + mo->radius;
-	}
-
-	bestslidefrac = FRACUNIT + 1;
+	maxslidefrac = mo->radius + FixedHypot(mmomx, mmomy);
+	bestslidefrac = maxslidefrac;
 
-	P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse);
+	P_RadiusLinesCheck(mo->radius, mo->x + mmomx, mo->y + mmomy, PTR_SlideTraverse);
 
 	// Now continue along the wall.
 	// First calculate remainder.
-	bestslidefrac = FRACUNIT - bestslidefrac;
+	bestslidefrac = maxslidefrac - bestslidefrac;
 
 	if (bestslidefrac > FRACUNIT)
 		bestslidefrac = FRACUNIT;
@@ -3671,6 +3650,7 @@ void P_BounceMove(mobj_t *mo)
 	fixed_t newx, newy;
 	INT32 hitcount;
 	fixed_t mmomx = 0, mmomy = 0;
+	fixed_t maxslidefrac;
 
 	if (mo->player)
 	{
@@ -3694,37 +3674,12 @@ retry:
 	mmomx = mo->momx;
 	mmomy = mo->momy;
 
-	// trace along the three leading corners
-	if (mo->momx > 0)
-	{
-		leadx = mo->x + mo->radius;
-		trailx = mo->x - mo->radius;
-	}
-	else
-	{
-		leadx = mo->x - mo->radius;
-		trailx = mo->x + mo->radius;
-	}
-
-	if (mo->momy > 0)
-	{
-		leady = mo->y + mo->radius;
-		traily = mo->y - mo->radius;
-	}
-	else
-	{
-		leady = mo->y - mo->radius;
-		traily = mo->y + mo->radius;
-	}
-
-	bestslidefrac = FRACUNIT + 1;
-
-	P_PathTraverse(leadx, leady, leadx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(trailx, leady, trailx + mmomx, leady + mmomy, PT_ADDLINES, PTR_SlideTraverse);
-	P_PathTraverse(leadx, traily, leadx + mmomx, traily + mmomy, PT_ADDLINES, PTR_SlideTraverse);
+	maxslidefrac = mo->radius + FixedHypot(mmomx, mmomy);
+	bestslidefrac = maxslidefrac;
 
+	P_RadiusLinesCheck(mo->radius, mo->x + mmomx, mo->y + mmomy, PTR_SlideTraverse);
 	// move up to the wall
-	if (bestslidefrac == FRACUNIT + 1)
+	if (bestslidefrac == maxslidefrac)
 	{
 		// the move must have hit the middle, so bounce straight back
 bounceback:
@@ -4405,7 +4360,7 @@ static inline boolean PIT_GetSectors(line_t *ld)
 		tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
 	return true;
 
-	if (P_BoxOnLineSide(tmbbox, ld) != -1)
+	if (P_CircleOnLineSide(tmx, tmy, tmthing->radius, ld) != -1)
 		return true;
 
 	if (ld->polyobj) // line belongs to a polyobject, don't add it
@@ -4432,6 +4387,7 @@ static inline boolean PIT_GetSectors(line_t *ld)
 }
 
 // Tails 08-25-2002
+// Precipitation can stay square for hitboxes, because I would normally use tmx and tmy for P_CircleOnLineSide, but those don't seem to be set for tmprecipthing
 static inline boolean PIT_GetPrecipSectors(line_t *ld)
 {
 	if (preciptmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] ||
@@ -4440,7 +4396,7 @@ static inline boolean PIT_GetPrecipSectors(line_t *ld)
 		preciptmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
 	return true;
 
-	if (P_BoxOnLineSide(preciptmbbox, ld) != -1)
+	if (P_CircleOnLineSide(tmx, tmy, tmprecipthing->radius, ld) != -1)
 		return true;
 
 	if (ld->polyobj) // line belongs to a polyobject, don't add it
@@ -4468,7 +4424,6 @@ static inline boolean PIT_GetPrecipSectors(line_t *ld)
 
 // P_CreateSecNodeList alters/creates the sector_list that shows what sectors
 // the object resides in.
-
 void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 {
 	INT32 xl, xh, yl, yh, bx, by;
@@ -4558,6 +4513,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 	INT32 xl, xh, yl, yh, bx, by;
 	mprecipsecnode_t *node = precipsector_list;
 	precipmobj_t *saved_tmthing = tmprecipthing; /* cph - see comment at func end */
+	fixed_t saved_tmx = tmx, saved_tmy = tmy; /* ditto */
 
 	// First, clear out the existing m_thing fields. As each node is
 	// added or verified as needed, m_thing will be set properly. When
@@ -4572,6 +4528,9 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 
 	tmprecipthing = thing;
 
+	tmx = x;
+	tmy = y;
+
 	preciptmbbox[BOXTOP] = y + 2*FRACUNIT;
 	preciptmbbox[BOXBOTTOM] = y - 2*FRACUNIT;
 	preciptmbbox[BOXRIGHT] = x + 2*FRACUNIT;
@@ -4617,6 +4576,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 	*  Fun. We restore its previous value unless we're in a Boom/MBF demo.
 	*/
 	tmprecipthing = saved_tmthing;
+	tmx = saved_tmx, tmy = saved_tmy;
 }
 
 /* cphipps 2004/08/30 -
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 17df33a917256bdff71cb3e9dea03b4739bf22a0..826d02cf30296965d13c90694cc3db891d635490 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -26,6 +26,7 @@
 //
 // P_ClosestPointOnLine
 // Finds the closest point on a given line to the supplied point
+// Considers line length to be infinite, and can return results outside of the actual line
 //
 void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result)
 {
@@ -65,6 +66,27 @@ void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result)
 	return;
 }
 
+//
+// P_ClosestPointOnLineWithinLine
+// Finds the closest point on a given line to the supplied point
+// Like P_ClosestPointOnLine, except the result is constrained within the actual line
+//
+void P_ClosestPointOnLineWithinLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result)
+{
+	P_ClosestPointOnLine(x, y, line, result);
+
+	// Determine max and min bounds of the line
+	fixed_t maxx = max(line->v1->x, line->v2->x);
+	fixed_t maxy = max(line->v1->y, line->v2->y);
+	fixed_t minx = min(line->v1->x, line->v2->x);
+	fixed_t miny = min(line->v1->y, line->v2->y);
+
+	// Constrain result to line by ensuring x and y don't go beyond the maximums
+	result->x = min(max(result->x, minx),maxx);
+	result->y = min(max(result->y, miny),maxy);
+	return;
+}
+
 //
 // P_ClosestPointOnLine3D
 // Finds the closest point on a given line to the supplied point IN 3D!!!
@@ -216,6 +238,23 @@ INT32 P_BoxOnLineSide(fixed_t *tmbox, line_t *ld)
 	return -1;
 }
 
+//
+// P_CircleOnLineSide
+// Considers the line to be infinite
+// Returns side 0 or 1, -1 if circle crosses the line.
+// Man, circles are easier than boxes
+//
+INT32 P_CircleOnLineSide(fixed_t x, fixed_t y, fixed_t radius, line_t *ld)
+{
+	vertex_t closestpoint;	
+	P_ClosestPointOnLine(x, y, ld, &closestpoint);
+
+	if (abs(R_PointToDist2(closestpoint.x, closestpoint.y, x, y)) < radius)
+		return -1; // Inside circle
+	else
+		return P_PointOnLineSide(x, y, ld); // Not inside so just return this instead
+}
+
 //
 // P_PointOnDivlineSide
 // Returns 0 or 1.
@@ -1340,7 +1379,7 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
 		}
 	}
 	// Go through the sorted list
-	return P_TraverseIntercepts(trav, FRACUNIT);
+	return P_TraverseIntercepts(trav, 256*FRACUNIT);
 }
 
 
@@ -1353,13 +1392,12 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
 // returns FALSE if the loop exited early after a false return
 // value from your user function
 
-//abandoned, maybe I'll need it someday..
-/*
 boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y,
 	boolean (*func)(line_t *))
 {
 	INT32 xl, xh, yl, yh;
 	INT32 bx, by;
+	boolean blockval = true;
 
 	tmbbox[BOXTOP] = y + radius;
 	tmbbox[BOXBOTTOM] = y - radius;
@@ -1372,10 +1410,14 @@ boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y,
 	yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
 	yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
+	validcount++;
+
 	for (bx = xl; bx <= xh; bx++)
 		for (by = yl; by <= yh; by++)
 			if (!P_BlockLinesIterator(bx, by, func))
-				return false;
-	return true;
-}
-*/
+				blockval = false;
+				
+	return blockval;
+}
\ No newline at end of file
diff --git a/src/p_maputl.h b/src/p_maputl.h
index ec4a4aa3357d739f7e19957fe3246b27ee92c283..b1791cba4e0a461dfd0ec4d1ce9d0f568296cf63 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -43,12 +43,14 @@ boolean P_PathTraverse(fixed_t px1, fixed_t py1, fixed_t px2, fixed_t py2,
 
 #define P_AproxDistance(dx, dy) FixedHypot(dx, dy)
 void P_ClosestPointOnLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result);
+void P_ClosestPointOnLineWithinLine(fixed_t x, fixed_t y, line_t *line, vertex_t *result);
 void P_ClosestPointOnLine3D(fixed_t x, fixed_t y, fixed_t z, line_t *line, vertex_t *result);
 INT32 P_PointOnLineSide(fixed_t x, fixed_t y, line_t *line);
 void P_MakeDivline(line_t *li, divline_t *dl);
 void P_CameraLineOpening(line_t *plinedef);
 fixed_t P_InterceptVector(divline_t *v2, divline_t *v1);
 INT32 P_BoxOnLineSide(fixed_t *tmbox, line_t *ld);
+INT32 P_CircleOnLineSide(fixed_t x, fixed_t y, fixed_t radius, line_t *ld);
 void P_UnsetPrecipThingPosition(precipmobj_t *thing);
 void P_SetPrecipitationThingPosition(precipmobj_t *thing);
 void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y);
@@ -72,6 +74,6 @@ extern fixed_t tmbbox[4]; // p_map.c
 
 // call your user function for each line of the blockmap in the
 // bbox defined by the radius
-//boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y,
-//	boolean (*func)(line_t *));
+boolean P_RadiusLinesCheck(fixed_t radius, fixed_t x, fixed_t y,
+	boolean (*func)(line_t *));
 #endif // __P_MAPUTL__
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 7978d0f3c90b0814156b3dc62edef29509db28d6..7f895d4066f1e321f61a025f5bfc264c4298a511 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -659,136 +659,66 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover)
 	return true;
 }
 
-// P_GetFloorZ (and its ceiling counterpart)
-// Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y]
-// If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line
-// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate).
-// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking
-// usage will handle that later.
 static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, pslope_t *slope, boolean actuallylowest)
 {
 	// Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching...
-	// The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box
-	// (assuming it isn't already inside), then test each point's slope Z and return the higher of the two.
-	vertex_t v1, v2;
-	v1.x = line->v1->x;
-	v1.y = line->v1->y;
-	v2.x = line->v2->x;
-	v2.y = line->v2->y;
-
-	/*CONS_Printf("BEFORE: v1 = %f %f %f\n",
-				FIXED_TO_FLOAT(v1.x),
-				FIXED_TO_FLOAT(v1.y),
-				FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y))
-				);
-	CONS_Printf("        v2 = %f %f %f\n",
-				FIXED_TO_FLOAT(v2.x),
-				FIXED_TO_FLOAT(v2.y),
-				FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y))
-				);*/
-
-	if (abs(v1.x-x) > radius) {
-		// v1's x is out of range, so rein it in
-		fixed_t diff = abs(v1.x-x) - radius;
-
-		if (v1.x < x) { // Moving right
-			v1.x += diff;
-			v1.y += FixedMul(diff, FixedDiv(line->dy, line->dx));
-		} else { // Moving left
-			v1.x -= diff;
-			v1.y -= FixedMul(diff, FixedDiv(line->dy, line->dx));
-		}
-	}
-
-	if (abs(v1.y-y) > radius) {
-		// v1's y is out of range, so rein it in
-		fixed_t diff = abs(v1.y-y) - radius;
-
-		if (v1.y < y) { // Moving up
-			v1.y += diff;
-			v1.x += FixedMul(diff, FixedDiv(line->dx, line->dy));
-		} else { // Moving down
-			v1.y -= diff;
-			v1.x -= FixedMul(diff, FixedDiv(line->dx, line->dy));
-		}
-	}
-
-	if (abs(v2.x-x) > radius) {
-		// v1's x is out of range, so rein it in
-		fixed_t diff = abs(v2.x-x) - radius;
-
-		if (v2.x < x) { // Moving right
-			v2.x += diff;
-			v2.y += FixedMul(diff, FixedDiv(line->dy, line->dx));
-		} else { // Moving left
-			v2.x -= diff;
-			v2.y -= FixedMul(diff, FixedDiv(line->dy, line->dx));
-		}
-	}
-
-	if (abs(v2.y-y) > radius) {
-		// v2's y is out of range, so rein it in
-		fixed_t diff = abs(v2.y-y) - radius;
-
-		if (v2.y < y) { // Moving up
-			v2.y += diff;
-			v2.x += FixedMul(diff, FixedDiv(line->dx, line->dy));
-		} else { // Moving down
-			v2.y -= diff;
-			v2.x -= FixedMul(diff, FixedDiv(line->dx, line->dy));
-		}
-	}
-
-	/*CONS_Printf("AFTER:  v1 = %f %f %f\n",
-				FIXED_TO_FLOAT(v1.x),
-				FIXED_TO_FLOAT(v1.y),
-				FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y))
-				);
-	CONS_Printf("        v2 = %f %f %f\n",
-				FIXED_TO_FLOAT(v2.x),
-				FIXED_TO_FLOAT(v2.y),
-				FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y))
-				);*/
+	// https://stackoverflow.com/questions/25203613/find-intersection-of-circle-and-line because I can't be arsed to re-learn linear algebra
+
+	vertex_t closestvertex;
+	vector2_t n, closestpoint, offset, i1, i2;
+	fixed_t dist, distsquared, radiussquared;
+	n.x = line->dx;
+	n.y = line->dy;
+	FV2_Normalize(&n); // fixed it
+	P_ClosestPointOnLine(x, y, line, &closestvertex);
+	closestpoint.x = closestvertex.x;
+	closestpoint.y = closestvertex.y;
+	dist = FixedHypot(x - closestpoint.x, y - closestpoint.y);
+	distsquared = FixedMul(dist, dist);
+	radiussquared = FixedMul(radius, radius);
+	offset = *FV2_Mul(&n, FixedSqrt(radiussquared - distsquared));
+	i1 = *FV2_Add(&closestpoint, &offset);
+	i2 = *FV2_Sub(&closestpoint, &offset);
 
 	// Return the higher of the two points
 	if (actuallylowest)
 		return min(
-			P_GetZAt(slope, v1.x, v1.y),
-			P_GetZAt(slope, v2.x, v2.y)
+			P_GetZAt(slope, i1.x, i1.y),
+			P_GetZAt(slope, i2.x, i2.y)
 		);
 	else
 		return max(
-			P_GetZAt(slope, v1.x, v1.y),
-			P_GetZAt(slope, v2.x, v2.y)
+			P_GetZAt(slope, i1.x, i1.y),
+			P_GetZAt(slope, i2.x, i2.y)
 		);
 }
 
+// P_GetFloorZ (and its ceiling counterpart)
+// Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y]
+// If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line
+// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate).
+// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking
+// usage will handle that later.
 fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
 {
 	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 	if (sector->f_slope) {
-		fixed_t testx, testy;
+		fixed_t testx = x;
+		fixed_t testy = y;
+		angle_t angleuphill;
 		pslope_t *slope = sector->f_slope;
 
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
-
+		angleuphill = (INT32)slope->zangle >= 0 ? slope->xydirection : slope->xydirection+ANGLE_180;
+		
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
+			testx -= P_ReturnThrustX(mobj, angleuphill, mobj->radius);
+			testy -= P_ReturnThrustY(mobj, angleuphill, mobj->radius);
+		}
+		else {
+			testx += P_ReturnThrustX(mobj, angleuphill, mobj->radius);
+			testy += P_ReturnThrustY(mobj, angleuphill, mobj->radius);
 		}
-
-		testx += x;
-		testy += y;
 
 		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
 		if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector))
@@ -806,6 +736,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 			else
 				finalheight = INT32_MIN;
 
+			//bbox calc is still probably faster/less calculations than P_CircleOnLineSide, so we leave it for performance
 			bbox[BOXLEFT] = x-mobj->radius;
 			bbox[BOXRIGHT] = x+mobj->radius;
 			bbox[BOXTOP] = y+mobj->radius;
@@ -817,7 +748,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
 					continue;
 
-				if (P_BoxOnLineSide(bbox, ld) != -1)
+				if (P_CircleOnLineSide(x, y, mobj->radius, ld) != -1)
 					continue;
 
 				if (lowest)
@@ -834,6 +765,9 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t
 		if (line == NULL)
 			return P_GetZAt(slope, x, y);
 
+		if (mobj->player) {
+			CONS_Printf("");
+		}
 		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
 	} else // Well, that makes it easy. Just get the floor height
 		return sector->floorheight;
@@ -844,27 +778,21 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 	I_Assert(mobj != NULL);
 	I_Assert(sector != NULL);
 	if (sector->c_slope) {
-		fixed_t testx, testy;
+		fixed_t testx = x;
+		fixed_t testy = y;
+		angle_t angleuphill;
 		pslope_t *slope = sector->c_slope;
 
-		// Get the corner of the object that should be the highest on the slope
-		if (slope->d.x < 0)
-			testx = mobj->radius;
-		else
-			testx = -mobj->radius;
-
-		if (slope->d.y < 0)
-			testy = mobj->radius;
-		else
-			testy = -mobj->radius;
+		angleuphill = (INT32)slope->zangle >= 0 ? slope->xydirection : slope->xydirection+ANGLE_180;
 
 		if ((slope->zdelta > 0) ^ !!(lowest)) {
-			testx = -testx;
-			testy = -testy;
+			testx -= P_ReturnThrustX(mobj, angleuphill, mobj->radius);
+			testy -= P_ReturnThrustY(mobj, angleuphill, mobj->radius);
+		}
+		else {
+			testx += P_ReturnThrustX(mobj, angleuphill, mobj->radius);
+			testy += P_ReturnThrustY(mobj, angleuphill, mobj->radius);
 		}
-
-		testx += x;
-		testy += y;
 
 		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
 		if (R_PointInSubsector(testx, testy)->sector == (boundsec ? boundsec : sector))
@@ -893,7 +821,7 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed
 				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
 					continue;
 
-				if (P_BoxOnLineSide(bbox, ld) != -1)
+				if (P_CircleOnLineSide(x, y, mobj->radius, ld) != -1)
 					continue;
 
 				if (lowest)
@@ -1525,6 +1453,26 @@ void P_XYMovement(mobj_t *mo)
 		}
 	}
 
+	//{ SRB2kart - Ballhogs
+	if (mo->type == MT_BALLHOG)
+	{
+		if (mo->health)
+		{
+			mo->health--;
+			if (mo->health == 0)
+				mo->destscale = 1;
+		}
+		else
+		{
+			if (mo->scale < mapobjectscale/16)
+			{
+				P_RemoveMobj(mo);
+				return;
+			}
+		}
+	}
+	//}
+
 	player = mo->player; //valid only if player avatar
 
 	xmove = mo->momx;
@@ -1559,25 +1507,6 @@ void P_XYMovement(mobj_t *mo)
 	if (CheckForBustableBlocks && mo->flags & MF_PUSHABLE)
 		P_PushableCheckBustables(mo);
 
-	//{ SRB2kart - Ballhogs
-	if (mo->type == MT_BALLHOG)
-	{
-		if (mo->health)
-		{
-			mo->health--;
-			if (mo->health == 0)
-				mo->destscale = 1;
-		}
-		else
-		{
-			if (mo->scale < mapobjectscale/16)
-			{
-				P_RemoveMobj(mo);
-				return;
-			}
-		}
-	}
-	//}
 	if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !(mo->eflags & MFE_SPRUNG))
 	{
 		// blocked move
@@ -1956,12 +1885,20 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 			&& !(rover->flags & FF_REVERSEPLATFORM)
 			&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
 		{
+			if (mo->player) 
+			{
+				CONS_Printf(""); // debugger conditional
+			}
 			mo->floorz = topheight;
 		}
 		if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
 			&& !(rover->flags & FF_PLATFORM)
 			&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
 		{
+			if (mo->player) 
+			{
+				CONS_Printf(""); // debugger conditional
+			}
 			mo->ceilingz = bottomheight;
 		}
 	}
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index fa98ad9a547dfed428020eeaba0e9da65af6ba23..fed8d46eca329205b74447636edff84dfd2b5689 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -177,17 +177,11 @@ boolean P_PointInsidePolyobj(polyobj_t *po, fixed_t x, fixed_t y)
 //
 boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo)
 {
-	fixed_t mbbox[4];
 	size_t i;
 
-	mbbox[BOXTOP] = mo->y + mo->radius;
-	mbbox[BOXBOTTOM] = mo->y - mo->radius;
-	mbbox[BOXRIGHT] = mo->x + mo->radius;
-	mbbox[BOXLEFT] = mo->x - mo->radius;
-
 	for (i = 0; i < po->numLines; i++)
 	{
-		if (P_BoxOnLineSide(mbbox, po->lines[i]) == -1)
+		if (P_CircleOnLineSide(mo->x, mo->y, mo->radius, po->lines[i]) == -1)
 			return true;
 	}
 
@@ -201,17 +195,11 @@ boolean P_MobjTouchingPolyobj(polyobj_t *po, mobj_t *mo)
 //
 boolean P_MobjInsidePolyobj(polyobj_t *po, mobj_t *mo)
 {
-	fixed_t mbbox[4];
 	size_t i;
 
-	mbbox[BOXTOP] = mo->y + mo->radius;
-	mbbox[BOXBOTTOM] = mo->y - mo->radius;
-	mbbox[BOXRIGHT] = mo->x + mo->radius;
-	mbbox[BOXLEFT] = mo->x - mo->radius;
-
 	for (i = 0; i < po->numLines; i++)
 	{
-		if (P_BoxOnLineSide(mbbox, po->lines[i]) == 0)
+		if (P_CircleOnLineSide(mo->x, mo->y, mo->radius, po->lines[i]) == 0)
 			return false;
 	}