diff --git a/.travis.yml b/.travis.yml
index e3408cf6f1d28b1615a7aa4fde68349d8677f9aa..d728758ed89f222f90c83d440e9ddf7bb25e08ef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -98,7 +98,7 @@ matrix:
               - p7zip-full
               - gcc-6
           compiler: gcc-6
-          env: WFLAGS="-Wno-error=tautological-compare"
+          env: WFLAGS="-Wno-tautological-compare"
           #gcc-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511
         - os: linux
           compiler: clang
@@ -213,7 +213,7 @@ before_script:
   - 7z x $HOME/srb2_cache/SRB2-v2115-assets-2.7z -oassets
   - mkdir build
   - cd build
-  - export CFLAGS="-Wall -W $WFLAGS"
+  - export CFLAGS="-Wall -W -Werror $WFLAGS"
   - export CCACHE_COMPRESS=true
   - cmake .. -DCMAKE_BUILD_TYPE=Release
 
diff --git a/src/doomdef.h b/src/doomdef.h
index 70ec8c0d19970a72d91c5041f2fb98fe8d6cb375..4428ef617e24063e3feaf2b6119b16e5738b6bab 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -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
 
 // =========================================================================
 
@@ -435,6 +435,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/lua_baselib.c b/src/lua_baselib.c
index 1bacf9102691de7a117a40c97737fdf5f1c0d1a4..bbcec06d3a8c01e5a8975fc769381f31b5f04c7b 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -429,6 +429,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);
@@ -2003,6 +2013,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/p_local.h b/src/p_local.h
index 57ca425e155b0b40ffc8b344c4c7cbb764fb8e43..a6573d487f13f540d8c60fe8fa3442320c1ef0d9 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);
 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 0d4bae83023182b275286c0f35302f6444e644a9..a91e5fd11447f19ba9d994179f2542d8a9eeacd8 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -2433,6 +2433,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;
@@ -2657,6 +2659,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);
 
@@ -2667,9 +2670,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))
diff --git a/src/p_mobj.c b/src/p_mobj.c
index d516e25280464efa9c8d2cfc105da667161f64fe..999f2bf7285878caa9572c04d37f7db78f20c5ce 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1427,13 +1427,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
@@ -1492,9 +1491,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]
@@ -1575,12 +1571,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;
@@ -1655,7 +1670,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
 				)
 		{
@@ -2329,16 +2344,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);
@@ -2353,6 +2358,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:
@@ -2539,10 +2554,7 @@ static boolean P_ZMovement(mobj_t *mo)
 		if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
 			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
 
diff --git a/src/p_setup.c b/src/p_setup.c
index 6c14e3614118c24deccf30c711a12de268e42763..e56c44c70616814a2f6f216864f07aaa0e2e8b8f 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1934,7 +1934,7 @@ static void P_GroupLines(void)
 		if (sector->linecount == 0) // no lines found?
 		{
 			sector->lines = NULL;
-			CONS_Debug(DBG_SETUP, "P_GroupLines: sector %d has no lines\n", i);
+			CONS_Debug(DBG_SETUP, "P_GroupLines: sector %s has no lines\n", sizeu1(i));
 		}
 		else
 		{
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_user.c b/src/p_user.c
index 6b7c9d4ed5d483334a06f7fbcbe82420aa7f4c46..09941745b48c4f2d7a47e5ccb12a9290da20aff3 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1852,12 +1852,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
@@ -2279,9 +2275,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;
@@ -2293,298 +2289,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)
 		{
@@ -2846,16 +2847,18 @@ static void P_DoTeeter(player_t *player)
 {
 	boolean teeter = false;
 	boolean roverfloor; // solid 3d floors?
+	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.
 
+	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...
 	{
-		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;
@@ -2863,13 +2866,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))
@@ -2877,12 +2910,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;
@@ -2896,12 +2929,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;
@@ -2919,18 +2952,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;
 		}
 	}
@@ -3682,7 +3709,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
 			)
 		{
@@ -3718,7 +3745,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))
 		{
@@ -3734,7 +3761,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
 			)
 	{
@@ -4723,7 +4750,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;