diff --git a/src/p_map.c b/src/p_map.c
index d4d8796a2421a8a061b11974a57910ad478c05d3..38c310d0bf6318bd0d787c6545880a10bfec43d3 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -4328,6 +4328,11 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 	sector_t *sec = R_PointInSubsector(x, y)->sector;
 	fixed_t floorz = sec->floorheight;
 
+#ifdef ESLOPE
+	if (sec->f_slope)
+		floorz = P_GetZAt(sec->f_slope, x, y);
+#endif
+
 	// Intercept the stupid 'fall through 3dfloors' bug Tails 03-17-2002
 	if (sec->ffloors)
 	{
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index f4ebb6df9fce7df919b0ba68aec1b96f7e51cc85..752c443f5b4e01d76c0daf77d98590450bfb729e 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -107,6 +107,9 @@ static SDL_bool disable_mouse = SDL_FALSE;
 // first entry in the modelist which is not bigger than MAXVIDWIDTHxMAXVIDHEIGHT
 static      INT32          firstEntry = 0;
 
+// Total mouse motion X/Y offsets
+static      INT32        mousemovex = 0, mousemovey = 0;
+
 // SDL vars
 static      SDL_Surface *vidSurface = NULL;
 static      SDL_Surface *bufSurface = NULL;
@@ -119,7 +122,8 @@ static       Uint8       BitsPerPixel = 16;
 Uint16      realwidth = BASEVIDWIDTH;
 Uint16      realheight = BASEVIDHEIGHT;
 static       SDL_bool    mousegrabok = SDL_TRUE;
-#define HalfWarpMouse(x,y) SDL_WarpMouseInWindow(window, (Uint16)(x/2),(Uint16)(y/2))
+static       SDL_bool    wrapmouseok = SDL_FALSE;
+#define HalfWarpMouse(x,y) if (wrapmouseok) SDL_WarpMouseInWindow(window, (Uint16)(x/2),(Uint16)(y/2))
 static       SDL_bool    videoblitok = SDL_FALSE;
 static       SDL_bool    exposevideo = SDL_FALSE;
 static       SDL_bool    usesdl2soft = SDL_FALSE;
@@ -348,6 +352,8 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
 static void SDLdoUngrabMouse(void)
 {
 	SDL_SetWindowGrab(window, SDL_FALSE);
+	wrapmouseok = SDL_FALSE;
+	SDL_SetRelativeMouseMode(SDL_FALSE);
 }
 
 void SDLforceUngrabMouse(void)
@@ -355,6 +361,8 @@ void SDLforceUngrabMouse(void)
 	if (SDL_WasInit(SDL_INIT_VIDEO)==SDL_INIT_VIDEO && window != NULL)
 	{
 		SDL_SetWindowGrab(window, SDL_FALSE);
+		wrapmouseok = SDL_FALSE;
+		SDL_SetRelativeMouseMode(SDL_FALSE);
 	}
 }
 
@@ -603,36 +611,43 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
 
 static void Impl_HandleMouseMotionEvent(SDL_MouseMotionEvent evt)
 {
-	event_t event;
-	int wwidth, wheight;
-
 	if (USE_MOUSEINPUT)
 	{
-		SDL_GetWindowSize(window, &wwidth, &wheight);
-
 		if ((SDL_GetMouseFocus() != window && SDL_GetKeyboardFocus() != window))
 		{
 			SDLdoUngrabMouse();
 			return;
 		}
 
-		if ((evt.x == realwidth/2) && (evt.y == realheight/2))
+		// If using relative mouse mode, don't post an event_t just now,
+		// add on the offsets so we can make an overall event later.
+		if (SDL_GetRelativeMouseMode())
 		{
+			if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window)
+			{
+				mousemovex +=  evt.xrel;
+				mousemovey += -evt.yrel;
+				SDL_SetWindowGrab(window, SDL_TRUE);
+			}
 			return;
 		}
-		else
+
+		// If the event is from warping the pointer to middle
+		// of the screen then ignore it.
+		if ((evt.x == realwidth/2) && (evt.y == realheight/2))
 		{
-			event.data2 = (INT32)lround((evt.xrel) * ((float)wwidth / (float)realwidth));
-			event.data3 = (INT32)lround(-evt.yrel * ((float)wheight / (float)realheight));
+			return;
 		}
 
-		event.type = ev_mouse;
-
+		// Don't send an event_t if not in relative mouse mode anymore,
+		// just grab and set relative mode
+		// this fixes the stupid camera jerk on mouse entering bug
+		// -- Monster Iestyn
 		if (SDL_GetMouseFocus() == window && SDL_GetKeyboardFocus() == window)
 		{
-			D_PostEvent(&event);
 			SDL_SetWindowGrab(window, SDL_TRUE);
-			HalfWarpMouse(wwidth, wheight);
+			if (SDL_SetRelativeMouseMode(SDL_TRUE) == 0) // already warps mouse if successful
+				wrapmouseok = SDL_TRUE; // TODO: is wrapmouseok or HalfWarpMouse needed anymore?
 		}
 	}
 }
@@ -780,13 +795,15 @@ void I_GetEvent(void)
 	SDL_Event evt;
 	// We only want the first motion event,
 	// otherwise we'll end up catching the warp back to center.
-	int mouseMotionOnce = 0;
+	//int mouseMotionOnce = 0;
 
 	if (!graphics_started)
 	{
 		return;
 	}
 
+	mousemovex = mousemovey = 0;
+
 	while (SDL_PollEvent(&evt))
 	{
 		switch (evt.type)
@@ -799,8 +816,9 @@ void I_GetEvent(void)
 				Impl_HandleKeyboardEvent(evt.key, evt.type);
 				break;
 			case SDL_MOUSEMOTION:
-				if (!mouseMotionOnce) Impl_HandleMouseMotionEvent(evt.motion);
-				mouseMotionOnce = 1;
+				//if (!mouseMotionOnce)
+				Impl_HandleMouseMotionEvent(evt.motion);
+				//mouseMotionOnce = 1;
 				break;
 			case SDL_MOUSEBUTTONUP:
 			case SDL_MOUSEBUTTONDOWN:
@@ -823,6 +841,20 @@ void I_GetEvent(void)
 		}
 	}
 
+	// Send all relative mouse movement as one single mouse event.
+	if (mousemovex || mousemovey)
+	{
+		event_t event;
+		int wwidth, wheight;
+		SDL_GetWindowSize(window, &wwidth, &wheight);
+		//SDL_memset(&event, 0, sizeof(event_t));
+		event.type = ev_mouse;
+		event.data1 = 0;
+		event.data2 = (INT32)lround(mousemovex * ((float)wwidth / (float)realwidth));
+		event.data3 = (INT32)lround(mousemovey * ((float)wheight / (float)realheight));
+		D_PostEvent(&event);
+	}
+
 	// In order to make wheels act like buttons, we have to set their state to Up.
 	// This is because wheel messages don't have an up/down state.
 	gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
@@ -836,7 +868,9 @@ void I_StartupMouse(void)
 		return;
 
 	if (!firsttimeonmouse)
+	{
 		HalfWarpMouse(realwidth, realheight); // warp to center
+	}
 	else
 		firsttimeonmouse = SDL_FALSE;
 	if (cv_usemouse.value)