diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..eb06156b4673c7656512ed16528b0edbbada3970
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# Sonic Robo Blast 2
+
+[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
+[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
+
+[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
+
+## Dependencies
+- NASM (x86 builds only)
+- SDL2 (Linux/OS X only)
+- SDL2-Mixer (Linux/OS X only)
+- libupnp (Linux/OS X only)
+- libgme (Linux/OS X only)
+
+Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
+
+## Compiling
+
+See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)
+
+## Disclaimer
+Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do not claim ownership of any of SEGA's intellectual property used in SRB2.
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index c1898d491f0291bbfad2bd09b8b2cbc7b673e9ee..0000000000000000000000000000000000000000
--- a/readme.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-Here it is! SRB2 v2.1.14 source code!
-(why do we keep the version number up to date
-	when everything else in this file is hilariously old?
-	- Inuyasha)
-
-
-Win32 with Visual C (6SP6+Processor Pack OR 7)
-~~~
-
-2 VC++ 6.0 project files are included:
-
-Win32/DirectX/FMOD
-src\win32\wLegacy.dsw
-You'll need FMOD to compile this version (www.fmod.org)
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dsp
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-
-Both needs NASM (http://sourceforge.net/projects/nasm)
-For PNG screenshot, libPNG, and Zlib (from http://gnuwin32.sourceforge.net/)
-
-No warranty, support, etc. of any kind is offered,
-just plain old as is.
-Some bits of code are still really scary.
-Go nuts!
-
-
-Win32 with Dev-C++ (http://bloodshed.net/ free!)
-~~~
-2 Dev-C++ project files are included:
-
-Win32/DirectX/FMOD
-src\win32\SRB2.dev
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dev
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-libPNG and Zlib (from http://gnuwin32.sourceforge.net/)
-Note there are precompiled libpng.a and libz.a for Mingw
-
-you will need NASM for both SDL/SDL_mixer and DirectX/FMOD
-and you need DirectX 6 (or up) Dev-Paks to compile DirectX version
-
-GNU/Linux
-~~~
-
-Dependencies:
-  SDL 1.2.7 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-make -C src LINUX=1
-
-Build instructions (64 bit):
-
-make -C src LINUX64=1
-
-Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src LINUX=1 WIILINUX=1
-
-Build instructions to build for Pandora (Linux) on a ARM system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src PANDORA=1
-
-Solaris
-~~~
-
-Dependencies:
-  SDL 1.2.5 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-  You can get all these programs/libraries from the Companion CD (except SDL_mixer and OpenGL)
-
-Build instructions:
-
-gmake -C src SOLARIS=1
-
-FreeBSD
-~~~
-
-Dependencies:
-  SDL 1.2.7 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-gmake -C src FREEBSD=1
-
-DJGPP/DOS
-~~~
-
-Dependencies:
-  Allegro 3.12 game programming library, (from
-  http://alleg.sourceforge.net/index.html)
-  Nasm (use NOASM=1 if you don't have it)
-  libsocket (from http://homepages.nildram.co.uk/~phekda/richdawe/lsck/) or
-  Watt-32 (from http://www.bgnett.no/~giva/)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-make -C src # to link with Watt-32, add WATTCP=1
-      # for remote debugging over the COM port, add RDB=1
-
-Notes:
- use tools\djgpp\all313.diff to update Allegro to a "more usable" version ;)
- Example: E:\djgpp\allegro>patch -p# < D:\SRB2Code\1.1\srb2\tools\djgpp\all313.diff
-
-Windows CE
-~~~
-
-Dependencies:
-  SDL 1.27
-
-Build instructions:
-
-use src\SDL\WinCE\SRB2CE.vcw
-
--------------------------------------------------------------------------------
-
-binaries will turn in up in bin/
-
-note: read the src/makefile for more options
-
-- Sonic Team Junior
-http://www.srb2.org
diff --git a/src/doomdef.h b/src/doomdef.h
index 4de83fda1f4edf1f80bf5d4f2abe80906bc7068e..3f504d25f812a7f5ff988cb2b816406f7c0982d1 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -60,6 +60,7 @@
 #endif
 
 #ifdef _WINDOWS
+#define NONET
 #if !defined (HWRENDER) && !defined (NOHW)
 #define HWRENDER
 #endif
diff --git a/src/f_finale.c b/src/f_finale.c
index 68b23528da215eedf7e2a5cdf045abb60493f120..81c530e6ab9ba05a88c546cf59e0cb8d1e90b367 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -1727,6 +1727,7 @@ static void F_AdvanceToNextScene(void)
 
 void F_EndCutScene(void)
 {
+	cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later
 	if (runningprecutscene)
 	{
 		if (server)
@@ -1743,7 +1744,6 @@ void F_EndCutScene(void)
 		else
 			Y_EndGame();
 	}
-	cutsceneover = true;
 }
 
 void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)
diff --git a/src/g_game.c b/src/g_game.c
index c12d3b25def8d7987083c88eb194bf77b8a4852b..76229347e562f3ff20e7ff38c3589908854b6922 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -711,6 +711,10 @@ void G_SetGameModified(boolean silent)
 
 	if (!silent)
 		CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n"));
+
+	// If in record attack recording, cancel it.
+	if (modeattacking)
+		M_EndModeAttackRun();
 }
 
 /** Builds an original game map name from a map number.
diff --git a/src/i_tcp.c b/src/i_tcp.c
index eca218c804dde4eabf59963d6a752d2c3aed0fa6..f6212458b889f9ff3a70321e54bd9aa7c8951f42 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -56,7 +56,9 @@
 //#define NONET
 #endif
 
-#ifndef NONET
+#ifdef NONET
+#undef HAVE_MINIUPNPC
+#else
 #ifdef USE_WINSOCK1
 #include <winsock.h>
 #elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)
diff --git a/src/m_menu.c b/src/m_menu.c
index 35495ec55f869ea46ce5aeacf6c7aaf838dd7235..d2c730504b404e254edca6a4ca8c3d50d4297c24 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -706,7 +706,7 @@ static menuitem_t SP_TimeAttackMenu[] =
 	{IT_DISABLED,              NULL, "Guest Option...", &SP_GuestReplayDef, 100},
 	{IT_DISABLED,              NULL, "Replay...",     &SP_ReplayDef,        110},
 	{IT_DISABLED,              NULL, "Ghosts...",     &SP_GhostDef,         120},
-	{IT_WHITESTRING|IT_CALL,   NULL, "Start",         M_ChooseTimeAttack,   130},
+	{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED,   NULL, "Start",         M_ChooseTimeAttack,   130},
 };
 
 enum
@@ -798,7 +798,7 @@ static menuitem_t SP_NightsAttackMenu[] =
 	{IT_DISABLED,              NULL, "Guest Option...",  &SP_NightsGuestReplayDef,   108},
 	{IT_DISABLED,              NULL, "Replay...",        &SP_NightsReplayDef,        118},
 	{IT_DISABLED,              NULL, "Ghosts...",        &SP_NightsGhostDef,         128},
-	{IT_WHITESTRING|IT_CALL,   NULL, "Start",            M_ChooseNightsAttack, 138},
+	{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED,   NULL, "Start",            M_ChooseNightsAttack, 138},
 };
 
 enum
@@ -3705,6 +3705,11 @@ static void M_DrawMessageMenu(void)
 
 	mlines = currentMenu->lastOn>>8;
 	max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
+
+	// hack: draw RA background in RA menus
+	if (gamestate == GS_TIMEATTACK)
+		V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
+
 	M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
 
 	while (*(msg+start))
@@ -4313,9 +4318,9 @@ static void M_SinglePlayerMenu(INT32 choice)
 {
 	(void)choice;
 	SP_MainMenu[sprecordattack].status =
-		(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+		(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
 	SP_MainMenu[spnightsmode].status =
-		(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+		(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
 
 	M_SetupNextMenu(&SP_MainDef);
 }
diff --git a/src/p_map.c b/src/p_map.c
index 48946a4ba6bfba15e3776167bdd46c023ed24541..6d4acf1a29f673a360720d93d603439d53525ac8 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1312,7 +1312,7 @@ static boolean PIT_CheckLine(line_t *ld)
 	}
 
 	// set openrange, opentop, openbottom
-	P_LineOpening(ld);
+	P_LineOpening(ld, tmthing);
 
 	// adjust floor / ceiling heights
 	if (opentop < tmceilingz)
@@ -1430,7 +1430,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 			topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
 			bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
 
-			if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY))
+			if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER) && !(thing->flags & MF_NOGRAVITY))
 			{
 				// If you're inside goowater and slowing down
 				fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);
@@ -2744,7 +2744,7 @@ static boolean PTR_SlideTraverse(intercept_t *in)
 	}
 
 	// set openrange, opentop, openbottom
-	P_LineOpening(li);
+	P_LineOpening(li, slidemo);
 
 	if (openrange < slidemo->height)
 		goto isblocking; // doesn't fit
diff --git a/src/p_maputl.c b/src/p_maputl.c
index c3a6fa842b08a12267d7904368fd6e49120816fc..fea8530a125bf3a5d001d87507f5513a85bb1e06 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -489,7 +489,7 @@ void P_CameraLineOpening(line_t *linedef)
 	}
 }
 
-void P_LineOpening(line_t *linedef)
+void P_LineOpening(line_t *linedef, mobj_t *mobj)
 {
 	sector_t *front, *back;
 
@@ -520,8 +520,8 @@ void P_LineOpening(line_t *linedef)
 	{ // Set open and high/low values here
 		fixed_t frontheight, backheight;
 
-		frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef);
-		backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef);
+		frontheight = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
+		backheight = P_GetCeilingZ(mobj, back, tmx, tmy, linedef);
 
 		if (frontheight < backheight)
 		{
@@ -540,8 +540,8 @@ void P_LineOpening(line_t *linedef)
 #endif
 		}
 
-		frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef);
-		backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef);
+		frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
+		backheight = P_GetFloorZ(mobj, back, tmx, tmy, linedef);
 
 		if (frontheight > backheight)
 		{
@@ -561,12 +561,14 @@ void P_LineOpening(line_t *linedef)
 		}
 	}
 
-	if (tmthing)
+	if (mobj)
 	{
-		fixed_t thingtop = tmthing->z + tmthing->height;
+		fixed_t thingtop = mobj->z + mobj->height;
 
 		// Check for collision with front side's midtexture if Effect 4 is set
-		if (linedef->flags & ML_EFFECT4) {
+		if (linedef->flags & ML_EFFECT4
+			&& !linedef->polyobj // don't do anything for polyobjects! ...for now
+			) {
 			side_t *side = &sides[linedef->sidenum[0]];
 			fixed_t textop, texbottom, texheight;
 			fixed_t texmid, delta1, delta2;
@@ -575,30 +577,38 @@ void P_LineOpening(line_t *linedef)
 			texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
 
 			// Set texbottom and textop to the Z coordinates of the texture's boundaries
-#ifdef POLYOBJECTS
+#if 0 // #ifdef POLYOBJECTS
+			// don't remove this code unless solid midtextures
+			// on non-solid polyobjects should NEVER happen in the future
 			if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
-				if (linedef->flags & ML_DONTPEGBOTTOM) {
+				if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+					texbottom = back->floorheight + side->rowoffset;
+					textop = back->ceilingheight + side->rowoffset;
+				} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
 					texbottom = back->floorheight + side->rowoffset;
 					textop = texbottom + texheight*(side->repeatcnt+1);
 				} else {
-					textop = back->ceilingheight - side->rowoffset;
+					textop = back->ceilingheight + side->rowoffset;
 					texbottom = textop - texheight*(side->repeatcnt+1);
 				}
 			} else
 #endif
 			{
-				if (linedef->flags & ML_DONTPEGBOTTOM) {
+				if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+					texbottom = openbottom + side->rowoffset;
+					textop = opentop + side->rowoffset;
+				} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
 					texbottom = openbottom + side->rowoffset;
 					textop = texbottom + texheight*(side->repeatcnt+1);
 				} else {
-					textop = opentop - side->rowoffset;
+					textop = opentop + side->rowoffset;
 					texbottom = textop - texheight*(side->repeatcnt+1);
 				}
 			}
 
 			texmid = texbottom+(textop-texbottom)/2;
 
-			delta1 = abs(tmthing->z - texmid);
+			delta1 = abs(mobj->z - texmid);
 			delta2 = abs(thingtop - texmid);
 
 			if (delta1 > delta2) { // Below
@@ -636,16 +646,16 @@ void P_LineOpening(line_t *linedef)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
-				else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
-					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
 					continue;
 
-				topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef);
-				bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef);
+				topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef);
+				bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef);
 
-				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
 				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -680,16 +690,16 @@ void P_LineOpening(line_t *linedef)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
-				else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
-					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
 					continue;
 
-				topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef);
-				bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef);
+				topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef);
+				bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef);
 
-				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
 				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -723,7 +733,7 @@ void P_LineOpening(line_t *linedef)
 			{
 				const sector_t *polysec = linedef->backsector;
 
-				delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
+				delta1 = abs(mobj->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
 				delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
 				if (polysec->floorheight < lowestceiling && delta1 >= delta2) {
 					lowestceiling = polysec->floorheight;
diff --git a/src/p_maputl.h b/src/p_maputl.h
index c160bfa288f7ed5ca36275ee9eb0cc9ff8385583..3d74e927b3ba44c76585c513dcbd941369c76377 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -59,7 +59,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
 extern pslope_t *opentopslope, *openbottomslope;
 #endif
 
-void P_LineOpening(line_t *plinedef);
+void P_LineOpening(line_t *plinedef, mobj_t *mobj);
 
 boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *));
 boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *));
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 808ff6355634ca54a5607405aaceec1292a45f2e..7d9c324513fda2357de331e1af9f5b8a0cc93e91 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1644,25 +1644,23 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 
 		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
 		{
-			if (!(rover->flags & FF_EXISTS))
+			if (!(rover->flags & FF_EXISTS) || !P_InsideANonSolidFFloor(mo, rover)) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
 				continue;
 
-			if (P_InsideANonSolidFFloor(mo, rover))
-			{
-				if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
-					goopgravity = true;
-				if (rover->master->frontsector->gravity)
-				{
-					gravityadd = -FixedMul(gravity,
-						(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+			if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
+				goopgravity = true;
 
-					if (rover->master->frontsector->verticalflip && gravityadd > 0)
-						mo->eflags |= MFE_VERTICALFLIP;
+			if (!(rover->master->frontsector->gravity))
+				continue;
 
-					no3dfloorgrav = false;
-					break;
-				}
-			}
+			gravityadd = -FixedMul(gravity,
+				(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+
+			if (rover->master->frontsector->verticalflip && gravityadd > 0)
+				mo->eflags |= MFE_VERTICALFLIP;
+
+			no3dfloorgrav = false;
+			break;
 		}
 	}
 
@@ -1684,28 +1682,20 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 
 	if (mo->player)
 	{
-		if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
-		|| mo->state-states == S_PLAY_FLY_TIRED))
-			gravityadd = gravityadd/3; // less gravity while flying
-		if (mo->player->pflags & PF_GLIDING)
-			gravityadd = gravityadd/3; // less gravity while gliding
-		if (mo->player->climbing)
-			gravityadd = 0;
-		if (mo->player->pflags & PF_NIGHTSMODE)
+		if ((mo->player->pflags & PF_GLIDING)
+		|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
+			|| mo->state-states == S_PLAY_FLY_TIRED)))
+			gravityadd = gravityadd/3; // less gravity while flying/gliding
+		if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE))
 			gravityadd = 0;
 
+		if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be
 		{
-			UINT8 bits = 0;
-			if (mo->flags2 & MF2_OBJECTFLIP)
-				bits ^= 1;
-			if (mo->player->powers[pw_gravityboots])
-				bits ^= 1;
-			if (bits & 1)
-			{
-				gravityadd = -gravityadd;
-				mo->eflags ^= MFE_VERTICALFLIP;
-			}
+			gravityadd = -gravityadd;
+			mo->eflags ^= MFE_VERTICALFLIP;
 		}
+		if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
+			P_PlayerFlip(mo);
 	}
 	else
 	{
@@ -1713,10 +1703,10 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 		if (mo->flags2 & MF2_OBJECTFLIP)
 		{
 			mo->eflags |= MFE_VERTICALFLIP;
-			if (gravityadd < 0) // Don't sink, only rise up
-				gravityadd *= -1;
 			if (mo->z + mo->height >= mo->ceilingz)
 				gravityadd = 0;
+			else if (gravityadd < 0) // Don't sink, only rise up
+				gravityadd *= -1;
 		}
 		else //Otherwise, sort through the other exceptions.
 		{
@@ -1762,9 +1752,6 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
 	if (goopgravity)
 		gravityadd = -gravityadd/5;
 
-	if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
-		P_PlayerFlip(mo);
-
 	gravityadd = FixedMul(gravityadd, mo->scale);
 
 	return gravityadd;
@@ -1919,6 +1906,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 		if (node->m_sector->ffloors)
 		{
 			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 			{
@@ -1931,37 +1919,39 @@ static void P_PushableCheckBustables(mobj_t *mo)
 
 				if (!rover->master->frontsector->crumblestate)
 				{
+					topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
+					bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
 					// Height checks
 					if (rover->flags & FF_SHATTERBOTTOM)
 					{
-						if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+						if (mo->z+mo->momz + mo->height < bottomheight)
 							continue;
 
-						if (mo->z+mo->height > *rover->bottomheight)
+						if (mo->z+mo->height > bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SPINBUST)
 					{
-						if (mo->z+mo->momz > *rover->topheight)
+						if (mo->z+mo->momz > topheight)
 							continue;
 
-						if (mo->z+mo->height < *rover->bottomheight)
+						if (mo->z+mo->height < bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SHATTER)
 					{
-						if (mo->z+mo->momz > *rover->topheight)
+						if (mo->z+mo->momz > topheight)
 							continue;
 
-						if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+						if (mo->z+mo->momz + mo->height < bottomheight)
 							continue;
 					}
 					else
 					{
-						if (mo->z >= *rover->topheight)
+						if (mo->z >= topheight)
 							continue;
 
-						if (mo->z+mo->height < *rover->bottomheight)
+						if (mo->z+mo->height < bottomheight)
 							continue;
 					}
 
@@ -7322,6 +7312,7 @@ void P_MobjThinker(mobj_t *mobj)
 					{
 						mobj->flags &= ~MF_NOGRAVITY;
 						P_SetMobjState(mobj, S_NIGHTSDRONE1);
+						mobj->flags2 |= MF2_DONTDRAW;
 					}
 				}
 				else if (mobj->tracer && mobj->tracer->player)
diff --git a/src/p_user.c b/src/p_user.c
index 90f021377eabb3dfaa3e2a8603ec82e0370fe59f..f6e9270eccb2f1d2b3cf16de3914add1531389eb 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1699,6 +1699,7 @@ static void P_CheckBustableBlocks(player_t *player)
 		if (node->m_sector->ffloors)
 		{
 			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 			{
@@ -1737,42 +1738,45 @@ static void P_CheckBustableBlocks(player_t *player)
 						|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)))
 						continue;
 
+					topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+					bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+
 					// Height checks
 					if (rover->flags & FF_SHATTERBOTTOM)
 					{
-						if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+						if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
 							continue;
 
-						if (player->mo->z+player->mo->height > *rover->bottomheight)
+						if (player->mo->z+player->mo->height > bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SPINBUST)
 					{
-						if (player->mo->z+player->mo->momz > *rover->topheight)
+						if (player->mo->z+player->mo->momz > topheight)
 							continue;
 
-						if (player->mo->z + player->mo->height < *rover->bottomheight)
+						if (player->mo->z + player->mo->height < bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SHATTER)
 					{
-						if (player->mo->z + player->mo->momz > *rover->topheight)
+						if (player->mo->z + player->mo->momz > topheight)
 							continue;
 
-						if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+						if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
 							continue;
 					}
 					else
 					{
-						if (player->mo->z >= *rover->topheight)
+						if (player->mo->z >= topheight)
 							continue;
 
-						if (player->mo->z + player->mo->height < *rover->bottomheight)
+						if (player->mo->z + player->mo->height < bottomheight)
 							continue;
 					}
 
 					// Impede the player's fall a bit
-					if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= *rover->topheight)
+					if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight)
 						player->mo->momz >>= 1;
 					else if (rover->flags & FF_SHATTER)
 					{
@@ -7067,6 +7071,7 @@ static void P_MovePlayer(player_t *player)
 		msecnode_t *node; // only place it's being used in P_MovePlayer now
 		fixed_t oldx;
 		fixed_t oldy;
+		fixed_t floorz, ceilingz;
 
 		oldx = player->mo->x;
 		oldy = player->mo->y;
@@ -7084,31 +7089,34 @@ static void P_MovePlayer(player_t *player)
 			if (node->m_sector->ffloors)
 			{
 				ffloor_t *rover;
+				fixed_t topheight, bottomheight;
 
 				for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 				{
-					if (!(rover->flags & FF_EXISTS)) continue;
+					if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
+						continue;
 
-					if ((rover->flags & FF_BLOCKPLAYER))
+					topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+					bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+					if (topheight > player->mo->z && bottomheight < player->mo->z)
 					{
-						if (*rover->topheight > player->mo->z && *rover->bottomheight < player->mo->z)
-						{
-							P_ResetPlayer(player);
-							S_StartSound(player->mo, sfx_s3k4a);
-							player->climbing = 5;
-							player->mo->momx = player->mo->momy = player->mo->momz = 0;
-							break;
-						}
+						P_ResetPlayer(player);
+						S_StartSound(player->mo, sfx_s3k4a);
+						player->climbing = 5;
+						player->mo->momx = player->mo->momy = player->mo->momz = 0;
+						break;
 					}
 				}
 			}
 
-			if (player->mo->z+player->mo->height > node->m_sector->ceilingheight
+			floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+			ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+
+			if (player->mo->z+player->mo->height > ceilingz
 				&& node->m_sector->ceilingpic == skyflatnum)
 				continue;
 
-			if (node->m_sector->floorheight > player->mo->z
-				|| node->m_sector->ceilingheight < player->mo->z)
+			if (floorz > player->mo->z || ceilingz < player->mo->z)
 			{
 				P_ResetPlayer(player);
 				S_StartSound(player->mo, sfx_s3k4a);
diff --git a/src/st_stuff.c b/src/st_stuff.c
index 340f8a2b2bd770b51329396c74762387b07e1f01..43d2bd176a8b400b34e4157cc250104b89bd83e0 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -982,7 +982,7 @@ static void ST_drawNiGHTSHUD(void)
 	if (cv_debug & DBG_NIGHTSBASIC)
 		minlink = 0;
 
-	// Cheap hack: don't display when the score is showing
+	// Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
 	if (stplyr->texttimer && stplyr->textvar == 4)
 		minlink = INT32_MAX;