diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index 57c7c88a329073ec1ed1f97b1e0adb41fef38b62..6d64aea813acdd5f0bf35318577fa8304b6243d4 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -74,6 +74,11 @@ sectorflags
 	colormapfog = "Fog Planes in Colormap";
 	colormapfadesprites = "Fade Fullbright in Colormap";
 	colormapprotected = "Protected Colormap";
+	flipspecial_nofloor = "No Trigger on Floor Touch";
+	flipspecial_ceiling = "Trigger on Ceiling Touch";
+	triggerspecial_touch = "Trigger on Edge Touch";
+	triggerspecial_headbump = "Trigger on Headbump";
+	invertprecip = "Invert Precipitation";
 }
 
 thingflags
diff --git a/src/deh_lua.c b/src/deh_lua.c
index a2ffca95b0622826dd69d350c60dba52e221b0f9..ae062695c0c985bc15bfcc395983692b6d3c6b9a 100644
--- a/src/deh_lua.c
+++ b/src/deh_lua.c
@@ -338,6 +338,21 @@ static inline int lib_getenum(lua_State *L)
 		if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
 		return 0;
 	}
+	else if (fastncmp("MSF_", word, 3)) {
+		p = word + 4;
+		for (i = 0; i < 4; i++)
+			if (MSF_LIST[i] && fastcmp(p, MSF_LIST[i])) {
+				lua_pushinteger(L, ((lua_Integer)1 << i));
+				return 1;
+			}
+		if (fastcmp(p, "FLIPSPECIAL_BOTH"))
+		{
+			lua_pushinteger(L, (lua_Integer)MSF_FLIPSPECIAL_BOTH);
+			return 1;
+		}
+		if (mathlib) return luaL_error(L, "sector flag '%s' could not be found.\n", word);
+		return 0;
+	}
 	else if (fastncmp("S_",word,2)) {
 		p = word+2;
 		for (i = 0; i < NUMSTATEFREESLOTS; i++) {
diff --git a/src/deh_tables.c b/src/deh_tables.c
index f73f101516526651ee34656b59bc5b403af8d5af..73cf7068eb826fbb0bc0d88e97441222f4b61af4 100644
--- a/src/deh_tables.c
+++ b/src/deh_tables.c
@@ -4471,6 +4471,14 @@ const char *const ML_LIST[16] = {
 	"TFERLINE"
 };
 
+// Sector flags
+const char *const MSF_LIST[4] = {
+	"FLIPSPECIAL_FLOOR",
+	"FLIPSPECIAL_CEILING",
+	"TRIGGERSPECIAL_TOUCH",
+	"TRIGGERSPECIAL_HEADBUMP",
+};
+
 const char *COLOR_ENUMS[] = {
 	"NONE",			// SKINCOLOR_NONE,
 
diff --git a/src/deh_tables.h b/src/deh_tables.h
index 1f265cc9992da1c3d5c6e53781f6151710bc798f..77260d50711abdc52cbb51c610ec6b54795b1e58 100644
--- a/src/deh_tables.h
+++ b/src/deh_tables.h
@@ -65,6 +65,7 @@ extern const char *const MAPTHINGFLAG_LIST[4];
 extern const char *const PLAYERFLAG_LIST[];
 extern const char *const GAMETYPERULE_LIST[];
 extern const char *const ML_LIST[16]; // Linedef flags
+extern const char* const MSF_LIST[4]; // Sector flags
 extern const char *COLOR_ENUMS[];
 extern const char *const POWERS_LIST[];
 extern const char *const HUDITEMS_LIST[];
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 0ee87d2d2e3e054d448e5fb355d6572f89cb3139..9f267d0719e0f12219571e6c8f8733dbe0ec12ab 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -48,7 +48,8 @@ enum sector_e {
 	sector_lines,
 	sector_ffloors,
 	sector_fslope,
-	sector_cslope
+	sector_cslope,
+	sector_flags,
 };
 
 static const char *const sector_opt[] = {
@@ -72,6 +73,7 @@ static const char *const sector_opt[] = {
 	"ffloors",
 	"f_slope",
 	"c_slope",
+	"flags",
 	NULL};
 
 enum subsector_e {
@@ -649,6 +651,9 @@ static int sector_get(lua_State *L)
 	case sector_cslope: // c_slope
 		LUA_PushUserdata(L, sector->c_slope, META_SLOPE);
 		return 1;
+	case sector_flags: // flags
+		lua_pushinteger(L, sector->flags);
+		return 1;
 	}
 	return 0;
 }
@@ -735,6 +740,9 @@ static int sector_set(lua_State *L)
 		break;
 	case sector_taglist:
 		return LUA_ErrSetDirectly(L, "sector_t", "taglist");
+	case sector_flags:
+		sector->flags = luaL_checkinteger(L, 3);
+		break;
 	}
 	return 0;
 }
diff --git a/src/p_map.c b/src/p_map.c
index 5d90399d5cd3743ade20eb3d43fb77f315bdfc8e..6b69df9cbb6a7478709cde2bbc85461434e56698 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -3455,7 +3455,7 @@ static boolean PTR_SlideTraverse(intercept_t *in)
 	// 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))
+		if ((li->polyobj->lines[0]->backsector->flags & MSF_TRIGGERSPECIAL_TOUCH) && !(li->polyobj->flags & POF_NOSPECIALS))
 			P_ProcessSpecialSector(slidemo->player, slidemo->subsector->sector, li->polyobj->lines[0]->backsector);
 	}
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 46510200e3e903aba37f8dbee43222cf8fdf025b..47a70233b0988a058caa5d5911c57df2de76bdb9 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -2324,9 +2324,9 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
 		return false;
 
 	if (((mo->z <= mo->subsector->sector->floorheight
-		&& ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR))
+		&& ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_FLOOR))
 	|| (mo->z + mo->height >= mo->subsector->sector->ceilingheight
-		&& ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING)))
+		&& ((mo->subsector->sector->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & MSF_FLIPSPECIAL_CEILING)))
 	&& (GETSECSPECIAL(mo->subsector->sector->special, 1) == 6
 	|| GETSECSPECIAL(mo->subsector->sector->special, 1) == 7))
 		return true;
@@ -11219,7 +11219,7 @@ void P_SpawnPrecipitation(void)
 		if (curWeather == PRECIP_SNOW)
 		{
 			// Not in a sector with visible sky -- exception for NiGHTS.
-			if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & SF_INVERTPRECIP))
+			if ((!(maptol & TOL_NIGHTS) && (precipsector->sector->ceilingpic != skyflatnum)) == !(precipsector->sector->flags & MSF_INVERTPRECIP))
 				continue;
 
 			rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE);
@@ -11232,7 +11232,7 @@ void P_SpawnPrecipitation(void)
 		else // everything else.
 		{
 			// Not in a sector with visible sky.
-			if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & SF_INVERTPRECIP))
+			if ((precipsector->sector->ceilingpic != skyflatnum) == !(precipsector->sector->flags & MSF_INVERTPRECIP))
 				continue;
 
 			rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN);
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index 47327c94921b5364d2d3ae8ceb3e4d461f4b4521..bcad36f80f529fa123c8a3ba89b6d4f4c53101a4 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -963,7 +963,7 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line)
 					else
 						Polyobj_pushThing(po, line, mo);
 
-					if (mo->player && (po->lines[0]->backsector->flags & SF_TRIGGERSPECIAL_TOUCH) && !(po->flags & POF_NOSPECIALS))
+					if (mo->player && (po->lines[0]->backsector->flags & MSF_TRIGGERSPECIAL_TOUCH) && !(po->flags & POF_NOSPECIALS))
 						P_ProcessSpecialSector(mo->player, mo->subsector->sector, po->lines[0]->backsector);
 
 					hitflags |= 1;
diff --git a/src/p_setup.c b/src/p_setup.c
index 2e3fb1967229e3cb1d35caaa4745951986b7f22f..b83d950f2305feb5acb17e3402fe2b400c074977 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1001,7 +1001,6 @@ static void P_InitializeSector(sector_t *ss)
 
 	ss->gravity = NULL;
 	ss->verticalflip = false;
-	ss->flags = SF_FLIPSPECIAL_FLOOR;
 
 	ss->cullheight = NULL;
 
@@ -1048,6 +1047,8 @@ static void P_LoadSectors(UINT8 *data)
 
 		ss->colormap_protected = false;
 
+		ss->flags = MSF_FLIPSPECIAL_FLOOR;
+
 		P_InitializeSector(ss);
 	}
 }
@@ -1661,6 +1662,16 @@ static void ParseTextmapSectorParameter(UINT32 i, char *param, char *val)
 	}
 	else if (fastcmp(param, "colormapprotected") && fastcmp("true", val))
 		sectors[i].colormap_protected = true;
+	else if (fastcmp(param, "flipspecial_nofloor") && fastcmp("true", val))
+		sectors[i].flags &= ~MSF_FLIPSPECIAL_FLOOR;
+	else if (fastcmp(param, "flipspecial_ceiling") && fastcmp("true", val))
+		sectors[i].flags |= MSF_FLIPSPECIAL_CEILING;
+	else if (fastcmp(param, "triggerspecial_touch") && fastcmp("true", val))
+		sectors[i].flags |= MSF_TRIGGERSPECIAL_TOUCH;
+	else if (fastcmp(param, "triggerspecial_headbump") && fastcmp("true", val))
+		sectors[i].flags |= MSF_TRIGGERSPECIAL_HEADBUMP;
+	else if (fastcmp(param, "invertprecip") && fastcmp("true", val))
+		sectors[i].flags |= MSF_INVERTPRECIP;
 }
 
 static void ParseTextmapSidedefParameter(UINT32 i, char *param, char *val)
@@ -1937,6 +1948,8 @@ static void P_LoadTextmap(void)
 
 		sc->colormap_protected = false;
 
+		sc->flags = MSF_FLIPSPECIAL_FLOOR;
+
 		textmap_colormap.used = false;
 		textmap_colormap.lightcolor = 0;
 		textmap_colormap.lightalpha = 25;
diff --git a/src/p_spec.c b/src/p_spec.c
index ab2f67d74f5e2637f24521ad126cff7f853957d3..37b07753560aa35a7465749c62958aae3e3bc7b4 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3945,8 +3945,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 
 static boolean P_IsMobjTouchingPlane(mobj_t *mo, sector_t *sec, fixed_t floorz, fixed_t ceilingz)
 {
-	boolean floorallowed = ((sec->flags & SF_FLIPSPECIAL_FLOOR) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == floorz));
-	boolean ceilingallowed = ((sec->flags & SF_FLIPSPECIAL_CEILING) && ((sec->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == ceilingz));
+	boolean floorallowed = ((sec->flags & MSF_FLIPSPECIAL_FLOOR) && ((sec->flags & MSF_TRIGGERSPECIAL_HEADBUMP) || !(mo->eflags & MFE_VERTICALFLIP)) && (mo->z == floorz));
+	boolean ceilingallowed = ((sec->flags & MSF_FLIPSPECIAL_CEILING) && ((sec->flags &  MSF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->z + mo->height == ceilingz));
 	return (floorallowed || ceilingallowed);
 }
 
@@ -4007,7 +4007,7 @@ static sector_t *P_MobjTouching3DFloorSpecial(mobj_t *mo, sector_t *sector, INT3
 
 		// This FOF has the special we're looking for, but are we allowed to touch it?
 		if (sector == mo->subsector->sector
-			|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
+			|| (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 			return rover->master->frontsector;
 	}
 
@@ -4031,7 +4031,7 @@ static sector_t *P_MobjTouchingPolyobjSpecial(mobj_t *mo, INT32 section, INT32 n
 		if (GETSECSPECIAL(polysec->special, section) != number)
 			continue;
 
-		touching = (polysec->flags & SF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo);
+		touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo);
 		inside = P_MobjInsidePolyobj(po, mo);
 
 		if (!(inside || touching))
@@ -4071,7 +4071,7 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number)
 		if (result)
 			return result;
 
-		if (!(node->m_sector->flags & SF_TRIGGERSPECIAL_TOUCH))
+		if (!(node->m_sector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 			continue;
 
 		if (GETSECSPECIAL(mo->subsector->sector->special, section) == number)
@@ -4120,7 +4120,7 @@ static sector_t *P_Check3DFloorTriggers(player_t *player, sector_t *sector, line
 
 		// This FOF has the special we're looking for, but are we allowed to touch it?
 		if (sector == player->mo->subsector->sector
-			|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
+			|| (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 			return rover->master->frontsector;
 	}
 
@@ -4147,7 +4147,7 @@ static sector_t *P_CheckPolyobjTriggers(player_t *player, line_t *sourceline)
 		if (!Tag_Find(&sourceline->tags, Tag_FGet(&polysec->tags)))
 			return false;
 
-		touching = (polysec->flags & SF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo);
+		touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo);
 		inside = P_MobjInsidePolyobj(po, player->mo);
 
 		if (!(inside || touching))
@@ -4217,7 +4217,7 @@ sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline)
 		if (caller)
 			return caller;
 
-		if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH))
+		if (!(loopsector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 			continue;
 
 		if (P_CheckSectorTriggers(player, loopsector, sourceline))
@@ -5024,7 +5024,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 
 		// This FOF has the special we're looking for, but are we allowed to touch it?
 		if (sector == player->mo->subsector->sector
-			|| (rover->master->frontsector->flags & SF_TRIGGERSPECIAL_TOUCH))
+			|| (rover->master->frontsector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 		{
 			P_ProcessSpecialSector(player, rover->master->frontsector, sector);
 			if TELEPORTED(player->mo) return;
@@ -5050,7 +5050,7 @@ static void P_PlayerOnSpecialPolyobj(player_t *player)
 		if (!polysec->special)
 			continue;
 
-		touching = (polysec->flags & SF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo);
+		touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, player->mo);
 		inside = P_MobjInsidePolyobj(po, player->mo);
 
 		if (!(inside || touching))
@@ -5102,7 +5102,7 @@ void P_PlayerInSpecialSector(player_t *player)
 		P_PlayerOnSpecial3DFloor(player, loopsector);
 		if TELEPORTED(player->mo) return;
 
-		if (!(loopsector->flags & SF_TRIGGERSPECIAL_TOUCH))
+		if (!(loopsector->flags & MSF_TRIGGERSPECIAL_TOUCH))
 			continue;
 
 		P_ProcessSpecialSector(player, loopsector, NULL);
@@ -5152,7 +5152,7 @@ static void P_CheckMobjPolyobjTrigger(mobj_t *mo)
 		if (!polysec->special)
 			continue;
 
-		touching = (polysec->flags & SF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo);
+		touching = (polysec->flags & MSF_TRIGGERSPECIAL_TOUCH) && P_MobjTouchingPolyobj(po, mo);
 		inside = P_MobjInsidePolyobj(po, mo);
 
 		if (!(inside || touching))
@@ -5994,9 +5994,9 @@ void P_SpawnSpecials(boolean fromnetsave)
 		{
 			case 5: // Spikes
 				//Terrible hack to replace an even worse hack:
-				//Spike damage automatically sets SF_TRIGGERSPECIAL_TOUCH.
+				//Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH.
 				//Yes, this also affects other specials on the same sector. Sorry.
-				sector->flags |= SF_TRIGGERSPECIAL_TOUCH;
+				sector->flags |= MSF_TRIGGERSPECIAL_TOUCH;
 				break;
 			case 15: // Bouncy FOF
 				CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n"));
@@ -6148,19 +6148,19 @@ void P_SpawnSpecials(boolean fromnetsave)
 				{
 					if (lines[i].flags & ML_NOCLIMB)
 					{
-						sectors[s].flags &= ~SF_FLIPSPECIAL_FLOOR;
-						sectors[s].flags |= SF_FLIPSPECIAL_CEILING;
+						sectors[s].flags &= ~MSF_FLIPSPECIAL_FLOOR;
+						sectors[s].flags |= MSF_FLIPSPECIAL_CEILING;
 					}
 					else if (lines[i].flags & ML_EFFECT4)
-						sectors[s].flags |= SF_FLIPSPECIAL_BOTH;
+						sectors[s].flags |= MSF_FLIPSPECIAL_BOTH;
 
 					if (lines[i].flags & ML_EFFECT3)
-						sectors[s].flags |= SF_TRIGGERSPECIAL_TOUCH;
+						sectors[s].flags |= MSF_TRIGGERSPECIAL_TOUCH;
 					if (lines[i].flags & ML_EFFECT2)
-						sectors[s].flags |= SF_TRIGGERSPECIAL_HEADBUMP;
+						sectors[s].flags |= MSF_TRIGGERSPECIAL_HEADBUMP;
 
 					if (lines[i].flags & ML_EFFECT1)
-						sectors[s].flags |= SF_INVERTPRECIP;
+						sectors[s].flags |= MSF_INVERTPRECIP;
 
 					if (lines[i].frontsector && GETSECSPECIAL(lines[i].frontsector->special, 4) == 12)
 						sectors[s].camsec = sides[*lines[i].sidenum].sector-sectors;
diff --git a/src/r_defs.h b/src/r_defs.h
index 0609a48a8c9a2de1f9f7ed591fac0027ac31a5c3..c10428431a55cf81754e3c88346039395d79e687 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -276,14 +276,14 @@ typedef struct pslope_s
 typedef enum
 {
 	// flipspecial - planes with effect
-	SF_FLIPSPECIAL_FLOOR       =  1,
-	SF_FLIPSPECIAL_CEILING     =  1<<1,
-	SF_FLIPSPECIAL_BOTH        =  (SF_FLIPSPECIAL_FLOOR|SF_FLIPSPECIAL_CEILING),
+	MSF_FLIPSPECIAL_FLOOR       =  1,
+	MSF_FLIPSPECIAL_CEILING     =  1<<1,
+	MSF_FLIPSPECIAL_BOTH        =  (MSF_FLIPSPECIAL_FLOOR|MSF_FLIPSPECIAL_CEILING),
 	// triggerspecial - conditions under which plane touch causes effect
-	SF_TRIGGERSPECIAL_TOUCH    =  1<<2,
-	SF_TRIGGERSPECIAL_HEADBUMP =  1<<3,
+	MSF_TRIGGERSPECIAL_TOUCH    =  1<<2,
+	MSF_TRIGGERSPECIAL_HEADBUMP =  1<<3,
 	// invertprecip - inverts presence of precipitation
-	SF_INVERTPRECIP            =  1<<4,
+	MSF_INVERTPRECIP            =  1<<4,
 } sectorflags_t;