diff --git a/.travis.yml b/.travis.yml
index c652584f8879153f879a24c0f3f5a741cc8eae4f..54c5901d07c591f1a3abf2872d18a8d448ab675a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,13 +3,19 @@ sudo: required
 dist: trusty
 
 env:
-- CFLAGS=-Wno-absolute-value -Werror
+- CFLAGS=-Wall -W -Werror
+
+os:
+  - linux
+  - osx
 
 compiler:
   - gcc
   - clang
 
 cache:
+  apt:  true
+  ccache: true
   directories:
   - $HOME/srb2_cache
 
@@ -30,4 +36,10 @@ before_script:
   - cd build
   - cmake ..
 
+before_install:
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install sdl2_mixer game-music-emu p7zip ; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/release/SDL2-2.0.4.dmg; hdiutil attach SDL2-2.0.4.dmg; sudo cp -a /Volumes/SDL2/SDL2.framework /Library/Frameworks/; fi
+  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -O -L https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.dmg; hdiutil attach SDL2_mixer-2.0.1.dmg; sudo cp -a /Volumes/SDL2_mixer/SDL2_mixer.framework /Library/Frameworks/; fi
+
 script: make
diff --git a/SRB2.cbp b/SRB2.cbp
index 5a03955b8dc036d688497e7fa0018796423b00e4..43696ee2e4b23a9ecf6eafafe51bfeaa834cb154 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -3293,23 +3293,6 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_fab.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
 		<Unit filename="src/p_floor.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
diff --git a/appveyor.yml b/appveyor.yml
index 4edcd7a7f422f45b84159f2a07dc8248e552b12a..3ddec6dfb41a3ab886568d0276eee713aef60b22 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -11,6 +11,7 @@ environment:
  SDL2_MIXER_URL: https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-devel-2.0.1-mingw.tar.gz
  SDL2_MIXER_ARCHIVE: SDL2_mixer-devel-2.0.1-mingw.tar
  SDL2_MIXER_MOVE: SDL2_mixer-2.0.1\i686-w64-mingw32
+ CFLAGS: -Wall -W -Werror
 
 cache:
 - SDL2-devel-2.0.4-mingw.tar.gz
diff --git a/cmake/Modules/FindGME.cmake b/cmake/Modules/FindGME.cmake
index 3b0c68de735e67458ce4652c600b5768c8124046..ea80af45442c098f21cef962082ce0602546cd29 100644
--- a/cmake/Modules/FindGME.cmake
+++ b/cmake/Modules/FindGME.cmake
@@ -6,16 +6,16 @@ find_path(GME_INCLUDE_DIR
 	NAMES gme.h
 	PATHS
 		${GME_PKGCONF_INCLUDE_DIRS}
-		/usr/include/gme
-		/usr/local/include/gme
+		"/usr/include/gme"
+		"/usr/local/include/gme"
 )
 
 find_library(GME_LIBRARY
 	NAMES gme
 	PATHS
 		${GME_PKGCONF_LIBRARY_DIRS}
-		/usr/lib
-		/usr/local/lib
+		"/usr/lib"
+		"/usr/local/lib"
 )
 
 set(GME_PROCESS_INCLUDES GME_INCLUDE_DIR)
diff --git a/comptime.bat b/comptime.bat
index 9e127f001a984ebf3e6febffb8307adb21d08aaf..0c7ea06d60955ec1cd5015a9b660625dae0b6d2c 100644
--- a/comptime.bat
+++ b/comptime.bat
@@ -1,4 +1,4 @@
-@ECHO OFF
+@echo off
 set BRA=Unknown
 set REV=illegal
 
@@ -13,20 +13,20 @@ goto filwri
 :gitrev
 set GIT=%2
 if "%GIT%"=="" set GIT=git
-FOR /F "usebackq" %%s IN (`%GIT% rev-parse --abbrev-ref HEAD`) DO @SET BRA=%%s
-FOR /F "usebackq" %%s IN (`%GIT% rev-parse HEAD`) DO @SET REV=%%s
+for /f "usebackq" %%s in (`%GIT% rev-parse --abbrev-ref HEAD`) do @set BRA=%%s
+for /f "usebackq" %%s in (`%GIT% rev-parse HEAD`) do @set REV=%%s
 set REV=%REV:~0,8%
 goto filwri
 
 :svnrev
 set BRA=Subversion
-FOR /F "usebackq" %%s IN (`svnversion .`) DO @SET REV=%%s
+for /f "usebackq" %%s in (`svnversion .`) do @set REV=%%s
 set REV=r%REV%
 goto filwri
 
 :filwri
-ECHO // Do not edit!  This file was autogenerated > %1\comptime.h
-ECHO // by the %0 batch file >> %1\comptime.h
-ECHO // >> %1\comptime.h
-ECHO const char* compbranch = "%BRA%"; >> %1\comptime.h
-ECHO const char* comprevision = "%REV%"; >> %1\comptime.h
+echo // Do not edit!  This file was autogenerated > %1\comptime.h
+echo // by the %0 batch file >> %1\comptime.h
+echo // >> %1\comptime.h
+echo const char* compbranch = "%BRA%"; >> %1\comptime.h
+echo const char* comprevision = "%REV%"; >> %1\comptime.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 54a08ea0bb31b03d23c3758b37874dc99f3fdcd0..035b4655699bdf4c6d2830d6ab8dc358360948d1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -139,7 +139,6 @@ set(SRB2_CORE_RENDER_SOURCES
 set(SRB2_CORE_GAME_SOURCES
 	p_ceilng.c
 	p_enemy.c
-	p_fab.c
 	p_floor.c
 	p_inter.c
 	p_lights.c
@@ -316,6 +315,7 @@ if(${SRB2_CONFIG_HAVE_GME})
 	find_package(GME)
 	if(${GME_FOUND})
 		set(SRB2_HAVE_GME ON)
+		add_definitions(-DHAVE_LIBGME)
 	else()
 		message(WARNING "You have specified that GME is available but it was not found.")
 	endif()
diff --git a/src/Makefile b/src/Makefile
index bee60804720da1dcbee09065c29f616e145848f0..0c034143d956c7547ded9e7657a53fcbd91fc936 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -262,9 +262,7 @@ else
 	OBJS+=$(OBJDIR)/hw3sound.o
 endif
 
-ifndef NOVERSION
 OPTS += -DCOMPVERSION
-endif
 
 ifndef NONX86
 ifndef GCC29
@@ -439,7 +437,6 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/info.o     \
 		$(OBJDIR)/p_ceilng.o \
 		$(OBJDIR)/p_enemy.o  \
-		$(OBJDIR)/p_fab.o    \
 		$(OBJDIR)/p_floor.o  \
 		$(OBJDIR)/p_inter.o  \
 		$(OBJDIR)/p_lights.o \
@@ -551,15 +548,11 @@ cleandep:
 	$(REMOVE) comptime.h
 
 pre-build:
-ifdef NOVERSION
-	-@touch comptime.c
-else
 ifdef WINDOWSHELL
 	-..\comptime.bat .
 else
 	-@../comptime.sh .
 endif
-endif
 
 clean:
 	$(REMOVE) *~ *.flc
diff --git a/src/am_map.c b/src/am_map.c
index 70714facb62d07b4dff1edc281d531e03b4bf284..97b7c51642bbea4d87d22d197cd46ed15d986f26 100644
--- a/src/am_map.c
+++ b/src/am_map.c
@@ -30,9 +30,7 @@ static const UINT8 REDRANGE    = 16;
 static const UINT8 GRAYS       = (1*16);
 static const UINT8 GRAYSRANGE  = 16;
 static const UINT8 BROWNS      = (3*16);
-static const UINT8 BROWNRANGE  = 16;
 static const UINT8 YELLOWS     = (7*16);
-static const UINT8 YELLOWRANGE = 8;
 static const UINT8 GREENS      = (10*16);
 static const UINT8 GREENRANGE  = 16;
 static const UINT8 DBLACK      = 31;
@@ -41,11 +39,8 @@ static const UINT8 DWHITE      = 0;
 static const UINT8 NOCLIMBREDS        = 248;
 static const UINT8 NOCLIMBREDRANGE    = 8;
 static const UINT8 NOCLIMBGRAYS       = 204;
-static const UINT8 NOCLIMBGRAYSRANGE  = 4;
 static const UINT8 NOCLIMBBROWNS      = (2*16);
-static const UINT8 NOCLIMBBROWNRANGE  = 16;
 static const UINT8 NOCLIMBYELLOWS     = (11*16);
-static const UINT8 NOCLIMBYELLOWRANGE = 8;
 
 
 #ifdef _NDS
@@ -67,15 +62,10 @@ static const UINT8 NOCLIMBYELLOWRANGE = 8;
 #define TSWALLCOLORS          GRAYS
 #define TSWALLRANGE           GRAYSRANGE
 #define NOCLIMBTSWALLCOLORS   NOCLIMBGRAYS
-#define NOCLIMBTSWALLRANGE    NOCLIMBGRAYSRANGE
 #define FDWALLCOLORS          BROWNS
-#define FDWALLRANGE           BROWNRANGE
 #define NOCLIMBFDWALLCOLORS   NOCLIMBBROWNS
-#define NOCLIMBFDWALLRANGE    NOCLIMBBROWNRANGE
 #define CDWALLCOLORS          YELLOWS
-#define CDWALLRANGE           YELLOWRANGE
 #define NOCLIMBCDWALLCOLORS   NOCLIMBYELLOWS
-#define NOCLIMBCDWALLRANGE    NOCLIMBYELLOWRANGE
 #define THINGCOLORS           GREENS
 #define THINGRANGE            GREENRANGE
 #define SECRETWALLCOLORS      WALLCOLORS
@@ -255,29 +245,6 @@ static AMDRAWFLINEFUNC AM_drawFline;
 
 static void AM_drawFline_soft(const fline_t *fl, INT32 color);
 
-/** Calculates the slope and slope according to the x-axis of a line
-  * segment in map coordinates (with the upright y-axis and all) so
-  * that it can be used with the braindead drawing stuff.
-  *
-  * \param ml The line segment.
-  * \param is Holds the result.
-  */
-static inline void AM_getIslope(const mline_t *ml, islope_t *is)
-{
-	INT32 dx, dy;
-
-	dy = ml->a.y - ml->b.y;
-	dx = ml->b.x - ml->a.x;
-	if (!dy)
-		is->islp = (dx < 0 ? -INT32_MAX : INT32_MAX);
-	else
-		is->islp = FixedDiv(dx, dy);
-	if (!dx)
-		is->slp = (dy < 0 ? -INT32_MAX : INT32_MAX);
-	else
-		is->slp = FixedDiv(dy, dx);
-}
-
 static void AM_activateNewScale(void)
 {
 	m_x += m_w/2;
diff --git a/src/b_bot.c b/src/b_bot.c
index 7f55b50b1accbeccdb46c2c5c8e614208a7314b6..7976d557114bebe1216a6412d90a62a068a7b1b6 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -49,7 +49,7 @@ static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cm
 		if (sonic->player->pflags & (PF_MACESPIN|PF_ITEMHANG))
 		{
 			cmd->forwardmove = sonic->player->cmd.forwardmove;
-			cmd->angleturn = abs((tails->angle - sonic->angle))>>16;
+			cmd->angleturn = abs((signed)(tails->angle - sonic->angle))>>16;
 			if (sonic->angle < tails->angle)
 				cmd->angleturn = -cmd->angleturn;
 		} else if (dist > FixedMul(512*FRACUNIT, tails->scale))
diff --git a/src/config.h.in b/src/config.h.in
index 5cd75fa5a50962f34a638b3dda519cfe2483fa47..eef4fec1314a44baa2ddaf1f59cb8f460dda9c9f 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -15,7 +15,9 @@
 #define ASSET_HASH_PLAYER_DTA "${SRB2_ASSET_player.dta_HASH}"
 #define ASSET_HASH_RINGS_DTA  "${SRB2_ASSET_rings.dta_HASH}"
 #define ASSET_HASH_ZONES_DTA  "${SRB2_ASSET_zones.dta_HASH}"
+#ifdef USE_PATCH_DTA
 #define ASSET_HASH_PATCH_DTA  "${SRB2_ASSET_patch.dta_HASH}"
+#endif
 
 #define SRB2_COMP_REVISION    "${SRB2_COMP_REVISION}"
 #define SRB2_COMP_BRANCH      "${SRB2_COMP_BRANCH}"
@@ -26,10 +28,16 @@
 
 #else
 
+/* Manually defined asset hashes for non-CMake builds
+ * Last updated 2000 / 00 / 00
+ */
 #define ASSET_HASH_SRB2_SRB   "c1b9577687f8a795104aef4600720ea7"
 #define ASSET_HASH_ZONES_DTA  "303838c6c534d9540288360fa49cca60"
 #define ASSET_HASH_PLAYER_DTA "cfca0f1c73023cbbd8f844f45480f799"
 #define ASSET_HASH_RINGS_DTA  "85901ad4bf94637e5753d2ac2c03ea26"
+#ifdef USE_PATCH_DTA
+#define ASSET_HASH_PATCH_DTA  "0c66790502e648bfce90fdc5bb15722e"
+#endif
 
 #endif
 #endif
diff --git a/src/d_main.c b/src/d_main.c
index c5f0d0b396029bb4c18b8e46a2488906abc51c21..4519197db65e814b9973edf90500bdcd34f205e9 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -513,7 +513,6 @@ static void D_Display(void)
 // =========================================================================
 
 tic_t rendergametic;
-boolean supdate;
 
 void D_SRB2Loop(void)
 {
@@ -604,7 +603,6 @@ void D_SRB2Loop(void)
 
 			// Update display, next frame, with current state.
 			D_Display();
-			supdate = false;
 
 			if (moviemode)
 				M_SaveFrame();
@@ -841,8 +839,10 @@ static void IdentifyVersion(void)
 	// Add the weapons
 	D_AddFile(va(pandf,srb2waddir,"rings.dta"));
 
+#ifdef USE_PATCH_DTA
 	// Add our crappy patches to fix our bugs
-	// D_AddFile(va(pandf,srb2waddir,"patch.dta"));
+	D_AddFile(va(pandf,srb2waddir,"patch.dta"));
+#endif
 
 #if !defined (HAVE_SDL) || defined (HAVE_MIXER)
 	{
@@ -1133,12 +1133,18 @@ void D_SRB2Main(void)
 	//W_VerifyFileMD5(1, ASSET_HASH_ZONES_DTA); // zones.dta
 	//W_VerifyFileMD5(2, ASSET_HASH_PLAYER_DTA); // player.dta
 	//W_VerifyFileMD5(3, ASSET_HASH_RINGS_DTA); // rings.dta
-	//W_VerifyFileMD5(4, "0c66790502e648bfce90fdc5bb15722e"); // patch.dta
+#ifdef USE_PATCH_DTA
+	W_VerifyFileMD5(4, ASSET_HASH_PATCH_DTA); // patch.dta
+#endif
+
 	// don't check music.dta because people like to modify it, and it doesn't matter if they do
 	// ...except it does if they slip maps in there, and that's what W_VerifyNMUSlumps is for.
-#endif
+#endif //ifndef DEVELOP
 
-	mainwads = 4; // there are 5 wads not to unload
+	mainwads = 4; // there are 4 wads not to unload
+#ifdef USE_PATCH_DTA
+	++mainwads; // patch.dta adds one more
+#endif
 
 	cht_Init();
 
diff --git a/src/d_main.h b/src/d_main.h
index 800b61f531fb9c79f6b19f4d2eb0d23c1430b045..c5ce19ef4cb199ca489840e1899f0e40d0c3f775 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -17,7 +17,6 @@
 #include "d_event.h"
 #include "w_wad.h"   // for MAX_WADFILES
 
-extern boolean supdate;
 extern boolean advancedemo;
 
 // make sure not to write back the config until it's been correctly loaded
diff --git a/src/dehacked.c b/src/dehacked.c
index 6747f2c59444e0faeb00cb7f59e01ca48ae1ca9f..f5e5879afdfb556555fb7477f06864b26887490f 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -7271,36 +7271,36 @@ struct {
 	{"FF_GOOWATER",FF_GOOWATER},               ///< Used with ::FF_SWIMMABLE. Makes thick bouncey goop.
 
 	// Angles
-	{"ANG1",ANG1>>16},
-	{"ANG2",ANG2>>16},
-	{"ANG10",ANG10>>16},
-	{"ANG15",ANG15>>16},
-	{"ANG20",ANG20>>16},
-	{"ANG30",ANG30>>16},
-	{"ANG60",ANG60>>16},
-	{"ANG64h",ANG64h>>16},
-	{"ANG105",ANG105>>16},
-	{"ANG210",ANG210>>16},
-	{"ANG255",ANG255>>16},
-	{"ANG340",ANG340>>16},
-	{"ANG350",ANG350>>16},
-	{"ANGLE_11hh",ANGLE_11hh>>16},
-	{"ANGLE_22h",ANGLE_22h>>16},
-	{"ANGLE_45",ANGLE_45>>16},
-	{"ANGLE_67h",ANGLE_67h>>16},
-	{"ANGLE_90",ANGLE_90>>16},
-	{"ANGLE_112h",ANGLE_112h>>16},
-	{"ANGLE_135",ANGLE_135>>16},
-	{"ANGLE_157h",ANGLE_157h>>16},
-	{"ANGLE_180",ANGLE_180>>16},
-	{"ANGLE_202h",ANGLE_202h>>16},
-	{"ANGLE_225",ANGLE_225>>16},
-	{"ANGLE_247h",ANGLE_247h>>16},
-	{"ANGLE_270",ANGLE_270>>16},
-	{"ANGLE_292h",ANGLE_292h>>16},
-	{"ANGLE_315",ANGLE_315>>16},
-	{"ANGLE_337h",ANGLE_337h>>16},
-	{"ANGLE_MAX",ANGLE_MAX>>16},
+	{"ANG1",ANG1},
+	{"ANG2",ANG2},
+	{"ANG10",ANG10},
+	{"ANG15",ANG15},
+	{"ANG20",ANG20},
+	{"ANG30",ANG30},
+	{"ANG60",ANG60},
+	{"ANG64h",ANG64h},
+	{"ANG105",ANG105},
+	{"ANG210",ANG210},
+	{"ANG255",ANG255},
+	{"ANG340",ANG340},
+	{"ANG350",ANG350},
+	{"ANGLE_11hh",ANGLE_11hh},
+	{"ANGLE_22h",ANGLE_22h},
+	{"ANGLE_45",ANGLE_45},
+	{"ANGLE_67h",ANGLE_67h},
+	{"ANGLE_90",ANGLE_90},
+	{"ANGLE_112h",ANGLE_112h},
+	{"ANGLE_135",ANGLE_135},
+	{"ANGLE_157h",ANGLE_157h},
+	{"ANGLE_180",ANGLE_180},
+	{"ANGLE_202h",ANGLE_202h},
+	{"ANGLE_225",ANGLE_225},
+	{"ANGLE_247h",ANGLE_247h},
+	{"ANGLE_270",ANGLE_270},
+	{"ANGLE_292h",ANGLE_292h},
+	{"ANGLE_315",ANGLE_315},
+	{"ANGLE_337h",ANGLE_337h},
+	{"ANGLE_MAX",ANGLE_MAX},
 
 	// P_Chase directions (dirtype_t)
 	{"DI_NODIR",DI_NODIR},
diff --git a/src/doomdef.h b/src/doomdef.h
index f0cb88e71e19346c40ccb16bc20c3a8ff774e3da..49a44dcf43bbe030e4ed246bc5dd424abf9b6bc4 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -155,6 +155,10 @@ extern FILE *logstream;
 // Otherwise we can't force updates!
 #endif
 
+// Does this version require an added patch file?
+// Comment or uncomment this as necessary.
+//#define USE_PATCH_DTA
+
 // Modification options
 // If you want to take advantage of the Master Server's ability to force clients to update
 // to the latest version, fill these out.  Otherwise, just comment out UPDATE_ALERT and leave
diff --git a/src/doomtype.h b/src/doomtype.h
index 8e7da6881df87beb351470bbc1d6bfb01fead98a..d833176f780d32f9dd357ed0bbf9850b06830b68 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -94,7 +94,6 @@ typedef long ssize_t;
 #ifdef __APPLE_CC__
 #define DIRECTFULLSCREEN
 #define DEBUG_LOG
-#define HWRENDER
 #define NOIPX
 #endif
 
diff --git a/src/g_game.c b/src/g_game.c
index af70ce4241e34fa5885c123632493c1d131dc1c6..43e58c0ed0bd4cebc0fc58487e9607e4ab403799 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -4347,7 +4347,7 @@ void G_GhostTicker(void)
 		{
 		case GHC_SUPER: // Super Sonic (P_DoSuperStuff)
 			g->mo->color = SKINCOLOR_SUPER1;
-			g->mo->color += abs( ( ( leveltime >> 1 ) % 9) - 4);
+			g->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4);
 			break;
 		case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
 			g->mo->color = (UINT8)(leveltime % MAXSKINCOLORS);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index ac54cc13026d8cd4accda297bcfa4d2e02e65c32..3ab3bb028a98a494c3549894fcc4b01fc8ced036 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -3387,12 +3387,6 @@ static void HWR_ClearSprites(void)
 	gr_visspritecount = 0;
 }
 
-static inline void HWR_ResetVisSpriteChunks(void)
-{
-	memset(gr_visspritechunks, 0, sizeof(gr_visspritechunks));
-}
-
-
 // --------------------------------------------------------------------------
 // HWR_NewVisSprite
 // --------------------------------------------------------------------------
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index ea175dbeaa56fc4378bf80c0c7c8db6b6ba7239c..dfa36f1de251bcda8d1f23cb424f7fd16fa98740 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -406,191 +406,6 @@ static md2_model_t *md2_readModel(const char *filename)
 	return model;
 }
 
-/*
- * center model
- */
-static inline void md2_getBoundingBox (md2_model_t *model, float *minmax)
-{
-	size_t i;
-	float minx, maxx;
-	float miny, maxy;
-	float minz, maxz;
-
-	minx = miny = minz = 999999.0f;
-	maxx = maxy = maxz = -999999.0f;
-
-	/* get bounding box */
-	for (i = 0; i < model->header.numVertices; i++)
-	{
-		md2_triangleVertex_t *v = &model->frames[0].vertices[i];
-
-		if (v->vertex[0] < minx)
-			minx = v->vertex[0];
-		else if (v->vertex[0] > maxx)
-			maxx = v->vertex[0];
-
-		if (v->vertex[1] < miny)
-			miny = v->vertex[1];
-		else if (v->vertex[1] > maxy)
-			maxy = v->vertex[1];
-
-		if (v->vertex[2] < minz)
-			minz = v->vertex[2];
-		else if (v->vertex[2] > maxz)
-			maxz = v->vertex[2];
-	}
-
-	minmax[0] = minx;
-	minmax[1] = maxx;
-	minmax[2] = miny;
-	minmax[3] = maxy;
-	minmax[4] = minz;
-	minmax[5] = maxz;
-}
-
-static inline INT32 md2_getAnimationCount(md2_model_t *model)
-{
-	size_t i, pos;
-	INT32 j = 0, count;
-	char name[16], last[16];
-
-	strcpy(last, model->frames[0].name);
-	pos = strlen(last) - 1;
-	while (last[pos] >= '0' && last[pos] <= '9' && j < 2)
-	{
-		pos--;
-		j++;
-	}
-	last[pos + 1] = '\0';
-
-	count = 0;
-
-	for (i = 0; i <= model->header.numFrames; i++)
-	{
-		if (i == model->header.numFrames)
-			strcpy(name, ""); // some kind of a sentinel
-		else
-			strcpy(name, model->frames[i].name);
-		pos = strlen(name) - 1;
-		j = 0;
-		while (name[pos] >= '0' && name[pos] <= '9' && j < 2)
-		{
-			pos--;
-			j++;
-		}
-		name[pos + 1] = '\0';
-
-		if (strcmp(last, name))
-		{
-			strcpy(last, name);
-			count++;
-		}
-	}
-
-	return count;
-}
-
-static inline const char * md2_getAnimationName (md2_model_t *model, INT32 animation)
-{
-	size_t i, pos;
-	INT32 j = 0, count;
-	static char last[32];
-	char name[32];
-
-	strcpy(last, model->frames[0].name);
-	pos = strlen(last) - 1;
-	while (last[pos] >= '0' && last[pos] <= '9' && j < 2)
-	{
-		pos--;
-		j++;
-	}
-	last[pos + 1] = '\0';
-
-	count = 0;
-
-	for (i = 0; i <= model->header.numFrames; i++)
-	{
-		if (i == model->header.numFrames)
-			strcpy(name, ""); // some kind of a sentinel
-		else
-			strcpy(name, model->frames[i].name);
-		pos = strlen(name) - 1;
-		j = 0;
-		while (name[pos] >= '0' && name[pos] <= '9' && j < 2)
-		{
-			pos--;
-			j++;
-		}
-		name[pos + 1] = '\0';
-
-		if (strcmp(last, name))
-		{
-			if (count == animation)
-				return last;
-
-			strcpy(last, name);
-			count++;
-		}
-	}
-
-	return 0;
-}
-
-static inline void md2_getAnimationFrames(md2_model_t *model,
-	INT32 animation, INT32 *startFrame, INT32 *endFrame)
-{
-	size_t i, pos;
-	INT32 j = 0, count, numFrames, frameCount;
-	char name[16], last[16];
-
-	strcpy(last, model->frames[0].name);
-	pos = strlen(last) - 1;
-	while (last[pos] >= '0' && last[pos] <= '9' && j < 2)
-	{
-		pos--;
-		j++;
-	}
-	last[pos + 1] = '\0';
-
-	count = 0;
-	numFrames = 0;
-	frameCount = 0;
-
-	for (i = 0; i <= model->header.numFrames; i++)
-	{
-		if (i == model->header.numFrames)
-			strcpy(name, ""); // some kind of a sentinel
-		else
-			strcpy(name, model->frames[i].name);
-		pos = strlen(name) - 1;
-		j = 0;
-		while (name[pos] >= '0' && name[pos] <= '9' && j < 2)
-		{
-			pos--;
-			j++;
-		}
-		name[pos + 1] = '\0';
-
-		if (strcmp(last, name))
-		{
-			strcpy(last, name);
-
-			if (count == animation)
-			{
-				*startFrame = frameCount - numFrames;
-				*endFrame = frameCount - 1;
-				return;
-			}
-
-			count++;
-			numFrames = 0;
-		}
-		frameCount++;
-		numFrames++;
-	}
-	*startFrame = *endFrame = 0;
-}
-
 static inline void md2_printModelInfo (md2_model_t *model)
 {
 #if 0
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 89b834828bae53d0cd9290a7c86e57b71cd5901a..8bd9c816be998d7a9f4f832c9b1c868b8d0997a9 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -140,14 +140,38 @@ static int lib_pAproxDistance(lua_State *L)
 
 static int lib_pClosestPointOnLine(lua_State *L)
 {
+	int n = lua_gettop(L);
 	fixed_t x = luaL_checkfixed(L, 1);
 	fixed_t y = luaL_checkfixed(L, 2);
-	line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
 	vertex_t result;
 	//HUDSAFE
-	if (!line)
-		return LUA_ErrInvalid(L, "line_t");
-	P_ClosestPointOnLine(x, y, line, &result);
+	if (lua_isuserdata(L, 3)) // use a real linedef to get our points
+	{
+		line_t *line = *((line_t **)luaL_checkudata(L, 3, META_LINE));
+		if (!line)
+			return LUA_ErrInvalid(L, "line_t");
+		P_ClosestPointOnLine(x, y, line, &result);
+	}
+	else // use custom coordinates of our own!
+	{
+		vertex_t v1, v2; // fake vertexes
+		line_t junk; // fake linedef
+
+		if (n < 6)
+			return luaL_error(L, "arguments 3 to 6 not all given (expected 4 fixed-point integers)");
+
+		v1.x = luaL_checkfixed(L, 3);
+		v1.y = luaL_checkfixed(L, 4);
+		v2.x = luaL_checkfixed(L, 5);
+		v2.y = luaL_checkfixed(L, 6);
+
+		junk.v1 = &v1;
+		junk.v2 = &v2;
+		junk.dx = v2.x - v1.x;
+		junk.dy = v2.y - v1.y;
+		P_ClosestPointOnLine(x, y, &junk, &result);
+	}
+
 	lua_pushfixed(L, result.x);
 	lua_pushfixed(L, result.y);
 	return 2;
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 325f00b013e5495f67d79b2ca78775e02812a4c6..52770a88a500d72cddbc7484e88a1126102807c3 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -395,7 +395,7 @@ static int libd_drawPaddedNum(lua_State *L)
 	HUDONLY
 	x = luaL_checkinteger(L, 1);
 	y = luaL_checkinteger(L, 2);
-	num = abs(luaL_checkinteger(L, 3));
+	num = labs(luaL_checkinteger(L, 3));
 	digits = luaL_optinteger(L, 4, 2);
 	flags = luaL_optinteger(L, 5, 0);
 	flags &= ~V_PARAMMASK; // Don't let crashes happen.
diff --git a/src/lua_script.h b/src/lua_script.h
index 96f832e2c60623998b16643ca2cf0131bffc7935..45fab2f53570f4118fdb14026807532b59dc9080 100644
--- a/src/lua_script.h
+++ b/src/lua_script.h
@@ -30,9 +30,9 @@
 #define lua_pushfixed(L, f) lua_pushinteger(L, f)
 
 // angle_t casting
-// we reduce the angle to a fixed point between 0.0 and 1.0
-#define luaL_checkangle(L, i) (((angle_t)(luaL_checkfixed(L, i)&0xFFFF))<<16)
-#define lua_pushangle(L, a) lua_pushfixed(L, a>>16)
+// TODO deal with signedness
+#define luaL_checkangle(L, i) ((angle_t)luaL_checkinteger(L, i))
+#define lua_pushangle(L, a) lua_pushinteger(L, a)
 
 #ifdef _DEBUG
 void LUA_ClearExtVars(void);
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 929945ecf0e25ff8d074c0cb437a3b3edd300039..2576a27ce30f6546be62b4bdca4dc2c4cdc1a385 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -196,26 +196,6 @@ static UINT8 cht_CheckCheat(cheatseq_t *cht, char key)
 	return rc;
 }
 
-static inline void cht_GetParam(cheatseq_t *cht, char *buffer)
-{
-	UINT8 *p;
-	UINT8 c;
-
-	p = cht->sequence;
-	while (*(p++) != 1)
-		;
-
-	do
-	{
-		c = *p;
-		*(buffer++) = c;
-		*(p++) = 0;
-	} while (c && *p != 0xff);
-
-	if (*p == 0xff)
-		*buffer = 0;
-}
-
 boolean cht_Responder(event_t *ev)
 {
 	UINT8 ret = 0, ch = 0;
diff --git a/src/md5.c b/src/md5.c
index aeaac2cdee6d5421e0c8c391b0da3246351f6e31..ba89c499b11ba6875e3420b450444ef365ac96ff 100644
--- a/src/md5.c
+++ b/src/md5.c
@@ -36,7 +36,7 @@
  #include <stdlib.h>
 #else
  #ifndef HAVE_MEMCPY
-  #if !((defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__))
+  #if !((defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__)) && !defined (__APPLE__)
    #define memcpy(d, s, n) bcopy ((s), (d), (n))
   #endif
  #endif
diff --git a/src/mserv.c b/src/mserv.c
index 568474d73e1219d46395dc4e832419ababab81a9..c47d149ee5c1f7f560a30e94e85340470f94a166 100644
--- a/src/mserv.c
+++ b/src/mserv.c
@@ -351,33 +351,6 @@ static INT32 GetServersList(void)
 }
 #endif
 
-/** Get the MOTD from the master server.
-  */
-static inline INT32 GetMSMOTD(void)
-{
-	msg_t msg;
-	INT32 count = 0;
-
-	msg.type = GET_MOTD_MSG;
-	msg.length = 0;
-	if (MS_Write(&msg) < 0)
-		return MS_WRITE_ERROR;
-
-	while (MS_Read(&msg) >= 0)
-	{
-		if (!msg.length)
-		{
-			if (!count)
-				CONS_Alert(CONS_NOTICE, M_GetText("No servers currently running.\n"));
-			return MS_NO_ERROR;
-		}
-		count++;
-		CONS_Printf("%s",msg.buffer);
-	}
-
-	return MS_READ_ERROR;
-}
-
 //
 // MS_Connect()
 //
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 373190cfe760b1271eae444d4b823a9f85826279..5e52bcaf435de59a0d3958461cf0c5b581f7743e 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -7223,7 +7223,7 @@ void A_ChangeAngleAbsolute(mobj_t *actor)
 	//const angle_t amin = FixedAngle(locvar1*FRACUNIT);
 	//const angle_t amax = FixedAngle(locvar2*FRACUNIT);
 #ifdef HAVE_BLUA
-	if (LUA_CallAction("A_ChangeAngelAbsolute", actor))
+	if (LUA_CallAction("A_ChangeAngleAbsolute", actor))
 		return;
 #endif
 
diff --git a/src/p_fab.c b/src/p_fab.c
deleted file mode 100644
index 7ccb93a94cf145024dd2b124dbdfc555d06f394e..0000000000000000000000000000000000000000
--- a/src/p_fab.c
+++ /dev/null
@@ -1,15 +0,0 @@
-// SONIC ROBO BLAST 2
-//-----------------------------------------------------------------------------
-// Copyright (C) 1998-2000 by DooM Legacy Team.
-// Copyright (C) 1999-2014 by Sonic Team Junior.
-//
-// This program is free software distributed under the
-// terms of the GNU General Public License, version 2.
-// See the 'LICENSE' file for more details.
-//-----------------------------------------------------------------------------
-/// \file  p_fab.c
-/// \brief some new action routines, separated from the original doom
-///        sources, so that you can include it or remove it easy.
-
-/// \todo
-///   This file is now unused, please remove at some point
diff --git a/src/p_map.c b/src/p_map.c
index e603aaa7592761a47927db135f834e6ac72830a0..28af18a19dce7827cd4fc849ef8c855ebf3dc440 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -1626,7 +1626,7 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
 
 						po->validcount = validcount;
 
-						if (!P_PointInsidePolyobj(po, x, y))
+						if (!P_PointInsidePolyobj(po, x, y) || !(po->flags & POF_SOLID))
 						{
 							plink = (polymaplink_t *)(plink->link.next);
 							continue;
@@ -2646,8 +2646,8 @@ isblocking:
 
 			climbangle += (ANGLE_90 * (whichside ? -1 : 1));
 
-			if (((!slidemo->player->climbing && abs((slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
-			|| (slidemo->player->climbing == 1 && abs((slidemo->angle - climbline)) < ANGLE_135))
+			if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
+			|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
 			&& P_IsClimbingValid(slidemo->player, climbangle))
 			{
 				slidemo->angle = climbangle;
@@ -3715,6 +3715,9 @@ static inline boolean PIT_GetSectors(line_t *ld)
 	if (P_BoxOnLineSide(tmbbox, ld) != -1)
 		return true;
 
+	if (ld->polyobj) // line belongs to a polyobject, don't add it
+		return true;
+
 	// This line crosses through the object.
 
 	// Collect the sector(s) from the line and add to the
@@ -3747,6 +3750,9 @@ static inline boolean PIT_GetPrecipSectors(line_t *ld)
 	if (P_BoxOnLineSide(preciptmbbox, ld) != -1)
 		return true;
 
+	if (ld->polyobj) // line belongs to a polyobject, don't add it
+		return true;
+
 	// This line crosses through the object.
 
 	// Collect the sector(s) from the line and add to the
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 8f349a2a99118cffc884b6d4302eab8f2e6d1dd6..82d9bbfe4001d129b62bd0c126a50840d0afda77 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -36,21 +36,6 @@ fixed_t P_AproxDistance(fixed_t dx, fixed_t dy)
 	return dx + dy - (dy>>1);
 }
 
-//
-// P_PartialDistance
-// Useful only for iterations finding the 'closest point'
-//
-FUNCMATH static inline fixed_t P_PartialDistance(fixed_t dx, fixed_t dy)
-{
-	dx >>= FRACBITS;
-	dy >>= FRACBITS;
-
-	dx *= dx;
-	dy *= dy;
-
-	return dx + dy;
-}
-
 //
 // P_ClosestPointOnLine
 // Finds the closest point on a given line to the supplied point
diff --git a/src/p_spec.c b/src/p_spec.c
index aa61138a031e83f237f4d5fe3b757c2906ba832c..8d3dfa8c8ae99be185fa5a9b884ae2411efa2725 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -103,7 +103,7 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *
 static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t offset, INT32 line, INT32 sourceline);
 static void P_AddBlockThinker(sector_t *sec, line_t *sourceline);
 static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline);
-static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec);
+//static void P_AddBridgeThinker(line_t *sourceline, sector_t *sec);
 static void P_AddFakeFloorsByLine(size_t line, ffloortype_e ffloorflags, thinkerlist_t *secthinkers);
 static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec);
 static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32 referrer);
@@ -594,6 +594,7 @@ void P_SetupLevelFlatAnims(void)
 // UTILITIES
 //
 
+#if 0
 /** Gets a side from a sector line.
   *
   * \param currentSector Sector the line is in.
@@ -633,6 +634,7 @@ static inline boolean twoSided(INT32 sector, INT32 line)
 {
 	return (sectors[sector].lines[line])->sidenum[1] != 0xffff;
 }
+#endif
 
 /** Finds sector next to current.
   *
@@ -4978,6 +4980,7 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline)
   * \sa P_SpawnSpecials, T_BridgeThinker
   * \author SSNTails <http://www.ssntails.org>
   */
+/*
 static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
 {
 	levelspecthink_t *bridge;
@@ -5000,6 +5003,7 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
 	bridge->vars[4] = sourceline->tag; // Start tag
 	bridge->vars[5] = (sides[sourceline->sidenum[0]].textureoffset>>FRACBITS); // End tag
 }
+*/
 
 /** Adds a Mario block thinker, which changes the block's texture between blank
   * and ? depending on whether it has contents.
diff --git a/src/p_user.c b/src/p_user.c
index dee5d4452df8d00fb5b67dcbb654909727e240c4..4f9bca55e2de2a6b51e388c14d662ac2903e7cd0 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -3109,7 +3109,7 @@ static void P_DoTeeter(player_t *player)
 							}
 
 							if (polybottom > player->mo->z + player->mo->height + tiptop
-							|| (polybottom < player->mo->z
+							|| (polytop < player->mo->z
 							&& player->mo->z + player->mo->height < player->mo->ceilingz - tiptop))
 								teeter = true;
 							else
@@ -3127,7 +3127,7 @@ static void P_DoTeeter(player_t *player)
 							}
 
 							if (polytop < player->mo->z - tiptop
-							|| (polytop > player->mo->z + player->mo->height
+							|| (polybottom > player->mo->z + player->mo->height
 							&& player->mo->z > player->mo->floorz + tiptop))
 								teeter = true;
 							else
@@ -3449,7 +3449,7 @@ static void P_DoSuperStuff(player_t *player)
 			case 2:  /* Knux     */ player->mo->color = SKINCOLOR_KSUPER1; break;
 			default: /* everyone */ player->mo->color = SKINCOLOR_SUPER1; break;
 		}
-		player->mo->color += abs( ( ( leveltime >> 1 ) % 9) - 4);
+		player->mo->color += abs( ( (signed)( (unsigned)leveltime >> 1 ) % 9) - 4);
 
 		if ((cmd->forwardmove != 0 || cmd->sidemove != 0 || player->pflags & (PF_CARRIED|PF_ROPEHANG|PF_ITEMHANG|PF_MACESPIN))
 		&& !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy))
@@ -7950,9 +7950,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		if (player == &players[consoleplayer])
 		{
 			if (focusangle >= localangle)
-				localangle += abs((focusangle - localangle))>>5;
+				localangle += abs((signed)(focusangle - localangle))>>5;
 			else
-				localangle -= abs((focusangle - localangle))>>5;
+				localangle -= abs((signed)(focusangle - localangle))>>5;
 		}
 	}
 	else if (P_AnalogMove(player)) // Analog
@@ -8161,7 +8161,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 
 						po->validcount = validcount;
 
-						if (!P_PointInsidePolyobj(po, x, y))
+						if (!P_PointInsidePolyobj(po, x, y) || !(po->flags & POF_SOLID))
 						{
 							plink = (polymaplink_t *)(plink->link.next);
 							continue;
diff --git a/src/r_bsp.c b/src/r_bsp.c
index c87d8baa716328e567ce5978a1ffc0baf21b9ad3..52be9a0e340a334d89ffb27bcc0c36ed2e5d9083 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -26,6 +26,7 @@ side_t *sidedef;
 line_t *linedef;
 sector_t *frontsector;
 sector_t *backsector;
+boolean portalline; // is curline a portal seg?
 
 // very ugly realloc() of drawsegs at run-time, I upped it to 512
 // instead of 256.. and someone managed to send me a level with
@@ -378,6 +379,7 @@ static void R_AddLine(seg_t *line)
 		return;
 
 	curline = line;
+	portalline = false;
 
 	// OPTIMIZE: quickly reject orthogonal back sides.
 	angle1 = R_PointToAngle(line->v1->x, line->v1->y);
@@ -431,7 +433,7 @@ static void R_AddLine(seg_t *line)
 	backsector = line->backsector;
 
 	// Portal line
-	if (line->linedef->special == 40 && P_PointOnLineSide(viewx, viewy, line->linedef) == 0)
+	if (line->linedef->special == 40 && line->side == 0)
 	{
 		if (portalrender < cv_maxportals.value)
 		{
diff --git a/src/r_bsp.h b/src/r_bsp.h
index 14b11ea77bc0dff35f8abf318c5dc1d31e42e857..3d0429fec5f7183b049bf03199643a5cf049690e 100644
--- a/src/r_bsp.h
+++ b/src/r_bsp.h
@@ -23,6 +23,7 @@ extern side_t *sidedef;
 extern line_t *linedef;
 extern sector_t *frontsector;
 extern sector_t *backsector;
+extern boolean portalline; // is curline a portal seg?
 
 // drawsegs are allocated on the fly... see r_segs.c
 
diff --git a/src/r_defs.h b/src/r_defs.h
index 2915b9259e46730069f0eb6fd614265eb2f41675..5eb3e7f68e5e747d00ad6084a70c8d05d2dcce68 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -667,6 +667,8 @@ typedef struct drawseg_s
 	INT32 numthicksides;
 	fixed_t frontscale[MAXVIDWIDTH];
 
+	UINT8 portalpass; // if > 0 and <= portalrender, do not affect sprite clipping
+
 #ifdef ESLOPE
 	fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures
 
diff --git a/src/r_main.c b/src/r_main.c
index 71b225e836f292f2d2d984e9c6d59a3548f487ce..fca29e57c3d09a5dc889ff70f20dc5a5fb56639d 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -91,7 +91,6 @@ typedef struct portal_pair
 	INT16 *ceilingclip;
 	INT16 *floorclip;
 	fixed_t *frontscale;
-	size_t seg;
 } portal_pair;
 portal_pair *portal_base, *portal_cap;
 line_t *portalclipline;
@@ -1230,7 +1229,7 @@ void R_AddPortal(INT32 line1, INT32 line2, INT32 x1, INT32 x2)
 	portal->start = x1;
 	portal->end = x2;
 
-	portal->seg = ds_p-drawsegs;
+	portalline = true; // this tells R_StoreWallRange that curline is a portal seg
 
 	portal->viewx = viewx;
 	portal->viewy = viewy;
@@ -1344,14 +1343,6 @@ void R_RenderPlayerView(player_t *player)
 
 		validcount++;
 
-		if (portal->seg)
-		{
-			// Push the portal's old drawseg out of the way so it isn't interfering with sprite clipping. -Red
-			drawseg_t *seg = drawsegs+portal->seg;
-			seg->scale1 = 0;
-			seg->scale2 = 0;
-		}
-
 		R_RenderBSPNode((INT32)numnodes - 1);
 		R_ClipSprites();
 		//R_DrawPlanes();
@@ -1360,6 +1351,9 @@ void R_RenderPlayerView(player_t *player)
 		// okay done. free it.
 		portalcullsector = NULL; // Just in case...
 		portal_base = portal->next;
+		Z_Free(portal->ceilingclip);
+		Z_Free(portal->floorclip);
+		Z_Free(portal->frontscale);
 		Z_Free(portal);
 	}
 	// END PORTAL RENDERING
diff --git a/src/r_segs.c b/src/r_segs.c
index 04873b29cda604ef7fff122520e139b0edc0604f..252f6faced8f3a239952dfb4f3e021d2c96880ca 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1922,7 +1922,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		    || backsector->ceilingpic_angle != frontsector->ceilingpic_angle
 		    //SoM: 3/22/2000: Prevents bleeding.
 		    || (frontsector->heightsec != -1 && frontsector->ceilingpic != skyflatnum)
-		    || backsector->floorlightsec != frontsector->floorlightsec
+		    || backsector->ceilinglightsec != frontsector->ceilinglightsec
 		    //SoM: 4/3/2000: Check for colormaps
 		    || frontsector->extra_colormap != backsector->extra_colormap
 		    || (frontsector->ffloors != backsector->ffloors && frontsector->tag != backsector->tag))
@@ -2887,6 +2887,11 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		R_RenderSegLoop();
 	colfunc = wallcolfunc;
 
+	if (portalline) // if curline is a portal, set portalrender for drawseg
+		ds_p->portalpass = portalrender+1;
+	else
+		ds_p->portalpass = 0;
+
 	// save sprite clipping info
 	if (((ds_p->silhouette & SIL_TOP) || maskedtexture) && !ds_p->sprtopclip)
 	{
diff --git a/src/r_things.c b/src/r_things.c
index a5f795e0bbf5e43d2712414609e03e8c0a3e6c12..c667c80a354228682f2bdee24de3a546df2b6845 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -555,11 +555,6 @@ void R_ClearSprites(void)
 	visspritecount = clippedvissprites = 0;
 }
 
-static inline void R_ResetVisSpriteChunks(void)
-{
-	memset(visspritechunks, 0, sizeof(visspritechunks));
-}
-
 //
 // R_NewVisSprite
 //
@@ -843,10 +838,10 @@ static void R_DrawVisSprite(vissprite_t *vis)
 		dc_texturemid = FixedDiv(dc_texturemid,this_scale);
 
 		//Oh lordy, mercy me. Don't freak out if sprites go offscreen!
-		if (vis->xiscale > 0)
+		/*if (vis->xiscale > 0)
 			frac = FixedDiv(frac, this_scale);
 		else if (vis->x1 <= 0)
-			frac = (vis->x1 - vis->x2) * vis->xiscale;
+			frac = (vis->x1 - vis->x2) * vis->xiscale;*/
 
 		sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
 		//dc_hires = 1;
@@ -1315,7 +1310,7 @@ static void R_ProjectSprite(mobj_t *thing)
 	}
 
 	if (vis->x1 > x1)
-		vis->startfrac += vis->xiscale*(vis->x1-x1);
+		vis->startfrac += FixedDiv(vis->xiscale, this_scale)*(vis->x1-x1);
 
 	//Fab: lumppat is the lump number of the patch to use, this is different
 	//     than lumpid for sprites-in-pwad : the graphics are patched
@@ -2067,6 +2062,9 @@ void R_ClipSprites(void)
 				continue;
 			}
 
+			if (ds->portalpass > 0 && ds->portalpass <= portalrender)
+				continue; // is a portal
+
 			r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
 			r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
 
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index b3d734521bed110b4d3c107fd2e52db252ee4523..7f6771262dcbd2415639f41d20ad7a15a3092da4 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -117,11 +117,13 @@ if(${SDL2_FOUND})
 	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
 	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
 
-	if((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
-		add_framework(CoreFoundation SRB2SDL2)
-		add_framework(SDL2 SRB2SDL2)
-		add_framework(SDL2_mixer SRB2SDL2)
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
+		find_library(CORE_LIB CoreFoundation)
 		target_link_libraries(SRB2SDL2 PRIVATE
+			${CORE_LIB}
+			SDL2
+			SDL2_mixer
+			${GME_LIBRARIES}
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
@@ -131,6 +133,7 @@ if(${SDL2_FOUND})
 		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_LIBRARIES}
 			${SDL2_MIXER_LIBRARIES}
+			${GME_LIBRARIES}
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
@@ -198,6 +201,7 @@ if(${SDL2_FOUND})
 	target_include_directories(SRB2SDL2 PRIVATE
 		${SDL2_INCLUDE_DIRS}
 		${SDL2_MIXER_INCLUDE_DIRS}
+		${GME_INCLUDE_DIRS}
 		${PNG_INCLUDE_DIRS}
 		${ZLIB_INCLUDE_DIRS}
 		${OPENGL_INCLUDE_DIRS}
@@ -224,7 +228,7 @@ if(${SDL2_FOUND})
 	endif()
 
 	#### Installation ####
-	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		install(TARGETS SRB2SDL2
 			BUNDLE DESTINATION .
 		)
@@ -265,7 +269,7 @@ if(${SDL2_FOUND})
 
 
 	# Mac bundle fixup
-	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		install(CODE "
 			include(BundleUtilities)
 			fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/Sonic Robo Blast 2.app\"
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 963310a261546984379b7fe105e761fb8c7d351a..0f9fa58a8ef44079c5112aa186682fbdf9f7df77 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -126,8 +126,6 @@ static       Uint8       BitsPerPixel = 16;
 #endif
 Uint16      realwidth = BASEVIDWIDTH;
 Uint16      realheight = BASEVIDHEIGHT;
-static const Uint32      surfaceFlagsW = 0/*|SDL_RESIZABLE*/;
-static const Uint32      surfaceFlagsF = 0;
 static       SDL_bool    mousegrabok = SDL_TRUE;
 #define HalfWarpMouse(x,y) SDL_WarpMouseInWindow(window, (Uint16)(x/2),(Uint16)(y/2))
 static       SDL_bool    videoblitok = SDL_FALSE;
@@ -1252,17 +1250,6 @@ static inline boolean I_SkipFrame(void)
 	}
 }
 
-static inline SDL_bool SDLmatchVideoformat(void)
-{
-	const SDL_PixelFormat *vidformat = vidSurface->format;
-	const INT32 vfBPP = vidformat?vidformat->BitsPerPixel:0;
-	return (((vfBPP == 8 && vid.bpp == 1 &&
-	 !vidformat->Rmask && !vidformat->Gmask && !vidformat->Bmask) ||
-	 (vfBPP == 15 && vid.bpp == 2 && vidformat->Rmask == 0x7C00 &&
-	 vidformat->Gmask == 0x03E0 && vidformat->Bmask == 0x001F )) &&
-	 !vidformat->Amask && (vidSurface->flags & SDL_RLEACCEL) == 0);
-}
-
 //
 // I_FinishUpdate
 //
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index 98599fb60b7ad0a89046d317f63292bc461dbae3..c3f0d3b38ca398116070f687881a551969feefbb 100644
--- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1270,6 +1270,7 @@
 					HAVE_BLUA,
 					LUA_USE_POSIX,
 					COMPVERSION,
+					HWRENDER,
 				);
 				GCC_THREADSAFE_STATICS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@@ -1392,6 +1393,7 @@
 					HAVE_BLUA,
 					LUA_USE_POSIX,
 					COMPVERSION,
+					HWRENDER,
 				);
 				GCC_THREADSAFE_STATICS = NO;
 				GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
diff --git a/src/string.c b/src/string.c
index 436757309d96845a8e516e95326132261031fc25..19540547c937bf49b1f8eb755f14f9a87830322d 100644
--- a/src/string.c
+++ b/src/string.c
@@ -15,6 +15,8 @@
 #include <string.h>
 #include "doomdef.h"
 
+#if !defined (__APPLE__)
+
 // Like the OpenBSD version, but it doesn't check for src not being a valid
 // C string.
 size_t strlcat(char *dst, const char *src, size_t siz)
@@ -46,3 +48,5 @@ size_t strlcpy(char *dst, const char *src, size_t siz)
 	dst[0] = '\0';
 	return strlcat(dst, src, siz);
 }
+
+#endif
diff --git a/src/v_video.c b/src/v_video.c
index c5afd783f0ccb4c4cd00f472c1fad118e34e6112..d7168a33e0ebf4bf6740e71c29535aebc0f973f2 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -336,6 +336,8 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
 	const column_t *column;
 	UINT8 *desttop, *dest, *deststart, *destend;
 	const UINT8 *source, *deststop;
+	fixed_t pwidth; // patch width
+	fixed_t offx = 0; // x offset
 
 	if (rendermode == render_none)
 		return;
@@ -476,16 +478,36 @@ void V_DrawFixedPatch(fixed_t x, fixed_t y, fixed_t pscale, INT32 scrn, patch_t
 		}
 	}
 
+	if (pscale != FRACUNIT) // scale width properly
+	{
+		pwidth = SHORT(patch->width)<<FRACBITS;
+		pwidth = FixedMul(pwidth, pscale);
+		pwidth = FixedMul(pwidth, dupx<<FRACBITS);
+		pwidth >>= FRACBITS;
+	}
+	else
+		pwidth = SHORT(patch->width) * dupx;
+
 	deststart = desttop;
-	destend = desttop + SHORT(patch->width) * dupx;
+	destend = desttop + pwidth;
 
-	for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, ++x, desttop++)
+	for (col = 0; (col>>FRACBITS) < SHORT(patch->width); col += colfrac, ++offx, desttop++)
 	{
 		INT32 topdelta, prevdelta = -1;
-		if (x < 0) // don't draw off the left of the screen (WRAP PREVENTION)
-			continue;
-		if (x >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
-			break;
+		if (flip) // offx is measured from right edge instead of left
+		{
+			if (x+pwidth-offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
+				break;
+			if (x+pwidth-offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
+				continue;
+		}
+		else
+		{
+			if (x+offx < 0) // don't draw off the left of the screen (WRAP PREVENTION)
+				continue;
+			if (x+offx >= vid.width) // don't draw off the right of the screen (WRAP PREVENTION)
+				break;
+		}
 		column = (const column_t *)((const UINT8 *)(patch) + LONG(patch->columnofs[col>>FRACBITS]));
 
 		while (column->topdelta != 0xff)
diff --git a/src/y_inter.c b/src/y_inter.c
index 718434d8354353edd7dec5a48cda4e3ea93b75af..790cd917f102845e5ed8529d2ea19da7759115c2 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -77,10 +77,14 @@ typedef union
 
 	struct
 	{
-		char passed1[13]; // KNUCKLES GOT
-		char passed2[16]; // A CHAOS EMERALD
+		char passed1[SKINNAMESIZE+1]; // KNUCKLES GOT    / CRAWLA HONCHO
+		char passed2[17];             // A CHAOS EMERALD / GOT THEM ALL!
+		char passed3[15];             //                   CAN NOW BECOME
+		char passed4[SKINNAMESIZE+7]; //                   SUPER CRAWLA HONCHO
 		INT32 passedx1;
 		INT32 passedx2;
+		INT32 passedx3;
+		INT32 passedx4;
 
 		y_bonus_t bonus;
 		patch_t *bonuspatch;
@@ -250,19 +254,62 @@ void Y_IntermissionDrawer(void)
 	}
 	else if (intertype == int_spec)
 	{
+		static tic_t animatetic = 0;
+		INT32 ttheight = 16;
+		INT32 xoffset1 = 0; // Line 1 x offset
+		INT32 xoffset2 = 0; // Line 2 x offset
+		INT32 xoffset3 = 0; // Line 3 x offset
+		UINT8 drawsection = 0;
+
 		// draw the header
-/*		if (endtic != -1 && ALL7EMERALDS(emeralds) && data.spec.nowsuper != NULL)
-			V_DrawScaledPatch(48, 32, 0, data.spec.nowsuper);
-		else
-			V_DrawScaledPatch(data.spec.headx, 26, 0, data.spec.cemerald); */
+		if (intertic <= TICRATE)
+			animatetic = 0;
+		else if (!animatetic && data.spec.bonus.points == 0 && data.spec.passed3[0] != '\0')
+			animatetic = intertic;
+
+		if (animatetic)
+		{
+			INT32 animatetimer = (intertic - animatetic);
+			if (animatetimer <= 8)
+			{
+				xoffset1 = -(animatetimer     * 40);
+				xoffset2 = -((animatetimer-2) * 40);
+				if (xoffset2 > 0) xoffset2 = 0;
+			}
+			else if (animatetimer <= 19)
+			{
+				drawsection = 1;
+				xoffset1 = (16-animatetimer) * 40;
+				xoffset2 = (18-animatetimer) * 40;
+				xoffset3 = (20-animatetimer) * 40;
+				if (xoffset1 < 0) xoffset1 = 0;
+				if (xoffset2 < 0) xoffset2 = 0;
+			}
+			else
+				drawsection = 1;
+		}
 
-		if (data.spec.passed1[0] != '\0')
+		if (drawsection == 1)
 		{
-			V_DrawLevelTitle(data.spec.passedx1, 24, 0, data.spec.passed1);
-			V_DrawLevelTitle(data.spec.passedx2, 24+V_LevelNameHeight(data.spec.passed2)+2, 0, data.spec.passed2);
+			ttheight = 16;
+			V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
+			ttheight += V_LevelNameHeight(data.spec.passed3) + 2;
+			V_DrawLevelTitle(data.spec.passedx3 + xoffset2, ttheight, 0, data.spec.passed3);
+			ttheight += V_LevelNameHeight(data.spec.passed4) + 2;
+			V_DrawLevelTitle(data.spec.passedx4 + xoffset3, ttheight, 0, data.spec.passed4);
+		}
+		else if (data.spec.passed1[0] != '\0')
+		{
+			ttheight = 24;
+			V_DrawLevelTitle(data.spec.passedx1 + xoffset1, ttheight, 0, data.spec.passed1);
+			ttheight += V_LevelNameHeight(data.spec.passed2) + 2;
+			V_DrawLevelTitle(data.spec.passedx2 + xoffset2, ttheight, 0, data.spec.passed2);
 		}
 		else
-			V_DrawLevelTitle(data.spec.passedx2, 24+(V_LevelNameHeight(data.spec.passed2)/2)+2, 0, data.spec.passed2);
+		{
+			ttheight = 24 + (V_LevelNameHeight(data.spec.passed2)/2) + 2;
+			V_DrawLevelTitle(data.spec.passedx2 + xoffset1, ttheight, 0, data.spec.passed2);
+		}
 
 		// draw the emeralds
 		if (intertic & 1)
@@ -708,7 +755,7 @@ void Y_Ticker(void)
 		{
 			if (intertic > tallydonetic)
 			{
-				endtic = intertic + 4*TICRATE; // 4 second pause after end of tally for sound
+				endtic = intertic + 4*TICRATE; // 4 second pause after end of tally
 				S_StartSound(NULL, sfx_flgcap); // cha-ching!
 			}
 			return;
@@ -728,7 +775,7 @@ void Y_Ticker(void)
 			if (data.spec.continues & 0x80) // don't set endtic yet!
 				tallydonetic = intertic + (3*TICRATE)/2;
 			else // okay we're good.
-				endtic = intertic + 3*TICRATE; // 3 second pause after end of tally
+				endtic = intertic + 4*TICRATE; // 4 second pause after end of tally
 
 			S_StartSound(NULL, sfx_chchng); // cha-ching!
 
@@ -1098,6 +1145,10 @@ void Y_StartIntermission(void)
 				data.spec.nowsuper = NULL;
 			} */
 
+			// Super form stuff (normally blank)
+			data.spec.passed3[0] = '\0';
+			data.spec.passed4[0] = '\0';
+
 			// set up the "got through act" message according to skin name
 			if (stagefailed)
 			{
@@ -1111,10 +1162,19 @@ void Y_StartIntermission(void)
 					skins[players[consoleplayer].skin].realname);
 				data.spec.passed1[sizeof data.spec.passed1 - 1] = '\0';
 				strcpy(data.spec.passed2, "GOT THEM ALL!");
+
+				if (skins[players[consoleplayer].skin].flags & SF_SUPER)
+				{
+					strcpy(data.spec.passed3, "CAN NOW BECOME");
+					snprintf(data.spec.passed4,
+						sizeof data.spec.passed4, "SUPER %s",
+						skins[players[consoleplayer].skin].realname);
+					data.spec.passed4[sizeof data.spec.passed4 - 1] = '\0';
+				}
 			}
 			else
 			{
-				if (strlen(skins[players[consoleplayer].skin].realname) <= 8)
+				if (strlen(skins[players[consoleplayer].skin].realname) <= SKINNAMESIZE-5)
 				{
 					snprintf(data.spec.passed1,
 						sizeof data.spec.passed1, "%s GOT",
@@ -1127,6 +1187,8 @@ void Y_StartIntermission(void)
 			}
 			data.spec.passedx1 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed1))/2;
 			data.spec.passedx2 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed2))/2;
+			data.spec.passedx3 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed3))/2;
+			data.spec.passedx4 = (BASEVIDWIDTH - V_LevelNameWidth(data.spec.passed4))/2;
 			break;
 		}