diff --git a/src/g_demo.c b/src/g_demo.c
index c30b07f25473ac8ed1b4549ac3fefef76b425823..f64f34168efd8286ba21199841be95bc60fceb3d 100644
--- a/src/g_demo.c
+++ b/src/g_demo.c
@@ -55,7 +55,7 @@ static UINT8 *demobuffer = NULL;
 static UINT8 *demo_p, *demotime_p;
 static UINT8 *demoend;
 static UINT8 demoflags;
-static UINT16 demoversion;
+UINT16 demoversion;
 boolean singledemo; // quit after playing a demo from cmdline
 boolean demo_start; // don't start playing demo right away
 boolean demo_forwardmove_rng; // old demo backwards compatibility
@@ -98,7 +98,7 @@ demoghost *ghosts = NULL;
 // DEMO RECORDING
 //
 
-#define DEMOVERSION 0x0010
+#define DEMOVERSION 0x0011
 #define DEMOHEADER  "\xF0" "SRB2Replay" "\x0F"
 
 #define DF_GHOST        0x01 // This demo contains ghost data too!
diff --git a/src/g_demo.h b/src/g_demo.h
index 379c57428a6db9daeef1b5d6ab6368436224c828..e8c0c8d956187161ea5bbaffe9c145c764a40ba4 100644
--- a/src/g_demo.h
+++ b/src/g_demo.h
@@ -25,6 +25,7 @@
 // demoplaying back and demo recording
 extern boolean demoplayback, titledemo, demorecording, timingdemo;
 extern tic_t demostarttime;
+extern UINT16 demoversion;
 
 typedef enum
 {
diff --git a/src/p_user.c b/src/p_user.c
index 52cdc41e5208a236734143fc22bd9487f5982d76..7e19e8d6367dbb874c7b21b105dd5f18e6dba9fb 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -19,6 +19,7 @@
 #include "d_event.h"
 #include "netcode/d_net.h"
 #include "netcode/net_command.h"
+#include "g_demo.h" // demoplayback, demoversion
 #include "g_game.h"
 #include "p_local.h"
 #include "r_fps.h"
@@ -7521,49 +7522,46 @@ static void P_NiGHTSMovement(player_t *player)
 				newangle = 270;
 		}
 		else // AngleFixed(R_PointToAngle2()) results in slight inaccuracy! Don't use it unless movement is on both axises.
+		{
 			newangle = (INT16)FixedInt(AngleFixed(R_PointToAngle2(0,0, cmd->sidemove*FRACUNIT, cmd->forwardmove*FRACUNIT)));
 
+			if (cmd->forwardmove == -36 && cmd->sidemove == 35 && !(demoplayback && demoversion < 0x0011))
+				newangle = 315; // Hack to compensate for directly down-right returning 314, not 315
+		}
+
 		newangle -= player->viewrollangle / ANG1;
 
 		if (newangle < 0 && moved)
 			newangle = (INT16)(360+newangle);
-	}
 
-	if (player->pflags & PF_DRILLING)
-		thrustfactor = 2;
-	else
-	{
-		thrustfactor = 8;
-
-		// Decelerate while turning normally.
-		if (moved && player->flyangle != newangle && player->speed > 12000)
-			player->speed -= 60;
-	}
-
-	for (i = 0; i < thrustfactor; i++)
-	{
 		if (moved && player->flyangle != newangle)
 		{
-			INT32 anglediff = (((newangle-player->flyangle)+360)%360);
-			INT32 angledif2 = (((player->flyangle-newangle)+360)%360);
+			// "player->flyangle" is our current angle, "newangle" is where we want to go
+			INT32 anglediff = ((newangle - player->flyangle) + 360) % 360; // "+360" and then "%360" wraps it to 0-359
 
-			// player->flyangle is the one to move
-			// newangle is the "move to"
-			if (anglediff == 0 && angledif2 == 0)
-				break;
+			// How sharply can we turn?
+			if (player->pflags & PF_DRILLING)
+				thrustfactor = 2;
+			else
+			{
+				thrustfactor = 8;
+				if (player->speed > 12000) // Decelerate while turning normally
+					player->speed -= 60;
+			}
 
-			if (anglediff>angledif2)
-				player->flyangle--;
-			else // if (anglediff<angledif2)
-				player->flyangle++;
-		}
+			// Now, turn!
+			if (anglediff <= thrustfactor || anglediff >= (360-thrustfactor))
+				player->flyangle = newangle;
+			else if (anglediff <= 180)
+				player->flyangle += thrustfactor;
+			else
+				player->flyangle -= thrustfactor;
 
-		// Buff out negatives, >360 angles...
-		player->flyangle = ((player->flyangle + 360) % 360);
+			player->flyangle = (player->flyangle + 360) % 360; // Buff out negatives, >360 angles...
+		}
 	}
 
-	if (!(player->speed)
-		&& cmd->forwardmove == 0)
+	if (player->speed == 0 && cmd->forwardmove == 0 && (cmd->sidemove == 0 || (demoplayback && demoversion < 0x0011)))
 		still = true;
 
 	// No more bumper braking
@@ -7724,6 +7722,9 @@ static void P_NiGHTSMovement(player_t *player)
 					visangle += 180;
 			}
 
+			if (player->mo->eflags & MFE_VERTICALFLIP) // Flip the roll angle in reverse gravity
+				visangle *= -1;
+
 			rollangle = FixedAngle(visangle<<FRACBITS);
 		}
 	}
diff --git a/src/st_stuff.c b/src/st_stuff.c
index e33d61f36578d5eae7d27ddf5b81138f439d1232..378d3ba7d0dee09aff27902d61646c880b43aad9 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1785,45 +1785,48 @@ static void ST_drawNightsRecords(void)
 
 static void ST_drawNiGHTSLink(void)
 {
-	static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0};
-	const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0);
-	INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? (stplyr->linkcount-1 >= 600) ? 2 : 1 : 0);
-	skincolornum_t colornum;
-	fixed_t x, y, scale;
-
-	if (sel != prevsel[q])
+	if (stplyr->linkcount != 0) // Don't show a faint 4294967295 link, even when debugging
 	{
-		prevsel[q] = sel;
-		prevtime[q] = 2 + mag;
-	}
+		static INT32 prevsel[2] = {0, 0}, prevtime[2] = {0, 0};
+		const UINT8 q = ((splitscreen && stplyr == &players[secondarydisplayplayer]) ? 1 : 0);
+		INT32 sel = ((stplyr->linkcount-1) / 5) % NUMLINKCOLORS, aflag = V_PERPLAYER, mag = ((stplyr->linkcount-1 >= 300) ? (stplyr->linkcount-1 >= 600) ? 2 : 1 : 0);
+		skincolornum_t colornum;
+		fixed_t x, y, scale;
 
-	if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics)))
-		colornum = SKINCOLOR_ICY;
-	else
-		colornum = linkColor[mag][sel];
+		if (sel != prevsel[q])
+		{
+			prevsel[q] = sel;
+			prevtime[q] = 2 + mag;
+		}
 
-	aflag |= ((stplyr->linktimer < (UINT32)nightslinktics/3)
-	? (9 - 9*stplyr->linktimer/(nightslinktics/3)) << V_ALPHASHIFT
-	: 0);
+		if (stplyr->powers[pw_nights_linkfreeze] && (!(stplyr->powers[pw_nights_linkfreeze] & 2) || (stplyr->powers[pw_nights_linkfreeze] > flashingtics)))
+			colornum = SKINCOLOR_ICY;
+		else
+			colornum = linkColor[mag][sel];
 
-	y = (160+11)<<FRACBITS;
-	aflag |= V_SNAPTOBOTTOM;
+		aflag |= ((stplyr->linktimer < (UINT32)nightslinktics/3)
+		? (9 - 9*stplyr->linktimer/(nightslinktics/3)) << V_ALPHASHIFT
+		: 0);
 
-	x = (160+4)<<FRACBITS;
+		y = (160+11)<<FRACBITS;
+		aflag |= V_SNAPTOBOTTOM;
 
-	if (prevtime[q])
-	{
-		scale = ((32 + prevtime[q])<<FRACBITS)/32;
-		prevtime[q]--;
-	}
-	else
-		scale = FRACUNIT;
+		x = (160+4)<<FRACBITS;
+
+		if (prevtime[q])
+		{
+			scale = ((32 + prevtime[q])<<FRACBITS)/32;
+			prevtime[q]--;
+		}
+		else
+			scale = FRACUNIT;
 
-	y -= (11*scale);
+		y -= (11*scale);
 
-	ST_DrawNightsOverlayNum(x-(4*scale), y, scale, aflag, (stplyr->linkcount-1), nightsnum, colornum);
-	V_DrawFixedPatch(x+(4*scale), y, scale, aflag, nightslink,
-		colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
+		ST_DrawNightsOverlayNum(x-(4*scale), y, scale, aflag, (stplyr->linkcount-1), nightsnum, colornum);
+		V_DrawFixedPatch(x+(4*scale), y, scale, aflag, nightslink,
+			colornum == 0 ? colormaps : R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE));
+	}
 
 	// Show remaining link time left in debug
 	if (cv_debug & DBG_NIGHTSBASIC)
@@ -1854,13 +1857,15 @@ static void ST_drawNiGHTSHUD(void)
 		for (dfill = 0; dfill < stplyr->drillmeter/20 && dfill < 96; ++dfill)
 			V_DrawScaledPatch(locx + 2 + dfill, locy + 3, V_PERPLAYER|V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_HUDTRANS, drillfill[fillpatch]);
 
-		// Display actual drill amount and bumper time
+		// Display actual flyangle, drill amount, and bumper time
 		if (!splitscreen && (cv_debug & DBG_NIGHTSBASIC))
 		{
+			V_DrawString(locx, locy - 16, V_MONOSPACE, va("ANGLE: %3d", stplyr->flyangle));
+
 			if (stplyr->bumpertime)
 				V_DrawString(locx, locy - 8, V_REDMAP|V_MONOSPACE, va("BUMPER: 0.%02d", G_TicsToCentiseconds(stplyr->bumpertime)));
 			else
-				V_DrawString(locx, locy - 8, V_MONOSPACE, va("Drill: %3d%%", (stplyr->drillmeter*100)/(96*20)));
+				V_DrawString(locx, locy - 8, V_MONOSPACE, va("DRILL: %3d%%", (stplyr->drillmeter*100)/(96*20)));
 		}
 	}