diff --git a/src/deh_tables.c b/src/deh_tables.c
index cfc98f631e9d475f403e104425eae189949157bf..9db18be9bd1bc203b245e1c4209a48e66a69e0b5 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -3496,6 +3496,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
 // because sadly no one remembers this place while searching for full state names.
 const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for sanity testing later.
 	"MT_NULL",
+	"MT_RAY",
 	"MT_UNKNOWN",
 
 	"MT_THOK", // Thok! mobj
diff --git a/src/info.c b/src/info.c
index 57899f4f1759f2955f7adcb50f5673660a21f5e4..eaea5110a39936b829fe1a2dcff9d6be99f7ebed 100644
--- a/src/info.c
+++ b/src/info.c
@@ -3964,6 +3964,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		S_NULL          // raisestate
 	},
 
+	{           // MT_RAY
+		-1,             // doomednum
+		S_NULL,         // spawnstate
+		0,              // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		0,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		0,              // speed
+		0,              // radius
+		0,              // height
+		0,              // display offset
+		0,              // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_UNKNOWN
 		-1,             // doomednum
 		S_UNKNOWN,      // spawnstate
diff --git a/src/info.h b/src/info.h
index 031a08b4316a00d135cf45a45827ff117181373e..9ceeead2c6f3ce01de87f2fcff6a16fc78402682 100644
--- a/src/info.h
+++ b/src/info.h
@@ -4316,6 +4316,7 @@ extern playersprite_t free_spr2;
 typedef enum mobj_type
 {
 	MT_NULL,
+	MT_RAY, // General purpose mobj
 	MT_UNKNOWN,
 
 	MT_THOK, // Thok! mobj
diff --git a/src/p_local.h b/src/p_local.h
index 28a77afe5c9a5022a5e5f92641df34806f32b91d..4fa244a056bbe9070d208133c159a372f6dfd086 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -410,6 +410,7 @@ void P_SetUnderlayPosition(mobj_t *thing);
 
 boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y);
 boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
+boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
 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);
diff --git a/src/p_map.c b/src/p_map.c
index 329224d0bd353c8a345f5483ffd5142695b9f0e3..bd504ca17019596b1a20a162ad0ff4e9114e8362 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -2654,17 +2654,17 @@ boolean PIT_PushableMoved(mobj_t *thing)
 	return true;
 }
 
-//
-// P_TryMove
-// Attempt to move to a new position.
-//
-boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
+static boolean
+increment_move
+(		mobj_t * thing,
+		fixed_t x,
+		fixed_t y,
+		boolean allowdropoff)
 {
 	fixed_t tryx = thing->x;
 	fixed_t tryy = thing->y;
 	fixed_t radius = thing->radius;
 	fixed_t thingtop;
-	fixed_t startingonground = P_IsObjectOnGround(thing);
 	floatok = false;
 
 	if (radius < MAXRADIUS/2)
@@ -2802,7 +2802,38 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 		}
 	} while (tryx != x || tryy != y);
 
+	return true;
+}
+
+//
+// P_CheckMove
+// Check if a P_TryMove would be successful.
+//
+boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
+{
+	boolean moveok;
+	mobj_t *hack = P_SpawnMobjFromMobj(thing, 0, 0, 0, MT_RAY);
+
+	hack->radius = thing->radius;
+	hack->height = thing->height;
+
+	moveok = increment_move(hack, x, y, allowdropoff);
+	P_RemoveMobj(hack);
+
+	return moveok;
+}
+
+//
+// P_TryMove
+// Attempt to move to a new position.
+//
+boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
+{
+	fixed_t startingonground = P_IsObjectOnGround(thing);
+
 	// The move is ok!
+	if (!increment_move(thing, x, y, allowdropoff))
+		return false;
 
 	// If it's a pushable object, check if anything is
 	// standing on top and move it, too.