diff --git a/src/f_finale.h b/src/f_finale.h
index c0c6360c316186698c1c78b200d56b3399f121f8..29e9b4d8c8676a827b58afc786b53b11ef68bd8f 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -82,7 +82,6 @@ typedef enum
 
 // Current menu parameters
 
-extern UINT8 titlemapinaction;
 extern mobj_t *titlemapcameraref;
 extern char curbgname[8];
 extern SINT8 curfadevalue;
diff --git a/src/g_game.c b/src/g_game.c
index 95cc2288d3dab64873657fdd50bc45c04c1ef008..3cb5da1b5ba367f04f4e7c36d8e01d527ee3c401 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -4366,7 +4366,7 @@ void G_WriteGhostTic(mobj_t *ghost)
 		ghostext.flags = 0;
 	}
 
-	if (ghost->player && ghost->player->followmobj)
+	if (ghost->player && ghost->player->followmobj) // bloats tails runs but what can ya do
 	{
 		INT16 temp;
 
@@ -4592,6 +4592,9 @@ void G_GhostTicker(void)
 				switch(g->color)
 				{
 				default:
+				case GHC_RETURNSKIN:
+					g->mo->skin = g->oldmo.skin;
+					// fallthru
 				case GHC_NORMAL: // Go back to skin color
 					g->mo->color = g->oldmo.color;
 					break;
@@ -4602,6 +4605,9 @@ void G_GhostTicker(void)
 				case GHC_FIREFLOWER: // Fireflower
 					g->mo->color = SKINCOLOR_WHITE;
 					break;
+				case GHC_NIGHTSSKIN: // not actually a colour
+					g->mo->skin = &skins[DEFAULTNIGHTSSKIN];
+					break;
 				}
 			}
 			if (xziptic & EZT_FLIP)
diff --git a/src/g_game.h b/src/g_game.h
index 3cbde9a3c689259a30959c8772c9299f536fad9e..96a192ee8a9aea77293a543dfd59c7747824cb46 100644
--- a/src/g_game.h
+++ b/src/g_game.h
@@ -140,7 +140,9 @@ typedef enum
 	GHC_NORMAL = 0,
 	GHC_SUPER,
 	GHC_FIREFLOWER,
-	GHC_INVINCIBLE
+	GHC_INVINCIBLE,
+	GHC_NIGHTSSKIN, // not actually a colour
+	GHC_RETURNSKIN // ditto
 } ghostcolor_t;
 
 // Record/playback tics
diff --git a/src/g_state.h b/src/g_state.h
index 76c9bd16f1e63e76cdd5b60c9d14fed560f765f1..7ee0cfb6347ad5dabe6759eb53052faa1c1e6332 100644
--- a/src/g_state.h
+++ b/src/g_state.h
@@ -50,6 +50,7 @@ typedef enum
 } gameaction_t;
 
 extern gamestate_t gamestate;
+extern UINT8 titlemapinaction;
 extern UINT8 ultimatemode; // was sk_insane
 extern gameaction_t gameaction;
 
diff --git a/src/info.c b/src/info.c
index a4446d65712972ef1cae87c3ee8a0a39f865f6a9..0ae723546a3ebbd65a10da50655b5ea78115b75c 100644
--- a/src/info.c
+++ b/src/info.c
@@ -1791,7 +1791,11 @@ state_t states[NUMSTATES] =
 
 	// Blue Sphere for special stages
 	{SPR_SPHR, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERE
-	{SPR_SPHR, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
+	{SPR_SPHR, FF_FULLBRIGHT
+#ifdef MANIASPHERES
+							|FF_ANIMATE|FF_RANDOMANIM
+#endif
+													, -1, {NULL}, 1, 4, S_NULL}, // S_BLUESPHEREBONUS
 	{SPR_SPHR, 0, 20, {NULL}, 0, 0, S_NULL}, // S_BLUESPHERESPARK
 
 	// Bomb Sphere
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 1d69b238bcb2558ab197fb81d0d7d3ee15935d3d..7d3ab2140c30417120f4f093ff4b465d91e76c53 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -33,8 +33,6 @@
 
 #define NOHUD if (hud_running)\
 return luaL_error(L, "HUD rendering code should not call this function!");
-#define INLEVEL if (gamestate != GS_LEVEL)\
-return luaL_error(L, "This function can only be used in a level!");
 
 boolean luaL_checkboolean(lua_State *L, int narg) {
 	luaL_checktype(L, narg, LUA_TBOOLEAN);
@@ -2047,12 +2045,22 @@ static int lib_pStartQuake(lua_State *L)
 
 static int lib_evCrumbleChain(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));
+	sector_t *sec = NULL;
+	ffloor_t *rover = NULL;
 	NOHUD
 	INLEVEL
-	if (!sec)
-		return LUA_ErrInvalid(L, "sector_t");
+	if (!lua_isnone(L, 2))
+	{
+		if (!lua_isnil(L, 1))
+		{
+			sec = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
+			if (!sec)
+				return LUA_ErrInvalid(L, "sector_t");
+		}
+		rover = *((ffloor_t **)luaL_checkudata(L, 2, META_FFLOOR));
+	}
+	else
+		rover = *((ffloor_t **)luaL_checkudata(L, 1, META_FFLOOR));
 	if (!rover)
 		return LUA_ErrInvalid(L, "ffloor_t");
 	EV_CrumbleChain(sec, rover);
diff --git a/src/lua_consolelib.c b/src/lua_consolelib.c
index 98d18d8db06713c4eed15cc9b5364d858956589d..c6856b426224b17f29f7fd26b122865ad0d51b51 100644
--- a/src/lua_consolelib.c
+++ b/src/lua_consolelib.c
@@ -28,9 +28,6 @@ return luaL_error(L, "HUD rendering code should not call this function!");
 // for functions not allowed in hooks or coroutines (supercedes above)
 #define NOHOOK if (!lua_lumploading)\
 		return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
-// for functions only allowed within a level
-#define INLEVEL if (gamestate != GS_LEVEL)\
-return luaL_error(L, "This function can only be used in a level!");
 
 static const char *cvname = NULL;
 
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index ded90daf08a8b5f76293f65c0af150fb455835d3..82843db4ee768a129f23e82e728d00964ffdcdde 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -333,8 +333,7 @@ static int lib_iterateSectorThinglist(lua_State *L)
 	mobj_t *state = NULL;
 	mobj_t *thing = NULL;
 
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call sector.thinglist() directly, use it as 'for rover in sector.thinglist do <block> end'.");
@@ -369,8 +368,7 @@ static int lib_iterateSectorFFloors(lua_State *L)
 	ffloor_t *state = NULL;
 	ffloor_t *ffloor = NULL;
 
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call sector.ffloors() directly, use it as 'for rover in sector.ffloors do <block> end'.");
@@ -1251,8 +1249,7 @@ static int bbox_get(lua_State *L)
 static int lib_iterateSectors(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call sectors.iterate() directly, use it as 'for sector in sectors.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1270,8 +1267,7 @@ static int lib_iterateSectors(lua_State *L)
 static int lib_getSector(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1305,8 +1301,7 @@ static int lib_numsectors(lua_State *L)
 static int lib_iterateSubsectors(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call subsectors.iterate() directly, use it as 'for subsector in subsectors.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1324,8 +1319,7 @@ static int lib_iterateSubsectors(lua_State *L)
 static int lib_getSubsector(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1359,8 +1353,7 @@ static int lib_numsubsectors(lua_State *L)
 static int lib_iterateLines(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call lines.iterate() directly, use it as 'for line in lines.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1378,8 +1371,7 @@ static int lib_iterateLines(lua_State *L)
 static int lib_getLine(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1413,8 +1405,7 @@ static int lib_numlines(lua_State *L)
 static int lib_iterateSides(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call sides.iterate() directly, use it as 'for side in sides.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1432,8 +1423,7 @@ static int lib_iterateSides(lua_State *L)
 static int lib_getSide(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1467,8 +1457,7 @@ static int lib_numsides(lua_State *L)
 static int lib_iterateVertexes(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call vertexes.iterate() directly, use it as 'for vertex in vertexes.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1486,8 +1475,7 @@ static int lib_iterateVertexes(lua_State *L)
 static int lib_getVertex(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1523,8 +1511,7 @@ static int lib_numvertexes(lua_State *L)
 static int lib_iterateSegs(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call segs.iterate() directly, use it as 'for seg in segs.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1542,8 +1529,7 @@ static int lib_iterateSegs(lua_State *L)
 static int lib_getSeg(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
@@ -1577,8 +1563,7 @@ static int lib_numsegs(lua_State *L)
 static int lib_iterateNodes(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call nodes.iterate() directly, use it as 'for node in nodes.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -1596,8 +1581,7 @@ static int lib_iterateNodes(lua_State *L)
 static int lib_getNode(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index 8bbbebe1d4c1340e974bd4df7e3d9b29d8ddaa1a..de1b854f6234a9b6d1f5ec2a0e3e7bebfbb1f1d6 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -816,8 +816,7 @@ static int mapthing_set(lua_State *L)
 static int lib_iterateMapthings(lua_State *L)
 {
 	size_t i = 0;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 		return luaL_error(L, "Don't call mapthings.iterate() directly, use it as 'for mapthing in mapthings.iterate do <block> end'.");
 	lua_settop(L, 2);
@@ -835,8 +834,7 @@ static int lib_iterateMapthings(lua_State *L)
 static int lib_getMapthing(lua_State *L)
 {
 	int field;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	lua_settop(L, 2);
 	lua_remove(L, 1); // dummy userdata table is unused.
 	if (lua_isnumber(L, 1))
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index 700dab21100acb79d222be025ae3ca4b728ab8a0..b7bdaa1be87a078974490fe569e171c15906b319 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -25,8 +25,7 @@
 static int lib_iteratePlayers(lua_State *L)
 {
 	INT32 i = -1;
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 	if (lua_gettop(L) < 2)
 	{
 		//return luaL_error(L, "Don't call players.iterate() directly, use it as 'for player in players.iterate do <block> end'.");
@@ -53,8 +52,7 @@ static int lib_getPlayer(lua_State *L)
 {
 	const char *field;
 	// i -> players[i]
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "You cannot access this outside of a level!");
+	INLEVEL
 	if (lua_type(L, 2) == LUA_TNUMBER)
 	{
 		lua_Integer i = luaL_checkinteger(L, 2);
diff --git a/src/lua_script.h b/src/lua_script.h
index b690e4fa7577e6f0076a7f6d7b878bde9d01581d..fcbca29379e0acd50aeeab20250696ee16a3233d 100644
--- a/src/lua_script.h
+++ b/src/lua_script.h
@@ -15,6 +15,7 @@
 #include "m_fixed.h"
 #include "doomtype.h"
 #include "d_player.h"
+#include "g_state.h"
 
 #include "blua/lua.h"
 #include "blua/lualib.h"
@@ -97,4 +98,7 @@ void COM_Lua_f(void);
 // uncomment if you want seg_t/node_t in Lua
 // #define HAVE_LUA_SEGS
 
+#define INLEVEL if (gamestate != GS_LEVEL && !titlemapinaction)\
+return luaL_error(L, "This can only be used in a level!");
+
 #endif
diff --git a/src/lua_thinkerlib.c b/src/lua_thinkerlib.c
index 63eb15846b29a2b465b26a662144dcf5d757d92d..877294898e1483541b12d093adf70b9accb9cd35 100644
--- a/src/lua_thinkerlib.c
+++ b/src/lua_thinkerlib.c
@@ -56,8 +56,7 @@ static int lib_iterateThinkers(lua_State *L)
 	thinker_t *th = NULL, *next = NULL;
 	struct iterationState *it;
 
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 
 	it = luaL_checkudata(L, 1, META_ITERATIONSTATE);
 
@@ -112,8 +111,7 @@ static int lib_startIterate(lua_State *L)
 {
 	struct iterationState *it;
 
-	if (gamestate != GS_LEVEL)
-		return luaL_error(L, "This function can only be used in a level!");
+	INLEVEL
 
 	lua_pushvalue(L, lua_upvalueindex(1));
 	it = lua_newuserdata(L, sizeof(struct iterationState));
diff --git a/src/p_floor.c b/src/p_floor.c
index c01e568d02f5c5a63d5604e2e745c526d1c9f70a..7887dc530a6291adb50adb1304baee52197fe440 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -719,6 +719,8 @@ void T_ContinuousFalling(levelspecthink_t *faller)
 		}
 	}
 
+	P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong
+
 	faller->sector->floorspeed = faller->speed*faller->direction;
 	faller->sector->ceilspeed = 42;
 	faller->sector->moved = true;
@@ -3029,20 +3031,40 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
 
 void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
 {
-	size_t i;
-	size_t leftmostvertex = 0, rightmostvertex = 0;
-	size_t topmostvertex = 0, bottommostvertex = 0;
-	fixed_t leftx, rightx;
-	fixed_t topy, bottomy;
-	fixed_t topz, bottomz;
-	fixed_t widthfactor = FRACUNIT, heightfactor = FRACUNIT;
-	fixed_t a, b, c;
-	mobjtype_t type = MT_ROCKCRUMBLE1;
-	fixed_t spacing = (32<<FRACBITS);
-	tic_t lifetime = 3*TICRATE;
-	INT16 flags = 0;
-
-#define controlsec rover->master->frontsector
+	size_t i, leftmostvertex, rightmostvertex, topmostvertex, bottommostvertex;
+	fixed_t leftx, rightx, topy, bottomy, topz, bottomz, widthfactor, heightfactor, a, b, c, spacing;
+	mobjtype_t type;
+	tic_t lifetime;
+	INT16 flags;
+
+	sector_t *controlsec = rover->master->frontsector;
+
+	if (sec == NULL)
+	{
+		if (controlsec->numattached)
+		{
+			for (i = 0; i < controlsec->numattached; i++)
+			{
+				sec = &sectors[controlsec->attached[i]];
+				if (!sec->ffloors)
+					continue;
+
+				for (rover = sec->ffloors; rover; rover = rover->next)
+				{
+					if (rover->master->frontsector == controlsec)
+						EV_CrumbleChain(sec, rover);
+				}
+			}
+		}
+		return;
+	}
+
+	leftmostvertex = rightmostvertex = topmostvertex = bottommostvertex = 0;
+	widthfactor = heightfactor = FRACUNIT;
+	spacing = (32<<FRACBITS);
+	type = MT_ROCKCRUMBLE1;
+	lifetime = 3*TICRATE;
+	flags = 0;
 
 	if (controlsec->tag != 0)
 	{
diff --git a/src/p_inter.c b/src/p_inter.c
index abf33429fa973f470499613c667771de0cde35fc..0489bab90439e1aa75bd3eff84bed6f88bfd8f0d 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -670,7 +670,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 				P_DoMatchSuper(player);
 			}
 			else
+			{
 				emeralds |= special->info->speed;
+				stagefailed = false;
+			}
 
 			if (special->target && special->target->type == MT_EMERALDSPAWN)
 			{
@@ -3652,7 +3655,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
 {
 	INT32 i;
 	mobj_t *mo;
-	angle_t fa;
+	angle_t fa, va;
 	fixed_t ns;
 	fixed_t z;
 	boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
@@ -3674,6 +3677,11 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
 	// Spill weapons first
 	P_PlayerWeaponPanelOrAmmoBurst(player);
 
+	if (abs(player->mo->momx) > player->mo->scale || abs(player->mo->momy) > player->mo->scale)
+		va = R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0)>>ANGLETOFINESHIFT;
+	else
+		va = player->mo->angle>>ANGLETOFINESHIFT;
+
 	for (i = 0; i < num_rings; i++)
 	{
 		INT32 objType = mobjinfo[MT_RING].reactiontime;
@@ -3695,7 +3703,7 @@ void P_PlayerRingBurst(player_t *player, INT32 num_rings)
 		P_SetScale(mo, player->mo->scale);
 
 		// Angle offset by player angle, then slightly offset by amount of rings
-		fa = ((i*FINEANGLES/16) + (player->mo->angle>>ANGLETOFINESHIFT) - ((num_rings-1)*FINEANGLES/32)) & FINEMASK;
+		fa = ((i*FINEANGLES/16) + va - ((num_rings-1)*FINEANGLES/32)) & FINEMASK;
 
 		// Make rings spill out around the player in 16 directions like SA, but spill like Sonic 2.
 		// Technically a non-SA way of spilling rings. They just so happen to be a little similar.
diff --git a/src/p_local.h b/src/p_local.h
index cb8f95533fd2fde2922baa48b8950f52909895c3..3c62d6277df880c45499d1026b6d438d0f86b7d2 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -142,7 +142,7 @@ boolean P_IsObjectOnGround(mobj_t *mo);
 boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec);
 boolean P_InSpaceSector(mobj_t *mo);
 boolean P_InQuicksand(mobj_t *mo);
-boolean P_PlayerHitFloor(player_t *player);
+boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff);
 
 void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative);
 void P_RestoreMusic(player_t *player);
diff --git a/src/p_map.c b/src/p_map.c
index 76bb99bff09675fab7414a732a610a639e1fb2e0..6beca92f14c2a5614971b21e4925b3c57d1f705e 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -342,7 +342,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		if (horizspeed)
 		{
 			object->player->drawangle = spring->angle;
-			if (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0)
+			if (vertispeed || (object->player->cmd.forwardmove == 0 && object->player->cmd.sidemove == 0))
 			{
 				object->angle = spring->angle;
 
@@ -2822,7 +2822,7 @@ boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
 static boolean P_ThingHeightClip(mobj_t *thing)
 {
 	boolean floormoved;
-	fixed_t oldfloorz = thing->floorz;
+	fixed_t oldfloorz = thing->floorz, oldz = thing->z;
 	ffloor_t *oldfloorrover = thing->floorrover;
 	ffloor_t *oldceilingrover = thing->ceilingrover;
 	boolean onfloor = P_IsObjectOnGround(thing);//(thing->z <= thing->floorz);
@@ -2881,6 +2881,12 @@ static boolean P_ThingHeightClip(mobj_t *thing)
 			thing->z = thing->ceilingz - thing->height;
 	}
 
+	if (thing->z != oldz)
+	{
+		if (thing->player)
+			P_PlayerHitFloor(thing->player, false);
+	}
+
 	// debug: be sure it falls to the floor
 	thing->eflags &= ~MFE_ONGROUND;
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 1cb7f742d44173e7679a32f7b99bc319069b8e58..7ff3c3594a356d721513c70ddbb5ac897bd3e592 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1784,7 +1784,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 							continue;
 					}
 
-					EV_CrumbleChain(node->m_sector, rover);
+					EV_CrumbleChain(NULL, rover); // node->m_sector
 
 					// Run a linedef executor??
 					if (rover->master->flags & ML_EFFECT5)
@@ -3047,7 +3047,7 @@ static void P_PlayerZMovement(mobj_t *mo)
 				}
 			}
 
-			clipmomz = P_PlayerHitFloor(mo->player);
+			clipmomz = P_PlayerHitFloor(mo->player, true);
 
 			if (!(mo->player->pflags & PF_SPINNING) && mo->player->powers[pw_carry] != CR_NIGHTSMODE)
 				mo->player->pflags &= ~PF_STARTDASH;
@@ -3129,7 +3129,7 @@ nightsdone:
 						{
 							// DO THE MARIO!
 							if (rover->flags & FF_SHATTERBOTTOM) // Brick block!
-								EV_CrumbleChain(node->m_sector, rover);
+								EV_CrumbleChain(NULL, rover); // node->m_sector
 							else // Question block!
 								EV_MarioBlock(rover, node->m_sector, mo);
 						}
@@ -11985,6 +11985,15 @@ ML_EFFECT5 : Don't stop thinking when too far away
 			if (i == MT_YELLOWDIAG || i == MT_REDDIAG)
 				mobj->angle += ANGLE_22h;
 
+			if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ)
+			{
+				if (mthing->options & MTF_OBJECTFLIP)
+					mobj->z -= 16*FRACUNIT;
+				else
+					mobj->z += 16*FRACUNIT;
+			}
+
+
 			if (mobj->flags & MF_NIGHTSITEM)
 			{
 				// Spawn already displayed
@@ -12012,6 +12021,9 @@ ML_EFFECT5 : Don't stop thinking when too far away
 
 		if (mthing->options & MTF_OBJECTSPECIAL)
 		{
+			if (i == MT_YELLOWDIAG || i == MT_REDDIAG)
+				mobj->flags |= MF_NOGRAVITY;
+
 			if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
 			{
 				// flag for strong/weak random boxes
@@ -12355,28 +12367,33 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 		if (nightsreplace)
 			ringthing = MT_NIGHTSSTAR;
 
-		for (r = 1; r <= 5; r++)
+		if (mthing->options & MTF_OBJECTFLIP)
 		{
-			if (mthing->options & MTF_OBJECTFLIP)
-			{
-				z = (
+			z = (
 #ifdef ESLOPE
-					sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
+				sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
 #endif
-					sec->ceilingheight) - mobjinfo[ringthing].height - dist*r;
-				if (mthing->options >> ZSHIFT)
-					z -= ((mthing->options >> ZSHIFT) << FRACBITS);
+				sec->ceilingheight) - mobjinfo[ringthing].height;
+			if (mthing->options >> ZSHIFT)
+				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
 			}
-			else
-			{
-				z = (
+		else
+		{
+			z = (
 #ifdef ESLOPE
-					sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
 #endif
-					sec->floorheight) + dist*r;
-				if (mthing->options >> ZSHIFT)
-					z += ((mthing->options >> ZSHIFT) << FRACBITS);
-			}
+				sec->floorheight);
+			if (mthing->options >> ZSHIFT)
+				z += ((mthing->options >> ZSHIFT) << FRACBITS);
+		}
+
+		for (r = 1; r <= 5; r++)
+		{
+			if (mthing->options & MTF_OBJECTFLIP)
+				z -= dist;
+			else
+				z += dist;
 
 			mobj = P_SpawnMobj(x, y, z, ringthing);
 
@@ -12410,31 +12427,36 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
 		closestangle = FixedAngle(mthing->angle*FRACUNIT);
 		fa = (closestangle >> ANGLETOFINESHIFT);
 
+		if (mthing->options & MTF_OBJECTFLIP)
+		{
+			z = (
+#ifdef ESLOPE
+				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);
+			}
+		else
+		{
+			z = (
+#ifdef ESLOPE
+				sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+				sec->floorheight);
+			if (mthing->options >> ZSHIFT)
+				z += ((mthing->options >> ZSHIFT) << FRACBITS);
+		}
+
 		for (r = 1; r <= iterations; r++)
 		{
 			x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
 			y += FixedMul(64*FRACUNIT, FINESINE(fa));
 
 			if (mthing->options & MTF_OBJECTFLIP)
-			{
-				z = (
-#ifdef ESLOPE
-					sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
-#endif
-					sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r;
-				if (mthing->options >> ZSHIFT)
-					z -= ((mthing->options >> ZSHIFT) << FRACBITS);
-			}
+				z -= 64*FRACUNIT;
 			else
-			{
-				z = (
-#ifdef ESLOPE
-					sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
-#endif
-					sec->floorheight) + 64*FRACUNIT*r;
-				if (mthing->options >> ZSHIFT)
-					z += ((mthing->options >> ZSHIFT) << FRACBITS);
-			}
+				z += 64*FRACUNIT;
 
 			mobj = P_SpawnMobj(x, y, z, ringthing);
 
diff --git a/src/p_setup.c b/src/p_setup.c
index c0aa7ffa355c109933a6180d559c0cf9032617b8..26e8144cf77e13386604637245b309848e3b3dc2 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -859,12 +859,7 @@ void P_ReloadRings(void)
 			mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
 				->sector->floorheight>>FRACBITS);
 
-			P_SpawnHoopsAndRings(mt,
-#ifdef MANIASPHERES
-				true);
-#else
-				!G_IsSpecialStage(gamemap)); // prevent flashing spheres in special stages
-#endif
+			P_SpawnHoopsAndRings(mt, true);
 		}
 	}
 	for (i = 0; i < numHoops; i++)
@@ -878,11 +873,6 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
 	mobj_t *mo;
 	thinker_t *th;
 
-#ifndef MANIASPHERES
-	if (G_IsSpecialStage(gamemap)) // prevent flashing spheres in special stages
-		return;
-#endif
-
 	// scan the thinkers to find spheres to switch
 	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
 	{
@@ -2215,7 +2205,7 @@ static void P_LevelInitStuff(void)
 	ssspheres = timeinmap = 0;
 
 	// special stage
-	stagefailed = false;
+	stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial
 	// Reset temporary record data
 	memset(&ntemprecords, 0, sizeof(nightsdata_t));
 
diff --git a/src/p_spec.c b/src/p_spec.c
index 3cd0461e242f13e6149121f192a869df83ff9124..7e1230528b21a4e2a0164937aaa72e5f0c039577 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -4601,7 +4601,10 @@ DoneSection2:
 			if (player->bot)
 				break;
 			if (!(maptol & TOL_NIGHTS) && G_IsSpecialStage(gamemap) && player->nightstime > 6)
+			{
 				player->nightstime = 6; // Just let P_Ticker take care of the rest.
+				return;
+			}
 
 			// Exit (for FOF exits; others are handled in P_PlayerThink in p_user.c)
 			{
diff --git a/src/p_tick.c b/src/p_tick.c
index a0f6edef9b8f6cac74b987204d9845dfbb832f9e..cfdd54eb2091bcb144d195e6eb5968e9192543ea 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -518,10 +518,7 @@ static inline void P_DoSpecialStageStuff(void)
 			}
 		}
 		else
-		{
 			sstimer = 0;
-			stagefailed = true;
-		}
 	}
 }
 
diff --git a/src/p_user.c b/src/p_user.c
index b758cebe49a5e033184d58cbb9439f929cedb2ef..e14e922accd091ce12857300f2432409fb891d58 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -302,15 +302,39 @@ void P_GiveEmerald(boolean spawnObj)
 
 	S_StartSound(NULL, sfx_cgot); // Got the emerald!
 	emeralds |= (1 << em);
+	stagefailed = false;
 
-	if (spawnObj && playeringame[consoleplayer])
+	if (spawnObj)
 	{
 		// The Chaos Emerald begins to orbit us!
-		// Only give it to ONE person!
-		mobj_t *emmo = P_SpawnMobjFromMobj(players[consoleplayer].mo, 0, 0, players[consoleplayer].mo->height, MT_GOTEMERALD);
-		P_SetTarget(&emmo->target, players[consoleplayer].mo);
-		P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
-		P_SetTarget(&players[consoleplayer].mo->tracer, emmo);
+		// Only visibly give it to ONE person!
+		UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255;
+		for (i = 0; i < MAXPLAYERS; i++)
+		{
+			mobj_t *emmo;
+			if (!playeringame[i])
+				continue;
+			if (players[i].spectator)
+				continue;
+			if (!players[i].mo)
+				continue;
+
+			emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD);
+			P_SetTarget(&emmo->target, players[i].mo);
+			P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
+			P_SetTarget(&players[i].mo->tracer, emmo);
+
+			if (pnum == 255)
+			{
+				i = pnum;
+				continue;
+			}
+
+			if (i == pnum)
+				continue;
+
+			emmo->flags2 |= MF2_DONTDRAW;
+		}
 	}
 }
 
@@ -597,7 +621,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	player->mo->skin = &skins[player->skin];
 	player->followitem = skins[player->skin].followitem;
 	player->mo->color = player->skincolor;
-	G_GhostAddColor(GHC_NORMAL);
+	G_GhostAddColor(GHC_RETURNSKIN);
 
 	// Restore aiming angle
 	if (player == &players[consoleplayer])
@@ -615,7 +639,6 @@ static void P_DeNightserizePlayer(player_t *player)
 			if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
 				players[i].nightstime = 1; // force everyone else to fall too.
 		player->exiting = 3*TICRATE;
-		stagefailed = true; // NIGHT OVER
 
 		// If you screwed up, kiss your score and ring bonus goodbye.
 		// But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground.
@@ -716,6 +739,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 		if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
 			player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
 		player->followitem = skins[DEFAULTNIGHTSSKIN].followitem;
+		G_GhostAddColor(GHC_NIGHTSSKIN);
 	}
 
 	player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE;
@@ -2007,7 +2031,7 @@ boolean P_InSpaceSector(mobj_t *mo) // Returns true if you are in space
 //
 // Handles player hitting floor surface.
 // Returns whether to clip momz.
-boolean P_PlayerHitFloor(player_t *player)
+boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
 {
 	boolean clipmomz;
 
@@ -2015,22 +2039,31 @@ boolean P_PlayerHitFloor(player_t *player)
 
 	if ((clipmomz = !(P_CheckDeathPitCollide(player->mo))) && player->mo->health && !player->spectator)
 	{
-		if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
+		if (dorollstuff)
 		{
-			player->pflags |= PF_SPINNING;
-			P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
-			S_StartSound(player->mo, sfx_spin);
+			if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_THOKKED) && (player->cmd.buttons & BT_USE) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale)))
+			{
+				player->pflags |= PF_SPINNING;
+				P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
+				S_StartSound(player->mo, sfx_spin);
+			}
+			else
+				player->pflags &= ~PF_SPINNING;
 		}
-		else
-		{
-			player->pflags &= ~PF_SPINNING;
 
-			if (player->pflags & PF_GLIDING) // ground gliding
+		if (player->pflags & PF_GLIDING) // ground gliding
+		{
+			if (dorollstuff)
 			{
 				player->skidtime = TICRATE;
 				player->mo->tics = -1;
 			}
-			else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING))
+			else
+				player->pflags &= ~PF_GLIDING;
+		}
+		else if (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
+		{
+			if (player->mo->state-states != S_PLAY_MELEE_LANDING)
 			{
 				mobjtype_t type = player->revitem;
 				P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING);
@@ -2062,45 +2095,48 @@ boolean P_PlayerHitFloor(player_t *player)
 							P_ReturnThrustY(missile, throwang, mu)); // side to side component
 						P_Thrust(missile, player->drawangle, mu2); // forward component
 						P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
+						missile->momz += player->mo->pmomz;
 						missile->fuse = TICRATE/2;
 						missile->extravalue2 = ev;
 
 						i++;
 						throwang += ANG30;
 					}
-					if (mobjinfo[type].seesound)
+					if (mobjinfo[type].seesound && missile)
 						S_StartSound(missile, missile->info->seesound);
 				}
 			}
-			else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
+		}
+		else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
+			;
+		else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
 			|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
+		{
+			if (player->cmomx || player->cmomy)
 			{
-				if (player->cmomx || player->cmomy)
-				{
-					if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
-						P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
-					else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
-					&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
-						P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
-					else if ((player->rmomx || player->rmomy)
-					&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
-						P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
-					else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE)
-						P_SetPlayerMobjState(player->mo, S_PLAY_STND);
-				}
-				else
-				{
-					if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
-						P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
-					else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
-					&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
-						P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
-					else if ((player->mo->momx || player->mo->momy)
-					&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
-						P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
-					else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE)
-						P_SetPlayerMobjState(player->mo, S_PLAY_STND);
-				}
+				if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
+					P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
+				else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
+				&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
+					P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
+				else if ((player->rmomx || player->rmomy)
+				&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
+					P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
+				else if (!player->rmomx && !player->rmomy && player->panim != PA_IDLE)
+					P_SetPlayerMobjState(player->mo, S_PLAY_STND);
+			}
+			else
+			{
+				if (player->charflags & SF_DASHMODE && player->dashmode >= 3*TICRATE && player->panim != PA_DASH)
+					P_SetPlayerMobjState(player->mo, S_PLAY_DASH);
+				else if (player->speed >= FixedMul(player->runspeed, player->mo->scale)
+				&& (player->panim != PA_RUN || player->mo->state-states == S_PLAY_FLOAT_RUN))
+					P_SetPlayerMobjState(player->mo, S_PLAY_RUN);
+				else if ((player->mo->momx || player->mo->momy)
+				&& (player->panim != PA_WALK || player->mo->state-states == S_PLAY_FLOAT))
+					P_SetPlayerMobjState(player->mo, S_PLAY_WALK);
+				else if (!player->mo->momx && !player->mo->momy && player->panim != PA_IDLE)
+					P_SetPlayerMobjState(player->mo, S_PLAY_STND);
 			}
 		}
 
@@ -2320,7 +2356,7 @@ static void P_CheckBustableBlocks(player_t *player)
 					//if (metalrecording)
 					//	G_RecordBustup(rover);
 
-					EV_CrumbleChain(node->m_sector, rover);
+					EV_CrumbleChain(NULL, rover); // node->m_sector
 
 					// Run a linedef executor??
 					if (rover->master->flags & ML_EFFECT5)
@@ -2537,7 +2573,7 @@ static void P_CheckQuicksand(player_t *player)
 					player->mo->z = ceilingheight - player->mo->height;
 
 				if (player->mo->momz <= 0)
-					P_PlayerHitFloor(player);
+					P_PlayerHitFloor(player, false);
 			}
 			else
 			{
@@ -2549,7 +2585,7 @@ static void P_CheckQuicksand(player_t *player)
 					player->mo->z = floorheight;
 
 				if (player->mo->momz >= 0)
-					P_PlayerHitFloor(player);
+					P_PlayerHitFloor(player, false);
 			}
 
 			friction = abs(rover->master->v1->y - rover->master->v2->y)>>6;
@@ -4410,6 +4446,10 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
 					{
 						player->mo->z += P_MobjFlip(player->mo);
 						P_SetObjectMomZ(player->mo, player->mindash, false);
+						if (P_MobjFlip(player->mo)*player->mo->pmomz > 0)
+							player->mo->momz += player->mo->pmomz; // Add the platform's momentum to your jump.
+						else
+							player->mo->pmomz = 0;
 						if (player->mo->eflags & MFE_UNDERWATER)
 							player->mo->momz >>= 1;
 #if 0
@@ -11641,7 +11681,6 @@ void P_PlayerAfterThink(player_t *player)
 							player->followmobj->threshold = player->mo->z;
 							player->followmobj->movecount = player->panim;
 							player->followmobj->angle = horizangle;
-							player->followmobj->scale = player->mo->scale;
 							P_SetScale(player->followmobj, player->mo->scale);
 							player->followmobj->destscale = player->mo->destscale;
 							player->followmobj->radius = player->mo->radius;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 4122793ad4a3f6cdfc4cc807a40b12d2dbf9ff73..3b8fc749d2506b9d020eb2aab61447d6495f89f2 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1617,12 +1617,8 @@ static void ST_drawNiGHTSHUD(void)
 #endif
 	ST_DrawTopLeftOverlayPatch(16, 8, nbracket);
 	if (G_IsSpecialStage(gamemap))
-#ifdef MANIASPHERES
 		ST_DrawTopLeftOverlayPatch(24, 16, (
-			(stplyr->bonustime && (leveltime & 4)) ? nssbon : nsshud));
-#else
-		ST_DrawTopLeftOverlayPatch(24, 16, (nsshud));
-#endif
+			(stplyr->bonustime && (leveltime & 4) && (states[S_BLUESPHEREBONUS].frame & FF_ANIMATE)) ? nssbon : nsshud));
 	else
 		ST_DrawTopLeftOverlayPatch(24, 16, *(((stplyr->bonustime) ? nbon : nhud)+((leveltime/2)%12)));