diff --git a/CMakeLists.txt b/CMakeLists.txt
index dd970391410c3cea7fb0b29b0d8a7bb3f00a62d1..8bbf46945f0eb0f561702ef014e96dfd3d72ce96 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -95,7 +95,6 @@ set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
 
 # Set EXE names so the assets CMakeLists can refer to its target
 set(SRB2_SDL2_EXE_NAME srb2 CACHE STRING "Executable binary output name")
-set(SRB2_WIN_EXE_NAME srb2dd CACHE STRING "Executable binary output name for DirectDraw build")
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 97feae18bbda248b274a9e3c0b1797b97260b790..e8c9c31820c3ba1fcf46691cff5f4476df98220c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -518,10 +518,6 @@ add_definitions(-DCMAKECONFIG)
 
 add_subdirectory(sdl)
 
-if(${CMAKE_SYSTEM} MATCHES Windows)
-	add_subdirectory(win32)
-endif()
-
-if(NOT ${SRB2_SDL2_AVAILABLE} AND NOT ${SRB2_WIN32_AVAILABLE})
+if(NOT ${SRB2_SDL2_AVAILABLE})
 	message(FATAL_ERROR "There are no targets available to build an SRB2 executable. :(")
 endif()
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index e80d07b767b6874cd99d83b7e651446b90b0ef69..00cb6e65eb901aecd0d42aeec4f6d8f91c27e78b 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -1907,7 +1907,7 @@ static void Command_Map_f(void)
 		}
 	}
 
-	if (newmapnum == 0 || !mapheaderinfo[newmapnum-1])
+	if (newmapnum == 0)
 	{
 		CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
 		Z_Free(mapname);
diff --git a/src/dehacked.c b/src/dehacked.c
index 175c1fcfac2264ba105b6559e83bc186ff300383..938699516d20bb29eb9df793091e8bd3f21d0c75 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -10479,12 +10479,84 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"paused")) {
 		lua_pushboolean(L, paused);
 		return 1;
+	// begin map vars
+	} else if (fastcmp(word,"spstage_start")) {
+		lua_pushinteger(L, spstage_start);
+		return 1;
+	} else if (fastcmp(word,"sstage_start")) {
+		lua_pushinteger(L, sstage_start);
+		return 1;
+	} else if (fastcmp(word,"sstage_end")) {
+		lua_pushinteger(L, sstage_end);
+		return 1;
+	} else if (fastcmp(word,"smpstage_start")) {
+		lua_pushinteger(L, smpstage_start);
+		return 1;
+	} else if (fastcmp(word,"smpstage_end")) {
+		lua_pushinteger(L, smpstage_end);
+		return 1;
 	} else if (fastcmp(word,"titlemap")) {
 		lua_pushinteger(L, titlemap);
 		return 1;
 	} else if (fastcmp(word,"titlemapinaction")) {
 		lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
 		return 1;
+	} else if (fastcmp(word,"bootmap")) {
+		lua_pushinteger(L, bootmap);
+		return 1;
+	} else if (fastcmp(word,"tutorialmap")) {
+		lua_pushinteger(L, tutorialmap);
+		return 1;
+	} else if (fastcmp(word,"tutorialmode")) {
+		lua_pushboolean(L, tutorialmode);
+		return 1;
+	// end map vars
+	// begin CTF colors
+	} else if (fastcmp(word,"skincolor_redteam")) {
+		lua_pushinteger(L, skincolor_redteam);
+		return 1;
+	} else if (fastcmp(word,"skincolor_blueteam")) {
+		lua_pushinteger(L, skincolor_blueteam);
+		return 1;
+	} else if (fastcmp(word,"skincolor_redring")) {
+		lua_pushinteger(L, skincolor_redring);
+		return 1;
+	} else if (fastcmp(word,"skincolor_bluering")) {
+		lua_pushinteger(L, skincolor_bluering);
+		return 1;
+	// end CTF colors
+	// begin timers
+	} else if (fastcmp(word,"invulntics")) {
+		lua_pushinteger(L, invulntics);
+		return 1;
+	} else if (fastcmp(word,"sneakertics")) {
+		lua_pushinteger(L, sneakertics);
+		return 1;
+	} else if (fastcmp(word,"flashingtics")) {
+		lua_pushinteger(L, flashingtics);
+		return 1;
+	} else if (fastcmp(word,"tailsflytics")) {
+		lua_pushinteger(L, tailsflytics);
+		return 1;
+	} else if (fastcmp(word,"underwatertics")) {
+		lua_pushinteger(L, underwatertics);
+		return 1;
+	} else if (fastcmp(word,"spacetimetics")) {
+		lua_pushinteger(L, spacetimetics);
+		return 1;
+	} else if (fastcmp(word,"extralifetics")) {
+		lua_pushinteger(L, extralifetics);
+		return 1;
+	} else if (fastcmp(word,"nightslinktics")) {
+		lua_pushinteger(L, nightslinktics);
+		return 1;
+	} else if (fastcmp(word,"gameovertics")) {
+		lua_pushinteger(L, gameovertics);
+		return 1;
+	} else if (fastcmp(word,"ammoremovaltics")) {
+		lua_pushinteger(L, ammoremovaltics);
+		return 1;
+	// end timers
 	} else if (fastcmp(word,"gametype")) {
 		lua_pushinteger(L, gametype);
 		return 1;
diff --git a/src/lua_hud.h b/src/lua_hud.h
index abfbba4413a399471f0b0b9ae93205e41179a920..23e3ef8348c5e5d8e746f6a8d0f3fd5b0b1df8fc 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -21,6 +21,7 @@ enum hud {
 	// Match / CTF / Tag / Ringslinger
 	hud_weaponrings,
 	hud_powerstones,
+	hud_teamscores,
 	// NiGHTS mode
 	hud_nightslink,
 	hud_nightsdrill,
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index a2f48c4ad5d2daced33e46e3f0f830e2a39b8f98..5b5aa3b4ba277ed00f81cb0113a66a905f4627f5 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -48,6 +48,7 @@ static const char *const hud_disable_options[] = {
 
 	"weaponrings",
 	"powerstones",
+	"teamscores",
 
 	"nightslink",
 	"nightsdrill",
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 0fe1df0b61daf5f9a3bf5a6abec3daeaf591c5dc..b35bb6a41cbaddd7cd09d3095f1e60accf4ac87a 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -445,7 +445,7 @@ static int sectorlines_get(lua_State *L)
 	// get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result
 	// we need this to determine the array's actual size, and therefore also the maximum value allowed as an index
 	// this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy
-	numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
+	numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
 
 /* OLD HACK
 	// check first linedef to figure which of its sectors owns this sector->lines pointer
@@ -479,7 +479,7 @@ static int sectorlines_num(lua_State *L)
 		return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
 
 	// see comments in the _get function above
-	numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
+	numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
 	lua_pushinteger(L, numoflines);
 	return 1;
 }
diff --git a/src/m_cheat.c b/src/m_cheat.c
index e31ce7869cefba560717f813e0b5480c8859d671..0451a5fb3abeb61714a054253065f9066cdcadb4 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1106,7 +1106,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 #else
 		fixed_t cheight = sec->ceilingheight;
 #endif
-		mt->options = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
+		mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
 	}
 	else
 	{
@@ -1115,12 +1115,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
 #else
 		fixed_t fheight = sec->floorheight;
 #endif
-		mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS);
+		mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS);
 	}
-	mt->options <<= ZSHIFT;
 	mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle)));
 
-	mt->options |= (UINT16)cv_opflags.value;
+	mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
 	return mt;
 }
 
diff --git a/src/m_menu.c b/src/m_menu.c
index f20a8e22e055ec8334a4934a02289cf34bd3b6e8..23dc10701c0cb9ffd451eb392619b7d7128770f3 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -6370,11 +6370,7 @@ static void M_PandorasBox(INT32 choice)
 	else
 		CV_StealthSetValue(&cv_dummylives, max(players[consoleplayer].lives, 1));
 	CV_StealthSetValue(&cv_dummycontinues, players[consoleplayer].continues);
-	SR_PandorasBox[6].status = ((players[consoleplayer].charflags & SF_SUPER)
-#ifndef DEVELOP
-	|| cv_skin.value == 1
-#endif
-	) ? (IT_GRAYEDOUT) : (IT_STRING | IT_CALL);
+	SR_PandorasBox[6].status = (players[consoleplayer].charflags & SF_SUPER) ? (IT_GRAYEDOUT) : (IT_STRING | IT_CALL);
 	SR_PandorasBox[7].status = (emeralds == ((EMERALD7)*2)-1) ? (IT_GRAYEDOUT) : (IT_STRING | IT_CALL);
 	M_SetupNextMenu(&SR_PandoraDef);
 }
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 74a11fe6735027ad018f110a031ffdc82e274f0a..5361f453b574620829eaf3f98ad353d9cf085f9a 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -14712,20 +14712,35 @@ void A_DragonWing(mobj_t *actor)
 void A_DragonSegment(mobj_t *actor)
 {
 	mobj_t *target = actor->target;
-	fixed_t dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
-	fixed_t radius = actor->radius + target->radius;
-	angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
-	angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z);
-	fixed_t hdist = P_ReturnThrustX(target, zangle, radius);
-	fixed_t xdist = P_ReturnThrustX(target, hangle, hdist);
-	fixed_t ydist = P_ReturnThrustY(target, hangle, hdist);
-	fixed_t zdist = P_ReturnThrustY(target, zangle, radius);
+	fixed_t dist;
+	fixed_t radius;
+	angle_t hangle;
+	angle_t zangle;
+	fixed_t hdist;
+	fixed_t xdist;
+	fixed_t ydist;
+	fixed_t zdist;
 
 	#ifdef HAVE_BLUA
 		if (LUA_CallAction("A_DragonSegment", actor))
 			return;
 	#endif
 
+	if (target == NULL || !target->health)
+	{
+		P_RemoveMobj(actor);
+		return;
+	}
+
+	dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
+	radius = actor->radius + target->radius;
+	hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
+	zangle = R_PointToAngle2(0, target->z, dist, actor->z);
+	hdist = P_ReturnThrustX(target, zangle, radius);
+	xdist = P_ReturnThrustX(target, hangle, hdist);
+	ydist = P_ReturnThrustY(target, hangle, hdist);
+	zdist = P_ReturnThrustY(target, zangle, radius);
+
 	actor->angle = hangle;
 	P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
 }
diff --git a/src/p_mobj.c b/src/p_mobj.c
index a6812ff01b631c663d30c263e8882b86a93f56a6..06d8aa3f54b5378a7ba1f063cb42781debda19ed 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11551,6 +11551,82 @@ void P_MovePlayerToStarpost(INT32 playernum)
 mapthing_t *huntemeralds[MAXHUNTEMERALDS];
 INT32 numhuntemeralds;
 
+
+static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y)
+{
+	const subsector_t *ss = R_PointInSubsector(x, y);
+	fixed_t offset = mthing->z << FRACBITS;
+	boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP));
+
+	switch (mobjtype)
+	{
+	// Bumpers never spawn flipped.
+	case MT_NIGHTSBUMPER:
+		flip = false;
+		break;
+
+	// Axis objects snap to the floor.
+	case MT_AXIS:
+	case MT_AXISTRANSFER:
+	case MT_AXISTRANSFERLINE:
+		return ONFLOORZ;
+
+	// Objects with a non-zero default height.
+	case MT_CRAWLACOMMANDER:
+	case MT_DETON:
+	case MT_JETTBOMBER:
+	case MT_JETTGUNNER:
+	case MT_EGGMOBILE2:
+		if (!offset)
+			offset = 33*FRACUNIT;
+		break;
+	case MT_EGGMOBILE:
+		if (!offset)
+			offset = 128*FRACUNIT;
+		break;
+	case MT_GOLDBUZZ:
+	case MT_REDBUZZ:
+		if (!offset)
+			offset = 288*FRACUNIT;
+		break;
+
+	// Ring-like items, may float additional units with MTF_AMBUSH.
+	case MT_SPIKEBALL:
+	case MT_EMERALDSPAWN:
+	case MT_TOKEN:
+	case MT_EMBLEM:
+		offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0;
+		break;
+
+	// Remaining objects.
+	default:
+		if (P_WeaponOrPanel(mobjtype))
+			offset += mthing->options & MTF_AMBUSH ? 24 * FRACUNIT : 0;
+	}
+
+	if (!offset) // Snap to the surfaces when there's no offset set.
+	{
+		if (flip)
+			return ONCEILINGZ;
+		else
+			return ONFLOORZ;
+	}
+
+	// Establish height.
+	if (flip)
+		return (
+#ifdef ESLOPE
+			ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
+#endif
+			ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height;
+	else
+		return (
+#ifdef ESLOPE
+			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
+#endif
+			ss->sector->floorheight) + offset;
+}
+
 //
 // P_SpawnMapThing
 // The fields of the mapthing should
@@ -11561,7 +11637,6 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	mobjtype_t i;
 	mobj_t *mobj;
 	fixed_t x, y, z;
-	subsector_t *ss;
 	boolean doangle = true;
 
 	if (!mthing->type)
@@ -11686,13 +11761,6 @@ You should think about modifying the deathmatch starts to take full advantage of
 		if (gametype != GT_COOP)
 			return;
 
-		ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS);
-		mthing->z = (INT16)(((
-#ifdef ESLOPE
-								ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, mthing->x << FRACBITS, mthing->y << FRACBITS) :
-#endif
-								ss->sector->floorheight)>>FRACBITS) + (mthing->options >> ZSHIFT));
-
 		if (numhuntemeralds < MAXHUNTEMERALDS)
 			huntemeralds[numhuntemeralds++] = mthing;
 		return;
@@ -11821,102 +11889,7 @@ You should think about modifying the deathmatch starts to take full advantage of
 	// spawn it
 	x = mthing->x << FRACBITS;
 	y = mthing->y << FRACBITS;
-	ss = R_PointInSubsector(x, y);
-
-	if (i == MT_NIGHTSBUMPER)
-		z = (
-#ifdef ESLOPE
-			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
-#endif
-			ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS);
-	else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE)
-		z = ONFLOORZ;
-	else if (i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN || i == MT_EMBLEM)
-	{
-		if (mthing->options & MTF_OBJECTFLIP)
-		{
-			z = (
-#ifdef ESLOPE
-			ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
-#endif
-			ss->sector->ceilingheight);
-
-			if (mthing->options & MTF_AMBUSH) // Special flag for rings
-				z -= 24*FRACUNIT;
-			if (mthing->options >> ZSHIFT)
-				z -= (mthing->options >> ZSHIFT)*FRACUNIT;
-
-			z -= mobjinfo[i].height; //Don't forget the height!
-		}
-		else
-		{
-			z = (
-#ifdef ESLOPE
-			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
-#endif
-			ss->sector->floorheight);
-
-			if (mthing->options & MTF_AMBUSH) // Special flag for rings
-				z += 24*FRACUNIT;
-			if (mthing->options >> ZSHIFT)
-				z += (mthing->options >> ZSHIFT)*FRACUNIT;
-		}
-
-		if (z == ONFLOORZ)
-			mthing->z = 0;
-		else
-			mthing->z = (INT16)(z>>FRACBITS);
-	}
-	else
-	{
-		fixed_t offset = 0;
-		boolean flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP));
-
-		// base positions
-		if (flip)
-			z = (
-#ifdef ESLOPE
-			ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
-#endif
-			ss->sector->ceilingheight) - mobjinfo[i].height;
-		else
-			z = (
-#ifdef ESLOPE
-			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
-#endif
-			ss->sector->floorheight);
-
-		// offsetting
-		if (mthing->options >> ZSHIFT)
-			offset = ((mthing->options >> ZSHIFT) << FRACBITS);
-		else if (i == MT_CRAWLACOMMANDER || i == MT_DETON || i == MT_JETTBOMBER || i == MT_JETTGUNNER || i == MT_EGGMOBILE2)
-			offset = 33*FRACUNIT;
-		else if (i == MT_EGGMOBILE)
-			offset = 128*FRACUNIT;
-		else if (i == MT_GOLDBUZZ || i == MT_REDBUZZ)
-			offset = 288*FRACUNIT;
-
-		// applying offsets! (if any)
-		if (flip)
-		{
-			if (offset)
-				z -= offset;
-			else
-				z = ONCEILINGZ;
-		}
-		else
-		{
-			if (offset)
-				z += offset;
-			else
-				z = ONFLOORZ;
-		}
-
-		if (z == ONFLOORZ)
-			mthing->z = 0;
-		else
-			mthing->z = (INT16)(z>>FRACBITS);
-	}
+	z = P_GetMobjSpawnHeight(i, mthing, x, y);
 
 	mobj = P_SpawnMobj(x, y, z, i);
 	mobj->spawnpoint = mthing;
@@ -12020,7 +11993,7 @@ You should think about modifying the deathmatch starts to take full advantage of
 		if (mthing->angle)
 			mobj->health = mthing->angle;
 		else
-			mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS;
+			mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS;
 		break;
 	case MT_METALSONIC_RACE:
 	case MT_METALSONIC_BATTLE:
@@ -13106,7 +13079,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 		mobj_t *hoopcenter;
 		INT16 spewangle;
 
-		z = mthing->options << FRACBITS;
+		z = mthing->z << FRACBITS;
 
 		hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
 
@@ -13246,8 +13219,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 		INT32 hoopsize;
 		INT32 hoopplacement;
 
-		// Save our flags!
-		z = (mthing->options>>ZSHIFT) << FRACBITS;
+		z = mthing->z << FRACBITS;
 
 		hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
 		hoopcenter->spawnpoint = mthing;
@@ -13389,8 +13361,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
 #endif
 				sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->options >> ZSHIFT)
-				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z -= (mthing->z << FRACBITS);
 			}
 		else
 		{
@@ -13399,8 +13371,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
 				sec->floorheight);
-			if (mthing->options >> ZSHIFT)
-				z += ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z += (mthing->z << FRACBITS);
 		}
 
 		for (r = 1; r <= 5; r++)
@@ -13449,8 +13421,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
 #endif
 				sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->options >> ZSHIFT)
-				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z -= (mthing->z << FRACBITS);
 			}
 		else
 		{
@@ -13459,8 +13431,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
 				sec->floorheight);
-			if (mthing->options >> ZSHIFT)
-				z += ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z += (mthing->z << FRACBITS);
 		}
 
 		for (r = 1; r <= iterations; r++)
@@ -13506,8 +13478,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
 			sec->floorheight;
-		if (mthing->options >> ZSHIFT)
-			z += ((mthing->options >> ZSHIFT) << FRACBITS);
+		if (mthing->z)
+			z += (mthing->z << FRACBITS);
 
 		closestangle = FixedAngle(mthing->angle*FRACUNIT);
 
@@ -13611,8 +13583,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
 #endif
 			sec->ceilingheight) - mobjinfo[ringthing].height;
-			if (mthing->options >> ZSHIFT)
-				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z -= (mthing->z << FRACBITS);
 		}
 		else
 		{
@@ -13621,8 +13593,8 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
 			sec->floorheight;
-			if (mthing->options >> ZSHIFT)
-				z += ((mthing->options >> ZSHIFT) << FRACBITS);
+			if (mthing->z)
+				z += (mthing->z << FRACBITS);
 		}
 
 		if (mthing->options & MTF_AMBUSH) // Special flag for rings
@@ -13633,8 +13605,6 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 				z += 24*FRACUNIT;
 		}
 
-		mthing->z = (INT16)(z>>FRACBITS);
-
 		mobj = P_SpawnMobj(x, y, z, ringthing);
 		mobj->spawnpoint = mthing;
 
diff --git a/src/p_setup.c b/src/p_setup.c
index bf3493d8c2ab5c99ccf79cbceeb8393b71b29a73..9528307d6f81e9bd52a45f8a1927cad8f0185e98 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -906,10 +906,6 @@ void P_ReloadRings(void)
 		{
 			mt->mobj = NULL;
 
-			// Z for objects Tails 05-26-2002
-			mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
-				->sector->floorheight>>FRACBITS);
-
 			P_SpawnHoopsAndRings(mt, true);
 		}
 	}
@@ -1013,13 +1009,11 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
 	nummapthings = i / (5 * sizeof (INT16));
 	mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
 
-	// Spawn axis points first so they are
-	// at the front of the list for fast searching.
-	mt = mapthings;
-	for (i = 0; i < nummapthings; i++, mt++)
+	for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
 	{
 		mt->x = READINT16(data);
 		mt->y = READINT16(data);
+
 		mt->angle = READINT16(data);
 		mt->type = READUINT16(data);
 		mt->options = READUINT16(data);
@@ -1027,17 +1021,10 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
 
 		mt->type &= 4095;
 
-		switch (mt->type)
-		{
-			case 1700: // MT_AXIS
-			case 1701: // MT_AXISTRANSFER
-			case 1702: // MT_AXISTRANSFERLINE
-				mt->mobj = NULL;
-				P_SpawnMapThing(mt);
-				break;
-			default:
-				break;
-		}
+		if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo))
+			mt->z = mt->options; // NiGHTS Hoops use the full flags bits to set the height.
+		else
+			mt->z = mt->options >> ZSHIFT;
 	}
 }
 
@@ -1048,26 +1035,76 @@ static void P_PrepareThings(lumpnum_t lumpnum)
 	Z_Free(data);
 }
 
+static void P_SpawnEmeraldHunt(void)
+{
+	INT32 emer1, emer2, emer3;
+	INT32 timeout = 0; // keeps from getting stuck
+
+	emer1 = emer2 = emer3 = 0;
+
+	//increment spawn numbers because zero is valid.
+	emer1 = (P_RandomKey(numhuntemeralds)) + 1;
+	while (timeout++ < 100)
+	{
+		emer2 = (P_RandomKey(numhuntemeralds)) + 1;
+
+		if (emer2 != emer1)
+			break;
+	}
+
+	timeout = 0;
+	while (timeout++ < 100)
+	{
+		emer3 = (P_RandomKey(numhuntemeralds)) + 1;
+
+		if (emer3 != emer2 && emer3 != emer1)
+			break;
+	}
+
+	//decrement spawn values to the actual number because zero is valid.
+	if (emer1--)
+		P_SpawnMobj(huntemeralds[emer1]->x<<FRACBITS,
+			huntemeralds[emer1]->y<<FRACBITS,
+			huntemeralds[emer1]->z<<FRACBITS, MT_EMERHUNT);
+
+	if (emer2--)
+		P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer2]->x<<FRACBITS,
+			huntemeralds[emer2]->y<<FRACBITS,
+			huntemeralds[emer2]->z<<FRACBITS, MT_EMERHUNT),
+		mobjinfo[MT_EMERHUNT].spawnstate+1);
+
+	if (emer3--)
+		P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer3]->x<<FRACBITS,
+			huntemeralds[emer3]->y<<FRACBITS,
+			huntemeralds[emer3]->z<<FRACBITS, MT_EMERHUNT),
+		mobjinfo[MT_EMERHUNT].spawnstate+2);
+}
+
 static void P_LoadThings(boolean loademblems)
 {
 	size_t i;
 	mapthing_t *mt;
 
-	// Loading the things lump itself into memory is now handled in P_PrepareThings, above
-
-	mt = mapthings;
-	numhuntemeralds = 0;
-	for (i = 0; i < nummapthings; i++, mt++)
+	// Spawn axis points first so they are at the front of the list for fast searching.
+	for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
 	{
-		sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector;
+		switch (mt->type)
+		{
+			case 1700: // MT_AXIS
+			case 1701: // MT_AXISTRANSFER
+			case 1702: // MT_AXISTRANSFERLINE
+				mt->mobj = NULL;
+				P_SpawnMapThing(mt);
+				break;
+			default:
+				break;
+		}
+	}
 
-		// Z for objects
-		mt->z = (INT16)(
-#ifdef ESLOPE
-				mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) :
-#endif
-				mtsector->floorheight)>>FRACBITS;
+	numhuntemeralds = 0;
 
+	for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
+	{
 		if (mt->type == 1700 // MT_AXIS
 			|| mt->type == 1701 // MT_AXISTRANSFER
 			|| mt->type == 1702) // MT_AXISTRANSFERLINE
@@ -1082,49 +1119,7 @@ static void P_LoadThings(boolean loademblems)
 
 	// random emeralds for hunt
 	if (numhuntemeralds)
-	{
-		INT32 emer1, emer2, emer3;
-		INT32 timeout = 0; // keeps from getting stuck
-
-		emer1 = emer2 = emer3 = 0;
-
-		//increment spawn numbers because zero is valid.
-		emer1 = (P_RandomKey(numhuntemeralds)) + 1;
-		while (timeout++ < 100)
-		{
-			emer2 = (P_RandomKey(numhuntemeralds)) + 1;
-
-			if (emer2 != emer1)
-				break;
-		}
-
-		timeout = 0;
-		while (timeout++ < 100)
-		{
-			emer3 = (P_RandomKey(numhuntemeralds)) + 1;
-
-			if (emer3 != emer2 && emer3 != emer1)
-				break;
-		}
-
-		//decrement spawn values to the actual number because zero is valid.
-		if (emer1--)
-			P_SpawnMobj(huntemeralds[emer1]->x<<FRACBITS,
-				huntemeralds[emer1]->y<<FRACBITS,
-				huntemeralds[emer1]->z<<FRACBITS, MT_EMERHUNT);
-
-		if (emer2--)
-			P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer2]->x<<FRACBITS,
-				huntemeralds[emer2]->y<<FRACBITS,
-				huntemeralds[emer2]->z<<FRACBITS, MT_EMERHUNT),
-			mobjinfo[MT_EMERHUNT].spawnstate+1);
-
-		if (emer3--)
-			P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer3]->x<<FRACBITS,
-				huntemeralds[emer3]->y<<FRACBITS,
-				huntemeralds[emer3]->z<<FRACBITS, MT_EMERHUNT),
-			mobjinfo[MT_EMERHUNT].spawnstate+2);
-	}
+		P_SpawnEmeraldHunt();
 
 	if (metalrecording) // Metal Sonic gets no rings to distract him.
 		return;
@@ -1140,11 +1135,6 @@ static void P_LoadThings(boolean loademblems)
 		 || mt->type == 1705 || mt->type == 1713) // hoops
 		{
 			mt->mobj = NULL;
-
-			// Z for objects Tails 05-26-2002
-			mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
-				->sector->floorheight>>FRACBITS);
-
 			P_SpawnHoopsAndRings(mt, false);
 		}
 	}
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index f1aa135b9eafd520e0700835b9c509898f22bef3..38d557a3f59517b33b256db39aecff4ed3d6ddb9 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -140,7 +140,13 @@ if(${SDL2_FOUND})
 	endif()
 
 	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
-	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
+	if(${CMAKE_SYSTEM} MATCHES Windows)
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2win)
+	elseif(${CMAKE_SYSTEM} MATCHES Linux)
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME lsdlsrb2)
+	else()
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME srb2)
+	endif()
 
 	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		find_library(CORE_LIB CoreFoundation)
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 1b8107edb89ff57751eadb7f96c869f01efb3f47..1b116a7f3d276891088122de4b7b4cace36136d1 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -2320,14 +2320,20 @@ static void ST_drawTeamHUD(void)
 		p = bflagico;
 	else
 		p = bmatcico;
-
+	
+#ifdef HAVE_BLUA
+	if (LUA_HudEnabled(hud_teamscores))
+#endif
 	V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
-
+	
 	if (gametype == GT_CTF)
 		p = rflagico;
 	else
 		p = rmatcico;
-
+	
+#ifdef HAVE_BLUA
+	if (LUA_HudEnabled(hud_teamscores))
+#endif
 	V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
 
 	if (gametype != GT_CTF)
@@ -2339,28 +2345,53 @@ static void ST_drawTeamHUD(void)
 		// Show which flags aren't at base.
 		for (i = 0; i < MAXPLAYERS; i++)
 		{
-			if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base
+			if (players[i].gotflag & GF_BLUEFLAG // Blue flag isn't at base
+#ifdef HAVE_BLUA
+			&& LUA_HudEnabled(hud_teamscores)
+#endif
+			)
 				V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon);
-			if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base
+
+			if (players[i].gotflag & GF_REDFLAG // Red flag isn't at base
+#ifdef HAVE_BLUA
+			&& LUA_HudEnabled(hud_teamscores)
+#endif
+			)
 				V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2);
 
 			whichflag |= players[i].gotflag;
+
 			if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG))
 				break; // both flags were found, let's stop early
 		}
 
 		// Display a countdown timer showing how much time left until the flag returns to base.
 		{
-			if (blueflag && blueflag->fuse > 1)
+			if (blueflag && blueflag->fuse > 1
+#ifdef HAVE_BLUA
+			&& LUA_HudEnabled(hud_teamscores)
+#endif
+			)
 				V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE)));
 
-			if (redflag && redflag->fuse > 1)
+			if (redflag && redflag->fuse > 1
+#ifdef HAVE_BLUA
+			&& LUA_HudEnabled(hud_teamscores)
+#endif
+			)
 				V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE)));
 		}
 	}
 
 num:
+#ifdef HAVE_BLUA
+	if (LUA_HudEnabled(hud_teamscores))
+#endif
 	V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore));
+
+#ifdef HAVE_BLUA
+	if (LUA_HudEnabled(hud_teamscores))
+#endif
 	V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore));
 
 #undef SEP