diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index cad5a4ddc6a8f8e26af6e016e385c03e90b10b53..4d48521cab4a26de0c75e8a75366b44fe242226c 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -1821,6 +1821,33 @@ static int lib_evCrumbleChain(lua_State *L)
 	return 0;
 }
 
+static int lib_evStartCrumble(lua_State *L)
+{
+	sector_t *sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
+	ffloor_t *rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
+	boolean floating = lua_optboolean(L, 3);
+	player_t *player = NULL;
+	fixed_t origalpha;
+	boolean crumblereturn = lua_optboolean(L, 6);
+	NOHUD
+	if (!sec)
+		return LUA_ErrInvalid(L, "sector_t");
+	if (!rover)
+		return LUA_ErrInvalid(L, "ffloor_t");
+	if (!lua_isnone(L, 4) && lua_isuserdata(L, 4))
+	{
+		player = *((player_t **)luaL_checkudata(L, 4, META_PLAYER));
+		if (!player)
+			return LUA_ErrInvalid(L, "player_t");
+	}
+	if (!lua_isnone(L,5))
+		origalpha = luaL_checkfixed(L, 5);
+	else
+		origalpha = rover->alpha;
+	lua_pushboolean(L, EV_StartCrumble(sec, rover, floating, player, origalpha, crumblereturn) != 0);
+	return 0;
+}
+
 // R_DEFS
 ////////////
 
@@ -2406,6 +2433,7 @@ static luaL_Reg lib[] = {
 	{"P_SetSkyboxMobj",lib_pSetSkyboxMobj},
 	{"P_StartQuake",lib_pStartQuake},
 	{"EV_CrumbleChain",lib_evCrumbleChain},
+	{"EV_StartCrumble",lib_evStartCrumble},
 
 	// r_defs
 	{"R_PointToAngle",lib_rPointToAngle},
diff --git a/src/p_spec.c b/src/p_spec.c
index b4380bb4bd9f68e2c8a97b2f721d607cd36b2063..ddcdfbd539666da21081a07f368147a82db118cb 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3111,6 +3111,51 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 			}
 			break;
 
+		case 446: // Make block fall remotely (acts like FF_CRUMBLE)
+			{
+				INT16 sectag = (INT16)(sides[line->sidenum[0]].textureoffset>>FRACBITS);
+				INT16 foftag = (INT16)(sides[line->sidenum[0]].rowoffset>>FRACBITS);
+				sector_t *sec; // Sector that the FOF is visible in
+				ffloor_t *rover; // FOF that we are going to make fall down
+				player_t *player = NULL; // player that caused FOF to fall
+				boolean respawn = true; // should the fallen FOF respawn?
+
+				if (mo) // NULL check
+					player = mo->player;
+
+				if (line->flags & ML_NOCLIMB) // don't respawn!
+					respawn = false;
+
+				for (secnum = -1; (secnum = P_FindSectorFromTag(sectag, secnum)) >= 0 ;)
+				{
+					sec = sectors + secnum;
+
+					if (!sec->ffloors)
+					{
+						CONS_Debug(DBG_GAMELOGIC, "Line type 446 Executor: Target sector #%d has no FOFs.\n", secnum);
+						return;
+					}
+
+					for (rover = sec->ffloors; rover; rover = rover->next)
+					{
+						if (rover->master->frontsector->tag == foftag)
+							break;
+					}
+
+					if (!rover)
+					{
+						CONS_Debug(DBG_GAMELOGIC, "Line type 446 Executor: Can't find a FOF control sector with tag %d\n", foftag);
+						return;
+					}
+
+					if (line->flags & ML_BLOCKMONSTERS) // FOF flags determine respawn ability instead?
+						respawn = !(rover->flags & FF_NORETURN) ^ !!(line->flags & ML_NOCLIMB); // no climb inverts
+
+					EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, respawn);
+				}
+			}
+			break;
+
 		case 450: // Execute Linedef Executor - for recursion
 			P_LinedefExecute(line->tag, mo, NULL);
 			break;