diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 2a82ec5129c11410d008090ae41f29e0a5e69a87..7f1d2bbea01a6fc1ea31aa0cca72f95119d3c80d 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -681,6 +681,17 @@ static int lib_pSpawnPlayerMissile(lua_State *L)
 	return 1;
 }
 
+static int lib_pRailThinker(lua_State *L)
+{
+	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	NOHUD
+	INLEVEL
+	if (!mobj)
+		return LUA_ErrInvalid(L, "mobj_t");
+	lua_pushboolean(L, P_RailThinker(mobj));
+	return 1;
+}
+
 static int lib_pMobjFlip(lua_State *L)
 {
 	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@@ -1406,6 +1417,19 @@ static int lib_pTeleportMove(lua_State *L)
 	return 2;
 }
 
+static int lib_pCheckMoveBlocked(lua_State *L)
+{
+	line_t *li = luaL_checkudata(L, 1, META_LINE);
+	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
+	INLEVEL
+	if (!li)
+		return LUA_ErrInvalid(L, "line_t");
+	if (!mo)
+		return LUA_ErrInvalid(L, "mobj_t");
+	lua_pushboolean(L, P_CheckMoveBlocked(li, mo));
+	return 1;
+}
+
 static int lib_pSlideMove(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@@ -3003,6 +3027,7 @@ static luaL_Reg lib[] = {
 	{"P_ColorTeamMissile",lib_pColorTeamMissile},
 	{"P_SPMAngle",lib_pSPMAngle},
 	{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
+	{"P_RailThinker",lib_pRailThinker},
 	{"P_MobjFlip",lib_pMobjFlip},
 	{"P_GetMobjGravity",lib_pGetMobjGravity},
 	{"P_WeaponOrPanel",lib_pWeaponOrPanel},
@@ -3065,6 +3090,7 @@ static luaL_Reg lib[] = {
 	{"P_TryMove",lib_pTryMove},
 	{"P_Move",lib_pMove},
 	{"P_TeleportMove",lib_pTeleportMove},
+	{"P_CheckMoveBlocked",lib_pCheckMoveBlocked},
 	{"P_SlideMove",lib_pSlideMove},
 	{"P_BounceMove",lib_pBounceMove},
 	{"P_CheckSight", lib_pCheckSight},
diff --git a/src/p_local.h b/src/p_local.h
index a5f3d313ce25c71fc50a3695ea8eafd7a01831f8..a825c340063987f62e45dd587164c4aae6d55d99 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -405,6 +405,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
 boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
 boolean P_Move(mobj_t *actor, fixed_t speed);
 boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
+boolean P_CheckMoveBlocked(line_t *li, mobj_t *mo);
 void P_SlideMove(mobj_t *mo);
 void P_BounceMove(mobj_t *mo);
 boolean P_CheckSight(mobj_t *t1, mobj_t *t2);
diff --git a/src/p_map.c b/src/p_map.c
index 40fee7b46f8ccc7cfe27fc6a8639d3887efbd4c3..d1d175f8a39e3d7687846f0fce69342ffc8a14e3 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -3386,173 +3386,207 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 }
 
 //
-// PTR_SlideTraverse
+//P_CheckMoveBlocked
 //
-static boolean PTR_SlideTraverse(intercept_t *in)
+boolean P_CheckMoveBlocked(line_t *li, mobj_t *mo)
 {
-	line_t *li;
-
-	I_Assert(in->isaline);
-
-	li = in->d.line;
-
 	// one-sided linedefs are always solid to sliding movement.
 	// one-sided linedef
 	if (!li->backsector)
 	{
-		if (P_PointOnLineSide(slidemo->x, slidemo->y, li))
+		if (P_PointOnLineSide(mo->x, mo->y, li))
 			return true; // don't hit the back side
-		goto isblocking;
+		return false;
 	}
 
-	if (!(slidemo->flags & MF_MISSILE))
+	if (!(mo->flags & MF_MISSILE))
 	{
 		if (li->flags & ML_IMPASSIBLE)
-			goto isblocking;
+			return false;
 
-		if ((slidemo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS)
-			goto isblocking;
+		if ((mo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS)
+			return false;
 	}
 
 	// set openrange, opentop, openbottom
-	P_LineOpening(li, slidemo);
+	P_LineOpening(li, mo);
 
-	if (openrange < slidemo->height)
-		goto isblocking; // doesn't fit
+	if (openrange < mo->height)
+		return false; // doesn't fit
 
-	if (opentop - slidemo->z < slidemo->height)
-		goto isblocking; // mobj is too high
+	if (opentop - mo->z < mo->height)
+		return false; // mobj is too high
 
-	if (openbottom - slidemo->z > FixedMul(MAXSTEPMOVE, slidemo->scale))
-		goto isblocking; // too big a step up
+	if (openbottom - mo->z > FixedMul(MAXSTEPMOVE, mo->scale))
+		return false; // too big a step up
 
 	// this line doesn't block movement
 	return true;
+}
 
-	// the line does block movement,
-	// see if it is closer than best so far
-isblocking:
-	if (li->polyobj && slidemo->player)
+	if (!(mo->flags & MF_MISSILE))
 	{
-		if ((li->polyobj->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS))
-			P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector);
+		if (li->flags & ML_IMPASSIBLE)
+			return false;
+
+		if ((mo->flags & (MF_ENEMY|MF_BOSS)) && li->flags & ML_BLOCKMONSTERS)
+			return false;
 	}
 
-	if (slidemo->player && (slidemo->player->pflags & PF_GLIDING || slidemo->player->climbing)
-		&& slidemo->player->charability == CA_GLIDEANDCLIMB)
-	{
-		line_t *checkline = li;
-		sector_t *checksector;
-		ffloor_t *rover;
-		fixed_t topheight, bottomheight;
-		boolean fofline = false;
-		INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li);
+	// set openrange, opentop, openbottom
+	P_LineOpening(li, mo);
 
-		if (!side && li->backsector)
-			checksector = li->backsector;
-		else
-			checksector = li->frontsector;
+	if (openrange < mo->height)
+		return false; // doesn't fit
 
-		if (checksector->ffloors)
-		{
-			for (rover = checksector->ffloors; rover; rover = rover->next)
-			{
-				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-					continue;
+	if (opentop - mo->z < mo->height)
+		return false; // mobj is too high
 
-				topheight = *rover->topheight;
-				bottomheight = *rover->bottomheight;
+	if (openbottom - mo->z > FixedMul(MAXSTEPMOVE, mo->scale))
+		return false; // too big a step up
 
-#ifdef ESLOPE
-				if (*rover->t_slope)
-					topheight = P_GetZAt(*rover->t_slope, slidemo->x, slidemo->y);
-				if (*rover->b_slope)
-					bottomheight = P_GetZAt(*rover->b_slope, slidemo->x, slidemo->y);
-#endif
+	// this line doesn't block movement
+	return true;
+}
 
-				if (topheight < slidemo->z)
-					continue;
+//
+// PTR_SlideTraverse
+//
+static boolean PTR_SlideTraverse(intercept_t *in)
+{
+	line_t *li;
 
-				if (bottomheight > slidemo->z + slidemo->height)
-					continue;
+	I_Assert(in->isaline);
 
-				// Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this?
-				if (rover->master->flags & ML_TFERLINE)
-				{
-					size_t linenum = li-checksector->lines[0];
-					checkline = rover->master->frontsector->lines[0] + linenum;
-					fofline = true;
-				}
+	li = in->d.line;
 
-				break;
-			}
+	if (!P_CheckMoveBlocked(li, slidemo))
+	{
+		// the line does block movement,
+		// see if it is closer than best so far
+		if (li->polyobj && slidemo->player)
+		{
+			if ((li->polyobj->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS))
+				P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector);
 		}
 
-		// see about climbing on the wall
-		if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL)
+		if (slidemo->player && (slidemo->player->pflags & PF_GLIDING || slidemo->player->climbing)
+			&& slidemo->player->charability == CA_GLIDEANDCLIMB)
 		{
-			boolean canclimb;
-			angle_t climbangle, climbline;
-			INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
+			line_t *checkline = li;
+			sector_t *checksector;
+			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
+			boolean fofline = false;
+			INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li);
+
+			if (!side && li->backsector)
+				checksector = li->backsector;
+			else
+				checksector = li->frontsector;
 
-			climbangle = climbline = R_PointToAngle2(li->v1->x, li->v1->y, li->v2->x, li->v2->y);
+			if (checksector->ffloors)
+			{
+				for (rover = checksector->ffloors; rover; rover = rover->next)
+				{
+					if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+						continue;
 
-			if (whichside) // on second side?
-				climbline += ANGLE_180;
+					topheight = *rover->topheight;
+					bottomheight = *rover->bottomheight;
 
-			climbangle += (ANGLE_90 * (whichside ? -1 : 1));
+	#ifdef ESLOPE
+					if (*rover->t_slope)
+						topheight = P_GetZAt(*rover->t_slope, slidemo->x, slidemo->y);
+					if (*rover->b_slope)
+						bottomheight = P_GetZAt(*rover->b_slope, slidemo->x, slidemo->y);
+	#endif
 
-			canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
+					if (topheight < slidemo->z)
+						continue;
 
-			if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
-			|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
-			&& canclimb)
-			{
-				slidemo->angle = climbangle;
-				/*if (!demoplayback || P_ControlStyle(slidemo->player) == CS_LMAOGALOG)
-				{
-					if (slidemo->player == &players[consoleplayer])
-						localangle = slidemo->angle;
-					else if (slidemo->player == &players[secondarydisplayplayer])
-						localangle2 = slidemo->angle;
-				}*/
+					if (bottomheight > slidemo->z + slidemo->height)
+						continue;
 
-				if (!slidemo->player->climbing)
-				{
-					S_StartSound(slidemo->player->mo, sfx_s3k4a);
-					slidemo->player->climbing = 5;
+					// Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this?
+					if (rover->master->flags & ML_TFERLINE)
+					{
+						size_t linenum = li-checksector->lines[0];
+						checkline = rover->master->frontsector->lines[0] + linenum;
+						fofline = true;
+					}
+
+					break;
 				}
+			}
+
+			// see about climbing on the wall
+			if (!(checkline->flags & ML_NOCLIMB) && checkline->special != HORIZONSPECIAL)
+			{
+				boolean canclimb;
+				angle_t climbangle, climbline;
+				INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
 
-				slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED);
-				slidemo->player->glidetime = 0;
-				slidemo->player->secondjump = 0;
+				climbangle = climbline = R_PointToAngle2(li->v1->x, li->v1->y, li->v2->x, li->v2->y);
 
-				if (slidemo->player->climbing > 1)
-					slidemo->momz = slidemo->momx = slidemo->momy = 0;
+				if (whichside) // on second side?
+					climbline += ANGLE_180;
 
-				if (fofline)
-					whichside = 0;
+				climbangle += (ANGLE_90 * (whichside ? -1 : 1));
 
-				if (!whichside)
+				canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
+
+				if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
+				|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
+				&& canclimb)
 				{
-					slidemo->player->lastsidehit = checkline->sidenum[whichside];
-					slidemo->player->lastlinehit = (INT16)(checkline - lines);
-				}
+					slidemo->angle = climbangle;
+					/*if (!demoplayback || P_AnalogMove(slidemo->player))
+					{
+						if (slidemo->player == &players[consoleplayer])
+							localangle = slidemo->angle;
+						else if (slidemo->player == &players[secondarydisplayplayer])
+							localangle2 = slidemo->angle;
+					}*/
+
+					if (!slidemo->player->climbing)
+					{
+						S_StartSound(slidemo->player->mo, sfx_s3k4a);
+						slidemo->player->climbing = 5;
+					}
+
+					slidemo->player->pflags &= ~(PF_GLIDING|PF_SPINNING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED);
+					slidemo->player->glidetime = 0;
+					slidemo->player->secondjump = 0;
+
+					if (slidemo->player->climbing > 1)
+						slidemo->momz = slidemo->momx = slidemo->momy = 0;
+
+					if (fofline)
+						whichside = 0;
+
+					if (!whichside)
+					{
+						slidemo->player->lastsidehit = checkline->sidenum[whichside];
+						slidemo->player->lastlinehit = (INT16)(checkline - lines);
+					}
 
-				P_Thrust(slidemo, slidemo->angle, FixedMul(5*FRACUNIT, slidemo->scale));
+					P_Thrust(slidemo, slidemo->angle, FixedMul(5*FRACUNIT, slidemo->scale));
+				}
 			}
 		}
-	}
 
-	if (in->frac < bestslidefrac && (!slidemo->player || !slidemo->player->climbing))
-	{
-		secondslidefrac = bestslidefrac;
-		secondslideline = bestslideline;
-		bestslidefrac = in->frac;
-		bestslideline = li;
-	}
+		if (in->frac < bestslidefrac && (!slidemo->player || !slidemo->player->climbing))
+		{
+			secondslidefrac = bestslidefrac;
+			secondslideline = bestslideline;
+			bestslidefrac = in->frac;
+			bestslideline = li;
+		}
 
-	return false; // stop
+		return false; // stop
+	}
+	return true; // keep going!
 }
 
 //