diff --git a/extras/conf/udb/Includes/SRB222_misc.cfg b/extras/conf/udb/Includes/SRB222_misc.cfg
index fcc24741e3b7f7ff9a2172e6cff702964f6dd71a..ed0488a3ff872aa28e5262ee876ccd2b53ce1397 100644
--- a/extras/conf/udb/Includes/SRB222_misc.cfg
+++ b/extras/conf/udb/Includes/SRB222_misc.cfg
@@ -265,14 +265,8 @@ universalfields
 
 		triggerer
 		{
-			type = 0;
-			default = 0;
-			enum
-			{
-				0 = "Player";
-				1 = "All players";
-				2 = "Object";
-			}
+			type = 2;
+			default = "Player";
 		}
 	}
 
diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index 1de661e29643d303acb08b961fc564f083aae2b5..b4508c91ea568aecc702ad1bf9927f079e820bd1 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -4546,7 +4546,7 @@ udmf
 			sprite = "EMBMA0";
 			width = 16;
 			height = 30;
-			arg0
+			arg1
 			{
 				title = "Float?";
 				type = 11;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6fe260fb4633fa4909100cf78149e6bbf2100fbb..2f4467a322026aa73b4281b97daeae8800855deb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -127,7 +127,9 @@ endif()
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
 if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
-	target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+	if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64|em64t|EM64T)")
+		target_compile_options(SRB2SDL2 PRIVATE -mno-ms-bitfields)
+	endif()
 endif()
 
 # Compiler warnings configuration
diff --git a/src/g_input.c b/src/g_input.c
index 79bd2a4a291b37abedfbbed2c41a2145810f50a9..262e68c6a65af402927d57ce0b86a2162cb50cd4 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -744,31 +744,31 @@ void G_DefineDefaultControls(void)
 		gamecontroldefault[i][GC_CUSTOM1      ][1] = KEY_JOY1+1; // B
 		gamecontroldefault[i][GC_CUSTOM2      ][1] = KEY_JOY1+3; // Y
 		gamecontroldefault[i][GC_CUSTOM3      ][1] = KEY_JOY1+8; // Left Stick
-		gamecontroldefault[i][GC_CENTERVIEW   ][1] = KEY_JOY1+9; // Right Stick
-		gamecontroldefault[i][GC_WEAPONPREV   ][1] = KEY_JOY1+4; // LB
-		gamecontroldefault[i][GC_WEAPONNEXT   ][1] = KEY_JOY1+5; // RB
+		gamecontroldefault[i][GC_CAMTOGGLE    ][1] = KEY_JOY1+4; // LB
+		gamecontroldefault[i][GC_CENTERVIEW   ][1] = KEY_JOY1+5; // RB
 		gamecontroldefault[i][GC_SCREENSHOT   ][1] = KEY_JOY1+6; // Back
 		gamecontroldefault[i][GC_SYSTEMMENU   ][0] = KEY_JOY1+7; // Start
-		gamecontroldefault[i][GC_CAMTOGGLE    ][1] = KEY_HAT1+0; // D-Pad Up
-		gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_HAT1+1; // D-Pad Down
-		gamecontroldefault[i][GC_TOSSFLAG     ][1] = KEY_HAT1+2; // D-Pad Left
-		gamecontroldefault[i][GC_SCORES       ][1] = KEY_HAT1+3; // D-Pad Right
+		gamecontroldefault[i][GC_WEAPONPREV   ][1] = KEY_HAT1+2; // D-Pad Left
+		gamecontroldefault[i][GC_WEAPONNEXT   ][1] = KEY_HAT1+3; // D-Pad Right
+		gamecontroldefault[i][GC_VIEWPOINTNEXT][1] = KEY_JOY1+9; // Right Stick
+		gamecontroldefault[i][GC_TOSSFLAG     ][1] = KEY_HAT1+0; // D-Pad Up
+		gamecontroldefault[i][GC_SCORES       ][1] = KEY_HAT1+1; // D-Pad Down
 
 		// Second player controls only have joypad defaults
-		gamecontrolbisdefault[i][GC_JUMP        ][1] = KEY_2JOY1+0; // A
-		gamecontrolbisdefault[i][GC_SPIN        ][1] = KEY_2JOY1+2; // X
-		gamecontrolbisdefault[i][GC_CUSTOM1     ][1] = KEY_2JOY1+1; // B
-		gamecontrolbisdefault[i][GC_CUSTOM2     ][1] = KEY_2JOY1+3; // Y
-		gamecontrolbisdefault[i][GC_CUSTOM3     ][1] = KEY_2JOY1+8; // Left Stick
-		gamecontrolbisdefault[i][GC_CENTERVIEW  ][1] = KEY_2JOY1+9; // Right Stick
-		gamecontrolbisdefault[i][GC_WEAPONPREV  ][1] = KEY_2JOY1+4; // LB
-		gamecontrolbisdefault[i][GC_WEAPONNEXT  ][1] = KEY_2JOY1+5; // RB
-		gamecontrolbisdefault[i][GC_SCREENSHOT  ][1] = KEY_2JOY1+6; // Back
+		gamecontrolbisdefault[i][GC_JUMP         ][1] = KEY_2JOY1+0; // A
+		gamecontrolbisdefault[i][GC_SPIN         ][1] = KEY_2JOY1+2; // X
+		gamecontrolbisdefault[i][GC_CUSTOM1      ][1] = KEY_2JOY1+1; // B
+		gamecontrolbisdefault[i][GC_CUSTOM2      ][1] = KEY_2JOY1+3; // Y
+		gamecontrolbisdefault[i][GC_CUSTOM3      ][1] = KEY_2JOY1+8; // Left Stick
+		gamecontrolbisdefault[i][GC_CAMTOGGLE    ][1] = KEY_2JOY1+4; // LB
+		gamecontrolbisdefault[i][GC_CENTERVIEW   ][1] = KEY_2JOY1+5; // RB
+		gamecontrolbisdefault[i][GC_SCREENSHOT   ][1] = KEY_2JOY1+6; // Back
 		//gamecontrolbisdefault[i][GC_SYSTEMMENU   ][0] = KEY_2JOY1+7; // Start
-		gamecontrolbisdefault[i][GC_CAMTOGGLE    ][1] = KEY_2HAT1+0; // D-Pad Up
-		gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2HAT1+1; // D-Pad Down
-		gamecontrolbisdefault[i][GC_TOSSFLAG     ][1] = KEY_2HAT1+2; // D-Pad Left
-		//gamecontrolbisdefault[i][GC_SCORES       ][1] = KEY_2HAT1+3; // D-Pad Right
+		gamecontrolbisdefault[i][GC_WEAPONPREV   ][1] = KEY_2HAT1+2; // D-Pad Left
+		gamecontrolbisdefault[i][GC_WEAPONNEXT   ][1] = KEY_2HAT1+3; // D-Pad Right
+		gamecontrolbisdefault[i][GC_VIEWPOINTNEXT][1] = KEY_2JOY1+9; // Right Stick
+		gamecontrolbisdefault[i][GC_TOSSFLAG     ][1] = KEY_2HAT1+0; // D-Pad Up
+		//gamecontrolbisdefault[i][GC_SCORES       ][1] = KEY_2HAT1+1; // D-Pad Down
 	}
 }
 
diff --git a/src/info.c b/src/info.c
index 174eb5cc4434182adda83040cbc7a13140769902..b55302170c08de9c70896b7e165a4e2c9f905670 100644
--- a/src/info.c
+++ b/src/info.c
@@ -3429,10 +3429,10 @@ state_t states[NUMSTATES] =
 	{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF3
 	{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF4
 
-	{SPR_TTAG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_TTAG
+	{SPR_TTAG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_TTAG
 
 	// CTF Sign
-	{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
+	{SPR_GFLG, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
 
 	// Finish flag
 	{SPR_FNSF,    FF_TRANS30, -1, {NULL}, 0, 0, S_NULL}, // S_FINISHFLAG
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 29adb478abfffd58a5d564769382c6290c6acefd..a4ad81358fbae523df8ecf316d179029c1f35f55 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -2261,6 +2261,18 @@ static int lib_pMobjTouchingSectorSpecial(lua_State *L)
 	return 1;
 }
 
+static int lib_pThingOnSpecial3DFloor(lua_State *L)
+{
+	mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	NOHUD
+	INLEVEL
+	if (!mo)
+		return LUA_ErrInvalid(L, "mobj_t");
+	LUA_Deprecated(L, "P_ThingOnSpecial3DFloor", "P_MobjTouchingSectorSpecial\" or \"P_MobjTouchingSectorSpecialFlag");
+	LUA_PushUserdata(L, P_ThingOnSpecial3DFloor(mo), META_SECTOR);
+	return 1;
+}
+
 static int lib_pMobjTouchingSectorSpecialFlag(lua_State *L)
 {
 	mobj_t *mo = *((mobj_t**)luaL_checkudata(L, 1, META_MOBJ));
@@ -4132,6 +4144,7 @@ static luaL_Reg lib[] = {
 	{"P_DoSuperTransformation",lib_pDoSuperTransformation},
 	{"P_ExplodeMissile",lib_pExplodeMissile},
 	{"P_MobjTouchingSectorSpecial",lib_pMobjTouchingSectorSpecial},
+	{"P_ThingOnSpecial3DFloor",lib_pThingOnSpecial3DFloor},
 	{"P_MobjTouchingSectorSpecialFlag",lib_pMobjTouchingSectorSpecialFlag},
 	{"P_PlayerTouchingSectorSpecial",lib_pPlayerTouchingSectorSpecial},
 	{"P_PlayerTouchingSectorSpecialFlag",lib_pPlayerTouchingSectorSpecialFlag},
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 3305709fc14df8e8aed71b04cc1cfa4a6d15b73d..c376c2db45d8fe288718a0ff4ca6565a82bd7941 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -13460,6 +13460,9 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
 	if (!player)
 		return true;
 
+	if (player->spectator)
+		return true;
+
 	if (player->powers[pw_carry] != CR_DUSTDEVIL && (player->powers[pw_ignorelatch] & (1<<15)))
 		return true;
 
diff --git a/src/p_floor.c b/src/p_floor.c
index a367a08d8433466a888072bc7757b90d4a5d2670..869384b534c1f100d300fb706acf300bb2560e1b 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1660,7 +1660,7 @@ void EV_DoFloor(mtag_t tag, line_t *line, floor_e floortype)
 				// chained linedef executing ability
 				// Only set it on one of the moving sectors (the smallest numbered)
 				if (line->args[3])
-					dofloor->tag = firstone ? (INT16)line->args[3] : -1;
+					dofloor->tag = firstone ? (INT16)line->args[3] : 0;
 
 				// flat changing ability
 				dofloor->texture = line->args[4] ? line->frontsector->floorpic : -1;
diff --git a/src/p_map.c b/src/p_map.c
index 5c8ccbb19327542e118c19e404673fdc1981de82..54e2003ba2e73b1be880b770fe005f771dccc52c 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -262,13 +262,15 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 			}
 			else
 			{
-				INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING); // Not identical to below...
+				INT32 pflags = object->player->pflags & (PF_JUMPED|PF_NOJUMPDAMAGE|PF_SPINNING|PF_THOKKED|PF_BOUNCING|PF_CANCARRY); // Not identical to below...
 				UINT8 secondjump = object->player->secondjump;
+				UINT16 tailsfly = object->player->powers[pw_tailsfly];
 				if (object->player->pflags & PF_GLIDING)
 					P_SetPlayerMobjState(object, S_PLAY_FALL);
 				P_ResetPlayer(object->player);
 				object->player->pflags |= pflags;
 				object->player->secondjump = secondjump;
+				object->player->powers[pw_tailsfly] = tailsfly;
 			}
 		}
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 635d4f42b69cdac7e8e400394a16d1e3fb154cbf..b279a8a88b8b7375fa962ee790096d145985c9c8 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11849,7 +11849,6 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
 	case MT_EMERHUNT:
 	case MT_EMERALDSPAWN:
 	case MT_TOKEN:
-	case MT_EMBLEM:
 	case MT_RING:
 	case MT_REDTEAMRING:
 	case MT_BLUETEAMRING:
@@ -11861,6 +11860,10 @@ fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mt
 		offset += mthing->args[0] ? 0 : 24*FRACUNIT;
 		break;
 
+	case MT_EMBLEM:
+		offset += mthing->args[1] ? 0 : 24 * FRACUNIT;
+		break;
+
 	// Remaining objects.
 	default:
 		if (P_WeaponOrPanel(mobjtype))
@@ -13277,6 +13280,23 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
 	return true;
 }
 
+// Pre-UDMF backwards compatibility stuff. Remove for 2.3
+static void P_SetAmbush(mapthing_t *mthing, mobj_t *mobj)
+{
+	if (mobj->type == MT_NIGHTSBUMPER
+		|| mobj->type == MT_AXIS
+		|| mobj->type == MT_AXISTRANSFER
+		|| mobj->type == MT_AXISTRANSFERLINE
+		|| mobj->type == MT_NIGHTSBUMPER
+		|| mobj->type == MT_STARPOST)
+		return;
+
+	if ((mthing->options & MTF_OBJECTSPECIAL) && (mobj->flags & MF_PUSHABLE))
+		return;
+
+	mobj->flags2 |= MF2_AMBUSH;
+}
+
 static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t i)
 {
 	mobj_t *mobj = NULL;
@@ -13299,6 +13319,9 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
 
 	mthing->mobj = mobj;
 
+	if (!udmf && (mthing->options & MTF_AMBUSH))
+		P_SetAmbush(mthing, mobj);
+
 	// Generic reverse gravity for individual objects flag.
 	if (mthing->options & MTF_OBJECTFLIP)
 	{
diff --git a/src/p_setup.c b/src/p_setup.c
index 2c804f53557c6f9b53a8a47fae17c62d6a20c6e5..53905b90818c48a27087221252e9866a49cc5eca 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1761,7 +1761,14 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
 	else if (fastcmp(param, "triggertag"))
 		sectors[i].triggertag = atol(val);
 	else if (fastcmp(param, "triggerer"))
-		sectors[i].triggerer = atol(val);
+	{
+		if (fastcmp(val, "Player"))
+			sectors[i].triggerer = TO_PLAYER;
+		if (fastcmp(val, "AllPlayers"))
+			sectors[i].triggerer = TO_ALLPLAYERS;
+		if (fastcmp(val, "Mobj"))
+			sectors[i].triggerer = TO_MOBJ;
+	}
 }
 
 static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
@@ -2263,6 +2270,9 @@ static void P_WriteTextmap(void)
 			case 10:
 				CONS_Alert(CONS_WARNING, M_GetText("Sector %s has ring drainer effect, which is not supported in UDMF. Use linedef type 462 instead.\n"), sizeu1(i));
 				break;
+			case 15:
+				CONS_Alert(CONS_WARNING, M_GetText("Sector %s has bouncy FOF effect, which is not supported in UDMF. Use linedef type 76 instead.\n"), sizeu1(i));
+				break;
 			default:
 				break;
 		}
@@ -2278,6 +2288,12 @@ static void P_WriteTextmap(void)
 			case 9:
 				CONS_Alert(CONS_WARNING, M_GetText("Sector %s has Egg Capsule type, which is not supported in UDMF. Use linedef type 464 instead.\n"), sizeu1(i));
 				break;
+			case 10:
+				CONS_Alert(CONS_WARNING, M_GetText("Sector %s has special stage time/spheres requirements effect, which is not supported in UDMF. Use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"), sizeu1(i));
+				break;
+			case 11:
+				CONS_Alert(CONS_WARNING, M_GetText("Sector %s has custom global gravity effect, which is not supported in UDMF. Use the Gravity level header option instead.\n"), sizeu1(i));
+				break;
 			default:
 				break;
 		}
@@ -2633,7 +2649,22 @@ static void P_WriteTextmap(void)
 		if (wsectors[i].triggertag != 0)
 			fprintf(f, "triggertag = %d;\n", wsectors[i].triggertag);
 		if (wsectors[i].triggerer != 0)
-			fprintf(f, "triggerer = %d;\n", wsectors[i].triggerer);
+		{
+			switch (wsectors[i].triggerer)
+			{
+				case TO_PLAYER:
+					fprintf(f, "triggerer = \"Player\";\n");
+					break;
+				case TO_ALLPLAYERS:
+					fprintf(f, "triggerer = \"AllPlayers\";\n");
+					break;
+				case TO_MOBJ:
+					fprintf(f, "triggerer = \"Mobj\";\n");
+					break;
+				default:
+					break;
+			}
+		}
 		fprintf(f, "}\n");
 		fprintf(f, "\n");
 	}
@@ -4187,7 +4218,8 @@ static void P_ConvertBinaryLinedefTypes(void)
 			lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
 			lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS;
 			lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD);
-			P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]);
+			if (sides[lines[i].sidenum[0]].toptexture)
+				P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]);
 			break;
 		case 16: //Minecart parameters
 			lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS;
@@ -5986,6 +6018,9 @@ static void P_ConvertBinarySectorTypes(void)
 			case 14: //Non-ramp sector
 				sectors[i].specialflags |= SSF_NOSTEPDOWN;
 				break;
+			case 15: //Bouncy FOF
+				CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n"));
+				break;
 			default:
 				break;
 		}
@@ -6018,11 +6053,13 @@ static void P_ConvertBinarySectorTypes(void)
 				sectors[i].triggerer = TO_PLAYER;
 				break;
 			case 6: //Trigger linedef executor (Emerald check)
+				CONS_Alert(CONS_WARNING, M_GetText("Deprecated emerald check sector type detected. Please use linedef types 337-339 instead.\n"));
 				sectors[i].triggertag = tag;
 				sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE;
 				sectors[i].triggerer = TO_PLAYEREMERALDS;
 				break;
 			case 7: //Trigger linedef executor (NiGHTS mare)
+				CONS_Alert(CONS_WARNING, M_GetText("Deprecated NiGHTS mare sector type detected. Please use linedef types 340-342 instead.\n"));
 				sectors[i].triggertag = tag;
 				sectors[i].flags &= ~MSF_TRIGGERLINE_PLANE;
 				sectors[i].triggerer = TO_PLAYERNIGHTS;
@@ -6030,6 +6067,12 @@ static void P_ConvertBinarySectorTypes(void)
 			case 8: //Check for linedef executor on FOFs
 				sectors[i].flags |= MSF_TRIGGERLINE_MOBJ;
 				break;
+			case 10: //Special stage time/spheres requirements
+				CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for special stage requirements detected. Please use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"));
+				break;
+			case 11: //Custom global gravity
+				CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for global gravity detected. Please use the Gravity level header option instead.\n"));
+				break;
 			default:
 				break;
 		}
@@ -6266,7 +6309,6 @@ static void P_ConvertBinaryThingTypes(void)
 		case 312: //Emerald token
 		case 320: //Emerald hunt location
 		case 321: //Match chaos emerald spawn
-		case 322: //Emblem
 		case 330: //Bounce ring panel
 		case 331: //Rail ring panel
 		case 332: //Automatic ring panel
@@ -6279,6 +6321,9 @@ static void P_ConvertBinaryThingTypes(void)
 		case 1800: //Coin
 			mapthings[i].args[0] = !(mapthings[i].options & MTF_AMBUSH);
 			break;
+		case 322: //Emblem
+			mapthings[i].args[1] = !(mapthings[i].options & MTF_AMBUSH);
+			break;
 		case 409: //Extra life monitor
 			mapthings[i].args[2] = !(mapthings[i].options & (MTF_AMBUSH|MTF_OBJECTSPECIAL));
 			break;
diff --git a/src/p_spec.c b/src/p_spec.c
index 5c9caa82fa97914db4c481a7e037939b0b09d613..4e6ef531faaef17949cf6fbfb663f54d777811e0 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1760,13 +1760,11 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 	{
 		if (caller->triggerer == TO_PLAYEREMERALDS)
 		{
-			CONS_Alert(CONS_WARNING, M_GetText("Deprecated emerald check sector type detected. Please use linedef types 337-339 instead.\n"));
 			if (!(ALL7EMERALDS(emeralds)))
 				return false;
 		}
 		else if (caller->triggerer == TO_PLAYERNIGHTS)
 		{
-			CONS_Alert(CONS_WARNING, M_GetText("Deprecated NiGHTS mare sector type detected. Please use linedef types 340-342 instead.\n"));
 			if (!P_CheckPlayerMareOld(triggerline))
 				return false;
 		}
@@ -4180,6 +4178,29 @@ sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number)
 	return NULL;
 }
 
+// Deprecated in favor of P_MobjTouchingSectorSpecial
+// Kept for Lua backwards compatibility only
+sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
+{
+	ffloor_t *rover;
+
+	for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
+	{
+		if (!rover->master->frontsector->special)
+			continue;
+
+		if (!(rover->fofflags & FOF_EXISTS))
+			continue;
+
+		if (!P_IsMobjTouching3DFloor(mo, rover, mo->subsector->sector))
+			continue;
+
+		return rover->master->frontsector;
+	}
+
+	return NULL;
+}
+
 sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag)
 {
 	msecnode_t *node;
@@ -4375,7 +4396,7 @@ sector_t *P_FindPlayerTrigger(player_t *player, line_t *sourceline)
 			return loopsector;
 	}
 
-	return false;
+	return NULL;
 }
 
 boolean P_IsPlayerValid(size_t playernum)
@@ -4579,6 +4600,9 @@ static void P_ProcessExitSector(player_t *player, mtag_t sectag)
 	if (player->bot)
 		return;
 
+	if (G_IsSpecialStage(gamemap) && !(maptol & TOL_NIGHTS))
+		return;
+
 	// Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c)
 	P_DoPlayerFinish(player);
 
@@ -4627,7 +4651,7 @@ static void P_ProcessTeamBase(player_t *player, boolean redteam)
 
 	// Make sure the team still has their own
 	// flag at their base so they can score.
-	if (!P_IsFlagAtBase(redteam ? MT_BLUEFLAG : MT_REDFLAG))
+	if (!P_IsFlagAtBase(redteam ? MT_REDFLAG : MT_BLUEFLAG))
 		return;
 
 	HU_SetCEchoFlags(V_AUTOFADEOUT|V_ALLOWLOWERCASE);
@@ -5944,8 +5968,6 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
 {
 	elevator_t *elevator; // Why not? LOL
 
-	CONS_Alert(CONS_WARNING, M_GetText("Detected a camera scanner effect (linedef type 5). This effect is deprecated and will be removed in the future!\n"));
-
 	// create and initialize new elevator thinker
 	elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
 	P_AddThinker(THINK_MAIN, &elevator->thinker);
@@ -6200,22 +6222,21 @@ void P_SpawnSpecials(boolean fromnetsave)
 				circuitmap = true;
 		}
 
-		if (!sector->special)
+		if (sector->damagetype == SD_SPIKE) {
+			//Terrible hack to replace an even worse hack:
+			//Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH.
+			//Yes, this also affects other specials on the same sector. Sorry.
+			sector->flags |= MSF_TRIGGERSPECIAL_TOUCH;
+		}
+
+		// Process deprecated binary sector specials
+		if (udmf || !sector->special)
 			continue;
 
 		// Process Section 1
 		switch(GETSECSPECIAL(sector->special, 1))
 		{
-			case 5: // Spikes
-				//Terrible hack to replace an even worse hack:
-				//Spike damage automatically sets MSF_TRIGGERSPECIAL_TOUCH.
-				//Yes, this also affects other specials on the same sector. Sorry.
-				sector->flags |= MSF_TRIGGERSPECIAL_TOUCH;
-				break;
 			case 15: // Bouncy FOF
-				if (udmf)
-					break;
-				CONS_Alert(CONS_WARNING, M_GetText("Deprecated bouncy FOF sector type detected. Please use linedef type 76 instead.\n"));
 				CheckForBouncySector = true;
 				break;
 		}
@@ -6224,17 +6245,11 @@ void P_SpawnSpecials(boolean fromnetsave)
 		switch(GETSECSPECIAL(sector->special, 2))
 		{
 			case 10: // Time for special stage
-				if (udmf)
-					break;
-				CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for special stage requirements detected. Please use the SpecialStageTime and SpecialStageSpheres level header options instead.\n"));
 				sstimer = (sector->floorheight>>FRACBITS) * TICRATE + 6; // Time to finish
 				ssspheres = sector->ceilingheight>>FRACBITS; // Ring count for special stage
 				break;
 
 			case 11: // Custom global gravity!
-				if (udmf)
-					break;
-				CONS_Alert(CONS_WARNING, M_GetText("Deprecated sector type for global gravity detected. Please use the Gravity level header option instead.\n"));
 				gravity = sector->floorheight/1000;
 				break;
 		}
diff --git a/src/p_spec.h b/src/p_spec.h
index cd97efa1a7486b5c0afb1b3ae0294fac69c1cb6b..779afdd0537765347b502d55be06583dd7a728d1 100644
--- a/src/p_spec.h
+++ b/src/p_spec.h
@@ -496,6 +496,7 @@ void P_SpawnSpecials(boolean fromnetsave);
 // every tic
 void P_UpdateSpecials(void);
 sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number);
+sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);
 sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag);
 sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 number);
 sector_t *P_PlayerTouchingSectorSpecialFlag(player_t *player, sectorspecialflags_t flag);
diff --git a/src/p_user.c b/src/p_user.c
index bdb164484141fb2d8c1cb5d2dd00ce4afd124532..60a0f5106c95cd4421c20556f662b7f95f4dec4b 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1,4 +1,3 @@
-
 // SONIC ROBO BLAST 2
 //-----------------------------------------------------------------------------
 // Copyright (C) 1993-1996 by id Software, Inc.
@@ -3108,14 +3107,25 @@ static void P_DoPlayerHeadSigns(player_t *player)
 	if (G_TagGametype())
 	{
 		// If you're "IT", show a big "IT" over your head for others to see.
-		if (player->pflags & PF_TAGIT)
+		if (player->pflags & PF_TAGIT && !P_IsLocalPlayer(player))
 		{
-			if (!P_IsLocalPlayer(player)) // Don't display it on your own view.
+			mobj_t* it = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_TAG);
+			it->x = player->mo->x;
+			it->y = player->mo->y;
+			it->z = player->mo->z;
+			it->old_x = player->mo->old_x;
+			it->old_y = player->mo->old_y;
+			it->old_z = player->mo->old_z;
+
+			if (!(player->mo->eflags & MFE_VERTICALFLIP))
 			{
-				if (!(player->mo->eflags & MFE_VERTICALFLIP))
-					P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height, MT_TAG);
-				else
-					P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z - mobjinfo[MT_TAG].height, MT_TAG)->eflags |= MFE_VERTICALFLIP;
+				it->z += player->mo->height;
+				it->old_z += player->mo->height;
+			}
+			else
+			{
+				it->z -= mobjinfo[MT_TAG].height;
+				it->old_z -= mobjinfo[MT_TAG].height;
 			}
 		}
 	}
@@ -3125,15 +3135,32 @@ static void P_DoPlayerHeadSigns(player_t *player)
 		// has it (but not on your own screen if you have the flag).
 		if (splitscreen || player != &players[consoleplayer])
 		{
-			mobj_t *sign = P_SpawnMobj(player->mo->x+player->mo->momx, player->mo->y+player->mo->momy,
-					player->mo->z+player->mo->momz, MT_GOTFLAG);
-			if (player->mo->eflags & MFE_VERTICALFLIP)
+			fixed_t zofs;
+			mobj_t *sign;
+			boolean player_is_flipped = (player->mo->eflags & MFE_VERTICALFLIP) > 0;
+
+			zofs = player->mo->momz;
+			if (player_is_flipped)
 			{
-				sign->z += player->mo->height-P_GetPlayerHeight(player)-mobjinfo[MT_GOTFLAG].height-FixedMul(16*FRACUNIT, player->mo->scale);
-				sign->eflags |= MFE_VERTICALFLIP;
+				zofs += player->mo->height - P_GetPlayerHeight(player) - mobjinfo[MT_GOTFLAG].height - FixedMul(16 * FRACUNIT, player->mo->scale);
 			}
 			else
-				sign->z += P_GetPlayerHeight(player)+FixedMul(16*FRACUNIT, player->mo->scale);
+			{
+				zofs += P_GetPlayerHeight(player) + FixedMul(16 * FRACUNIT, player->mo->scale);
+			}
+
+			sign = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, MT_GOTFLAG);
+			sign->x = player->mo->x;
+			sign->y = player->mo->y;
+			sign->z = player->mo->z + zofs;
+			sign->old_x = player->mo->old_x;
+			sign->old_y = player->mo->old_y;
+			sign->old_z = player->mo->old_z + zofs;
+
+			if (player_is_flipped)
+			{
+				sign->eflags |= MFE_VERTICALFLIP;
+			}
 
 			if (player->gotflag & GF_REDFLAG)
 				sign->frame = 1|FF_FULLBRIGHT;
@@ -11281,6 +11308,11 @@ static void P_DoTailsOverlay(player_t *player, mobj_t *tails)
 	tails->y = player->mo->y + P_ReturnThrustY(tails, tails->angle, FixedMul(backwards, tails->scale));
 	tails->z = player->mo->z + zoffs;
 	P_SetThingPosition(tails);
+	
+	if (player->mo->flags2 & MF2_SHADOW)
+		tails->flags2 |= MF2_SHADOW;
+	else
+		tails->flags2 &= ~MF2_SHADOW;
 }
 
 // Metal Sonic's jet fume
@@ -12028,7 +12060,6 @@ void P_PlayerThink(player_t *player)
 	P_DoBubbleBreath(player); // Spawn Sonic's bubbles
 	P_CheckUnderwaterAndSpaceTimer(player); // Display the countdown drown numbers!
 	P_CheckInvincibilityTimer(player); // Spawn Invincibility Sparkles
-	P_DoPlayerHeadSigns(player); // Spawn Tag/CTF signs over player's head
 
 #if 1
 	// "Blur" a bit when you have speed shoes and are going fast enough
@@ -12893,6 +12924,8 @@ void P_PlayerAfterThink(player_t *player)
 			}
 		}
 	}
+
+	P_DoPlayerHeadSigns(player); // Spawn Tag/CTF signs over player's head
 }
 
 void P_SetPlayerAngle(player_t *player, angle_t angle)
diff --git a/src/taglist.c b/src/taglist.c
index 305b05f041b189fed25ba6c49e6f43ecb4577300..4050076140149fe3a5ca74dba16e129d1961b24d 100644
--- a/src/taglist.c
+++ b/src/taglist.c
@@ -472,5 +472,5 @@ mtag_t Tag_NextUnused(mtag_t start)
 		start++;
 	}
 
-	return MAXTAGS;
+	return (mtag_t)MAXTAGS;
 }