diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index c0179ca1be99cff5fb94b2a15b73a81269c02719..7852a0a224d0e5fa1b03205712dda12320268b56 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -517,9 +517,9 @@ 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->actionspd = LONG(players[i].actionspd);
-	rsp->mindash = LONG(players[i].mindash);
-	rsp->maxdash = LONG(players[i].maxdash);
+	rsp->actionspd = (fixed_t)LONG(players[i].actionspd);
+	rsp->mindash = (fixed_t)LONG(players[i].mindash);
+	rsp->maxdash = (fixed_t)LONG(players[i].maxdash);
 	rsp->jumpfactor = (fixed_t)LONG(players[i].jumpfactor);
 
 	rsp->speed = (fixed_t)LONG(players[i].speed);
@@ -531,6 +531,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
 	rsp->deadtimer = players[i].deadtimer;
 	rsp->exiting = (tic_t)LONG(players[i].exiting);
 	rsp->homing = players[i].homing;
+	rsp->skidtime = (tic_t)LONG(players[i].skidtime);
 	rsp->cmomx = (fixed_t)LONG(players[i].cmomx);
 	rsp->cmomy = (fixed_t)LONG(players[i].cmomy);
 	rsp->rmomx = (fixed_t)LONG(players[i].rmomx);
@@ -590,7 +591,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i)
 
 	rsp->tics = LONG(players[i].mo->tics);
 	rsp->statenum = (statenum_t)LONG(players[i].mo->state-states); // :(
-	rsp->eflags = (UINT32)LONG(players[i].mo->eflags);
+	rsp->eflags = (UINT16)SHORT(players[i].mo->eflags);
 	rsp->flags = LONG(players[i].mo->flags);
 	rsp->flags2 = LONG(players[i].mo->flags2);
 
@@ -642,9 +643,9 @@ 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].actionspd = LONG(rsp->actionspd);
-	players[i].mindash = LONG(rsp->mindash);
-	players[i].maxdash = LONG(rsp->maxdash);
+	players[i].actionspd = (fixed_t)LONG(rsp->actionspd);
+	players[i].mindash = (fixed_t)LONG(rsp->mindash);
+	players[i].maxdash = (fixed_t)LONG(rsp->maxdash);
 	players[i].jumpfactor = (fixed_t)LONG(rsp->jumpfactor);
 
 	players[i].speed = (fixed_t)LONG(rsp->speed);
@@ -656,6 +657,7 @@ static void resynch_read_player(resynch_pak *rsp)
 	players[i].deadtimer = rsp->deadtimer;
 	players[i].exiting = (tic_t)LONG(rsp->exiting);
 	players[i].homing = rsp->homing;
+	players[i].skidtime = (tic_t)LONG(rsp->skidtime);
 	players[i].cmomx = (fixed_t)LONG(rsp->cmomx);
 	players[i].cmomy = (fixed_t)LONG(rsp->cmomy);
 	players[i].rmomx = (fixed_t)LONG(rsp->rmomx);
@@ -713,7 +715,7 @@ static void resynch_read_player(resynch_pak *rsp)
 	//At this point, the player should have a body, whether they were respawned or not.
 	P_UnsetThingPosition(players[i].mo);
 	players[i].mo->angle = (angle_t)LONG(rsp->angle);
-	players[i].mo->eflags = (UINT32)LONG(rsp->eflags);
+	players[i].mo->eflags = (UINT16)SHORT(rsp->eflags);
 	players[i].mo->flags = LONG(rsp->flags);
 	players[i].mo->flags2 = LONG(rsp->flags2);
 	players[i].mo->friction = LONG(rsp->friction);
@@ -2935,9 +2937,9 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
 			if (botingame)
 				players[newplayernum].bot = 1;
 			// Same goes for player 2 when relevant
-			players[newplayernum].pflags &= ~(/*PF_FLIPCAM|*/PF_ANALOGMODE);
-			//if (cv_flipcam2.value)
-				//players[newplayernum].pflags |= PF_FLIPCAM;
+			players[newplayernum].pflags &= ~(PF_FLIPCAM|PF_ANALOGMODE);
+			if (cv_flipcam2.value)
+				players[newplayernum].pflags |= PF_FLIPCAM;
 			if (cv_analog2.value)
 				players[newplayernum].pflags |= PF_ANALOGMODE;
 		}
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 6bc06f13a5e00e2e8bbe572ac208ba469644ab43..246447ed6c9610bf498249eb56ebdafcc35c0eb8 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -177,9 +177,9 @@ typedef struct
 	UINT32 thokitem; //mobjtype_t
 	UINT32 spinitem; //mobjtype_t
 	UINT32 revitem; //mobjtype_t
-	INT32 actionspd;
-	INT32 mindash;
-	INT32 maxdash;
+	fixed_t actionspd;
+	fixed_t mindash;
+	fixed_t maxdash;
 	fixed_t jumpfactor;
 
 	fixed_t speed;
@@ -191,6 +191,7 @@ typedef struct
 	INT32 deadtimer;
 	tic_t exiting;
 	UINT8 homing;
+	tic_t skidtime;
 	fixed_t cmomx;
 	fixed_t cmomy;
 	fixed_t rmomx;
@@ -241,11 +242,11 @@ typedef struct
 	fixed_t friction;
 	fixed_t movefactor;
 
-	INT16 tics;
+	INT32 tics;
 	statenum_t statenum;
 	UINT32 flags;
 	UINT32 flags2;
-	UINT8 eflags;
+	UINT16 eflags;
 
 	fixed_t radius;
 	fixed_t height;
diff --git a/src/d_main.c b/src/d_main.c
index b04c55cbf668510284410c1bd36b75e0488e3f10..c9282be7e00f9ee7732a3c44a81feff9ae9105f1 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -221,10 +221,7 @@ gamestate_t wipegamestate = GS_LEVEL;
 
 static void D_Display(void)
 {
-	static boolean menuactivestate = false;
-	static gamestate_t oldgamestate = -1;
-	boolean redrawsbar = false;
-
+	boolean forcerefresh = false;
 	static boolean wipe = false;
 	INT32 wipedefindex = 0;
 
@@ -245,23 +242,15 @@ static void D_Display(void)
 	if (setsizeneeded)
 	{
 		R_ExecuteSetViewSize();
-		oldgamestate = -1; // force background redraw
-		redrawsbar = true;
+		forcerefresh = true; // force background redraw
 	}
 
-	// save the current screen if about to wipe
-	if (gamestate != wipegamestate)
-	{
-		wipe = true;
-		F_WipeStartScreen();
-	}
-	else
-		wipe = false;
-
 	// draw buffered stuff to screen
 	// Used only by linux GGI version
 	I_UpdateNoBlit();
 
+	// save the current screen if about to wipe
+	wipe = (gamestate != wipegamestate);
 	if (wipe)
 	{
 		// set for all later
@@ -280,6 +269,7 @@ static void D_Display(void)
 			if (gamestate != GS_LEVEL // fades to black on its own timing, always
 			 && wipedefs[wipedefindex] != UINT8_MAX)
 			{
+				F_WipeStartScreen();
 				V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
 				F_WipeEndScreen();
 				F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK);
@@ -298,8 +288,6 @@ static void D_Display(void)
 			HU_Erase();
 			if (automapactive)
 				AM_Drawer();
-			if (wipe || menuactivestate || (rendermode != render_soft && rendermode != render_none) || vid.recalc)
-				redrawsbar = true;
 			break;
 
 		case GS_INTERMISSION:
@@ -357,11 +345,6 @@ static void D_Display(void)
 	// see if the border needs to be initially drawn
 	if (gamestate == GS_LEVEL)
 	{
-#if 0
-		if (oldgamestate != GS_LEVEL)
-			R_FillBackScreen(); // draw the pattern into the back screen
-#endif
-
 		// draw the view directly
 		if (!automapactive && !dedicated && cv_renderview.value)
 		{
@@ -417,17 +400,17 @@ static void D_Display(void)
 			lastdraw = false;
 		}
 
-		ST_Drawer(redrawsbar);
+		ST_Drawer();
 
 		HU_Drawer();
 	}
 
 	// change gamma if needed
-	if (gamestate != oldgamestate && gamestate != GS_LEVEL)
+	// (GS_LEVEL handles this already due to level-specific palettes)
+	if (forcerefresh && gamestate != GS_LEVEL)
 		V_SetPalette(0);
 
-	menuactivestate = menuactive;
-	oldgamestate = wipegamestate = gamestate;
+	wipegamestate = gamestate;
 
 	// draw pause pic
 	if (paused && cv_showhud.value && (!menuactive || netgame))
@@ -450,15 +433,22 @@ static void D_Display(void)
 		CON_Drawer();
 
 	M_Drawer(); // menu is drawn even on top of everything
+	// focus lost moved to M_Drawer
 
-	// focus lost notification goes on top of everything, even the former everything
-	if (window_notinfocus)
+	//
+	// wipe update
+	//
+	if (wipe)
 	{
-		M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2);
-		if (gamestate == GS_LEVEL && (P_AutoPause() || paused))
-			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Game Paused");
-		else
-			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Focus Lost");
+		// note: moved up here because NetUpdate does input changes
+		// and input during wipe tends to mess things up
+		wipedefindex += WIPEFINALSHIFT;
+
+		if (rendermode != render_none)
+		{
+			F_WipeEndScreen();
+			F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK);
+		}
 	}
 
 	NetUpdate(); // send out any new accumulation
@@ -493,18 +483,6 @@ static void D_Display(void)
 		}
 
 		I_FinishUpdate(); // page flip or blit buffer
-		return;
-	}
-
-	//
-	// wipe update
-	//
-	wipedefindex += WIPEFINALSHIFT;
-
-	if (rendermode != render_none)
-	{
-		F_WipeEndScreen();
-		F_RunWipe(wipedefs[wipedefindex], gamestate != GS_TIMEATTACK);
 	}
 }
 
diff --git a/src/g_game.c b/src/g_game.c
index b89d2c33770a3caec016d22115e77814c31633cd..6012f4fcd472b4c61c04236a813a7929873818c8 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2332,8 +2332,8 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
 		}
 	}
 	P_MovePlayerToSpawn(playernum, spawnpoint);
-	
-#ifdef HAVE_BLUA 
+
+#ifdef HAVE_BLUA
 	LUAh_PlayerSpawn(&players[playernum]); // Lua hook for player spawning :)
 #endif
 
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index e6a26e605899307a4796e2a84b3d5408b29c8af4..60183b58e72a168ceea2a2971f6b18f3e8fe5831 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -657,6 +657,9 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 	FOutVector v[4];
 	FSurfaceInfo Surf;
 
+	if (w < 0 || h < 0)
+		return; // consistency w/ software
+
 //  3--2
 //  | /|
 //  |/ |
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 4eb083780ea69e5d1674483e9ef83908a5dd9cba..df0ea43fa7324f3063ff5ecb3b4149697362af3b 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -76,6 +76,6 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd); // Hook for B_B
 boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector); // Hook for linedef executors
 boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg); // Hook for chat messages
 boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source); // Hook for hurt messages
-#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer 
+#define LUAh_PlayerSpawn(player) LUAh_PlayerHook(player, hook_PlayerSpawn) // Hook for G_SpawnPlayer
 
 #endif
diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c
index fd00180d5b6bb5106de861999ae4db37ed1caf8a..a55e3a0e4ed3ad510a170820f1204d389a3f0ded 100644
--- a/src/lua_mathlib.c
+++ b/src/lua_mathlib.c
@@ -100,7 +100,11 @@ static int lib_fixedint(lua_State *L)
 
 static int lib_fixeddiv(lua_State *L)
 {
-	lua_pushfixed(L, FixedDiv(luaL_checkfixed(L, 1), luaL_checkfixed(L, 2)));
+	fixed_t i = luaL_checkfixed(L, 1);
+	fixed_t j = luaL_checkfixed(L, 2);
+	if (j == 0)
+		return luaL_error(L, "divide by zero");
+	lua_pushfixed(L, FixedDiv(i, j));
 	return 1;
 }
 
@@ -112,7 +116,10 @@ static int lib_fixedrem(lua_State *L)
 
 static int lib_fixedsqrt(lua_State *L)
 {
-	lua_pushfixed(L, FixedSqrt(luaL_checkfixed(L, 1)));
+	fixed_t i = luaL_checkfixed(L, 1);
+	if (i < 0)
+		return luaL_error(L, "square root domain error");
+	lua_pushfixed(L, FixedSqrt(i));
 	return 1;
 }
 
diff --git a/src/m_menu.c b/src/m_menu.c
index 95752c7aacc1f34de012bb820e6f894fdd26ede8..3aad54282521043953d9b009dbe7162e8f1127d7 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -2059,6 +2059,10 @@ static void M_PrevOpt(void)
 	} while (oldItemOn != itemOn && (currentMenu->menuitems[itemOn].status & IT_TYPE) == IT_SPACE);
 }
 
+// lock out further input in a tic when important buttons are pressed
+// (in other words -- stop bullshit happening by mashing buttons in fades)
+static boolean noFurtherInput = false;
+
 //
 // M_Responder
 //
@@ -2081,6 +2085,12 @@ boolean M_Responder(event_t *ev)
 		shiftdown = false;
 		return false;
 	}
+	if (noFurtherInput)
+	{
+		// Ignore input after enter/escape/other buttons
+		// (but still allow shift keyup so caps doesn't get stuck)
+		return false;
+	}
 	else if (ev->type == ev_keydown)
 	{
 		ch = ev->data1;
@@ -2182,6 +2192,7 @@ boolean M_Responder(event_t *ev)
 	// F-Keys
 	if (!menuactive)
 	{
+		noFurtherInput = true;
 		switch (ch)
 		{
 			case KEY_F1: // Help key
@@ -2252,6 +2263,7 @@ boolean M_Responder(event_t *ev)
 					M_StartControlPanel();
 				return true;
 		}
+		noFurtherInput = false; // turns out we didn't care
 		return false;
 	}
 
@@ -2275,6 +2287,7 @@ boolean M_Responder(event_t *ev)
 				if (routine)
 					routine(ch);
 				M_StopMessage(0);
+				noFurtherInput = true;
 				return true;
 			}
 			return true;
@@ -2354,6 +2367,7 @@ boolean M_Responder(event_t *ev)
 			return true;
 
 		case KEY_ENTER:
+			noFurtherInput = true;
 			currentMenu->lastOn = itemOn;
 			if (routine)
 			{
@@ -2387,6 +2401,7 @@ boolean M_Responder(event_t *ev)
 			return true;
 
 		case KEY_ESCAPE:
+			noFurtherInput = true;
 			currentMenu->lastOn = itemOn;
 			if (currentMenu->prevMenu)
 			{
@@ -2443,35 +2458,45 @@ void M_Drawer(void)
 	if (currentMenu == &MessageDef)
 		menuactive = true;
 
-	if (!menuactive)
-		return;
-
-	// now that's more readable with a faded background (yeah like Quake...)
-	if (!WipeInAction)
-		V_DrawFadeScreen();
+	if (menuactive)
+	{
+		// now that's more readable with a faded background (yeah like Quake...)
+		if (!WipeInAction)
+			V_DrawFadeScreen();
 
-	if (currentMenu->drawroutine)
-		currentMenu->drawroutine(); // call current menu Draw routine
+		if (currentMenu->drawroutine)
+			currentMenu->drawroutine(); // call current menu Draw routine
 
-	// Draw version down in corner
-	// ... but only in the MAIN MENU.  I'm a picky bastard.
-	if (currentMenu == &MainDef)
-	{
-		if (customversionstring[0] != '\0')
-		{
-			V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:");
-			V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring);
-		}
-		else
+		// Draw version down in corner
+		// ... but only in the MAIN MENU.  I'm a picky bastard.
+		if (currentMenu == &MainDef)
 		{
+			if (customversionstring[0] != '\0')
+			{
+				V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:");
+				V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring);
+			}
+			else
+			{
 #ifdef DEVELOP // Development -- show revision / branch info
-			V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, compbranch);
-			V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy,  V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, comprevision);
+				V_DrawThinString(vid.dupx, vid.height - 17*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, compbranch);
+				V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy,  V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, comprevision);
 #else // Regular build
-			V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, va("%s", VERSIONSTRING));
+				V_DrawThinString(vid.dupx, vid.height - 9*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, va("%s", VERSIONSTRING));
 #endif
+			}
 		}
 	}
+
+	// focus lost notification goes on top of everything, even the former everything
+	if (window_notinfocus)
+	{
+		M_DrawTextBox((BASEVIDWIDTH/2) - (60), (BASEVIDHEIGHT/2) - (16), 13, 2);
+		if (gamestate == GS_LEVEL && (P_AutoPause() || paused))
+			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Game Paused");
+		else
+			V_DrawCenteredString(BASEVIDWIDTH/2, (BASEVIDHEIGHT/2) - (4), V_YELLOWMAP, "Focus Lost");
+	}
 }
 
 //
@@ -2656,6 +2681,9 @@ void M_SetupNextMenu(menu_t *menudef)
 //
 void M_Ticker(void)
 {
+	// reset input trigger
+	noFurtherInput = false;
+
 	if (dedicated)
 		return;
 
diff --git a/src/p_inter.c b/src/p_inter.c
index b8101f12b1561f97c88e64bebd30ce99e215c189..c08f1f267a7c188681626d18ec4b66692bacb563 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -27,6 +27,10 @@
 #include "m_misc.h"
 #include "v_video.h" // video flags for CEchos
 
+// CTF player names
+#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
+#define CTFTEAMENDCODE(pl) pl->ctfteam ? "\x80" : ""
+
 void P_ForceFeed(const player_t *player, INT32 attack, INT32 fade, tic_t duration, INT32 period)
 {
 	BasicFF_t Basicfeed;
@@ -574,11 +578,23 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			{
 				UINT8 flagteam = (special->type == MT_REDFLAG) ? 1 : 2;
 				const char *flagtext;
+				char flagcolor;
+				char plname[MAXPLAYERNAME+4];
 
 				if (special->type == MT_REDFLAG)
-					flagtext = M_GetText("red");
+				{
+					flagtext = M_GetText("Red flag");
+					flagcolor = '\x85';
+				}
 				else
-					flagtext = M_GetText("blue");
+				{
+					flagtext = M_GetText("Blue flag");
+					flagcolor = '\x84';
+				}
+				snprintf(plname, sizeof(plname), "%s%s%s",
+						 CTFTEAMCODE(player),
+						 player_names[player - players],
+						 CTFTEAMENDCODE(player));
 
 				if (player->ctfteam == flagteam) // Player is on the same team as the flag
 				{
@@ -592,10 +608,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 
 						if (!P_PlayerTouchingSectorSpecial(player, 4, 2 + flagteam))
 						{
-							CONS_Printf(M_GetText("%s returned the %s flag to base.\n"), player_names[player-players], flagtext);
+							CONS_Printf(M_GetText("%s returned the %c%s%c to base.\n"), plname, flagcolor, flagtext, 0x80);
 
-							if (players[consoleplayer].ctfteam == player->ctfteam)
-								S_StartSound(NULL, sfx_hoop1);
+							// The fuse code plays this sound effect
+							//if (players[consoleplayer].ctfteam == player->ctfteam)
+							//	S_StartSound(NULL, sfx_hoop1);
 						}
 					}
 				}
@@ -608,7 +625,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 						return;
 
 					player->gotflag |= flagflag;
-					CONS_Printf(M_GetText("%s picked up the %s flag!\n"), player_names[player-players], flagtext);
+					CONS_Printf(M_GetText("%s picked up the %c%s%c!\n"), plname, flagcolor, flagtext, 0x80);
 					(*flagmobj) = NULL;
 					// code for dealing with abilities is handled elsewhere now
 					break;
@@ -1447,9 +1464,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 	P_KillMobj(special, NULL, toucher);
 }
 
-#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
-#define CTFTEAMENDCODE(pl) pl->ctfteam ? "\x80" : ""
-
 /** Prints death messages relating to a dying or hit player.
   *
   * \param player    Affected player.
@@ -1472,6 +1486,9 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
 	if (!player)
 		return; // Impossible!
 
+	if (player->spectator)
+		return; // No messages for dying (crushed) spectators.
+
 	if (!netgame)
 		return; // Presumably it's obvious what's happening in splitscreen.
 
@@ -2068,7 +2085,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 
 			if (target->player->lives <= 0) // Tails 03-14-2000
 			{
-				if (P_IsLocalPlayer(target->player) && target->player == &players[consoleplayer])
+				if (P_IsLocalPlayer(target->player)/* && target->player == &players[consoleplayer] */)
 				{
 					S_StopMusic(); // Stop the Music! Tails 03-14-2000
 					S_ChangeMusicInternal("gmover", false); // Yousa dead now, Okieday? Tails 03-14-2000
@@ -3618,10 +3635,33 @@ void P_PlayerFlagBurst(player_t *player, boolean toss)
 	flag->fuse = cv_flagtime.value * TICRATE;
 	P_SetTarget(&flag->target, player->mo);
 
-	if (toss)
-		CONS_Printf(M_GetText("%s tossed the %s flag.\n"), player_names[player-players], (type == MT_REDFLAG ? "red" : "blue"));
-	else
-		CONS_Printf(M_GetText("%s dropped the %s flag.\n"), player_names[player-players], (type == MT_REDFLAG ? "red" : "blue"));
+	// Flag text
+	{
+		char plname[MAXPLAYERNAME+4];
+		char *flagtext;
+		char flagcolor;
+
+		snprintf(plname, sizeof(plname), "%s%s%s",
+				 CTFTEAMCODE(player),
+				 player_names[player - players],
+				 CTFTEAMENDCODE(player));
+
+		if (type == MT_REDFLAG)
+		{
+			flagtext = M_GetText("Red flag");
+			flagcolor = '\x85';
+		}
+		else
+		{
+			flagtext = M_GetText("Blue flag");
+			flagcolor = '\x84';
+		}
+
+		if (toss)
+			CONS_Printf(M_GetText("%s tossed the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80);
+		else
+			CONS_Printf(M_GetText("%s dropped the %c%s%c.\n"), plname, flagcolor, flagtext, 0x80);
+	}
 
 	player->gotflag = 0;
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 42571a5c3d2df2b059bf5940c3ddb64f72195e1a..ce67f1a5a15d6c72a8e9e492cf079c063f8d43d9 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -7149,9 +7149,10 @@ void P_MobjThinker(mobj_t *mobj)
 						if (mobj->type == MT_REDFLAG)
 						{
 							if (!(mobj->flags2 & MF2_JUSTATTACKED))
-								CONS_Printf(M_GetText("The red flag has returned to base.\n"));
+								CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80);
 
-							if (players[consoleplayer].ctfteam == 1)
+							// Assumedly in splitscreen players will be on opposing teams
+							if (players[consoleplayer].ctfteam == 1 || splitscreen)
 								S_StartSound(NULL, sfx_hoop1);
 
 							redflag = flagmo;
@@ -7159,9 +7160,10 @@ void P_MobjThinker(mobj_t *mobj)
 						else // MT_BLUEFLAG
 						{
 							if (!(mobj->flags2 & MF2_JUSTATTACKED))
-								CONS_Printf(M_GetText("The blue flag has returned to base.\n"));
+								CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80);
 
-							if (players[consoleplayer].ctfteam == 2)
+							// Assumedly in splitscreen players will be on opposing teams
+							if (players[consoleplayer].ctfteam == 2 || splitscreen)
 								S_StartSound(NULL, sfx_hoop1);
 
 							blueflag = flagmo;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index e0112bb79b84c5169b018f090c56117efb0cdef3..952e567d7d410ede4c6aa4f57e3e8772c2e52c48 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -613,7 +613,7 @@ static void P_NetArchiveWorld(void)
 						WRITEUINT16(put, j); // save ffloor "number"
 						WRITEUINT8(put, fflr_diff);
 						if (fflr_diff & 1)
-							WRITEUINT16(put, rover->flags);
+							WRITEUINT32(put, rover->flags);
 						if (fflr_diff & 2)
 							WRITEINT16(put, rover->alpha);
 					}
@@ -815,7 +815,7 @@ static void P_NetUnArchiveWorld(void)
 				fflr_diff = READUINT8(get);
 
 				if (fflr_diff & 1)
-					rover->flags = READUINT16(get);
+					rover->flags = READUINT32(get);
 				if (fflr_diff & 2)
 					rover->alpha = READINT16(get);
 
diff --git a/src/p_spec.c b/src/p_spec.c
index 86a25170c46195cfd85206d3101e3f58cc55b716..7f911a3379b49817e70fb3906c8b009e65a33d9b 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -3784,7 +3784,7 @@ DoneSection2:
 					HU_SetCEchoDuration(5);
 					HU_DoCEcho(va(M_GetText("%s\\captured the blue flag.\\\\\\\\"), player_names[player-players]));
 
-					if (players[consoleplayer].ctfteam == 1)
+					if (splitscreen || players[consoleplayer].ctfteam == 1)
 						S_StartSound(NULL, sfx_flgcap);
 					else if (players[consoleplayer].ctfteam == 2)
 						S_StartSound(NULL, sfx_lose);
@@ -3817,7 +3817,7 @@ DoneSection2:
 					HU_SetCEchoDuration(5);
 					HU_DoCEcho(va(M_GetText("%s\\captured the red flag.\\\\\\\\"), player_names[player-players]));
 
-					if (players[consoleplayer].ctfteam == 2)
+					if (splitscreen || players[consoleplayer].ctfteam == 2)
 						S_StartSound(NULL, sfx_flgcap);
 					else if (players[consoleplayer].ctfteam == 1)
 						S_StartSound(NULL, sfx_lose);
diff --git a/src/p_user.c b/src/p_user.c
index 73702517ceb088f5d30505f944001909732c8c19..da02c74fef607e2a451caee25ee1bba29fac4266 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -7722,8 +7722,25 @@ static void P_DeathThink(player_t *player)
 		}
 
 		// Return to level music
-		if (netgame && player->deadtimer == gameovertics && P_IsLocalPlayer(player))
-			S_ChangeMusic(mapmusname, mapmusflags, true);
+		if (player->lives <= 0)
+		{
+			if (netgame)
+			{
+				if (player->deadtimer == gameovertics && P_IsLocalPlayer(player))
+					S_ChangeMusic(mapmusname, mapmusflags, true);
+			}
+			else if (multiplayer) // local multiplayer only
+			{
+				if (player->deadtimer != gameovertics)
+					;
+				// Restore the other player's music once we're dead for long enough
+				// -- that is, as long as they aren't dead too
+				else if (player == &players[displayplayer] && players[secondarydisplayplayer].lives > 0)
+					P_RestoreMusic(&players[secondarydisplayplayer]);
+				else if (player == &players[secondarydisplayplayer] && players[displayplayer].lives > 0)
+					P_RestoreMusic(&players[displayplayer]);
+			}
+		}
 	}
 
 	if (!player->mo)
@@ -8445,9 +8462,9 @@ static boolean P_SpectatorJoinGame(player_t *player)
 			displayplayer = consoleplayer;
 
 		if (changeto == 1)
-			CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red Team"), '\x80');
+			CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x85', M_GetText("Red team"), '\x80');
 		else if (changeto == 2)
-			CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x84', M_GetText("Blue Team"), '\x80');
+			CONS_Printf(M_GetText("%s switched to the %c%s%c.\n"), player_names[player-players], '\x84', M_GetText("Blue team"), '\x80');
 
 		return true; // no more player->mo, cannot continue.
 	}
diff --git a/src/r_main.c b/src/r_main.c
index a6b13302ee56b858d14a476d28e8bc848f4f75ba..3b71b7f92b4834325d5de2ba40c8dbf52b16097d 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -1382,6 +1382,7 @@ void R_RegisterEngineStuff(void)
 	CV_RegisterVar(&cv_allowmlook);
 	CV_RegisterVar(&cv_homremoval);
 	CV_RegisterVar(&cv_flipcam);
+	CV_RegisterVar(&cv_flipcam2);
 
 	// Enough for dedicated server
 	if (dedicated)
diff --git a/src/r_segs.c b/src/r_segs.c
index 0e2b9ea5c75358aa5feb34002b259b0e979c5ba0..bac90eb1644638f1cb6e6a42b65207fd617ebb3e 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1421,7 +1421,7 @@ static void R_RenderSegLoop (void)
 			for (i = 0; i < dc_numlights; i++)
 			{
 				dc_lightlist[i].height += dc_lightlist[i].heightstep;
-				if (dc_lightlist[i].flags & FF_SOLID)
+				if (dc_lightlist[i].flags & FF_CUTSOLIDS)
 					dc_lightlist[i].botheight += dc_lightlist[i].botheightstep;
 			}
 		}
@@ -2508,7 +2508,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 #endif
 			rlight->flags = light->flags;
 
-			if (light->caster && light->caster->flags & FF_SOLID)
+			if (light->caster && light->caster->flags & FF_CUTSOLIDS)
 			{
 #ifdef ESLOPE
 				if (*light->caster->b_slope) {
diff --git a/src/r_things.c b/src/r_things.c
index 5616c2224f38f3e1d3ce658d701a496a3f2d38b8..2ec2f6ead19e20bf784490973bc53f5b6844c1e6 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -964,7 +964,7 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
 		cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS);
 		if (cutfrac < 0)
 			continue;
-		if (cutfrac > vid.height)
+		if (cutfrac > viewheight)
 			return;
 
 		// Found a split! Make a new sprite, copy the old sprite to it, and
diff --git a/src/s_sound.c b/src/s_sound.c
index 49373d94c445e7354123a36d7c36c63da9036c8a..0bb8f3e2be1dc5b7f0a1537f560d60c3f2f863f8 100644
--- a/src/s_sound.c
+++ b/src/s_sound.c
@@ -1310,8 +1310,7 @@ void S_SetDigMusicVolume(INT32 volume)
 #ifdef DJGPPDOS
 	I_SetDigMusicVolume(31); // Trick for buggy dos drivers. Win32 doesn't need this.
 #endif
-	if (!nodigimusic)
-		I_SetDigMusicVolume(volume&31);
+	I_SetDigMusicVolume(volume&31);
 }
 
 void S_SetMIDIMusicVolume(INT32 volume)
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 0f96f47339e4fee106b506e9266e8f9546b94968..9eb5c31540b7c2d5ba342cce4928ed8f8ec95585 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -529,14 +529,8 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 #endif
 
 	if (lumpnum == LUMPERROR)
-	{
-		lumpnum = W_CheckNumForName(va("D_%s",musicname));
-		if (lumpnum == LUMPERROR)
-			return false;
-		midimode = true;
-	}
-	else
-		midimode = false;
+		return false;
+	midimode = false;
 
 	data = (char *)W_CacheLumpNum(lumpnum, PU_MUSIC);
 	len = W_LumpLength(lumpnum);
@@ -686,10 +680,7 @@ boolean I_StartDigSong(const char *musicname, boolean looping)
 		CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
 		return true;
 	}
-	if (midimode)
-		Mix_VolumeMusic((UINT32)midi_volume*128/31);
-	else
-		Mix_VolumeMusic((UINT32)music_volume*128/31);
+	Mix_VolumeMusic((UINT32)music_volume*128/31);
 
 	if (loop_point != 0.0f)
 		Mix_HookMusicFinished(music_loop);
@@ -792,10 +783,15 @@ void I_ShutdownMIDIMusic(void)
 
 void I_SetMIDIMusicVolume(UINT8 volume)
 {
-	midi_volume = volume;
+	// HACK: Until we stop using native MIDI,
+	// disable volume changes
+	(void)volume;
+	midi_volume = 31;
+	//midi_volume = volume;
+
 	if (!midimode || !music)
 		return;
-	Mix_VolumeMusic((UINT32)volume*128/31);
+	Mix_VolumeMusic((UINT32)midi_volume*128/31);
 }
 
 INT32 I_RegisterSong(void *data, size_t len)
@@ -820,7 +816,8 @@ boolean I_PlaySong(INT32 handle, boolean looping)
 		CONS_Alert(CONS_ERROR, "Mix_PlayMusic: %s\n", Mix_GetError());
 		return false;
 	}
-	Mix_VolumeMusic((UINT32)music_volume*128/31);
+
+	Mix_VolumeMusic((UINT32)midi_volume*128/31);
 	return true;
 }
 
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 585db0c873a78a861858590fb0cb581ecba79a67..9a4df8a07b9639a127c5bb79f2e2b33e5ba29c4c 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1889,7 +1889,7 @@ static void ST_overlayDrawer(void)
 	ST_drawDebugInfo();
 }
 
-void ST_Drawer(boolean refresh)
+void ST_Drawer(void)
 {
 #ifdef SEENAMES
 	if (cv_seenames.value && cv_allowseenames.value && displayplayer == consoleplayer && seenplayer && seenplayer->mo)
@@ -1906,8 +1906,11 @@ void ST_Drawer(boolean refresh)
 	}
 #endif
 
+	// Doom's status bar only updated if necessary.
+	// However, ours updates every frame regardless, so the "refresh" param was removed
+	//(void)refresh;
+
 	// force a set of the palette by using doPaletteStuff()
-	(void)refresh; //?
 	if (vid.recalc)
 		st_palette = -1;
 
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 9873efbe749b3195082a1b331937e43fb7fcc9e3..44994a6d30a5e855e7bf850c918b1e542b27031b 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -27,7 +27,7 @@
 void ST_Ticker(void);
 
 // Called by main loop.
-void ST_Drawer(boolean refresh);
+void ST_Drawer(void);
 
 // Called when the console player is spawned on each level.
 void ST_Start(void);