diff --git a/src/lua_hook.h b/src/lua_hook.h
index d035be097cdd0efb356a36ba91baf42daf5d37b5..6f8805708225536611dd0cb2d929fbbe690e176e 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -25,6 +25,7 @@ enum hook {
 	hook_PostThinkFrame,
 	hook_MobjSpawn,
 	hook_MobjCollide,
+	hook_MobjLineCollide,
 	hook_MobjMoveCollide,
 	hook_TouchSpecial,
 	hook_MobjFuse,
@@ -70,7 +71,9 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which);
 boolean LUAh_PlayerHook(player_t *plr, enum hook which);
 #define LUAh_MobjSpawn(mo) LUAh_MobjHook(mo, hook_MobjSpawn) // Hook for P_SpawnMobj by mobj type
 UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
+UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which);
 #define LUAh_MobjCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjCollide) // Hook for PIT_CheckThing by (thing) mobj type
+#define LUAh_MobjLineCollide(thing, line) LUAh_MobjLineCollideHook(thing, line, hook_MobjLineCollide) // Hook for PIT_CheckThing by (thing) mobj type
 #define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
 boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
 #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index d548f6a65a7cd42570f71dcc039ac7fd16ea16eb..2d9a98c4bf4b7cdda58b410bc541a2876a2571cf 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -36,6 +36,7 @@ const char *const hookNames[hook_MAX+1] = {
 	"PostThinkFrame",
 	"MobjSpawn",
 	"MobjCollide",
+	"MobjLineCollide",
 	"MobjMoveCollide",
 	"TouchSpecial",
 	"MobjFuse",
@@ -125,6 +126,7 @@ static int lib_addHook(lua_State *L)
 	// Take a mobjtype enum which this hook is specifically for.
 	case hook_MobjSpawn:
 	case hook_MobjCollide:
+	case hook_MobjLineCollide:
 	case hook_MobjMoveCollide:
 	case hook_TouchSpecial:
 	case hook_MobjFuse:
@@ -184,6 +186,7 @@ static int lib_addHook(lua_State *L)
 		lastp = &mobjthinkerhooks[hook.s.mt];
 		break;
 	case hook_MobjCollide:
+	case hook_MobjLineCollide:
 	case hook_MobjMoveCollide:
 		lastp = &mobjcollidehooks[hook.s.mt];
 		break;
@@ -562,6 +565,84 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
 	return shouldCollide;
 }
 
+UINT8 LUAh_MobjLineCollideHook(mobj_t *thing, line_t *line, enum hook which)
+{
+	hook_p hookp;
+	UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no.
+	if (!gL || !(hooksAvailable[which/8] & (1<<(which%8))))
+		return 0;
+
+	I_Assert(thing->type < NUMMOBJTYPES);
+
+	lua_settop(gL, 0);
+
+	// Look for all generic mobj collision hooks
+	for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
+	{
+		if (hookp->type != which)
+			continue;
+
+		if (lua_gettop(gL) == 0)
+		{
+			LUA_PushUserdata(gL, thing, META_MOBJ);
+			LUA_PushUserdata(gL, line, META_LINE);
+		}
+		lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+		lua_gettable(gL, LUA_REGISTRYINDEX);
+		lua_pushvalue(gL, -3);
+		lua_pushvalue(gL, -3);
+		if (lua_pcall(gL, 2, 1, 0)) {
+			if (!hookp->error || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			hookp->error = true;
+			continue;
+		}
+		if (!lua_isnil(gL, -1))
+		{ // if nil, leave shouldCollide = 0.
+			if (lua_toboolean(gL, -1))
+				shouldCollide = 1; // Force yes
+			else
+				shouldCollide = 2; // Force no
+		}
+		lua_pop(gL, 1);
+	}
+
+	for (hookp = mobjcollidehooks[thing->type]; hookp; hookp = hookp->next)
+	{
+		if (hookp->type != which)
+			continue;
+
+		if (lua_gettop(gL) == 0)
+		{
+			LUA_PushUserdata(gL, thing, META_MOBJ);
+			LUA_PushUserdata(gL, line, META_LINE);
+		}
+		lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+		lua_gettable(gL, LUA_REGISTRYINDEX);
+		lua_pushvalue(gL, -3);
+		lua_pushvalue(gL, -3);
+		if (lua_pcall(gL, 2, 1, 0)) {
+			if (!hookp->error || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			hookp->error = true;
+			continue;
+		}
+		if (!lua_isnil(gL, -1))
+		{ // if nil, leave shouldCollide = 0.
+			if (lua_toboolean(gL, -1))
+				shouldCollide = 1; // Force yes
+			else
+				shouldCollide = 2; // Force no
+		}
+		lua_pop(gL, 1);
+	}
+
+	lua_settop(gL, 0);
+	return shouldCollide;
+}
+
 // Hook for mobj thinkers
 boolean LUAh_MobjThinker(mobj_t *mo)
 {
diff --git a/src/p_map.c b/src/p_map.c
index 1b6f23cdefad839512185180d57b3f161b7c8b94..628268bffa9d2902d7a5b8c3cac701a52750fff7 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1988,6 +1988,17 @@ static boolean PIT_CheckLine(line_t *ld)
 	if (lowfloor < tmdropoffz)
 		tmdropoffz = lowfloor;
 
+#ifdef HAVE_BLUA
+	{
+		UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, ld); // checks hook for thing's type
+		if (P_MobjWasRemoved(tmthing))
+			return true; // one of them was removed???
+		if (shouldCollide == 1)
+			return false; // force collide
+		else if (shouldCollide == 2)
+			return true; // force no collide
+	}
+#endif
 	return true;
 }