diff --git a/SRB2.cbp b/SRB2.cbp
index 43696ee2e4b23a9ecf6eafafe51bfeaa834cb154..99a71226467e07aeb3e6f01f01cb99608bea6cf7 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -2815,6 +2815,39 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/m_aatree.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/m_aatree.h">
+			<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/m_anigif.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 035b4655699bdf4c6d2830d6ab8dc358360948d1..ba354c2899870ccb7d4d850863b6a20ebd618110 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRB2_CORE_SOURCES
 	i_tcp.c
 	info.c
 	lzf.c
+	m_aatree.c
 	m_anigif.c
 	m_argv.c
 	m_bbox.c
@@ -83,6 +84,7 @@ set(SRB2_CORE_HEADERS
 	info.h
 	keys.h
 	lzf.h
+	m_aatree.h
 	m_anigif.h
 	m_argv.h
 	m_bbox.h
diff --git a/src/Makefile b/src/Makefile
index 55ef15038595c54ddd9ca2cf419fda285666cbf5..ce4b569eebd7dcc94cfc8858daea7bf4f38dd287 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -433,6 +433,7 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/hu_stuff.o \
 		$(OBJDIR)/y_inter.o  \
 		$(OBJDIR)/st_stuff.o \
+		$(OBJDIR)/m_aatree.o \
 		$(OBJDIR)/m_anigif.o \
 		$(OBJDIR)/m_argv.o   \
 		$(OBJDIR)/m_bbox.o   \
diff --git a/src/dehacked.c b/src/dehacked.c
index e798d8f1077f6f10aae5af24cfd871a1bca47175..f03dd73b474f975317e644bf180697960e31764f 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -8280,6 +8280,9 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"VERSIONSTRING")) {
 		lua_pushstring(L, VERSIONSTRING);
 		return 1;
+	} else if (fastcmp(word, "token")) {
+		lua_pushinteger(L, token);
+		return 1;
 	}
 
 	return 0;
diff --git a/src/doomdef.h b/src/doomdef.h
index 9a1e5af9ee5a6e5ce5c1bc7063a918354a4b17ab..66e649ee0f14be7d4cf3e609760dc23f77b11595 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -149,9 +149,9 @@ extern FILE *logstream;
 // we use comprevision and compbranch instead.
 #else
 #define VERSION    201 // Game version
-#define SUBVERSION 15  // more precise version number
-#define VERSIONSTRING "v2.1.15"
-#define VERSIONSTRINGW L"v2.1.15"
+#define SUBVERSION 16  // more precise version number
+#define VERSIONSTRING "v2.1.16"
+#define VERSIONSTRINGW L"v2.1.16"
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
@@ -213,7 +213,7 @@ extern FILE *logstream;
 // it's only for detection of the version the player is using so the MS can alert them of an update.
 // Only set it higher, not lower, obviously.
 // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
-#define MODVERSION 20
+#define MODVERSION 21
 
 // =========================================================================
 
@@ -431,6 +431,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 /// Kalaron/Eternity Engine slope code (SRB2CB ported)
 #define ESLOPE
 
+#ifdef ESLOPE
+/// Backwards compatibility with SRB2CB's slope linedef types.
+///	\note	A simple shim that prints a warning.
+#define ESLOPE_TYPESHIM
+#endif
+
 ///	Delete file while the game is running.
 ///	\note	EXTREMELY buggy, tends to crash game.
 //#define DELFILE
diff --git a/src/f_finale.c b/src/f_finale.c
index 776bec9812f602f9bab2987ef28e213471279837..784d820478af38b429a8ac8b70ee94ea683db1f3 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -986,6 +986,7 @@ static const char *credits[] = {
 	"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
 	"Andrew \"orospakr\" Clunis",
 	"Gregor \"Oogaland\" Dick",
+	"Vivian \"toaster\" Grannell",
 	"Julio \"Chaos Zero 64\" Guir",
 	"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
 	"Matthew \"Shuffle\" Marsalko",
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 7678c7c49c26c150caac4623934b0916bde090b5..e8e8fd02044320e495d11d00310a5ee292b9b625 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -437,6 +437,16 @@ static int lib_pMobjFlip(lua_State *L)
 	return 1;
 }
 
+static int lib_pGetMobjGravity(lua_State *L)
+{
+	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	//HUDSAFE
+	if (!mobj)
+		return LUA_ErrInvalid(L, "mobj_t");
+	lua_pushfixed(L, P_GetMobjGravity(mobj));
+	return 1;
+}
+
 static int lib_pWeaponOrPanel(lua_State *L)
 {
 	mobjtype_t type = luaL_checkinteger(L, 1);
@@ -2008,6 +2018,7 @@ static luaL_Reg lib[] = {
 	{"P_SPMAngle",lib_pSPMAngle},
 	{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
 	{"P_MobjFlip",lib_pMobjFlip},
+	{"P_GetMobjGravity",lib_pGetMobjGravity},
 	{"P_WeaponOrPanel",lib_pWeaponOrPanel},
 	{"P_FlashPal",lib_pFlashPal},
 	{"P_GetClosestAxis",lib_pGetClosestAxis},
diff --git a/src/m_aatree.c b/src/m_aatree.c
new file mode 100644
index 0000000000000000000000000000000000000000..6cb3a32cb927aac773db7739b6a0dc6887e14294
--- /dev/null
+++ b/src/m_aatree.c
@@ -0,0 +1,167 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 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  m_aatree.h
+/// \brief AA trees code
+
+#include "m_aatree.h"
+#include "z_zone.h"
+
+// A partial implementation of AA trees,
+// according to the algorithms given on Wikipedia.
+// http://en.wikipedia.org/wiki/AA_tree
+
+typedef struct aatree_node_s
+{
+	INT32	level;
+	INT32	key;
+	void*	value;
+
+	struct aatree_node_s *left, *right;
+} aatree_node_t;
+
+struct aatree_s
+{
+	aatree_node_t	*root;
+	UINT32		flags;
+};
+
+aatree_t *M_AATreeAlloc(UINT32 flags)
+{
+	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
+	aatree->root = NULL;
+	aatree->flags = flags;
+	return aatree;
+}
+
+static void M_AATreeFree_Node(aatree_node_t *node)
+{
+	if (node->left) M_AATreeFree_Node(node->left);
+	if (node->right) M_AATreeFree_Node(node->right);
+	Z_Free(node);
+}
+
+void M_AATreeFree(aatree_t *aatree)
+{
+	if (aatree->root)
+		M_AATreeFree_Node(aatree->root);
+
+	Z_Free(aatree);
+}
+
+static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
+{
+	if (node && node->left && node->left->level == node->level)
+	{
+		// Not allowed: horizontal left-link. Reverse the
+		// horizontal link and hook the orphan back in.
+		aatree_node_t *oldleft = node->left;
+		node->left = oldleft->right;
+		oldleft->right = node;
+
+		return oldleft;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
+{
+	if (node && node->right && node->right->right && node->level == node->right->right->level)
+	{
+		// Not allowed: two consecutive horizontal right-links.
+		// The middle one becomes the new root at this point,
+		// with suitable adjustments below.
+
+		aatree_node_t *oldright = node->right;
+		node->right = oldright->left;
+		oldright->left = node;
+		oldright->level++;
+
+		return oldright;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
+{
+	if (!node)
+	{
+		// Nothing here, so just add where we are
+
+		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
+		node->level = 1;
+		node->key = key;
+		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+		else node->value = value;
+		node->left = node->right = NULL;
+	}
+	else
+	{
+		if (key < node->key)
+			node->left = M_AATreeSet_Node(node->left, flags, key, value);
+		else if (key > node->key)
+			node->right = M_AATreeSet_Node(node->right, flags, key, value);
+		else
+		{
+			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+			else node->value = value;
+		}
+
+		node = M_AATreeSkew(node);
+		node = M_AATreeSplit(node);
+	}
+
+	return node;
+}
+
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
+{
+	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
+}
+
+// Caveat: we don't distinguish between nodes that don't exists
+// and nodes with value == NULL.
+static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
+{
+	if (node)
+	{
+		if (node->key == key)
+			return node->value;
+		else if(node->key < key)
+			return M_AATreeGet_Node(node->right, key);
+		else
+			return M_AATreeGet_Node(node->left, key);
+	}
+
+	return NULL;
+}
+
+void *M_AATreeGet(aatree_t *aatree, INT32 key)
+{
+	return M_AATreeGet_Node(aatree->root, key);
+}
+
+
+static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
+{
+	if (node->left) M_AATreeIterate_Node(node->left, callback);
+	callback(node->key, node->value);
+	if (node->right) M_AATreeIterate_Node(node->right, callback);
+}
+
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
+{
+	if (aatree->root)
+		M_AATreeIterate_Node(aatree->root, callback);
+}
diff --git a/src/m_aatree.h b/src/m_aatree.h
new file mode 100644
index 0000000000000000000000000000000000000000..c9077b9740f1251eb4584120cd2f8283174d3eb3
--- /dev/null
+++ b/src/m_aatree.h
@@ -0,0 +1,31 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 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  m_aatree.h
+/// \brief AA trees code
+
+#ifndef __M_AATREE__
+#define __M_AATREE__
+
+#include "doomtype.h"
+
+// Flags for AA trees.
+#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
+
+typedef struct aatree_s aatree_t;
+typedef void (*aatree_iter_t)(INT32 key, void *value);
+
+aatree_t *M_AATreeAlloc(UINT32 flags);
+void M_AATreeFree(aatree_t *aatree);
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
+void *M_AATreeGet(aatree_t *aatree, INT32 key);
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
+
+#endif
\ No newline at end of file
diff --git a/src/m_misc.c b/src/m_misc.c
index 64054d4f9cada065577d1293d09fed5823460730..457214e339e66b5897d0451f21f2798d99f24d63 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -2323,158 +2323,3 @@ void M_SetupMemcpy(void)
 	M_Memcpy = cpu_cpy;
 #endif
 }
-
-
-// A partial implementation of AA trees,
-// according to the algorithms given on Wikipedia.
-// http://en.wikipedia.org/wiki/AA_tree
-
-
-
-typedef struct aatree_node_s
-{
-	INT32	level;
-	INT32	key;
-	void*	value;
-
-	struct aatree_node_s *left, *right;
-} aatree_node_t;
-
-struct aatree_s
-{
-	aatree_node_t	*root;
-	UINT32		flags;
-};
-
-aatree_t *M_AATreeAlloc(UINT32 flags)
-{
-	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
-	aatree->root = NULL;
-	aatree->flags = flags;
-	return aatree;
-}
-
-static void M_AATreeFree_Node(aatree_node_t *node)
-{
-	if (node->left) M_AATreeFree_Node(node->left);
-	if (node->right) M_AATreeFree_Node(node->right);
-	Z_Free(node);
-}
-
-void M_AATreeFree(aatree_t *aatree)
-{
-	if (aatree->root)
-		M_AATreeFree_Node(aatree->root);
-
-	Z_Free(aatree);
-}
-
-static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
-{
-	if (node && node->left && node->left->level == node->level)
-	{
-		// Not allowed: horizontal left-link. Reverse the
-		// horizontal link and hook the orphan back in.
-		aatree_node_t *oldleft = node->left;
-		node->left = oldleft->right;
-		oldleft->right = node;
-
-		return oldleft;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
-{
-	if (node && node->right && node->right->right && node->level == node->right->right->level)
-	{
-		// Not allowed: two consecutive horizontal right-links.
-		// The middle one becomes the new root at this point,
-		// with suitable adjustments below.
-
-		aatree_node_t *oldright = node->right;
-		node->right = oldright->left;
-		oldright->left = node;
-		oldright->level++;
-
-		return oldright;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
-{
-	if (!node)
-	{
-		// Nothing here, so just add where we are
-
-		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
-		node->level = 1;
-		node->key = key;
-		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-		else node->value = value;
-		node->left = node->right = NULL;
-	}
-	else
-	{
-		if (key < node->key)
-			node->left = M_AATreeSet_Node(node->left, flags, key, value);
-		else if (key > node->key)
-			node->right = M_AATreeSet_Node(node->right, flags, key, value);
-		else
-		{
-			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-			else node->value = value;
-		}
-
-		node = M_AATreeSkew(node);
-		node = M_AATreeSplit(node);
-	}
-
-	return node;
-}
-
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
-{
-	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
-}
-
-// Caveat: we don't distinguish between nodes that don't exists
-// and nodes with value == NULL.
-static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
-{
-	if (node)
-	{
-		if (node->key == key)
-			return node->value;
-		else if(node->key < key)
-			return M_AATreeGet_Node(node->right, key);
-		else
-			return M_AATreeGet_Node(node->left, key);
-	}
-
-	return NULL;
-}
-
-void *M_AATreeGet(aatree_t *aatree, INT32 key)
-{
-	return M_AATreeGet_Node(aatree->root, key);
-}
-
-
-static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
-{
-	if (node->left) M_AATreeIterate_Node(node->left, callback);
-	callback(node->key, node->value);
-	if (node->right) M_AATreeIterate_Node(node->right, callback);
-}
-
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
-{
-	if (aatree->root)
-		M_AATreeIterate_Node(aatree->root, callback);
-}
diff --git a/src/m_misc.h b/src/m_misc.h
index fa1f3b33ca78032e64620bcc139d7cf365680c07..dc540dc16325ffca245ba194393463067823c083 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -96,19 +96,6 @@ void M_SetupMemcpy(void);
 // counting bits, for weapon ammo code, usually
 FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
 
-// Flags for AA trees.
-#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
-
-typedef struct aatree_s aatree_t;
-typedef void (*aatree_iter_t)(INT32 key, void *value);
-
-aatree_t *M_AATreeAlloc(UINT32 flags);
-void M_AATreeFree(aatree_t *aatree);
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
-void *M_AATreeGet(aatree_t *aatree, INT32 key);
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
-
-// Nasty cyclic dependency workaround. This must come after aatree stuff.
 #include "w_wad.h"
 extern char configfile[MAX_WADPATH];
 
diff --git a/src/p_floor.c b/src/p_floor.c
index 1c396c8773ab93aeb1a2ef164d1a429c2d9cfe3c..9112130145cc7df7bca88b34cd74620e8f9670ed 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1163,7 +1163,7 @@ void T_SpikeSector(levelspecthink_t *spikes)
 
 	node = spikes->sector->touching_thinglist; // things touching this sector
 
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (!thing->player)
@@ -1316,7 +1316,7 @@ void T_BridgeThinker(levelspecthink_t *bridge)
 			controlsec = &sectors[k];
 
 			// Is a player standing on me?
-			for (node = sector->touching_thinglist; node; node = node->m_snext)
+			for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
 			{
 				thing = node->m_thing;
 
@@ -1739,7 +1739,7 @@ wegotit:
 static mobj_t *SearchMarioNode(msecnode_t *node)
 {
 	mobj_t *thing = NULL;
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		// Things which should NEVER be ejected from a MarioBlock, by type.
 		switch (node->m_thing->type)
@@ -2003,7 +2003,7 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
 						goto foundenemy;
 					}
 
-					node = node->m_snext;
+					node = node->m_thinglist_next;
 				}
 			}
 		}
@@ -2288,7 +2288,7 @@ void T_RaiseSector(levelspecthink_t *raise)
 		sector = &sectors[i];
 
 		// Is a player standing on me?
-		for (node = sector->touching_thinglist; node; node = node->m_snext)
+		for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
 		{
 			thing = node->m_thing;
 
diff --git a/src/p_local.h b/src/p_local.h
index 972e26e799408b173d80f0e97d7211ca30952e1c..1fd7ada04219b928fe1619e2398fb4fef5ba500a 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -251,6 +251,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype
 #endif
 void P_ColorTeamMissile(mobj_t *missile, player_t *source);
 SINT8 P_MobjFlip(mobj_t *mobj);
+fixed_t P_GetMobjGravity(mobj_t *mo);
 FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
 
 boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
diff --git a/src/p_map.c b/src/p_map.c
index 71adf2e1631a6a0cb2fab6aafe124638c42a7e54..1f2d903e80efaa6d3073244eca69ed2ca26f1b6e 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -129,6 +129,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		return false;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you.
+#endif
+
 	object->eflags |= MFE_SPRUNG; // apply this flag asap!
 	spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
 
@@ -232,20 +236,24 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 	if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
 		return;
 
-	// is object below thruster's position? if not, calculate distance between their bottoms
+	// is object's top below thruster's position? if not, calculate distance between their bottoms
 	if (spring->eflags & MFE_VERTICALFLIP)
 	{
-		if (object->z + object->height > spring->z + spring->height)
+		if (object->z > spring->z + spring->height)
 			return;
 		zdist = (spring->z + spring->height) - (object->z + object->height);
 	}
 	else
 	{
-		if (object->z < spring->z)
+		if (object->z + object->height < spring->z)
 			return;
 		zdist = object->z - spring->z;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // No launching off at silly angles for you.
+#endif
+
 	switch (spring->type)
 	{
 		case MT_FAN: // fan
@@ -2423,6 +2431,8 @@ isblocking:
 //
 // P_IsClimbingValid
 //
+// Unlike P_DoClimbing, don't use when up against a one-sided linedef.
+//
 static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 {
 	fixed_t platx, platy;
@@ -2647,6 +2657,7 @@ isblocking:
 		// see about climbing on the wall
 		if (!(checkline->flags & ML_NOCLIMB))
 		{
+			boolean canclimb; // FUCK C90
 			angle_t climbangle, climbline;
 			INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
 
@@ -2657,9 +2668,11 @@ isblocking:
 
 			climbangle += (ANGLE_90 * (whichside ? -1 : 1));
 
+			canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
+
 			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))
+			&& canclimb)
 			{
 				slidemo->angle = climbangle;
 				if (!demoplayback || P_AnalogMove(slidemo->player))
@@ -3365,7 +3378,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 		for (i = 0; i < sector->numattached; i++)
 		{
 			sec = &sectors[sector->attached[i]];
-			for (n = sec->touching_thinglist; n; n = n->m_snext)
+			for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				n->visited = false;
 
 			sec->moved = true;
@@ -3377,7 +3390,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 
 			do
 			{
-				for (n = sec->touching_thinglist; n; n = n->m_snext)
+				for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				if (!n->visited)
 				{
 					n->visited = true;
@@ -3398,12 +3411,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 	// Mark all things invalid
 	sector->moved = true;
 
-	for (n = sector->touching_thinglist; n; n = n->m_snext)
+	for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
 		n->visited = false;
 
 	do
 	{
-		for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+		for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
 			if (!n->visited) // unprocessed thing found
 			{
 				n->visited = true; // mark thing as processed
@@ -3427,7 +3440,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 		for (i = 0; i < sector->numattached; i++)
 		{
 			sec = &sectors[sector->attached[i]];
-			for (n = sec->touching_thinglist; n; n = n->m_snext)
+			for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				n->visited = false;
 
 			sec->moved = true;
@@ -3439,7 +3452,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 
 			do
 			{
-				for (n = sec->touching_thinglist; n; n = n->m_snext)
+				for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				if (!n->visited)
 				{
 					n->visited = true;
@@ -3457,12 +3470,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 	// Mark all things invalid
 	sector->moved = true;
 
-	for (n = sector->touching_thinglist; n; n = n->m_snext)
+	for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
 		n->visited = false;
 
 	do
 	{
-		for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+		for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
 			if (!n->visited) // unprocessed thing found
 			{
 				n->visited = true; // mark thing as processed
@@ -3502,7 +3515,7 @@ static msecnode_t *P_GetSecnode(void)
 	if (headsecnode)
 	{
 		node = headsecnode;
-		headsecnode = headsecnode->m_snext;
+		headsecnode = headsecnode->m_thinglist_next;
 	}
 	else
 		node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3516,7 +3529,7 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
 	if (headprecipsecnode)
 	{
 		node = headprecipsecnode;
-		headprecipsecnode = headprecipsecnode->m_snext;
+		headprecipsecnode = headprecipsecnode->m_thinglist_next;
 	}
 	else
 		node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3527,14 +3540,14 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
 
 static inline void P_PutSecnode(msecnode_t *node)
 {
-	node->m_snext = headsecnode;
+	node->m_thinglist_next = headsecnode;
 	headsecnode = node;
 }
 
 // Tails 08-25-2002
 static inline void P_PutPrecipSecnode(mprecipsecnode_t *node)
 {
-	node->m_snext = headprecipsecnode;
+	node->m_thinglist_next = headprecipsecnode;
 	headprecipsecnode = node;
 }
 
@@ -3555,7 +3568,7 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
 			node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
 			return nextnode;
 		}
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	// Couldn't find an existing node for this sector. Add one at the head
@@ -3568,17 +3581,17 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
 
 	node->m_sector = s; // sector
 	node->m_thing = thing; // mobj
-	node->m_tprev = NULL; // prev node on Thing thread
-	node->m_tnext = nextnode; // next node on Thing thread
+	node->m_sectorlist_prev = NULL; // prev node on Thing thread
+	node->m_sectorlist_next = nextnode; // next node on Thing thread
 	if (nextnode)
-		nextnode->m_tprev = node; // set back link on Thing
+		nextnode->m_sectorlist_prev = node; // set back link on Thing
 
 	// Add new node at head of sector thread starting at s->touching_thinglist
 
-	node->m_sprev = NULL; // prev node on sector thread
-	node->m_snext = s->touching_thinglist; // next node on sector thread
+	node->m_thinglist_prev = NULL; // prev node on sector thread
+	node->m_thinglist_next = s->touching_thinglist; // next node on sector thread
 	if (s->touching_thinglist)
-		node->m_snext->m_sprev = node;
+		node->m_thinglist_next->m_thinglist_prev = node;
 	s->touching_thinglist = node;
 	return node;
 }
@@ -3596,7 +3609,7 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
 			node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
 			return nextnode;
 		}
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	// Couldn't find an existing node for this sector. Add one at the head
@@ -3609,17 +3622,17 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
 
 	node->m_sector = s; // sector
 	node->m_thing = thing; // mobj
-	node->m_tprev = NULL; // prev node on Thing thread
-	node->m_tnext = nextnode; // next node on Thing thread
+	node->m_sectorlist_prev = NULL; // prev node on Thing thread
+	node->m_sectorlist_next = nextnode; // next node on Thing thread
 	if (nextnode)
-		nextnode->m_tprev = node; // set back link on Thing
+		nextnode->m_sectorlist_prev = node; // set back link on Thing
 
 	// Add new node at head of sector thread starting at s->touching_thinglist
 
-	node->m_sprev = NULL; // prev node on sector thread
-	node->m_snext = s->touching_preciplist; // next node on sector thread
+	node->m_thinglist_prev = NULL; // prev node on sector thread
+	node->m_thinglist_next = s->touching_preciplist; // next node on sector thread
 	if (s->touching_preciplist)
-		node->m_snext->m_sprev = node;
+		node->m_thinglist_next->m_thinglist_prev = node;
 	s->touching_preciplist = node;
 	return node;
 }
@@ -3641,24 +3654,24 @@ static msecnode_t *P_DelSecnode(msecnode_t *node)
 	// Unlink from the Thing thread. The Thing thread begins at
 	// sector_list and not from mobj_t->touching_sectorlist.
 
-	tp = node->m_tprev;
-	tn = node->m_tnext;
+	tp = node->m_sectorlist_prev;
+	tn = node->m_sectorlist_next;
 	if (tp)
-		tp->m_tnext = tn;
+		tp->m_sectorlist_next = tn;
 	if (tn)
-		tn->m_tprev = tp;
+		tn->m_sectorlist_prev = tp;
 
 	// Unlink from the sector thread. This thread begins at
 	// sector_t->touching_thinglist.
 
-	sp = node->m_sprev;
-	sn = node->m_snext;
+	sp = node->m_thinglist_prev;
+	sn = node->m_thinglist_next;
 	if (sp)
-		sp->m_snext = sn;
+		sp->m_thinglist_next = sn;
 	else
 		node->m_sector->touching_thinglist = sn;
 	if (sn)
-		sn->m_sprev = sp;
+		sn->m_thinglist_prev = sp;
 
 	// Return this node to the freelist
 
@@ -3680,24 +3693,24 @@ static mprecipsecnode_t *P_DelPrecipSecnode(mprecipsecnode_t *node)
 	// Unlink from the Thing thread. The Thing thread begins at
 	// sector_list and not from mobj_t->touching_sectorlist.
 
-	tp = node->m_tprev;
-	tn = node->m_tnext;
+	tp = node->m_sectorlist_prev;
+	tn = node->m_sectorlist_next;
 	if (tp)
-		tp->m_tnext = tn;
+		tp->m_sectorlist_next = tn;
 	if (tn)
-		tn->m_tprev = tp;
+		tn->m_sectorlist_prev = tp;
 
 	// Unlink from the sector thread. This thread begins at
 	// sector_t->touching_thinglist.
 
-	sp = node->m_sprev;
-	sn = node->m_snext;
+	sp = node->m_thinglist_prev;
+	sn = node->m_thinglist_next;
 	if (sp)
-		sp->m_snext = sn;
+		sp->m_thinglist_next = sn;
 	else
 		node->m_sector->touching_preciplist = sn;
 	if (sn)
-		sn->m_sprev = sp;
+		sn->m_thinglist_prev = sp;
 
 	// Return this node to the freelist
 
@@ -3812,7 +3825,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 	while (node)
 	{
 		node->m_thing = NULL;
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	P_SetTarget(&tmthing, thing);
@@ -3850,11 +3863,11 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 		if (!node->m_thing)
 		{
 			if (node == sector_list)
-				sector_list = node->m_tnext;
+				sector_list = node->m_sectorlist_next;
 			node = P_DelSecnode(node);
 		}
 		else
-			node = node->m_tnext;
+			node = node->m_sectorlist_next;
 	}
 
 	/* cph -
@@ -3895,7 +3908,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 	while (node)
 	{
 		node->m_thing = NULL;
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	tmprecipthing = thing;
@@ -3929,11 +3942,11 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 		if (!node->m_thing)
 		{
 			if (node == precipsector_list)
-				precipsector_list = node->m_tnext;
+				precipsector_list = node->m_sectorlist_next;
 			node = P_DelPrecipSecnode(node);
 		}
 		else
-			node = node->m_tnext;
+			node = node->m_sectorlist_next;
 	}
 
 	/* cph -
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4122619d1d06929db0ce5810d283aba12a3adaf4..62dee0a6730393589c69a0722a1841079438f399 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1252,13 +1252,12 @@ static void P_PlayerFlip(mobj_t *mo)
 }
 
 //
-// P_CheckGravity
+// P_GetMobjGravity
 //
-// Checks the current gravity state
-// of the object. If affect is true,
-// a gravity force will be applied.
+// Returns the current gravity
+// value of the object.
 //
-void P_CheckGravity(mobj_t *mo, boolean affect)
+fixed_t P_GetMobjGravity(mobj_t *mo)
 {
 	fixed_t gravityadd = 0;
 	boolean no3dfloorgrav = true; // Custom gravity
@@ -1317,9 +1316,6 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 	if (mo->eflags & MFE_UNDERWATER && !goopgravity)
 		gravityadd = gravityadd/3;
 
-	if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
-		gravityadd <<= 1;
-
 	if (mo->player)
 	{
 		if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
@@ -1400,12 +1396,31 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 	if (goopgravity)
 		gravityadd = -gravityadd/5;
 
-	if (affect)
-		mo->momz += FixedMul(gravityadd, mo->scale);
-
 	if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
 		P_PlayerFlip(mo);
 
+	gravityadd = FixedMul(gravityadd, mo->scale);
+
+	return gravityadd;
+}
+
+//
+// P_CheckGravity
+//
+// Checks the current gravity state
+// of the object. If affect is true,
+// a gravity force will be applied.
+//
+void P_CheckGravity(mobj_t *mo, boolean affect)
+{
+	fixed_t gravityadd = P_GetMobjGravity(mo);
+
+	if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
+		gravityadd <<= 1;
+
+	if (affect)
+		mo->momz += gravityadd;
+
 	if (mo->type == MT_SKIM && mo->z + mo->momz <= mo->watertop && mo->z >= mo->watertop)
 	{
 		mo->momz = 0;
@@ -1480,7 +1495,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
 		    && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
 		    && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))
 #ifdef ESLOPE
-			&& !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+			&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2))
 #endif
 				)
 		{
@@ -1530,7 +1545,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 	mo->y += mo->momy;
 	P_SetThingPosition(mo);
 
-	for (node = mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -2013,12 +2028,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 		delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2));
 		delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
 		if (topheight > mo->floorz && abs(delta1) < abs(delta2)
-			&& !(rover->flags & FF_REVERSEPLATFORM))
+			&& !(rover->flags & FF_REVERSEPLATFORM)
+			&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
 		{
 			mo->floorz = topheight;
 		}
 		if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-			&& !(rover->flags & FF_PLATFORM))
+			&& !(rover->flags & FF_PLATFORM)
+			&& ((P_MobjFlip(mo)*mo->momz > 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
 		{
 			mo->ceilingz = bottomheight;
 		}
@@ -2152,16 +2169,6 @@ static boolean P_ZMovement(mobj_t *mo)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-#ifdef ESLOPE
-	if (mo->standingslope)
-	{
-		if (mo->flags & MF_NOCLIPHEIGHT)
-			mo->standingslope = NULL;
-		else if (!P_IsObjectOnGround(mo))
-			P_SlopeLaunch(mo);
-	}
-#endif
-
 	// Intercept the stupid 'fall through 3dfloors' bug
 	if (mo->subsector->sector->ffloors)
 		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
@@ -2176,6 +2183,16 @@ static boolean P_ZMovement(mobj_t *mo)
 	}
 	mo->z += mo->momz;
 
+#ifdef ESLOPE
+	if (mo->standingslope)
+	{
+		if (mo->flags & MF_NOCLIPHEIGHT)
+			mo->standingslope = NULL;
+		else if (!P_IsObjectOnGround(mo))
+			P_SlopeLaunch(mo);
+	}
+#endif
+
 	switch (mo->type)
 	{
 		case MT_THROWNBOUNCE:
@@ -2245,6 +2262,7 @@ static boolean P_ZMovement(mobj_t *mo)
 		case MT_BLUETEAMRING:
 		case MT_FLINGRING:
 		case MT_FLINGCOIN:
+		case MT_FLINGEMERALD:
 			// Remove flinged stuff from death pits.
 			if (P_CheckDeathPitCollide(mo))
 			{
@@ -2276,7 +2294,6 @@ static boolean P_ZMovement(mobj_t *mo)
 			if (!(mo->momx || mo->momy || mo->momz))
 				return true;
 			break;
-		case MT_FLINGEMERALD:
 		case MT_NIGHTSWING:
 			if (!(mo->momx || mo->momy || mo->momz))
 				return true;
@@ -2359,13 +2376,10 @@ static boolean P_ZMovement(mobj_t *mo)
 
 #ifdef ESLOPE
 		P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
-		if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
+		if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
+		{
 			mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
-
-			// Reverse quantizing might could use its own function later
-			mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
-			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
-			mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
+			P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif
 
@@ -2518,7 +2532,7 @@ static boolean P_ZMovement(mobj_t *mo)
 			mom.z = tmfloorthing->momz;
 
 #ifdef ESLOPE
-		if (mo->standingslope) {
+		if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
 			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif
@@ -2703,7 +2717,7 @@ static void P_PlayerZMovement(mobj_t *mo)
 					msecnode_t *node;
 					boolean stopmovecut = false;
 
-					for (node = mo->touching_sectorlist; node; node = node->m_snext)
+					for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 					{
 						sector_t *sec = node->m_sector;
 						subsector_t *newsubsec;
@@ -2880,7 +2894,7 @@ nightsdone:
 			if (CheckForMarioBlocks && !(netgame && mo->player->spectator)) // Only let the player punch
 			{
 				// Search the touching sectors, from side-to-side...
-				for (node = mo->touching_sectorlist; node; node = node->m_snext)
+				for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 				{
 					ffloor_t *rover;
 					if (!node->m_sector->ffloors)
@@ -3648,7 +3662,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	if (!(netgame && mobj->player->spectator))
 	{
 		// Crumbling platforms
-		for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+		for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			fixed_t topheight, bottomheight;
 			ffloor_t *rover;
@@ -3673,7 +3687,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	{
 		boolean thereiswater = false;
 
-		for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+		for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			if (node->m_sector->ffloors)
 			{
@@ -3694,7 +3708,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 		}
 		if (thereiswater)
 		{
-			for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+			for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 			{
 				if (node->m_sector->ffloors)
 				{
@@ -3807,7 +3821,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
 
 	sector->moved = true; // Recalc lighting and things too, maybe
 
-	for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_snext)
+	for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
 		CalculatePrecipFloor(psecnode->m_thing);
 }
 
diff --git a/src/p_setup.c b/src/p_setup.c
index b36bf0b809c877ba06f86dba599e5564a71bae8a..e56c44c70616814a2f6f216864f07aaa0e2e8b8f 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1931,10 +1931,18 @@ static void P_GroupLines(void)
 	// allocate linebuffers for each sector
 	for (i = 0, sector = sectors; i < numsectors; i++, sector++)
 	{
-		sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
+		if (sector->linecount == 0) // no lines found?
+		{
+			sector->lines = NULL;
+			CONS_Debug(DBG_SETUP, "P_GroupLines: sector %s has no lines\n", sizeu1(i));
+		}
+		else
+		{
+			sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
 
-		// zero the count, since we'll later use this to track how many we've recorded
-		sector->linecount = 0;
+			// zero the count, since we'll later use this to track how many we've recorded
+			sector->linecount = 0;
+		}
 	}
 
 	// iterate through lines, assigning them to sectors' linebuffers,
@@ -1952,11 +1960,14 @@ static void P_GroupLines(void)
 	{
 		M_ClearBox(bbox);
 
-		for (j = 0; j < sector->linecount; j++)
+		if (sector->linecount != 0)
 		{
-			li = sector->lines[j];
-			M_AddToBox(bbox, li->v1->x, li->v1->y);
-			M_AddToBox(bbox, li->v2->x, li->v2->y);
+			for (j = 0; j < sector->linecount; j++)
+			{
+				li = sector->lines[j];
+				M_AddToBox(bbox, li->v1->x, li->v1->y);
+				M_AddToBox(bbox, li->v2->x, li->v2->y);
+			}
 		}
 
 		// set the degenmobj_t to the middle of the bounding box
@@ -1966,6 +1977,35 @@ static void P_GroupLines(void)
 	}
 }
 
+//
+// P_LoadReject
+//
+// Detect if the REJECT lump is valid,
+// if not, rejectmatrix will be NULL
+static void P_LoadReject(lumpnum_t lumpnum)
+{
+	size_t count;
+	const char *lumpname = W_CheckNameForNum(lumpnum);
+
+	// Check if the lump exists, and if it's named "REJECT"
+	if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n");
+		return;
+	}
+
+	count = W_LumpLength(lumpnum);
+
+	if (!count) // zero length, someone probably used ZDBSP
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n");
+	}
+	else
+		rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+}
+
 #if 0
 static char *levellumps[] =
 {
@@ -2574,7 +2614,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
 	P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
 	P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
-	rejectmatrix = W_CacheLumpNum(lastloadedmaplumpnum + ML_REJECT, PU_LEVEL);
+	P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
 	P_GroupLines();
 
 	numdmstarts = numredctfstarts = numbluectfstarts = 0;
diff --git a/src/p_sight.c b/src/p_sight.c
index 14c1c945fb9ec0a551fcf77a19bbe4764d23ad7f..bd6ab4d730f308973b011af421f147384ecbd648 100644
--- a/src/p_sight.c
+++ b/src/p_sight.c
@@ -325,9 +325,12 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
 	s2 = t2->subsector->sector;
 	pnum = (s1-sectors)*numsectors + (s2-sectors);
 
-	// Check in REJECT table.
-	if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
-		return false;
+	if (rejectmatrix != NULL)
+	{
+		// Check in REJECT table.
+		if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
+			return false;
+	}
 
 	// killough 11/98: shortcut for melee situations
 	// same subsector? obviously visible
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 6393ca4b558514e0616dc0423f60d899e29342c9..d939fee98b9cb36f015da6cb187131acc6407eb6 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -199,7 +199,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
 
 	// Find furthest vertex from the reference line. It, along with the two ends
 	// of the line, will define the plane.
-	// SRB2CBTODO: Use a formula to get the slope to slide objects depending on how steep
 	for(i = 0; i < sector->linecount; i++)
 	{
 		line_t *li = sector->lines[i];
@@ -231,7 +230,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
 //
 // Creates one or more slopes based on the given line type and front/back
 // sectors.
-// Kalaron: Check if dynamic slopes need recalculation
 //
 void P_SpawnSlope_Line(int linenum)
 {
@@ -276,7 +274,6 @@ void P_SpawnSlope_Line(int linenum)
 		ny = -FixedDiv(line->dx, len);
 	}
 
-	// SRB2CBTODO: Transform origin relative to the bounds of an individual FOF
 	origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
 	origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
 
@@ -327,7 +324,7 @@ void P_SpawnSlope_Line(int linenum)
 			// fslope->normal is a 3D line perpendicular to the 3D vector
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			fslope->sourceline = line;
 
 			// To find the real highz/lowz of a slope, you need to check all the vertexes
@@ -379,7 +376,7 @@ void P_SpawnSlope_Line(int linenum)
             cslope->refpos = 2;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			cslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -445,7 +442,7 @@ void P_SpawnSlope_Line(int linenum)
             fslope->refpos = 3;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			fslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -488,7 +485,7 @@ void P_SpawnSlope_Line(int linenum)
             cslope->refpos = 4;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			cslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -554,16 +551,11 @@ static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
 			ret->vertices[2] = mt;
 	}
 
-	if (!ret->vertices[0])
-		CONS_Printf("PANIC 0\n");
-	if (!ret->vertices[1])
-		CONS_Printf("PANIC 1\n");
-	if (!ret->vertices[2])
-		CONS_Printf("PANIC 2\n");
-
 	// Now set heights for each vertex, because they haven't been set yet
 	for (i = 0; i < 3; i++) {
 		mt = ret->vertices[i];
+		if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
+			I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
 		if (mt->extrainfo)
 			mt->z = mt->options;
 		else
@@ -623,265 +615,10 @@ pslope_t *P_SlopeById(UINT16 id)
 	return ret;
 }
 
-#ifdef SPRINGCLEAN
-#include "byteptr.h"
-
-#include "p_setup.h"
-#include "p_local.h"
-
-//==========================================================================
-//
-//	P_SetSlopesFromVertexHeights
-//
-//==========================================================================
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum)
-{
-	mapthing_t *mt;
-	boolean vt_found = false;
-	size_t i, j, k, l, q;
-
-	//size_t i;
-	//mapthing_t *mt;
-	char *data;
-	char *datastart;
-
-	// SRB2CBTODO: WHAT IS (5 * sizeof (short))?! It = 10
-	// anything else seems to make a map not load properly,
-	// but this hard-coded value MUST have some reason for being what it is
-	size_t snummapthings = W_LumpLength(lumpnum) / (5 * sizeof (short));
-	mapthing_t *smapthings = Z_Calloc(snummapthings * sizeof (*smapthings), PU_LEVEL, NULL);
-	fixed_t x, y;
-	sector_t *sector;
-	// Spawn axis points first so they are
-	// at the front of the list for fast searching.
-	data = datastart = W_CacheLumpNum(lumpnum, PU_LEVEL);
-	mt = smapthings;
-	for (i = 0; i < snummapthings; i++, mt++)
-	{
-		mt->x = READINT16(data);
-		mt->y = READINT16(data);
-		mt->angle = READINT16(data);
-		mt->type = READINT16(data);
-		mt->options = READINT16(data);
-		// mt->z hasn't been set yet!
-		//mt->extrainfo = (byte)(mt->type >> 12); // slope things are special, they have a bigger range of types
-
-		//mt->type &= 4095; // SRB2CBTODO: WHAT IS THIS???? Mobj type limits?!!!!
-		x = mt->x*FRACUNIT;
-		y = mt->y*FRACUNIT;
-		sector = R_PointInSubsector(x, y)->sector;
-		// Z for objects
-#ifdef ESLOPE
-		if (sector->f_slope)
-			mt->z = (short)(P_GetZAt(sector->f_slope, x, y)>>FRACBITS);
-		else
-#endif
-			mt->z = (short)(sector->floorheight>>FRACBITS);
-
-		mt->z = mt->z + (mt->options >> ZSHIFT);
-
-		if (mt->type == THING_VertexFloorZ || mt->type == THING_VertexCeilingZ) // THING_VertexFloorZ
-		{
-			for(l = 0; l < numvertexes; l++)
-			{
-				if (vertexes[l].x == mt->x*FRACUNIT && vertexes[l].y == mt->y*FRACUNIT)
-				{
-					if (mt->type == THING_VertexFloorZ)
-					{
-						vertexes[l].z = mt->z*FRACUNIT;
-						//I_Error("Z value: %i", vertexes[l].z/FRACUNIT);
-
-					}
-					else
-					{
-						vertexes[l].z = mt->z*FRACUNIT; // celing floor
-					}
-					vt_found = true;
-				}
-			}
-			//mt->type = 0; // VPHYSICS: Dynamic slopes
-
-
-
-
-
-
-			if (vt_found)
-			{
-				for (k = 0; k < numsectors; k++)
-				{
-					sector_t *sec = &sectors[k];
-					if (sec->linecount != 3) continue;	// only works with triangular sectors
-
-					v3float_t vt1, vt2, vt3; // cross = ret->normalf
-					v3float_t vec1, vec2;
-
-					int vi1, vi2, vi3;
-
-					vi1 = (int)(sec->lines[0]->v1 - vertexes);
-					vi2 = (int)(sec->lines[0]->v2 - vertexes);
-					vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)?
-					(int)(sec->lines[1]->v2 - vertexes) : (int)(sec->lines[1]->v1 - vertexes);
-
-					//if (vertexes[vi1].z)
-					//	I_Error("OSNAP %i", vertexes[vi1].z/FRACUNIT);
-					//if (vertexes[vi2].z)
-					//	I_Error("OSNAP %i", vertexes[vi2].z/FRACUNIT);
-					//if (vertexes[vi3].z)
-					//	I_Error("OSNAP %i", vertexes[vi3].z/FRACUNIT);
-
-					//I_Error("%i, %i", mt->z*FRACUNIT, vertexes[vi1].z);
-
-					//I_Error("%i, %i, %i", mt->x, mt->y, mt->z);
-					//P_SpawnMobj(mt->x*FRACUNIT, mt->y*FRACUNIT, mt->z*FRACUNIT, MT_RING);
-
-					// TODO: Make sure not to spawn in the same place 2x! (we need an object in every vertex of the
-					// triangle sector to setup the real vertex slopes
-					// Check for the vertexes of all sectors
-					for(q = 0; q < numvertexes; q++)
-					{
-						if (vertexes[q].x == mt->x*FRACUNIT && vertexes[q].y == mt->y*FRACUNIT)
-						{
-							//I_Error("yeah %i", vertexes[q].z);
-							P_SpawnMobj(vertexes[q].x, vertexes[q].y, vertexes[q].z, MT_RING);
-#if 0
-					if ((mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
-						P_SpawnMobj(vertexes[vi1].x, vertexes[vi1].y, vertexes[vi1].z, MT_RING);
-					else if ((mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
-						P_SpawnMobj(vertexes[vi2].x, vertexes[vi2].y, vertexes[vi2].z, MT_BOUNCETV);
-					else if ((mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z))
-						P_SpawnMobj(vertexes[vi3].x, vertexes[vi3].y, vertexes[vi3].z, MT_GFZFLOWER1);
-					else
-#endif
-						continue;
-						}
-					}
-
-					vt1.x = FIXED_TO_FLOAT(vertexes[vi1].x);
-					vt1.y = FIXED_TO_FLOAT(vertexes[vi1].y);
-					vt2.x = FIXED_TO_FLOAT(vertexes[vi2].x);
-					vt2.y = FIXED_TO_FLOAT(vertexes[vi2].y);
-					vt3.x = FIXED_TO_FLOAT(vertexes[vi3].x);
-					vt3.y = FIXED_TO_FLOAT(vertexes[vi3].y);
-
-					for(j = 0; j < 2; j++)
-					{
-
-						fixed_t z3;
-						//I_Error("Lo hicimos");
-
-						vt1.z = mt->z;//FIXED_TO_FLOAT(j==0 ? sec->floorheight : sec->ceilingheight);
-						vt2.z = mt->z;//FIXED_TO_FLOAT(j==0? sec->floorheight : sec->ceilingheight);
-						z3 = mt->z;//j==0? sec->floorheight : sec->ceilingheight; // Destination height
-						vt3.z = FIXED_TO_FLOAT(z3);
-
-						if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0)
-						{
-							vec1.x = vt2.x - vt3.x;
-							vec1.y = vt2.y - vt3.y;
-							vec1.z = vt2.z - vt3.z;
-
-							vec2.x = vt1.x - vt3.x;
-							vec2.y = vt1.y - vt3.y;
-							vec2.z = vt1.z - vt3.z;
-						}
-						else
-						{
-							vec1.x = vt1.x - vt3.x;
-							vec1.y = vt1.y - vt3.y;
-							vec1.z = vt1.z - vt3.z;
-
-							vec2.x = vt2.x - vt3.x;
-							vec2.y = vt2.y - vt3.y;
-							vec2.z = vt2.z - vt3.z;
-						}
-
-
-						pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
-						memset(ret, 0, sizeof(*ret));
-
-						{
-							M_CrossProduct3f(&ret->normalf, &vec1, &vec2);
-
-							// Cross product length
-							float len = (float)sqrt(ret->normalf.x * ret->normalf.x +
-													ret->normalf.y * ret->normalf.y +
-													ret->normalf.z * ret->normalf.z);
-
-							if (len == 0)
-							{
-								// Only happens when all vertices in this sector are on the same line.
-								// Let's just ignore this case.
-								//CONS_Printf("Slope thing at (%d,%d) lies directly on its target line.\n", (int)(x>>16), (int)(y>>16));
-								return;
-							}
-							// cross/len
-							ret->normalf.x /= len;
-							ret->normalf.y /= len;
-							ret->normalf.z /= len;
-
-							// ZDoom cross = ret->normalf
-							// Fix backward normals
-							if ((ret->normalf.z < 0 && j == 0) || (ret->normalf.z > 0 && j == 1))
-							{
-								// cross = -cross
-								ret->normalf.x = -ret->normalf.x;
-								ret->normalf.y = -ret->normalf.x;
-								ret->normalf.z = -ret->normalf.x;
-							}
-						}
-
-						secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL);
-
-						srcplane->a = FLOAT_TO_FIXED (ret->normalf.x);
-						srcplane->b = FLOAT_TO_FIXED (ret->normalf.y);
-						srcplane->c = FLOAT_TO_FIXED (ret->normalf.z);
-						//srcplane->ic = FixedDiv(FRACUNIT, srcplane->c);
-						srcplane->d = -TMulScale16 (srcplane->a, vertexes[vi3].x,
-													srcplane->b, vertexes[vi3].y,
-													srcplane->c, z3);
-
-						if (j == 0)
-						{
-							sec->f_slope = ret;
-							sec->f_slope->secplane = *srcplane;
-						}
-						else if (j == 1)
-						{
-							sec->c_slope = ret;
-							sec->c_slope->secplane = *srcplane;
-						}
-					}
-				}
-			}
-
-
-
-
-
-
-
-
-		}
-	}
-	Z_Free(datastart);
-
-
-
-
-}
-#endif
-
 // Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes
 void P_ResetDynamicSlopes(void) {
 	size_t i;
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
 	boolean warned = false;
 #endif
 
@@ -894,7 +631,7 @@ void P_ResetDynamicSlopes(void) {
 	{
 		switch (lines[i].special)
 		{
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
 #define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
 			case 386:
 			case 387:
@@ -1018,7 +755,11 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y)
 // When given a vector, rotates it and aligns it to a slope
 void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
 {
-	vector3_t axis;
+	vector3_t axis; // Fuck you, C90.
+
+	if (slope->flags & SL_NOPHYSICS)
+		return; // No physics, no quantizing.
+
 	axis.x = -slope->d.y;
 	axis.y = slope->d.x;
 	axis.z = 0;
@@ -1026,24 +767,38 @@ void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
 	FV3_Rotate(momentum, &axis, slope->zangle >> ANGLETOFINESHIFT);
 }
 
+//
+// P_ReverseQuantizeMomentumToSlope
+//
+// When given a vector, rotates and aligns it to a flat surface (from being relative to a given slope)
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
+{
+	slope->zangle = InvAngle(slope->zangle);
+	P_QuantizeMomentumToSlope(momentum, slope);
+	slope->zangle = InvAngle(slope->zangle);
+}
+
 //
 // P_SlopeLaunch
 //
 // Handles slope ejection for objects
 void P_SlopeLaunch(mobj_t *mo)
 {
-	// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
-	// vertical launch given from slopes while increasing the horizontal launch
-	// given. Good for SRB2's gravity and horizontal speeds.
-	vector3_t slopemom;
-	slopemom.x = mo->momx;
-	slopemom.y = mo->momy;
-	slopemom.z = mo->momz*2;
-	P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
-
-	mo->momx = slopemom.x;
-	mo->momy = slopemom.y;
-	mo->momz = slopemom.z/2;
+	if (!(mo->standingslope->flags & SL_NOPHYSICS)) // If there's physics, time for launching.
+	{
+		// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
+		// vertical launch given from slopes while increasing the horizontal launch
+		// given. Good for SRB2's gravity and horizontal speeds.
+		vector3_t slopemom;
+		slopemom.x = mo->momx;
+		slopemom.y = mo->momy;
+		slopemom.z = mo->momz*2;
+		P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
+
+		mo->momx = slopemom.x;
+		mo->momy = slopemom.y;
+		mo->momz = slopemom.z/2;
+	}
 
 	//CONS_Printf("Launched off of slope.\n");
 	mo->standingslope = NULL;
@@ -1052,17 +807,21 @@ void P_SlopeLaunch(mobj_t *mo)
 // Function to help handle landing on slopes
 void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
 {
-	vector3_t mom;
+	vector3_t mom; // Ditto.
+
+	if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated.
+		if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope
+			thing->momz = -P_MobjFlip(thing);
+			thing->standingslope = slope;
+		}
+		return;
+	}
+
 	mom.x = thing->momx;
 	mom.y = thing->momy;
 	mom.z = thing->momz*2;
 
-	//CONS_Printf("langing on slope\n");
-
-	// Reverse quantizing might could use its own function later
-	slope->zangle = ANGLE_MAX-slope->zangle;
-	P_QuantizeMomentumToSlope(&mom, slope);
-	slope->zangle = ANGLE_MAX-slope->zangle;
+	P_ReverseQuantizeMomentumToSlope(&mom, slope);
 
 	if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
 		thing->momx = mom.x;
@@ -1082,6 +841,9 @@ void P_ButteredSlope(mobj_t *mo)
 	if (!mo->standingslope)
 		return;
 
+	if (mo->standingslope->flags & SL_NOPHYSICS)
+		return; // No physics, no butter.
+
 	if (mo->flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY))
 		return; // don't slide down slopes if you can't touch them or you're not affected by gravity
 
@@ -1106,8 +868,6 @@ void P_ButteredSlope(mobj_t *mo)
 			mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
 		}
 
-		//CONS_Printf("%d\n", mult);
-
 		thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8);
 	}
 
@@ -1115,10 +875,11 @@ void P_ButteredSlope(mobj_t *mo)
 		thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/16);
 	// This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down
 
-	// Multiply by gravity
-	thrust = FixedMul(thrust, gravity); // TODO account for per-sector gravity etc
-	// Multiply by scale (gravity strength depends on mobj scale)
-	thrust = FixedMul(thrust, mo->scale);
+	// Let's get the gravity strength for the object...
+	thrust = FixedMul(thrust, abs(P_GetMobjGravity(mo)));
+
+	// ... and its friction against the ground for good measure (divided by original friction to keep behaviour for normal slopes the same).
+	thrust = FixedMul(thrust, FixedDiv(mo->friction, ORIG_FRICTION));
 
 	P_Thrust(mo, mo->standingslope->xydirection, thrust);
 }
diff --git a/src/p_slopes.h b/src/p_slopes.h
index 80921a84b49ce9bc38e76f7fdf6186426dc05bd0..de38f1d9ed279be0059a8c0a283a337d8e4e7bb8 100644
--- a/src/p_slopes.h
+++ b/src/p_slopes.h
@@ -21,26 +21,6 @@ void P_RunDynamicSlopes(void);
 // sectors.
 void P_SpawnSlope_Line(int linenum);
 
-#ifdef SPRINGCLEAN
-// Loads just map objects that make slopes,
-// terrain affecting objects have to be spawned first
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum);
-
-typedef enum
-{
-	THING_SlopeFloorPointLine = 9500,
-	THING_SlopeCeilingPointLine = 9501,
-	THING_SetFloorSlope = 9502,
-	THING_SetCeilingSlope = 9503,
-	THING_CopyFloorPlane = 9510,
-	THING_CopyCeilingPlane = 9511,
-	THING_VavoomFloor=1500,
-	THING_VavoomCeiling=1501,
-	THING_VertexFloorZ=1504,
-	THING_VertexCeilingZ=1505,
-} slopething_e;
-#endif
-
 //
 // P_CopySectorSlope
 //
@@ -55,6 +35,7 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y);
 
 // Lots of physics-based bullshit
 void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
 void P_SlopeLaunch(mobj_t *mo);
 void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
 void P_ButteredSlope(mobj_t *mo);
diff --git a/src/p_spec.c b/src/p_spec.c
index fbcb8b4f0eb02417a025cf64384b0d60e5ecf782..0bd530279c720aa36254d0f0a49bb1298e8e05a0 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1642,7 +1642,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 			mo = node->m_thing;
 			if (mo->flags & MF_PUSHABLE)
 				numpush++;
-			node = node->m_snext;
+			node = node->m_thinglist_next;
 		}
 
 		if (triggerline->flags & ML_NOCLIMB) // Need at least or more
@@ -2434,10 +2434,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						if (rover->master->frontsector->tag != line->tag)
 							continue;
 
-						if (mo->z > *rover->topheight)
+						if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
 							continue;
 
-						if (mo->z + mo->height < *rover->bottomheight)
+						if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
 							continue;
 
 						foundit = true;
@@ -3144,7 +3144,7 @@ void P_SetupSignExit(player_t *player)
 	thinker_t *think;
 	INT32 numfound = 0;
 
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (thing->type != MT_SIGN)
@@ -3227,8 +3227,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 				if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
 					continue;
 
-				if (mo->z <= *rover->topheight
-					&& mo->z >= *rover->bottomheight)
+				if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
+					&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
 					return true;
 			}
 		}
@@ -3262,12 +3262,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 	// Hmm.. maybe there's a FOF that has it...
 	for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+		bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
@@ -3275,27 +3280,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != *rover->bottomheight)
+					|| player->mo->z + player->mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and DEATH FOG!!! heh
-			if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+			if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 				continue;
 		}
 
@@ -3303,7 +3308,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 		return rover->master->frontsector;
 	}
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (GETSECSPECIAL(node->m_sector->special, section) == number)
 		{
@@ -3317,12 +3322,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 		// Hmm.. maybe there's a FOF that has it...
 		for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 		{
+			fixed_t topheight, bottomheight;
+
 			if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
 				continue;
 
 			if (!(rover->flags & FF_EXISTS))
 				continue;
 
+			topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+			bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
 			// Check the 3D floor's type...
 			if (rover->flags & FF_BLOCKPLAYER)
 			{
@@ -3330,27 +3340,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 				if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 				{
-					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 						continue;
 				}
 				else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 				{
 					if (!(player->mo->eflags & MFE_VERTICALFLIP)
-						|| player->mo->z + player->mo->height != *rover->bottomheight)
+						|| player->mo->z + player->mo->height != bottomheight)
 						continue;
 				}
 				else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 				{
-					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
-						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 						continue;
 				}
 			}
 			else
 			{
 				// Water and DEATH FOG!!! heh
-				if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+				if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 					continue;
 			}
 
@@ -4335,12 +4345,17 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
 
 	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (!rover->master->frontsector->special)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, sector);
+		bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, sector);
+
 		// Check the 3D floor's type...
 		if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
 			|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
@@ -4349,27 +4364,27 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != *rover->topheight)
+				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(mo->eflags & MFE_VERTICALFLIP)
-					|| mo->z + mo->height != *rover->bottomheight)
+					|| mo->z + mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == *rover->bottomheight)
-					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == *rover->topheight)))
+				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
+					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and intangible FOFs
-			if (mo->z > *rover->topheight || (mo->z + mo->height) < *rover->bottomheight)
+			if (mo->z > topheight || (mo->z + mo->height) < bottomheight)
 				continue;
 		}
 
@@ -4391,12 +4406,17 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 
 	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (!rover->master->frontsector->special)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector);
+		bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector);
+
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
@@ -4404,27 +4424,27 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))
+				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+					|| player->mo->z + player->mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))))
+				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and DEATH FOG!!! heh
-			if (player->mo->z > P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector) || (player->mo->z + player->mo->height) < P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+			if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 				continue;
 		}
 
@@ -4637,7 +4657,7 @@ void P_PlayerInSpecialSector(player_t *player)
 		P_RunSpecialSectorCheck(player, sector);
 
 	// Iterate through touching_sectorlist
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		sector = node->m_sector;
 
@@ -5276,11 +5296,19 @@ void T_LaserFlash(laserthink_t *flash)
 
 	sourcesec = ffloor->master->frontsector; // Less to type!
 
+#ifdef ESLOPE
+	top = (*ffloor->t_slope) ? P_GetZAt(*ffloor->t_slope, sector->soundorg.x, sector->soundorg.y)
+			: *ffloor->topheight;
+	bottom = (*ffloor->b_slope) ? P_GetZAt(*ffloor->b_slope, sector->soundorg.x, sector->soundorg.y)
+			: *ffloor->bottomheight;
+	sector->soundorg.z = (top + bottom)/2;
+#else
 	sector->soundorg.z = (*ffloor->topheight + *ffloor->bottomheight)/2;
+#endif
 	S_StartSound(&sector->soundorg, sfx_laser);
 
 	// Seek out objects to DESTROY! MUAHAHHAHAHAA!!!*cough*
-	for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_snext)
+	for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 
@@ -6551,7 +6579,7 @@ void T_Scroll(scroll_t *s)
 					sector_t *psec;
 					psec = sectors + sect;
 
-					for (node = psec->touching_thinglist; node; node = node->m_snext)
+					for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
 					{
 						thing = node->m_thing;
 
@@ -6573,7 +6601,7 @@ void T_Scroll(scroll_t *s)
 
 			if (!is3dblock)
 			{
-				for (node = sec->touching_thinglist; node; node = node->m_snext)
+				for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
 				{
 					thing = node->m_thing;
 
@@ -6614,7 +6642,7 @@ void T_Scroll(scroll_t *s)
 					sector_t *psec;
 					psec = sectors + sect;
 
-					for (node = psec->touching_thinglist; node; node = node->m_snext)
+					for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
 					{
 						thing = node->m_thing;
 
@@ -6636,7 +6664,7 @@ void T_Scroll(scroll_t *s)
 
 			if (!is3dblock)
 			{
-				for (node = sec->touching_thinglist; node; node = node->m_snext)
+				for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
 				{
 					thing = node->m_thing;
 
@@ -6875,6 +6903,11 @@ void T_Disappear(disappear_t *d)
 
 					if (!(lines[d->sourceline].flags & ML_NOCLIMB))
 					{
+#ifdef ESLOPE
+						if (*rover->t_slope)
+							sectors[s].soundorg.z = P_GetZAt(*rover->t_slope, sectors[s].soundorg.x, sectors[s].soundorg.y);
+						else
+#endif
 						sectors[s].soundorg.z = *rover->topheight;
 						S_StartSound(&sectors[s].soundorg, sfx_appear);
 					}
@@ -6981,7 +7014,7 @@ void T_Friction(friction_t *f)
 			{
 				if (thing->floorz != P_GetSpecialTopZ(thing, referrer, sec))
 				{
-					node = node->m_snext;
+					node = node->m_thinglist_next;
 					continue;
 				}
 
@@ -6999,7 +7032,7 @@ void T_Friction(friction_t *f)
 				thing->movefactor = f->movefactor;
 			}
 		}
-		node = node->m_snext;
+		node = node->m_thinglist_next;
 	}
 }
 
@@ -7339,7 +7372,7 @@ void T_Pusher(pusher_t *p)
 
 	// constant pushers p_wind and p_current
 	node = sec->touching_thinglist; // things touching this sector
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)
diff --git a/src/p_user.c b/src/p_user.c
index 0ee5a36b463b645f63c610b5293377f951d79370..9cd6aa401946d7f4700dfc75e24c510d53f5565f 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1684,7 +1684,7 @@ static void P_CheckBustableBlocks(player_t *player)
 	player->mo->y += player->mo->momy;
 	P_SetThingPosition(player->mo);
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -1801,7 +1801,7 @@ static void P_CheckBouncySectors(player_t *player)
 	player->mo->z += player->mo->momz;
 	P_SetThingPosition(player->mo);
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -1851,12 +1851,8 @@ static void P_CheckBouncySectors(player_t *player)
 						momentum.y = player->mo->momy;
 						momentum.z = player->mo->momz*2;
 
-						if (slope) {
-							// Reverse quantizing might could use its own function later
-							slope->zangle = ANGLE_MAX-slope->zangle;
-							P_QuantizeMomentumToSlope(&momentum, slope);
-							slope->zangle = ANGLE_MAX-slope->zangle;
-						}
+						if (slope)
+							P_ReverseQuantizeMomentumToSlope(&momentum, slope);
 
 						newmom = momentum.z = -FixedMul(momentum.z,linedist)/2;
 #else
@@ -2284,9 +2280,9 @@ static void P_DoClimbing(player_t *player)
 	platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 	platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 
-	glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy);
+	glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
 
-	if (glidesector->sector != player->mo->subsector->sector)
+	if (!glidesector || glidesector->sector != player->mo->subsector->sector)
 	{
 		boolean floorclimb;
 		boolean thrust;
@@ -2298,298 +2294,303 @@ static void P_DoClimbing(player_t *player)
 		boostup = false;
 		skyclimber = false;
 
+		if (glidesector)
+		{
 #ifdef ESLOPE
-		floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
-		                                           : glidesector->sector->floorheight;
-		ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
-		                                             : glidesector->sector->ceilingheight;
+			floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
+													   : glidesector->sector->floorheight;
+			ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
+														 : glidesector->sector->ceilingheight;
 #else
-		floorheight = glidesector->sector->floorheight;
-		ceilingheight = glidesector->sector->ceilingheight;
+			floorheight = glidesector->sector->floorheight;
+			ceilingheight = glidesector->sector->ceilingheight;
 #endif
 
-		if (glidesector->sector->ffloors)
-		{
-			ffloor_t *rover;
-			fixed_t topheight, bottomheight; // ESLOPE
-
-			for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+			if (glidesector->sector->ffloors)
 			{
-				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-					continue;
+				ffloor_t *rover;
+				fixed_t topheight, bottomheight; // ESLOPE
 
-				floorclimb = true;
+				for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+				{
+					if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+						continue;
+
+					floorclimb = true;
 
 #ifdef ESLOPE
-				bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
-				topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
+					bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+					topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
 #else
-				bottomheight = *rover->bottomheight;
-				topheight = *rover->topheight;
+					bottomheight = *rover->bottomheight;
+					topheight = *rover->topheight;
 #endif
 
-				// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
-				if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
-				{
-					if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
-						&& (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
-					|| ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
-						&& (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
+					// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
+					if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
 					{
-						if (cmd->forwardmove != 0)
-							player->mo->momz += rover->master->frontsector->floorspeed;
-						else
+						if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
+							&& (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
+						|| ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
+							&& (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
 						{
-							player->mo->momz = rover->master->frontsector->floorspeed;
-							climb = false;
+							if (cmd->forwardmove != 0)
+								player->mo->momz += rover->master->frontsector->floorspeed;
+							else
+							{
+								player->mo->momz = rover->master->frontsector->floorspeed;
+								climb = false;
+							}
 						}
 					}
-				}
 
-				// Gravity is flipped, so the comments are, too.
-				if (player->mo->eflags & MFE_VERTICALFLIP)
-				{
-					// Trying to climb down past the bottom of the FOF
-					if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
+					// Gravity is flipped, so the comments are, too.
+					if (player->mo->eflags & MFE_VERTICALFLIP)
 					{
-						fixed_t bottomheight2;
-						ffloor_t *roverbelow;
-						boolean foundfof = false;
-						floorclimb = true;
-						boostup = false;
-
-						// Is there a FOF directly below this one that we can move onto?
-						for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+						// Trying to climb down past the bottom of the FOF
+						if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
 						{
-							if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
-								continue;
+							fixed_t bottomheight2;
+							ffloor_t *roverbelow;
+							boolean foundfof = false;
+							floorclimb = true;
+							boostup = false;
+
+							// Is there a FOF directly below this one that we can move onto?
+							for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+							{
+								if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+									continue;
 
-							if (roverbelow == rover)
-								continue;
+								if (roverbelow == rover)
+									continue;
 
 #ifdef ESLOPE
-							bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
+								bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
 #else
-							bottomheight2 = *roverbelow->bottomheight;
+								bottomheight2 = *roverbelow->bottomheight;
 #endif
 
-							if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
-								foundfof = true;
-						}
+								if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
+									foundfof = true;
+							}
 
-						if (!foundfof)
-							player->mo->momz = 0;
-					}
+							if (!foundfof)
+								player->mo->momz = 0;
+						}
 
-					// Below the FOF
-					if (topheight <= player->mo->z)
-					{
-						floorclimb = false;
-						boostup = false;
-						thrust = false;
-					}
+						// Below the FOF
+						if (topheight <= player->mo->z)
+						{
+							floorclimb = false;
+							boostup = false;
+							thrust = false;
+						}
 
-					// Above the FOF
-					if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
-					{
-						floorclimb = false;
-						thrust = true;
-						boostup = true;
+						// Above the FOF
+						if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
+						{
+							floorclimb = false;
+							thrust = true;
+							boostup = true;
+						}
 					}
-				}
-				else
-				{
-					// Trying to climb down past the bottom of a FOF
-					if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
+					else
 					{
-						fixed_t topheight2;
-						ffloor_t *roverbelow;
-						boolean foundfof = false;
-						floorclimb = true;
-						boostup = false;
-
-						// Is there a FOF directly below this one that we can move onto?
-						for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+						// Trying to climb down past the bottom of a FOF
+						if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
 						{
-							if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
-								continue;
+							fixed_t topheight2;
+							ffloor_t *roverbelow;
+							boolean foundfof = false;
+							floorclimb = true;
+							boostup = false;
+
+							// Is there a FOF directly below this one that we can move onto?
+							for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+							{
+								if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+									continue;
 
-							if (roverbelow == rover)
-								continue;
+								if (roverbelow == rover)
+									continue;
 
 #ifdef ESLOPE
-							topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
+								topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
 #else
-							topheight2 = *roverbelow->topheight;
+								topheight2 = *roverbelow->topheight;
 #endif
 
-							if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
-								foundfof = true;
+								if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
+									foundfof = true;
+							}
+
+							if (!foundfof)
+								player->mo->momz = 0;
 						}
 
-						if (!foundfof)
-							player->mo->momz = 0;
-					}
+						// Below the FOF
+						if (bottomheight >= player->mo->z + player->mo->height)
+						{
+							floorclimb = false;
+							boostup = false;
+							thrust = false;
+						}
 
-					// Below the FOF
-					if (bottomheight >= player->mo->z + player->mo->height)
-					{
-						floorclimb = false;
-						boostup = false;
-						thrust = false;
+						// Above the FOF
+						if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+						{
+							floorclimb = false;
+							thrust = true;
+							boostup = true;
+						}
 					}
 
-					// Above the FOF
-					if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+					if (floorclimb)
 					{
-						floorclimb = false;
-						thrust = true;
-						boostup = true;
+						if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
+							EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
+						break;
 					}
 				}
-
-				if (floorclimb)
-				{
-					if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
-						EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
-					break;
-				}
 			}
-		}
 
-		// Gravity is flipped, so are comments.
-		if (player->mo->eflags & MFE_VERTICALFLIP)
-		{
-			// Trying to climb down past the upper texture area
-			if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
+			// Gravity is flipped, so are comments.
+			if (player->mo->eflags & MFE_VERTICALFLIP)
 			{
-				boolean foundfof = false;
-				floorclimb = true;
-
-				// Is there a FOF directly below that we can move onto?
-				if (glidesector->sector->ffloors)
+				// Trying to climb down past the upper texture area
+				if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
 				{
-					fixed_t bottomheight;
-					ffloor_t *rover;
-					for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+					boolean foundfof = false;
+					floorclimb = true;
+
+					// Is there a FOF directly below that we can move onto?
+					if (glidesector->sector->ffloors)
 					{
-						if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-							continue;
+						fixed_t bottomheight;
+						ffloor_t *rover;
+						for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+						{
+							if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+								continue;
 
 #ifdef ESLOPE
-						bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+							bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
 #else
-						bottomheight = *rover->bottomheight;
+							bottomheight = *rover->bottomheight;
 #endif
 
-						if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
-						{
-							foundfof = true;
-							break;
+							if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
+							{
+								foundfof = true;
+								break;
+							}
 						}
 					}
-				}
 
-				if (!foundfof)
-					player->mo->momz = 0;
-			}
+					if (!foundfof)
+						player->mo->momz = 0;
+				}
 
-			// Reached the top of the lower texture area
-			if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
-			{
-				thrust = true;
-				boostup = true;
-				// Play climb-up animation here
+				// Reached the top of the lower texture area
+				if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
+					&& (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
+				{
+					thrust = true;
+					boostup = true;
+					// Play climb-up animation here
+				}
 			}
-		}
-		else
-		{
-			// Trying to climb down past the upper texture area
-			if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
+			else
 			{
-				boolean foundfof = false;
-				floorclimb = true;
-
-				// Is there a FOF directly below that we can move onto?
-				if (glidesector->sector->ffloors)
+				// Trying to climb down past the upper texture area
+				if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
 				{
-					ffloor_t *rover;
-					for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
-					{
-						if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-							continue;
+					boolean foundfof = false;
+					floorclimb = true;
 
-						if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+					// Is there a FOF directly below that we can move onto?
+					if (glidesector->sector->ffloors)
+					{
+						ffloor_t *rover;
+						for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
 						{
-							foundfof = true;
-							break;
+							if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+								continue;
+
+							if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+							{
+								foundfof = true;
+								break;
+							}
 						}
 					}
+
+					if (!foundfof)
+						player->mo->momz = 0;
 				}
 
-				if (!foundfof)
-					player->mo->momz = 0;
-			}
+				// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
+				if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+				{
+					floorclimb = true;
+					thrust = false;
+					boostup = false;
+				}
 
-			// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
-			if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
-			{
-				floorclimb = true;
-				thrust = false;
-				boostup = false;
+				// Reached the top of the lower texture area
+				if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
+					&& (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+				{
+					thrust = true;
+					boostup = true;
+					// Play climb-up animation here
+				}
 			}
 
-			// Reached the top of the lower texture area
-			if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+			// Trying to climb on the sky
+			if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
 			{
-				thrust = true;
-				boostup = true;
-				// Play climb-up animation here
+				skyclimber = true;
 			}
-		}
-
-		// Trying to climb on the sky
-		if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
-		{
-			skyclimber = true;
-		}
-
-		// Climbing on the lower texture area?
-		if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
-		{
-			floorclimb = true;
 
-			if (glidesector->sector->floorspeed)
+			// Climbing on the lower texture area?
+			if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
+				|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
 			{
-				if (cmd->forwardmove != 0)
-					player->mo->momz += glidesector->sector->floorspeed;
-				else
+				floorclimb = true;
+
+				if (glidesector->sector->floorspeed)
 				{
-					player->mo->momz = glidesector->sector->floorspeed;
-					climb = false;
+					if (cmd->forwardmove != 0)
+						player->mo->momz += glidesector->sector->floorspeed;
+					else
+					{
+						player->mo->momz = glidesector->sector->floorspeed;
+						climb = false;
+					}
 				}
 			}
-		}
-		// Climbing on the upper texture area?
-		else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
-		{
-			floorclimb = true;
-
-			if (glidesector->sector->ceilspeed)
+			// Climbing on the upper texture area?
+			else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
+				|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
 			{
-				if (cmd->forwardmove != 0)
-					player->mo->momz += glidesector->sector->ceilspeed;
-				else
+				floorclimb = true;
+
+				if (glidesector->sector->ceilspeed)
 				{
-					player->mo->momz = glidesector->sector->ceilspeed;
-					climb = false;
+					if (cmd->forwardmove != 0)
+						player->mo->momz += glidesector->sector->ceilspeed;
+					else
+					{
+						player->mo->momz = glidesector->sector->ceilspeed;
+						climb = false;
+					}
 				}
 			}
 		}
+		else
+			floorclimb = true;
 
 		if (player->lastsidehit != -1 && player->lastlinehit != -1)
 		{
@@ -2849,94 +2850,20 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
 //
 static void P_DoTeeter(player_t *player)
 {
-	msecnode_t *node;
 	boolean teeter = false;
 	boolean roverfloor; // solid 3d floors?
-	boolean checkedforteeter = false;
+	fixed_t floorheight, ceilingheight;
+	fixed_t topheight, bottomheight; // for 3d floor usage
 	const fixed_t tiptop = FixedMul(MAXSTEPMOVE, player->mo->scale); // Distance you have to be above the ground in order to teeter.
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	if (player->mo->standingslope && player->mo->standingslope->zdelta >= (FRACUNIT/2)) // Always teeter if the slope is too steep.
+		teeter = true;
+	else // Let's do some checks...
 	{
-		// Ledge teetering. Check if any nearby sectors are low enough from your current one.
-		checkedforteeter = true;
-		roverfloor = false;
-		if (node->m_sector->ffloors)
-		{
-			ffloor_t *rover;
-			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
-			{
-				if (!(rover->flags & FF_EXISTS)) continue;
-
-				if (P_CheckSolidLava(player->mo, rover))
-					;
-				else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
-					continue; // intangible 3d floor
-
-				if (player->mo->eflags & MFE_VERTICALFLIP)
-				{
-					if (*rover->bottomheight > node->m_sector->ceilingheight) // Above the ceiling
-						continue;
-
-					if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
-						|| (*rover->topheight < player->mo->z
-						&& player->mo->z + player->mo->height < node->m_sector->ceilingheight - tiptop))
-					{
-						teeter = true;
-						roverfloor = true;
-					}
-					else
-					{
-						teeter = false;
-						roverfloor = true;
-						break;
-					}
-				}
-				else
-				{
-					if (*rover->topheight < node->m_sector->floorheight) // Below the floor
-						continue;
-
-					if (*rover->topheight < player->mo->z - tiptop
-						|| (*rover->bottomheight > player->mo->z + player->mo->height
-						&& player->mo->z > node->m_sector->floorheight + tiptop))
-					{
-						teeter = true;
-						roverfloor = true;
-					}
-					else
-					{
-						teeter = false;
-						roverfloor = true;
-						break;
-					}
-				}
-			}
-		}
-
-		if (!teeter && !roverfloor)
-		{
-			if (player->mo->eflags & MFE_VERTICALFLIP)
-			{
-				if (node->m_sector->ceilingheight > player->mo->z + player->mo->height + tiptop)
-					teeter = true;
-			}
-			else
-			{
-				if (node->m_sector->floorheight < player->mo->z - tiptop)
-					teeter = true;
-			}
-		}
-	}
-
-	if (checkedforteeter && !teeter) // Backup code
-	{
-		subsector_t *subsec[4]; // changed abcd into array instead
 		UINT8 i;
-
-		subsec[0] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[1] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[2] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[3] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
+		sector_t *sec;
+		fixed_t highestceilingheight = INT32_MIN;
+		fixed_t lowestfloorheight = INT32_MAX;
 
 		teeter = false;
 		roverfloor = false;
@@ -2944,13 +2871,43 @@ static void P_DoTeeter(player_t *player)
 		{
 			ffloor_t *rover;
 
-			if (!(subsec[i]->sector->ffloors))
+#define xsign ((i & 1) ? -1 : 1) // 0 -> 1 | 1 -> -1 | 2 -> 1 | 3 -> -1
+#define ysign ((i & 2) ? 1 : -1) // 0 -> 1 | 1 -> 1 | 2 -> -1 | 3 -> -1
+			fixed_t checkx = player->mo->x + (xsign*FixedMul(5*FRACUNIT, player->mo->scale));
+			fixed_t checky = player->mo->y + (ysign*FixedMul(5*FRACUNIT, player->mo->scale));
+#undef xsign
+#undef ysign
+
+			sec = R_PointInSubsector(checkx, checky)->sector;
+
+			ceilingheight = sec->ceilingheight;
+			floorheight = sec->floorheight;
+#ifdef ESLOPE
+			if (sec->c_slope)
+				ceilingheight = P_GetZAt(sec->c_slope, checkx, checky);
+			if (sec->f_slope)
+				floorheight = P_GetZAt(sec->f_slope, checkx, checky);
+#endif
+			highestceilingheight = (ceilingheight > highestceilingheight) ? ceilingheight : highestceilingheight;
+			lowestfloorheight = (floorheight < lowestfloorheight) ? floorheight : lowestfloorheight;
+
+			if (!(sec->ffloors))
 				continue; // move on to the next subsector
 
-			for (rover = subsec[i]->sector->ffloors; rover; rover = rover->next)
+			for (rover = sec->ffloors; rover; rover = rover->next)
 			{
 				if (!(rover->flags & FF_EXISTS)) continue;
 
+				topheight = *rover->topheight;
+				bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+				if (*rover->t_slope)
+					topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y);
+				if (*rover->b_slope)
+					bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y);
+#endif
+
 				if (P_CheckSolidLava(player->mo, rover))
 					;
 				else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
@@ -2958,12 +2915,12 @@ static void P_DoTeeter(player_t *player)
 
 				if (player->mo->eflags & MFE_VERTICALFLIP)
 				{
-					if (*rover->bottomheight > subsec[i]->sector->ceilingheight) // Above the ceiling
+					if (bottomheight > ceilingheight) // Above the ceiling
 						continue;
 
-					if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
-						|| (*rover->topheight < player->mo->z
-						&& player->mo->z + player->mo->height < subsec[i]->sector->ceilingheight - tiptop))
+					if (bottomheight > player->mo->z + player->mo->height + tiptop
+						|| (topheight < player->mo->z
+						&& player->mo->z + player->mo->height < ceilingheight - tiptop))
 					{
 						teeter = true;
 						roverfloor = true;
@@ -2977,12 +2934,12 @@ static void P_DoTeeter(player_t *player)
 				}
 				else
 				{
-					if (*rover->topheight < subsec[i]->sector->floorheight) // Below the floor
+					if (topheight < floorheight) // Below the floor
 						continue;
 
-					if (*rover->topheight < player->mo->z - tiptop
-						|| (*rover->bottomheight > player->mo->z + player->mo->height
-						&& player->mo->z > subsec[i]->sector->floorheight + tiptop))
+					if (topheight < player->mo->z - tiptop
+						|| (bottomheight > player->mo->z + player->mo->height
+						&& player->mo->z > floorheight + tiptop))
 					{
 						teeter = true;
 						roverfloor = true;
@@ -3000,18 +2957,12 @@ static void P_DoTeeter(player_t *player)
 
 		if (player->mo->eflags & MFE_VERTICALFLIP)
 		{
-			if (!teeter && !roverfloor && (subsec[0]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[1]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[2]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[3]->sector->ceilingheight > player->mo->ceilingz + tiptop))
+			if (!teeter && !roverfloor && (highestceilingheight > player->mo->ceilingz + tiptop))
 					teeter = true;
 		}
 		else
 		{
-			if (!teeter && !roverfloor && (subsec[0]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[1]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[2]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[3]->sector->floorheight < player->mo->floorz - tiptop))
+			if (!teeter && !roverfloor && (lowestfloorheight < player->mo->floorz - tiptop))
 					teeter = true;
 		}
 	}
@@ -3147,7 +3098,7 @@ teeterdone:
 		if ((player->mo->state == &states[S_PLAY_STND] || player->mo->state == &states[S_PLAY_TAP1] || player->mo->state == &states[S_PLAY_TAP2] || player->mo->state == &states[S_PLAY_SUPERSTAND]))
 			P_SetPlayerMobjState(player->mo, S_PLAY_TEETER1);
 	}
-	else if (checkedforteeter && (player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
+	else if ((player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
 		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
 }
 
@@ -3741,7 +3692,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 	{
 		if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<<FRACBITS, player->mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)
 #ifdef ESLOPE
-			&& (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+			&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
 #endif
 			)
 		{
@@ -3774,7 +3725,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 		else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
 			&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
 #ifdef ESLOPE
-			|| (player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+			|| (player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
 #endif
 			) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
 		{
@@ -3790,7 +3741,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 	if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
 		&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale)
 #ifdef ESLOPE
-			&& (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+			&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
 #endif
 			)
 	{
@@ -4776,7 +4727,7 @@ static void P_3dMovement(player_t *player)
 
 #ifdef ESLOPE
 	if ((totalthrust.x || totalthrust.y)
-		&& player->mo->standingslope && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
+		&& player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
 		// Factor thrust to slope, but only for the part pushing up it!
 		// The rest is unaffected.
 		angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection;
@@ -7037,7 +6988,7 @@ static void P_MovePlayer(player_t *player)
 		player->mo->y += player->mo->momy;
 		P_SetThingPosition(player->mo);
 
-		for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+		for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			if (!node->m_sector)
 				break;
@@ -8123,6 +8074,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 	{
 		fixed_t myfloorz, myceilingz;
 		fixed_t midz = thiscam->z + (thiscam->z - mo->z)/2;
+		fixed_t midx = ((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1);
+		fixed_t midy = ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1);
 
 		// Cameras use the heightsec's heights rather then the actual sector heights.
 		// If you can see through it, why not move the camera through it too?
@@ -8138,8 +8091,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		}
 		else
 		{
-			myfloorz = newsubsec->sector->floorheight;
-			myceilingz = newsubsec->sector->ceilingheight;
+			myfloorz = P_CameraGetFloorZ(thiscam, newsubsec->sector, midx, midy, NULL);
+			myceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, midx, midy, NULL);
 		}
 
 		// Check list of fake floors and see if floorz/ceilingz need to be altered.
@@ -8151,17 +8104,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 
 			for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
 			{
+				fixed_t topheight, bottomheight;
 				if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
 					continue;
 
-				delta1 = midz - (*rover->bottomheight
-					+ ((*rover->topheight - *rover->bottomheight)/2));
-				delta2 = thingtop - (*rover->bottomheight
-					+ ((*rover->topheight - *rover->bottomheight)/2));
-				if (*rover->topheight > myfloorz && abs(delta1) < abs(delta2))
-					myfloorz = *rover->topheight;
-				if (*rover->bottomheight < myceilingz && abs(delta1) >= abs(delta2))
-					myceilingz = *rover->bottomheight;
+				topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+				bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+
+				delta1 = midz - (bottomheight
+					+ ((topheight - bottomheight)/2));
+				delta2 = thingtop - (bottomheight
+					+ ((topheight - bottomheight)/2));
+				if (topheight > myfloorz && abs(delta1) < abs(delta2))
+					myfloorz = topheight;
+				if (bottomheight < myceilingz && abs(delta1) >= abs(delta2))
+					myceilingz = bottomheight;
 			}
 		}
 
@@ -8275,18 +8232,22 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 
 			for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
 			{
+				fixed_t topheight, bottomheight;
 				if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && GETSECSPECIAL(rover->master->frontsector->special, 4) != 12)
 				{
-					if (*rover->bottomheight - thiscam->height < z
-						&& midz < *rover->bottomheight)
-						z = *rover->bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
+					topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+					bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+
+					if (bottomheight - thiscam->height < z
+						&& midz < bottomheight)
+						z = bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
 
-					else if (*rover->topheight + thiscam->height > z
-						&& midz > *rover->topheight)
-						z = *rover->topheight;
+					else if (topheight + thiscam->height > z
+						&& midz > topheight)
+						z = topheight;
 
-					if ((mo->z >= *rover->topheight && midz < *rover->bottomheight)
-						|| ((mo->z < *rover->bottomheight && mo->z+mo->height < *rover->topheight) && midz >= *rover->topheight))
+					if ((mo->z >= topheight && midz < bottomheight)
+						|| ((mo->z < bottomheight && mo->z+mo->height < topheight) && midz >= topheight))
 					{
 						// Can't see
 						if (!resetcalled)
diff --git a/src/r_defs.h b/src/r_defs.h
index 84870816419c757f33eed663d79f088d863b97d1..2c5860ee767f54653a538e82b3d015643c48bad9 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -500,10 +500,10 @@ typedef struct subsector_s
 // Sector list node showing all sectors an object appears in.
 //
 // There are two threads that flow through these nodes. The first thread
-// starts at touching_thinglist in a sector_t and flows through the m_snext
+// starts at touching_thinglist in a sector_t and flows through the m_thinglist_next
 // links to find all mobjs that are entirely or partially in the sector.
 // The second thread starts at touching_sectorlist in an mobj_t and flows
-// through the m_tnext links to find all sectors a thing touches. This is
+// through the m_sectorlist_next links to find all sectors a thing touches. This is
 // useful when applying friction or push effects to sectors. These effects
 // can be done as thinkers that act upon all objects touching their sectors.
 // As an mobj moves through the world, these nodes are created and
@@ -515,10 +515,10 @@ typedef struct msecnode_s
 {
 	sector_t *m_sector; // a sector containing this object
 	struct mobj_s *m_thing;  // this object
-	struct msecnode_s *m_tprev;  // prev msecnode_t for this thing
-	struct msecnode_s *m_tnext;  // next msecnode_t for this thing
-	struct msecnode_s *m_sprev;  // prev msecnode_t for this sector
-	struct msecnode_s *m_snext;  // next msecnode_t for this sector
+	struct msecnode_s *m_sectorlist_prev;  // prev msecnode_t for this thing
+	struct msecnode_s *m_sectorlist_next;  // next msecnode_t for this thing
+	struct msecnode_s *m_thinglist_prev;  // prev msecnode_t for this sector
+	struct msecnode_s *m_thinglist_next;  // next msecnode_t for this sector
 	boolean visited; // used in search algorithms
 } msecnode_t;
 
@@ -526,10 +526,10 @@ typedef struct mprecipsecnode_s
 {
 	sector_t *m_sector; // a sector containing this object
 	struct precipmobj_s *m_thing;  // this object
-	struct mprecipsecnode_s *m_tprev;  // prev msecnode_t for this thing
-	struct mprecipsecnode_s *m_tnext;  // next msecnode_t for this thing
-	struct mprecipsecnode_s *m_sprev;  // prev msecnode_t for this sector
-	struct mprecipsecnode_s *m_snext;  // next msecnode_t for this sector
+	struct mprecipsecnode_s *m_sectorlist_prev;  // prev msecnode_t for this thing
+	struct mprecipsecnode_s *m_sectorlist_next;  // next msecnode_t for this thing
+	struct mprecipsecnode_s *m_thinglist_prev;  // prev msecnode_t for this sector
+	struct mprecipsecnode_s *m_thinglist_next;  // next msecnode_t for this sector
 	boolean visited; // used in search algorithms
 } mprecipsecnode_t;
 
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index d12a7efbf86acf4ae461b101c4024ab13708e88b..820192649d981adeaa477f0791d200f46d3ddfe9 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -167,6 +167,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
@@ -308,6 +309,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9396b4823bf5ed60465fc8fef72fcb86e989b64e..d04007dd77d026e48e8480bf93a54b86d279b7c5 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -294,6 +294,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
@@ -666,6 +669,9 @@
     <ClCompile Include="..\md5.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
diff --git a/src/w_wad.c b/src/w_wad.c
index 40fea52230c20ef4cdac76a22a162158314c080b..aeaad3ced975cafeb8a190b814d9361d381765c6 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -475,11 +475,11 @@ UINT16 W_LoadWadFile(const char *filename)
 	//
 	CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
 	wadfiles[numwadfiles] = wadfile;
-	W_LoadDehackedLumps(numwadfiles);
+	numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
+	W_LoadDehackedLumps(numwadfiles-1);
 
 	W_InvalidateLumpnumCache();
 
-	numwadfiles++;
 	return wadfile->numlumps;
 }
 
diff --git a/src/w_wad.h b/src/w_wad.h
index c13f6933816ec1fe0091eebca00f65c6393f3880..b03e376bfaf76c62778a163f44994c25fc37efaf 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -54,10 +54,8 @@ typedef struct
 
 #define lumpcache_t void *
 
-// Annoying cyclic dependency workaround: this inlcusion must come after
-// the definition of MAX_WADPATH.
 #ifdef HWRENDER
-#include "m_misc.h"
+#include "m_aatree.h"
 #endif
 
 typedef struct wadfile_s
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 1e9d8241ede783576e7463246d5730164f54b836..064f75d7d06cdee1aa62d70dda03e9e28d53e6f2 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -145,6 +145,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
@@ -300,6 +301,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 3f5b84bfb7d131fef86d800acffcb53c4b9d6e4d..b2647ea1c21518389b7061276f6464d05998721b 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -255,6 +255,9 @@
     <ClCompile Include="..\lua_skinlib.c">
       <Filter>LUA</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
@@ -662,6 +665,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>