diff --git a/.travis.yml b/.travis.yml
index ee440503b..4648ae567 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -113,7 +113,7 @@ matrix:
               - p7zip-full
               - gcc-7
           compiler: gcc-7
-          env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough"
+          env: WFLAGS="-Wno-tautological-compare -Wno-error=implicit-fallthrough -Wimplicit-fallthrough=3"
           #gcc-7 (Ubuntu 7.2.0-1ubuntu1~14.04) 7.2.0 20170802
         - os: linux
           compiler: clang
@@ -177,6 +177,51 @@ matrix:
               - clang-3.8
           compiler: clang-3.8
           #clang version 3.8.1-svn271127-1~exp1 (branches/release_38)
+        - os: linux
+          addons:
+            apt:
+              sources:
+              - llvm-toolchain-precise-3.9
+              - ubuntu-toolchain-r-test
+              packages:
+              - libsdl2-mixer-dev
+              - libpng-dev
+              - libgl1-mesa-dev
+              - libgme-dev
+              - p7zip-full
+              - clang-3.9
+          compiler: clang-3.9
+          #clang version 3.9.X
+#        - os: linux
+#          addons:
+#            apt:
+#              sources:
+#              - llvm-toolchain-precise-4.0
+#              - ubuntu-toolchain-r-test
+#              packages:
+#              - libsdl2-mixer-dev
+#              - libpng-dev
+#              - libgl1-mesa-dev
+#              - libgme-dev
+#              - p7zip-full
+#              - clang-4.0
+#          compiler: clang-4.0
+#          #clang version 4.0.X
+#        - os: linux
+#          addons:
+#            apt:
+#              sources:
+#              - llvm-toolchain-precise-5.0
+#              - ubuntu-toolchain-r-test
+#              packages:
+#              - libsdl2-mixer-dev
+#              - libpng-dev
+#              - libgl1-mesa-dev
+#              - libgme-dev
+#              - p7zip-full
+#              - clang-5.0
+#          compiler: clang-5.0
+#          #clang version 5.0.X
 #        - os: osx
 #          osx_image: beta-xcode6.1
 #          #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
@@ -207,6 +252,9 @@ matrix:
       - compiler: clang-3.6
       - compiler: clang-3.7
       - compiler: clang-3.8
+      - compiler: clang-3.9
+      - compiler: clang-4.0
+      - compiler: clang-5.0
 
 cache:
   apt: true
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 1b323ca0b..317218397 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -7,6 +7,10 @@
 # and other things
 #
 
+ifdef GCC80
+GCC72=1
+endif
+
 ifdef GCC72
 GCC71=1
 endif
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index 6685cd5ee..4ec9cdb20 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -544,6 +544,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
 	rsp->thokitem = (UINT32)LONG(players[i].thokitem); //mobjtype_t
 	rsp->spinitem = (UINT32)LONG(players[i].spinitem); //mobjtype_t
 	rsp->revitem = (UINT32)LONG(players[i].revitem); //mobjtype_t
+	rsp->followitem = (UINT32)LONG(players[i].followitem); //mobjtype_t
 	rsp->actionspd = (fixed_t)LONG(players[i].actionspd);
 	rsp->mindash = (fixed_t)LONG(players[i].mindash);
 	rsp->maxdash = (fixed_t)LONG(players[i].maxdash);
@@ -673,6 +674,7 @@ static void resynch_read_player(resynch_pak *rsp)
 	players[i].thokitem = (UINT32)LONG(rsp->thokitem); //mobjtype_t
 	players[i].spinitem = (UINT32)LONG(rsp->spinitem); //mobjtype_t
 	players[i].revitem = (UINT32)LONG(rsp->revitem); //mobjtype_t
+	players[i].followitem = (UINT32)LONG(rsp->followitem); //mobjtype_t
 	players[i].actionspd = (fixed_t)LONG(rsp->actionspd);
 	players[i].mindash = (fixed_t)LONG(rsp->mindash);
 	players[i].maxdash = (fixed_t)LONG(rsp->maxdash);
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index b9a4eec3e..bdf332665 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -189,6 +189,7 @@ typedef struct
 	UINT32 thokitem; // mobjtype_t
 	UINT32 spinitem; // mobjtype_t
 	UINT32 revitem; // mobjtype_t
+	UINT32 followitem; // mobjtype_t
 	fixed_t actionspd;
 	fixed_t mindash;
 	fixed_t maxdash;
diff --git a/src/d_player.h b/src/d_player.h
index bf0b303b8..e1350fe67 100644
--- a/src/d_player.h
+++ b/src/d_player.h
@@ -369,6 +369,8 @@ typedef struct player_s
 	mobjtype_t thokitem; // Object # to spawn for the thok
 	mobjtype_t spinitem; // Object # to spawn for spindash/spinning
 	mobjtype_t revitem; // Object # to spawn for spindash/spinning
+	mobjtype_t followitem; // Object # to spawn for Smiles
+	mobj_t *followmobj; // Smiles all around
 
 	fixed_t actionspd; // Speed of thok/glide/fly
 	fixed_t mindash; // Minimum spindash speed
diff --git a/src/dehacked.c b/src/dehacked.c
index cddbd1a0e..9df077672 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -1804,6 +1804,7 @@ static actionpointer_t actionpointers[] =
 	{{A_FlickyHeightCheck},    "A_FLICKYHEIGHTCHECK"},
 	{{A_FlickyFlutter},        "A_FLICKYFLUTTER"},
 	{{A_FlameParticle},        "A_FLAMEPARTICLE"},
+	{{A_FadeOverlay},          "A_FADEOVERLAY"},
 
 	{{NULL},                   "NONE"},
 
@@ -2831,6 +2832,11 @@ static void readmaincfg(MYFILE *f)
 				bootmap = (INT16)value;
 				//titlechanged = true;
 			}
+			else if (fastcmp(word, "STARTCHAR"))
+			{
+				startchar = (INT16)value;
+				char_on = -1;
+			}
 			else
 				deh_warning("Maincfg: unknown word '%s'", word);
 		}
@@ -3460,15 +3466,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_PLAY_MELEE_LANDING",
 
 	// SF_SUPER
-	"S_PLAY_SUPERTRANS1",
-	"S_PLAY_SUPERTRANS2",
-	"S_PLAY_SUPERTRANS3",
-	"S_PLAY_SUPERTRANS4",
-	"S_PLAY_SUPERTRANS5",
-	"S_PLAY_SUPERTRANS6",
-	"S_PLAY_SUPERTRANS7",
-	"S_PLAY_SUPERTRANS8",
-	"S_PLAY_SUPERTRANS9", // This has special significance in the code. If you add more frames, search for it and make the appropriate changes.
+	"S_PLAY_SUPER_TRANS1",
+	"S_PLAY_SUPER_TRANS2",
+	"S_PLAY_SUPER_TRANS3",
+	"S_PLAY_SUPER_TRANS4",
+	"S_PLAY_SUPER_TRANS5",
+	"S_PLAY_SUPER_TRANS6", // This has special significance in the code. If you add more frames, search for it and make the appropriate changes.
 
 	// technically the player goes here but it's an infinite tic state
 	"S_OBJPLACE_DUMMY",
@@ -3484,15 +3487,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_PLAY_SIGN",
 
 	// NiGHTS character (uses player sprite)
-	"S_PLAY_NIGHTS_TRANS",
+	"S_PLAY_NIGHTS_TRANS1",
 	"S_PLAY_NIGHTS_TRANS2",
 	"S_PLAY_NIGHTS_TRANS3",
 	"S_PLAY_NIGHTS_TRANS4",
 	"S_PLAY_NIGHTS_TRANS5",
 	"S_PLAY_NIGHTS_TRANS6",
-	"S_PLAY_NIGHTS_TRANS7",
-	"S_PLAY_NIGHTS_TRANS8",
-	"S_PLAY_NIGHTS_TRANS9",
 
 	"S_PLAY_NIGHTS_STAND",
 	"S_PLAY_NIGHTS_FLOAT",
@@ -3527,6 +3527,20 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 	"S_PLAY_NIGHTS_FLYC",
 	"S_PLAY_NIGHTS_DRILLC",
 
+	// c:
+	"S_TAILSOVERLAY_STAND",
+	"S_TAILSOVERLAY_0DEGREES",
+	"S_TAILSOVERLAY_PLUS30DEGREES",
+	"S_TAILSOVERLAY_PLUS60DEGREES",
+	"S_TAILSOVERLAY_MINUS30DEGREES",
+	"S_TAILSOVERLAY_MINUS60DEGREES",
+	"S_TAILSOVERLAY_RUN",
+	"S_TAILSOVERLAY_FLY",
+	"S_TAILSOVERLAY_TIRE",
+	"S_TAILSOVERLAY_PAIN",
+	"S_TAILSOVERLAY_GASP",
+	"S_TAILSOVERLAY_EDGE",
+
 	// Blue Crawla
 	"S_POSS_STND",
 	"S_POSS_RUN1",
@@ -5881,6 +5895,7 @@ static const char *const MOBJTYPE_LIST[] = {  // array length left dynamic for s
 
 	"MT_THOK", // Thok! mobj
 	"MT_PLAYER",
+	"MT_TAILSOVERLAY", // c:
 
 	// Enemies
 	"MT_BLUECRAWLA",
diff --git a/src/g_game.c b/src/g_game.c
index dbef873ad..389208440 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2183,6 +2183,7 @@ void G_PlayerReborn(INT32 player)
 	UINT32 thokitem;
 	UINT32 spinitem;
 	UINT32 revitem;
+	UINT32 followitem;
 	fixed_t actionspd;
 	fixed_t mindash;
 	fixed_t maxdash;
@@ -2254,6 +2255,7 @@ void G_PlayerReborn(INT32 player)
 	thokitem = players[player].thokitem;
 	spinitem = players[player].spinitem;
 	revitem = players[player].revitem;
+	followitem = players[player].followitem;
 	actionspd = players[player].actionspd;
 	mindash = players[player].mindash;
 	maxdash = players[player].maxdash;
@@ -2291,6 +2293,7 @@ void G_PlayerReborn(INT32 player)
 	p->thokitem = thokitem;
 	p->spinitem = spinitem;
 	p->revitem = revitem;
+	p->followitem = followitem;
 	p->actionspd = actionspd;
 	p->mindash = mindash;
 	p->maxdash = maxdash;
diff --git a/src/hardware/hw_clip.c b/src/hardware/hw_clip.c
index 8b01cabd5..fd6ba13f3 100644
--- a/src/hardware/hw_clip.c
+++ b/src/hardware/hw_clip.c
@@ -338,7 +338,7 @@ angle_t gld_FrustumAngle(void)
 	}
 
 	// If the pitch is larger than this you can look all around at a FOV of 90
-	if (abs(aimingangle) > 46 * ANG1)
+	if (aimingangle > (ANGLE_45+ANG1) && (ANGLE_315-ANG1) > aimingangle)
 		return 0xffffffff;
 
 	// ok, this is a gross hack that barely works...
diff --git a/src/hardware/hw_data.h b/src/hardware/hw_data.h
index a6525a2f5..d76fcc1c8 100644
--- a/src/hardware/hw_data.h
+++ b/src/hardware/hw_data.h
@@ -64,7 +64,7 @@ typedef struct GLMipmap_s GLMipmap_t;
 //
 struct GLTexture_s
 {
-	GLMipmap_t mipmap;
+	GLMipmap_t  mipmap;
 	float       scaleX;             //used for scaling textures on walls
 	float       scaleY;
 };
@@ -88,7 +88,7 @@ struct GLPatch_s
 	UINT16              wadnum;      // the software patch lump num for when the hardware patch
 	UINT16              lumpnum;     // was flushed, and we need to re-create it
 	GLMipmap_t          mipmap;
-} ATTRPACK;
+};
 typedef struct GLPatch_s GLPatch_t;
 
 #endif //_HWR_DATA_
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index b49d3eb96..7e09079cf 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -1180,7 +1180,7 @@ void HU_Erase(void)
 //                   IN-LEVEL MULTIPLAYER RANKINGS
 //======================================================================
 
-#define supercheckdef ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS] || players[tab[i].num].mo->state > &states[S_PLAY_SUPER_TRANS9])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER))
+#define supercheckdef ((players[tab[i].num].powers[pw_super] && players[tab[i].num].mo && (players[tab[i].num].mo->state < &states[S_PLAY_SUPER_TRANS1] || players[tab[i].num].mo->state >= &states[S_PLAY_SUPER_TRANS6])) || (players[tab[i].num].powers[pw_carry] == CR_NIGHTSMODE && skins[players[tab[i].num].skin].flags & SF_SUPER))
 #define greycheckdef ((players[tab[i].num].mo && players[tab[i].num].mo->health <= 0) || players[tab[i].num].spectator)
 
 //
diff --git a/src/info.c b/src/info.c
index d62111640..acb12379a 100644
--- a/src/info.c
+++ b/src/info.c
@@ -479,6 +479,19 @@ char spr2names[NUMPLAYERSPRITES][5] =
 	"DRLB",
 	"DRLC",
 
+	"TAL0",
+	"TAL1",
+	"TAL2",
+	"TAL3",
+	"TAL4",
+	"TAL5",
+	"TAL6",
+	"TAL7",
+	"TAL8",
+	"TAL9",
+	"TALA",
+	"TALB",
+
 	"SIGN",
 	"LIFE"
 };
@@ -562,8 +575,21 @@ playersprite_t spr2defaults[NUMPLAYERSPRITES] = {
 	SPR2_NGTB, // SPR2_DRLB,
 	SPR2_NGTC, // SPR2_DRLC,
 
+	0, // SPR2_TAL0,
+	SPR2_TAL0, // SPR2_TAL1,
+	SPR2_TAL1, // SPR2_TAL2,
+	SPR2_TAL2, // SPR2_TAL3,
+	SPR2_TAL1, // SPR2_TAL4,
+	SPR2_TAL4, // SPR2_TAL5,
+	SPR2_TAL0, // SPR2_TAL6,
+	SPR2_TAL3, // SPR2_TAL7,
+	SPR2_TAL7, // SPR2_TAL8,
+	SPR2_TAL0, // SPR2_TAL9,
+	SPR2_TAL9, // SPR2_TALA,
+	SPR2_TAL0, // SPR2_TALB,
+
 	0, // SPR2_SIGN,
-	0, // SPR2_LIFE
+	0, // SPR2_LIFE,
 };
 
 // Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@@ -644,15 +670,12 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, SPR2_MLEL,                35, {NULL},                   0, 0, S_PLAY_WALK},  // S_PLAY_MELEE_LANDING
 
 	// SF_SUPER
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                4, {NULL}, 0, 0, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                4, {NULL}, 0, 0, S_PLAY_SUPER_TRANS3}, // S_PLAY_SUPER_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  4, {NULL}, 0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS7}, // S_PLAY_SUPER_TRANS6
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS8}, // S_PLAY_SUPER_TRANS7
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  3, {NULL}, 0, 0, S_PLAY_SUPER_TRANS9}, // S_PLAY_SUPER_TRANS8
-	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 16, {NULL}, 0, 0, S_PLAY_WALK},         // S_PLAY_SUPER_TRANS9
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS2}, // S_PLAY_SUPER_TRANS1
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER,                3, {NULL},          0, 0, S_PLAY_SUPER_TRANS3}, // S_PLAY_SUPER_TRANS2
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS4}, // S_PLAY_SUPER_TRANS3
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS5}, // S_PLAY_SUPER_TRANS4
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_SUPER_TRANS6}, // S_PLAY_SUPER_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_SPR2SUPER|FF_FULLBRIGHT, 20, {A_FadeOverlay}, 0, 0, S_PLAY_FALL},         // S_PLAY_SUPER_TRANS6
 
 	{SPR_NULL, 0, -1, {NULL}, 0, 0, S_OBJPLACE_DUMMY}, //S_OBJPLACE_DUMMY
 
@@ -667,15 +690,12 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, SPR2_SIGN, 1, {NULL}, 0, 24, S_PLAY_SIGN},         // S_PLAY_SIGN
 
 	// NiGHTS Player, transforming
-	{SPR_PLAY, SPR2_TRNS,                4, {A_Scream}, 0, 0, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS
-	{SPR_PLAY, SPR2_TRNS,                4, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS3}, // S_PLAY_NIGHTS_TRANS2
-	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  4, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS4}, // S_PLAY_NIGHTS_TRANS3
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS5}, // S_PLAY_NIGHTS_TRANS4
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS7}, // S_PLAY_NIGHTS_TRANS6
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS8}, // S_PLAY_NIGHTS_TRANS7
-	{SPR_PLAY, SPR2_TRNS,                3, {NULL},     0, 0, S_PLAY_NIGHTS_TRANS9}, // S_PLAY_NIGHTS_TRANS8
-	{SPR_PLAY, SPR2_TRNS,               16, {NULL},     0, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_TRANS9
+	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS2}, // S_PLAY_NIGHTS_TRANS1
+	{SPR_PLAY, SPR2_TRNS,                3, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS3}, // S_PLAY_NIGHTS_TRANS2
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS4}, // S_PLAY_NIGHTS_TRANS3
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS5}, // S_PLAY_NIGHTS_TRANS4
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT,  2, {NULL},          0, 0, S_PLAY_NIGHTS_TRANS6}, // S_PLAY_NIGHTS_TRANS5
+	{SPR_PLAY, SPR2_TRNS|FF_FULLBRIGHT, 25, {A_FadeOverlay}, 4, 0, S_PLAY_NIGHTS_FLOAT},  // S_PLAY_NIGHTS_TRANS5
 
 	// NiGHTS Player, stand, float, pain, pull and attack
 	{SPR_PLAY, SPR2_NSTD, 7, {NULL}, 0, 0, S_PLAY_NIGHTS_STAND},  // S_PLAY_NIGHTS_STAND
@@ -712,6 +732,20 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, SPR2_NGTC, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_FLYC},   // S_PLAY_NIGHTS_FLYC
 	{SPR_PLAY, SPR2_DRLC, 2, {NULL}, 0, 0, S_PLAY_NIGHTS_DRILLC}, // S_PLAY_NIGHTS_DRILLC
 
+	// c:
+	{SPR_PLAY, SPR2_TAL0|FF_SPR2MIDSTART,  5, {NULL}, 0, 0, S_TAILSOVERLAY_STAND}, // S_TAILSOVERLAY_STAND
+	{SPR_PLAY, SPR2_TAL1|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_0DEGREES}, // S_TAILSOVERLAY_0DEGREES
+	{SPR_PLAY, SPR2_TAL2|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS30DEGREES}, // S_TAILSOVERLAY_PLUS30DEGREES
+	{SPR_PLAY, SPR2_TAL3|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PLUS60DEGREES}, // S_TAILSOVERLAY_PLUS60DEGREES
+	{SPR_PLAY, SPR2_TAL4|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS30DEGREES}, // S_TAILSOVERLAY_MINUS30DEGREES
+	{SPR_PLAY, SPR2_TAL5|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_MINUS60DEGREES}, // S_TAILSOVERLAY_MINUS60DEGREES
+	{SPR_PLAY, SPR2_TAL6|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_RUN}, // S_TAILSOVERLAY_RUN
+	{SPR_PLAY, SPR2_TAL7|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_FLY}, // S_TAILSOVERLAY_FLY
+	{SPR_PLAY, SPR2_TAL8|FF_SPR2MIDSTART,  4, {NULL}, 0, 0, S_TAILSOVERLAY_TIRE}, // S_TAILSOVERLAY_TIRE
+	{SPR_PLAY, SPR2_TAL9|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_PAIN}, // S_TAILSOVERLAY_PAIN
+	{SPR_PLAY, SPR2_TALA|FF_SPR2MIDSTART, 35, {NULL}, 0, 0, S_TAILSOVERLAY_GASP}, // S_TAILSOVERLAY_GASP
+	{SPR_PLAY, SPR2_TALB                , 35, {NULL}, 0, 0, S_TAILSOVERLAY_EDGE}, // S_TAILSOVERLAY_EDGE
+
 	// Blue Crawla
 	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},   // S_POSS_STND
 	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2},   // S_POSS_RUN1
@@ -3235,6 +3269,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		(statenum_t)MT_NULL // raisestate
 	},
 
+	{           // MT_TAILSOVERLAY
+		-1,             // doomednum
+		S_INVISIBLE,    // spawnstate
+		1000,           // spawnhealth
+		S_NULL,         // seestate
+		sfx_None,       // seesound
+		8,              // reactiontime
+		sfx_None,       // attacksound
+		S_NULL,         // painstate
+		0,              // painchance
+		sfx_None,       // painsound
+		S_NULL,         // meleestate
+		S_NULL,         // missilestate
+		S_NULL,         // deathstate
+		S_NULL,         // xdeathstate
+		sfx_None,       // deathsound
+		8,              // speed
+		16*FRACUNIT,    // radius
+		48*FRACUNIT,    // height
+		2,              // display offset
+		16,             // mass
+		0,              // damage
+		sfx_None,       // activesound
+		MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
+		S_NULL          // raisestate
+	},
+
 	{           // MT_BLUECRAWLA
 		100,            // doomednum
 		S_POSS_STND,    // spawnstate
@@ -11703,7 +11764,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_ELEMENTAL,   // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11730,7 +11791,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_ATTRACT,     // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11757,7 +11818,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_FORCE,       // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11784,7 +11845,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_ARMAGEDDON,  // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11811,7 +11872,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_WHIRLWIND,        // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11838,7 +11899,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_PITY,        // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11865,7 +11926,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_FLAMEAURA,   // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		-2,             // display offset
+		-4,             // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11892,7 +11953,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_BUBBLEWRAP,  // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		2,              // display offset
+		4,              // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -11919,7 +11980,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		SH_THUNDERCOIN, // speed
 		64*FRACUNIT,    // radius
 		64*FRACUNIT,    // height
-		-2,             // display offset
+		-4,             // display offset
 		16,             // mass
 		0,              // damage
 		sfx_None,       // activesound
@@ -14957,7 +15018,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		0,              // speed
 		16*FRACUNIT,    // radius
 		48*FRACUNIT,    // height
-		0,              // display offset
+		1,              // display offset
 		1000,           // mass
 		8,              // damage
 		sfx_None,       // activesound
diff --git a/src/info.h b/src/info.h
index 7bc7e673a..ea2103393 100644
--- a/src/info.h
+++ b/src/info.h
@@ -216,6 +216,7 @@ void A_FlickyCheck();
 void A_FlickyHeightCheck();
 void A_FlickyFlutter();
 void A_FlameParticle();
+void A_FadeOverlay();
 
 // ratio of states to sprites to mobj types is roughly 6 : 1 : 1
 #define NUMMOBJFREESLOTS 256
@@ -685,6 +686,20 @@ typedef enum playersprite
 	SPR2_DRLB,
 	SPR2_DRLC,
 
+	// c:
+	SPR2_TAL0,
+	SPR2_TAL1,
+	SPR2_TAL2,
+	SPR2_TAL3,
+	SPR2_TAL4,
+	SPR2_TAL5,
+	SPR2_TAL6,
+	SPR2_TAL7,
+	SPR2_TAL8,
+	SPR2_TAL9,
+	SPR2_TALA,
+	SPR2_TALB,
+
 	SPR2_SIGN, // end sign head
 	SPR2_LIFE, // life monitor icon
 
@@ -763,15 +778,12 @@ typedef enum state
 	S_PLAY_MELEE_LANDING,
 
 	// SF_SUPER
-	S_PLAY_SUPER_TRANS,
+	S_PLAY_SUPER_TRANS1,
 	S_PLAY_SUPER_TRANS2,
 	S_PLAY_SUPER_TRANS3,
 	S_PLAY_SUPER_TRANS4,
 	S_PLAY_SUPER_TRANS5,
 	S_PLAY_SUPER_TRANS6,
-	S_PLAY_SUPER_TRANS7,
-	S_PLAY_SUPER_TRANS8,
-	S_PLAY_SUPER_TRANS9,
 
 	// technically the player goes here but it's an infinite tic state
 	S_OBJPLACE_DUMMY,
@@ -787,15 +799,12 @@ typedef enum state
 	S_PLAY_SIGN,
 
 	// NiGHTS character (uses player sprite)
-	S_PLAY_NIGHTS_TRANS,
+	S_PLAY_NIGHTS_TRANS1,
 	S_PLAY_NIGHTS_TRANS2,
 	S_PLAY_NIGHTS_TRANS3,
 	S_PLAY_NIGHTS_TRANS4,
 	S_PLAY_NIGHTS_TRANS5,
 	S_PLAY_NIGHTS_TRANS6,
-	S_PLAY_NIGHTS_TRANS7,
-	S_PLAY_NIGHTS_TRANS8,
-	S_PLAY_NIGHTS_TRANS9,
 
 	S_PLAY_NIGHTS_STAND,
 	S_PLAY_NIGHTS_FLOAT,
@@ -830,6 +839,20 @@ typedef enum state
 	S_PLAY_NIGHTS_FLYC,
 	S_PLAY_NIGHTS_DRILLC,
 
+	// c:
+	S_TAILSOVERLAY_STAND,
+	S_TAILSOVERLAY_0DEGREES,
+	S_TAILSOVERLAY_PLUS30DEGREES,
+	S_TAILSOVERLAY_PLUS60DEGREES,
+	S_TAILSOVERLAY_MINUS30DEGREES,
+	S_TAILSOVERLAY_MINUS60DEGREES,
+	S_TAILSOVERLAY_RUN,
+	S_TAILSOVERLAY_FLY,
+	S_TAILSOVERLAY_TIRE,
+	S_TAILSOVERLAY_PAIN,
+	S_TAILSOVERLAY_GASP,
+	S_TAILSOVERLAY_EDGE,
+
 	// Blue Crawla
 	S_POSS_STND,
 	S_POSS_RUN1,
@@ -3206,6 +3229,7 @@ typedef enum mobj_type
 
 	MT_THOK, // Thok! mobj
 	MT_PLAYER,
+	MT_TAILSOVERLAY, // c:
 
 	// Enemies
 	MT_BLUECRAWLA,
diff --git a/src/lua_hook.h b/src/lua_hook.h
index fe5706f56..822edf79f 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -47,6 +47,7 @@ enum hook {
 	hook_ShieldSpecial,
 	hook_MobjMoveBlocked,
 	hook_MapThingSpawn,
+	hook_FollowMobj,
 
 	hook_MAX // last hook
 };
@@ -85,5 +86,6 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
 #define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
 #define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
 boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
+boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following
 
 #endif
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 3dd3f932f..0a7ef801e 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -58,6 +58,7 @@ const char *const hookNames[hook_MAX+1] = {
 	"ShieldSpecial",
 	"MobjMoveBlocked",
 	"MapThingSpawn",
+	"FollowMobj",
 	NULL
 };
 
@@ -197,6 +198,7 @@ static int lib_addHook(lua_State *L)
 	case hook_SpinSpecial:
 	case hook_JumpSpinSpecial:
 	case hook_PlayerSpawn:
+	case hook_FollowMobj:
 		lastp = &playerhooks;
 		break;
 	case hook_LinedefExecute:
@@ -1138,4 +1140,42 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing)
 	return hooked;
 }
 
+// Hook for P_PlayerAfterThink Smiles mobj-following
+boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj)
+{
+	hook_p hookp;
+	boolean hooked = false;
+	if (!gL || !(hooksAvailable[hook_FollowMobj/8] & (1<<(hook_FollowMobj%8))))
+		return 0;
+
+	lua_settop(gL, 0);
+
+	for (hookp = playerhooks; hookp; hookp = hookp->next)
+		if (hookp->type == hook_FollowMobj)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, player, META_PLAYER);
+				LUA_PushUserdata(gL, mobj, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
+			lua_pop(gL, 1);
+		}
+
+	lua_settop(gL, 0);
+	return hooked;
+}
+
 #endif
diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c
index 7c55012d2..12b2646d0 100644
--- a/src/lua_playerlib.c
+++ b/src/lua_playerlib.c
@@ -174,6 +174,10 @@ static int player_get(lua_State *L)
 		lua_pushinteger(L, plr->spinitem);
 	else if (fastcmp(field,"revitem"))
 		lua_pushinteger(L, plr->revitem);
+	else if (fastcmp(field,"followitem"))
+		lua_pushinteger(L, plr->followitem);
+	else if (fastcmp(field,"followmobj"))
+		LUA_PushUserdata(L, plr->followmobj, META_MOBJ);
 	else if (fastcmp(field,"actionspd"))
 		lua_pushfixed(L, plr->actionspd);
 	else if (fastcmp(field,"mindash"))
@@ -441,6 +445,10 @@ static int player_set(lua_State *L)
 		plr->spinitem = luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"revitem"))
 		plr->revitem = luaL_checkinteger(L, 3);
+	else if (fastcmp(field,"followitem"))
+		plr->followitem = luaL_checkinteger(L, 3);
+	else if (fastcmp(field,"followmobj"))
+		plr->followmobj = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
 	else if (fastcmp(field,"actionspd"))
 		plr->actionspd = (INT32)luaL_checkinteger(L, 3);
 	else if (fastcmp(field,"mindash"))
diff --git a/src/lua_skinlib.c b/src/lua_skinlib.c
index f93513c49..1a70a82d9 100644
--- a/src/lua_skinlib.c
+++ b/src/lua_skinlib.c
@@ -35,6 +35,7 @@ enum skin {
 	skin_thokitem,
 	skin_spinitem,
 	skin_revitem,
+	skin_followitem,
 	skin_actionspd,
 	skin_mindash,
 	skin_maxdash,
@@ -73,6 +74,7 @@ static const char *const skin_opt[] = {
 	"thokitem",
 	"spinitem",
 	"revitem",
+	"followitem",
 	"actionspd",
 	"mindash",
 	"maxdash",
@@ -162,6 +164,9 @@ static int skin_get(lua_State *L)
 	case skin_revitem:
 		lua_pushinteger(L, skin->revitem);
 		break;
+	case skin_followitem:
+		lua_pushinteger(L, skin->followitem);
+		break;
 	case skin_actionspd:
 		lua_pushfixed(L, skin->actionspd);
 		break;
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 5f45790a1..0e2ae0957 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1255,7 +1255,7 @@ void Command_ObjectPlace_f(void)
 	{
 		objectplacing = true;
 
-		if ((players[0].powers[pw_carry] == CR_NIGHTSMODE))
+		if (players[0].powers[pw_carry] == CR_NIGHTSMODE)
 			return;
 
 		if (!COM_CheckParm("-silent"))
diff --git a/src/m_menu.c b/src/m_menu.c
index 3efede002..49c3bce07 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -149,7 +149,7 @@ description_t description[32] =
 	{false, "???", "", "", 0, 0},
 	{false, "???", "", "", 0, 0}
 };
-static INT16 char_on = 0;
+INT16 char_on = -1, startchar = 1;
 static char *char_notes = NULL;
 static fixed_t char_scroll = 0;
 
@@ -6742,7 +6742,15 @@ static void M_SetupChoosePlayer(INT32 choice)
 	SP_PlayerDef.prevMenu = currentMenu;
 	M_SetupNextMenu(&SP_PlayerDef);
 	if (!allowed)
+	{
 		char_on = firstvalid;
+		if (startchar > 0 && startchar < 32)
+		{
+			INT16 workchar = startchar;
+			while (workchar--)
+				char_on = description[char_on].next;
+		}
+	}
 	char_scroll = 0; // finish scrolling the menu
 	Z_Free(char_notes);
 	char_notes = V_WordWrap(0, 21*8, V_ALLOWLOWERCASE, description[char_on].notes);
diff --git a/src/m_menu.h b/src/m_menu.h
index 8040b63e6..aa80445c8 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -232,6 +232,7 @@ extern CV_PossibleValue_t gametype_cons_t[];
 
 extern INT16 startmap;
 extern INT32 ultimate_selectable;
+extern INT16 char_on, startchar;
 
 #define MAXSAVEGAMES 31 //note: last save game is "no save"
 #define NOSAVESLOT 0 //slot where Play Without Saving appears
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 21dc3b4ed..4c6ecb15e 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -244,6 +244,7 @@ void A_FlickyCheck(mobj_t *actor);
 void A_FlickyHeightCheck(mobj_t *actor);
 void A_FlickyFlutter(mobj_t *actor);
 void A_FlameParticle(mobj_t *actor);
+void A_FadeOverlay(mobj_t *actor);
 
 //
 // ENEMY THINKING
@@ -10496,3 +10497,39 @@ void A_FlameParticle(mobj_t *actor)
 		type);
 	P_SetObjectMomZ(particle, locvar1<<FRACBITS, false);
 }
+
+// Function: A_FadeOverlay
+//
+// Description: Makes a pretty overlay (primarily for super/NiGHTS transformation).
+//
+// var1 = bit 1 = don't halt momentum, bit 2 = don't make fast, bit 3 = don't set tracer
+// var2 = unused
+//
+void A_FadeOverlay(mobj_t *actor)
+{
+	mobj_t *fade;
+	INT32 locvar1 = var1;
+	//INT32 locvar2 = var2;
+
+#ifdef HAVE_BLUA
+	if (LUA_CallAction("A_FadeOverlay", actor))
+		return;
+#endif
+
+	if (!(locvar1 & 1))
+		actor->momx = actor->momy = actor->momz = 0;
+
+	fade = P_SpawnGhostMobj(actor);
+	fade->frame = actor->frame;
+
+	if (!(locvar1 & 2))
+	{
+		fade->fuse = 15;
+		fade->flags2 |= MF2_BOSSNOTRAP;
+	}
+	else
+		fade->fuse = 20;
+
+	if (!(locvar1 & 4))
+		P_SetTarget(&actor->tracer, fade);
+}
diff --git a/src/p_floor.c b/src/p_floor.c
index 9ac6a3896..c72de6b70 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1751,6 +1751,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
 		{
 		case MT_NULL:
 		case MT_UNKNOWN:
+		case MT_TAILSOVERLAY:
 		case MT_THOK:
 		case MT_GHOST:
 		case MT_OVERLAY:
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4fe5be9c4..fffee7c8b 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -322,7 +322,9 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
 		mobj->tics = st->tics;
 
 		// Adjust the player's animation speed to match their velocity.
-		if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
+		if (state == S_PLAY_STND && player->powers[pw_super] && skins[player->skin].sprites[SPR2_WAIT|FF_SPR2SUPER].numframes == 0) // if no super wait, don't wait at all
+			mobj->tics = -1;
+		else if (player->panim == PA_EDGE && (player->charflags & SF_FASTEDGE))
 			mobj->tics = 2;
 		else if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST))
 		{
@@ -6646,10 +6648,21 @@ void P_MobjThinker(mobj_t *mobj)
 			}
 	}
 
-	if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
-	&& (signed)(mobj->frame >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
-		// fade out when nearing the end of fuse...
-		mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
+	if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
+	{
+		if (mobj->flags2 & MF2_BOSSNOTRAP) // "fast" flag
+		{
+			if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - (2*mobj->fuse)/3)
+				// fade out when nearing the end of fuse...
+				mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - (2*mobj->fuse)/3) << FF_TRANSSHIFT);
+		}
+		else
+		{
+			if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
+				// fade out when nearing the end of fuse...
+				mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
+		}
+	}
 
 	if (mobj->flags2 & MF2_MACEROTATE)
 	{
@@ -6890,9 +6903,9 @@ void P_MobjThinker(mobj_t *mobj)
 				P_SetScale(mobj, mobj->target->scale);
 
 				if (!(mobj->eflags & MFE_VERTICALFLIP))
-					mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
+					mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
 				else
-					mobj->z = mobj->target->z - FixedMul((16 + abs((leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height;
+					mobj->z = mobj->target->z - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height;
 				break;
 			case MT_DROWNNUMBERS:
 				if (!mobj->target)
@@ -9831,7 +9844,7 @@ ML_EFFECT4 : Don't clip inside the ground
 			mmin = mnumspokes;
 
 		// Make the links the same type as the end - repeated below
-		if ((mobj->type != MT_CHAINPOINT) && (!(lines[line].flags & ML_EFFECT2) == (mobj->type == MT_FIREBARPOINT))) // exclusive or
+		if ((mobj->type != MT_CHAINPOINT) && ((lines[line].flags & ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or
 		{
 			linktype = macetype;
 			radiusfactor = 2; // Double the radius.
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 71bc93971..2e8615c17 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -56,6 +56,7 @@ typedef enum
 	AWAYVIEW   = 0x08,
 	FIRSTAXIS  = 0x10,
 	SECONDAXIS = 0x20,
+	FOLLOW     = 0x40,
 } player_saveflags;
 
 //
@@ -220,6 +221,9 @@ static void P_NetArchivePlayers(void)
 		if (players[i].axis2)
 			flags |= SECONDAXIS;
 
+		if (players[i].followmobj)
+			flags |= FOLLOW;
+
 		WRITEINT16(save_p, players[i].lastsidehit);
 		WRITEINT16(save_p, players[i].lastlinehit);
 
@@ -245,6 +249,9 @@ static void P_NetArchivePlayers(void)
 		if (flags & AWAYVIEW)
 			WRITEUINT32(save_p, players[i].awayviewmobj->mobjnum);
 
+		if (flags & FOLLOW)
+			WRITEUINT32(save_p, players[i].followmobj->mobjnum);
+
 		WRITEFIXED(save_p, players[i].camerascale);
 		WRITEFIXED(save_p, players[i].shieldscale);
 
@@ -254,6 +261,7 @@ static void P_NetArchivePlayers(void)
 		WRITEUINT32(save_p, (UINT32)players[i].thokitem);
 		WRITEUINT32(save_p, (UINT32)players[i].spinitem);
 		WRITEUINT32(save_p, (UINT32)players[i].revitem);
+		WRITEUINT32(save_p, (UINT32)players[i].followitem);
 		WRITEFIXED(save_p, players[i].actionspd);
 		WRITEFIXED(save_p, players[i].mindash);
 		WRITEFIXED(save_p, players[i].maxdash);
@@ -413,6 +421,9 @@ static void P_NetUnArchivePlayers(void)
 		if (flags & AWAYVIEW)
 			players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save_p);
 
+		if (flags & FOLLOW)
+			players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p);
+
 		players[i].viewheight = READFIXED(save_p);
 
 		players[i].camerascale = READFIXED(save_p);
@@ -425,6 +436,7 @@ static void P_NetUnArchivePlayers(void)
 		players[i].thokitem = (mobjtype_t)READUINT32(save_p);
 		players[i].spinitem = (mobjtype_t)READUINT32(save_p);
 		players[i].revitem = (mobjtype_t)READUINT32(save_p);
+		players[i].followitem = (mobjtype_t)READUINT32(save_p);
 		players[i].actionspd = READFIXED(save_p);
 		players[i].mindash = READFIXED(save_p);
 		players[i].maxdash = READFIXED(save_p);
@@ -3060,6 +3072,13 @@ static void P_RelinkPointers(void)
 				if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp)))
 					CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type);
 			}
+			if (mobj->player && mobj->player->followmobj)
+			{
+				temp = (UINT32)(size_t)mobj->player->followmobj;
+				mobj->player->followmobj = NULL;
+				if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp)))
+					CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type);
+			}
 		}
 	}
 }
diff --git a/src/p_user.c b/src/p_user.c
index 6dd2a5e18..67375d862 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -592,6 +592,7 @@ static void P_DeNightserizePlayer(player_t *player)
 	player->mo->flags &= ~MF_NOGRAVITY;
 
 	player->mo->skin = &skins[player->skin];
+	player->followitem = skins[player->skin].followitem;
 	player->mo->color = player->skincolor;
 
 	// Restore aiming angle
@@ -666,14 +667,16 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
 	if (skins[player->skin].sprites[SPR2_NGT0].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
 	{
 		player->mo->skin = &skins[DEFAULTNIGHTSSKIN];
-		player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
+		if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
+			player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
+		player->followitem = skins[DEFAULTNIGHTSSKIN].followitem;
 	}
 
 	player->nightstime = player->startedtime = nighttime*TICRATE;
 	player->bonustime = false;
 
 	P_RestoreMusic(player);
-	P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_TRANS);
+	P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_TRANS1);
 
 	if (gametype == GT_RACE || gametype == GT_COMPETITION)
 	{
@@ -1000,10 +1003,10 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
 	S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
 
 	// Transformation animation
-	P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS);
+	P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1);
 
 	player->mo->momx = player->mo->momy = player->mo->momz = 0;
-	player->pflags &= ~(PF_JUMPED|PF_NOJUMPDAMAGE);
+	player->pflags |= PF_NOJUMPDAMAGE; // just to avoid recurling but still allow thok
 
 	if (giverings)
 		player->rings = 50;
@@ -1552,9 +1555,7 @@ void P_SwitchShield(player_t *player, UINT16 shieldtype)
 //
 mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 {
-	mobj_t *ghost;
-
-	ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST);
+	mobj_t *ghost = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_GHOST);
 
 	P_SetScale(ghost, mobj->scale);
 	ghost->destscale = mobj->scale;
@@ -1580,6 +1581,14 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
 	if (mobj->flags2 & MF2_OBJECTFLIP)
 		ghost->flags |= MF2_OBJECTFLIP;
 
+	if (mobj->player && mobj->player->followmobj)
+	{
+		mobj_t *ghost2 = P_SpawnGhostMobj(mobj->player->followmobj);
+		P_SetTarget(&ghost2->tracer, ghost);
+		P_SetTarget(&ghost->tracer, ghost2);
+		ghost2->flags2 |= MF2_LINKDRAW;
+	}
+
 	return ghost;
 }
 
@@ -3651,9 +3660,8 @@ static void P_DoSuperStuff(player_t *player)
 {
 	mobj_t *spark;
 	ticcmd_t *cmd = &player->cmd;
-	if (player->mo->state >= &states[S_PLAY_SUPER_TRANS]
-	&& (player->mo->state < &states[S_PLAY_SUPER_TRANS9]
-	|| (player->mo->state == &states[S_PLAY_SUPER_TRANS9] && player->mo->tics > 1))) // needed to prevent one-frame old colour...
+	if (player->mo->state >= &states[S_PLAY_SUPER_TRANS1]
+	&& player->mo->state < &states[S_PLAY_SUPER_TRANS6])
 		return; // don't do anything right now, we're in the middle of transforming!
 
 	if (player->powers[pw_carry] == CR_NIGHTSMODE)
@@ -3670,7 +3678,7 @@ static void P_DoSuperStuff(player_t *player)
 			P_SpawnShieldOrb(player);
 
 			// Restore color
-			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_FIREFLOWER)
+			if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
 			{
 				player->mo->color = SKINCOLOR_WHITE;
 				G_GhostAddColor(GHC_FIREFLOWER);
@@ -3690,14 +3698,19 @@ static void P_DoSuperStuff(player_t *player)
 			return;
 		}
 
+		player->mo->color = (player->pflags & PF_GODMODE && cv_debug == 0)
+		? (SKINCOLOR_SUPERSILVER1 + 5*(((signed)leveltime >> 1) % 7)) // A wholesome easter egg.
+		: skins[player->skin].supercolor + abs( ( (player->powers[pw_super] >> 1) % 9) - 4); // This is where super flashing is handled.
+
+		G_GhostAddColor(GHC_SUPER);
+
+		if (player->mo->state == &states[S_PLAY_SUPER_TRANS6]) // stop here for now
+			return;
+
 		// Deplete one ring every second while super
 		if ((leveltime % TICRATE == 0) && !(player->exiting))
 			player->rings--;
 
-		player->mo->color = (player->pflags & PF_GODMODE && cv_debug == 0)
-		? (SKINCOLOR_SUPERSILVER1 + 5*((leveltime >> 1) % 7)) // A wholesome easter egg.
-		: skins[player->skin].supercolor + (unsigned)abs( ( (signed)(leveltime >> 1) % 9) - 4); // This is where super flashing is handled.
-
 		if ((cmd->forwardmove != 0 || cmd->sidemove != 0 || player->powers[pw_carry])
 		&& !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy))
 		{
@@ -3706,8 +3719,6 @@ static void P_DoSuperStuff(player_t *player)
 			P_SetScale(spark, player->mo->scale);
 		}
 
-		G_GhostAddColor(GHC_SUPER);
-
 		// Ran out of rings while super!
 		if (player->rings <= 0 || player->exiting)
 		{
@@ -3717,7 +3728,7 @@ static void P_DoSuperStuff(player_t *player)
 			player->powers[pw_super] = 0;
 
 			// Restore color
-			if ((player->powers[pw_shield] & SH_NOSTACK) == SH_FIREFLOWER)
+			if ((player->powers[pw_shield] & SH_STACK) == SH_FIREFLOWER)
 			{
 				player->mo->color = SKINCOLOR_WHITE;
 				G_GhostAddColor(GHC_FIREFLOWER);
@@ -6082,14 +6093,14 @@ static void P_NiGHTSMovement(player_t *player)
 			&& (players[i].capsule && players[i].capsule->reactiontime))
 				capsule = true;
 		if (!capsule
-		&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS]
-			&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS9])
+		&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
+			&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
 		&& !player->exiting)
 			player->nightstime--;
 	}
 	else if (gametype != GT_RACE && gametype != GT_COMPETITION
-	&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS]
-			&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS9])
+	&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
+			&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
 	&& !(player->capsule && player->capsule->reactiontime)
 	&& !player->exiting)
 		player->nightstime--;
@@ -6228,8 +6239,8 @@ static void P_NiGHTSMovement(player_t *player)
 		return;
 	}
 
-	if (player->mo->state >= &states[S_PLAY_NIGHTS_TRANS]
-		&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS9])
+	if (player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
+		&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6])
 	{
 		player->mo->momx = player->mo->momy = player->mo->momz = 0;
 		return;
@@ -6833,7 +6844,7 @@ static void P_MovePlayer(player_t *player)
 
 	fixed_t runspd;
 
-	if (player->mo->state >= &states[S_PLAY_SUPER_TRANS] && player->mo->state <= &states[S_PLAY_SUPER_TRANS9])
+	if (player->mo->state >= &states[S_PLAY_SUPER_TRANS1] && player->mo->state <= &states[S_PLAY_SUPER_TRANS6])
 	{
 		player->mo->momx = player->mo->momy = player->mo->momz = 0;
 		return;
@@ -6902,12 +6913,12 @@ static void P_MovePlayer(player_t *player)
 	else if (maptol & TOL_NIGHTS)
 	{
 		if ((player->powers[pw_carry] == CR_NIGHTSMODE)
-		&& !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS]
-		&& player->mo->state <= &states[S_PLAY_NIGHTS_TRANS6] // NOT 9 - it's 6 when the player turns their supercolor.
-		&& !(player->exiting)))
+		&& (player->exiting
+		|| !(player->mo->state >= &states[S_PLAY_NIGHTS_TRANS1]
+			&& player->mo->state < &states[S_PLAY_NIGHTS_TRANS6])))
 		{
 			skin_t *skin = ((skin_t *)(player->mo->skin));
-			player->mo->color = (skin->flags & SF_SUPER) ? skin->supercolor + (unsigned)abs(((signed)(leveltime >> 1) % 9) - 4) : player->mo->color; // This is where super flashing is handled.
+			player->mo->color = (skin->flags & SF_SUPER) ? skin->supercolor + abs((((signed)(player->startedtime - player->nightstime) >> 1) % 9) - 4) : player->mo->color; // This is where super flashing is handled.
 		}
 
 		if (!player->capsule && !player->bonustime)
@@ -9721,7 +9732,8 @@ void P_PlayerThink(player_t *player)
 				ticmiss++;
 
 			P_DoRopeHang(player);
-			P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
+			if (player->mo->state-states != S_PLAY_RIDE)
+				P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
 			P_DoJumpStuff(player, &player->cmd);
 		}
 		else //if (player->powers[pw_carry] == CR_ZOOMTUBE)
@@ -9892,10 +9904,17 @@ void P_PlayerThink(player_t *player)
 	{
 		mobj_t *gmobj = P_SpawnGhostMobj(player->mo);
 		gmobj->fuse = 2;
+		if (gmobj->tracer)
+			gmobj->tracer->fuse = 2;
 		if (leveltime & 1)
 		{
 			gmobj->frame &= ~FF_TRANSMASK;
 			gmobj->frame |= tr_trans70<<FF_TRANSSHIFT;
+			if (gmobj->tracer)
+			{
+				gmobj->tracer->frame &= ~FF_TRANSMASK;
+				gmobj->tracer->frame |= tr_trans70<<FF_TRANSSHIFT;
+			}
 		}
 
 		// Hide the mobj from our sights if we're the displayplayer and chasecam is off,
@@ -9969,7 +9988,9 @@ void P_PlayerThink(player_t *player)
 		player->powers[pw_nocontrol] = 0;
 
 	//pw_super acts as a timer now
-	if (player->powers[pw_super])
+	if (player->powers[pw_super]
+	&& (player->mo->state < &states[S_PLAY_SUPER_TRANS1]
+	|| player->mo->state > &states[S_PLAY_SUPER_TRANS6]))
 		player->powers[pw_super]++;
 
 	if (player->powers[pw_carry] == CR_BRAKGOOP)
@@ -10161,6 +10182,11 @@ void P_PlayerAfterThink(player_t *player)
 			if (thiscam && thiscam->chase)
 				P_MoveChaseCamera(player, thiscam, false);
 		}
+		if (player->followmobj)
+		{
+			P_RemoveMobj(player->followmobj);
+			player->followmobj = NULL;
+		}
 		return;
 	}
 
@@ -10334,7 +10360,10 @@ void P_PlayerAfterThink(player_t *player)
 			player->powers[pw_carry] = CR_NONE;
 
 		if (player->powers[pw_carry] != CR_NONE)
-			P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
+		{
+			if (player->mo->state-states != S_PLAY_RIDE)
+				P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
+		}
 		else
 			P_SetTarget(&player->mo->tracer, NULL);
 
@@ -10353,7 +10382,8 @@ void P_PlayerAfterThink(player_t *player)
 			player->mo->z = player->mo->tracer->z - FixedDiv(player->mo->height, 3*FRACUNIT/2);
 		player->mo->momx = player->mo->momy = player->mo->momz = 0;
 		P_SetThingPosition(player->mo);
-		P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
+		if (player->mo->state-states != S_PLAY_RIDE)
+			P_SetPlayerMobjState(player->mo, S_PLAY_RIDE);
 
 		// Controllable missile
 		if (player->mo->tracer->type == MT_BLACKEGGMAN_MISSILE)
@@ -10447,4 +10477,224 @@ void P_PlayerAfterThink(player_t *player)
 
 	if (P_IsObjectOnGround(player->mo))
 		player->mo->pmomz = 0;
+
+	if (player->followmobj && (player->spectator || player->mo->health <= 0 || player->followmobj->type != player->followitem))
+	{
+		P_RemoveMobj(player->followmobj);
+		player->followmobj = NULL;
+	}
+
+	if (!player->spectator && player->mo->health && player->followitem)
+	{
+		if (!player->followmobj || P_MobjWasRemoved(player->followmobj))
+		{
+			player->followmobj = P_SpawnMobjFromMobj(player->mo, 0, 0, 0, player->followitem);
+			P_SetTarget(&player->followmobj->tracer, player->mo);
+			player->followmobj->flags2 |= MF2_LINKDRAW;
+		}
+
+		if (player->followmobj)
+		{
+#ifdef HAVE_BLUA
+			if (LUAh_FollowMobj(player, player->followmobj) || P_MobjWasRemoved(player->followmobj))
+				{;}
+			else
+#endif
+			{
+				switch (player->followmobj->type)
+				{
+					case MT_TAILSOVERLAY: // c:
+						{
+							// init...
+							boolean smilesonground = P_IsObjectOnGround(player->mo);
+							angle_t horizangle = player->drawangle;
+							fixed_t zoffs = 0;
+							fixed_t backwards = -1*FRACUNIT;
+							boolean doroll = (player->panim == PA_ROLL || player->panim == PA_JUMP);
+							angle_t rollangle;
+							boolean panimchange;
+							INT32 ticnum = 0;
+							statenum_t chosenstate;
+
+							if (!player->followmobj->skin)
+							{
+								player->followmobj->skin = player->mo->skin;
+								P_SetMobjState(player->followmobj, S_TAILSOVERLAY_STAND);
+								player->followmobj->movecount = -1;
+							}
+
+							panimchange = (player->followmobj->movecount != (INT32)player->panim);
+
+							// initial position...
+							if (doroll)
+							{
+								fixed_t testval, zdist;
+								if (player->speed < FRACUNIT)
+									testval = FRACUNIT;
+								else
+								{
+									testval = (FixedMul(player->speed, FINECOSINE((horizangle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT)));
+									if (testval < FRACUNIT)
+										testval = FRACUNIT;
+								}
+								if (smilesonground && !player->mo->reactiontime)
+									zdist = (player->mo->z - player->followmobj->threshold);
+								else
+									zdist = player->mo->momz;
+								rollangle = R_PointToAngle2(0, 0, testval, -P_MobjFlip(player->mo)*zdist);
+								zoffs = 3*FRACUNIT + 12*FINESINE(rollangle >> ANGLETOFINESHIFT);
+								backwards = -12*FINECOSINE(rollangle >> ANGLETOFINESHIFT);
+							}
+							else if (player->panim == PA_RUN)
+								backwards = -5*FRACUNIT;
+							else if (player->panim == PA_SPRING)
+							{
+								zoffs += 4*FRACUNIT;
+								backwards /= 2;
+							}
+							else if (player->panim == PA_PAIN)
+								backwards /= 16;
+							else if (player->mo->state-states == S_PLAY_GASP)
+							{
+								backwards /= 16;
+								zoffs += 12*FRACUNIT;
+							}
+							else if (player->mo->state-states == S_PLAY_EDGE)
+							{
+								backwards /= 16;
+								zoffs = 3*FRACUNIT;
+							}
+							else if (player->panim == PA_ABILITY2)
+							{
+								zoffs = -7*FRACUNIT;
+								backwards = -9*FRACUNIT;
+							}
+							else if (player->mo->sprite2 == SPR2_FLY || player->mo->sprite2 == SPR2_TIRE)
+								backwards = -5*FRACUNIT;
+
+							// sprite...
+							if (doroll)
+							{
+								statenum_t add = ((rollangle > ANGLE_180) ? 2 : 0);
+								if (add)
+									rollangle = InvAngle(rollangle);
+								rollangle += ANG15; // modify the thresholds to be nice clean numbers
+								if (rollangle > ANG60)
+									chosenstate = S_TAILSOVERLAY_PLUS60DEGREES + add;
+								else if (rollangle > ANG30)
+									chosenstate = S_TAILSOVERLAY_PLUS30DEGREES + add;
+								else
+									chosenstate = S_TAILSOVERLAY_0DEGREES;
+							}
+							else if (player->panim == PA_SPRING)
+								chosenstate = S_TAILSOVERLAY_MINUS60DEGREES;
+							else if (player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
+								chosenstate = S_TAILSOVERLAY_PLUS60DEGREES;
+							else if (player->panim == PA_PAIN)
+								chosenstate = S_TAILSOVERLAY_PAIN;
+							else if (player->mo->state-states == S_PLAY_GASP)
+								chosenstate = S_TAILSOVERLAY_GASP;
+							else if (player->mo->state-states == S_PLAY_EDGE)
+								chosenstate = S_TAILSOVERLAY_EDGE;
+							else if (player->panim == PA_RUN)
+								chosenstate = S_TAILSOVERLAY_RUN;
+							else if (player->panim == PA_WALK)
+							{
+								if (!smilesonground)
+									chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
+								else if (player->speed >= FixedMul(player->runspeed/2, player->mo->scale))
+									chosenstate = S_TAILSOVERLAY_0DEGREES;
+								else
+									chosenstate = S_TAILSOVERLAY_MINUS30DEGREES;
+							}
+							else if (player->mo->sprite2 == SPR2_FLY)
+								chosenstate = S_TAILSOVERLAY_FLY;
+							else if (player->mo->sprite2 == SPR2_TIRE)
+								chosenstate = S_TAILSOVERLAY_TIRE;
+							else if (player->panim == PA_ABILITY2)
+								chosenstate = S_TAILSOVERLAY_PLUS30DEGREES;
+							else if (player->panim == PA_IDLE)
+								chosenstate = S_TAILSOVERLAY_STAND;
+							else
+								chosenstate = S_INVISIBLE;
+
+							// state...
+							if (panimchange)
+							{
+								player->followmobj->sprite2 = -1;
+								P_SetMobjState(player->followmobj, chosenstate);
+							}
+							else
+							{
+								if (player->followmobj->state != states+chosenstate)
+								{
+									if (states[chosenstate].sprite == SPR_PLAY)
+										player->followmobj->sprite2 = P_GetSkinSprite2(((skin_t *)player->followmobj->skin), (states[chosenstate].frame & FF_FRAMEMASK), player);
+									P_SetMobjState(player->followmobj, chosenstate);
+								}
+							}
+
+							if (player->fly1 != 0 && player->powers[pw_tailsfly] != 0 && !smilesonground)
+								P_SetMobjState(player->followmobj, chosenstate);
+
+							// animation...
+							if (player->panim == PA_SPRING || player->panim == PA_FALL || player->mo->state-states == S_PLAY_RIDE)
+							{
+								if (FixedDiv(abs(player->mo->momz), player->mo->scale) < 20<<FRACBITS)
+									ticnum = 2;
+								else
+									ticnum = 1;
+							}
+							else if (player->panim == PA_PAIN)
+								ticnum = 2;
+							else if (player->mo->state-states == S_PLAY_GASP)
+								player->followmobj->tics = -1;
+							else if (player->mo->sprite2 == SPR2_TIRE)
+								ticnum = 4;
+							else if (player->panim != PA_IDLE)
+								ticnum = player->mo->tics;
+
+							if (ticnum && player->followmobj->tics > ticnum)
+								player->followmobj->tics = ticnum;
+
+							// final handling...
+							player->followmobj->color = player->mo->color;
+							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;
+							player->followmobj->height = player->mo->height;
+							zoffs = FixedMul(zoffs, player->followmobj->scale);
+
+							if (player->mo->eflags & MFE_VERTICALFLIP)
+							{
+								player->followmobj->eflags |= MFE_VERTICALFLIP;
+								player->followmobj->flags2 |= MF2_OBJECTFLIP;
+								zoffs = player->mo->height - player->followmobj->height - zoffs;
+							}
+							else
+							{
+								player->followmobj->eflags &= ~MFE_VERTICALFLIP;
+								player->followmobj->flags2 &= ~MF2_OBJECTFLIP;
+							}
+
+							P_UnsetThingPosition(player->followmobj);
+							player->followmobj->x = player->mo->x + P_ReturnThrustX(player->followmobj, player->followmobj->angle, FixedMul(backwards, player->followmobj->scale));
+							player->followmobj->y = player->mo->y + P_ReturnThrustY(player->followmobj, player->followmobj->angle, FixedMul(backwards, player->followmobj->scale));
+							player->followmobj->z = player->mo->z + zoffs;
+							P_SetThingPosition(player->followmobj);
+						}
+						break;
+					default:
+						var1 = 1;
+						var2 = 0;
+						A_CapeChase(player->followmobj);
+						break;
+				}
+			}
+		}
+	}
 }
diff --git a/src/r_things.c b/src/r_things.c
index 116782c3c..9ab7b5d1e 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -1385,12 +1385,12 @@ static void R_ProjectSprite(mobj_t *thing)
 	// specific translucency
 	if (!cv_translucency.value)
 		; // no translucency
-	else if (oldthing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
+	else if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
 		vis->transmap = transtables + ((tr_trans80-1)<<FF_TRANSSHIFT); // because now the translucency is set through FF_TRANSMASK
 	else if (oldthing->frame & FF_TRANSMASK)
 		vis->transmap = transtables + (oldthing->frame & FF_TRANSMASK) - 0x10000;
 
-	if ((oldthing->frame & FF_FULLBRIGHT) || (oldthing->flags2 & MF2_SHADOW))
+	if (oldthing->frame & FF_FULLBRIGHT || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW)
 		vis->cut |= SC_FULLBRIGHT;
 
 	if (vis->cut & SC_FULLBRIGHT
@@ -2438,7 +2438,7 @@ UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player)
 
 	while (!(skin->sprites[spr2].numframes)
 		&& spr2 != SPR2_STND
-		&& ++i != 32) // recursion limiter
+		&& ++i < 32) // recursion limiter
 	{
 		if (spr2 & FF_SPR2SUPER)
 		{
@@ -2525,6 +2525,7 @@ static void Sk_SetDefaultValue(skin_t *skin)
 	skin->thokitem = -1;
 	skin->spinitem = -1;
 	skin->revitem = -1;
+	skin->followitem = 0;
 
 	skin->highresscale = FRACUNIT;
 
@@ -2638,6 +2639,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 		player->thokitem = skin->thokitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].painchance : (UINT32)skin->thokitem;
 		player->spinitem = skin->spinitem < 0 ? (UINT32)mobjinfo[MT_PLAYER].damage : (UINT32)skin->spinitem;
 		player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
+		player->followitem = skin->followitem;
 
 		player->actionspd = skin->actionspd;
 		player->mindash = skin->mindash;
@@ -2663,13 +2665,21 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
 			player->skincolor = newcolor = skin->prefcolor;
 		}
 
+		if (player->followmobj)
+		{
+			P_RemoveMobj(player->followmobj);
+			player->followmobj = NULL;
+		}
+
 		if (player->mo)
 		{
 			fixed_t radius = FixedMul(skin->radius, player->mo->scale);
 			if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (skin->sprites[SPR2_NGT0].numframes == 0)) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
 			{
 				skin = &skins[DEFAULTNIGHTSSKIN];
-				newcolor = skin->prefcolor; // will be updated in thinker to flashing
+				player->followitem = skin->followitem;
+				if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
+					newcolor = skin->prefcolor; // will be updated in thinker to flashing
 			}
 			player->mo->skin = skin;
 			if (newcolor)
@@ -2803,6 +2813,7 @@ static boolean R_ProcessPatchableFields(skin_t *skin, char *stoken, char *value)
 	FULLPROCESS(thokitem)
 	FULLPROCESS(spinitem)
 	FULLPROCESS(revitem)
+	FULLPROCESS(followitem)
 #undef FULLPROCESS
 
 #define GETFRACBITS(field) else if (!stricmp(stoken, #field)) skin->field = atoi(value)<<FRACBITS;
diff --git a/src/r_things.h b/src/r_things.h
index 18cc701ab..e1a171c1f 100644
--- a/src/r_things.h
+++ b/src/r_things.h
@@ -82,6 +82,7 @@ typedef struct
 	INT32 thokitem;
 	INT32 spinitem;
 	INT32 revitem;
+	INT32 followitem;
 	fixed_t actionspd;
 	fixed_t mindash;
 	fixed_t maxdash;
diff --git a/src/st_stuff.c b/src/st_stuff.c
index ceef586a4..66907036e 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -700,10 +700,21 @@ static void ST_drawLives(void)
 		// skincolor face/super
 		UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->color, GTC_CACHE);
 		patch_t *face = faceprefix[stplyr->skin];
-		if ((stplyr->powers[pw_super] && (stplyr->mo->state < &states[S_PLAY_SUPER_TRANS] || stplyr->mo->state > &states[S_PLAY_SUPER_TRANS9])) || (stplyr->powers[pw_carry] == CR_NIGHTSMODE && skins[stplyr->skin].flags & SF_SUPER))
+		if (stplyr->powers[pw_super])
 			face = superprefix[stplyr->skin];
 		V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0),
 			V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS|v_splitflag,face, colormap);
+		if (cv_translucenthud.value == 10 && stplyr->powers[pw_super] == 1 && stplyr->mo->tracer)
+		{
+			INT32 v_supertrans = (stplyr->mo->tracer->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
+			if (v_supertrans < 10)
+			{
+				v_supertrans <<= V_ALPHASHIFT;
+				colormap = R_GetTranslationColormap(stplyr->skin, stplyr->mo->tracer->color, GTC_CACHE);
+				V_DrawSmallMappedPatch(hudinfo[HUD_LIVESPIC].x, hudinfo[HUD_LIVESPIC].y + (v_splitflag ? -12 : 0),
+					V_SNAPTOLEFT|V_SNAPTOBOTTOM|v_supertrans|v_splitflag,face, colormap);
+			}
+		}
 	}
 	else if (stplyr->skincolor)
 	{
@@ -2066,7 +2077,7 @@ static void ST_overlayDrawer(void)
 						V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132)-(splitscreen ? 12 : 0), V_HUDTRANSHALF, M_GetText("You'll steal a life on respawn."));
 				}
 			}
-			else if (!gametype == GT_COOP)
+			else if (gametype != GT_COOP)
 				V_DrawCenteredString(BASEVIDWIDTH/2, STRINGY(132), V_HUDTRANSHALF, M_GetText("Press Fire to enter the game."));
 			if (!splitscreen)
 			{