diff --git a/src/p_map.c b/src/p_map.c
index 93c8852413b1f4652e18f79e66970db2eb185633..10f048e77d749e11114e52254a0e071f80a3ddf3 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -58,6 +58,8 @@ mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz
 mobj_t *tmhitthing; // the solid thing you bumped into (for collisions)
 ffloor_t *tmfloorrover, *tmceilingrover;
 pslope_t *tmfloorslope, *tmceilingslope;
+static fixed_t tmfloorstep;
+static fixed_t tmceilingstep;
 
 // keep track of the line that lowers the ceiling,
 // so missiles don't explode against sky hack walls
@@ -1618,6 +1620,8 @@ static boolean PIT_CheckCameraLine(line_t *ld)
 //
 static boolean PIT_CheckLine(line_t *ld)
 {
+	const fixed_t thingtop = tmthing->z + tmthing->height;
+
 	if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID))
 		return true;
 
@@ -1704,6 +1708,11 @@ static boolean PIT_CheckLine(line_t *ld)
 		ceilingline = ld;
 		tmceilingrover = openceilingrover;
 		tmceilingslope = opentopslope;
+		tmceilingstep = openceilingstep;
+		if (thingtop == tmthing->ceilingz)
+		{
+			tmthing->ceilingdrop = openceilingdrop;
+		}
 	}
 
 	if (openbottom > tmfloorz)
@@ -1711,6 +1720,11 @@ static boolean PIT_CheckLine(line_t *ld)
 		tmfloorz = openbottom;
 		tmfloorrover = openfloorrover;
 		tmfloorslope = openbottomslope;
+		tmfloorstep = openfloorstep;
+		if (tmthing->z == tmthing->floorz)
+		{
+			tmthing->floordrop = openfloordrop;
+		}
 	}
 
 	if (highceiling > tmdrpoffceilz)
@@ -1765,6 +1779,7 @@ static boolean PIT_CheckLine(line_t *ld)
 //
 boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 {
+	INT32 thingtop = thing->z + thing->height;
 	INT32 xl, xh, yl, yh, bx, by;
 	subsector_t *newsubsec;
 	boolean blockval = true;
@@ -1800,12 +1815,24 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 	tmfloorslope = newsubsec->sector->f_slope;
 	tmceilingslope = newsubsec->sector->c_slope;
 
+	tmfloorstep = 0;
+	tmceilingstep = 0;
+
+	if (thingtop < thing->ceilingz)
+	{
+		thing->ceilingdrop = 0;
+	}
+
+	if (thing->z > thing->floorz)
+	{
+		thing->floordrop = 0;
+	}
+
 	// Check list of fake floors and see if tmfloorz/tmceilingz need to be altered.
 	if (newsubsec->sector->ffloors)
 	{
 		ffloor_t *rover;
 		fixed_t delta1, delta2;
-		INT32 thingtop = thing->z + thing->height;
 
 		for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
 		{
@@ -1937,7 +1964,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 					if (po->validcount != validcount) // if polyobj hasn't been checked
 					{
 						sector_t *polysec;
-						fixed_t delta1, delta2, thingtop;
+						fixed_t delta1, delta2;
 						fixed_t polytop, polybottom;
 
 						po->validcount = validcount;
@@ -1963,7 +1990,6 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 							polybottom = INT32_MIN;
 						}
 
-						thingtop = thing->z + thing->height;
 						delta1 = thing->z - (polybottom + ((polytop - polybottom)/2));
 						delta2 = thingtop - (polybottom + ((polytop - polybottom)/2));
 
@@ -2511,26 +2537,28 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 
 				if (thing->eflags & MFE_VERTICALFLIP)
 				{
-					if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep)
+					if (thingtop == thing->ceilingz && tmceilingz > thingtop && thing->ceilingdrop <= maxstep)
 					{
 						thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height;
 						thing->ceilingrover = tmceilingrover;
 						thing->eflags |= MFE_JUSTSTEPPEDDOWN;
+						thing->ceilingdrop = 0;
 					}
-					else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep)
+					else if (tmceilingz < thingtop && tmceilingstep <= maxstep)
 					{
 						thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height;
 						thing->ceilingrover = tmceilingrover;
 						thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 					}
 				}
-				else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep)
+				else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->floordrop <= maxstep)
 				{
 					thing->z = thing->floorz = tmfloorz;
 					thing->floorrover = tmfloorrover;
 					thing->eflags |= MFE_JUSTSTEPPEDDOWN;
+					thing->floordrop = 0;
 				}
-				else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep)
+				else if (tmfloorz > thing->z && tmfloorstep <= maxstep)
 				{
 					thing->z = thing->floorz = tmfloorz;
 					thing->floorrover = tmfloorrover;
diff --git a/src/p_maputl.c b/src/p_maputl.c
index de6feb143bacbd8b8e95eb2f1540173ae4e64eff..ee1fb5a42112fb5c3b49e69a045e324dc12929ae 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -279,6 +279,10 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1)
 fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
 pslope_t *opentopslope, *openbottomslope;
 ffloor_t *openfloorrover, *openceilingrover;
+fixed_t openceilingstep;
+fixed_t openceilingdrop;
+fixed_t openfloorstep;
+fixed_t openfloordrop;
 
 // P_CameraLineOpening
 // P_LineOpening, but for camera
@@ -423,7 +427,18 @@ void P_CameraLineOpening(line_t *linedef)
 
 void P_LineOpening(line_t *linedef, mobj_t *mobj)
 {
+	enum { FRONT, BACK };
+
 	sector_t *front, *back;
+	fixed_t thingtop = 0;
+	vertex_t cross;
+
+	/* these init to shut compiler up */
+	fixed_t topedge[2] = {0};
+	fixed_t botedge[2] = {0};
+
+	int hi = 0;
+	int lo = 0;
 
 	if (linedef->sidenum[1] == 0xffff)
 	{
@@ -432,6 +447,8 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 		return;
 	}
 
+	P_ClosestPointOnLine(tmx, tmy, linedef, &cross);
+
 	// Treat polyobjects kind of like 3D Floors
 	if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT))
 	{
@@ -447,6 +464,11 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 	I_Assert(front != NULL);
 	I_Assert(back != NULL);
 
+	if (mobj)
+	{
+		thingtop = mobj->z + mobj->height;
+	}
+
 	openfloorrover = openceilingrover = NULL;
 	if (linedef->polyobj)
 	{
@@ -456,48 +478,57 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 		highceiling = INT32_MIN;
 		lowfloor = INT32_MAX;
 		opentopslope = openbottomslope = NULL;
+		openceilingstep = 0;
+		openceilingdrop = 0;
+		openfloorstep = 0;
+		openfloordrop = 0;
 	}
 	else
 	{ // Set open and high/low values here
-		fixed_t frontheight, backheight;
+		fixed_t          height[2];
+		const sector_t * sector[2] = { front, back };
 
-		frontheight = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
-		backheight = P_GetCeilingZ(mobj, back, tmx, tmy, linedef);
+		height[FRONT] = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
+		height[BACK]  = P_GetCeilingZ(mobj, back,  tmx, tmy, linedef);
 
-		if (frontheight < backheight)
-		{
-			opentop = frontheight;
-			highceiling = backheight;
-			opentopslope = front->c_slope;
-		}
-		else
-		{
-			opentop = backheight;
-			highceiling = frontheight;
-			opentopslope = back->c_slope;
-		}
+		hi = ( height[0] < height[1] );
+		lo = ! hi;
 
-		frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
-		backheight = P_GetFloorZ(mobj, back, tmx, tmy, linedef);
+		opentop      = height[lo];
+		highceiling  = height[hi];
+		opentopslope = sector[lo]->c_slope;
 
-		if (frontheight > backheight)
+		if (mobj)
 		{
-			openbottom = frontheight;
-			lowfloor = backheight;
-			openbottomslope = front->f_slope;
+			topedge[FRONT] = P_GetSectorCeilingZAt(front, cross.x, cross.y);
+			topedge[BACK]  = P_GetSectorCeilingZAt(back,  cross.x, cross.y);
+
+			openceilingstep = ( thingtop    - topedge[lo] );
+			openceilingdrop = ( topedge[hi] - topedge[lo] );
 		}
-		else
+
+		height[FRONT] = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
+		height[BACK]  = P_GetFloorZ(mobj, back,  tmx, tmy, linedef);
+
+		hi = ( height[0] < height[1] );
+		lo = ! hi;
+
+		openbottom      = height[hi];
+		lowfloor        = height[lo];
+		openbottomslope = sector[hi]->f_slope;
+
+		if (mobj)
 		{
-			openbottom = backheight;
-			lowfloor = frontheight;
-			openbottomslope = back->f_slope;
+			botedge[FRONT] = P_GetSectorFloorZAt(front, cross.x, cross.y);
+			botedge[BACK]  = P_GetSectorFloorZAt(back,  cross.x, cross.y);
+
+			openfloorstep = ( botedge[hi] - mobj->z );
+			openfloordrop = ( botedge[hi] - botedge[lo] );
 		}
 	}
 
 	if (mobj)
 	{
-		fixed_t thingtop = mobj->z + mobj->height;
-
 		// Check for collision with front side's midtexture if Effect 4 is set
 		if (linedef->flags & ML_EFFECT4
 			&& !linedef->polyobj // don't do anything for polyobjects! ...for now
@@ -548,10 +579,22 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 
 				if (delta1 > delta2) { // Below
 					if (opentop > texbottom)
+					{
+						topedge[lo] -= ( opentop - texbottom );
+
 						opentop = texbottom;
+						openceilingstep = ( thingtop    - topedge[lo] );
+						openceilingdrop = ( topedge[hi] - topedge[lo] );
+					}
 				} else { // Above
 					if (openbottom < textop)
+					{
+						botedge[hi] += ( textop - openbottom );
+
 						openbottom = textop;
+						openfloorstep = ( botedge[hi] - mobj->z );
+						openfloordrop = ( botedge[hi] - botedge[lo] );
+					}
 				}
 			}
 		}
@@ -579,14 +622,22 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				delta2 = abs(thingtop - (polybottom + ((polytop - polybottom)/2)));
 
 				if (polybottom < opentop && delta1 >= delta2)
+				{
 					opentop = polybottom;
+				}
 				else if (polybottom < highceiling && delta1 >= delta2)
+				{
 					highceiling = polybottom;
+				}
 
 				if (polytop > openbottom && delta1 < delta2)
+				{
 					openbottom = polytop;
+				}
 				else if (polytop > lowfloor && delta1 < delta2)
+				{
 					lowfloor = polytop;
+				}
 			}
 			// otherwise don't do anything special, pretend there's nothing else there
 		}
@@ -598,6 +649,21 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 				ffloor_t *rover;
 				fixed_t delta1, delta2;
 
+				/* yuck */
+				struct
+				{
+					fixed_t top;
+					fixed_t bottom;
+					ffloor_t * ceilingrover;
+					ffloor_t *   floorrover;
+				} open[2] = {
+					{ INT32_MAX, INT32_MIN, NULL, NULL },
+					{ INT32_MAX, INT32_MIN, NULL, NULL },
+				};
+
+				const fixed_t oldopentop = opentop;
+				const fixed_t oldopenbottom = openbottom;
+
 				// Check for frontsector's fake floors
 				for (rover = front->ffloors; rover; rover = rover->next)
 				{
@@ -619,10 +685,10 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 
 					if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF
 					{
-						if (bottomheight < opentop) {
-							opentop = bottomheight;
+						if (bottomheight < open[FRONT].top) {
+							open[FRONT].top = bottomheight;
 							opentopslope = *rover->b_slope;
-							openceilingrover = rover;
+							open[FRONT].ceilingrover = rover;
 						}
 						else if (bottomheight < highceiling)
 							highceiling = bottomheight;
@@ -630,10 +696,10 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 
 					if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF
 					{
-						if (topheight > openbottom) {
-							openbottom = topheight;
+						if (topheight > open[FRONT].bottom) {
+							open[FRONT].bottom = topheight;
 							openbottomslope = *rover->t_slope;
-							openfloorrover = rover;
+							open[FRONT].floorrover = rover;
 						}
 						else if (topheight > lowfloor)
 							lowfloor = topheight;
@@ -661,10 +727,10 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 
 					if (delta1 >= delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_PLATFORM) // thing is below FOF
 					{
-						if (bottomheight < opentop) {
-							opentop = bottomheight;
+						if (bottomheight < open[BACK].top) {
+							open[BACK].top = bottomheight;
 							opentopslope = *rover->b_slope;
-							openceilingrover = rover;
+							open[BACK].ceilingrover = rover;
 						}
 						else if (bottomheight < highceiling)
 							highceiling = bottomheight;
@@ -672,15 +738,53 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
 
 					if (delta1 < delta2 && (rover->flags & FF_INTANGIBLEFLATS) != FF_REVERSEPLATFORM) // thing is above FOF
 					{
-						if (topheight > openbottom) {
-							openbottom = topheight;
+						if (topheight > open[BACK].bottom) {
+							open[BACK].bottom = topheight;
 							openbottomslope = *rover->t_slope;
-							openfloorrover = rover;
+							open[BACK].floorrover = rover;
 						}
 						else if (topheight > lowfloor)
 							lowfloor = topheight;
 					}
 				}
+
+				lo = ( open[0].top > open[1].top );
+
+				if (open[lo].top <= oldopentop)
+				{
+					hi = ! lo;
+
+					topedge[lo] = P_GetFFloorBottomZAt(open[lo].ceilingrover, cross.x, cross.y);
+
+					if (open[hi].top < oldopentop)
+					{
+						topedge[hi] = P_GetFFloorBottomZAt(open[hi].ceilingrover, cross.x, cross.y);
+					}
+
+					opentop = open[lo].top;
+					openceilingrover = open[lo].ceilingrover;
+					openceilingstep = ( thingtop    - topedge[lo] );
+					openceilingdrop = ( topedge[hi] - topedge[lo] );
+				}
+
+				hi = ( open[0].bottom < open[1].bottom );
+
+				if (open[hi].bottom >= oldopenbottom)
+				{
+					lo = ! hi;
+
+					botedge[hi] = P_GetFFloorTopZAt(open[hi].floorrover, cross.x, cross.y);
+
+					if (open[lo].bottom > oldopenbottom)
+					{
+						botedge[lo] = P_GetFFloorTopZAt(open[lo].floorrover, cross.x, cross.y);
+					}
+
+					openbottom = open[hi].bottom;
+					openfloorrover = open[hi].floorrover;
+					openfloorstep = ( botedge[hi] - mobj->z );
+					openfloordrop = ( botedge[hi] - botedge[lo] );
+				}
 			}
 		}
 	}
diff --git a/src/p_maputl.h b/src/p_maputl.h
index 1c071c2cdc77d2fdae9a613b905a6eba3f15aa5e..9349d0e53c95c75a344432d093cfe19251c09db2 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -58,6 +58,10 @@ void P_HitSpecialLines(mobj_t *thing, fixed_t x, fixed_t y, fixed_t momx, fixed_
 extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
 extern pslope_t *opentopslope, *openbottomslope;
 extern ffloor_t *openfloorrover, *openceilingrover;
+extern fixed_t openceilingstep;
+extern fixed_t openceilingdrop;
+extern fixed_t openfloorstep;
+extern fixed_t openfloordrop;
 
 void P_LineOpening(line_t *plinedef, mobj_t *mobj);
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index eaf97c44152dcb40e4ebef5c03f84879ba9546a4..cd0cc3bc74f4ecd2c18207287071eb55ded4625b 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -326,6 +326,8 @@ typedef struct mobj_s
 	fixed_t ceilingz; // Nearest ceiling above.
 	struct ffloor_s *floorrover; // FOF referred by floorz
 	struct ffloor_s *ceilingrover; // FOF referred by ceilingz
+	fixed_t floordrop;
+	fixed_t ceilingdrop;
 
 	// For movement checking.
 	fixed_t radius;