diff --git a/extras/conf/udb/Includes/SRB222_linedefs.cfg b/extras/conf/udb/Includes/SRB222_linedefs.cfg
index a6682cd07c18ceffb827e982c3ca5856594dd9a2..fcf342e3d19eb455d13e431fed5febd2d956932f 100644
--- a/extras/conf/udb/Includes/SRB222_linedefs.cfg
+++ b/extras/conf/udb/Includes/SRB222_linedefs.cfg
@@ -130,6 +130,11 @@ doom
 			title = "Bridge Thinker <disabled>";
 			prefix = "(65)";
 		}
+		76
+		{
+			title = "Make FOF Bouncy";
+			prefix = "(76)";
+		}
 	}
 
 	polyobject
@@ -1669,6 +1674,27 @@ udmf
 				title = "Friction";
 			}
 		}
+
+		76
+		{
+			title = "Make FOF Bouncy";
+			prefix = "(76)";
+			arg0
+			{
+				title = "Control linedef tag";
+				type = 15;
+			}
+			arg1
+			{
+				title = "Bounce strength";
+			}
+			arg2
+			{
+				title = "Dampen?";
+				type = 11;
+				enum = "noyes";
+			}
+		}
 	}
 
 	fof
@@ -2114,6 +2140,7 @@ udmf
 					67108864 = "Intangible from above";
 					134217728 = "Ripple effect";
 					268435456 = "Don't copy light level";
+					536870912 = "Bouncy";
 				}
 			}
 		}
diff --git a/extras/conf/udb/Includes/SRB222_sectors.cfg b/extras/conf/udb/Includes/SRB222_sectors.cfg
index 5cc14ad0fb1a6b58c7d9ab29e23045b4a7ff8b1e..aebc8fa29979c2c9fc05f055c6493f69f0872aa3 100644
--- a/extras/conf/udb/Includes/SRB222_sectors.cfg
+++ b/extras/conf/udb/Includes/SRB222_sectors.cfg
@@ -15,7 +15,6 @@ sectortypes
 	12 = "Space Countdown";
 	13 = "Ramp Sector (double step-up/down)";
 	14 = "Non-Ramp Sector (no step-down)";
-	15 = "Bouncy FOF";
 	16 = "Trigger Line Ex. (Pushable Objects)";
 	32 = "Trigger Line Ex. (Anywhere, All Players)";
 	48 = "Trigger Line Ex. (Floor Touch, All Players)";
@@ -63,7 +62,6 @@ gen_sectortypes
 		12 = "Space Countdown";
 		13 = "Ramp Sector (double step-up/down)";
 		14 = "Non-Ramp Sector (no step-down)";
-		15 = "Bouncy FOF";
 	}
 
 	second
diff --git a/src/dehacked.c b/src/dehacked.c
index 3051b92d16d4376cdf3dd0f096ab58292cfd1e68..8edf0103ddb901c5e0922b171edcd7a483dcb923 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -9697,6 +9697,14 @@ struct {
 	{"FF_INTANGABLEFLATS",FF_INTANGIBLEFLATS}, ///< Both flats are intangable, but the sides are still solid.
 	{"FF_RIPPLE",FF_RIPPLE},                   ///< Ripple the flats
 	{"FF_COLORMAPONLY",FF_COLORMAPONLY},       ///< Only copy the colormap, not the lightlevel
+	{"FF_BOUNCY",FF_BOUNCY},                   ///< Bounces players
+
+	// FOF special flags
+	{"FS_PUSHABLES",FS_PUSHABLES},
+	{"FS_EXECUTOR",FS_EXECUTOR},
+	{"FS_ONLYBOTTOM",FS_ONLYBOTTOM},
+	{"FS_BUSTMASK",FS_BUSTMASK},
+	{"FS_DAMPEN",FS_DAMPEN},
 
 	// Bustable FOF type
 	{"BT_TOUCH",BT_TOUCH},
@@ -9704,11 +9712,6 @@ struct {
 	{"BT_REGULAR",BT_REGULAR},
 	{"BT_STRONG",BT_STRONG},
 
-	// Bustable FOF flags
-	{"BF_PUSHABLES",BF_PUSHABLES},
-	{"BF_EXECUTOR",BF_EXECUTOR},
-	{"BF_ONLYBOTTOM",BF_ONLYBOTTOM},
-
 #ifdef HAVE_LUA_SEGS
 	// Node flags
 	{"NF_SUBSECTOR",NF_SUBSECTOR}, // Indicate a leaf.
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 282605b194656a3514d8634bd0f559b099592987..e5de3de37a2077dfd87cdeb929f5f2ce7e7079c1 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -187,11 +187,12 @@ enum ffloor_e {
 	ffloor_next,
 	ffloor_prev,
 	ffloor_alpha,
+	ffloor_specialflags,
 	ffloor_busttype,
-	ffloor_bustflags,
 	ffloor_busttag,
 	ffloor_sinkspeed,
 	ffloor_friction,
+	ffloor_bouncestrength,
 };
 
 static const char *const ffloor_opt[] = {
@@ -210,11 +211,12 @@ static const char *const ffloor_opt[] = {
 	"next",
 	"prev",
 	"alpha",
+	"specialflags",
 	"busttype",
-	"bustflags",
 	"busttag",
 	"sinkspeed",
 	"friction",
+	"bouncestrength",
 	NULL};
 
 #ifdef HAVE_LUA_SEGS
@@ -1762,12 +1764,12 @@ static int ffloor_get(lua_State *L)
 	case ffloor_alpha:
 		lua_pushinteger(L, ffloor->alpha);
 		return 1;
+	case ffloor_specialflags:
+		lua_pushinteger(L, ffloor->specialflags);
+		return 1;
 	case ffloor_busttype:
 		lua_pushinteger(L, ffloor->busttype);
 		return 1;
-	case ffloor_bustflags:
-		lua_pushinteger(L, ffloor->bustflags);
-		return 1;
 	case ffloor_busttag:
 		lua_pushinteger(L, ffloor->busttag);
 		return 1;
@@ -1777,6 +1779,9 @@ static int ffloor_get(lua_State *L)
 	case ffloor_friction:
 		lua_pushfixed(L, ffloor->friction);
 		return 1;
+	case ffloor_bouncestrength:
+		lua_pushfixed(L, ffloor->bouncestrength);
+		return 1;
 	}
 	return 0;
 }
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 62aa7770a6e0693aa0059bc7c8549978e1b2f337..97cc766673bbd1d227d98a7c61564a71837d657e 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1691,7 +1691,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 			if (!(rover->flags & FF_BUSTUP))
 				continue;
 
-			if (!(rover->bustflags & BF_PUSHABLES))
+			if (!(rover->specialflags & FS_PUSHABLES))
 				continue;
 
 			if (rover->master->frontsector->crumblestate != CRUMBLE_NONE)
@@ -1701,7 +1701,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 			bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
 
 			// Height checks
-			if (rover->bustflags & BF_ONLYBOTTOM)
+			if (rover->specialflags & FS_ONLYBOTTOM)
 			{
 				if (mo->z + mo->momz + mo->height < bottomheight)
 					continue;
@@ -1743,7 +1743,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 			EV_CrumbleChain(NULL, rover); // node->m_sector
 
 			// Run a linedef executor??
-			if (rover->bustflags & BF_EXECUTOR)
+			if (rover->specialflags & FS_EXECUTOR)
 				P_LinedefExecute(rover->busttag, mo, node->m_sector);
 
 			goto bustupdone;
diff --git a/src/p_setup.c b/src/p_setup.c
index e21cc150c38db519b72f8ec3a258c1c6305f61b8..bd312652acdb72b831e0bdf2368478437ac42238 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -2800,6 +2800,12 @@ static void P_ConvertBinaryMap(void)
 	{
 		switch (lines[i].special)
 		{
+		case 76: //Make FOF bouncy
+			lines[i].args[0] = lines[i].tag;
+			lines[i].args[1] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
+			if (lines[i].flags & ML_BOUNCY)
+				lines[i].args[2] = 1;
+			break;
 		case 100: //FOF: solid, opaque, shadowcasting
 		case 101: //FOF: solid, opaque, non-shadowcasting
 		case 102: //FOF: solid, translucent
diff --git a/src/p_spec.c b/src/p_spec.c
index 77bc2407fe79c22bf4ca9b09c098a928119db352..0262bc0e90aa70c6d295820ca5355cd3431dce8e 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -4443,7 +4443,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
 			break;
 		case 13: // Ramp Sector (Increase step-up/down)
 		case 14: // Non-Ramp Sector (Don't step-down)
-		case 15: // Bouncy Sector (FOF Control Only)
+		case 15: // Unused
 			break;
 	}
 
@@ -6287,6 +6287,36 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
 
 }
 
+static void P_MakeFOFBouncy(line_t *paramline, line_t *masterline)
+{
+	INT32 s;
+
+	if (masterline->special < 100 || masterline->special >= 300)
+		return;
+
+	for (s = -1; (s = P_FindSectorFromTag(masterline->args[0], s)) >= 0 ;)
+	{
+		ffloor_t *rover;
+
+		for (rover = sectors[s].ffloors; rover; rover = rover->next)
+		{
+			if (rover->master != masterline)
+				continue;
+
+			rover->flags |= FF_BOUNCY;
+			rover->spawnflags |= FF_BOUNCY;
+			rover->bouncestrength = (paramline->args[1]<< FRACBITS)/100;
+			if (paramline->args[2])
+				rover->specialflags |= FS_DAMPEN;
+			else
+				rover->specialflags &= ~FS_DAMPEN;
+			CheckForBouncySector = true;
+			break;
+		}
+	}
+
+}
+
 /** After the map has loaded, scans for specials that spawn 3Dfloors and
   * thinkers.
   *
@@ -6327,10 +6357,6 @@ void P_SpawnSpecials(boolean fromnetsave)
 				//Yes, this also affects other specials on the same sector. Sorry.
 				sector->flags |= SF_TRIGGERSPECIAL_TOUCH;
 				break;
-
-			case 15: // Bouncy sector
-				CheckForBouncySector = true;
-				break;
 		}
 
 		// Process Section 2
@@ -6947,7 +6973,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 			case 254: // Bustable block
 			{
 				UINT8 busttype = BT_REGULAR;
-				UINT8 bustflags = 0;
+				ffloorspecialflags_e bustflags = 0;
 
 				ffloorflags = FF_EXISTS|FF_BLOCKOTHERS|FF_RENDERALL|FF_BUSTUP;
 
@@ -6974,20 +7000,20 @@ void P_SpawnSpecials(boolean fromnetsave)
 
 				//Flags
 				if (lines[i].args[3] & TMFB_PUSHABLES)
-					bustflags |= BF_PUSHABLES;
+					bustflags |= FS_PUSHABLES;
 				if (lines[i].args[3] & TMFB_EXECUTOR)
-					bustflags |= BF_EXECUTOR;
+					bustflags |= FS_EXECUTOR;
 				if (lines[i].args[3] & TMFB_ONLYBOTTOM)
-					bustflags |= BF_ONLYBOTTOM;
+					bustflags |= FS_ONLYBOTTOM;
 
-				if (busttype != BT_TOUCH || bustflags & BF_ONLYBOTTOM)
+				if (busttype != BT_TOUCH || bustflags & FS_ONLYBOTTOM)
 					ffloorflags |= FF_BLOCKPLAYER;
 
 				for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0], s)) >= 0 ;)
 				{
 					ffloor_t *fflr = P_AddFakeFloor(&sectors[s], lines[i].frontsector, lines + i, ffloorflags, secthinkers);
 					fflr->busttype = busttype;
-					fflr->bustflags = bustflags;
+					fflr->specialflags = bustflags;
 					fflr->busttag = lines[i].args[4];
 				}
 				break;
@@ -7040,12 +7066,12 @@ void P_SpawnSpecials(boolean fromnetsave)
 							}
 
 							if (lines[i].args[2] & TMFB_ONLYBOTTOM)
-								fflr->bustflags |= BF_ONLYBOTTOM;
+								fflr->specialflags |= FS_ONLYBOTTOM;
 							if (lines[i].flags & ML_EFFECT4)
-								fflr->bustflags |= BF_PUSHABLES;
+								fflr->specialflags |= FS_PUSHABLES;
 							if (lines[i].flags & ML_EFFECT5)
 							{
-								fflr->bustflags |= BF_EXECUTOR;
+								fflr->specialflags |= FS_EXECUTOR;
 								fflr->busttag = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS;
 							}
 						}
@@ -7309,7 +7335,7 @@ void P_SpawnSpecials(boolean fromnetsave)
 			case 74: // Make FOF bustable
 			{
 				UINT8 busttype = BT_REGULAR;
-				UINT8 bustflags = 0;
+				ffloorspecialflags_e bustflags = 0;
 
 				if (!udmf)
 					break;
@@ -7331,11 +7357,11 @@ void P_SpawnSpecials(boolean fromnetsave)
 				}
 
 				if (lines[i].args[2] & TMFB_PUSHABLES)
-					bustflags |= BF_PUSHABLES;
+					bustflags |= FS_PUSHABLES;
 				if (lines[i].args[2] & TMFB_EXECUTOR)
-					bustflags |= BF_EXECUTOR;
+					bustflags |= FS_EXECUTOR;
 				if (lines[i].args[2] & TMFB_ONLYBOTTOM)
-					bustflags |= BF_ONLYBOTTOM;
+					bustflags |= FS_ONLYBOTTOM;
 
 				for (l = -1; (l = P_FindLineFromTag(lines[i].args[0], l)) >= 0 ;)
 				{
@@ -7354,7 +7380,8 @@ void P_SpawnSpecials(boolean fromnetsave)
 							rover->flags |= FF_BUSTUP;
 							rover->spawnflags |= FF_BUSTUP;
 							rover->busttype = busttype;
-							rover->bustflags = bustflags;
+							rover->specialflags &= ~FS_BUSTMASK;
+							rover->specialflags |= bustflags;
 							rover->busttag = lines[i].args[3];
 							CheckForBustableBlocks = true;
 							break;
@@ -7394,6 +7421,22 @@ void P_SpawnSpecials(boolean fromnetsave)
 				}
 				break;
 			}
+
+			case 76: // Make FOF bouncy
+			{
+				if (udmf)
+				{
+					for (l = -1; (l = P_FindLineFromTag(lines[i].args[0], l)) >= 0 ;)
+						P_MakeFOFBouncy(lines + i, lines + l);
+				}
+				else
+				{
+					for (s = -1; (s = P_FindSectorFromTag(lines[i].args[0], s)) >= 0 ;)
+						for (j = 0; (unsigned)j < sectors[s].linecount; j++)
+							P_MakeFOFBouncy(lines + i, sectors[s].lines[j]);
+				}
+				break;
+			}
 		}
 	}
 
diff --git a/src/p_user.c b/src/p_user.c
index 8d16b0e7a2ef6868bcfcdd658cab4723abb133b8..26dfb7a91095d1f07b5ad80949b175e6f1d3a87f 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -2643,7 +2643,7 @@ static void P_CheckBustableBlocks(player_t *player)
 			}
 
 			// Height checks
-			if (rover->bustflags & BF_ONLYBOTTOM)
+			if (rover->specialflags & FS_ONLYBOTTOM)
 			{
 				if (player->mo->z + player->mo->momz + player->mo->height < bottomheight)
 					continue;
@@ -2697,7 +2697,7 @@ static void P_CheckBustableBlocks(player_t *player)
 			EV_CrumbleChain(NULL, rover); // node->m_sector
 
 			// Run a linedef executor??
-			if (rover->bustflags & BF_EXECUTOR)
+			if (rover->specialflags & FS_EXECUTOR)
 				P_LinedefExecute(rover->busttag, player->mo, node->m_sector);
 
 			goto bustupdone;
@@ -2743,14 +2743,13 @@ static void P_CheckBouncySectors(player_t *player)
 
 		for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 		{
-			fixed_t bouncestrength;
 			fixed_t topheight, bottomheight;
 
 			if (!(rover->flags & FF_EXISTS))
 				continue; // FOFs should not be bouncy if they don't even "exist"
 
-			if (GETSECSPECIAL(rover->master->frontsector->special, 1) != 15)
-				continue; // this sector type is required for FOFs to be bouncy
+			if (!(rover->flags & FF_BOUNCY))
+				continue;
 
 			topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
 			bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
@@ -2761,13 +2760,13 @@ static void P_CheckBouncySectors(player_t *player)
 			if (player->mo->z + player->mo->height < bottomheight)
 				continue;
 
-			bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100;
+			//bouncestrength = P_AproxDistance(rover->master->dx, rover->master->dy)/100;
 
 			if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)
 					&& oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL))
 			{
-				player->mo->momx = -FixedMul(player->mo->momx,bouncestrength);
-				player->mo->momy = -FixedMul(player->mo->momy,bouncestrength);
+				player->mo->momx = -FixedMul(player->mo->momx,rover->bouncestrength);
+				player->mo->momy = -FixedMul(player->mo->momy,rover->bouncestrength);
 
 				if (player->pflags & PF_SPINNING)
 				{
@@ -2788,12 +2787,12 @@ static void P_CheckBouncySectors(player_t *player)
 				if (slope)
 					P_ReverseQuantizeMomentumToSlope(&momentum, slope);
 
-				newmom = momentum.z = -FixedMul(momentum.z,bouncestrength)/2;
+				newmom = momentum.z = -FixedMul(momentum.z,rover->bouncestrength)/2;
 
-				if (abs(newmom) < (bouncestrength*2))
+				if (abs(newmom) < (rover->bouncestrength*2))
 					goto bouncydone;
 
-				if (!(rover->master->flags & ML_BOUNCY))
+				if (!(rover->specialflags & FS_DAMPEN))
 				{
 					if (newmom > 0)
 					{
diff --git a/src/r_defs.h b/src/r_defs.h
index 2f7b5622c052c4fda5d9579570cb3820f51b93cf..160bcac2ad3ac3a3f4e604fe02863e25aca96635 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -146,8 +146,18 @@ typedef enum
 	FF_INTANGIBLEFLATS   = 0x6000000,  ///< Both flats are intangible, but the sides are still solid.
 	FF_RIPPLE            = 0x8000000,  ///< Ripple the flats
 	FF_COLORMAPONLY      = 0x10000000, ///< Only copy the colormap, not the lightlevel
+	FF_BOUNCY            = 0x20000000, ///< Bounces players
 } ffloortype_e;
 
+typedef enum
+{
+	FS_PUSHABLES   = 0x1, // FF_BUSTABLE: Bustable by pushables
+	FS_EXECUTOR    = 0x2, // FF_BUSTABLE: Trigger linedef executor
+	FS_ONLYBOTTOM  = 0x4, // FF_BUSTABLE: Only bustable from below
+	FS_BUSTMASK    = 0x7,
+	FS_DAMPEN      = 0x8, // FF_BOUNCY:   Dampen bounce
+} ffloorspecialflags_e;
+
 typedef enum
 {
 	BT_TOUCH,
@@ -156,13 +166,6 @@ typedef enum
 	BT_STRONG,
 } busttype_e;
 
-typedef enum
-{
-	BF_PUSHABLES   = 1,
-	BF_EXECUTOR    = 1<<1,
-	BF_ONLYBOTTOM  = 1<<2,
-} bustflags_e;
-
 typedef struct ffloor_s
 {
 	fixed_t *topheight;
@@ -195,15 +198,20 @@ typedef struct ffloor_s
 	INT32 alpha;
 	tic_t norender; // for culling
 
+	// Flags that are only relevant for special ffloor types
+	ffloorspecialflags_e specialflags;
+
 	// Only relevant for FF_BUSTUP
 	UINT8 busttype;
-	UINT8 bustflags;
 	INT16 busttag;
 
 	// Only relevant for FF_QUICKSAND
 	fixed_t sinkspeed;
 	fixed_t friction;
 
+	// Only relevant for FF_BOUNCY
+	fixed_t bouncestrength;
+
 	// these are saved for netgames, so do not let Lua touch these!
 	ffloortype_e spawnflags; // flags the 3D floor spawned with
 	INT32 spawnalpha; // alpha the 3D floor spawned with