diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8abe511d42f3bbbf01fd80f525f0978cbb573ca..0fb5cb28fbd6eacb2459c848e91b2ba7ae86943b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,10 @@ project(SRB2
 	VERSION 2.1.14
 	LANGUAGES C)
 
+if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
+	message(FATAL_ERROR "In-source builds will bring you a world of pain. Please make a separate directory to invoke CMake from.")
+endif()
+
 # Set up CMAKE path
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
 
@@ -44,7 +48,7 @@ macro(copy_files_to_build_dir target dlllist_var)
 			add_custom_command(TARGET ${target} POST_BUILD
 				COMMAND ${CMAKE_COMMAND} -E copy_if_different
 				${dlllist_item}
-				${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/${dllname}
+				$<TARGET_FILE_DIR:${target}>/${dllname}
 			)
 		endforeach()
 	endif()
@@ -58,10 +62,6 @@ else()
 	set(SRB2_SYSTEM_BITS 32)
 endif()
 
-if(MSVC)
-	message(WARNING "!! MSVC BUILDS OF SRB2 CANNOT PLAY MULTIPLAYER !! You're more than welcome to try and fix this!")
-endif()
-
 # OS macros
 if (UNIX)
 	add_definitions(-DUNIXCOMMON)
@@ -85,6 +85,9 @@ if(${CMAKE_SYSTEM} MATCHES "Darwin")
 	endif()
 endif()
 
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+
 # Set EXE names so the assets CMakeLists can refer to its target
 set(SRB2_SDL2_EXE_NAME srb2)
 set(SRB2_WIN_EXE_NAME srb2dd)
@@ -98,7 +101,9 @@ add_subdirectory(assets)
 ## config.h generation
 set(GIT_EXECUTABLE "git" CACHE FILEPATH "Path to git binary")
 include(GitUtilities)
-git_describe(SRB2_COMP_REVISION "${CMAKE_CURRENT_SOURCE_DIR}")
+git_describe(SRB2_GIT_DESCRIBE "${CMAKE_SOURCE_DIR}")
+git_current_branch(SRB2_GIT_BRANCH "${CMAKE_SOURCE_DIR}")
+set(SRB2_COMP_REVISION "${SRB2_GIT_DESCRIBE}-<${SRB2_GIT_BRANCH}>")
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)
 
 ##### PACKAGE CONFIGURATION #####
diff --git a/SRB2.cbp b/SRB2.cbp
index 4834563ec842f1d4386a0a0f745f080bef189381..5a03955b8dc036d688497e7fa0018796423b00e4 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -154,8 +154,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/gme/include" />
 				</Compiler>
 				<Linker>
-					<Add library="SDL" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2" />
+					<Add library="SDL2_mixer" />
 					<Add library="advapi32" />
 					<Add library="kernel32" />
 					<Add library="msvcrt" />
@@ -200,8 +200,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/gme/include" />
 				</Compiler>
 				<Linker>
-					<Add library="SDL" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2" />
+					<Add library="SDL2_mixer" />
 					<Add library="advapi32" />
 					<Add library="kernel32" />
 					<Add library="msvcrt" />
@@ -4141,283 +4141,170 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/sdl/IMG_xpm.c">
+		<Unit filename="src/sdl2/IMG_xpm.c">
 			<Option compilerVar="CC" />
-			<Option compile="0" />
-			<Option link="0" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/dosstr.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/sdl2/SDL_icon.xpm">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/endtxt.c">
+		<Unit filename="src/sdl2/dosstr.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-		</Unit>
-		<Unit filename="src/sdl/endtxt.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<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" />
 		</Unit>
-		<Unit filename="src/sdl/filter/filters.c">
+		<Unit filename="src/sdl2/endtxt.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/filter/filters.h">
+		<Unit filename="src/sdl2/endtxt.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/filter/hq2x.c">
+		<Unit filename="src/sdl2/hwsym_sdl.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-		</Unit>
-		<Unit filename="src/sdl/filter/hq2x.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<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" />
 		</Unit>
-		<Unit filename="src/sdl/filter/interp.h">
+		<Unit filename="src/sdl2/hwsym_sdl.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/filter/lq2x.c">
+		<Unit filename="src/sdl2/i_cdmus.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-		</Unit>
-		<Unit filename="src/sdl/filter/lq2x.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<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" />
 		</Unit>
-		<Unit filename="src/sdl/filter/main.c">
+		<Unit filename="src/sdl2/i_main.c">
 			<Option compilerVar="CC" />
-			<Option compile="0" />
-			<Option link="0" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/hwsym_sdl.c">
+		<Unit filename="src/sdl2/i_net.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-		</Unit>
-		<Unit filename="src/sdl/hwsym_sdl.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<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" />
 		</Unit>
-		<Unit filename="src/sdl/i_cdmus.c">
+		<Unit filename="src/sdl2/i_system.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/i_main.c">
+		<Unit filename="src/sdl2/i_ttf.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/i_net.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/sdl2/i_ttf.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/i_system.c">
+		<Unit filename="src/sdl2/i_video.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/i_video.c">
+		<Unit filename="src/sdl2/mixer_sound.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-		</Unit>
-		<Unit filename="src/sdl/mixer_sound.c">
-			<Option compilerVar="CC" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/ogl_sdl.c">
+		<Unit filename="src/sdl2/ogl_sdl.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 Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
+			<Option target="Debug Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/ogl_sdl.h">
+		<Unit filename="src/sdl2/ogl_sdl.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/sdl_sound.c">
+		<Unit filename="src/sdl2/sdl_sound.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl/sdlmain.h">
+		<Unit filename="src/sdl2/sdlmain.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<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 Mingw/SDL" />
+			<Option target="Release Mingw/SDL" />
 		</Unit>
 		<Unit filename="src/sounds.c">
 			<Option compilerVar="CC" />
@@ -4590,13 +4477,13 @@ HW3SOUND for 3D hardware sound  support
 		</Unit>
 		<Unit filename="src/vid_copy.s">
 			<Option compilerVar="CC" />
-			<Option compiler="avrgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
+			<Option compiler="gcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
+			<Option compiler="ppcgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
 			<Option compiler="gnu_gcc_compiler_for_mingw32" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
-			<Option compiler="gnu_gcc_compiler_for_mingw64" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
 			<Option compiler="armelfgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
 			<Option compiler="tricoregcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
-			<Option compiler="ppcgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
-			<Option compiler="gcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
+			<Option compiler="avrgcc" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
+			<Option compiler="gnu_gcc_compiler_for_mingw64" use="1" buildCommand="$compiler $options -x assembler-with-cpp -c $file -o $object" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
diff --git a/assets/CMakeLists.txt b/assets/CMakeLists.txt
index 3ce133c6a67fde3d3ea55170bc7b8b24938fa8a6..292e184c72d20a3d2e2b5295de8dc818d6826a58 100644
--- a/assets/CMakeLists.txt
+++ b/assets/CMakeLists.txt
@@ -26,7 +26,7 @@ endforeach()
 # Installation
 
 if(CLANG)
-	get_target_property(outname ${SRB2_SDL2_EXE_NAME} OUTPUT_NAME)
+	get_target_property(outname SRB2SDL2 OUTPUT_NAME)
 	install(FILES ${SRB2_ASSET_ALL}
 		DESTINATION "${outname}.app/Contents/Resources"
 	)
diff --git a/cmake/Modules/FindSDL2.cmake b/cmake/Modules/FindSDL2.cmake
index faa556a883aae61ac482c304f32200a996b982de..9e789e19cc85e547bca49e7d23810421ba48dc1f 100644
--- a/cmake/Modules/FindSDL2.cmake
+++ b/cmake/Modules/FindSDL2.cmake
@@ -27,7 +27,6 @@ find_library(SDL2_LIBRARY
 		"/usr/local/lib"
 )
 
-
 # set include dir variables
 set(SDL2_PROCESS_INCLUDES SDL2_INCLUDE_DIR)
 set(SDL2_PROCESS_LIBS SDL2_LIBRARY)
diff --git a/cmake/Modules/GitUtilities.cmake b/cmake/Modules/GitUtilities.cmake
index de4015b0d1e45be3afd1c858c373db4b3d36277c..683cf9b6b505e788bd3139bf0513b433a3190a2e 100644
--- a/cmake/Modules/GitUtilities.cmake
+++ b/cmake/Modules/GitUtilities.cmake
@@ -14,9 +14,18 @@ function(git_describe variable path)
 		ERROR_QUIET
 		OUTPUT_STRIP_TRAILING_WHITESPACE
 	)
-	#if(NOT result EQUAL 0)
-	#	set(${variable} "GITERROR-${result}-NOTFOUND" CACHE STRING "revision" FORCE)
-	#endif()
 
 	set(${variable} "${output}" PARENT_SCOPE)
 endfunction()
+
+function(git_current_branch variable path)
+	execute_process(COMMAND ${GIT_EXECUTABLE} "symbolic-ref" "--short" "HEAD"
+		WORKING_DIRECTORY "${path}"
+		RESULT_VARIABLE result
+		OUTPUT_VARIABLE output
+		ERROR_QUIET
+		OUTPUT_STRIP_TRAILING_WHITESPACE
+	)
+
+	set(${variable} "${output}" PARENT_SCOPE)
+endfunction()
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 74f97048b3f5332070a14b05cf6f167f79267797..bb4f9a4a6f514ed1a098c2e5f38b4f8c08fd6917 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -34,32 +34,6 @@ set(SRB2_CORE_SOURCES
 	m_random.c
 	md5.c
 	mserv.c
-	p_ceilng.c
-	p_enemy.c
-	p_fab.c
-	p_floor.c
-	p_inter.c
-	p_lights.c
-	p_map.c
-	p_maputl.c
-	p_mobj.c
-	p_polyobj.c
-	p_saveg.c
-	p_setup.c
-	p_sight.c
-	p_spec.c
-	p_telept.c
-	p_tick.c
-	p_user.c
-	r_bsp.c
-	r_data.c
-	r_draw.c
-	r_main.c
-	r_plane.c
-	r_segs.c
-	r_sky.c
-	r_splats.c
-	r_things.c
 	s_sound.c
 	screen.c
 	sounds.c
@@ -124,15 +98,30 @@ set(SRB2_CORE_HEADERS
 	md5.h
 	mserv.h
 	p5prof.h
-	p_local.h
-	p_maputl.h
-	p_mobj.h
-	p_polyobj.h
-	p_pspr.h
-	p_saveg.h
-	p_setup.h
-	p_spec.h
-	p_tick.h
+	s_sound.h
+	screen.h
+	sounds.h
+	st_stuff.h
+	tables.h
+	v_video.h
+	w_wad.h
+	y_inter.h
+	z_zone.h
+
+	config.h.in
+)
+
+set(SRB2_CORE_RENDER_SOURCES
+	r_bsp.c
+	r_data.c
+	r_draw.c
+	r_main.c
+	r_plane.c
+	r_segs.c
+	r_sky.c
+	r_splats.c
+	r_things.c
+
 	r_bsp.h
 	r_data.h
 	r_defs.h
@@ -145,82 +134,78 @@ set(SRB2_CORE_HEADERS
 	r_splats.h
 	r_state.h
 	r_things.h
-	s_sound.h
-	screen.h
-	sounds.h
-	st_stuff.h
-	tables.h
-	v_video.h
-	w_wad.h
-	y_inter.h
-	z_zone.h
 )
 
-prepend_sources(SRB2_CORE_SOURCES)
-prepend_sources(SRB2_CORE_HEADERS)
-
-set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/config.h)
-
-set(SRB2_HWRENDER_SOURCES
-	hardware/hw_bsp.c
-	hardware/hw_cache.c
-	hardware/hw_draw.c
-	hardware/hw_light.c
-	hardware/hw_main.c
-	hardware/hw_md2.c
-	hardware/hw_trick.c
-)
+set(SRB2_CORE_GAME_SOURCES
+	p_ceilng.c
+	p_enemy.c
+	p_fab.c
+	p_floor.c
+	p_inter.c
+	p_lights.c
+	p_map.c
+	p_maputl.c
+	p_mobj.c
+	p_polyobj.c
+	p_saveg.c
+	p_setup.c
+	p_sight.c
+	p_slopes.c
+	p_spec.c
+	p_telept.c
+	p_tick.c
+	p_user.c
 
-set (SRB2_HWRENDER_HEADERS
-	hardware/hw_data.h
-	hardware/hw_defs.h
-	hardware/hw_dll.h
-	hardware/hw_drv.h
-	hardware/hw_glide.h
-	hardware/hw_glob.h
-	hardware/hw_light.h
-	hardware/hw_main.h
-	hardware/hw_md2.h
+	p_local.h
+	p_maputl.h
+	p_mobj.h
+	p_polyobj.h
+	p_pspr.h
+	p_saveg.h
+	p_setup.h
+	p_slopes.h
+	p_spec.h
+	p_tick.h
 )
 
-prepend_sources(SRB2_HWRENDER_SOURCES)
-prepend_sources(SRB2_HWRENDER_HEADERS)
+if(NOT CLANG)
+	set(SRB2_CORE_SOURCES ${SRB2_CORE_SOURCES} string.c)
+endif()
 
-set(SRB2_R_OPENGL_SOURCES
-	hardware/r_opengl/r_opengl.c
-)
+prepend_sources(SRB2_CORE_SOURCES)
+prepend_sources(SRB2_CORE_HEADERS)
+prepend_sources(SRB2_CORE_RENDER_SOURCES)
+prepend_sources(SRB2_CORE_GAME_SOURCES)
 
-set(SRB2_R_OPENGL_HEADERS
-	hardware/r_opengl/r_opengl.h
-)
+set(SRB2_CORE_HEADERS ${SRB2_CORE_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS})
+source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES})
+source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES})
 
-prepend_sources(SRB2_R_OPENGL_SOURCES)
-prepend_sources(SRB2_R_OPENGL_HEADERS)
 
 set(SRB2_ASM_SOURCES
-	vid_copy.s
+	${CMAKE_CURRENT_SOURCE_DIR}/vid_copy.s
 )
 
 set(SRB2_NASM_SOURCES
-	tmap_mmx.nas
-	tmap.nas
+	${CMAKE_CURRENT_SOURCE_DIR}/tmap_mmx.nas
+	${CMAKE_CURRENT_SOURCE_DIR}/tmap.nas
 )
 
 if(MSVC)
-	list(APPEND SRB2_NASM_SOURCES tmap_vc.nas)
+	list(APPEND SRB2_NASM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tmap_vc.nas)
 endif()
 
 set(SRB2_NASM_OBJECTS
-	tmap_mmx.obj
-	tmap.obj
+	${CMAKE_CURRENT_BINARY_DIR}/tmap_mmx.obj
+	${CMAKE_CURRENT_BINARY_DIR}/tmap.obj
 )
 
 if(MSVC)
-	list(APPEND SRB2_NASM_OBJECTS tmap_vc.obj)
+	list(APPEND SRB2_NASM_OBJECTS ${CMAKE_CURRENT_BINARY_DIR}/tmap_vc.obj)
 endif()
 
-prepend_sources(SRB2_ASM_SOURCES)
-prepend_sources(SRB2_NASM_SOURCES)
+source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES})
 
 
 ### Configuration
@@ -229,11 +214,11 @@ set(SRB2_CONFIG_HAVE_BLUA ON CACHE BOOL
 set(SRB2_CONFIG_HAVE_PNG ON CACHE BOOL
 	"Enable PNG support. Depends on zlib, so will be disabled if you don't enable that too.")
 set(SRB2_CONFIG_HAVE_ZLIB ON CACHE BOOL
-	"Enable zlib support")
+	"Enable zlib support.")
 set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
-	"Enable GME support")
+	"Enable GME support.")
 set(SRB2_CONFIG_HWRENDER ON CACHE BOOL
-	"Enable hardware rendering through OpenGL")
+	"Enable hardware rendering through OpenGL.")
 set(SRB2_CONFIG_USEASM OFF CACHE BOOL
 	"Enable NASM tmap implementation for software mode speedup.")
 set(SRB2_CONFIG_YASM OFF CACHE BOOL
@@ -267,6 +252,8 @@ if(${SRB2_CONFIG_HAVE_BLUA})
 	prepend_sources(SRB2_LUA_SOURCES)
 	prepend_sources(SRB2_LUA_HEADERS)
 
+	source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS})
+
 	set(SRB2_BLUA_SOURCES
 		blua/lapi.c
 		blua/lauxlib.c
@@ -318,8 +305,11 @@ if(${SRB2_CONFIG_HAVE_BLUA})
 		blua/lvm.h
 		blua/lzio.h
 	)
+
 	prepend_sources(SRB2_BLUA_SOURCES)
 	prepend_sources(SRB2_BLUA_HEADERS)
+
+	source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS})
 endif()
 
 if(${SRB2_CONFIG_HAVE_GME})
@@ -355,6 +345,36 @@ endif()
 
 if(${SRB2_CONFIG_HWRENDER})
 	add_definitions(-DHWRENDER)
+	set(SRB2_HWRENDER_SOURCES
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_bsp.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_cache.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_draw.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.c
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_trick.c
+	)
+
+	set (SRB2_HWRENDER_HEADERS
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_data.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_defs.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_dll.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_drv.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glide.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_glob.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_light.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_main.h
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/hw_md2.h
+	)
+
+	set(SRB2_R_OPENGL_SOURCES
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.c
+	)
+
+	set(SRB2_R_OPENGL_HEADERS
+		${CMAKE_CURRENT_SOURCE_DIR}/hardware/r_opengl/r_opengl.h
+	)
+
 endif()
 
 if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
@@ -384,10 +404,6 @@ endif()
 
 # Targets
 
-if(${CMAKE_SYSTEM} MATCHES Windows)
-	add_subdirectory(win32)
-endif()
-
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
 if(NOT CLANG AND NOT MSVC)
@@ -396,4 +412,23 @@ endif()
 
 add_definitions(-DCMAKECONFIG)
 
+#add_library(SRB2Core STATIC
+#	${SRB2_CORE_SOURCES}
+#	${SRB2_CORE_HEADERS}
+#	${SRB2_CORE_RENDER_SOURCES}
+#	${SRB2_CORE_GAME_SOURCES}
+#	${SRB2_LUA_SOURCES}
+#	${SRB2_LUA_HEADERS}
+#	${SRB2_BLUA_SOURCES}
+#	${SRB2_BLUA_HEADERS}
+#)
+
 add_subdirectory(sdl)
+
+if(${CMAKE_SYSTEM} MATCHES Windows)
+	add_subdirectory(win32)
+endif()
+
+if(NOT ${SRB2_SDL2_AVAILABLE} AND NOT ${SRB2_WIN32_AVAILABLE})
+	message(FATAL_ERROR "There are no targets available to build an SRB2 executable. :(")
+endif()
\ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
index d4cc64a4b6ff79da6672ee10df9ef30f574aca40..bee60804720da1dcbee09065c29f616e145848f0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -454,6 +454,7 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/p_telept.o \
 		$(OBJDIR)/p_tick.o   \
 		$(OBJDIR)/p_user.o   \
+		$(OBJDIR)/p_slopes.o \
 		$(OBJDIR)/tables.o   \
 		$(OBJDIR)/r_bsp.o    \
 		$(OBJDIR)/r_data.o   \
diff --git a/src/config.h.in b/src/config.h.in
index 7c5b299cfe375b67453121b30f5063c4d70f1e88..2ed7aec3e88d914abcf87843b1d025d23a04b2ae 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -3,6 +3,12 @@
 #ifndef __CONFIG_H__
 #define __CONFIG_H__
 
+/* DO NOT MODIFY config.h DIRECTLY! It will be overwritten by cmake.
+ * If you want to change a configuration option here, modify it in
+ * your CMakeCache.txt. config.h.in is used as a template for CMake
+ * variables, so you can insert them here too.
+ */
+
 #ifdef CMAKECONFIG
 
 #define ASSET_HASH_SRB2_SRB   "${SRB2_ASSET_srb2.srb_HASH}"
@@ -12,6 +18,8 @@
 #define ASSET_HASH_PATCH_DTA  "${SRB2_ASSET_patch.dta_HASH}"
 
 #define SRB2_COMP_REVISION    "${SRB2_COMP_REVISION}"
+#define SRB2_GIT_DESCRIBE     "${SRB2_GIT_DESCRIBE}"
+#define SRB2_GIT_BRANCH       "${SRB2_GIT_BRANCH}"
 
 #define CMAKE_ASSETS_DIR      "${CMAKE_SOURCE_DIR}/assets"
 
diff --git a/src/d_main.c b/src/d_main.c
index a959a86328e09d4a501c3c9b2eea52e197ed478d..61255e2722574bc6e28a6acd2fa461913c4fd67b 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -943,9 +943,9 @@ void D_SRB2Main(void)
 #endif
 
 #if defined (_WIN32_WCE) //|| defined (_DEBUG) || defined (GP2X)
-	devparm = !M_CheckParm("-nodebug");
+	devparm = M_CheckParm("-nodebug") == 0;
 #else
-	devparm = M_CheckParm("-debug");
+	devparm = M_CheckParm("-debug") != 0;
 #endif
 
 	// for dedicated server
@@ -1118,7 +1118,7 @@ void D_SRB2Main(void)
 #endif
 	D_CleanFile();
 
-#if 1 // md5s last updated 12/14/14
+#ifndef DEVELOP // md5s last updated 12/14/14
 
 	// Check MD5s of autoloaded files
 	W_VerifyFileMD5(0, ASSET_HASH_SRB2_SRB); // srb2.srb/srb2.wad
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index e410713e0848f8589d15b8943b1cc1e6aae42a34..772b98c82738c1c762e8734c6e9f0f88e89be34f 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -3193,7 +3193,27 @@ static void Command_ModDetails_f(void)
 //
 static void Command_ShowGametype_f(void)
 {
-	CONS_Printf(M_GetText("Current gametype is %d\n"), gametype);
+	INT32 j;
+	const char *gametypestr = NULL;
+
+	if (!(netgame || multiplayer)) // print "Single player" instead of "Co-op"
+	{
+		CONS_Printf(M_GetText("Current gametype is %s\n"), M_GetText("Single player"));
+		return;
+	}
+	// find name string for current gametype
+	for (j = 0; gametype_cons_t[j].strvalue; j++)
+	{
+		if (gametype_cons_t[j].value == gametype)
+		{
+			gametypestr = gametype_cons_t[j].strvalue;
+			break;
+		}
+	}
+	if (gametypestr)
+		CONS_Printf(M_GetText("Current gametype is %s\n"), gametypestr);
+	else // string for current gametype was not found above (should never happen)
+		CONS_Printf(M_GetText("Unknown gametype set (%d)\n"), gametype);
 }
 
 /** Plays the intro.
diff --git a/src/dehacked.c b/src/dehacked.c
index fc01bafddc1d116237086a1d0ca0e6b4d4f9d483..dfa90cd547b49b517ec3e57b5c9d194d5f895985 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -473,6 +473,7 @@ static void readPlayer(MYFILE *f, INT32 num)
 
 				if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
 					goto done;
+				PlayerMenu[num].status = IT_CALL;
 
 				for (i = 0; i < MAXLINELEN-3; i++)
 				{
@@ -545,6 +546,7 @@ static void readPlayer(MYFILE *f, INT32 num)
 				if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
 					goto done;
 				DEH_WriteUndoline(word, &description[num].picname[0], UNDO_NONE);
+				PlayerMenu[num].status = IT_CALL;
 				strncpy(description[num].picname, word2, 8);
 			}
 			else if (fastcmp(word, "STATUS"))
@@ -576,6 +578,8 @@ static void readPlayer(MYFILE *f, INT32 num)
 				if (!slotfound && (slotfound = findFreeSlot(&num)) == false)
 					goto done;
 				DEH_WriteUndoline(word, description[num].skinname, UNDO_NONE);
+				PlayerMenu[num].status = IT_CALL;
+
 				strlcpy(description[num].skinname, word2, sizeof description[num].skinname);
 				strlwr(description[num].skinname);
 			}
@@ -3883,7 +3887,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Blue Crawla
 	"S_POSS_STND",
-	"S_POSS_STND2",
 	"S_POSS_RUN1",
 	"S_POSS_RUN2",
 	"S_POSS_RUN3",
@@ -3893,7 +3896,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
 
 	// Red Crawla
 	"S_SPOS_STND",
-	"S_SPOS_STND2",
 	"S_SPOS_RUN1",
 	"S_SPOS_RUN2",
 	"S_SPOS_RUN3",
@@ -7248,7 +7250,6 @@ static const char *const MOBJFLAG2_LIST[] = {
 	"EXPLOSION",	// Thrown ring has explosive properties
 	"SCATTER",		// Thrown ring has scatter properties
 	"BEYONDTHEGRAVE",// Source of this missile has died and has since respawned.
-	"PUSHED",		// Mobj was already pushed this tic
 	"SLIDEPUSH",	// MF_PUSHABLE that pushes continuously.
 	"CLASSICPUSH",	// Drops straight down when object has negative Z.
 	"STANDONME",	// While not pushable, stand on me anyway.
@@ -7277,6 +7278,8 @@ static const char *const MOBJEFLAG_LIST[] = {
 	"JUSTSTEPPEDDOWN", // used for ramp sectors
 	"VERTICALFLIP", // Vertically flip sprite/allow upside-down physics
 	"GOOWATER", // Goo water
+	"PUSHED", // Mobj was already pushed this tic
+	"SPRUNG", // Mobj was already sprung this tic
 	NULL
 };
 
@@ -7379,6 +7382,7 @@ static const char *const ML_LIST[16] = {
 };
 
 // This DOES differ from r_draw's Color_Names, unfortunately.
+// Also includes Super colors
 static const char *COLOR_ENUMS[] = {
 	"NONE",     	// SKINCOLOR_NONE
 	"WHITE",    	// SKINCOLOR_WHITE
@@ -7405,7 +7409,25 @@ static const char *COLOR_ENUMS[] = {
 	"ZIM",      	// SKINCOLOR_ZIM
 	"OLIVE",    	// SKINCOLOR_OLIVE
 	"YELLOW",   	// SKINCOLOR_YELLOW
-	"GOLD"      	// SKINCOLOR_GOLD
+	"GOLD",     	// SKINCOLOR_GOLD
+	// Super special awesome Super flashing colors!
+	"SUPER1",   	// SKINCOLOR_SUPER1
+	"SUPER2",   	// SKINCOLOR_SUPER2,
+	"SUPER3",   	// SKINCOLOR_SUPER3,
+	"SUPER4",   	// SKINCOLOR_SUPER4,
+	"SUPER5",   	// SKINCOLOR_SUPER5,
+	// Super Tails
+	"TSUPER1",  	// SKINCOLOR_TSUPER1,
+	"TSUPER2",  	// SKINCOLOR_TSUPER2,
+	"TSUPER3",  	// SKINCOLOR_TSUPER3,
+	"TSUPER4",  	// SKINCOLOR_TSUPER4,
+	"TSUPER5",  	// SKINCOLOR_TSUPER5,
+	// Super Knuckles
+	"KSUPER1",  	// SKINCOLOR_KSUPER1,
+	"KSUPER2",  	// SKINCOLOR_KSUPER2,
+	"KSUPER3",  	// SKINCOLOR_KSUPER3,
+	"KSUPER4",  	// SKINCOLOR_KSUPER4,
+	"KSUPER5"   	// SKINCOLOR_KSUPER5,
 };
 
 static const char *const POWERS_LIST[] = {
@@ -7612,8 +7634,9 @@ struct {
 	{"EMERALD6",EMERALD6},
 	{"EMERALD7",EMERALD7},
 
-	// SKINCOLOR_ doesn't include this..!
+	// SKINCOLOR_ doesn't include these..!
 	{"MAXSKINCOLORS",MAXSKINCOLORS},
+	{"MAXTRANSLATIONS",MAXTRANSLATIONS},
 
 	// Precipitation
 	{"PRECIP_NONE",PRECIP_NONE},
@@ -8236,7 +8259,7 @@ static fixed_t find_const(const char **rword)
 	}
 	else if (fastncmp("SKINCOLOR_",word,10)) {
 		char *p = word+10;
-		for (i = 0; i < MAXSKINCOLORS; i++)
+		for (i = 0; i < MAXTRANSLATIONS; i++)
 			if (fastcmp(p, COLOR_ENUMS[i])) {
 				free(word);
 				return i;
@@ -8295,8 +8318,8 @@ void DEH_Check(void)
 	if (dehpowers != NUMPOWERS)
 		I_Error("You forgot to update the Dehacked powers list, you dolt!\n(%d powers defined, versus %s in the Dehacked list)\n", NUMPOWERS, sizeu1(dehpowers));
 
-	if (dehcolors != MAXSKINCOLORS)
-		I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", MAXSKINCOLORS, sizeu1(dehcolors));
+	if (dehcolors != MAXTRANSLATIONS)
+		I_Error("You forgot to update the Dehacked colors list, you dolt!\n(%d colors defined, versus %s in the Dehacked list)\n", MAXTRANSLATIONS, sizeu1(dehcolors));
 #endif
 }
 
@@ -8661,7 +8684,7 @@ static inline int lib_getenum(lua_State *L)
 	}
 	else if (fastncmp("SKINCOLOR_",word,10)) {
 		p = word+10;
-		for (i = 0; i < MAXSKINCOLORS; i++)
+		for (i = 0; i < MAXTRANSLATIONS; i++)
 			if (fastcmp(p, COLOR_ENUMS[i])) {
 				lua_pushinteger(L, i);
 				return 1;
@@ -8786,7 +8809,7 @@ static inline int lib_getenum(lua_State *L)
 		lua_pushinteger(L, mapmusic);
 		return 1;
 	} else if (fastcmp(word,"server")) {
-		if (!playeringame[serverplayer])
+		if ((!multiplayer || !netgame) && !playeringame[serverplayer])
 			return 0;
 		LUA_PushUserdata(L, &players[serverplayer], META_PLAYER);
 		return 1;
diff --git a/src/doomdef.h b/src/doomdef.h
index 4a6d6e5764bc48198d034f2e2e98ce8c5ac9ab26..bfa5ee0ceed8bad5a8eba5a18128a0cc16f024dc 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -138,10 +138,12 @@
 extern FILE *logstream;
 #endif
 
-#if 0
+//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
+#ifdef DEVELOP
 #define VERSION    0 // Game version
 #define SUBVERSION 0 // more precise version number
 #define VERSIONSTRING "Trunk"
+#define VERSIONSTRINGW L"Trunk"
 #else
 #define VERSION    201 // Game version
 #define SUBVERSION 14  // more precise version number
@@ -437,6 +439,13 @@ extern const char *compdate, *comptime, *comprevision;
 ///	Fun experimental slope stuff!
 //#define SLOPENESS
 
+/// Kalaron/Eternity Engine slope code (SRB2CB ported)
+/// Depends on NEED_FIXED_VECTORS? for a few functions.
+#define ESLOPE
+
+/// Fixed and float point types
+//#define NEED_FIXED_VECTOR
+
 ///	Delete file while the game is running.
 ///	\note	EXTREMELY buggy, tends to crash game.
 //#define DELFILE
diff --git a/src/g_game.c b/src/g_game.c
index c59f23c0787f23de3a7cfe58c1393a638d4b9e4d..917a86165684250ac5dd11693da0e2b3b52a3773 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -2180,8 +2180,7 @@ void G_PlayerReborn(INT32 player)
 	p->health = 1; // 0 rings
 	p->panim = PA_IDLE; // standing animation
 
-	if ((netgame || multiplayer) && !p->spectator
-	&& gametype != GT_RACE)
+	if ((netgame || multiplayer) && !p->spectator)
 		p->powers[pw_flashing] = flashingtics-1; // Babysitting deterrent
 
 	if (p-players == consoleplayer)
@@ -4330,20 +4329,10 @@ void G_GhostTicker(void)
 		switch(g->color)
 		{
 		case GHC_SUPER: // Super Sonic (P_DoSuperStuff)
-			// Yousa yellow now!
-			g->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5;
-			if (g->mo->skin)
-				switch (((skin_t*)g->mo->skin)-skins)
-				{
-				case 1: // Golden orange supertails.
-					g->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5;
-					break;
-				case 2: // Pink superknux.
-					g->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5;
-					break;
-				default:
-					break;
-				}
+			if (leveltime % 9 < 5)
+				g->mo->color = SKINCOLOR_SUPER1 + leveltime % 9;
+			else
+				g->mo->color = SKINCOLOR_SUPER1 + 9 - leveltime % 9;
 			break;
 		case GHC_INVINCIBLE: // Mario invincibility (P_CheckInvincibilityTimer)
 			g->mo->color = (UINT8)(leveltime % MAXSKINCOLORS);
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index e898d274d56a73c066f3d518f785632c957d2d0a..e54d303958d48c8741e81a5b33cf16c3b9126f66 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -3527,6 +3527,184 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v
 	return false;
 }
 
+static void HWR_DrawSpriteShadow(gr_vissprite_t *spr, GLPatch_t *gpatch, float this_scale)
+{
+	UINT8 i;
+	float tr_x, tr_y;
+	FOutVector *wv;
+	FOutVector swallVerts[4];
+	FSurfaceInfo sSurf;
+	fixed_t floorheight, mobjfloor;
+
+	mobjfloor = HWR_OpaqueFloorAtPos(
+		spr->mobj->x, spr->mobj->y,
+		spr->mobj->z, spr->mobj->height);
+	if (cv_shadowoffs.value)
+	{
+		angle_t shadowdir;
+
+		// Set direction
+		if (splitscreen && stplyr != &players[displayplayer])
+			shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value);
+		else
+			shadowdir = localangle + FixedAngle(cv_cam_rotate.value);
+
+		// Find floorheight
+		floorheight = HWR_OpaqueFloorAtPos(
+			spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
+			spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
+			spr->mobj->z, spr->mobj->height);
+
+		// The shadow is falling ABOVE it's mobj?
+		// Don't draw it, then!
+		if (spr->mobj->z < floorheight)
+			return;
+		else
+		{
+			fixed_t floorz;
+			floorz = HWR_OpaqueFloorAtPos(
+				spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight),
+				spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight),
+				spr->mobj->z, spr->mobj->height);
+			// The shadow would be falling on a wall? Don't draw it, then.
+			// Would draw midair otherwise.
+			if (floorz < floorheight)
+				return;
+		}
+
+		floorheight = FixedInt(spr->mobj->z - floorheight);
+	}
+	else
+		floorheight = FixedInt(spr->mobj->z - mobjfloor);
+
+	// create the sprite billboard
+	//
+	//  3--2
+	//  | /|
+	//  |/ |
+	//  0--1
+
+	// x1/x2 were already scaled in HWR_ProjectSprite
+	swallVerts[0].x = swallVerts[3].x = spr->x1;
+	swallVerts[2].x = swallVerts[1].x = spr->x2;
+
+	if (spr->mobj && this_scale != 1.0f)
+	{
+		// Always a pixel above the floor, perfectly flat.
+		swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3);
+
+		swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale;
+		swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale;
+	}
+	else
+	{
+		// Always a pixel above the floor, perfectly flat.
+		swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3);
+
+		// Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.)
+		swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset);
+		swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset;
+	}
+
+	// transform
+	wv = swallVerts;
+
+	for (i = 0; i < 4; i++,wv++)
+	{
+		// Offset away from the camera based on height from floor.
+		if (cv_shadowoffs.value)
+			wv->z += floorheight;
+		wv->z += 3;
+
+		//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+		tr_x = wv->z;
+		tr_y = wv->y;
+		wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
+		wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
+		// ---------------------- mega lame test ----------------------------------
+
+		//scale y before frustum so that frustum can be scaled to screen height
+		wv->y *= ORIGINAL_ASPECT * gr_fovlud;
+		wv->x *= gr_fovlud;
+	}
+
+	if (spr->flip)
+	{
+		swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s;
+		swallVerts[2].sow = swallVerts[1].sow = 0;
+	}
+	else
+	{
+		swallVerts[0].sow = swallVerts[3].sow = 0;
+		swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s;
+	}
+
+	// flip the texture coords (look familiar?)
+	if (spr->vflip)
+	{
+		swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t;
+		swallVerts[0].tow = swallVerts[1].tow = 0;
+	}
+	else
+	{
+		swallVerts[3].tow = swallVerts[2].tow = 0;
+		swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t;
+	}
+
+	sSurf.FlatColor.s.red = 0x00;
+	sSurf.FlatColor.s.blue = 0x00;
+	sSurf.FlatColor.s.green = 0x00;
+
+	/*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW)
+	{
+		sector_t *sector = spr->mobj->subsector->sector;
+		UINT8 lightlevel = 255;
+		extracolormap_t *colormap = sector->extra_colormap;
+
+		if (sector->numlights)
+		{
+			INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false);
+
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = *sector->lightlist[light].lightlevel;
+
+			if (sector->lightlist[light].extra_colormap)
+				colormap = sector->lightlist[light].extra_colormap;
+		}
+		else
+		{
+			lightlevel = sector->lightlevel;
+
+			if (sector->extra_colormap)
+				colormap = sector->extra_colormap;
+		}
+
+		if (colormap)
+			sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true);
+		else
+			sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true);
+	}*/
+
+	// shadow is always half as translucent as the sprite itself
+	if (!cv_translucency.value) // use default translucency (main sprite won't have any translucency)
+		sSurf.FlatColor.s.alpha = 0x80; // default
+	else if (spr->mobj->flags2 & MF2_SHADOW)
+		sSurf.FlatColor.s.alpha = 0x20;
+	else if (spr->mobj->frame & FF_TRANSMASK)
+	{
+		HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf);
+		sSurf.FlatColor.s.alpha /= 2; //cut alpha in half!
+	}
+	else
+		sSurf.FlatColor.s.alpha = 0x80; // default
+
+	if (sSurf.FlatColor.s.alpha > floorheight/4)
+	{
+		sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4);
+		HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
+	}
+}
+
 // -----------------+
 // HWR_DrawSprite   : Draw flat sprites
 //                  : (monsters, bonuses, weapons, lights, ...)
@@ -3629,7 +3807,7 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 
 	// Draw shadow BEFORE sprite
 	if (cv_shadow.value // Shadows enabled
-		&& !(spr->mobj->flags & MF_SCENERY && spr->mobj->flags & MF_SPAWNCEILING && spr->mobj->flags & MF_NOGRAVITY) // Ceiling scenery have no shadow.
+		&& (spr->mobj->flags & (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY)) != (MF_SCENERY|MF_SPAWNCEILING|MF_NOGRAVITY) // Ceiling scenery have no shadow.
 		&& !(spr->mobj->flags2 & MF2_DEBRIS) // Debris have no corona or shadow.
 #ifdef ALAM_LIGHTING
 		&& !(t_lspr[spr->mobj->sprite]->type // Things with dynamic lights have no shadow.
@@ -3640,187 +3818,9 @@ static void HWR_DrawSprite(gr_vissprite_t *spr)
 		////////////////////
 		// SHADOW SPRITE! //
 		////////////////////
-		FOutVector swallVerts[4];
-		FSurfaceInfo sSurf;
-		fixed_t floorheight, mobjfloor;
-
-		mobjfloor = HWR_OpaqueFloorAtPos(
-			spr->mobj->x, spr->mobj->y,
-			spr->mobj->z, spr->mobj->height);
-		if (cv_shadowoffs.value)
-		{
-			angle_t shadowdir;
-
-			// Set direction
-			if (splitscreen && stplyr != &players[displayplayer])
-				shadowdir = localangle2 + FixedAngle(cv_cam2_rotate.value);
-			else
-				shadowdir = localangle + FixedAngle(cv_cam_rotate.value);
-
-			// Find floorheight
-			floorheight = HWR_OpaqueFloorAtPos(
-				spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
-				spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - mobjfloor),
-				spr->mobj->z, spr->mobj->height);
-
-			// The shadow is falling ABOVE it's mobj?
-			// Don't draw it, then!
-			if (spr->mobj->z < floorheight)
-				goto noshadow;
-			else
-			{
-				fixed_t floorz;
-				floorz = HWR_OpaqueFloorAtPos(
-					spr->mobj->x + P_ReturnThrustX(spr->mobj, shadowdir, spr->mobj->z - floorheight),
-					spr->mobj->y + P_ReturnThrustY(spr->mobj, shadowdir, spr->mobj->z - floorheight),
-					spr->mobj->z, spr->mobj->height);
-				// The shadow would be falling on a wall? Don't draw it, then.
-				// Would draw midair otherwise.
-				if (floorz < floorheight)
-					goto noshadow;
-			}
-
-			floorheight = FixedInt(spr->mobj->z - floorheight);
-		}
-		else
-			floorheight = FixedInt(spr->mobj->z - mobjfloor);
-
-		// create the sprite billboard
-		//
-		//  3--2
-		//  | /|
-		//  |/ |
-		//  0--1
-
-		// x1/x2 were already scaled in HWR_ProjectSprite
-		swallVerts[0].x = swallVerts[3].x = spr->x1;
-		swallVerts[2].x = swallVerts[1].x = spr->x2;
-
-		if (spr->mobj && this_scale != 1.0f)
-		{
-			// Always a pixel above the floor, perfectly flat.
-			swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset * this_scale - (floorheight+3);
-
-			swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset) * this_scale;
-			swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset * this_scale;
-		}
-		else
-		{
-			// Always a pixel above the floor, perfectly flat.
-			swallVerts[0].y = swallVerts[1].y = swallVerts[2].y = swallVerts[3].y = spr->ty - gpatch->topoffset - (floorheight+3);
-
-			// Spread out top away from the camera. (Fixme: Make it always move out in the same direction!... somehow.)
-			swallVerts[0].z = swallVerts[1].z = spr->tz - (gpatch->height-gpatch->topoffset);
-			swallVerts[2].z = swallVerts[3].z = spr->tz + gpatch->topoffset;
-		}
-
-		// transform
-		wv = swallVerts;
-
-		for (i = 0; i < 4; i++,wv++)
-		{
-			// Offset away from the camera based on height from floor.
-			if (cv_shadowoffs.value)
-				wv->z += floorheight;
-			wv->z += 3;
-
-			//look up/down ----TOTAL SUCKS!!!--- do the 2 in one!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-			tr_x = wv->z;
-			tr_y = wv->y;
-			wv->y = (tr_x * gr_viewludcos) + (tr_y * gr_viewludsin);
-			wv->z = (tr_x * gr_viewludsin) - (tr_y * gr_viewludcos);
-			// ---------------------- mega lame test ----------------------------------
-
-			//scale y before frustum so that frustum can be scaled to screen height
-			wv->y *= ORIGINAL_ASPECT * gr_fovlud;
-			wv->x *= gr_fovlud;
-		}
-
-		if (spr->flip)
-		{
-			swallVerts[0].sow = swallVerts[3].sow = gpatch->max_s;
-			swallVerts[2].sow = swallVerts[1].sow = 0;
-		}
-		else
-		{
-			swallVerts[0].sow = swallVerts[3].sow = 0;
-			swallVerts[2].sow = swallVerts[1].sow = gpatch->max_s;
-		}
-
-		// flip the texture coords (look familiar?)
-		if (spr->vflip)
-		{
-			swallVerts[3].tow = swallVerts[2].tow = gpatch->max_t;
-			swallVerts[0].tow = swallVerts[1].tow = 0;
-		}
-		else
-		{
-			swallVerts[3].tow = swallVerts[2].tow = 0;
-			swallVerts[0].tow = swallVerts[1].tow = gpatch->max_t;
-		}
-
-		sSurf.FlatColor.s.red = 0x00;
-		sSurf.FlatColor.s.blue = 0x00;
-		sSurf.FlatColor.s.green = 0x00;
-
-		/*if (spr->mobj->frame & FF_TRANSMASK || spr->mobj->flags2 & MF2_SHADOW)
-		{
-			sector_t *sector = spr->mobj->subsector->sector;
-			UINT8 lightlevel = sector->lightlevel;
-			extracolormap_t *colormap = sector->extra_colormap;
-
-			if (sector->numlights)
-			{
-				INT32 light = R_GetPlaneLight(sector, spr->mobj->floorz, false);
-
-				if (!(spr->mobj->frame & FF_FULLBRIGHT))
-					lightlevel = *sector->lightlist[light].lightlevel;
-				else
-					lightlevel = 255;
-
-				if (sector->lightlist[light].extra_colormap)
-					colormap = sector->lightlist[light].extra_colormap;
-			}
-			else
-			{
-				lightlevel = sector->lightlevel;
-
-				if (sector->extra_colormap)
-					colormap = sector->extra_colormap;
-			}
-
-			if (colormap)
-				sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, colormap->rgba, colormap->fadergba, false, true);
-			else
-				sSurf.FlatColor.rgba = HWR_Lighting(lightlevel/2, NORMALFOG, FADEFOG, false, true);
-		}*/
-
-		// shadow is always half as translucent as the sprite itself
-		if (!cv_translucency.value)
-			; // translucency disabled
-		else if (spr->mobj->flags2 & MF2_SHADOW)
-			sSurf.FlatColor.s.alpha = 0x20;
-		else if (spr->mobj->frame & FF_TRANSMASK)
-		{
-			HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &sSurf);
-			sSurf.FlatColor.s.alpha /= 2; //cut alpha in half!
-		}
-		else
-			sSurf.FlatColor.s.alpha = 0x80; // default
-
-		/// \todo do the test earlier
-		if (!cv_grmd2.value || (md2_models[spr->mobj->sprite].scale < 0.0f) || (md2_models[spr->mobj->sprite].notfound = true) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound = true))
-		{
-			if (sSurf.FlatColor.s.alpha > floorheight/4)
-			{
-				sSurf.FlatColor.s.alpha = (UINT8)(sSurf.FlatColor.s.alpha - floorheight/4);
-				HWD.pfnDrawPolygon(&sSurf, swallVerts, 4, PF_Translucent|PF_Modulated|PF_Clip);
-			}
-		}
+		HWR_DrawSpriteShadow(spr, gpatch, this_scale);
 	}
 
-noshadow:
-
 	// This needs to be AFTER the shadows so that the regular sprites aren't drawn completely black.
 	// sprite lighting by modulating the RGB components
 	/// \todo coloured
@@ -3828,7 +3828,7 @@ noshadow:
 	// colormap test
 	{
 		sector_t *sector = spr->mobj->subsector->sector;
-		UINT8 lightlevel = sector->lightlevel;
+		UINT8 lightlevel = 255;
 		extracolormap_t *colormap = sector->extra_colormap;
 
 		if (sector->numlights)
@@ -3839,8 +3839,6 @@ noshadow:
 
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
 				lightlevel = *sector->lightlist[light].lightlevel;
-			else
-				lightlevel = 255;
 
 			if (sector->lightlist[light].extra_colormap)
 				colormap = sector->lightlist[light].extra_colormap;
@@ -3849,27 +3847,25 @@ noshadow:
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
 				lightlevel = sector->lightlevel;
-			else
-				lightlevel = 255;
 
 			if (sector->extra_colormap)
 				colormap = sector->extra_colormap;
 		}
 
-		if (spr->mobj->frame & FF_FULLBRIGHT)
-			lightlevel = 255;
-
 		if (colormap)
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
 		else
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
 	}
 
-	/// \todo do the test earlier
-	if (!cv_grmd2.value || (md2_models[spr->mobj->sprite].scale < 0.0f))
 	{
 		FBITFIELD blend = 0;
-		if (spr->mobj->flags2 & MF2_SHADOW)
+		if (!cv_translucency.value) // translucency disabled
+		{
+			Surf.FlatColor.s.alpha = 0xFF;
+			blend = PF_Translucent|PF_Occlude;
+		}
+		else if (spr->mobj->flags2 & MF2_SHADOW)
 		{
 			Surf.FlatColor.s.alpha = 0x40;
 			blend = PF_Translucent;
@@ -4391,10 +4387,10 @@ static void HWR_DrawSprites(void)
 #endif
 				if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
 				{
-					if (!cv_grmd2.value || (cv_grmd2.value && md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == true))
+					if (!cv_grmd2.value || md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound || md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale < 0.0f)
 						HWR_DrawSprite(spr);
 				}
-				else if (!cv_grmd2.value || (cv_grmd2.value && md2_models[spr->mobj->sprite].notfound == true))
+				else if (!cv_grmd2.value || md2_models[spr->mobj->sprite].notfound || md2_models[spr->mobj->sprite].scale < 0.0f)
 					HWR_DrawSprite(spr);
 		}
 	}
@@ -4420,7 +4416,7 @@ static void HWR_DrawMD2S(void)
 #endif
 				if (spr->mobj && spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
 				{
-					if ((md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false) && (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f))
+					if (md2_playermodels[(skin_t*)spr->mobj->skin-skins].notfound == false && md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)
 						HWR_DrawMD2(spr);
 				}
 				else if (md2_models[spr->mobj->sprite].notfound == false && md2_models[spr->mobj->sprite].scale > 0.0f)
@@ -4462,23 +4458,12 @@ static void HWR_AddSprites(sector_t *sec)
 	// If a limit exists, handle things a tiny bit different.
 	if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS))
 	{
-		if (!players[displayplayer].mo)
-			return; // Draw nothing if no player.
-			// todo: is this really the best option for this situation?
-
 		for (thing = sec->thinglist; thing; thing = thing->snext)
 		{
 			if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
 				continue;
 
-			approx_dist = P_AproxDistance(
-				players[displayplayer].mo->x - thing->x,
-				players[displayplayer].mo->y - thing->y);
-
-			if (splitscreen && approx_dist > limit_dist && players[secondarydisplayplayer].mo)
-				approx_dist = P_AproxDistance(
-					players[secondarydisplayplayer].mo->x - thing->x,
-					players[secondarydisplayplayer].mo->y - thing->y);
+			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
 			if (approx_dist <= limit_dist)
 				HWR_ProjectSprite(thing);
@@ -4496,23 +4481,12 @@ static void HWR_AddSprites(sector_t *sec)
 	// Someone seriously wants infinite draw distance for precipitation?
 	if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
 	{
-		if (!players[displayplayer].mo)
-			return; // Draw nothing if no player.
-			// todo: is this really the best option for this situation?
-
 		for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
 		{
-			if (precipthing->invisible)
+			if (precipthing->precipflags & PCF_INVISIBLE)
 				continue;
 
-			approx_dist = P_AproxDistance(
-				players[displayplayer].mo->x - precipthing->x,
-				players[displayplayer].mo->y - precipthing->y);
-
-			if (splitscreen && approx_dist > limit_dist && players[secondarydisplayplayer].mo)
-				approx_dist = P_AproxDistance(
-					players[secondarydisplayplayer].mo->x - precipthing->x,
-					players[secondarydisplayplayer].mo->y - precipthing->y);
+			approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
 
 			if (approx_dist <= limit_dist)
 				HWR_ProjectPrecipitationSprite(precipthing);
@@ -4522,7 +4496,7 @@ static void HWR_AddSprites(sector_t *sec)
 	{
 		// Draw everything in sector, no checks
 		for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
-			if (!precipthing->invisible)
+			if (!(precipthing->precipflags & PCF_INVISIBLE))
 				HWR_ProjectPrecipitationSprite(precipthing);
 	}
 #endif
@@ -4583,10 +4557,11 @@ static void HWR_ProjectSprite(mobj_t *thing)
 
 	if (rot >= sprdef->numframes)
 	{
-		CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
+		CONS_Alert(CONS_ERROR, M_GetText("HWR_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
 			sizeu1(rot), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
 		thing->sprite = states[S_UNKNOWN].sprite;
 		thing->frame = states[S_UNKNOWN].frame;
+		sprdef = &sprites[thing->sprite];
 		rot = thing->frame&FF_FRAMEMASK;
 		thing->state->sprite = thing->sprite;
 		thing->state->frame = thing->frame;
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 02f5053515af59e01cd77c3543ab93d21e19eebf..de648f1b90eb6fabb9c1a25ccc081a5b93ad41ff 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -921,24 +921,25 @@ void HWR_InitMD2(void)
 	}
 	while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
 	{
+		if (stricmp(name, "PLAY") == 0)
+		{
+			CONS_Printf("MD2 for sprite PLAY detected in md2.dat, use a player skin instead!\n");
+			continue;
+		}
+	
 		for (i = 0; i < NUMSPRITES; i++)
 		{
 			if (stricmp(name, sprnames[i]) == 0)
 			{
-				if (stricmp(name, "PLAY") == 0)
-					continue;
+				//if (stricmp(name, "PLAY") == 0)
+					//continue;
 
 				//CONS_Debug(DBG_RENDER, "  Found: %s %s %f %f\n", name, filename, scale, offset);
 				md2_models[i].scale = scale;
 				md2_models[i].offset = offset;
 				md2_models[i].notfound = false;
 				strcpy(md2_models[i].filename, filename);
-				break;
-			}
-			if (i == NUMSPRITES)
-			{
-				CONS_Printf("MD2 for sprite %s not found\n", name);
-				md2_models[i].notfound = true;
+				goto md2found;
 			}
 		}
 
@@ -952,15 +953,14 @@ void HWR_InitMD2(void)
 				md2_playermodels[s].offset = offset;
 				md2_playermodels[s].notfound = false;
 				strcpy(md2_playermodels[s].filename, filename);
-				break;
-			}
-			if (s == MAXSKINS-1)
-			{
-				CONS_Printf("MD2 for player skin %s not found\n", name);
-				md2_playermodels[s].notfound = true;
+				goto md2found;
 			}
 		}
-
+		// no sprite/player skin name found?!?
+		CONS_Printf("Unknown sprite/player skin %s detected in md2.dat\n", name);
+md2found:
+		// move on to next line...
+		continue;
 	}
 	fclose(f);
 }
@@ -996,17 +996,14 @@ void HWR_AddPlayerMD2(int skin) // For MD2's that were added after startup
 			md2_playermodels[skin].offset = offset;
 			md2_playermodels[skin].notfound = false;
 			strcpy(md2_playermodels[skin].filename, filename);
-			break;
-		}
-		if (skin == MAXSKINS-1)
-		{
-			CONS_Printf("MD2 for player skin %s not found\n", name);
-			md2_playermodels[skin].notfound = true;
+			goto playermd2found;
 		}
 	}
 
+	//CONS_Printf("MD2 for player skin %s not found\n", skins[skin].name);
+	md2_playermodels[skin].notfound = true;
+playermd2found:
 	fclose(f);
-
 }
 
 
@@ -1021,6 +1018,9 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu
 	if (nomd2s)
 		return;
 
+	if (spritenum == SPR_PLAY) // Handled already NEWMD2: Per sprite, per-skin check
+		return;
+
 	// Read the md2.dat file
 	f = fopen("md2.dat", "rt");
 
@@ -1034,27 +1034,19 @@ void HWR_AddSpriteMD2(size_t spritenum) // For MD2s that were added after startu
 	// Check for any MD2s that match the names of player skins!
 	while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4)
 	{
+		if (stricmp(name, sprnames[spritenum]) == 0)
 		{
-			if (stricmp(name, sprnames[spritenum]) == 0)
-			{
-				if (stricmp(name, "PLAY") == 0) // Handled already NEWMD2: Per sprite, per-skin check
-					continue;
-
-				md2_models[spritenum].scale = scale;
-				md2_models[spritenum].offset = offset;
-				md2_models[spritenum].notfound = false;
-				strcpy(md2_models[spritenum].filename, filename);
-				break;
-			}
-
-			if (spritenum == NUMSPRITES-1)
-			{
-				CONS_Printf("MD2 for sprite %s not found\n", name);
-				md2_models[spritenum].notfound = true;
-			}
+			md2_models[spritenum].scale = scale;
+			md2_models[spritenum].offset = offset;
+			md2_models[spritenum].notfound = false;
+			strcpy(md2_models[spritenum].filename, filename);
+			goto spritemd2found;
 		}
 	}
 
+	//CONS_Printf("MD2 for sprite %s not found\n", sprnames[spritenum]);
+	md2_models[spritenum].notfound = true;
+spritemd2found:
 	fclose(f);
 }
 
@@ -1090,11 +1082,17 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 	md2_t *md2;
 	UINT8 color[4];
 
+	if (!cv_grmd2.value)
+		return;
+
+	if (!spr->precip)
+		return;
+
 	// MD2 colormap fix
 	// colormap test
 	{
 		sector_t *sector = spr->mobj->subsector->sector;
-		UINT8 lightlevel = sector->lightlevel;
+		UINT8 lightlevel = 255;
 		extracolormap_t *colormap = sector->extra_colormap;
 
 		if (sector->numlights)
@@ -1105,8 +1103,6 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
 				lightlevel = *sector->lightlist[light].lightlevel;
-			else
-				lightlevel = 255;
 
 			if (sector->lightlist[light].extra_colormap)
 				colormap = sector->lightlist[light].extra_colormap;
@@ -1115,24 +1111,18 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		{
 			if (!(spr->mobj->frame & FF_FULLBRIGHT))
 				lightlevel = sector->lightlevel;
-			else
-				lightlevel = 255;
 
 			if (sector->extra_colormap)
 				colormap = sector->extra_colormap;
 		}
 
-		if (spr->mobj->frame & FF_FULLBRIGHT)
-			lightlevel = 255;
-
 		if (colormap)
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
 		else
 			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
 	}
 
-	// Look at HWR_ProjetctSprite for more
-	if (cv_grmd2.value && ((md2_models[spr->mobj->sprite].scale > 0.0f) || (md2_playermodels[(skin_t*)spr->mobj->skin-skins].scale > 0.0f)) && !spr->precip)
+	// Look at HWR_ProjectSprite for more
 	{
 		GLPatch_t *gpatch;
 		INT32 *buff;
@@ -1149,15 +1139,11 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 			//durs = tics;
 
 		if (spr->mobj->flags2 & MF2_SHADOW)
-		{
 			Surf.FlatColor.s.alpha = 0x40;
-		}
 		else if (spr->mobj->frame & FF_TRANSMASK)
 			HWR_TranstableToAlpha((spr->mobj->frame & FF_TRANSMASK)>>FF_TRANSSHIFT, &Surf);
 		else
-		{
 			Surf.FlatColor.s.alpha = 0xFF;
-		}
 
 		// dont forget to enabled the depth test because we can't do this like
 		// before: polygons models are not sorted
@@ -1263,8 +1249,6 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 			p.flip = false;
 
 		HWD.pfnDrawMD2i(buff, curr, durs, tics, next, &p, finalscale, flip, color);
-
-
 	}
 }
 
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index fd4261bcefd1a973343130c65217081795f3737e..f84b0e235f7b74fc376d51c87c7f9d7421828e7d 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -1919,6 +1919,13 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
     }
 
 
+	// Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?!
+	if (color[3] < 255)
+	{
+		pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
+		pglDepthMask(GL_FALSE);
+	}
+
 	val = *gl_cmd_buffer++;
 
 	while (val != 0)
diff --git a/src/info.c b/src/info.c
index fb30258c31b2ab85a813a3cc9d21d29df3bd58d3..9e04b4e342f4027b0a319f6bcfaaaf35a8ea035b 100644
--- a/src/info.c
+++ b/src/info.c
@@ -150,8 +150,7 @@ state_t states[NUMSTATES] =
 	{SPR_PLAY, 34, 1, {NULL}, 0, 24, S_PLAY_SIGN},         // S_PLAY_SIGN
 
 	// Blue Crawla
-	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND2},   // S_POSS_STND
-	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},    // S_POSS_STND2
+	{SPR_POSS, 0, 5, {A_Look}, 0, 0, S_POSS_STND},   // S_POSS_STND
 	{SPR_POSS, 0, 3, {A_Chase}, 0, 0, S_POSS_RUN2},   // S_POSS_RUN1
 	{SPR_POSS, 1, 3, {A_Chase}, 0, 0, S_POSS_RUN3},   // S_POSS_RUN2
 	{SPR_POSS, 2, 3, {A_Chase}, 0, 0, S_POSS_RUN4},   // S_POSS_RUN3
@@ -160,8 +159,7 @@ state_t states[NUMSTATES] =
 	{SPR_POSS, 5, 3, {A_Chase}, 0, 0, S_POSS_RUN1},   // S_POSS_RUN6
 
 	// Red Crawla
-	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND2},   // S_SPOS_STND
-	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND},    // S_SPOS_STND2
+	{SPR_SPOS, 0, 5, {A_Look}, 0, 0, S_SPOS_STND},   // S_SPOS_STND
 	{SPR_SPOS, 0, 1, {A_Chase}, 0, 0, S_SPOS_RUN2},   // S_SPOS_RUN1
 	{SPR_SPOS, 1, 1, {A_Chase}, 0, 0, S_SPOS_RUN3},   // S_SPOS_RUN2
 	{SPR_SPOS, 2, 1, {A_Chase}, 0, 0, S_SPOS_RUN4},   // S_SPOS_RUN3
diff --git a/src/info.h b/src/info.h
index 0c73281df34d7061803ac16f0aa23cd0d0c70dab..03726260b0b3261f83219951f1ae620306553598 100644
--- a/src/info.h
+++ b/src/info.h
@@ -663,7 +663,6 @@ typedef enum state
 
 	// Blue Crawla
 	S_POSS_STND,
-	S_POSS_STND2,
 	S_POSS_RUN1,
 	S_POSS_RUN2,
 	S_POSS_RUN3,
@@ -673,7 +672,6 @@ typedef enum state
 
 	// Red Crawla
 	S_SPOS_STND,
-	S_SPOS_STND2,
 	S_SPOS_RUN1,
 	S_SPOS_RUN2,
 	S_SPOS_RUN3,
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 19390d50df00d5b811b330b349949726399ac884..86ff11337a6fcd02e763da75ee612eb5ee789d1d 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -126,8 +126,6 @@ static const char *const widtht_opt[] = {
 enum cameraf {
 	camera_chase = 0,
 	camera_aiming,
-	camera_viewheight,
-	camera_startangle,
 	camera_x,
 	camera_y,
 	camera_z,
@@ -137,7 +135,6 @@ enum cameraf {
 	camera_ceilingz,
 	camera_radius,
 	camera_height,
-	camera_relativex,
 	camera_momx,
 	camera_momy,
 	camera_momz
@@ -147,8 +144,6 @@ enum cameraf {
 static const char *const camera_opt[] = {
 	"chase",
 	"aiming",
-	"viewheight",
-	"startangle",
 	"x",
 	"y",
 	"z",
@@ -158,7 +153,6 @@ static const char *const camera_opt[] = {
 	"ceilingz",
 	"radius",
 	"height",
-	"relativex",
 	"momx",
 	"momy",
 	"momz",
@@ -279,12 +273,6 @@ static int camera_get(lua_State *L)
 	case camera_aiming:
 		lua_pushinteger(L, cam->aiming);
 		break;
-	case camera_viewheight:
-		lua_pushinteger(L, cam->viewheight);
-		break;
-	case camera_startangle:
-		lua_pushinteger(L, cam->startangle);
-		break;
 	case camera_x:
 		lua_pushinteger(L, cam->x);
 		break;
@@ -312,9 +300,6 @@ static int camera_get(lua_State *L)
 	case camera_height:
 		lua_pushinteger(L, cam->height);
 		break;
-	case camera_relativex:
-		lua_pushinteger(L, cam->relativex);
-		break;
 	case camera_momx:
 		lua_pushinteger(L, cam->momx);
 		break;
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 80f66ed60543c3607e184594c25b705c82d5a30a..e5cc30c12571a3ce8f047f257add6fb0bf062841 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -60,7 +60,6 @@ enum subsector_e {
 	subsector_sector,
 	subsector_numlines,
 	subsector_firstline,
-	subsector_validcount
 };
 
 static const char *const subsector_opt[] = {
@@ -68,7 +67,6 @@ static const char *const subsector_opt[] = {
 	"sector",
 	"numlines",
 	"firstline",
-	"validcount",
 	NULL};
 
 enum line_e {
@@ -86,7 +84,6 @@ enum line_e {
 	line_slopetype,
 	line_frontsector,
 	line_backsector,
-	line_validcount,
 	line_firsttag,
 	line_nexttag,
 	line_text,
@@ -108,7 +105,6 @@ static const char *const line_opt[] = {
 	"slopetype",
 	"frontsector",
 	"backsector",
-	"validcount",
 	"firsttag",
 	"nexttag",
 	"text",
@@ -476,9 +472,6 @@ static int subsector_get(lua_State *L)
 	case subsector_firstline:
 		lua_pushinteger(L, subsector->firstline);
 		return 1;
-	case subsector_validcount:
-		lua_pushinteger(L, subsector->validcount);
-		return 1;
 	}
 	return 0;
 }
@@ -564,9 +557,6 @@ static int line_get(lua_State *L)
 	case line_backsector:
 		LUA_PushUserdata(L, line->backsector, META_SECTOR);
 		return 1;
-	case line_validcount:
-		lua_pushinteger(L, line->validcount);
-		return 1;
 	case line_firsttag:
 		lua_pushinteger(L, line->firsttag);
 		return 1;
diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c
index f455edf1fe79ded82228a4b3b03e859b4986e3ce..cf4db8f398aee2e765f51560a47001eabcd31202 100644
--- a/src/lua_mobjlib.c
+++ b/src/lua_mobjlib.c
@@ -500,7 +500,7 @@ static int mobj_set(lua_State *L)
 		return luaL_error(L, "mobj.skin '%s' not found!", skin);
 	}
 	case mobj_color:
-		mo->color = ((UINT8)luaL_checkinteger(L, 3)) % MAXSKINCOLORS;
+		mo->color = ((UINT8)luaL_checkinteger(L, 3)) % MAXTRANSLATIONS;
 		break;
 	case mobj_bnext:
 		return NOSETPOS;
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 8cea4c6ae1ea743e6d998792c550977d1252a70d..bc32e6cfab9b964e7c5cd974805de75d18fe7e61 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -91,6 +91,33 @@ static UINT8 cheatf_warp(void)
 	return 1;
 }
 
+#ifdef DEVELOP
+static UINT8 cheatf_devmode(void)
+{
+	UINT8 i;
+
+	if (modifiedgame)
+		return 0;
+
+	if (menuactive && currentMenu != &MainDef)
+		return 0; // Only on the main menu!
+
+	S_StartSound(0, sfx_itemup);
+
+	// Just unlock all the things and turn on -debug and console devmode.
+	G_SetGameModified(false);
+	for (i = 0; i < MAXUNLOCKABLES; i++)
+		unlockables[i].unlocked = true;
+	devparm = TRUE;
+	cv_debug |= 0x8000;
+
+	// Refresh secrets menu existing.
+	M_ClearMenus(true);
+	M_StartControlPanel();
+	return 1;
+}
+#endif
+
 static cheatseq_t cheat_ultimate = {
 	0, cheatf_ultimate,
 	{ SCRAMBLE('u'), SCRAMBLE('l'), SCRAMBLE('t'), SCRAMBLE('i'), SCRAMBLE('m'), SCRAMBLE('a'), SCRAMBLE('t'), SCRAMBLE('e'), 0xff }
@@ -115,6 +142,14 @@ static cheatseq_t cheat_warp_joy = {
 	  SCRAMBLE(KEY_LEFTARROW), SCRAMBLE(KEY_UPARROW),
 	  SCRAMBLE(KEY_ENTER), 0xff }
 };
+
+#ifdef DEVELOP
+static cheatseq_t cheat_devmode = {
+	0, cheatf_devmode,
+	{ SCRAMBLE('d'), SCRAMBLE('e'), SCRAMBLE('v'), SCRAMBLE('m'), SCRAMBLE('o'), SCRAMBLE('d'), SCRAMBLE('e'), 0xff }
+};
+#endif
+
 // ==========================================================================
 //                        CHEAT SEQUENCE PACKAGE
 // ==========================================================================
@@ -221,6 +256,9 @@ boolean cht_Responder(event_t *ev)
 	ret += cht_CheckCheat(&cheat_ultimate_joy, (char)ch);
 	ret += cht_CheckCheat(&cheat_warp, (char)ch);
 	ret += cht_CheckCheat(&cheat_warp_joy, (char)ch);
+#ifdef DEVELOP
+	ret += cht_CheckCheat(&cheat_devmode, (char)ch);
+#endif
 	return (ret != 0);
 }
 
diff --git a/src/m_fixed.c b/src/m_fixed.c
index 25a25a96695dd8c7d020d22f6af57bdd2452be7f..739265aa272c9aa9179fa58840111b6e03f249a9 100644
--- a/src/m_fixed.c
+++ b/src/m_fixed.c
@@ -119,7 +119,7 @@ fixed_t FixedHypot(fixed_t x, fixed_t y)
 	return FixedMul(ax, yx1); // |x|*((1 + (x/y)^2)^1/2)
 }
 
-#ifdef NEED_FIXED_VECTOR
+#if 1 //#ifdef NEED_FIXED_VECTOR
 
 vector2_t *FV2_Load(vector2_t *vec, fixed_t x, fixed_t y)
 {
diff --git a/src/m_fixed.h b/src/m_fixed.h
index e68de03080fb4a3de8342ff6f0d8d1c4fab953c8..53962269be8d92f087ddc4ba9fe8a7015f3e111f 100644
--- a/src/m_fixed.h
+++ b/src/m_fixed.h
@@ -357,7 +357,8 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
 	return INT32_MAX;
 }
 
-#ifdef NEED_FIXED_VECTOR
+
+#if 1//#ifdef NEED_FIXED_VECTOR
 
 typedef struct
 {
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 18a4ec5ff415be7bee7f5b828fca47ece86ac247..369b6f0c8fcb88f55c7ae5a8b472a9f3ada18869 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -363,12 +363,12 @@ boolean P_CheckMissileRange(mobj_t *actor)
 	if (!actor->target)
 		return false;
 
-	if (!P_CheckSight(actor, actor->target))
-		return false;
-
 	if (actor->reactiontime)
 		return false; // do not attack yet
 
+	if (!P_CheckSight(actor, actor->target))
+		return false;
+
 	// OPTIMIZE: get this from a global checksight
 	dist = P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) - FixedMul(64*FRACUNIT, actor->scale);
 
@@ -652,6 +652,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
 
 		player = &players[actor->lastlook];
 
+		if ((netgame || multiplayer) && player->spectator)
+			continue;
+
 		if (player->health <= 0)
 			continue; // dead
 
@@ -661,12 +664,6 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
 		if (!player->mo || P_MobjWasRemoved(player->mo))
 			continue;
 
-		if (!P_CheckSight(actor, player->mo))
-			continue; // out of sight
-
-		if ((netgame || multiplayer) && player->spectator)
-			continue;
-
 		if (dist > 0
 			&& P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist)
 			continue; // Too far away
@@ -683,6 +680,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
 			}
 		}
 
+		if (!P_CheckSight(actor, player->mo))
+			continue; // out of sight
+
 		if (tracer)
 			P_SetTarget(&actor->tracer, player->mo);
 		else
@@ -5024,7 +5024,7 @@ void A_MaceRotate(mobj_t *actor)
 		actor->movecount += actor->target->lastlook;
 		actor->movecount &= FINEMASK;
 
-		actor->threshold = FixedMul(FINECOSINE(actor->movecount), actor->target->lastlook);
+		actor->threshold = FixedMul(FINECOSINE(actor->movecount), actor->target->lastlook << FRACBITS);
 
 		v[0] = FRACUNIT;
 		v[1] = 0;
@@ -5032,7 +5032,7 @@ void A_MaceRotate(mobj_t *actor)
 		v[3] = FRACUNIT;
 
 		// Calculate the angle matrixes for the link.
-		res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->threshold << FRACBITS)));
+		res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(actor->threshold)));
 		M_Memcpy(&v, res, sizeof(v));
 		res = VectorMatrixMultiply(v, *RotateZMatrix(actor->target->health << ANGLETOFINESHIFT));
 		M_Memcpy(&v, res, sizeof(v));
@@ -5606,8 +5606,13 @@ void A_MixUp(mobj_t *actor)
 
 				P_SetThingPosition(players[i].mo);
 
+#ifdef ESLOPE
+				players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
+				players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
+#else
 				players[i].mo->floorz = players[i].mo->subsector->sector->floorheight;
 				players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight;
+#endif
 
 				P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y);
 			}
@@ -5660,6 +5665,11 @@ void A_RecyclePowers(mobj_t *actor)
 		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
 			&& !players[i].exiting && !((netgame || multiplayer) && players[i].spectator))
 		{
+#ifndef WEIGHTEDRECYCLER
+			if (players[i].powers[pw_super])
+				continue; // Ignore super players
+#endif
+
 			numplayers++;
 			postscramble[j] = playerslist[j] = (UINT8)i;
 
diff --git a/src/p_floor.c b/src/p_floor.c
index f798174ad83850e9664e781bc43f94116234812d..b8d3f7b5e0098605bb44dd37e4e25dfca6d4d81b 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1174,12 +1174,15 @@ void T_SpikeSector(levelspecthink_t *spikes)
 
 		if (affectsec == spikes->sector) // Applied to an actual sector
 		{
+			fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, affectsec);
+			fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, affectsec);
+
 			if (affectsec->flags & SF_FLIPSPECIAL_FLOOR)
 			{
 				if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0)
 					continue;
 
-				if (thing->z == affectsec->floorheight)
+				if (thing->z == affectfloor)
 					dothepain = true;
 			}
 
@@ -1188,18 +1191,20 @@ void T_SpikeSector(levelspecthink_t *spikes)
 				if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0)
 					continue;
 
-				if (thing->z + thing->height == affectsec->ceilingheight)
+				if (thing->z + thing->height == affectceil)
 					dothepain = true;
 			}
 		}
 		else
 		{
+			fixed_t affectfloor = P_GetSpecialBottomZ(thing, affectsec, spikes->sector);
+			fixed_t affectceil = P_GetSpecialTopZ(thing, affectsec, spikes->sector);
 			if (affectsec->flags & SF_FLIPSPECIAL_FLOOR)
 			{
 				if (!(thing->eflags & MFE_VERTICALFLIP) && thing->momz > 0)
 					continue;
 
-				if (thing->z == affectsec->ceilingheight)
+				if (thing->z == affectceil)
 					dothepain = true;
 			}
 
@@ -1208,7 +1213,7 @@ void T_SpikeSector(levelspecthink_t *spikes)
 				if ((thing->eflags & MFE_VERTICALFLIP) && thing->momz < 0)
 					continue;
 
-				if (thing->z + thing->height == affectsec->floorheight)
+				if (thing->z + thing->height == affectfloor)
 					dothepain = true;
 			}
 		}
@@ -1968,51 +1973,71 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
 {
 	size_t i;
 	fixed_t upperbound, lowerbound;
-	INT32 s;
-	sector_t *checksector;
+	sector_t *sec = NULL;
+	sector_t *targetsec = NULL;
+	INT32 secnum = -1;
 	msecnode_t *node;
 	mobj_t *thing;
-	boolean exists = false;
+	boolean FOFsector = false;
 
-	for (i = 0; i < nobaddies->sector->linecount; i++)
+	while ((secnum = P_FindSectorFromLineTag(nobaddies->sourceline, secnum)) >= 0)
 	{
-		if (nobaddies->sector->lines[i]->special == 223)
+		sec = &sectors[secnum];
+
+		FOFsector = false;
+
+		// Check the lines of this sector, to see if it is a FOF control sector.
+		for (i = 0; i < sec->linecount; i++)
 		{
+			INT32 targetsecnum = -1;
+
+			if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300)
+				continue;
 
-			upperbound = nobaddies->sector->ceilingheight;
-			lowerbound = nobaddies->sector->floorheight;
+			FOFsector = true;
 
-			for (s = -1; (s = P_FindSectorFromLineTag(nobaddies->sector->lines[i], s)) >= 0 ;)
+			while ((targetsecnum = P_FindSectorFromLineTag(sec->lines[i], targetsecnum)) >= 0)
 			{
-				checksector = &sectors[s];
+				targetsec = &sectors[targetsecnum];
 
-				node = checksector->touching_thinglist; // things touching this sector
+				upperbound = targetsec->ceilingheight;
+				lowerbound = targetsec->floorheight;
+				node = targetsec->touching_thinglist; // things touching this sector
 				while (node)
 				{
 					thing = node->m_thing;
 
 					if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0
-						&& thing->z < upperbound && thing->z+thing->height > lowerbound)
-					{
-						exists = true;
-						goto foundenemy;
-					}
+					&& thing->z < upperbound && thing->z+thing->height > lowerbound)
+						return;
 
 					node = node->m_snext;
 				}
 			}
 		}
-	}
-foundenemy:
-	if (exists)
-		return;
 
-	s = P_AproxDistance(nobaddies->sourceline->dx, nobaddies->sourceline->dy)>>FRACBITS;
+		if (!FOFsector)
+		{
+			upperbound = sec->ceilingheight;
+			lowerbound = sec->floorheight;
+			node = sec->touching_thinglist; // things touching this sector
+			while (node)
+			{
+				thing = node->m_thing;
 
-	CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", s);
+				if ((thing->flags & (MF_ENEMY|MF_BOSS)) && thing->health > 0
+				&& thing->z < upperbound && thing->z+thing->height > lowerbound)
+					return;
+
+				node = node->m_snext;
+			}
+		}
+	}
+
+	CONS_Debug(DBG_GAMELOGIC, "Running no-more-enemies exec with tag of %d\n", nobaddies->sourceline->tag);
 
-	// Otherwise, run the linedef exec and terminate this thinker
-	P_LinedefExecute((INT16)s, NULL, NULL);
+	// No enemies found, run the linedef exec and terminate this thinker
+	P_RunTriggerLinedef(nobaddies->sourceline, NULL, NULL);
 	P_RemoveThinker(&nobaddies->thinker);
 }
 
@@ -2067,6 +2092,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
 	boolean FOFsector = false;
 	boolean inAndOut = false;
 	boolean floortouch = false;
+	fixed_t bottomheight, topheight;
 
 	for (i = 0; i < MAXPLAYERS; i++)
 	{
@@ -2131,10 +2157,13 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
 					if (players[j].mo->subsector->sector != targetsec)
 						continue;
 
-					if (players[j].mo->z > sec->ceilingheight)
+					topheight = P_GetSpecialTopZ(players[j].mo, sec, targetsec);
+					bottomheight = P_GetSpecialBottomZ(players[j].mo, sec, targetsec);
+
+					if (players[j].mo->z > topheight)
 						continue;
 
-					if (players[j].mo->z + players[j].mo->height < sec->floorheight)
+					if (players[j].mo->z + players[j].mo->height < bottomheight)
 						continue;
 
 					if (floortouch == true && P_IsObjectOnGroundIn(players[j].mo, targetsec))
@@ -2217,7 +2246,7 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
 		oldPlayersArea = oldPlayersInArea;
 	}
 
-	if ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1)
+	while ((affectPlayer = P_HavePlayersEnteredArea(playersArea, oldPlayersArea, inAndOut)) != -1)
 	{
 		if (GETSECSPECIAL(sec->special, 2) == 2 || GETSECSPECIAL(sec->special, 2) == 3)
 		{
@@ -2250,6 +2279,8 @@ void T_EachTimeThinker(levelspecthink_t *eachtime)
 
 		if (!eachtime->sourceline->special) // this happens only for "Trigger on X calls" linedefs
 			P_RemoveThinker(&eachtime->thinker);
+
+		oldPlayersArea[affectPlayer]=playersArea[affectPlayer];
 	}
 }
 
@@ -2292,7 +2323,7 @@ void T_RaiseSector(levelspecthink_t *raise)
 			if (raise->vars[1] && !(thing->player->pflags & PF_STARTDASH))
 				continue;
 
-			if (!(thing->z == raise->sector->ceilingheight))
+			if (!(thing->z == P_GetSpecialTopZ(thing, raise->sector, sector)))
 				continue;
 
 			playeronme = true;
diff --git a/src/p_local.h b/src/p_local.h
index 0b27c40f307732e6d3dc4b66b99c02885ad64e7c..543d800cd101326f53734ea3e97917f1bcdcff42 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -38,6 +38,9 @@
 #define MAPBMASK      (MAPBLOCKSIZE-1)
 #define MAPBTOFRAC    (MAPBLOCKSHIFT-FRACBITS)
 
+// Convenience macro to fix issue with collision along bottom/left edges of blockmap -Red
+#define BMBOUNDFIX(xl, xh, yl, yh) {if (xl > xh) xl = 0; if (yl > yh) yl = 0;}
+
 // player radius used only in am_map.c
 #define PLAYERRADIUS (16*FRACUNIT)
 
@@ -214,6 +217,23 @@ boolean P_RailThinker(mobj_t *mobj);
 void P_PushableThinker(mobj_t *mobj);
 void P_SceneryThinker(mobj_t *mobj);
 
+
+fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
+fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
+#define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(mobj, sector, NULL, x, y, line, false, false)
+#define P_GetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(mobj, sector, NULL, x, y, line, true, false)
+#define P_GetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
+#define P_GetFOFBottomZ(mobj, sector, fof, x, y, line) P_MobjFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
+#define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(mobj, src, bound, mobj->x, mobj->y, NULL, src != bound, true)
+#define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(mobj, src, bound, mobj->x, mobj->y, NULL, src == bound, true)
+
+fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
+fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect);
+#define P_CameraGetFloorZ(mobj, sector, x, y, line) P_CameraFloorZ(mobj, sector, NULL, x, y, line, false, false)
+#define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_CameraCeilingZ(mobj, sector, NULL, x, y, line, true, false)
+#define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_CameraCeilingZ(mobj, sectors + fof->secnum, sector, x, y, line, false, false)
+#define P_CameraGetFOFBottomZ(mobj, sector, fof, x, y, line) P_CameraFloorZ(mobj, sectors + fof->secnum, sector, x, y, line, true, false)
+
 boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover);
 boolean P_CheckDeathPitCollide(mobj_t *mo);
 boolean P_CheckSolidLava(mobj_t *mo, ffloor_t *rover);
@@ -273,9 +293,13 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed
 extern boolean floatok;
 extern fixed_t tmfloorz;
 extern fixed_t tmceilingz;
-extern boolean tmsprung;
 extern mobj_t *tmfloorthing, *tmthing;
 extern camera_t *mapcampointer;
+extern fixed_t tmx;
+extern fixed_t tmy;
+#ifdef ESLOPE
+extern pslope_t *tmfloorslope, *tmceilingslope;
+#endif
 
 /* cphipps 2004/08/30 */
 extern void P_MapStart(void);
diff --git a/src/p_map.c b/src/p_map.c
index 62cbf7b77635b8604cd7ecf0ad7f01628e5c976f..eeff412d811e6c29f4df1e165d1f24ae70472ba8 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -27,6 +27,10 @@
 
 #include "r_splats.h"
 
+#ifdef ESLOPE
+#include "p_slopes.h"
+#endif
+
 #include "z_zone.h"
 
 #include "lua_hook.h"
@@ -34,8 +38,8 @@
 fixed_t tmbbox[4];
 mobj_t *tmthing;
 static INT32 tmflags;
-static fixed_t tmx;
-static fixed_t tmy;
+fixed_t tmx;
+fixed_t tmy;
 
 static precipmobj_t *tmprecipthing;
 static fixed_t preciptmbbox[4];
@@ -48,9 +52,9 @@ fixed_t tmfloorz, tmceilingz;
 static fixed_t tmdropoffz, tmdrpoffceilz; // drop-off floor/ceiling heights
 mobj_t *tmfloorthing; // the thing corresponding to tmfloorz or NULL if tmfloorz is from a sector
 static mobj_t *tmhitthing; // the solid thing you bumped into (for collisions)
-
-// turned on or off in PIT_CheckThing
-boolean tmsprung;
+#ifdef ESLOPE
+pslope_t *tmfloorslope, *tmceilingslope;
+#endif
 
 // keep track of the line that lowers the ceiling,
 // so missiles don't explode against sky hack walls
@@ -111,7 +115,9 @@ void P_DoSpring(mobj_t *spring, mobj_t *object)
 	fixed_t offx, offy;
 	fixed_t vertispeed = spring->info->mass;
 	fixed_t horizspeed = spring->info->damage;
-	fixed_t origvertispeed = vertispeed; // for vertical flipping
+
+	if (object->eflags & MFE_SPRUNG) // Object was already sprung this tic
+		return;
 
 	// Spectators don't trigger springs.
 	if (object->player && object->player->spectator)
@@ -123,6 +129,7 @@ void P_DoSpring(mobj_t *spring, mobj_t *object)
 		return;
 	}
 
+	object->eflags |= MFE_SPRUNG; // apply this flag asap!
 	spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
 
 	if (horizspeed && vertispeed) // Mimic SA
@@ -191,9 +198,9 @@ void P_DoSpring(mobj_t *spring, mobj_t *object)
 		pflags = object->player->pflags & (PF_JUMPED|PF_SPINNING|PF_THOKKED); // I still need these.
 		P_ResetPlayer(object->player);
 
-		if (origvertispeed > 0)
+		if (P_MobjFlip(object)*vertispeed > 0)
 			P_SetPlayerMobjState(object, S_PLAY_SPRING);
-		else if (origvertispeed < 0)
+		else if (P_MobjFlip(object)*vertispeed < 0)
 			P_SetPlayerMobjState(object, S_PLAY_FALL1);
 		else // horizontal spring
 		{
@@ -367,10 +374,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	fixed_t blockdist;
 
 	// don't clip against self
-	tmsprung = false;
+	if (thing == tmthing)
+		return true;
 
 	// Ignore... things.
-	if (!tmthing || !thing)
+	if (!tmthing || !thing || P_MobjWasRemoved(thing))
 		return true;
 
 	I_Assert(!P_MobjWasRemoved(tmthing));
@@ -438,9 +446,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE)))
 		return true;
 
-	if (!tmthing || !thing || thing == tmthing || P_MobjWasRemoved(thing))
-		return true;
-
 	// Don't collide with your buddies while NiGHTS-flying.
 	if (tmthing->player && thing->player && (maptol & TOL_NIGHTS)
 		&& ((tmthing->player->pflags & PF_NIGHTSMODE) || (thing->player->pflags & PF_NIGHTSMODE)))
@@ -549,7 +554,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
 		if ((tmznext <= thzh && tmz > thzh) || (tmznext > thzh - sprarea && tmznext < thzh))
 		{
 			P_DoSpring(thing, tmthing);
-			tmsprung = true;
 			return true;
 		}
 		else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down
@@ -818,15 +822,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	{
 		if (thing->type == MT_FAN || thing->type == MT_STEAM)
 			P_DoFanAndGasJet(thing, tmthing);
-
-		if ((!(thing->eflags & MFE_VERTICALFLIP) && (tmthing->z <= (thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) && (tmthing->z + tmthing->height) >= thing->z))
-		  || ((thing->eflags & MFE_VERTICALFLIP) && (tmthing->z + tmthing->height >= (thing->z - FixedMul(FRACUNIT, thing->scale)) && tmthing->z <= (thing->z + thing->height))))
+		else if (thing->flags & MF_SPRING)
 		{
-			if (thing->flags & MF_SPRING)
-			{
+			if ( thing->z <= tmthing->z + tmthing->height
+			&& tmthing->z <= thing->z + thing->height)
 				P_DoSpring(thing, tmthing);
-				tmsprung = true;
-			}
 		}
 	}
 
@@ -875,7 +875,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
 	{
 		// Doesn't matter what gravity player's following! Just do your stuff in YOUR direction only
 		if (tmthing->eflags & MFE_VERTICALFLIP
-		&& (tmthing->z + tmthing->height + tmthing->momz > thing->z
+		&& (tmthing->z + tmthing->height + tmthing->momz < thing->z
 		 || tmthing->z + tmthing->height + tmthing->momz >= thing->z + thing->height))
 			;
 		else if (!(tmthing->eflags & MFE_VERTICALFLIP)
@@ -909,17 +909,17 @@ static boolean PIT_CheckThing(mobj_t *thing)
 
 		if (thing->type == MT_FAN || thing->type == MT_STEAM)
 			P_DoFanAndGasJet(thing, tmthing);
-
+		else if (thing->flags & MF_SPRING)
+		{
+			if ( thing->z <= tmthing->z + tmthing->height
+			&& tmthing->z <= thing->z + thing->height)
+				P_DoSpring(thing, tmthing);
+		}
 		// Are you touching the side of the object you're interacting with?
-		if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height
+		else if (thing->z - FixedMul(FRACUNIT, thing->scale) <= tmthing->z + tmthing->height
 			&& thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) >= tmthing->z)
 		{
-			if (thing->flags & MF_SPRING)
-			{
-				P_DoSpring(thing, tmthing);
-				tmsprung = true;
-			}
-			else if (thing->flags & MF_MONITOR
+			if (thing->flags & MF_MONITOR
 				&& tmthing->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING))
 			{
 				SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
@@ -932,14 +932,12 @@ static boolean PIT_CheckThing(mobj_t *thing)
 					*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
 				return false;
 			}
-/*
-			else if ((thing->flags & (MF_SOLID|MF_NOCLIP|MF_PUSHABLE)) == MF_SOLID)
-				return false; // this fixes both monitors and non-pushable solids being walked through on bobbing FOFs... for now!
-*/
 		}
 	}
 
 
+	if (thing->flags & MF_SPRING && (tmthing->player || tmthing->flags & MF_PUSHABLE));
+	else
 	// Monitors are not treated as solid to players who are jumping, spinning or gliding,
 	// unless it's a CTF team monitor and you're on the wrong team
 	if (thing->flags & MF_MONITOR && tmthing->player && tmthing->player->pflags & (PF_JUMPED|PF_SPINNING|PF_GLIDING)
@@ -962,6 +960,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
 				if (thing->z + thing->height > tmfloorz)
 				{
 					tmfloorz = thing->z + thing->height;
+#ifdef ESLOPE
+					tmfloorslope = NULL;
+#endif
 				}
 				return true;
 			}
@@ -980,6 +981,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height)
 			{
 				tmceilingz = topz;
+#ifdef ESLOPE
+				tmceilingslope = NULL;
+#endif
 				tmfloorthing = thing; // thing we may stand on
 			}
 		}
@@ -993,6 +997,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
 				if (thing->z < tmceilingz)
 				{
 					tmceilingz = thing->z;
+#ifdef ESLOPE
+					tmceilingslope = NULL;
+#endif
 				}
 				return true;
 			}
@@ -1010,6 +1017,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			else if (topz > tmfloorz && tmthing->z >= thing->z)
 			{
 				tmfloorz = topz;
+#ifdef ESLOPE
+				tmfloorslope = NULL;
+#endif
 				tmfloorthing = thing; // thing we may stand on
 			}
 		}
@@ -1132,11 +1142,13 @@ static boolean PIT_CheckLine(line_t *ld)
 	{
 		tmceilingz = opentop;
 		ceilingline = ld;
+		tmceilingslope = opentopslope;
 	}
 
 	if (openbottom > tmfloorz)
 	{
 		tmfloorz = openbottom;
+		tmfloorslope = openbottomslope;
 	}
 
 	if (highceiling > tmdrpoffceilz)
@@ -1213,8 +1225,12 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 	// that contains the point.
 	// Any contacted lines the step closer together
 	// will adjust them.
-	tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
-	tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight;
+	tmfloorz = tmdropoffz = P_GetFloorZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->floorheight;
+	tmceilingz = P_GetCeilingZ(thing, newsubsec->sector, x, y, NULL); //newsubsec->sector->ceilingheight;
+#ifdef ESLOPE
+	tmfloorslope = newsubsec->sector->f_slope;
+	tmceilingslope = newsubsec->sector->c_slope;
+#endif
 
 	// Check list of fake floors and see if tmfloorz/tmceilingz need to be altered.
 	if (newsubsec->sector->ffloors)
@@ -1228,32 +1244,43 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 			if (!(rover->flags & FF_EXISTS))
 				continue;
 
+			fixed_t topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
+			fixed_t bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
+
 			if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY))
 			{
 				// If you're inside goowater and slowing down
 				fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);
 				fixed_t minspeed = FixedMul(thing->info->height/12, thing->scale);
-				if (thing->z < *rover->topheight && *rover->bottomheight < thingtop
+				if (thing->z < topheight && bottomheight < thingtop
 				&& abs(thing->momz) < minspeed)
 				{
 					// Oh no! The object is stick in between the surface of the goo and sinklevel! help them out!
-					if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z > *rover->topheight - sinklevel
+					if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z > topheight - sinklevel
 					&& thing->momz >= 0 && thing->momz < (minspeed>>2))
 						thing->momz += minspeed>>2;
-					else if (thing->eflags & MFE_VERTICALFLIP && thingtop < *rover->bottomheight + sinklevel
+					else if (thing->eflags & MFE_VERTICALFLIP && thingtop < bottomheight + sinklevel
 					&& thing->momz <= 0 && thing->momz > -(minspeed>>2))
 						thing->momz -= minspeed>>2;
 
 					// Land on the top or the bottom, depending on gravity flip.
-					if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= *rover->topheight - sinklevel && thing->momz <= 0)
+					if (!(thing->eflags & MFE_VERTICALFLIP) && thing->z >= topheight - sinklevel && thing->momz <= 0)
 					{
-						if (tmfloorz < *rover->topheight - sinklevel)
-							tmfloorz = *rover->topheight - sinklevel;
+						if (tmfloorz < topheight - sinklevel) {
+							tmfloorz = topheight - sinklevel;
+#ifdef ESLOPE
+							tmfloorslope = *rover->t_slope;
+#endif
+						}
 					}
-					else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= *rover->bottomheight + sinklevel && thing->momz >= 0)
+					else if (thing->eflags & MFE_VERTICALFLIP && thingtop <= bottomheight + sinklevel && thing->momz >= 0)
 					{
-						if (tmceilingz > *rover->bottomheight + sinklevel)
-							tmceilingz = *rover->bottomheight + sinklevel;
+						if (tmceilingz > bottomheight + sinklevel) {
+							tmceilingz = bottomheight + sinklevel;
+#ifdef ESLOPE
+							tmceilingslope = *rover->b_slope;
+#endif
+						}
 					}
 				}
 				continue;
@@ -1270,30 +1297,40 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 
 			if (rover->flags & FF_QUICKSAND)
 			{
-				if (thing->z < *rover->topheight && *rover->bottomheight < thingtop)
+				if (thing->z < topheight && bottomheight < thingtop)
 				{
-					if (tmfloorz < thing->z)
+					if (tmfloorz < thing->z) {
 						tmfloorz = thing->z;
+#ifdef ESLOPE
+						tmfloorslope = NULL;
+#endif
+					}
 				}
 				// Quicksand blocks never change heights otherwise.
 				continue;
 			}
 
-			delta1 = thing->z - (*rover->bottomheight
-				+ ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight
-				+ ((*rover->topheight - *rover->bottomheight)/2));
+			delta1 = thing->z - (bottomheight
+				+ ((topheight - bottomheight)/2));
+			delta2 = thingtop - (bottomheight
+				+ ((topheight - bottomheight)/2));
 
-			if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2)
+			if (topheight > tmfloorz && abs(delta1) < abs(delta2)
 				&& !(rover->flags & FF_REVERSEPLATFORM))
 			{
-				tmfloorz = tmdropoffz = *rover->topheight;
+				tmfloorz = tmdropoffz = topheight;
+#ifdef ESLOPE
+				tmfloorslope = *rover->t_slope;
+#endif
 			}
-			if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2)
+			if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2)
 				&& !(rover->flags & FF_PLATFORM)
 				&& !(thing->type == MT_SKIM && (rover->flags & FF_SWIMMABLE)))
 			{
-				tmceilingz = tmdrpoffceilz = *rover->bottomheight;
+				tmceilingz = tmdrpoffceilz = bottomheight;
+#ifdef ESLOPE
+				tmceilingslope = *rover->b_slope;
+#endif
 			}
 		}
 	}
@@ -1308,6 +1345,8 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 	yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
 	yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
 #ifdef POLYOBJECTS
 	// Check polyobjects and see if tmfloorz/tmceilingz need to be altered
 	{
@@ -1364,11 +1403,19 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 						delta1 = thing->z - (polybottom + ((polytop - polybottom)/2));
 						delta2 = thingtop - (polybottom + ((polytop - polybottom)/2));
 
-						if (polytop > tmfloorz && abs(delta1) < abs(delta2))
+						if (polytop > tmfloorz && abs(delta1) < abs(delta2)) {
 							tmfloorz = tmdropoffz = polytop;
+#ifdef ESLOPE
+							tmfloorslope = NULL;
+#endif
+						}
 
-						if (polybottom < tmceilingz && abs(delta1) >= abs(delta2))
+						if (polybottom < tmceilingz && abs(delta1) >= abs(delta2)) {
 							tmceilingz = tmdrpoffceilz = polybottom;
+#ifdef ESLOPE
+							tmceilingslope = NULL;
+#endif
+						}
 					}
 					plink = (polymaplink_t *)(plink->link.next);
 				}
@@ -1470,8 +1517,9 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
 	// that contains the point.
 	// Any contacted lines the step closer together
 	// will adjust them.
-	tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
-	tmceilingz = tmdrpoffceilz = newsubsec->sector->ceilingheight;
+	tmfloorz = tmdropoffz = P_CameraGetFloorZ(thiscam, newsubsec->sector, x, y, NULL);
+
+	tmceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, x, y, NULL);
 
 	// 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?
@@ -1500,17 +1548,20 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
 			if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
 				continue;
 
-			delta1 = thiscam->z - (*rover->bottomheight
-				+ ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight
-				+ ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > tmfloorz && abs(delta1) < abs(delta2))
+			fixed_t topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, x, y, NULL);
+			fixed_t bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, x, y, NULL);
+
+			delta1 = thiscam->z - (bottomheight
+				+ ((topheight - bottomheight)/2));
+			delta2 = thingtop - (bottomheight
+				+ ((topheight - bottomheight)/2));
+			if (topheight > tmfloorz && abs(delta1) < abs(delta2))
 			{
-				tmfloorz = tmdropoffz = *rover->topheight;
+				tmfloorz = tmdropoffz = topheight;
 			}
-			if (*rover->bottomheight < tmceilingz && abs(delta1) >= abs(delta2))
+			if (bottomheight < tmceilingz && abs(delta1) >= abs(delta2))
 			{
-				tmceilingz = tmdrpoffceilz = *rover->bottomheight;
+				tmceilingz = tmdrpoffceilz = bottomheight;
 			}
 		}
 	}
@@ -1525,6 +1576,8 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam)
 	yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
 	yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
 #ifdef POLYOBJECTS
 	// Check polyobjects and see if tmfloorz/tmceilingz need to be altered
 	{
@@ -1703,8 +1756,8 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam)
 	}
 	else
 	{
-		tmfloorz = thiscam->subsector->sector->floorheight;
-		tmceilingz = thiscam->subsector->sector->ceilingheight;
+		tmfloorz = P_CameraGetFloorZ(thiscam, thiscam->subsector->sector, x, y, NULL);
+		tmceilingz = P_CameraGetCeilingZ(thiscam, thiscam->subsector->sector, x, y, NULL);
 	}
 
 	// the move is ok,
@@ -1766,11 +1819,14 @@ boolean PIT_PushableMoved(mobj_t *thing)
 		boolean oldfltok = floatok;
 		fixed_t oldflrz = tmfloorz;
 		fixed_t oldceilz = tmceilingz;
-		boolean oldsprung = tmsprung;
 		mobj_t *oldflrthing = tmfloorthing;
 		mobj_t *oldthing = tmthing;
 		line_t *oldceilline = ceilingline;
 		line_t *oldblockline = blockingline;
+#ifdef ESLOPE
+		pslope_t *oldfslope = tmfloorslope;
+		pslope_t *oldcslope = tmceilingslope;
+#endif
 
 		// Move the player
 		P_TryMove(thing, thing->x+stand->momx, thing->y+stand->momy, true);
@@ -1779,11 +1835,14 @@ boolean PIT_PushableMoved(mobj_t *thing)
 		floatok = oldfltok;
 		tmfloorz = oldflrz;
 		tmceilingz = oldceilz;
-		tmsprung = oldsprung;
 		tmfloorthing = oldflrthing;
 		P_SetTarget(&tmthing, oldthing);
 		ceilingline = oldceilline;
 		blockingline = oldblockline;
+#ifdef ESLOPE
+		tmfloorslope = oldfslope;
+		tmceilingslope = oldcslope;
+#endif
 		thing->momz = stand->momz;
 	}
 	else
@@ -1805,6 +1864,9 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 	fixed_t tryy = thing->y;
 	fixed_t radius = thing->radius;
 	fixed_t thingtop = thing->z + thing->height;
+#ifdef ESLOPE
+	fixed_t startingonground = P_IsObjectOnGround(thing);
+#endif
 	floatok = false;
 
 	if (radius < MAXRADIUS/2)
@@ -1893,13 +1955,23 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 				{
 					if (thingtop == thing->ceilingz && tmceilingz > thingtop && tmceilingz - thingtop <= maxstep)
 					{
-						thing->z = tmceilingz - thing->height;
+						thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height;
+						thing->eflags |= MFE_JUSTSTEPPEDDOWN;
+					}
+					else if (tmceilingz < thingtop && thingtop - tmceilingz <= maxstep)
+					{
+						thing->z = (thing->ceilingz = thingtop = tmceilingz) - thing->height;
 						thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 					}
 				}
 				else if (thing->z == thing->floorz && tmfloorz < thing->z && thing->z - tmfloorz <= maxstep)
 				{
-					thing->z = tmfloorz;
+					thing->z = thing->floorz = tmfloorz;
+					thing->eflags |= MFE_JUSTSTEPPEDDOWN;
+				}
+				else if (tmfloorz > thing->z && tmfloorz - thing->z <= maxstep)
+				{
+					thing->z = thing->floorz = tmfloorz;
 					thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 				}
 			}
@@ -1954,6 +2026,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 		xh = (unsigned)(thing->x + MAXRADIUS - bmaporgx)>>MAPBLOCKSHIFT;
 		xl = (unsigned)(thing->x - MAXRADIUS - bmaporgx)>>MAPBLOCKSHIFT;
 
+		BMBOUNDFIX(xl, xh, yl, yh);
+
 		stand = thing;
 		standx = x;
 		standy = y;
@@ -1968,6 +2042,25 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 
 	thing->floorz = tmfloorz;
 	thing->ceilingz = tmceilingz;
+
+#ifdef ESLOPE
+	// Assign thing's standingslope if needed
+	if (thing->z <= tmfloorz && !(thing->eflags & MFE_VERTICALFLIP)) {
+		if (!startingonground && tmfloorslope)
+			P_HandleSlopeLanding(thing, tmfloorslope);
+
+		if (thing->momz <= 0)
+			thing->standingslope = tmfloorslope;
+	}
+	else if (thing->z+thing->height >= tmceilingz && (thing->eflags & MFE_VERTICALFLIP)) {
+		if (!startingonground && tmceilingslope)
+			P_HandleSlopeLanding(thing, tmceilingslope);
+
+		if (thing->momz >= 0)
+			thing->standingslope = tmceilingslope;
+	}
+#endif
+
 	thing->x = x;
 	thing->y = y;
 
@@ -1983,6 +2076,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y)
 {
 	fixed_t tryx, tryy;
+
 	tryx = thing->x;
 	tryy = thing->y;
 	do {
@@ -2308,15 +2402,25 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 {
 	fixed_t platx, platy;
 	subsector_t *glidesector;
+	fixed_t floorz, ceilingz;
 
 	platx = P_ReturnThrustX(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 	platy = P_ReturnThrustY(player->mo, angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 
 	glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy);
 
+#ifdef ESLOPE
+	floorz = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y) : glidesector->sector->floorheight;
+	ceilingz = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y) : glidesector->sector->ceilingheight;
+#else
+	floorz = glidesector->sector->floorheight;
+	ceilingz = glidesector->sector->ceilingheight;
+#endif
+
 	if (glidesector->sector != player->mo->subsector->sector)
 	{
 		boolean floorclimb = false;
+		fixed_t topheight, bottomheight;
 
 		if (glidesector->sector->ffloors)
 		{
@@ -2326,34 +2430,44 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
 					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
+
 				floorclimb = true;
 
 				if (player->mo->eflags & MFE_VERTICALFLIP)
 				{
-					if ((*rover->topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < *rover->topheight))
+					if ((topheight < player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) < topheight))
 					{
 						floorclimb = true;
 					}
-					if (*rover->topheight < player->mo->z) // Waaaay below the ledge.
+					if (topheight < player->mo->z) // Waaaay below the ledge.
 					{
 						floorclimb = false;
 					}
-					if (*rover->bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale))
+					if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale))
 					{
 						floorclimb = false;
 					}
 				}
 				else
 				{
-					if ((*rover->bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > *rover->bottomheight))
+					if ((bottomheight > player->mo->z) && ((player->mo->z - player->mo->momz) > bottomheight))
 					{
 						floorclimb = true;
 					}
-					if (*rover->bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge.
+					if (bottomheight > player->mo->z + player->mo->height) // Waaaay below the ledge.
 					{
 						floorclimb = false;
 					}
-					if (*rover->topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale))
+					if (topheight < player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale))
 					{
 						floorclimb = false;
 					}
@@ -2366,30 +2480,30 @@ static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 
 		if (player->mo->eflags & MFE_VERTICALFLIP)
 		{
-			if ((glidesector->sector->floorheight <= player->mo->z + player->mo->height)
-				&& ((player->mo->z + player->mo->height - player->mo->momz) <= glidesector->sector->floorheight))
+			if ((floorz <= player->mo->z + player->mo->height)
+				&& ((player->mo->z + player->mo->height - player->mo->momz) <= floorz))
 				floorclimb = true;
 
-			if ((glidesector->sector->floorheight > player->mo->z)
+			if ((floorz > player->mo->z)
 				&& glidesector->sector->floorpic == skyflatnum)
 				return false;
 
-			if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > glidesector->sector->ceilingheight)
-				|| (player->mo->z + player->mo->height <= glidesector->sector->floorheight))
+			if ((player->mo->z + player->mo->height - FixedMul(16*FRACUNIT,player->mo->scale) > ceilingz)
+				|| (player->mo->z + player->mo->height <= floorz))
 				floorclimb = true;
 		}
 		else
 		{
-			if ((glidesector->sector->ceilingheight >= player->mo->z)
-				&& ((player->mo->z - player->mo->momz) >= glidesector->sector->ceilingheight))
+			if ((ceilingz >= player->mo->z)
+				&& ((player->mo->z - player->mo->momz) >= ceilingz))
 				floorclimb = true;
 
-			if ((glidesector->sector->ceilingheight < player->mo->z+player->mo->height)
+			if ((ceilingz < player->mo->z+player->mo->height)
 				&& glidesector->sector->ceilingpic == skyflatnum)
 				return false;
 
-			if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < glidesector->sector->floorheight)
-				|| (player->mo->z >= glidesector->sector->ceilingheight))
+			if ((player->mo->z + FixedMul(16*FRACUNIT,player->mo->scale) < ceilingz)
+				|| (player->mo->z >= ceilingz))
 				floorclimb = true;
 		}
 
@@ -2461,6 +2575,7 @@ isblocking:
 		line_t *checkline = li;
 		sector_t *checksector;
 		ffloor_t *rover;
+		fixed_t topheight, bottomheight;
 		boolean fofline = false;
 		INT32 side = P_PointOnLineSide(slidemo->x, slidemo->y, li);
 
@@ -2476,13 +2591,23 @@ isblocking:
 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
 					continue;
 
-				if (*rover->topheight < slidemo->z)
+				topheight = *rover->topheight;
+				bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+				if (*rover->t_slope)
+					topheight = P_GetZAt(*rover->t_slope, slidemo->x, slidemo->y);
+				if (*rover->b_slope)
+					bottomheight = P_GetZAt(*rover->b_slope, slidemo->x, slidemo->y);
+#endif
+
+				if (topheight < slidemo->z)
 					continue;
 
-				if (*rover->bottomheight > slidemo->z + slidemo->height)
+				if (bottomheight > slidemo->z + slidemo->height)
 					continue;
 
-				// Got this far, so I guess it's climbable.
+				// Got this far, so I guess it's climbable. // TODO: Climbing check, also, better method to do this?
 				if (rover->master->flags & ML_TFERLINE)
 				{
 					size_t linenum = li-checksector->lines[0];
@@ -3040,6 +3165,8 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist)
 	xh = (unsigned)(spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
 	xl = (unsigned)(spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
 	bombspot = spot;
 	bombsource = source;
 	bombdamage = FixedMul(damagedist, spot->scale);
@@ -3100,6 +3227,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
 		if (thing->subsector->sector->ffloors && (realcrush || thing->flags & MF_PUSHABLE))
 		{
 			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
 			fixed_t delta1, delta2;
 			INT32 thingtop = thing->z + thing->height;
 
@@ -3109,9 +3237,19 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
 				|| ((rover->flags & FF_BLOCKOTHERS) && !thing->player)) || !(rover->flags & FF_EXISTS))
 					continue;
 
-				delta1 = thing->z - (*rover->bottomheight + *rover->topheight)/2;
-				delta2 = thingtop - (*rover->bottomheight + *rover->topheight)/2;
-				if (*rover->bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2))
+				topheight = *rover->topheight;
+				bottomheight = *rover->bottomheight;
+
+/*#ifdef ESLOPE
+				if (rover->t_slope)
+					topheight = P_GetZAt(rover->t_slope, thing->x, thing->y);
+				if (rover->b_slope)
+					bottomheight = P_GetZAt(rover->b_slope, thing->x, thing->y);
+#endif*/
+
+				delta1 = thing->z - (bottomheight + topheight)/2;
+				delta2 = thingtop - (bottomheight + topheight)/2;
+				if (bottomheight <= thing->ceilingz && abs(delta1) >= abs(delta2))
 				{
 					if (thing->flags & MF_PUSHABLE)
 					{
@@ -3661,6 +3799,8 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 	yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
 	yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
 	for (bx = xl; bx <= xh; bx++)
 		for (by = yl; by <= yh; by++)
 			P_BlockLinesIterator(bx, by, PIT_GetSectors);
@@ -3738,6 +3878,8 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 	yl = (unsigned)(preciptmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
 	yh = (unsigned)(preciptmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
 
+	BMBOUNDFIX(xl, xh, yl, yh);
+
 	for (bx = xl; bx <= xh; bx++)
 		for (by = yl; by <= yh; by++)
 			P_BlockLinesIterator(bx, by, PIT_GetPrecipSectors);
@@ -3785,7 +3927,7 @@ void P_MapEnd(void)
 }
 
 // P_FloorzAtPos
-// Returns the floorz of the XYZ position
+// Returns the floorz of the XYZ position // TODO: Need ceilingpos function too
 // Tails 05-26-2003
 fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 {
@@ -3806,9 +3948,19 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 			if ((!(rover->flags & FF_SOLID || rover->flags & FF_QUICKSAND) || (rover->flags & FF_SWIMMABLE)))
 				continue;
 
+			fixed_t topheight = *rover->topheight;
+			fixed_t bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+			if (*rover->t_slope)
+				topheight = P_GetZAt(*rover->t_slope, x, y);
+			if (*rover->b_slope)
+				bottomheight = P_GetZAt(*rover->b_slope, x, y);
+#endif
+
 			if (rover->flags & FF_QUICKSAND)
 			{
-				if (z < *rover->topheight && *rover->bottomheight < thingtop)
+				if (z < topheight && bottomheight < thingtop)
 				{
 					if (floorz < z)
 						floorz = z;
@@ -3816,10 +3968,10 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height)
 				continue;
 			}
 
-			delta1 = z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-			if (*rover->topheight > floorz && abs(delta1) < abs(delta2))
-				floorz = *rover->topheight;
+			delta1 = z - (bottomheight + ((topheight - bottomheight)/2));
+			delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
+			if (topheight > floorz && abs(delta1) < abs(delta2))
+				floorz = topheight;
 		}
 	}
 
diff --git a/src/p_maputl.c b/src/p_maputl.c
index 48dd54e8da8efbcebfc6183d9fa817698a2f54e8..c9a42bd4348b1603094c47bc0ef8cebc8bd05735 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -17,6 +17,7 @@
 
 #include "p_local.h"
 #include "r_main.h"
+#include "r_data.h"
 #include "p_maputl.h"
 #include "p_polyobj.h"
 #include "z_zone.h"
@@ -321,6 +322,9 @@ fixed_t P_InterceptVector(divline_t *v2, divline_t *v1)
 // OPTIMIZE: keep this precalculated
 //
 fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
+#ifdef ESLOPE
+pslope_t *opentopslope, *openbottomslope;
+#endif
 
 // P_CameraLineOpening
 // P_LineOpening, but for camera
@@ -347,31 +351,56 @@ void P_CameraLineOpening(line_t *linedef)
 	{
 		frontfloor = sectors[front->camsec].floorheight;
 		frontceiling = sectors[front->camsec].ceilingheight;
+#ifdef ESLOPE
+		if (sectors[front->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope)
+			frontfloor = P_GetZAt(sectors[front->camsec].f_slope, camera.x, camera.y);
+		if (sectors[front->camsec].c_slope)
+			frontceiling = P_GetZAt(sectors[front->camsec].c_slope, camera.x, camera.y);
+#endif
+
 	}
 	else if (front->heightsec >= 0)
 	{
 		frontfloor = sectors[front->heightsec].floorheight;
 		frontceiling = sectors[front->heightsec].ceilingheight;
+#ifdef ESLOPE
+		if (sectors[front->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope)
+			frontfloor = P_GetZAt(sectors[front->heightsec].f_slope, camera.x, camera.y);
+		if (sectors[front->heightsec].c_slope)
+			frontceiling = P_GetZAt(sectors[front->heightsec].c_slope, camera.x, camera.y);
+#endif
 	}
 	else
 	{
-		frontfloor = front->floorheight;
-		frontceiling = front->ceilingheight;
+		frontfloor = P_CameraGetFloorZ(mapcampointer, front, tmx, tmy, linedef);
+		frontceiling = P_CameraGetCeilingZ(mapcampointer, front, tmx, tmy, linedef);
 	}
 	if (back->camsec >= 0)
 	{
 		backfloor = sectors[back->camsec].floorheight;
 		backceiling = sectors[back->camsec].ceilingheight;
+#ifdef ESLOPE
+		if (sectors[back->camsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope)
+			frontfloor = P_GetZAt(sectors[back->camsec].f_slope, camera.x, camera.y);
+		if (sectors[back->camsec].c_slope)
+			frontceiling = P_GetZAt(sectors[back->camsec].c_slope, camera.x, camera.y);
+#endif
 	}
 	else if (back->heightsec >= 0)
 	{
 		backfloor = sectors[back->heightsec].floorheight;
 		backceiling = sectors[back->heightsec].ceilingheight;
+#ifdef ESLOPE
+		if (sectors[back->heightsec].f_slope) // SRB2CBTODO: ESLOPE (sectors[front->heightsec].f_slope)
+			frontfloor = P_GetZAt(sectors[back->heightsec].f_slope, camera.x, camera.y);
+		if (sectors[back->heightsec].c_slope)
+			frontceiling = P_GetZAt(sectors[back->heightsec].c_slope, camera.x, camera.y);
+#endif
 	}
 	else
 	{
-		backfloor = back->floorheight;
-		backceiling = back->ceilingheight;
+		backfloor = P_CameraGetFloorZ(mapcampointer, back, tmx, tmy, linedef);
+		backceiling = P_CameraGetCeilingZ(mapcampointer, back, tmx, tmy, linedef);
 	}
 
 	{
@@ -416,17 +445,20 @@ void P_CameraLineOpening(line_t *linedef)
 					if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
 						continue;
 
-					delta1 = abs(mapcampointer->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-					delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-					if (*rover->bottomheight < lowestceiling && delta1 >= delta2)
-						lowestceiling = *rover->bottomheight;
-					else if (*rover->bottomheight < highestceiling && delta1 >= delta2)
-						highestceiling = *rover->bottomheight;
-
-					if (*rover->topheight > highestfloor && delta1 < delta2)
-						highestfloor = *rover->topheight;
-					else if (*rover->topheight > lowestfloor && delta1 < delta2)
-						lowestfloor = *rover->topheight;
+					fixed_t topheight = P_CameraGetFOFTopZ(mapcampointer, front, rover, tmx, tmy, linedef);
+					fixed_t bottomheight = P_CameraGetFOFBottomZ(mapcampointer, front, rover, tmx, tmy, linedef);
+
+					delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2)));
+					delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
+					if (bottomheight < lowestceiling && delta1 >= delta2)
+						lowestceiling = bottomheight;
+					else if (bottomheight < highestceiling && delta1 >= delta2)
+						highestceiling = bottomheight;
+
+					if (topheight > highestfloor && delta1 < delta2)
+						highestfloor = topheight;
+					else if (topheight > lowestfloor && delta1 < delta2)
+						lowestfloor = topheight;
 				}
 
 			// Check for backsectors fake floors
@@ -436,17 +468,20 @@ void P_CameraLineOpening(line_t *linedef)
 					if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_RENDERALL) || !(rover->flags & FF_EXISTS) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
 						continue;
 
-					delta1 = abs(mapcampointer->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-					delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-					if (*rover->bottomheight < lowestceiling && delta1 >= delta2)
-						lowestceiling = *rover->bottomheight;
-					else if (*rover->bottomheight < highestceiling && delta1 >= delta2)
-						highestceiling = *rover->bottomheight;
-
-					if (*rover->topheight > highestfloor && delta1 < delta2)
-						highestfloor = *rover->topheight;
-					else if (*rover->topheight > lowestfloor && delta1 < delta2)
-						lowestfloor = *rover->topheight;
+					fixed_t topheight = P_CameraGetFOFTopZ(mapcampointer, back, rover, tmx, tmy, linedef);
+					fixed_t bottomheight = P_CameraGetFOFBottomZ(mapcampointer, back, rover, tmx, tmy, linedef);
+
+					delta1 = abs(mapcampointer->z - (bottomheight + ((topheight - bottomheight)/2)));
+					delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
+					if (bottomheight < lowestceiling && delta1 >= delta2)
+						lowestceiling = bottomheight;
+					else if (bottomheight < highestceiling && delta1 >= delta2)
+						highestceiling = bottomheight;
+
+					if (topheight > highestfloor && delta1 < delta2)
+						highestfloor = topheight;
+					else if (topheight > lowestfloor && delta1 < delta2)
+						lowestfloor = topheight;
 				}
 
 			if (highestceiling < highceiling)
@@ -494,32 +529,91 @@ void P_LineOpening(line_t *linedef)
 	I_Assert(front != NULL);
 	I_Assert(back != NULL);
 
-	if (front->ceilingheight < back->ceilingheight)
-	{
-		opentop = front->ceilingheight;
-		highceiling = back->ceilingheight;
-	}
-	else
-	{
-		opentop = back->ceilingheight;
-		highceiling = front->ceilingheight;
-	}
+	{ // Set open and high/low values here
+		fixed_t frontheight, backheight;
 
-	if (front->floorheight > back->floorheight)
-	{
-		openbottom = front->floorheight;
-		lowfloor = back->floorheight;
-	}
-	else
-	{
-		openbottom = back->floorheight;
-		lowfloor = front->floorheight;
+		frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef);
+		backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef);
+
+		if (frontheight < backheight)
+		{
+			opentop = frontheight;
+			highceiling = backheight;
+			opentopslope = front->c_slope;
+		}
+		else
+		{
+			opentop = backheight;
+			highceiling = frontheight;
+			opentopslope = back->c_slope;
+		}
+
+		frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef);
+		backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef);
+
+		if (frontheight > backheight)
+		{
+			openbottom = frontheight;
+			lowfloor = backheight;
+			openbottomslope = front->f_slope;
+		}
+		else
+		{
+			openbottom = backheight;
+			lowfloor = frontheight;
+			openbottomslope = back->f_slope;
+		}
 	}
 
 	if (tmthing)
 	{
 		fixed_t thingtop = tmthing->z + tmthing->height;
 
+		// Check for collision with front side's midtexture if Effect 4 is set
+		if (linedef->flags & ML_EFFECT4) {
+			side_t *side = &sides[linedef->sidenum[0]];
+			fixed_t textop, texbottom, texheight;
+			fixed_t texmid, delta1, delta2;
+
+			// Get the midtexture's height
+			texheight = textures[texturetranslation[side->midtexture]]->height << FRACBITS;
+
+			// Set texbottom and textop to the Z coordinates of the texture's boundaries
+#ifdef POLYOBJECTS
+			if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
+				if (linedef->flags & ML_DONTPEGBOTTOM) {
+					texbottom = back->floorheight + side->rowoffset;
+					textop = texbottom + texheight*(side->repeatcnt+1);
+				} else {
+					textop = back->ceilingheight - side->rowoffset;
+					texbottom = textop - texheight*(side->repeatcnt+1);
+				}
+			} else
+#endif
+			{
+				if (linedef->flags & ML_DONTPEGBOTTOM) {
+					texbottom = openbottom + side->rowoffset;
+					textop = texbottom + texheight*(side->repeatcnt+1);
+				} else {
+					textop = opentop - side->rowoffset;
+					texbottom = textop - texheight*(side->repeatcnt+1);
+				}
+			}
+
+			texmid = texbottom+(textop-texbottom)/2;
+
+			delta1 = abs(tmthing->z - texmid);
+			delta2 = abs(thingtop - texmid);
+
+			if (delta1 > delta2) { // Below
+				if (opentop > texbottom)
+					opentop = texbottom;
+			} else { // Above
+				if (openbottom < textop)
+					openbottom = textop;
+			}
+		}
+
 		// Check for fake floors in the sector.
 		if (front->ffloors || back->ffloors
 #ifdef POLYOBJECTS
@@ -534,6 +628,10 @@ void P_LineOpening(line_t *linedef)
 			fixed_t highestfloor = openbottom;
 			fixed_t lowestfloor = lowfloor;
 			fixed_t delta1, delta2;
+#ifdef ESLOPE
+			pslope_t *ceilingslope = opentopslope;
+			pslope_t *floorslope = openbottomslope;
+#endif
 
 			// Check for frontsector's fake floors
 			for (rover = front->ffloors; rover; rover = rover->next)
@@ -547,23 +645,34 @@ void P_LineOpening(line_t *linedef)
 					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
 					continue;
 
-				delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-				delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
+				fixed_t topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef);
+				fixed_t bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef);
+
+				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
 				{
-					if (*rover->bottomheight < lowestceiling)
-						lowestceiling = *rover->bottomheight;
-					else if (*rover->bottomheight < highestceiling)
-						highestceiling = *rover->bottomheight;
+					if (bottomheight < lowestceiling) {
+						lowestceiling = bottomheight;
+#ifdef ESLOPE
+						ceilingslope = *rover->b_slope;
+#endif
+					}
+					else if (bottomheight < highestceiling)
+						highestceiling = bottomheight;
 				}
 
 				if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF
 				{
-					if (*rover->topheight > highestfloor)
-						highestfloor = *rover->topheight;
-					else if (*rover->topheight > lowestfloor)
-						lowestfloor = *rover->topheight;
+					if (topheight > highestfloor) {
+						highestfloor = topheight;
+#ifdef ESLOPE
+						floorslope = *rover->t_slope;
+#endif
+					}
+					else if (topheight > lowestfloor)
+						lowestfloor = topheight;
 				}
 			}
 
@@ -579,23 +688,34 @@ void P_LineOpening(line_t *linedef)
 					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
 					continue;
 
-				delta1 = abs(tmthing->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
-				delta2 = abs(thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2)));
+				fixed_t topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef);
+				fixed_t bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef);
+
+				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
 				{
-					if (*rover->bottomheight < lowestceiling)
-						lowestceiling = *rover->bottomheight;
-					else if (*rover->bottomheight < highestceiling)
-						highestceiling = *rover->bottomheight;
+					if (bottomheight < lowestceiling) {
+						lowestceiling = bottomheight;
+#ifdef ESLOPE
+						ceilingslope = *rover->b_slope;
+#endif
+					}
+					else if (bottomheight < highestceiling)
+						highestceiling = bottomheight;
 				}
 
 				if (delta1 < delta2 && !(rover->flags & FF_REVERSEPLATFORM)) // thing is above FOF
 				{
-					if (*rover->topheight > highestfloor)
-						highestfloor = *rover->topheight;
-					else if (*rover->topheight > lowestfloor)
-						lowestfloor = *rover->topheight;
+					if (topheight > highestfloor) {
+						highestfloor = topheight;
+#ifdef ESLOPE
+						floorslope = *rover->t_slope;
+#endif
+					}
+					else if (topheight > lowestfloor)
+						lowestfloor = topheight;
 				}
 			}
 
@@ -607,13 +727,21 @@ void P_LineOpening(line_t *linedef)
 
 				delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
 				delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
-				if (polysec->floorheight < lowestceiling && delta1 >= delta2)
+				if (polysec->floorheight < lowestceiling && delta1 >= delta2) {
 					lowestceiling = polysec->floorheight;
+#ifdef ESLOPE
+					ceilingslope = NULL;
+#endif
+				}
 				else if (polysec->floorheight < highestceiling && delta1 >= delta2)
 					highestceiling = polysec->floorheight;
 
-				if (polysec->ceilingheight > highestfloor && delta1 < delta2)
+				if (polysec->ceilingheight > highestfloor && delta1 < delta2) {
 					highestfloor = polysec->ceilingheight;
+#ifdef ESLOPE
+					floorslope = NULL;
+#endif
+				}
 				else if (polysec->ceilingheight > lowestfloor && delta1 < delta2)
 					lowestfloor = polysec->ceilingheight;
 			}
@@ -621,11 +749,19 @@ void P_LineOpening(line_t *linedef)
 			if (highestceiling < highceiling)
 				highceiling = highestceiling;
 
-			if (highestfloor > openbottom)
+			if (highestfloor > openbottom) {
 				openbottom = highestfloor;
+#ifdef ESLOPE
+				openbottomslope = floorslope;
+#endif
+			}
 
-			if (lowestceiling < opentop)
+			if (lowestceiling < opentop) {
 				opentop = lowestceiling;
+#ifdef ESLOPE
+				opentopslope = ceilingslope;
+#endif
+			}
 
 			if (lowestfloor > lowfloor)
 				lowfloor = lowestfloor;
@@ -723,6 +859,7 @@ void P_SetThingPosition(mobj_t *thing)
 {                                                      // link into subsector
 	subsector_t *ss;
 	sector_t *oldsec = NULL;
+	fixed_t tfloorz, tceilz;
 
 	I_Assert(thing != NULL);
 	I_Assert(!P_MobjWasRemoved(thing));
@@ -792,12 +929,15 @@ void P_SetThingPosition(mobj_t *thing)
 	// sector's floor is the same height.
 	if (thing->player && oldsec != NULL && thing->subsector && oldsec != thing->subsector->sector)
 	{
+		tfloorz = P_GetFloorZ(thing, ss->sector, thing->x, thing->y, NULL);
+		tceilz = P_GetCeilingZ(thing, ss->sector, thing->x, thing->y, NULL);
+
 		if (thing->eflags & MFE_VERTICALFLIP)
 		{
-			if (thing->z + thing->height >= thing->subsector->sector->ceilingheight)
+			if (thing->z + thing->height >= tceilz)
 				thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 		}
-		else if (thing->z <= thing->subsector->sector->floorheight)
+		else if (thing->z <= tfloorz)
 			thing->eflags |= MFE_JUSTSTEPPEDDOWN;
 	}
 }
diff --git a/src/p_maputl.h b/src/p_maputl.h
index 66f7db2dbaeb30e215e231b0ca256fc450eb164a..7471899cc5bb0bc88e34b7e197621231e99eb289 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -55,6 +55,9 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing, fixed_t x,fixed_t y);
 boolean P_SceneryTryMove(mobj_t *thing, fixed_t x, fixed_t y);
 
 extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
+#ifdef ESLOPE
+extern pslope_t *opentopslope, *openbottomslope;
+#endif
 
 void P_LineOpening(line_t *plinedef);
 
diff --git a/src/p_mobj.c b/src/p_mobj.c
index cac4bc24bc4b326b18ff79f21107f53a7419b205..7d48ca60c6fd7348fbd30ba0a66e81d4e91e478d 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -31,6 +31,9 @@
 #include "i_video.h"
 #include "lua_hook.h"
 #include "b_bot.h"
+#ifdef ESLOPE
+#include "p_slopes.h"
+#endif
 
 // protos.
 static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}};
@@ -700,15 +703,441 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover)
 		|| ((rover->flags & FF_BLOCKOTHERS) && !mobj->player)))
 		return false;
 
-	if (mobj->z > *rover->topheight)
+	fixed_t topheight = *rover->topheight;
+	fixed_t bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+	if (*rover->t_slope)
+		topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y);
+	if (*rover->b_slope)
+		bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y);
+#endif
+
+	if (mobj->z > topheight)
 		return false;
 
-	if (mobj->z + mobj->height < *rover->bottomheight)
+	if (mobj->z + mobj->height < bottomheight)
 		return false;
 
 	return true;
 }
 
+// P_GetFloorZ (and its ceiling counterpart)
+// Gets the floor height (or ceiling height) of the mobj's contact point in sector, assuming object's center if moved to [x, y]
+// If line is supplied, it's a divider line on the sector. Set it to NULL if you're not checking for collision with a line
+// Supply boundsec ONLY when checking for specials! It should be the "in-level" sector, and sector the control sector (if separate).
+// If set, then this function will iterate through boundsec's linedefs to find the highest contact point on the slope. Non-special-checking
+// usage will handle that later.
+static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, pslope_t *slope, boolean actuallylowest)
+{
+	// Alright, so we're sitting on a line that contains our slope sector, and need to figure out the highest point we're touching...
+	// The solution is simple! Get the line's vertices, and pull each one in along its line until it touches the object's bounding box
+	// (assuming it isn't already inside), then test each point's slope Z and return the higher of the two.
+	vertex_t v1, v2;
+	v1.x = line->v1->x;
+	v1.y = line->v1->y;
+	v2.x = line->v2->x;
+	v2.y = line->v2->y;
+
+	/*CONS_Printf("BEFORE: v1 = %f %f %f\n",
+				FIXED_TO_FLOAT(v1.x),
+				FIXED_TO_FLOAT(v1.y),
+				FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y))
+				);
+	CONS_Printf("        v2 = %f %f %f\n",
+				FIXED_TO_FLOAT(v2.x),
+				FIXED_TO_FLOAT(v2.y),
+				FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y))
+				);*/
+
+	if (abs(v1.x-x) > radius) {
+		// v1's x is out of range, so rein it in
+		fixed_t diff = abs(v1.x-x) - radius;
+
+		if (v1.x < x) { // Moving right
+			v1.x += diff;
+			v1.y += FixedMul(diff, FixedDiv(line->dy, line->dx));
+		} else { // Moving left
+			v1.x -= diff;
+			v1.y -= FixedMul(diff, FixedDiv(line->dy, line->dx));
+		}
+	}
+
+	if (abs(v1.y-y) > radius) {
+		// v1's y is out of range, so rein it in
+		fixed_t diff = abs(v1.y-y) - radius;
+
+		if (v1.y < y) { // Moving up
+			v1.y += diff;
+			v1.x += FixedMul(diff, FixedDiv(line->dx, line->dy));
+		} else { // Moving down
+			v1.y -= diff;
+			v1.x -= FixedMul(diff, FixedDiv(line->dx, line->dy));
+		}
+	}
+
+	if (abs(v2.x-x) > radius) {
+		// v1's x is out of range, so rein it in
+		fixed_t diff = abs(v2.x-x) - radius;
+
+		if (v2.x < x) { // Moving right
+			v2.x += diff;
+			v2.y += FixedMul(diff, FixedDiv(line->dy, line->dx));
+		} else { // Moving left
+			v2.x -= diff;
+			v2.y -= FixedMul(diff, FixedDiv(line->dy, line->dx));
+		}
+	}
+
+	if (abs(v2.y-y) > radius) {
+		// v2's y is out of range, so rein it in
+		fixed_t diff = abs(v2.y-y) - radius;
+
+		if (v2.y < y) { // Moving up
+			v2.y += diff;
+			v2.x += FixedMul(diff, FixedDiv(line->dx, line->dy));
+		} else { // Moving down
+			v2.y -= diff;
+			v2.x -= FixedMul(diff, FixedDiv(line->dx, line->dy));
+		}
+	}
+
+	/*CONS_Printf("AFTER:  v1 = %f %f %f\n",
+				FIXED_TO_FLOAT(v1.x),
+				FIXED_TO_FLOAT(v1.y),
+				FIXED_TO_FLOAT(P_GetZAt(slope, v1.x, v1.y))
+				);
+	CONS_Printf("        v2 = %f %f %f\n",
+				FIXED_TO_FLOAT(v2.x),
+				FIXED_TO_FLOAT(v2.y),
+				FIXED_TO_FLOAT(P_GetZAt(slope, v2.x, v2.y))
+				);*/
+
+	// Return the higher of the two points
+	if (actuallylowest)
+		return min(
+			P_GetZAt(slope, v1.x, v1.y),
+			P_GetZAt(slope, v2.x, v2.y)
+		);
+	else
+		return max(
+			P_GetZAt(slope, v1.x, v1.y),
+			P_GetZAt(slope, v2.x, v2.y)
+		);
+}
+
+fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+{
+	I_Assert(mobj != NULL);
+	I_Assert(sector != NULL);
+#ifdef ESLOPE
+	if (sector->f_slope) {
+		fixed_t testx, testy;
+		pslope_t *slope = sector->f_slope;
+
+		// Get the corner of the object that should be the highest on the slope
+		if (slope->d.x < 0)
+			testx = mobj->radius;
+		else
+			testx = -mobj->radius;
+
+		if (slope->d.y < 0)
+			testy = mobj->radius;
+		else
+			testy = -mobj->radius;
+
+		if ((slope->zdelta > 0) ^ !!(lowest)) {
+			testx = -testx;
+			testy = -testy;
+		}
+
+		testx += x;
+		testy += y;
+
+		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
+		if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector))
+			return P_GetZAt(slope, testx, testy);
+
+		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
+		if (perfect) {
+			size_t i;
+			line_t *ld;
+			fixed_t bbox[4];
+			fixed_t finalheight;
+
+			if (lowest)
+				finalheight = INT32_MAX;
+			else
+				finalheight = INT32_MIN;
+
+			bbox[BOXLEFT] = x-mobj->radius;
+			bbox[BOXRIGHT] = x+mobj->radius;
+			bbox[BOXTOP] = y+mobj->radius;
+			bbox[BOXBOTTOM] = y-mobj->radius;
+			for (i = 0; i < boundsec->linecount; i++) {
+				ld = boundsec->lines[i];
+
+				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+					continue;
+
+				if (P_BoxOnLineSide(bbox, ld) != -1)
+					continue;
+
+				if (lowest)
+					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+				else
+					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+			}
+
+			return finalheight;
+		}
+
+		// If we're just testing for base sector location (no collision line), just go for the center's spot...
+		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
+		if (line == NULL)
+			return P_GetZAt(slope, x, y);
+
+		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+	} else // Well, that makes it easy. Just get the floor height
+#endif
+		return sector->floorheight;
+}
+
+fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+{
+	I_Assert(mobj != NULL);
+	I_Assert(sector != NULL);
+#ifdef ESLOPE
+	if (sector->c_slope) {
+		fixed_t testx, testy;
+		pslope_t *slope = sector->c_slope;
+
+		// Get the corner of the object that should be the highest on the slope
+		if (slope->d.x < 0)
+			testx = mobj->radius;
+		else
+			testx = -mobj->radius;
+
+		if (slope->d.y < 0)
+			testy = mobj->radius;
+		else
+			testy = -mobj->radius;
+
+		if ((slope->zdelta > 0) ^ !!(lowest)) {
+			testx = -testx;
+			testy = -testy;
+		}
+
+		testx += x;
+		testy += y;
+
+		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
+		if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector))
+			return P_GetZAt(slope, testx, testy);
+
+		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
+		if (perfect) {
+			size_t i;
+			line_t *ld;
+			fixed_t bbox[4];
+			fixed_t finalheight;
+
+			if (lowest)
+				finalheight = INT32_MAX;
+			else
+				finalheight = INT32_MIN;
+
+			bbox[BOXLEFT] = x-mobj->radius;
+			bbox[BOXRIGHT] = x+mobj->radius;
+			bbox[BOXTOP] = y+mobj->radius;
+			bbox[BOXBOTTOM] = y-mobj->radius;
+			for (i = 0; i < boundsec->linecount; i++) {
+				ld = boundsec->lines[i];
+
+				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+					continue;
+
+				if (P_BoxOnLineSide(bbox, ld) != -1)
+					continue;
+
+				if (lowest)
+					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+				else
+					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+			}
+
+			return finalheight;
+		}
+
+		// If we're just testing for base sector location (no collision line), just go for the center's spot...
+		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
+		if (line == NULL)
+			return P_GetZAt(slope, x, y);
+
+		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+	} else // Well, that makes it easy. Just get the ceiling height
+#endif
+		return sector->ceilingheight;
+}
+
+// Now do the same as all above, but for cameras because apparently cameras are special?
+fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+{
+	I_Assert(mobj != NULL);
+	I_Assert(sector != NULL);
+#ifdef ESLOPE
+	if (sector->f_slope) {
+		fixed_t testx, testy;
+		pslope_t *slope = sector->f_slope;
+
+		// Get the corner of the object that should be the highest on the slope
+		if (slope->d.x < 0)
+			testx = mobj->radius;
+		else
+			testx = -mobj->radius;
+
+		if (slope->d.y < 0)
+			testy = mobj->radius;
+		else
+			testy = -mobj->radius;
+
+		if ((slope->zdelta > 0) ^ !!(lowest)) {
+			testx = -testx;
+			testy = -testy;
+		}
+
+		testx += x;
+		testy += y;
+
+		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
+		if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector))
+			return P_GetZAt(slope, testx, testy);
+
+		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
+		if (perfect) {
+			size_t i;
+			line_t *ld;
+			fixed_t bbox[4];
+			fixed_t finalheight;
+
+			if (lowest)
+				finalheight = INT32_MAX;
+			else
+				finalheight = INT32_MIN;
+
+			bbox[BOXLEFT] = x-mobj->radius;
+			bbox[BOXRIGHT] = x+mobj->radius;
+			bbox[BOXTOP] = y+mobj->radius;
+			bbox[BOXBOTTOM] = y-mobj->radius;
+			for (i = 0; i < boundsec->linecount; i++) {
+				ld = boundsec->lines[i];
+
+				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+					continue;
+
+				if (P_BoxOnLineSide(bbox, ld) != -1)
+					continue;
+
+				if (lowest)
+					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+				else
+					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+			}
+
+			return finalheight;
+		}
+
+		// If we're just testing for base sector location (no collision line), just go for the center's spot...
+		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
+		if (line == NULL)
+			return P_GetZAt(slope, x, y);
+
+		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+	} else // Well, that makes it easy. Just get the floor height
+#endif
+		return sector->floorheight;
+}
+
+fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, line_t *line, boolean lowest, boolean perfect)
+{
+	I_Assert(mobj != NULL);
+	I_Assert(sector != NULL);
+#ifdef ESLOPE
+	if (sector->c_slope) {
+		fixed_t testx, testy;
+		pslope_t *slope = sector->c_slope;
+
+		// Get the corner of the object that should be the highest on the slope
+		if (slope->d.x < 0)
+			testx = mobj->radius;
+		else
+			testx = -mobj->radius;
+
+		if (slope->d.y < 0)
+			testy = mobj->radius;
+		else
+			testy = -mobj->radius;
+
+		if ((slope->zdelta > 0) ^ !!(lowest)) {
+			testx = -testx;
+			testy = -testy;
+		}
+
+		testx += x;
+		testy += y;
+
+		// If the highest point is in the sector, then we have it easy! Just get the Z at that point
+		if (R_PointInSubsector(testx, testy)->sector == (boundsec ?: sector))
+			return P_GetZAt(slope, testx, testy);
+
+		// If boundsec is set, we're looking for specials. In that case, iterate over every line in this sector to find the TRUE highest/lowest point
+		if (perfect) {
+			size_t i;
+			line_t *ld;
+			fixed_t bbox[4];
+			fixed_t finalheight;
+
+			if (lowest)
+				finalheight = INT32_MAX;
+			else
+				finalheight = INT32_MIN;
+
+			bbox[BOXLEFT] = x-mobj->radius;
+			bbox[BOXRIGHT] = x+mobj->radius;
+			bbox[BOXTOP] = y+mobj->radius;
+			bbox[BOXBOTTOM] = y-mobj->radius;
+			for (i = 0; i < boundsec->linecount; i++) {
+				ld = boundsec->lines[i];
+
+				if (bbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || bbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
+				|| bbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || bbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
+					continue;
+
+				if (P_BoxOnLineSide(bbox, ld) != -1)
+					continue;
+
+				if (lowest)
+					finalheight = min(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, true));
+				else
+					finalheight = max(finalheight, HighestOnLine(mobj->radius, x, y, ld, slope, false));
+			}
+
+			return finalheight;
+		}
+
+		// If we're just testing for base sector location (no collision line), just go for the center's spot...
+		// It'll get fixed when we test for collision anyway, and the final result can't be lower than this
+		if (line == NULL)
+			return P_GetZAt(slope, x, y);
+
+		return HighestOnLine(mobj->radius, x, y, line, slope, lowest);
+	} else // Well, that makes it easy. Just get the ceiling height
+#endif
+		return sector->ceilingheight;
+}
 static void P_PlayerFlip(mobj_t *mo)
 {
 	if (!mo->player)
@@ -975,7 +1404,11 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
 		}
 		else if (abs(player->rmomx) < FixedMul(STOPSPEED, mo->scale)
 		    && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
-		    && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING)))
+		    && (!(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)
+#endif
+				)
 		{
 			// if in a walking frame, stop moving
 			if (player->panim == PA_WALK)
@@ -1119,6 +1552,11 @@ void P_XYMovement(mobj_t *mo)
 	fixed_t xmove, ymove;
 	fixed_t oldx, oldy; // reducing bobbing/momentum on ice when up against walls
 	boolean moved;
+#ifdef ESLOPE
+	pslope_t *oldslope = NULL;
+	vector3_t slopemom;
+	fixed_t predictedz = 0;
+#endif
 
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
@@ -1150,11 +1588,35 @@ void P_XYMovement(mobj_t *mo)
 	oldx = mo->x;
 	oldy = mo->y;
 
+#ifdef ESLOPE
+	// adjust various things based on slope
+	if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8) {
+		if (!P_IsObjectOnGround(mo)) { // We fell off at some point? Do the twisty thing!
+			P_SlopeLaunch(mo);
+			xmove = mo->momx;
+			ymove = mo->momy;
+		} else { // Still on the ground.
+			slopemom.x = xmove;
+			slopemom.y = ymove;
+			slopemom.z = 0;
+			P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
+
+			xmove = slopemom.x;
+			ymove = slopemom.y;
+
+			predictedz = mo->z + slopemom.z; // We'll use this later...
+
+			oldslope = mo->standingslope;
+		}
+	} else if (P_IsObjectOnGround(mo) && !mo->momz)
+		predictedz = mo->z;
+#endif
+
 	// Pushables can break some blocks
 	if (CheckForBustableBlocks && mo->flags & MF_PUSHABLE)
 		P_PushableCheckBustables(mo);
 
-	if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !tmsprung)
+	if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !(mo->eflags & MFE_SPRUNG))
 	{
 		// blocked move
 
@@ -1270,6 +1732,54 @@ void P_XYMovement(mobj_t *mo)
 	if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;;
 		return;
 
+#ifdef ESLOPE
+	if (moved && oldslope) { // Check to see if we ran off
+
+		if (oldslope != mo->standingslope) { // First, compare different slopes
+			angle_t oldangle, newangle;
+			angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
+
+			oldangle = FixedMul((signed)oldslope->zangle, FINECOSINE((moveangle - oldslope->xydirection) >> ANGLETOFINESHIFT));
+
+			if (mo->standingslope)
+				newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT));
+			else
+				newangle = 0;
+
+			// Now compare the Zs of the different quantizations
+			if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later
+				mo->standingslope = oldslope;
+				P_SlopeLaunch(mo);
+
+				//CONS_Printf("launched off of slope - ");
+			}
+
+			/*CONS_Printf("old angle %f - new angle %f = %f\n",
+						FIXED_TO_FLOAT(AngleFixed(oldangle)),
+						FIXED_TO_FLOAT(AngleFixed(newangle)),
+						FIXED_TO_FLOAT(AngleFixed(oldangle-newangle))
+						);*/
+		} else if (predictedz-mo->z > abs(slopemom.z/2)) { // Now check if we were supposed to stick to this slope
+			//CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2));
+			P_SlopeLaunch(mo);
+		}
+	} else if (moved && mo->standingslope && predictedz) {
+		angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy);
+		angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT));
+
+			/*CONS_Printf("flat to angle %f - predicted z of %f\n",
+						FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)),
+						FIXED_TO_FLOAT(predictedz)
+						);*/
+		if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) {
+			mo->momz = P_MobjFlip(mo)*FRACUNIT/2;
+			mo->z = predictedz + P_MobjFlip(mo);
+			mo->standingslope = NULL;
+			//CONS_Printf("Launched off of flat surface running into downward slope\n");
+		}
+	}
+#endif
+
 	// Check the gravity status.
 	P_CheckGravity(mo, false);
 
@@ -1316,6 +1826,12 @@ void P_XYMovement(mobj_t *mo)
 	if (player && player->homing) // no friction for homing
 		return;
 
+#ifdef ESLOPE
+	if ((mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED)
+			&& (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8)) // Special exception for tumbleweeds on slopes
+		return;
+#endif
+
 	if (((!(mo->eflags & MFE_VERTICALFLIP) && mo->z > mo->floorz) || (mo->eflags & MFE_VERTICALFLIP && mo->z+mo->height < mo->ceilingz))
 		&& !(player && player->pflags & PF_SLIDING))
 		return; // no friction when airborne
@@ -1372,6 +1888,7 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 {
 	ffloor_t *rover;
 	fixed_t delta1, delta2, thingtop;
+	fixed_t topheight, bottomheight;
 
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
@@ -1383,6 +1900,9 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL);
+		bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL);
+
 		if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected
 			;
 		else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only
@@ -1397,14 +1917,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 			switch (motype)
 			{
 				case 2: // scenery does things differently for some reason
-					if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
+					if (mo->z < topheight && bottomheight < thingtop)
 					{
 						mo->floorz = mo->z;
 						continue;
 					}
 					break;
 				default:
-					if (mo->z < *rover->topheight && *rover->bottomheight < thingtop)
+					if (mo->z < topheight && bottomheight < thingtop)
 					{
 						if (mo->floorz < mo->z)
 							mo->floorz = mo->z;
@@ -1413,17 +1933,17 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 			}
 		}
 
-		delta1 = mo->z - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-		delta2 = thingtop - (*rover->bottomheight + ((*rover->topheight - *rover->bottomheight)/2));
-		if (*rover->topheight > mo->floorz && abs(delta1) < abs(delta2)
+		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))
 		{
-			mo->floorz = *rover->topheight;
+			mo->floorz = topheight;
 		}
-		if (*rover->bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
+		if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
 			&& !(rover->flags & FF_PLATFORM))
 		{
-			mo->ceilingz = *rover->bottomheight;
+			mo->ceilingz = bottomheight;
 		}
 	}
 }
@@ -1555,6 +2075,11 @@ static boolean P_ZMovement(mobj_t *mo)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
+#ifdef ESLOPE
+	if (mo->standingslope && !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);
@@ -1742,14 +2267,31 @@ static boolean P_ZMovement(mobj_t *mo)
 		|| (mo->z + mo->height >= mo->ceilingz && mo->eflags & MFE_VERTICALFLIP))
 	&& !(mo->flags & MF_NOCLIPHEIGHT))
 	{
+		vector3_t mom;
+		mom.x = mo->momx;
+		mom.y = mo->momy;
+		mom.z = mo->momz;
+
 		if (mo->eflags & MFE_VERTICALFLIP)
 			mo->z = mo->ceilingz - mo->height;
 		else
 			mo->z = mo->floorz;
 
+#ifdef ESLOPE
+		P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
+		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;
+		}
+#endif
+
 		// hit the floor
 		if (mo->type == MT_FIREBALL) // special case for the fireball
-			mo->momz = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale);
+			mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale);
 		else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here
 			;
 		else if (mo->flags & MF_MISSILE)
@@ -1764,12 +2306,12 @@ static boolean P_ZMovement(mobj_t *mo)
 				if (mo->flags & MF_GRENADEBOUNCE)
 				{
 					// Going down? (Or up in reverse gravity?)
-					if (P_MobjFlip(mo)*mo->momz < 0)
+					if (P_MobjFlip(mo)*mom.z < 0)
 					{
 						// If going slower than a fracunit, just stop.
-						if (abs(mo->momz) < FixedMul(FRACUNIT, mo->scale))
+						if (abs(mom.z) < FixedMul(FRACUNIT, mo->scale))
 						{
-							mo->momx = mo->momy = mo->momz = 0;
+							mom.x = mom.y = mom.z = 0;
 
 							// Napalm hack
 							if (mo->type == MT_CYBRAKDEMON_NAPALM_BOMB_LARGE && mo->fuse)
@@ -1777,7 +2319,7 @@ static boolean P_ZMovement(mobj_t *mo)
 						}
 						// Otherwise bounce up at half speed.
 						else
-							mo->momz = -mo->momz/2;
+							mom.z = -mom.z/2;
 						S_StartSound(mo, mo->info->activesound);
 					}
 				}
@@ -1800,14 +2342,14 @@ static boolean P_ZMovement(mobj_t *mo)
 			}
 		}
 
-		if (P_MobjFlip(mo)*mo->momz < 0) // falling
+		if (P_MobjFlip(mo)*mom.z < 0) // falling
 		{
 			if (!tmfloorthing || tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
 			|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER)
 				mo->eflags |= MFE_JUSTHITFLOOR;
 
 			if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something
-				mo->momz = -mo->momz;
+				mom.z = -mom.z;
 			else
 			// Flingrings bounce
 			if (mo->type == MT_FLINGRING
@@ -1820,35 +2362,42 @@ static boolean P_ZMovement(mobj_t *mo)
 				|| mo->type == MT_FALLINGROCK)
 			{
 				if (maptol & TOL_NIGHTS)
-					mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT);
+					mom.z = -FixedDiv(mom.z, 10*FRACUNIT);
 				else
-					mo->momz = -FixedMul(mo->momz, FixedDiv(17*FRACUNIT,20*FRACUNIT));
+					mom.z = -FixedMul(mom.z, FixedDiv(17*FRACUNIT,20*FRACUNIT));
 
 				if (mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED)
 				{
-					if (abs(mo->momx) < FixedMul(STOPSPEED, mo->scale)
-						&& abs(mo->momy) < FixedMul(STOPSPEED, mo->scale)
-						&& abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale))
+					if (abs(mom.x) < FixedMul(STOPSPEED, mo->scale)
+						&& abs(mom.y) < FixedMul(STOPSPEED, mo->scale)
+						&& abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale))
 					{
-						if (!(mo->flags & MF_AMBUSH))
-						{
-							mo->momx = mo->momy = mo->momz = 0;
-							P_SetMobjState(mo, mo->info->spawnstate);
-						}
-						else
+						if (mo->flags & MF_AMBUSH)
 						{
 							// If deafed, give the tumbleweed another random kick if it runs out of steam.
-							mo->momz += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale);
+							mom.z += P_MobjFlip(mo)*FixedMul(6*FRACUNIT, mo->scale);
 
 							if (P_Random() & 1)
-								mo->momx += FixedMul(6*FRACUNIT, mo->scale);
+								mom.x += FixedMul(6*FRACUNIT, mo->scale);
 							else
-								mo->momx -= FixedMul(6*FRACUNIT, mo->scale);
+								mom.x -= FixedMul(6*FRACUNIT, mo->scale);
 
 							if (P_Random() & 1)
-								mo->momy += FixedMul(6*FRACUNIT, mo->scale);
+								mom.y += FixedMul(6*FRACUNIT, mo->scale);
 							else
-								mo->momy -= FixedMul(6*FRACUNIT, mo->scale);
+								mom.y -= FixedMul(6*FRACUNIT, mo->scale);
+						}
+#ifdef ESLOPE
+						else if (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8)
+						{
+							// Pop the object up a bit to encourage bounciness
+							//mom.z = P_MobjFlip(mo)*mo->scale;
+						}
+#endif
+						else
+						{
+							mom.x = mom.y = mom.z = 0;
+							P_SetMobjState(mo, mo->info->spawnstate);
 						}
 					}
 
@@ -1858,14 +2407,14 @@ static boolean P_ZMovement(mobj_t *mo)
 				}
 				else if (mo->type == MT_FALLINGROCK)
 				{
-					if (P_MobjFlip(mo)*mo->momz > FixedMul(2*FRACUNIT, mo->scale))
+					if (P_MobjFlip(mo)*mom.z > FixedMul(2*FRACUNIT, mo->scale))
 						S_StartSound(mo, mo->info->activesound + P_RandomKey(mo->info->mass));
 
-					mo->momz /= 2; // Rocks not so bouncy
+					mom.z /= 2; // Rocks not so bouncy
 
-					if (abs(mo->momx) < FixedMul(STOPSPEED, mo->scale)
-						&& abs(mo->momy) < FixedMul(STOPSPEED, mo->scale)
-						&& abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale))
+					if (abs(mom.x) < FixedMul(STOPSPEED, mo->scale)
+						&& abs(mom.y) < FixedMul(STOPSPEED, mo->scale)
+						&& abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale))
 					{
 						P_RemoveMobj(mo);
 						return false;
@@ -1873,20 +2422,30 @@ static boolean P_ZMovement(mobj_t *mo)
 				}
 				else if (mo->type == MT_CANNONBALLDECOR)
 				{
-					mo->momz /= 2;
-					if (abs(mo->momz) < FixedMul(STOPSPEED*3, mo->scale))
-						mo->momz = 0;
+					mom.z /= 2;
+					if (abs(mom.z) < FixedMul(STOPSPEED*3, mo->scale))
+						mom.z = 0;
 				}
 			}
 			else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
 			|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER))
-				mo->momz = tmfloorthing->momz;
+				mom.z = tmfloorthing->momz;
 			else if (!tmfloorthing)
-				mo->momz = 0;
+				mom.z = 0;
 		}
 		else if (tmfloorthing && (tmfloorthing->flags & (MF_PUSHABLE|MF_MONITOR)
 		|| tmfloorthing->flags2 & MF2_STANDONME || tmfloorthing->type == MT_PLAYER))
-			mo->momz = tmfloorthing->momz;
+			mom.z = tmfloorthing->momz;
+
+#ifdef ESLOPE
+		if (mo->standingslope) {
+			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
+		}
+#endif
+
+		mo->momx = mom.x;
+		mo->momy = mom.y;
+		mo->momz = mom.z;
 
 		if (mo->type == MT_STEAM)
 			return true;
@@ -2000,6 +2559,11 @@ static void P_PlayerZMovement(mobj_t *mo)
 	|| mo->player->playerstate == PST_REBORN)
 		return;
 
+#ifdef ESLOPE
+	if (mo->standingslope && !P_IsObjectOnGround(mo))
+			P_SlopeLaunch(mo);
+#endif
+
 	// clip movement
 	if (P_IsObjectOnGround(mo) && !(mo->flags & MF_NOCLIPHEIGHT))
 	{
@@ -2021,6 +2585,13 @@ static void P_PlayerZMovement(mobj_t *mo)
 		if (mo->state == &states[mo->info->painstate] || mo->state == &states[S_PLAY_SUPERHIT])
 			P_SetPlayerMobjState(mo, S_PLAY_STND);
 
+#ifdef ESLOPE
+		if (!mo->standingslope && (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope)) {
+			// Handle landing on slope during Z movement
+			P_HandleSlopeLanding(mo, (mo->eflags & MFE_VERTICALFLIP ? tmceilingslope : tmfloorslope));
+		}
+#endif
+
 		if (P_MobjFlip(mo)*mo->momz < 0) // falling
 		{
 			// Squat down. Decrease viewheight for a moment after hitting the ground (hard),
@@ -2429,7 +3000,7 @@ void P_MobjCheckWater(mobj_t *mobj)
 	player_t *p = mobj->player; // Will just be null if not a player.
 
 	// Default if no water exists.
-	mobj->watertop = mobj->waterbottom = mobj->subsector->sector->floorheight - 1000*FRACUNIT;
+	mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT;
 
 	// Reset water state.
 	mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER|MFE_GOOWATER);
@@ -2441,34 +3012,45 @@ void P_MobjCheckWater(mobj_t *mobj)
 		 || ((rover->flags & FF_BLOCKOTHERS) && !mobj->player)))
 			continue;
 
+		fixed_t topheight = *rover->topheight;
+		fixed_t bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+		if (*rover->t_slope)
+			topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y);
+
+		if (*rover->b_slope)
+			bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y);
+#endif
+
 		if (mobj->eflags & MFE_VERTICALFLIP)
 		{
-			if (*rover->topheight < (thingtop - FixedMul(mobj->info->height/2, mobj->scale))
-			 || *rover->bottomheight > thingtop)
+			if (topheight < (thingtop - FixedMul(mobj->info->height/2, mobj->scale))
+			 || bottomheight > thingtop)
 				continue;
 		}
 		else
 		{
-			if (*rover->topheight < mobj->z
-			 || *rover->bottomheight > (mobj->z + FixedMul(mobj->info->height/2, mobj->scale)))
+			if (topheight < mobj->z
+			 || bottomheight > (mobj->z + FixedMul(mobj->info->height/2, mobj->scale)))
 				continue;
 		}
 
 		// Set the watertop and waterbottom
-		mobj->watertop = *rover->topheight;
-		mobj->waterbottom = *rover->bottomheight;
+		mobj->watertop = topheight;
+		mobj->waterbottom = bottomheight;
 
 		// Just touching the water?
-		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height, mobj->scale) < *rover->bottomheight)
-		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height, mobj->scale) > *rover->topheight))
+		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height, mobj->scale) < bottomheight)
+		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height, mobj->scale) > topheight))
 		{
 			mobj->eflags |= MFE_TOUCHWATER;
 			if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY))
 				mobj->eflags |= MFE_GOOWATER;
 		}
 		// Actually in the water?
-		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height/2, mobj->scale) > *rover->bottomheight)
-		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height/2, mobj->scale) < *rover->topheight))
+		if (((mobj->eflags & MFE_VERTICALFLIP) && thingtop - FixedMul(mobj->info->height/2, mobj->scale) > bottomheight)
+		 || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + FixedMul(mobj->info->height/2, mobj->scale) < topheight))
 		{
 			mobj->eflags |= MFE_UNDERWATER;
 			if (rover->flags & FF_GOOWATER && !(mobj->flags & MF_NOGRAVITY))
@@ -2647,7 +3229,7 @@ static void P_SceneryCheckWater(mobj_t *mobj)
 	sector_t *sector;
 
 	// Default if no water exists.
-	mobj->watertop = mobj->waterbottom = mobj->subsector->sector->floorheight - 1000*FRACUNIT;
+	mobj->watertop = mobj->waterbottom = mobj->z - 1000*FRACUNIT;
 
 	// see if we are in water, and set some flags for later
 	sector = mobj->subsector->sector;
@@ -2655,6 +3237,7 @@ static void P_SceneryCheckWater(mobj_t *mobj)
 	if (sector->ffloors)
 	{
 		ffloor_t *rover;
+		fixed_t topheight, bottomheight;
 
 		mobj->eflags &= ~(MFE_UNDERWATER|MFE_TOUCHWATER);
 
@@ -2662,20 +3245,32 @@ static void P_SceneryCheckWater(mobj_t *mobj)
 		{
 			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS)
 				continue;
-			if (*rover->topheight <= mobj->z
-				|| *rover->bottomheight > (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale)))
+
+			topheight = *rover->topheight;
+			bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+			if (*rover->t_slope)
+				topheight = P_GetZAt(*rover->t_slope, mobj->x, mobj->y);
+
+			if (*rover->b_slope)
+				bottomheight = P_GetZAt(*rover->b_slope, mobj->x, mobj->y);
+#endif
+
+			if (topheight <= mobj->z
+				|| bottomheight > (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale)))
 				continue;
 
-			if (mobj->z + FixedMul(mobj->info->height, mobj->scale) > *rover->topheight)
+			if (mobj->z + FixedMul(mobj->info->height, mobj->scale) > topheight)
 				mobj->eflags |= MFE_TOUCHWATER;
 			else
 				mobj->eflags &= ~MFE_TOUCHWATER;
 
 			// Set the watertop and waterbottom
-			mobj->watertop = *rover->topheight;
-			mobj->waterbottom = *rover->bottomheight;
+			mobj->watertop = topheight;
+			mobj->waterbottom = bottomheight;
 
-			if (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale) < *rover->topheight)
+			if (mobj->z + FixedMul(mobj->info->height >> 1, mobj->scale) < topheight)
 				mobj->eflags |= MFE_UNDERWATER;
 			else
 				mobj->eflags &= ~MFE_UNDERWATER;
@@ -2705,7 +3300,15 @@ static boolean P_CameraCheckHeat(camera_t *thiscam)
 			if (!(rover->flags & FF_EXISTS))
 				continue;
 
-			if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight)
+			if (halfheight >= (
+#ifdef ESLOPE
+					*rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) :
+#endif
+					*rover->topheight) || halfheight <= (
+#ifdef ESLOPE
+					*rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) :
+#endif
+					*rover->bottomheight))
 				continue;
 
 			if (P_FindSpecialLineFromTag(13, rover->master->frontsector->tag, -1) != -1)
@@ -2733,7 +3336,15 @@ static boolean P_CameraCheckWater(camera_t *thiscam)
 			if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE) || rover->flags & FF_BLOCKOTHERS)
 				continue;
 
-			if (halfheight >= *rover->topheight || halfheight <= *rover->bottomheight)
+			if (halfheight >= (
+#ifdef ESLOPE
+					*rover->t_slope ? P_GetZAt(*rover->t_slope, thiscam->x, thiscam->y) :
+#endif
+					*rover->topheight) || halfheight <= (
+#ifdef ESLOPE
+					*rover->b_slope ? P_GetZAt(*rover->b_slope, thiscam->x, thiscam->y) :
+#endif
+					*rover->bottomheight))
 				continue;
 
 			return true;
@@ -2903,6 +3514,10 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 
 	P_MobjCheckWater(mobj);
 
+#ifdef ESLOPE
+	P_ButteredSlope(mobj);
+#endif
+
 	// momentum movement
 	mobj->eflags &= ~MFE_JUSTSTEPPEDDOWN;
 
@@ -2941,6 +3556,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 		// Crumbling platforms
 		for (node = mobj->touching_sectorlist; node; node = node->m_snext)
 		{
+			fixed_t topheight, bottomheight;
 			ffloor_t *rover;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
@@ -2948,8 +3564,11 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_CRUMBLE))
 					continue;
 
-				if ((*rover->topheight == mobj->z && !(mobj->eflags & MFE_VERTICALFLIP))
-				|| (*rover->bottomheight == mobj->z + mobj->height && mobj->eflags & MFE_VERTICALFLIP)) // You nut.
+				topheight = P_GetSpecialTopZ(mobj, sectors + rover->secnum, node->m_sector);
+				bottomheight = P_GetSpecialBottomZ(mobj, sectors + rover->secnum, node->m_sector);
+
+				if ((topheight == mobj->z && !(mobj->eflags & MFE_VERTICALFLIP))
+				|| (bottomheight == mobj->z + mobj->height && mobj->eflags & MFE_VERTICALFLIP)) // You nut.
 					EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), mobj->player, rover->alpha, !(rover->flags & FF_NORETURN));
 			}
 		}
@@ -5448,7 +6067,7 @@ void P_MobjThinker(mobj_t *mobj)
 	if (mobj->tracer && P_MobjWasRemoved(mobj->tracer))
 		P_SetTarget(&mobj->tracer, NULL);
 
-	mobj->flags2 &= ~MF2_PUSHED;
+	mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG);
 
 	// 970 allows ANY mobj to trigger a linedef exec
 	if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8)
@@ -6658,6 +7277,21 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
 		mobj->eflags &= ~MFE_JUSTHITFLOOR;
 	}
 
+#ifdef ESLOPE // Sliding physics for slidey mobjs!
+	if (mobj->type == MT_FLINGRING
+		|| mobj->type == MT_FLINGCOIN
+		|| P_WeaponOrPanel(mobj->type)
+		|| mobj->type == MT_FLINGEMERALD
+		|| mobj->type == MT_BIGTUMBLEWEED
+		|| mobj->type == MT_LITTLETUMBLEWEED
+		|| mobj->type == MT_CANNONBALLDECOR
+		|| mobj->type == MT_FALLINGROCK) {
+		P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly
+		//if (mobj->standingslope) CONS_Printf("slope physics on mobj\n");
+		P_ButteredSlope(mobj);
+	}
+#endif
+
 	if (mobj->flags & (MF_ENEMY|MF_BOSS) && mobj->health
 		&& P_CheckDeathPitCollide(mobj)) // extra pit check in case these didn't have momz
 	{
@@ -6931,8 +7565,16 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 	// Make sure scale matches destscale immediately when spawned
 	P_SetScale(mobj, mobj->destscale);
 
-	mobj->floorz = mobj->subsector->sector->floorheight;
-	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+	mobj->floorz =
+#ifdef ESLOPE
+				mobj->subsector->sector->f_slope ? P_GetZAt(mobj->subsector->sector->f_slope, x, y) :
+#endif
+				mobj->subsector->sector->floorheight;
+	mobj->ceilingz =
+#ifdef ESLOPE
+				mobj->subsector->sector->c_slope ? P_GetZAt(mobj->subsector->sector->c_slope, x, y) :
+#endif
+				mobj->subsector->sector->ceilingheight;
 
 	// Tells MobjCheckWater that the water height was not set.
 	mobj->watertop = INT32_MAX;
@@ -7989,7 +8631,11 @@ void P_SpawnMapThing(mapthing_t *mthing)
 			return;
 
 		ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS);
-		mthing->z = (INT16)((ss->sector->floorheight>>FRACBITS) + (mthing->options >> ZSHIFT));
+		mthing->z = (INT16)(((
+#ifdef ESLOPE
+								ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, mthing->x << FRACBITS, mthing->y << FRACBITS) :
+#endif
+								ss->sector->floorheight)>>FRACBITS) + (mthing->options >> ZSHIFT));
 
 		if (numhuntemeralds < MAXHUNTEMERALDS)
 			huntemeralds[numhuntemeralds++] = mthing;
@@ -8107,14 +8753,22 @@ void P_SpawnMapThing(mapthing_t *mthing)
 	ss = R_PointInSubsector(x, y);
 
 	if (i == MT_NIGHTSBUMPER)
-		z = ss->sector->floorheight + ((mthing->options >> ZSHIFT) << FRACBITS);
+		z = (
+#ifdef ESLOPE
+			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
+#endif
+			ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS);
 	else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE)
 		z = ONFLOORZ;
 	else if (i == MT_SPECIALSPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_EMMY)
 	{
 		if (mthing->options & MTF_OBJECTFLIP)
 		{
-			z = ss->sector->ceilingheight;
+			z = (
+#ifdef ESLOPE
+			ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
+#endif
+			ss->sector->ceilingheight);
 
 			if (mthing->options & MTF_AMBUSH) // Special flag for rings
 				z -= 24*FRACUNIT;
@@ -8125,7 +8779,11 @@ void P_SpawnMapThing(mapthing_t *mthing)
 		}
 		else
 		{
-			z = ss->sector->floorheight;
+			z = (
+#ifdef ESLOPE
+			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
+#endif
+			ss->sector->floorheight);
 
 			if (mthing->options & MTF_AMBUSH) // Special flag for rings
 				z += 24*FRACUNIT;
@@ -8145,9 +8803,17 @@ void P_SpawnMapThing(mapthing_t *mthing)
 
 		// base positions
 		if (flip)
-			z = ss->sector->ceilingheight - mobjinfo[i].height;
+			z = (
+#ifdef ESLOPE
+			ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
+#endif
+			ss->sector->ceilingheight) - mobjinfo[i].height;
 		else
-			z = ss->sector->floorheight;
+			z = (
+#ifdef ESLOPE
+			ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
+#endif
+			ss->sector->floorheight);
 
 		// offsetting
 		if (mthing->options >> ZSHIFT)
@@ -8661,7 +9327,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		// Screw these damn hoops, I need this thinker.
 		//hoopcenter->flags |= MF_NOTHINK;
 
-		z += sec->floorheight;
+		z +=
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight;
 
 		hoopcenter->z = z - hoopcenter->height/2;
 
@@ -8794,7 +9464,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
 		hoopcenter->spawnpoint = mthing;
 
-		z += sec->floorheight;
+		z +=
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight;
 		hoopcenter->z = z - hoopcenter->height/2;
 
 		P_UnsetThingPosition(hoopcenter);
@@ -8906,7 +9580,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 	// Wing logo item.
 	else if (mthing->type == mobjinfo[MT_NIGHTSWING].doomednum)
 	{
-		z = sec->floorheight;
+		z =
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight;
 		if (mthing->options >> ZSHIFT)
 			z += ((mthing->options >> ZSHIFT) << FRACBITS);
 
@@ -8958,13 +9636,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		// Set proper height
 		if (mthing->options & MTF_OBJECTFLIP)
 		{
-			z = sec->ceilingheight - mobjinfo[ringthing].height;
+			z = (
+#ifdef ESLOPE
+			sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
+#endif
+			sec->ceilingheight) - mobjinfo[ringthing].height;
 			if (mthing->options >> ZSHIFT)
 				z -= ((mthing->options >> ZSHIFT) << FRACBITS);
 		}
 		else
 		{
-			z = sec->floorheight;
+			z =
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight;
 			if (mthing->options >> ZSHIFT)
 				z += ((mthing->options >> ZSHIFT) << FRACBITS);
 		}
@@ -9018,13 +9704,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 		{
 			if (mthing->options & MTF_OBJECTFLIP)
 			{
-				z = sec->ceilingheight - mobjinfo[ringthing].height - dist*r;
+				z = (
+#ifdef ESLOPE
+					sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
+#endif
+					sec->ceilingheight) - mobjinfo[ringthing].height - dist*r;
 				if (mthing->options >> ZSHIFT)
 					z -= ((mthing->options >> ZSHIFT) << FRACBITS);
 			}
 			else
 			{
-				z = sec->floorheight + dist*r;
+				z = (
+#ifdef ESLOPE
+					sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+					sec->floorheight) + dist*r;
 				if (mthing->options >> ZSHIFT)
 					z += ((mthing->options >> ZSHIFT) << FRACBITS);
 			}
@@ -9070,13 +9764,21 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 
 			if (mthing->options & MTF_OBJECTFLIP)
 			{
-				z = sec->ceilingheight - mobjinfo[ringthing].height - 64*FRACUNIT*r;
+				z = (
+#ifdef ESLOPE
+					sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
+#endif
+					sec->ceilingheight) - mobjinfo[ringthing].height - 64*FRACUNIT*r;
 				if (mthing->options >> ZSHIFT)
 					z -= ((mthing->options >> ZSHIFT) << FRACBITS);
 			}
 			else
 			{
-				z = sec->floorheight + 64*FRACUNIT*r;
+				z = (
+#ifdef ESLOPE
+					sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+					sec->floorheight) + 64*FRACUNIT*r;
 				if (mthing->options >> ZSHIFT)
 					z += ((mthing->options >> ZSHIFT) << FRACBITS);
 			}
@@ -9107,7 +9809,11 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 			size = 192*FRACUNIT;
 		}
 
-		z = sec->floorheight;
+		z =
+#ifdef ESLOPE
+			sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
+#endif
+			sec->floorheight;
 		if (mthing->options >> ZSHIFT)
 			z += ((mthing->options >> ZSHIFT) << FRACBITS);
 
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 6d120c4733b1f54ff25cbeab05b691891722c108..d7a370c38800e77c0422f4e88bd4c0e0d99672cd 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -175,24 +175,23 @@ typedef enum
 	MF2_EXPLOSION      = 1<<7,  // Thrown ring has explosive properties
 	MF2_SCATTER        = 1<<8,  // Thrown ring has scatter properties
 	MF2_BEYONDTHEGRAVE = 1<<9,  // Source of this missile has died and has since respawned.
-	MF2_PUSHED         = 1<<10, // Mobj was already pushed this tic
-	MF2_SLIDEPUSH      = 1<<11, // MF_PUSHABLE that pushes continuously.
-	MF2_CLASSICPUSH    = 1<<12, // Drops straight down when object has negative Z.
-	MF2_STANDONME      = 1<<13, // While not pushable, stand on me anyway.
-	MF2_INFLOAT        = 1<<14, // Floating to a height for a move, don't auto float to target's height.
-	MF2_DEBRIS         = 1<<15, // Splash ring from explosion ring
-	MF2_NIGHTSPULL     = 1<<16, // Attracted from a paraloop
-	MF2_JUSTATTACKED   = 1<<17, // can be pushed by other moving mobjs
-	MF2_FIRING         = 1<<18, // turret fire
-	MF2_SUPERFIRE      = 1<<19, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
-	MF2_SHADOW         = 1<<20, // Fuzzy draw, makes targeting harder.
-	MF2_STRONGBOX      = 1<<21, // Flag used for "strong" random monitors.
-	MF2_OBJECTFLIP     = 1<<22, // Flag for objects that always have flipped gravity.
-	MF2_SKULLFLY       = 1<<23, // Special handling: skull in flight.
-	MF2_FRET           = 1<<24, // Flashing from a previous hit
-	MF2_BOSSNOTRAP     = 1<<25, // No Egg Trap after boss
-	MF2_BOSSFLEE       = 1<<26, // Boss is fleeing!
-	MF2_BOSSDEAD       = 1<<27, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
+	MF2_SLIDEPUSH      = 1<<10, // MF_PUSHABLE that pushes continuously.
+	MF2_CLASSICPUSH    = 1<<11, // Drops straight down when object has negative Z.
+	MF2_STANDONME      = 1<<12, // While not pushable, stand on me anyway.
+	MF2_INFLOAT        = 1<<13, // Floating to a height for a move, don't auto float to target's height.
+	MF2_DEBRIS         = 1<<14, // Splash ring from explosion ring
+	MF2_NIGHTSPULL     = 1<<15, // Attracted from a paraloop
+	MF2_JUSTATTACKED   = 1<<16, // can be pushed by other moving mobjs
+	MF2_FIRING         = 1<<17, // turret fire
+	MF2_SUPERFIRE      = 1<<18, // Firing something with Super Sonic-stopping properties. Or, if mobj has MF_MISSILE, this is the actual fire from it.
+	MF2_SHADOW         = 1<<19, // Fuzzy draw, makes targeting harder.
+	MF2_STRONGBOX      = 1<<20, // Flag used for "strong" random monitors.
+	MF2_OBJECTFLIP     = 1<<21, // Flag for objects that always have flipped gravity.
+	MF2_SKULLFLY       = 1<<22, // Special handling: skull in flight.
+	MF2_FRET           = 1<<23, // Flashing from a previous hit
+	MF2_BOSSNOTRAP     = 1<<24, // No Egg Trap after boss
+	MF2_BOSSFLEE       = 1<<25, // Boss is fleeing!
+	MF2_BOSSDEAD       = 1<<26, // Boss is dead! (Not necessarily fleeing, if a fleeing point doesn't exist.)
 	// free: to and including 1<<31
 } mobjflag2_t;
 
@@ -232,7 +231,11 @@ typedef enum
 	MFE_VERTICALFLIP      = 1<<5,
 	// Goo water
 	MFE_GOOWATER          = 1<<6,
-	// free: to and including 1<<7
+	// Mobj was already pushed this tic
+	MFE_PUSHED            = 1<<7,
+	// Mobj was already sprung this tic
+	MFE_SPRUNG            = 1<<8,
+	// free: to and including 1<<15
 } mobjeflag_t;
 
 //
@@ -286,7 +289,7 @@ typedef struct mobj_s
 	state_t *state;
 	UINT32 flags; // flags from mobjinfo tables
 	UINT32 flags2; // MF2_ flags
-	UINT8 eflags; // extra flags
+	UINT16 eflags; // extra flags
 
 	void *skin; // overrides 'sprite' when non-NULL (for player bodies to 'remember' the skin)
 	// Player and mobj sprites in multiplayer modes are modified
@@ -349,6 +352,10 @@ typedef struct mobj_s
 	INT32 cusval;
 	INT32 cvmem;
 
+#ifdef ESLOPE
+	struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
+#endif
+
 	// WARNING: New fields must be added separately to savegame and Lua.
 } mobj_t;
 
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index 9c955c97beeb30af6f0a341bf46fc998869c5c29..f790fa768533574960a1a9621ed9f40333538e32 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -1043,9 +1043,10 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy)
 
 				mo->lastlook = pomovecount;
 
-				// always push players even if not solid
-				if (!((mo->flags & MF_SOLID) || mo->player))
+				// Don't scroll objects that aren't affected by gravity
+				if (mo->flags & MF_NOGRAVITY)
 					continue;
+				// (The above check used to only move MF_SOLID objects, but that's inconsistent with conveyor behavior. -Red)
 
 				if (mo->flags & MF_NOCLIP)
 					continue;
@@ -1097,9 +1098,11 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line)
 
 				for (; mo; mo = mo->bnext)
 				{
-					// always push players even if not solid
-					if (!((mo->flags & MF_SOLID) || mo->player))
+
+					// Don't scroll objects that aren't affected by gravity
+					if (mo->flags & MF_NOGRAVITY)
 						continue;
+					// (The above check used to only move MF_SOLID objects, but that's inconsistent with conveyor behavior. -Red)
 
 					if (mo->flags & MF_NOCLIP)
 						continue;
@@ -1259,6 +1262,7 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta,
 {
 	static INT32 pomovecount = 10000;
 	INT32 x, y;
+	angle_t deltafine = delta >> ANGLETOFINESHIFT;
 
 	pomovecount++;
 
@@ -1283,9 +1287,10 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta,
 
 				mo->lastlook = pomovecount;
 
-				// always push players even if not solid
-				if (!((mo->flags & MF_SOLID) || mo->player))
+				// Don't scroll objects that aren't affected by gravity
+				if (mo->flags & MF_NOGRAVITY)
 					continue;
+				// (The above check used to only move MF_SOLID objects, but that's inconsistent with conveyor behavior. -Red)
 
 				if (mo->flags & MF_NOCLIP)
 					continue;
@@ -1300,21 +1305,28 @@ static void Polyobj_rotateThings(polyobj_t *po, vertex_t origin, angle_t delta,
 					continue;
 
 				{
-					fixed_t newxoff, newyoff;
-					angle_t angletoobj = R_PointToAngle2(origin.x, origin.y, mo->x, mo->y);
-					fixed_t disttoobj = R_PointToDist2(origin.x, origin.y, mo->x, mo->y);
+					fixed_t oldxoff, oldyoff, newxoff, newyoff;
+					fixed_t c, s;
+
+					c = FINECOSINE(deltafine);
+					s = FINESINE(deltafine);
+
+					oldxoff = mo->x-origin.x;
+					oldyoff = mo->y-origin.y;
 
 					if (mo->player) // Hack to fix players sliding off of spinning polys -Red
 					{
-						disttoobj = FixedMul(disttoobj, 0xfe40);
+						fixed_t temp;
+
+						temp = FixedMul(oldxoff, c)-FixedMul(oldyoff, s);
+						oldyoff = FixedMul(oldyoff, c)+FixedMul(oldxoff, s);
+						oldxoff = temp;
 					}
 
-					angletoobj += delta;
-					angletoobj >>= ANGLETOFINESHIFT;
-					newxoff = FixedMul(FINECOSINE(angletoobj), disttoobj);
-					newyoff = FixedMul(FINESINE(angletoobj), disttoobj);
+					newxoff = FixedMul(oldxoff, c)-FixedMul(oldyoff, s);
+					newyoff = FixedMul(oldyoff, c)+FixedMul(oldxoff, s);
 
-					Polyobj_slideThing(mo, origin.x+newxoff-mo->x, origin.y+newyoff-mo->y);
+					Polyobj_slideThing(mo, newxoff-oldxoff, newyoff-oldyoff);
 
 					if (turnthings == 2 || (turnthings == 1 && !mo->player)) {
 						mo->angle += delta;
@@ -2491,6 +2503,10 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
 		return 0;
 	}
 
+	// Hotfix to not crash on single-waypoint sequences -Red
+	if (!last)
+		last = first;
+
 	// Set diffx, diffy, diffz
 	// Put these at 0 for now...might not be needed after all.
 	th->diffx = 0;//first->x - po->centerPt.x;
diff --git a/src/p_polyobj.h b/src/p_polyobj.h
index 71cf965e3b7c990ca937331da5f2c32bb8e6bc31..3d6576cc6d9c59aa5fbf57b26c4d35663852f038 100644
--- a/src/p_polyobj.h
+++ b/src/p_polyobj.h
@@ -100,6 +100,8 @@ typedef struct polyobj_s
 	UINT8 isBad;         // a bad polyobject: should not be rendered/manipulated
 	INT32 translucency; // index to translucency tables
 
+	struct visplane_s *visplane; // polyobject's visplane, for ease of putting into the list later
+
 	// these are saved for netgames, so do not let Lua touch these!
 	INT32 spawnflags; // Flags the polyobject originally spawned with
 } polyobj_t;
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 851d653fa2c2736d8a59a720f9a493b4f7ee5ffb..eec3dbf3eb27f7ff39e023da9e381f116a8f3ee5 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1174,7 +1174,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
 	if (diff & MD_FRAME)
 		WRITEUINT32(save_p, mobj->frame);
 	if (diff & MD_EFLAGS)
-		WRITEUINT8(save_p, mobj->eflags);
+		WRITEUINT16(save_p, mobj->eflags);
 	if (diff & MD_PLAYER)
 		WRITEUINT8(save_p, mobj->player-players);
 	if (diff & MD_MOVEDIR)
@@ -2000,7 +2000,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
 	else
 		mobj->frame = mobj->state->frame;
 	if (diff & MD_EFLAGS)
-		mobj->eflags = READUINT8(save_p);
+		mobj->eflags = READUINT16(save_p);
 	if (diff & MD_PLAYER)
 	{
 		i = READUINT8(save_p);
diff --git a/src/p_setup.c b/src/p_setup.c
index f2b0c49d84c3a1222308e130a539eff55a8cd670..c836d601c60cc21a454974f8cb2657ef4671149b 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -72,6 +72,10 @@
 #include "hardware/hw_light.h"
 #endif
 
+#ifdef ESLOPE
+#include "p_slopes.h"
+#endif
+
 //
 // Map MD5, calculated on level load.
 // Sent to clients in PT_SERVERINFO.
@@ -888,9 +892,14 @@ static void P_LoadThings(lumpnum_t lumpnum)
 	numhuntemeralds = 0;
 	for (i = 0; i < nummapthings; i++, mt++)
 	{
+		sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector;
+
 		// Z for objects
-		mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
-			->sector->floorheight>>FRACBITS);
+		mt->z = (INT16)(
+#ifdef ESLOPE
+				mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) :
+#endif
+				mtsector->floorheight)>>FRACBITS;
 
 		if (mt->type == 1700 // MT_AXIS
 			|| mt->type == 1701 // MT_AXISTRANSFER
@@ -2531,6 +2540,10 @@ boolean P_SetupLevel(boolean skipprecip)
 
 	P_MapStart();
 
+#ifdef ESLOPE
+	P_ResetDynamicSlopes();
+#endif
+
 	P_LoadThings(lastloadedmaplumpnum + ML_THINGS);
 
 	P_SpawnSecretItems(loademblems);
diff --git a/src/p_slopes.c b/src/p_slopes.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0b20216822a63f1fd6c6a224519e4cde54e3387
--- /dev/null
+++ b/src/p_slopes.c
@@ -0,0 +1,922 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2004 Stephen McGranahan
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+//--------------------------------------------------------------------------
+//
+// DESCRIPTION:
+//      Slopes
+//      SoM created 05/10/09
+//      ZDoom + Eternity Engine Slopes, ported and enhanced by Kalaron
+//
+//-----------------------------------------------------------------------------
+
+
+#include "doomdef.h"
+#include "r_defs.h"
+#include "r_state.h"
+#include "m_bbox.h"
+#include "z_zone.h"
+#include "p_spec.h"
+#include "p_slopes.h"
+#include "r_main.h"
+#include "p_maputl.h"
+#include "w_wad.h"
+
+#ifdef ESLOPE
+
+static pslope_t *dynslopes = NULL;
+
+// Calculate line normal
+void P_CalculateSlopeNormal(pslope_t *slope) {
+	slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
+	slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
+	slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
+}
+
+// Recalculate dynamic slopes
+void P_RunDynamicSlopes(void) {
+	pslope_t *slope;
+
+	for (slope = dynslopes; slope; slope = slope->next) {
+		fixed_t zdelta;
+
+		switch(slope->refpos) {
+		case 1: // front floor
+			zdelta = slope->sourceline->backsector->floorheight - slope->sourceline->frontsector->floorheight;
+			slope->o.z = slope->sourceline->frontsector->floorheight;
+			break;
+		case 2: // front ceiling
+			zdelta = slope->sourceline->backsector->ceilingheight - slope->sourceline->frontsector->ceilingheight;
+			slope->o.z = slope->sourceline->frontsector->ceilingheight;
+			break;
+		case 3: // back floor
+			zdelta = slope->sourceline->frontsector->floorheight - slope->sourceline->backsector->floorheight;
+			slope->o.z = slope->sourceline->backsector->floorheight;
+			break;
+		case 4: // back ceiling
+			zdelta = slope->sourceline->frontsector->ceilingheight - slope->sourceline->backsector->ceilingheight;
+			slope->o.z = slope->sourceline->backsector->ceilingheight;
+			break;
+
+		default:
+			I_Error("P_RunDynamicSlopes: slope has invalid type!");
+		}
+
+		if (slope->zdelta != FixedDiv(zdelta, slope->extent)) {
+			slope->zdelta = FixedDiv(zdelta, slope->extent);
+			slope->zangle = R_PointToAngle2(0, 0, slope->extent, -zdelta);
+			P_CalculateSlopeNormal(slope);
+		}
+	}
+}
+
+//
+// P_MakeSlope
+//
+// Alocates and fill the contents of a slope structure.
+//
+static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
+                             const fixed_t zdelta, boolean dynamic)
+{
+	pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
+	memset(ret, 0, sizeof(*ret));
+
+	ret->o.x = o->x;
+	ret->o.y = o->y;
+	ret->o.z = o->z;
+
+	ret->d.x = d->x;
+	ret->d.y = d->y;
+
+	ret->zdelta = zdelta;
+
+	if (dynamic) { // Add to the dynamic slopes list
+		ret->next = dynslopes;
+		dynslopes = ret;
+	}
+
+	return ret;
+}
+
+//
+// P_GetExtent
+//
+// Returns the distance to the first line within the sector that
+// is intersected by a line parallel to the plane normal with the point (ox, oy)
+//
+static fixed_t P_GetExtent(sector_t *sector, line_t *line)
+{
+	// ZDoom code reference: v3float_t = vertex_t
+	fixed_t fardist = -FRACUNIT;
+	size_t i;
+
+	// 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];
+		vertex_t tempv;
+		fixed_t dist;
+
+		// Don't compare to the slope line.
+		if(li == line)
+			continue;
+
+		P_ClosestPointOnLine(li->v1->x, li->v1->y, line, &tempv);
+		dist = R_PointToDist2(tempv.x, tempv.y, li->v1->x, li->v1->y);
+		if(dist > fardist)
+			fardist = dist;
+
+		// Okay, maybe do it for v2 as well?
+		P_ClosestPointOnLine(li->v2->x, li->v2->y, line, &tempv);
+		dist = R_PointToDist2(tempv.x, tempv.y, li->v2->x, li->v2->y);
+		if(dist > fardist)
+			fardist = dist;
+	}
+
+	return fardist;
+}
+
+
+//
+// P_SpawnSlope_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)
+{
+	// With dynamic slopes, it's fine to just leave this function as normal,
+	// because checking to see if a slope had changed will waste more memory than
+	// if the slope was just updated when called
+	line_t *line = lines + linenum;
+	INT16 special = line->special;
+	pslope_t *fslope = NULL, *cslope = NULL;
+	vector3_t origin, point;
+	vector2_t direction;
+	fixed_t nx, ny, dz, extent;
+
+	boolean frontfloor = (special == 700 || special == 702 || special == 703);
+	boolean backfloor  = (special == 710 || special == 712 || special == 713);
+	boolean frontceil  = (special == 701 || special == 702 || special == 713);
+	boolean backceil   = (special == 711 || special == 712 || special == 703);
+
+	if(!frontfloor && !backfloor && !frontceil && !backceil)
+	{
+		CONS_Printf("P_SpawnSlope_Line called with non-slope line special.\n");
+		return;
+	}
+
+	if(!line->frontsector || !line->backsector)
+	{
+		CONS_Printf("P_SpawnSlope_Line used on a line without two sides.\n");
+		return;
+	}
+
+	{
+		fixed_t len = R_PointToDist2(0, 0, line->dx, line->dy);
+		nx = FixedDiv(line->dy, len);
+		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;
+
+	// For FOF slopes, make a special function to copy to the xy origin & direction relative to the position of the FOF on the map!
+	if(frontfloor || frontceil)
+	{
+		line->frontsector->hasslope = true; // Tell the software renderer that we're sloped
+
+		origin.z = line->backsector->floorheight;
+		direction.x = nx;
+		direction.y = ny;
+
+		extent = P_GetExtent(line->frontsector, line);
+
+		if(extent < 0)
+		{
+			CONS_Printf("P_SpawnSlope_Line failed to get frontsector extent on line number %i\n", linenum);
+			return;
+		}
+
+		// reposition the origin according to the extent
+		point.x = origin.x + FixedMul(direction.x, extent);
+		point.y = origin.y + FixedMul(direction.y, extent);
+		direction.x = -direction.x;
+		direction.y = -direction.y;
+
+		// TODO: We take origin and point 's xy values and translate them to the center of an FOF!
+
+		if(frontfloor)
+		{
+
+			point.z = line->frontsector->floorheight; // Startz
+			dz = FixedDiv(origin.z - point.z, extent); // Destinationz
+
+			// In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef
+
+			fslope = line->frontsector->f_slope =
+            P_MakeSlope(&point, &direction, dz, !(line->flags & ML_NOTAILS));
+
+            // Set up some shit
+            fslope->extent = extent;
+            fslope->refpos = 1;
+
+			// Now remember that f_slope IS a vector
+			// fslope->o = origin      3D point 1 of the vector
+			// fslope->d = destination 3D point 2 of the vector
+			// 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?
+			fslope->sourceline = line;
+
+			// To find the real highz/lowz of a slope, you need to check all the vertexes
+			// in the slope's sector with P_GetZAt to get the REAL lowz & highz
+			// Although these slopes are set by floorheights the ANGLE is what a slope is,
+			// so technically any slope can extend on forever (they are just bound by sectors)
+			// *You can use sourceline as a reference to see if two slopes really are the same
+
+			// Default points for high and low
+			fixed_t highest = point.z > origin.z ? point.z : origin.z;
+			fixed_t lowest = point.z < origin.z ? point.z : origin.z;
+
+			// Now check to see what the REAL high and low points of the slope inside the sector
+			// TODO: Is this really needed outside of FOFs? -Red
+			size_t l;
+
+			for (l = 0; l < line->frontsector->linecount; l++)
+			{
+				fixed_t height = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
+
+				if (height > highest)
+					highest = height;
+
+				if (height < lowest)
+					lowest = height;
+			}
+
+			// Sets extra clipping data for the frontsector's slope
+			fslope->highz = highest;
+			fslope->lowz = lowest;
+
+			fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
+			fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
+
+			P_CalculateSlopeNormal(fslope);
+		}
+		if(frontceil)
+		{
+			origin.z = line->backsector->ceilingheight;
+			point.z = line->frontsector->ceilingheight;
+			dz = FixedDiv(origin.z - point.z, extent);
+
+			cslope = line->frontsector->c_slope =
+            P_MakeSlope(&point, &direction, dz, !(line->flags & ML_NOTAILS));
+
+            // Set up some shit
+            cslope->extent = extent;
+            cslope->refpos = 2;
+
+			// Sync the linedata of the line that started this slope
+			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			cslope->sourceline = line;
+
+			// Remember the way the slope is formed
+			fixed_t highest = point.z > origin.z ? point.z : origin.z;
+			fixed_t lowest = point.z < origin.z ? point.z : origin.z;
+			size_t l;
+
+			for (l = 0; l < line->frontsector->linecount; l++)
+			{
+				fixed_t height = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
+
+				if (height > highest)
+					highest = height;
+
+				if (height < lowest)
+					lowest = height;
+			}
+
+			// This line special sets extra clipping data for the frontsector's slope
+			cslope->highz = highest;
+			cslope->lowz = lowest;
+
+			cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
+			cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
+
+			P_CalculateSlopeNormal(cslope);
+		}
+	}
+	if(backfloor || backceil)
+	{
+		line->backsector->hasslope = true; // Tell the software renderer that we're sloped
+
+		origin.z = line->frontsector->floorheight;
+		// Backsector
+		direction.x = -nx;
+		direction.y = -ny;
+
+		extent = P_GetExtent(line->backsector, line);
+
+		if(extent < 0)
+		{
+			CONS_Printf("P_SpawnSlope_Line failed to get backsector extent on line number %i\n", linenum);
+			return;
+		}
+
+		// reposition the origin according to the extent
+		point.x = origin.x + FixedMul(direction.x, extent);
+		point.y = origin.y + FixedMul(direction.y, extent);
+		direction.x = -direction.x;
+		direction.y = -direction.y;
+
+		if(backfloor)
+		{
+			point.z = line->backsector->floorheight;
+			dz = FixedDiv(origin.z - point.z, extent);
+
+			fslope = line->backsector->f_slope =
+            P_MakeSlope(&point, &direction, dz, !(line->flags & ML_NOTAILS));
+
+            // Set up some shit
+            fslope->extent = extent;
+            fslope->refpos = 3;
+
+			// Sync the linedata of the line that started this slope
+			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			fslope->sourceline = line;
+
+			// Remember the way the slope is formed
+			fixed_t highest = point.z > origin.z ? point.z : origin.z;
+			fixed_t lowest = point.z < origin.z ? point.z : origin.z;
+			size_t l;
+
+			for (l = 0; l < line->backsector->linecount; l++)
+			{
+				fixed_t height = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
+
+				if (height > highest)
+					highest = height;
+
+				if (height < lowest)
+					lowest = height;
+			}
+
+			// This line special sets extra clipping data for the frontsector's slope
+			fslope->highz = highest;
+			fslope->lowz = lowest;
+
+			fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
+			fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
+
+			P_CalculateSlopeNormal(fslope);
+		}
+		if(backceil)
+		{
+			origin.z = line->frontsector->ceilingheight;
+			point.z = line->backsector->ceilingheight;
+			dz = FixedDiv(origin.z - point.z, extent);
+
+			cslope = line->backsector->c_slope =
+            P_MakeSlope(&point, &direction, dz, !(line->flags & ML_NOTAILS));
+
+            // Set up some shit
+            cslope->extent = extent;
+            cslope->refpos = 4;
+
+			// Sync the linedata of the line that started this slope
+			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			cslope->sourceline = line;
+
+			// Remember the way the slope is formed
+			fixed_t highest = point.z > origin.z ? point.z : origin.z;
+			fixed_t lowest = point.z < origin.z ? point.z : origin.z;
+
+			size_t l;
+
+			for (l = 0; l < line->backsector->linecount; l++)
+			{
+				fixed_t height = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
+
+				if (height > highest)
+					highest = height;
+
+				if (height < lowest)
+					lowest = height;
+			}
+
+			// This line special sets extra clipping data for the backsector's slope
+			cslope->highz = highest;
+			cslope->lowz = lowest;
+
+			cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
+			cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
+
+			P_CalculateSlopeNormal(cslope);
+		}
+	}
+
+	if(!line->tag)
+		return;
+}
+
+
+
+//
+// P_CopySectorSlope
+//
+// Searches through tagged sectors and copies
+//
+void P_CopySectorSlope(line_t *line)
+{
+   sector_t *fsec = line->frontsector;
+   int i, special = line->special;
+
+   // Check for copy linedefs
+   for(i = -1; (i = P_FindSectorFromLineTag(line, i)) >= 0;)
+   {
+      sector_t *srcsec = sectors + i;
+
+      if((special - 719) & 1 && !fsec->f_slope && srcsec->f_slope)
+         fsec->f_slope = srcsec->f_slope; //P_CopySlope(srcsec->f_slope);
+      if((special - 719) & 2 && !fsec->c_slope && srcsec->c_slope)
+         fsec->c_slope = srcsec->c_slope; //P_CopySlope(srcsec->c_slope);
+   }
+
+   fsec->hasslope = true;
+
+   line->special = 0; // Linedef was use to set slopes, it finished its job, so now make it a normal linedef
+}
+
+#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
+	boolean warned = false;
+#endif
+
+	dynslopes = NULL;
+
+	// We'll handle copy slopes later, after all the tag lists have been made.
+	// Yes, this means copied slopes won't affect things' spawning heights. Too bad for you.
+	for (i = 0; i < numlines; i++)
+	{
+		switch (lines[i].special)
+		{
+#if 1 // 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:
+			case 388:
+				lines[i].special += 700-386;
+				WARNME
+				P_SpawnSlope_Line(i);
+				break;
+
+			case 389:
+			case 390:
+			case 391:
+			case 392:
+				lines[i].special += 710-389;
+				WARNME
+				P_SpawnSlope_Line(i);
+				break;
+
+			case 393:
+				lines[i].special = 703;
+				WARNME
+				P_SpawnSlope_Line(i);
+				break;
+
+			case 394:
+			case 395:
+			case 396:
+				lines[i].special += 720-394;
+				WARNME
+				break;
+
+#endif
+
+			case 700:
+			case 701:
+			case 702:
+			case 703:
+			case 710:
+			case 711:
+			case 712:
+			case 713:
+				P_SpawnSlope_Line(i);
+				break;
+
+			default:
+				break;
+		}
+	}
+}
+
+
+
+
+// ============================================================================
+//
+// Various utilities related to slopes
+//
+
+//
+// P_GetZAt
+//
+// Returns the height of the sloped plane at (x, y) as a fixed_t
+//
+fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y)
+{
+   fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) +
+                  FixedMul(y - slope->o.y, slope->d.y);
+
+   return slope->o.z + FixedMul(dist, slope->zdelta);
+}
+
+
+//
+// P_QuantizeMomentumToSlope
+//
+// When given a vector, rotates it and aligns it to a slope
+void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
+{
+	vector3_t axis;
+	axis.x = -slope->d.y;
+	axis.y = slope->d.x;
+	axis.z = 0;
+
+	FV3_Rotate(momentum, &axis, slope->zangle >> ANGLETOFINESHIFT);
+}
+
+//
+// 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;
+
+	//CONS_Printf("Launched off of slope.\n");
+	mo->standingslope = NULL;
+}
+
+// Function to help handle landing on slopes
+void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
+{
+	vector3_t mom;
+	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;
+
+	if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
+		thing->momx = mom.x;
+		thing->momy = mom.y;
+		thing->momz = -P_MobjFlip(thing);
+
+		thing->standingslope = slope;
+	}
+}
+
+// https://yourlogicalfallacyis.com/slippery-slope
+// Handles sliding down slopes, like if they were made of butter :)
+void P_ButteredSlope(mobj_t *mo)
+{
+	fixed_t thrust;
+
+	if (!mo->standingslope)
+		return;
+
+	if (mo->player) {
+		if (abs(mo->standingslope->zdelta) < FRACUNIT/4 && !(mo->player->pflags & PF_SPINNING))
+			return; // Don't slide on non-steep slopes unless spinning
+
+		if (abs(mo->standingslope->zdelta) < FRACUNIT/2 && !(mo->player->rmomx || mo->player->rmomy))
+			return; // Allow the player to stand still on slopes below a certain steepness
+	}
+
+	thrust = FINESINE(mo->standingslope->zangle>>ANGLETOFINESHIFT) * 3 / 2 * (mo->eflags & MFE_VERTICALFLIP ? 1 : -1);
+
+	if (mo->player && (mo->player->pflags & PF_SPINNING)) {
+		fixed_t mult = 0;
+		if (mo->momx || mo->momy) {
+			angle_t angle = R_PointToAngle2(0, 0, mo->momx, mo->momy) - mo->standingslope->xydirection;
+
+			if (P_MobjFlip(mo) * mo->standingslope->zdelta < 0)
+				angle ^= ANGLE_180;
+
+			mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
+		}
+
+		//CONS_Printf("%d\n", mult);
+
+		thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8);
+	}
+
+	if (mo->momx || mo->momy) // Slightly increase thrust based on the object's speed
+		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, FRACUNIT/2); // TODO actually get this
+
+	P_Thrust(mo, mo->standingslope->xydirection, thrust);
+}
+
+// EOF
+#endif // #ifdef ESLOPE
+
diff --git a/src/p_slopes.h b/src/p_slopes.h
new file mode 100644
index 0000000000000000000000000000000000000000..52988c18ff44064cb94a83a0603ec510899bec7d
--- /dev/null
+++ b/src/p_slopes.h
@@ -0,0 +1,79 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 2004 Stephen McGranahan
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+//
+//--------------------------------------------------------------------------
+//
+// DESCRIPTION:
+//      Slopes
+//      SoM created 05/10/09
+//
+//-----------------------------------------------------------------------------
+
+#ifndef P_SLOPES_H__
+#define P_SLOPES_H__
+
+#ifdef ESLOPE
+void P_ResetDynamicSlopes(void);
+void P_RunDynamicSlopes(void);
+// P_SpawnSlope_Line
+// Creates one or more slopes based on the given line type and front/back
+// 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
+//
+// Searches through tagged sectors and copies
+//
+void P_CopySectorSlope(line_t *line);
+
+// Returns the height of the sloped plane at (x, y) as a fixed_t
+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_SlopeLaunch(mobj_t *mo);
+void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
+void P_ButteredSlope(mobj_t *mo);
+
+#endif
+
+// EOF
+#endif // #ifdef ESLOPE
+
diff --git a/src/p_spec.c b/src/p_spec.c
index 8228c60b3e5e085276d9a0ca23a420798b5adbcb..694893502e503db48c978e0cd2dfb568763fb77f 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -1890,6 +1890,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 	 || specialtype == 304  // Ring count - Once
 	 || specialtype == 307  // Character ability - Once
 	 || specialtype == 308  // Race only - Once
+	 || specialtype == 313  // No More Enemies - Once
 	 || specialtype == 315  // No of pushables - Once
 	 || specialtype == 318  // Unlockable trigger - Once
 	 || specialtype == 320  // Unlockable - Once
@@ -3364,6 +3365,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *targetsec)
 {
 	ffloor_t *rover;
+	fixed_t top, bottom;
 
 	if (!mo->player) // should NEVER happen
 		return false;
@@ -3380,6 +3382,9 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
 		//if (!(rover->flags & FF_EXISTS))
 		//	return false;
 
+		top = P_GetSpecialTopZ(mo, sector, targetsec);
+		bottom = P_GetSpecialBottomZ(mo, sector, targetsec);
+
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
@@ -3387,27 +3392,27 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
 			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 != top)
 					return false;
 			}
 			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 != bottom)
 					return false;
 			}
 			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 == bottom)
+					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == top)))
 					return false;
 			}
 		}
 		else
 		{
 			// Water and intangible FOFs
-			if (mo->z > *rover->topheight || (mo->z + mo->height) < *rover->bottomheight)
+			if (mo->z > top || (mo->z + mo->height) < bottom)
 				return false;
 		}
 
@@ -3425,9 +3430,9 @@ static boolean P_ThingIsOnThe3DFloor(mobj_t *mo, sector_t *sector, sector_t *tar
 static inline boolean P_MobjReadyToTrigger(mobj_t *mo, sector_t *sec)
 {
 	if (mo->eflags & MFE_VERTICALFLIP)
-		return (mo->z+mo->height == sec->ceilingheight && sec->flags & SF_FLIPSPECIAL_CEILING);
+		return (mo->z+mo->height == P_GetSpecialTopZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_CEILING);
 	else
-		return (mo->z == sec->floorheight && sec->flags & SF_FLIPSPECIAL_FLOOR);
+		return (mo->z == P_GetSpecialBottomZ(mo, sec, sec) && sec->flags & SF_FLIPSPECIAL_FLOOR);
 }
 
 /** Applies a sector special to a player.
@@ -4388,27 +4393,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 != *rover->topheight)
+				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))
 					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 != P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
 					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 == P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))))
 					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 > P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector) || (player->mo->z + player->mo->height) < P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
 				continue;
 		}
 
@@ -4518,6 +4523,7 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
 {
 	boolean nofloorneeded = false;
+	fixed_t f_affectpoint, c_affectpoint;
 
 	if (!sector->special) // nothing special, exit
 		return;
@@ -4580,16 +4586,19 @@ static void P_RunSpecialSectorCheck(player_t *player, sector_t *sector)
 		return;
 	}
 
+	f_affectpoint = P_GetSpecialBottomZ(player->mo, sector, sector);
+	c_affectpoint = P_GetSpecialTopZ(player->mo, sector, sector);
+
 	// Only go further if on the ground
-	if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != sector->floorheight)
+	if ((sector->flags & SF_FLIPSPECIAL_FLOOR) && !(sector->flags & SF_FLIPSPECIAL_CEILING) && player->mo->z != f_affectpoint)
 		return;
 
-	if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != sector->ceilingheight)
+	if ((sector->flags & SF_FLIPSPECIAL_CEILING) && !(sector->flags & SF_FLIPSPECIAL_FLOOR) && player->mo->z + player->mo->height != c_affectpoint)
 		return;
 
 	if ((sector->flags & SF_FLIPSPECIAL_BOTH)
-		&& player->mo->z != sector->floorheight
-		&& player->mo->z + player->mo->height != sector->ceilingheight)
+		&& player->mo->z != f_affectpoint
+		&& player->mo->z + player->mo->height != c_affectpoint)
 		return;
 
 	P_ProcessSpecialSector(player, sector, NULL);
@@ -4750,6 +4759,9 @@ void P_UpdateSpecials(void)
 	// POINT LIMIT
 	P_CheckPointLimit();
 
+	// Dynamic slopeness
+	P_RunDynamicSlopes();
+
 	// ANIMATE TEXTURES
 	for (anim = anims; anim < lastanim; anim++)
 	{
@@ -4893,6 +4905,12 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
 	ffloor->topyoffs = &sec2->ceiling_yoffs;
 	ffloor->topangle = &sec2->ceilingpic_angle;
 
+#ifdef ESLOPE
+	// Add slopes
+	ffloor->t_slope = &sec2->c_slope;
+	ffloor->b_slope = &sec2->f_slope;
+#endif
+
 	if ((flags & FF_SOLID) && (master->flags & ML_EFFECT1)) // Block player only
 		flags &= ~FF_BLOCKOTHERS;
 
@@ -5326,6 +5344,7 @@ void T_LaserFlash(laserthink_t *flash)
 	sector_t *sourcesec;
 	ffloor_t *ffloor = flash->ffloor;
 	sector_t *sector = flash->sector;
+	fixed_t top, bottom;
 
 	if (!ffloor || !(ffloor->flags & FF_EXISTS))
 		return;
@@ -5349,8 +5368,11 @@ void T_LaserFlash(laserthink_t *flash)
 			&& thing->flags & MF_BOSS)
 			continue; // Don't hurt bosses
 
-		if (thing->z >= sourcesec->ceilingheight
-		|| thing->z + thing->height <= sourcesec->floorheight)
+		top = P_GetSpecialTopZ(thing, sourcesec, sector);
+		bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
+
+		if (thing->z >= top
+		|| thing->z + thing->height <= bottom)
 			continue;
 
 		if (thing->flags & MF_SHOOTABLE)
@@ -6429,6 +6451,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
 					sectors[s].midmap = lines[i].frontsector->midmap;
 				break;
 
+#ifdef ESLOPE // Slope copy specials. Handled here for sanity.
+			case 720:
+			case 721:
+			case 722:
+				P_CopySectorSlope(&lines[i]);
+				break;
+#endif
+
 			default:
 				break;
 		}
@@ -6526,7 +6556,7 @@ static void P_DoScrollMove(mobj_t *thing, fixed_t dx, fixed_t dy, INT32 exclusiv
 	thing->momy += dy;
 
 	if (exclusive)
-		thing->flags2 |= MF2_PUSHED;
+		thing->eflags |= MFE_PUSHED;
 }
 
 /** Processes an active scroller.
@@ -6630,9 +6660,11 @@ void T_Scroll(scroll_t *s)
 					{
 						thing = node->m_thing;
 
-						if (thing->flags2 & MF2_PUSHED) // Already pushed this tic by an exclusive pusher.
+						if (thing->eflags & MFE_PUSHED) // Already pushed this tic by an exclusive pusher.
 							continue;
 
+						height = P_GetSpecialBottomZ(thing, sec, psec);
+
 						if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped
 						if (!(thing->flags & MF_NOGRAVITY || thing->z+thing->height != height)) // Thing must a) be non-floating and have z+height == height
 						{
@@ -6650,9 +6682,11 @@ void T_Scroll(scroll_t *s)
 				{
 					thing = node->m_thing;
 
-					if (thing->flags2 & MF2_PUSHED)
+					if (thing->eflags & MFE_PUSHED)
 						continue;
 
+					height = P_GetSpecialBottomZ(thing, sec, sec);
+
 					if (!(thing->flags & MF_NOCLIP) &&
 						(!(thing->flags & MF_NOGRAVITY || thing->z > height)))
 					{
@@ -6689,9 +6723,11 @@ void T_Scroll(scroll_t *s)
 					{
 						thing = node->m_thing;
 
-						if (thing->flags2 & MF2_PUSHED)
+						if (thing->eflags & MFE_PUSHED)
 							continue;
 
+						height = P_GetSpecialTopZ(thing, sec, psec);
+
 						if (!(thing->flags & MF_NOCLIP)) // Thing must be clipped
 						if (!(thing->flags & MF_NOGRAVITY || thing->z != height))// Thing must a) be non-floating and have z == height
 						{
@@ -6709,9 +6745,11 @@ void T_Scroll(scroll_t *s)
 				{
 					thing = node->m_thing;
 
-					if (thing->flags2 & MF2_PUSHED)
+					if (thing->eflags & MFE_PUSHED)
 						continue;
 
+					height = P_GetSpecialTopZ(thing, sec, sec);
+
 					if (!(thing->flags & MF_NOCLIP) &&
 						(!(thing->flags & MF_NOGRAVITY || thing->z+thing->height < height)))
 					{
@@ -7005,7 +7043,7 @@ static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32
   */
 void T_Friction(friction_t *f)
 {
-	sector_t *sec;
+	sector_t *sec, *referrer;
 	mobj_t *thing;
 	msecnode_t *node;
 
@@ -7014,7 +7052,7 @@ void T_Friction(friction_t *f)
 	// Make sure the sector type hasn't changed
 	if (f->roverfriction)
 	{
-		sector_t *referrer = sectors + f->referrer;
+		referrer = sectors + f->referrer;
 
 		if (!(GETSECSPECIAL(referrer->special, 3) == 1
 			|| GETSECSPECIAL(referrer->special, 3) == 3))
@@ -7046,9 +7084,7 @@ void T_Friction(friction_t *f)
 		{
 			if (f->roverfriction)
 			{
-				sector_t *referrer = &sectors[f->referrer];
-
-				if (thing->floorz != referrer->ceilingheight)
+				if (thing->floorz != P_GetSpecialTopZ(thing, referrer, sec))
 				{
 					node = node->m_snext;
 					continue;
@@ -7061,7 +7097,7 @@ void T_Friction(friction_t *f)
 					thing->movefactor = f->movefactor;
 				}
 			}
-			else if (sec->floorheight == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction?
+			else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction?
 				|| f->friction < thing->friction))
 			{
 				thing->friction = f->friction;
@@ -7192,7 +7228,7 @@ static pusher_t *tmpusher; // pusher structure for blockmap searches
   */
 static inline boolean PIT_PushThing(mobj_t *thing)
 {
-	if (thing->flags2 & MF2_PUSHED)
+	if (thing->eflags & MFE_PUSHED)
 		return false;
 
 	if (thing->player && thing->player->pflags & PF_ROPEHANG)
@@ -7322,7 +7358,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
 	}
 
 	if (tmpusher->exclusive)
-		thing->flags2 |= MF2_PUSHED;
+		thing->eflags |= MFE_PUSHED;
 
 	return true;
 }
@@ -7335,7 +7371,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
   */
 void T_Pusher(pusher_t *p)
 {
-	sector_t *sec;
+	sector_t *sec, *referrer;
 	mobj_t *thing;
 	msecnode_t *node;
 	INT32 xspeed = 0,yspeed = 0;
@@ -7344,7 +7380,6 @@ void T_Pusher(pusher_t *p)
 	//INT32 ht = 0;
 	boolean inFOF;
 	boolean touching;
-	boolean foundfloor = false;
 	boolean moved;
 
 	xspeed = yspeed = 0;
@@ -7356,19 +7391,16 @@ void T_Pusher(pusher_t *p)
 
 	if (p->roverpusher)
 	{
-		sector_t *referrer = &sectors[p->referrer];
+		referrer = &sectors[p->referrer];
 
-		if (GETSECSPECIAL(referrer->special, 3) == 2
-			|| GETSECSPECIAL(referrer->special, 3) == 3)
-			foundfloor = true;
+		if (!(GETSECSPECIAL(referrer->special, 3) == 2
+			|| GETSECSPECIAL(referrer->special, 3) == 3))
+			return;
 	}
 	else if (!(GETSECSPECIAL(sec->special, 3) == 2
 			|| GETSECSPECIAL(sec->special, 3) == 3))
 		return;
 
-	if (p->roverpusher && foundfloor == false) // Not even a 3d floor has the PUSH_MASK.
-		return;
-
 	// For constant pushers (wind/current) there are 3 situations:
 	//
 	// 1) Affected Thing is above the floor.
@@ -7429,7 +7461,7 @@ void T_Pusher(pusher_t *p)
 			|| thing->type == MT_BIGTUMBLEWEED))
 			continue;
 
-		if (thing->flags2 & MF2_PUSHED)
+		if (thing->eflags & MFE_PUSHED)
 			continue;
 
 		if (thing->player && thing->player->pflags & PF_ROPEHANG)
@@ -7443,41 +7475,38 @@ void T_Pusher(pusher_t *p)
 		// Find the area that the 'thing' is in
 		if (p->roverpusher)
 		{
-			sector_t *referrer = &sectors[p->referrer];
-			INT32 special;
+			fixed_t top, bottom;
 
-			special = GETSECSPECIAL(referrer->special, 3);
-
-			if (!(special == 2 || special == 3))
-				return;
+			top = P_GetSpecialTopZ(thing, referrer, sec);
+			bottom = P_GetSpecialBottomZ(thing, referrer, sec);
 
 			if (thing->eflags & MFE_VERTICALFLIP)
 			{
-				if (referrer->floorheight > thing->z + thing->height
-					|| referrer->ceilingheight < (thing->z + (thing->height >> 1)))
+				if (bottom > thing->z + thing->height
+					|| top < (thing->z + (thing->height >> 1)))
 					continue;
 
-				if (thing->z < referrer->floorheight)
+				if (thing->z < bottom)
 					touching = true;
 
-				if (thing->z + (thing->height >> 1) > referrer->floorheight)
+				if (thing->z + (thing->height >> 1) > bottom)
 					inFOF = true;
 
 			}
 			else
 			{
-				if (referrer->ceilingheight < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
+				if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
 					continue;
-				if (thing->z + thing->height > referrer->ceilingheight)
+				if (thing->z + thing->height > top)
 					touching = true;
 
-				if (thing->z + (thing->height >> 1) < referrer->ceilingheight)
+				if (thing->z + (thing->height >> 1) < top)
 					inFOF = true;
 			}
 		}
 		else // Treat the entire sector as one big FOF
 		{
-			if (thing->z == thing->subsector->sector->floorheight)
+			if (thing->z == P_GetSpecialBottomZ(thing, sec, sec))
 				touching = true;
 			else if (p->type != p_current)
 				inFOF = true;
@@ -7599,7 +7628,7 @@ void T_Pusher(pusher_t *p)
 			}
 
 			if (p->exclusive)
-				thing->flags2 |= MF2_PUSHED;
+				thing->eflags |= MFE_PUSHED;
 		}
 	}
 }
diff --git a/src/p_user.c b/src/p_user.c
index 6844d2cba37560905f15a2ab13b99ab3df7e0081..d57d5cb99771b18adfeb100bfe62958197a15238 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1212,7 +1212,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
 	if (mo->eflags & MFE_VERTICALFLIP)
 	{
 		// Detect if the player is on the ceiling.
-		if (mo->z+mo->height >= sec->ceilingheight)
+		if (mo->z+mo->height >= P_GetSpecialTopZ(mo, sec, sec))
 			return true;
 		// Otherwise, detect if the player is on the bottom of a FOF.
 		else
@@ -1236,7 +1236,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
 					continue;
 
 				// Actually check if the player is on the suitable FOF.
-				if (mo->z+mo->height == *rover->bottomheight)
+				if (mo->z+mo->height == P_GetSpecialBottomZ(mo, sectors + rover->secnum, sec))
 					return true;
 			}
 		}
@@ -1245,7 +1245,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
 	else
 	{
 		// Detect if the player is on the floor.
-		if (mo->z <= sec->floorheight)
+		if (mo->z <= P_GetSpecialBottomZ(mo, sec, sec))
 			return true;
 		// Otherwise, detect if the player is on the top of a FOF.
 		else
@@ -1269,7 +1269,7 @@ boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec)
 					continue;
 
 				// Actually check if the player is on the suitable FOF.
-				if (mo->z == *rover->topheight)
+				if (mo->z == P_GetSpecialTopZ(mo, sectors + rover->secnum, sec))
 					return true;
 			}
 		}
@@ -1789,6 +1789,9 @@ static void P_CheckBouncySectors(player_t *player)
 	fixed_t oldx;
 	fixed_t oldy;
 	fixed_t oldz;
+#ifdef ESLOPE
+	vector3_t momentum;
+#endif
 
 	oldx = player->mo->x;
 	oldy = player->mo->y;
@@ -1809,16 +1812,21 @@ static void P_CheckBouncySectors(player_t *player)
 		{
 			ffloor_t *rover;
 			boolean top = true;
+			fixed_t topheight, bottomheight;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 			{
-				if (player->mo->z > *rover->topheight)
+				topheight = P_GetFOFTopZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+				bottomheight = P_GetFOFBottomZ(player->mo, node->m_sector, rover, player->mo->x, player->mo->y, NULL);
+
+				if (player->mo->z > topheight)
 					continue;
 
-				if (player->mo->z + player->mo->height < *rover->bottomheight)
+				if (player->mo->z + player->mo->height < bottomheight)
 					continue;
 
-				if (oldz < *rover->topheight && oldz > *rover->bottomheight)
+				if (oldz < P_GetFOFTopZ(player->mo, node->m_sector, rover, oldx, oldy, NULL)
+						&& oldz + player->mo->height > P_GetFOFBottomZ(player->mo, node->m_sector, rover, oldx, oldy, NULL))
 					top = false;
 
 				if (GETSECSPECIAL(rover->master->frontsector->special, 1) == 15)
@@ -1833,7 +1841,29 @@ static void P_CheckBouncySectors(player_t *player)
 					{
 						fixed_t newmom;
 
+#ifdef ESLOPE
+						pslope_t *slope;
+						if (abs(oldz - topheight) < abs(oldz + player->mo->height - bottomheight)) { // Hit top
+							slope = *rover->t_slope;
+						} else { // Hit bottom
+							slope = *rover->b_slope;
+						}
+
+						momentum.x = player->mo->momx;
+						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;
+						}
+
+						newmom = momentum.z = -FixedMul(momentum.z,linedist)/2;
+#else
 						newmom = -FixedMul(player->mo->momz,linedist);
+#endif
 
 						if (abs(newmom) < (linedist*2))
 						{
@@ -1856,7 +1886,18 @@ static void P_CheckBouncySectors(player_t *player)
 						else if (newmom < -P_GetPlayerHeight(player)/2)
 							newmom = -P_GetPlayerHeight(player)/2;
 
+#ifdef ESLOPE
+						momentum.z = newmom*2;
+
+						if (slope)
+							P_QuantizeMomentumToSlope(&momentum, slope);
+
+						player->mo->momx = momentum.x;
+						player->mo->momy = momentum.y;
+						player->mo->momz = momentum.z/2;
+#else
 						player->mo->momz = newmom;
+#endif
 
 						if (player->pflags & PF_SPINNING)
 						{
@@ -2280,10 +2321,23 @@ static void P_DoClimbing(player_t *player)
 		floorclimb = false;
 		boostup = false;
 		skyclimber = false;
+		fixed_t floorheight, ceilingheight; // ESLOPE
+
+#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;
+#else
+		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 (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
@@ -2291,13 +2345,21 @@ static void P_DoClimbing(player_t *player)
 
 				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;
+#else
+				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) && (*rover->bottomheight < player->mo->z+player->mo->height)
-						&& (*rover->topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
-					|| ((player->mo->eflags & MFE_VERTICALFLIP) && (*rover->topheight > player->mo->z)
-						&& (*rover->bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
+					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))))
 					{
 						if (cmd->forwardmove != 0)
 							player->mo->momz += rover->master->frontsector->floorspeed;
@@ -2313,8 +2375,9 @@ static void P_DoClimbing(player_t *player)
 				if (player->mo->eflags & MFE_VERTICALFLIP)
 				{
 					// Trying to climb down past the bottom of the FOF
-					if ((*rover->topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= *rover->topheight))
+					if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
 					{
+						fixed_t bottomheight2;
 						ffloor_t *roverbelow;
 						boolean foundfof = false;
 						floorclimb = true;
@@ -2329,7 +2392,13 @@ static void P_DoClimbing(player_t *player)
 							if (roverbelow == rover)
 								continue;
 
-							if (*roverbelow->bottomheight < *rover->topheight + FixedMul(16*FRACUNIT, player->mo->scale))
+#ifdef ESLOPE
+							bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
+#else
+							bottomheight2 = *roverbelow->bottomheight;
+#endif
+
+							if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
 								foundfof = true;
 						}
 
@@ -2338,7 +2407,7 @@ static void P_DoClimbing(player_t *player)
 					}
 
 					// Below the FOF
-					if (*rover->topheight <= player->mo->z)
+					if (topheight <= player->mo->z)
 					{
 						floorclimb = false;
 						boostup = false;
@@ -2346,7 +2415,7 @@ static void P_DoClimbing(player_t *player)
 					}
 
 					// Above the FOF
-					if (*rover->bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
+					if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
 					{
 						floorclimb = false;
 						thrust = true;
@@ -2356,8 +2425,9 @@ static void P_DoClimbing(player_t *player)
 				else
 				{
 					// Trying to climb down past the bottom of a FOF
-					if ((*rover->bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= *rover->bottomheight))
+					if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
 					{
+						fixed_t topheight2;
 						ffloor_t *roverbelow;
 						boolean foundfof = false;
 						floorclimb = true;
@@ -2372,7 +2442,13 @@ static void P_DoClimbing(player_t *player)
 							if (roverbelow == rover)
 								continue;
 
-							if (*roverbelow->topheight > *rover->bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
+#ifdef ESLOPE
+							topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
+#else
+							topheight2 = *roverbelow->topheight;
+#endif
+
+							if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
 								foundfof = true;
 						}
 
@@ -2381,7 +2457,7 @@ static void P_DoClimbing(player_t *player)
 					}
 
 					// Below the FOF
-					if (*rover->bottomheight >= player->mo->z + player->mo->height)
+					if (bottomheight >= player->mo->z + player->mo->height)
 					{
 						floorclimb = false;
 						boostup = false;
@@ -2389,7 +2465,7 @@ static void P_DoClimbing(player_t *player)
 					}
 
 					// Above the FOF
-					if (*rover->topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+					if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
 					{
 						floorclimb = false;
 						thrust = true;
@@ -2410,7 +2486,7 @@ static void P_DoClimbing(player_t *player)
 		if (player->mo->eflags & MFE_VERTICALFLIP)
 		{
 			// Trying to climb down past the upper texture area
-			if ((glidesector->sector->floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= glidesector->sector->floorheight))
+			if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
 			{
 				boolean foundfof = false;
 				floorclimb = true;
@@ -2418,13 +2494,20 @@ static void P_DoClimbing(player_t *player)
 				// Is there a FOF directly below that we can move onto?
 				if (glidesector->sector->ffloors)
 				{
+					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;
 
-						if (*rover->bottomheight < glidesector->sector->floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
+#ifdef ESLOPE
+						bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+#else
+						bottomheight = *rover->bottomheight;
+#endif
+
+						if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
 						{
 							foundfof = true;
 							break;
@@ -2437,8 +2520,8 @@ static void P_DoClimbing(player_t *player)
 			}
 
 			// Reached the top of the lower texture area
-			if (!floorclimb && glidesector->sector->ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || glidesector->sector->floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
+			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;
@@ -2448,7 +2531,7 @@ static void P_DoClimbing(player_t *player)
 		else
 		{
 			// Trying to climb down past the upper texture area
-			if ((glidesector->sector->ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= glidesector->sector->ceilingheight))
+			if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
 			{
 				boolean foundfof = false;
 				floorclimb = true;
@@ -2462,7 +2545,7 @@ static void P_DoClimbing(player_t *player)
 						if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
 							continue;
 
-						if (*rover->topheight > glidesector->sector->ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+						if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
 						{
 							foundfof = true;
 							break;
@@ -2475,7 +2558,7 @@ static void P_DoClimbing(player_t *player)
 			}
 
 			// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
-			if (player->mo->z > glidesector->sector->ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+			if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
 			{
 				floorclimb = true;
 				thrust = false;
@@ -2483,8 +2566,8 @@ static void P_DoClimbing(player_t *player)
 			}
 
 			// Reached the top of the lower texture area
-			if (!floorclimb && glidesector->sector->floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || glidesector->sector->ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+			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;
@@ -2493,14 +2576,14 @@ static void P_DoClimbing(player_t *player)
 		}
 
 		// Trying to climb on the sky
-		if ((glidesector->sector->ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
+		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) < glidesector->sector->floorheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= glidesector->sector->floorheight))
+		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;
 
@@ -2516,8 +2599,8 @@ static void P_DoClimbing(player_t *player)
 			}
 		}
 		// Climbing on the upper texture area?
-		else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= glidesector->sector->ceilingheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > glidesector->sector->ceilingheight))
+		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;
 
@@ -2963,6 +3046,8 @@ static void P_DoTeeter(player_t *player)
 		xh = (unsigned)(player->mo->x + player->mo->radius - bmaporgx)>>MAPBLOCKSHIFT;
 		xl = (unsigned)(player->mo->x - player->mo->radius - bmaporgx)>>MAPBLOCKSHIFT;
 
+		BMBOUNDFIX(xl, xh, yl, yh);
+
 	// Polyobjects
 #ifdef POLYOBJECTS
 		validcount++;
@@ -3330,6 +3415,7 @@ firenormal:
 //
 static void P_DoSuperStuff(player_t *player)
 {
+	mobj_t *spark;
 	ticcmd_t *cmd = &player->cmd;
 	if (player->mo->state >= &states[S_PLAY_SUPERTRANS1] && player->mo->state <= &states[S_PLAY_SUPERTRANS9])
 		return; // don't do anything right now, we're in the middle of transforming!
@@ -3384,19 +3470,32 @@ static void P_DoSuperStuff(player_t *player)
 		switch (player->skin)
 		{
 		case 1: // Golden orange supertails.
-			player->mo->color = SKINCOLOR_TSUPER1 + (leveltime/2) % 5;
+			if (leveltime % 9 < 5)
+				player->mo->color = SKINCOLOR_TSUPER1 + leveltime % 9;
+			else
+				player->mo->color = SKINCOLOR_TSUPER1 + 9 - leveltime % 9;
 			break;
 		case 2: // Pink superknux.
-			player->mo->color = SKINCOLOR_KSUPER1 + (leveltime/2) % 5;
+			if (leveltime % 9 < 5)
+				player->mo->color = SKINCOLOR_KSUPER1 + leveltime % 9;
+			else
+				player->mo->color = SKINCOLOR_KSUPER1 + 9 - leveltime % 9;
 			break;
 		default: // Yousa yellow now!
-			player->mo->color = SKINCOLOR_SUPER1 + (leveltime/2) % 5;
+			if (leveltime % 9 < 5)
+				player->mo->color = SKINCOLOR_SUPER1 + leveltime % 9;
+			else
+				player->mo->color = SKINCOLOR_SUPER1 + 9 - leveltime % 9;
 			break;
 		}
 
 		if ((cmd->forwardmove != 0 || cmd->sidemove != 0 || player->pflags & (PF_CARRIED|PF_ROPEHANG|PF_ITEMHANG|PF_MACESPIN))
 		&& !(leveltime % TICRATE) && (player->mo->momx || player->mo->momy))
-			P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK);
+		{
+			spark = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SUPERSPARK);
+			spark->destscale = player->mo->scale;
+			P_SetScale(spark, player->mo->scale);
+		}
 
 		G_GhostAddColor(GHC_SUPER);
 
@@ -3661,7 +3760,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 	if ((player->charability2 == CA2_SPINDASH) && !(player->pflags & PF_SLIDING) && !player->exiting
 		&& !P_PlayerInPain(player)) // subsequent revs
 	{
-		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))
+		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)
+#endif
+			)
 		{
 			player->mo->momx = player->cmomx;
 			player->mo->momy = player->cmomy;
@@ -3690,7 +3793,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 		// down the spin button and not spinning.
 		// AKA Just go into a spin on the ground, you idiot. ;)
 		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) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
+			&& !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)
+#endif
+			) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
 		{
 			player->pflags |= PF_SPINNING;
 			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
@@ -3702,7 +3809,11 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 
 	// Rolling normally
 	if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
-		&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale))
+		&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale)
+#ifdef ESLOPE
+			&& (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+#endif
+			)
 	{
 		if (GETSECSPECIAL(player->mo->subsector->sector->special, 4) == 7 || (player->mo->ceilingz - player->mo->floorz < P_GetPlayerHeight(player)))
 			P_InstaThrust(player->mo, player->mo->angle, FixedMul(10*FRACUNIT, player->mo->scale));
@@ -4406,12 +4517,16 @@ static void P_3dMovement(player_t *player)
 	angle_t dangle; // replaces old quadrants bits
 	fixed_t normalspd = FixedMul(player->normalspeed, player->mo->scale);
 	boolean analogmove = false;
-#ifndef OLD_MOVEMENT_CODE
 	fixed_t oldMagnitude, newMagnitude;
+#ifdef ESLOPE
+	vector3_t totalthrust;
+
+	totalthrust.x = totalthrust.y = 0; // I forget if this is needed
+	totalthrust.z = FRACUNIT*P_MobjFlip(player->mo)/3; // A bit of extra push-back on slopes
+#endif // ESLOPE
 
 	// Get the old momentum; this will be needed at the end of the function! -SH
 	oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
-#endif
 
 	analogmove = P_AnalogMove(player);
 
@@ -4588,17 +4703,10 @@ static void P_3dMovement(player_t *player)
 		}
 
 		movepushforward = FixedMul(movepushforward, player->mo->scale);
-#ifdef OLD_MOVEMENT_CODE
-		if (player->speed < topspeed && mforward && cmd->forwardmove > 0) // Sonic's Speed
-			P_Thrust(player->mo, movepushangle, movepushforward);
-		else if (mforward && cmd->forwardmove < 0)
-			P_Thrust(player->mo, movepushangle, movepushforward);
-		else if (player->speed < topspeed && mbackward && cmd->forwardmove < 0)
-			P_Thrust(player->mo, movepushangle, movepushforward);
-		else if (mbackward && cmd->forwardmove > 0)
-			P_Thrust(player->mo, movepushangle, movepushforward);
-		else if (!mforward && !mbackward)
-			P_Thrust(player->mo, movepushangle, movepushforward);
+
+#ifdef ESLOPE
+		totalthrust.x += P_ReturnThrustX(player->mo, movepushangle, movepushforward);
+		totalthrust.y += P_ReturnThrustY(player->mo, movepushangle, movepushforward);
 #else
 		P_Thrust(player->mo, movepushangle, movepushforward);
 #endif
@@ -4617,33 +4725,12 @@ static void P_3dMovement(player_t *player)
 		if (!(player->pflags & PF_GLIDING || player->exiting || P_PlayerInPain(player)))
 		{
 			angle_t controldirection;
-#ifdef OLD_MOVEMENT_CODE
-			angle_t controlplayerdirection;
-			boolean cforward; // controls pointing forward from the player
-			boolean cbackward; // controls pointing backward from the player
-			angle_t dangle;
 
-			cforward = cbackward = false;
-#endif
 			// Calculate the angle at which the controls are pointing
 			// to figure out the proper mforward and mbackward.
 			// (Why was it so complicated before? ~Red)
 			controldirection = R_PointToAngle2(0, 0, cmd->forwardmove*FRACUNIT, -cmd->sidemove*FRACUNIT)+movepushangle;
 
-#ifdef OLD_MOVEMENT_CODE
-			controlplayerdirection = player->mo->angle;
-
-			dangle = controldirection - controlplayerdirection;
-
-			if (dangle > ANGLE_180) //flip to keep to one side
-				dangle = InvAngle(dangle);
-
-			if (dangle > ANGLE_90)
-				cbackward = true; // Controls pointing backwards from player
-			else
-				cforward = true; // Controls pointing in player's general direction
-#endif
-
 			movepushforward = max(abs(cmd->sidemove), abs(cmd->forwardmove)) * (thrustfactor * acceleration);
 
 			// allow very small movement while in air for gameplay
@@ -4666,13 +4753,10 @@ static void P_3dMovement(player_t *player)
 			movepushsideangle = controldirection;
 
 			movepushforward = FixedMul(movepushforward, player->mo->scale);
-#ifdef OLD_MOVEMENT_CODE
-			if (player->speed < topspeed)
-				P_Thrust(player->mo, controldirection, movepushforward);
-			else if ((mforward) && (cbackward))
-				P_Thrust(player->mo, controldirection, movepushforward);
-			else if ((mbackward) && (cforward))
-				P_Thrust(player->mo, controldirection, movepushforward);
+
+#ifdef ESLOPE
+			totalthrust.x += P_ReturnThrustX(player->mo, controldirection, movepushforward);
+			totalthrust.y += P_ReturnThrustY(player->mo, controldirection, movepushforward);
 #else
 			P_Thrust(player->mo, controldirection, movepushforward);
 #endif
@@ -4680,29 +4764,6 @@ static void P_3dMovement(player_t *player)
 	}
 	else if (cmd->sidemove && !(player->pflags & PF_GLIDING) && !player->exiting && !P_PlayerInPain(player))
 	{
-#ifdef OLD_MOVEMENT_CODE
-		boolean mright = 0;
-		boolean mleft = 0;
-		angle_t sideangle;
-
-		sideangle = player->mo->angle - ANGLE_90;
-
-		// Monster Iestyn - 04-11-13
-		// Quadrants are stupid, excessive and broken, let's do this a much simpler way!
-		// Get delta angle from rmom angle and player angle first
-		dangle = R_PointToAngle2(0,0, player->rmomx, player->rmomy) - sideangle;
-		if (dangle > ANGLE_180)
-			dangle = InvAngle(dangle);
-
-		// now use it to determine direction!
-		if (dangle <= ANGLE_45) // angles 0-45 or 315-360
-			mright = 1; // going right
-		else if (dangle >= ANGLE_135) // angles 135-225
-			mleft = 1; // going left
-
-		// anything else will leave both at 0, so no need to do anything else
-#endif
-
 		movepushside = cmd->sidemove * (thrustfactor * acceleration);
 
 		if (!onground)
@@ -4725,19 +4786,37 @@ static void P_3dMovement(player_t *player)
 
 		// Finally move the player now that his speed/direction has been decided.
 		movepushside = FixedMul(movepushside, player->mo->scale);
-#ifdef OLD_MOVEMENT_CODE
-		if (player->speed < topspeed)
-			P_Thrust(player->mo, movepushsideangle, movepushside);
-		else if (mright && cmd->sidemove < 0)
-			P_Thrust(player->mo, movepushsideangle, movepushside);
-		else if (mleft && cmd->sidemove > 0)
-			P_Thrust(player->mo, movepushsideangle, movepushside);
+
+#ifdef ESLOPE
+		totalthrust.x += P_ReturnThrustX(player->mo, movepushsideangle, movepushside);
+		totalthrust.y += P_ReturnThrustY(player->mo, movepushsideangle, movepushside);
 #else
 		P_Thrust(player->mo, movepushsideangle, movepushside);
 #endif
 	}
 
-#ifndef OLD_MOVEMENT_CODE
+#ifdef ESLOPE
+	if ((totalthrust.x || totalthrust.y)
+		&& player->mo->standingslope && 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;
+
+		if (player->mo->standingslope->zdelta < 0) { // Direction goes down, so thrustangle needs to face toward
+			if (thrustangle < ANGLE_90 || thrustangle > ANGLE_270) {
+				P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope);
+			}
+		} else { // Direction goes up, so thrustangle needs to face away
+			if (thrustangle > ANGLE_90 && thrustangle < ANGLE_270) {
+				P_QuantizeMomentumToSlope(&totalthrust, player->mo->standingslope);
+			}
+		}
+	}
+
+	player->mo->momx += totalthrust.x;
+	player->mo->momy += totalthrust.y;
+#endif
+
 	// Time to ask three questions:
 	// 1) Are we over topspeed?
 	// 2) If "yes" to 1, were we moving over topspeed to begin with?
@@ -4771,7 +4850,6 @@ static void P_3dMovement(player_t *player)
 			player->mo->momy = tempmomy + player->cmomy;
 		}
 	}
-#endif
 }
 
 //
@@ -7769,24 +7847,24 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 	angle_t angle = 0, focusangle = 0, focusaiming = 0;
 	fixed_t x, y, z, dist, checkdist, viewpointx, viewpointy, camspeed, camdist, camheight, pviewheight;
 	INT32 camrotate;
-	boolean camstill, forceon = false, cameranoclip;
+	boolean camstill, cameranoclip;
 	mobj_t *mo;
 	subsector_t *newsubsec;
 	fixed_t f1, f2;
 
 	cameranoclip = (player->pflags & (PF_NOCLIP|PF_NIGHTSMODE)) || (player->mo->flags & (MF_NOCLIP|MF_NOCLIPHEIGHT)); // Noclipping player camera noclips too!!
 
-	if (player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD)
-		forceon = true;
-
-	if (!forceon && player->spectator) // force cam off for spectators
-		return true;
+	if (!(player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD))
+	{
+		if (player->spectator) // force cam off for spectators
+			return true;
 
-	if (!forceon && !cv_chasecam.value && thiscam == &camera)
-		return true;
+		if (!cv_chasecam.value && thiscam == &camera)
+			return true;
 
-	if (!forceon && !cv_chasecam2.value && thiscam == &camera2)
-		return true;
+		if (!cv_chasecam2.value && thiscam == &camera2)
+			return true;
+	}
 
 	if (!thiscam->chase && !resetcalled)
 	{
@@ -8085,6 +8163,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		yl = (unsigned)(tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
 		yh = (unsigned)(tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
 
+		BMBOUNDFIX(xl, xh, yl, yh);
+
 		for (by = yl; by <= yh; by++)
 			for (bx = xl; bx <= xh; bx++)
 			{
@@ -9077,7 +9157,7 @@ void P_PlayerAfterThink(player_t *player)
 {
 	ticcmd_t *cmd;
 	INT32 oldweapon = player->currentweapon;
-	camera_t *thiscam;
+	camera_t *thiscam = NULL; // if not one of the displayed players, just don't bother
 
 #ifdef PARANOIA
 	if (!player->mo)
@@ -9091,7 +9171,7 @@ void P_PlayerAfterThink(player_t *player)
 
 	if (splitscreen && player == &players[secondarydisplayplayer])
 		thiscam = &camera2;
-	else
+	else if (player == &players[displayplayer])
 		thiscam = &camera;
 
 	if (player->playerstate == PST_DEAD)
@@ -9099,7 +9179,7 @@ void P_PlayerAfterThink(player_t *player)
 		// camera may still move when guy is dead
 		//if (!netgame)
 		{
-			if (((splitscreen && player == &players[secondarydisplayplayer]) || player == &players[displayplayer]) && thiscam->chase)
+			if (thiscam && thiscam->chase)
 				P_MoveChaseCamera(player, thiscam, false);
 		}
 		return;
@@ -9354,7 +9434,7 @@ void P_PlayerAfterThink(player_t *player)
 		}
 	}
 
-	if ((splitscreen && player == &players[secondarydisplayplayer]) || player == &players[displayplayer])
+	if (thiscam)
 	{
 		if (!thiscam->chase) // bob view only if looking through the player's eyes
 		{
diff --git a/src/r_bsp.c b/src/r_bsp.c
index e967e28cef3e194ebb5e43dcf652f9e2f91061e5..5474a4345f8a38f06299a2b387ac68183336490a 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -459,6 +459,11 @@ static void R_AddLine(seg_t *line)
 	doorclosed = 0;
 
 	// Closed door.
+#ifdef ESLOPE
+	// Just don't bother checking this if one side is sloped. This is probably inefficient, but it's better than
+	// random renderer stopping around slopes...
+	if (!(frontsector->f_slope || frontsector->c_slope || backsector->f_slope || backsector->c_slope))
+#endif
 	if (backsector->ceilingheight <= frontsector->floorheight
 		|| backsector->floorheight >= frontsector->ceilingheight)
 	{
@@ -487,6 +492,10 @@ static void R_AddLine(seg_t *line)
 #endif
 		backsector->ceilingpic == frontsector->ceilingpic
 		&& backsector->floorpic == frontsector->floorpic
+#ifdef ESLOPE
+		&& backsector->f_slope == frontsector->f_slope
+		&& backsector->c_slope == frontsector->c_slope
+#endif
 		&& backsector->lightlevel == frontsector->lightlevel
 		&& !curline->sidedef->midtexture
 		// Check offsets too!
@@ -842,11 +851,19 @@ static void R_Subsector(size_t num)
 			sub->sector->moved = frontsector->moved = false;
 		}
 
-		light = R_GetPlaneLight(frontsector, frontsector->floorheight, false);
+		light = R_GetPlaneLight(frontsector,
+#ifdef ESLOPE
+								frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+								frontsector->floorheight, false);
 		if (frontsector->floorlightsec == -1)
 			floorlightlevel = *frontsector->lightlist[light].lightlevel;
 		floorcolormap = frontsector->lightlist[light].extra_colormap;
-		light = R_GetPlaneLight(frontsector, frontsector->ceilingheight, false);
+		light = R_GetPlaneLight(frontsector,
+#ifdef ESLOPE
+								frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+								frontsector->ceilingheight, false);
 		if (frontsector->ceilinglightsec == -1)
 			ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
 		ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@@ -854,32 +871,52 @@ static void R_Subsector(size_t num)
 
 	sub->sector->extra_colormap = frontsector->extra_colormap;
 
-	if ((frontsector->floorheight < viewz || (frontsector->heightsec != -1
+	if (((
+#ifdef ESLOPE
+			frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) :
+#endif
+		frontsector->floorheight) < viewz || (frontsector->heightsec != -1
 		&& sectors[frontsector->heightsec].ceilingpic == skyflatnum)))
 	{
 		floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
-			frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL);
+			frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
+#ifdef ESLOPE
+			, frontsector->f_slope
+#endif
+			);
 	}
 	else
 		floorplane = NULL;
 
-	if ((frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum
+	if (((
+#ifdef ESLOPE
+			frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) :
+#endif
+		frontsector->ceilingheight) > viewz || frontsector->ceilingpic == skyflatnum
 		|| (frontsector->heightsec != -1
 		&& sectors[frontsector->heightsec].floorpic == skyflatnum)))
 	{
 		ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
 			ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
-			ceilingcolormap, NULL);
+			ceilingcolormap, NULL
+#ifdef ESLOPE
+			, frontsector->c_slope
+#endif
+			);
 	}
 	else
 		ceilingplane = NULL;
 
 	numffloors = 0;
+#ifdef ESLOPE
+	ffloor[numffloors].slope = NULL;
+#endif
 	ffloor[numffloors].plane = NULL;
 	ffloor[numffloors].polyobj = NULL;
 	if (frontsector->ffloors)
 	{
 		ffloor_t *rover;
+		fixed_t heightcheck;
 
 		for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
 		{
@@ -897,18 +934,47 @@ static void R_Subsector(size_t num)
 
 			ffloor[numffloors].plane = NULL;
 			ffloor[numffloors].polyobj = NULL;
+
+			heightcheck =
+#ifdef ESLOPE
+				*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
+#endif
+				*rover->bottomheight;
 			if (*rover->bottomheight <= frontsector->ceilingheight
 				&& *rover->bottomheight >= frontsector->floorheight
-				&& ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES))
-				|| (viewz > *rover->bottomheight && (rover->flags & FF_BOTHPLANES))))
+				&& ((viewz < heightcheck && !(rover->flags & FF_INVERTPLANES))
+				|| (viewz > heightcheck && (rover->flags & FF_BOTHPLANES))))
 			{
+#ifdef ESLOPE
+				light = R_GetPlaneLight(frontsector,
+					*rover->b_slope ? P_GetZAt(*rover->b_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->bottomheight,
+					viewz < heightcheck);
+#else
 				light = R_GetPlaneLight(frontsector, *rover->bottomheight,
 					viewz < *rover->bottomheight);
+#endif
 				ffloor[numffloors].plane = R_FindPlane(*rover->bottomheight, *rover->bottompic,
 					*frontsector->lightlist[light].lightlevel, *rover->bottomxoffs,
-					*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover);
+					*rover->bottomyoffs, *rover->bottomangle, frontsector->lightlist[light].extra_colormap, rover
+#ifdef ESLOPE
+					, *rover->b_slope
+#endif
+					);
+
+#ifdef ESLOPE
+				ffloor[numffloors].slope = *rover->b_slope;
+
+				// Tell the renderer this sector has slopes in it.
+				if (ffloor[numffloors].slope)
+					frontsector->hasslope = true;
+#endif
+
+				ffloor[numffloors].height =
+#ifdef ESLOPE
+				*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
+#endif
+				*rover->bottomheight;
 
-				ffloor[numffloors].height = *rover->bottomheight;
 				ffloor[numffloors].ffloor = rover;
 				numffloors++;
 			}
@@ -916,16 +982,46 @@ static void R_Subsector(size_t num)
 				break;
 			ffloor[numffloors].plane = NULL;
 			ffloor[numffloors].polyobj = NULL;
+
+			heightcheck =
+#ifdef ESLOPE
+				*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) :
+#endif
+				*rover->topheight;
 			if (*rover->topheight >= frontsector->floorheight
 				&& *rover->topheight <= frontsector->ceilingheight
-				&& ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES))
-				|| (viewz < *rover->topheight && (rover->flags & FF_BOTHPLANES))))
+				&& ((viewz > heightcheck && !(rover->flags & FF_INVERTPLANES))
+				|| (viewz < heightcheck && (rover->flags & FF_BOTHPLANES))))
 			{
+#ifdef ESLOPE
+				light = R_GetPlaneLight(frontsector,
+					*rover->t_slope ? P_GetZAt(*rover->t_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->topheight,
+					viewz < heightcheck);
+#else
 				light = R_GetPlaneLight(frontsector, *rover->topheight, viewz < *rover->topheight);
+#endif
 				ffloor[numffloors].plane = R_FindPlane(*rover->topheight, *rover->toppic,
 					*frontsector->lightlist[light].lightlevel, *rover->topxoffs, *rover->topyoffs, *rover->topangle,
-					frontsector->lightlist[light].extra_colormap, rover);
-				ffloor[numffloors].height = *rover->topheight;
+					frontsector->lightlist[light].extra_colormap, rover
+#ifdef ESLOPE
+					, *rover->t_slope
+#endif
+					);
+
+#ifdef ESLOPE
+				ffloor[numffloors].slope = *rover->t_slope;
+
+				// Tell the renderer this sector has slopes in it.
+				if (ffloor[numffloors].slope)
+					frontsector->hasslope = true;
+#endif
+
+				ffloor[numffloors].height =
+#ifdef ESLOPE
+				*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) :
+#endif
+				*rover->topheight;
+
 				ffloor[numffloors].ffloor = rover;
 				numffloors++;
 			}
@@ -977,12 +1073,20 @@ static void R_Subsector(size_t num)
 						polysec->lightlevel, xoff, yoff,
 						polysec->floorpic_angle-po->angle,
 						NULL,
-						NULL);
-				ffloor[numffloors].plane->polyobj = po;
+						NULL
+#ifdef ESLOPE
+					, NULL // will ffloors be slopable eventually?
+#endif
+					);
+				//ffloor[numffloors].plane->polyobj = po;
 
 				ffloor[numffloors].height = polysec->floorheight;
 				ffloor[numffloors].polyobj = po;
+#ifdef ESLOPE
+				ffloor[numffloors].slope = NULL;
+#endif
 //				ffloor[numffloors].ffloor = rover;
+				po->visplane = ffloor[numffloors].plane;
 				numffloors++;
 			}
 
@@ -1013,12 +1117,20 @@ static void R_Subsector(size_t num)
 				light = 0;
 				ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
 					polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
-					NULL, NULL);
-				ffloor[numffloors].plane->polyobj = po;
+					NULL, NULL
+#ifdef ESLOPE
+					, NULL // will ffloors be slopable eventually?
+#endif
+					);
+				//ffloor[numffloors].plane->polyobj = po;
 
 				ffloor[numffloors].polyobj = po;
 				ffloor[numffloors].height = polysec->ceilingheight;
+#ifdef ESLOPE
+				ffloor[numffloors].slope = NULL;
+#endif
 //				ffloor[numffloors].ffloor = rover;
+				po->visplane = ffloor[numffloors].plane;
 				numffloors++;
 			}
 
@@ -1075,6 +1187,11 @@ void R_Prep3DFloors(sector_t *sector)
 	fixed_t bestheight, maxheight;
 	INT32 count, i, mapnum;
 	sector_t *sec;
+#ifdef ESLOPE
+	pslope_t *bestslope;
+	fixed_t heighttest; // I think it's better to check the Z height at the sector's center
+	                    // than assume unsloped heights are accurate indicators of order in sloped sectors. -Red
+#endif
 
 	count = 1;
 	for (rover = sector->ffloors; rover; rover = rover->next)
@@ -1097,7 +1214,13 @@ void R_Prep3DFloors(sector_t *sector)
 	else
 		memset(sector->lightlist, 0, sizeof (lightlist_t) * count);
 
+#ifdef ESLOPE
+	heighttest = sector->c_slope ? P_GetZAt(sector->c_slope, sector->soundorg.x, sector->soundorg.y) : sector->ceilingheight;
+
+	sector->lightlist[0].height = heighttest + 1;
+#else
 	sector->lightlist[0].height = sector->ceilingheight + 1;
+#endif
 	sector->lightlist[0].lightlevel = &sector->lightlevel;
 	sector->lightlist[0].caster = NULL;
 	sector->lightlist[0].extra_colormap = sector->extra_colormap;
@@ -1115,6 +1238,29 @@ void R_Prep3DFloors(sector_t *sector)
 				&& !(rover->flags & FF_CUTLEVEL) && !(rover->flags & FF_CUTSPRITES)))
 			continue;
 
+#ifdef ESLOPE
+			heighttest = *rover->t_slope ? P_GetZAt(*rover->t_slope, sector->soundorg.x, sector->soundorg.y) : *rover->topheight;
+
+			if (heighttest > bestheight && heighttest < maxheight)
+			{
+				best = rover;
+				bestheight = heighttest;
+				bestslope = *rover->t_slope;
+				continue;
+			}
+			if (rover->flags & FF_DOUBLESHADOW) {
+				heighttest = *rover->b_slope ? P_GetZAt(*rover->b_slope, sector->soundorg.x, sector->soundorg.y) : *rover->bottomheight;
+
+				if (heighttest > bestheight
+					&& heighttest < maxheight)
+				{
+					best = rover;
+					bestheight = heighttest;
+					bestslope = *rover->b_slope;
+					continue;
+				}
+			}
+#else
 			if (*rover->topheight > bestheight && *rover->topheight < maxheight)
 			{
 				best = rover;
@@ -1128,6 +1274,7 @@ void R_Prep3DFloors(sector_t *sector)
 				bestheight = *rover->bottomheight;
 				continue;
 			}
+#endif
 		}
 		if (!best)
 		{
@@ -1138,6 +1285,9 @@ void R_Prep3DFloors(sector_t *sector)
 		sector->lightlist[i].height = maxheight = bestheight;
 		sector->lightlist[i].caster = best;
 		sector->lightlist[i].flags = best->flags;
+#ifdef ESLOPE
+		sector->lightlist[i].slope = bestslope;
+#endif
 		sec = &sectors[best->secnum];
 		mapnum = sec->midmap;
 		if (mapnum >= 0 && (size_t)mapnum < num_extra_colormaps)
@@ -1163,7 +1313,12 @@ void R_Prep3DFloors(sector_t *sector)
 
 		if (best->flags & FF_DOUBLESHADOW)
 		{
+#ifdef ESLOPE
+			heighttest = *best->b_slope ? P_GetZAt(*best->b_slope, sector->soundorg.x, sector->soundorg.y) : *best->bottomheight;
+			if (bestheight == heighttest) ///TODO: do this in a more efficient way -Red
+#else
 			if (bestheight == *best->bottomheight)
+#endif
 			{
 				sector->lightlist[i].lightlevel = sector->lightlist[best->lastlight].lightlevel;
 				sector->lightlist[i].extra_colormap =
diff --git a/src/r_defs.h b/src/r_defs.h
index 7f8bd7e1d1ee6f99a7542adf8eb9aec392a7e3fe..9f35af7e5f2a7bc2ea3c49b30060d26836c4407e 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -155,6 +155,12 @@ typedef struct ffloor_s
 	fixed_t *bottomyoffs;
 	angle_t *bottomangle;
 
+#ifdef ESLOPE
+	// Pointers to pointers. Yup.
+	struct pslope_s **t_slope;
+	struct pslope_s **b_slope;
+#endif
+
 	size_t secnum;
 	ffloortype_e flags;
 	struct line_s *master;
@@ -184,6 +190,9 @@ typedef struct lightlist_s
 	extracolormap_t *extra_colormap;
 	INT32 flags;
 	ffloor_t *caster;
+#ifdef ESLOPE
+	struct pslope_s *slope; // FF_DOUBLESHADOW makes me have to store this pointer here. Bluh bluh.
+#endif
 } lightlist_t;
 
 
@@ -224,6 +233,41 @@ typedef struct secplane_t
 	fixed_t a, b, c, d, ic;
 } secplane_t;
 
+// Kalaron Slopes
+#ifdef ESLOPE
+
+typedef struct pslope_s
+{
+	// --- Information used in clipping/projection ---
+	// Origin vector for the plane
+	vector3_t o;
+
+	// 2-Dimentional vector (x, y) normalized. Used to determine distance from
+	// the origin in 2d mapspace. (Basically a thrust of FRACUNIT in xydirection angle)
+	vector2_t d;
+
+	// The rate at which z changes based on distance from the origin plane.
+	fixed_t zdelta;
+
+	// The normal of the slope; will always point upward, and thus be inverted on ceilings. I think it's only needed for physics? -Red
+	vector3_t normal;
+
+	// For comparing when a slope should be rendered
+	fixed_t lowz;
+	fixed_t highz;
+
+	// This values only check and must be updated if the slope itself is modified
+	angle_t zangle; // Angle of the plane going up from the ground (not mesured in degrees)
+	angle_t xydirection; // The direction the slope is facing (north, west, south, etc.)
+
+	struct line_s *sourceline; // The line that generated the slope
+	fixed_t extent; // Distance value used for recalculating zdelta
+	UINT8 refpos; // 1=front floor 2=front ceiling 3=back floor 4=back ceiling (used for dynamic sloping) 0=disabled
+
+	struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
+} pslope_t;
+#endif
+
 typedef enum
 {
 	SF_FLIPSPECIAL_FLOOR    =  1,
@@ -337,6 +381,13 @@ typedef struct sector_s
 	precipmobj_t *preciplist;
 	struct mprecipsecnode_s *touching_preciplist;
 
+#ifdef ESLOPE
+	// Eternity engine slope
+	pslope_t *f_slope; // floor slope
+	pslope_t *c_slope; // ceiling slope
+	boolean hasslope; // The sector, or one of its visible FOFs, contains a slope
+#endif
+
 	// these are saved for netgames, so do not let Lua touch these!
 
 	// offsets sector spawned with (via linedef type 7)
@@ -612,6 +663,12 @@ typedef struct drawseg_s
 	INT16 *thicksidecol;
 	INT32 numthicksides;
 	fixed_t frontscale[MAXVIDWIDTH];
+
+#ifdef ESLOPE
+	fixed_t maskedtextureheight[MAXVIDWIDTH]; // For handling sloped midtextures
+
+	vertex_t leftpos, rightpos; // Used for rendering FOF walls with slopes
+#endif
 } drawseg_t;
 
 typedef enum
diff --git a/src/r_draw.c b/src/r_draw.c
index cd219c15f624cf9726148ac6d42124f2f40eef99..766e0428e09844b2f32d96ca00d257c3a4bc8f23 100644
--- a/src/r_draw.c
+++ b/src/r_draw.c
@@ -103,6 +103,12 @@ fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
 UINT8 *ds_source; // start of a 64*64 tile image
 UINT8 *ds_transmap; // one of the translucency tables
 
+#ifdef ESLOPE
+pslope_t *ds_slope; // Current slope being used
+floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff?
+float focallengthf, zeroheight;
+#endif
+
 /**	\brief Variable flat sizes
 */
 
diff --git a/src/r_draw.h b/src/r_draw.h
index 061a271b15be4d466d108b2b313f9e389a738792..e1818545b71ef8e25473dec8d91f2b04ae42c03a 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -60,6 +60,16 @@ extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
 extern UINT8 *ds_source; // start of a 64*64 tile image
 extern UINT8 *ds_transmap;
 
+#ifdef ESLOPE
+typedef struct {
+	float x, y, z;
+} floatv3_t;
+
+pslope_t *ds_slope; // Current slope being used
+floatv3_t ds_su, ds_sv, ds_sz; // Vectors for... stuff?
+float focallengthf, zeroheight;
+#endif
+
 // Variable flat sizes
 extern UINT32 nflatxshift;
 extern UINT32 nflatyshift;
@@ -141,6 +151,10 @@ void ASMCALL R_DrawSpan_8_MMX(void);
 void R_DrawTranslatedColumn_8(void);
 void R_DrawTranslatedTranslucentColumn_8(void);
 void R_DrawSpan_8(void);
+#ifdef ESLOPE
+void R_DrawTiltedSpan_8(void);
+void R_DrawTiltedTranslucentSpan_8(void);
+#endif
 void R_DrawSplat_8(void);
 void R_DrawTranslucentSplat_8(void);
 void R_DrawTranslucentSpan_8(void);
diff --git a/src/r_draw8.c b/src/r_draw8.c
index e0264ba921a1b2ee3ec7824ba86ffe17a5a86db9..279690492c5a4ba6b7a59ab5030d939c5b0517f1 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -526,6 +526,297 @@ void R_DrawSpan_8 (void)
 	}
 }
 
+#ifdef ESLOPE
+// R_CalcTiltedLighting
+// Exactly what it says on the tin. I wish I wasn't too lazy to explain things properly.
+static size_t tiltlighting[MAXVIDWIDTH];
+void R_CalcTiltedLighting(fixed_t start, fixed_t end)
+{
+	// ZDoom uses a different lighting setup to us, and I couldn't figure out how to adapt their version
+	// of this function. Here's my own.
+	INT32 left = ds_x1, right = ds_x2;
+	fixed_t step = (end-start)/(ds_x2-ds_x1+1);
+	size_t i;
+
+	// I wanna do some optimizing by checking for out-of-range segments on either side to fill in all at once,
+	// but I'm too bad at coding to not crash the game trying to do that. I guess this is fast enough for now...
+
+	for (i = left; i <= right; i++) {
+		tiltlighting[i] = (start += step) >> FRACBITS;
+		if (tiltlighting[i] < 0)
+			tiltlighting[i] = 0;
+		else if (tiltlighting[i] >= MAXLIGHTSCALE)
+			tiltlighting[i] = MAXLIGHTSCALE-1;
+	}
+}
+
+
+/**	\brief The R_DrawTiltedSpan_8 function
+	Draw slopes! Holy sheit!
+*/
+void R_DrawTiltedSpan_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+
+	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
+	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (UINT32)(uz*z) + viewx;
+		v = (UINT32)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+
+		*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+		dest++;
+		iz += ds_sz.x;
+		uz += ds_su.x;
+		vz += ds_sv.x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	double startz = 1.f/iz;
+	double startu = uz*startz;
+	double startv = vz*startz;
+	double izstep, uzstep, vzstep;
+
+	izstep = ds_sz.x * SPANSIZE;
+	uzstep = ds_su.x * SPANSIZE;
+	vzstep = ds_sv.x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		double endz = 1.f/iz;
+		double endu = uz*endz;
+		double endv = vz*endz;
+		UINT32 stepu = (INT64)((endu - startu) * INVSPAN);
+		UINT32 stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (UINT32)(startu) + viewx;
+		v = (UINT32)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (UINT32)(startu);
+			v = (UINT32)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+		}
+		else
+		{
+			double left = width;
+			iz += ds_sz.x * left;
+			uz += ds_su.x * left;
+			vz += ds_sv.x * left;
+
+			double endz = 1.f/iz;
+			double endu = uz*endz;
+			double endv = vz*endz;
+			left = 1.f/left;
+			UINT32 stepu = (INT64)((endu - startu) * left);
+			UINT32 stepv = (INT64)((endv - startv) * left);
+			u = (UINT32)(startu) + viewx;
+			v = (UINT32)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				*dest = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+
+
+/**	\brief The R_DrawTiltedTranslucentSpan_8 function
+	Like DrawTiltedSpan, but translucent
+*/
+void R_DrawTiltedTranslucentSpan_8(void)
+{
+	// x1, x2 = ds_x1, ds_x2
+	int width = ds_x2 - ds_x1;
+	double iz, uz, vz;
+	UINT32 u, v;
+	int i;
+
+	UINT8 *source;
+	UINT8 *colormap;
+	UINT8 *dest;
+
+	iz = ds_sz.z + ds_sz.y*(centery-ds_y) + ds_sz.x*(ds_x1-centerx);
+
+	// Lighting is simple. It's just linear interpolation from start to end
+	{
+		float planelightfloat = BASEVIDWIDTH*BASEVIDWIDTH/vid.width / (zeroheight - FIXED_TO_FLOAT(viewz)) / 21.0f;
+		float lightstart, lightend;
+
+		lightend = (iz + ds_sz.x*width) * planelightfloat;
+		lightstart = iz * planelightfloat;
+
+		R_CalcTiltedLighting(FLOAT_TO_FIXED(lightstart), FLOAT_TO_FIXED(lightend));
+		//CONS_Printf("tilted lighting %f to %f (foc %f)\n", lightstart, lightend, focallengthf);
+	}
+
+	uz = ds_su.z + ds_su.y*(centery-ds_y) + ds_su.x*(ds_x1-centerx);
+	vz = ds_sv.z + ds_sv.y*(centery-ds_y) + ds_sv.x*(ds_x1-centerx);
+
+	dest = ylookup[ds_y] + columnofs[ds_x1];
+	source = ds_source;
+	//colormap = ds_colormap;
+
+#if 0	// The "perfect" reference version of this routine. Pretty slow.
+		// Use it only to see how things are supposed to look.
+	i = 0;
+	do
+	{
+		double z = 1.f/iz;
+		u = (UINT32)(uz*z) + viewx;
+		v = (UINT32)(vz*z) + viewy;
+
+		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+
+		*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+		dest++;
+		iz += ds_sz.x;
+		uz += ds_su.x;
+		vz += ds_sv.x;
+	} while (--width >= 0);
+#else
+#define SPANSIZE 16
+#define INVSPAN	0.0625f
+
+	double startz = 1.f/iz;
+	double startu = uz*startz;
+	double startv = vz*startz;
+	double izstep, uzstep, vzstep;
+
+	izstep = ds_sz.x * SPANSIZE;
+	uzstep = ds_su.x * SPANSIZE;
+	vzstep = ds_sv.x * SPANSIZE;
+	//x1 = 0;
+	width++;
+
+	while (width >= SPANSIZE)
+	{
+		iz += izstep;
+		uz += uzstep;
+		vz += vzstep;
+
+		double endz = 1.f/iz;
+		double endu = uz*endz;
+		double endv = vz*endz;
+		UINT32 stepu = (INT64)((endu - startu) * INVSPAN);
+		UINT32 stepv = (INT64)((endv - startv) * INVSPAN);
+		u = (UINT32)(startu) + viewx;
+		v = (UINT32)(startv) + viewy;
+
+		for (i = SPANSIZE-1; i >= 0; i--)
+		{
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+			dest++;
+			u += stepu;
+			v += stepv;
+		}
+		startu = endu;
+		startv = endv;
+		width -= SPANSIZE;
+	}
+	if (width > 0)
+	{
+		if (width == 1)
+		{
+			u = (UINT32)(startu);
+			v = (UINT32)(startv);
+			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+			*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+		}
+		else
+		{
+			double left = width;
+			iz += ds_sz.x * left;
+			uz += ds_su.x * left;
+			vz += ds_sv.x * left;
+
+			double endz = 1.f/iz;
+			double endu = uz*endz;
+			double endv = vz*endz;
+			left = 1.f/left;
+			UINT32 stepu = (INT64)((endu - startu) * left);
+			UINT32 stepv = (INT64)((endv - startv) * left);
+			u = (UINT32)(startu) + viewx;
+			v = (UINT32)(startv) + viewy;
+
+			for (; width != 0; width--)
+			{
+				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
+				*dest = colormap[*(ds_transmap + (source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)] << 8) + dest[0])];
+				dest++;
+				u += stepu;
+				v += stepv;
+			}
+		}
+	}
+#endif
+}
+#endif // ESLOPE
+
 /**	\brief The R_DrawSplat_8 function
 	Just like R_DrawSpan_8, but skips transparent pixels.
 */
diff --git a/src/r_main.c b/src/r_main.c
index ffd4d5d504c3b6c98e9c02894c41ec1ca0340d7c..127801598703014296efae0a08170b1adc329f15 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -527,6 +527,8 @@ static void R_InitTextureMapping(void)
 	focallength = FixedDiv(centerxfrac,
 		FINETANGENT(FINEANGLES/4+/*cv_fov.value*/ FIELDOFVIEW/2));
 
+	focallengthf = FIXED_TO_FLOAT(focallength);
+
 	for (i = 0; i < FINEANGLES/2; i++)
 	{
 		if (FINETANGENT(i) > FRACUNIT*2)
@@ -1026,34 +1028,31 @@ void R_SetupFrame(player_t *player, boolean skybox)
 {
 	INT32 dy = 0;
 	camera_t *thiscam;
-	boolean forcechase = false;
+	boolean chasecam = false;
 
 	if (splitscreen && player == &players[secondarydisplayplayer]
 		&& player != &players[consoleplayer])
 	{
 		thiscam = &camera2;
+		chasecam = (cv_chasecam2.value != 0);
 	}
 	else
+	{
 		thiscam = &camera;
+		chasecam = (cv_chasecam.value != 0);
+	}
 
 	if (player->climbing || (player->pflags & PF_NIGHTSMODE) || player->playerstate == PST_DEAD)
-		forcechase = true;
+		chasecam = true; // force chasecam on
+	else if (player->spectator) // no spectator chasecam
+		chasecam = false; // force chasecam off
 
-	if (!forcechase && player->spectator) // no spectator chasecam
-		thiscam->chase = false;
-	else if ((cv_chasecam.value || forcechase) && !player->spectator && thiscam == &camera && !thiscam->chase)
+	if (chasecam && !thiscam->chase)
 	{
-		P_ResetCamera(player, &camera);
+		P_ResetCamera(player, thiscam);
 		thiscam->chase = true;
 	}
-	else if ((cv_chasecam2.value || forcechase) && !player->spectator && thiscam == &camera2 && !thiscam->chase)
-	{
-		P_ResetCamera(player, &camera2);
-		thiscam->chase = true;
-	}
-	else if (!(cv_chasecam.value || forcechase) && thiscam == &camera)
-		thiscam->chase = false;
-	else if (!(cv_chasecam2.value || forcechase) && thiscam == &camera2)
+	else if (!chasecam)
 		thiscam->chase = false;
 
 	viewsky = !skybox;
@@ -1066,9 +1065,7 @@ void R_SetupFrame(player_t *player, boolean skybox)
 		aimingangle = player->awayviewaiming;
 		viewangle = viewmobj->angle;
 	}
-	else if (!player->spectator && (forcechase
-		|| (cv_chasecam.value && thiscam == &camera)
-		|| (cv_chasecam2.value && thiscam == &camera2)))
+	else if (!player->spectator && chasecam)
 	// use outside cam view
 	{
 		viewmobj = NULL;
@@ -1105,8 +1102,7 @@ void R_SetupFrame(player_t *player, boolean skybox)
 
 	viewplayer = player;
 
-	if ((forcechase || (cv_chasecam.value && thiscam == &camera) || (cv_chasecam2.value && thiscam == &camera2))
-		&& !player->awayviewtics && !player->spectator)
+	if (chasecam && !player->awayviewtics && !player->spectator)
 	{
 		viewx = thiscam->x;
 		viewy = thiscam->y;
diff --git a/src/r_plane.c b/src/r_plane.c
index dcff25c1304fd45deba11b9845cdaa40f23c7658..6aae1e250b1d1b29e61a7b1503f9a6b15ec01e08 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -74,7 +74,7 @@ static INT32 spanstart[MAXVIDHEIGHT];
 //
 // texture mapping
 //
-static lighttable_t **planezlight;
+lighttable_t **planezlight;
 static fixed_t planeheight;
 
 //added : 10-02-98: yslopetab is what yslope used to be,
@@ -327,6 +327,11 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2)
 	if (pindex >= MAXLIGHTZ)
 		pindex = MAXLIGHTZ - 1;
 
+#ifdef ESLOPE
+	if (currentplane->slope)
+		ds_colormap = colormaps;
+	else
+#endif
 	ds_colormap = planezlight[pindex];
 
 	if (currentplane->extra_colormap)
@@ -423,11 +428,18 @@ static visplane_t *new_visplane(unsigned hash)
 //
 visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 	fixed_t xoff, fixed_t yoff, angle_t plangle, extracolormap_t *planecolormap,
-	ffloor_t *pfloor)
+	ffloor_t *pfloor
+#ifdef ESLOPE
+			, pslope_t *slope
+#endif
+			)
 {
 	visplane_t *check;
 	unsigned hash;
 
+#ifdef ESLOPE
+	if (slope); else // Don't mess with this right now if a slope is involved
+#endif
 	if (plangle != 0)
 	{
 		// Add the view offset, rotated by the plane angle.
@@ -462,7 +474,11 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 			&& xoff == check->xoffs && yoff == check->yoffs
 			&& planecolormap == check->extra_colormap
 			&& !pfloor && !check->ffloor && check->viewz == viewz
-			&& check->viewangle == viewangle)
+			&& check->viewangle == viewangle
+#ifdef ESLOPE
+			&& check->slope == slope
+#endif
+			)
 		{
 			return check;
 		}
@@ -485,6 +501,9 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 #ifdef POLYOBJECTS_PLANES
 	check->polyobj = NULL;
 #endif
+#ifdef ESLOPE
+	check->slope = slope;
+#endif
 
 	memset(check->top, 0xff, sizeof (check->top));
 	memset(check->bottom, 0x00, sizeof (check->bottom));
@@ -551,6 +570,9 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop)
 		new_pl->plangle = pl->plangle;
 #ifdef POLYOBJECTS_PLANES
 		new_pl->polyobj = pl->polyobj;
+#endif
+#ifdef ESLOPE
+		new_pl->slope = pl->slope;
 #endif
 		pl = new_pl;
 		pl->minx = start;
@@ -842,6 +864,9 @@ void R_DrawSinglePlane(visplane_t *pl)
 	}
 	else light = (pl->lightlevel >> LIGHTSEGSHIFT);
 
+#ifdef ESLOPE
+	if (!pl->slope) // Don't mess with angle on slopes! We'll handle this ourselves later
+#endif
 	if (viewangle != pl->viewangle)
 	{
 		memset(cachedheight, 0, sizeof (cachedheight));
@@ -915,6 +940,97 @@ void R_DrawSinglePlane(visplane_t *pl)
 	if (light < 0)
 		light = 0;
 
+#ifdef ESLOPE
+	if (pl->slope) {
+		// Potentially override other stuff for now cus we're mean. :< But draw a slope plane!
+		// I copied ZDoom's code and adapted it to SRB2... -Red
+		floatv3_t p, m, n;
+		float ang;
+		float vx, vy, vz;
+		float fudge;
+
+		xoffs &= ((1 << (32-nflatshiftup))-1);
+		yoffs &= ((1 << (32-nflatshiftup))-1);
+
+		xoffs -= (pl->slope->o.x + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
+		yoffs += (pl->slope->o.y + (1 << (31-nflatshiftup))) & ~((1 << (32-nflatshiftup))-1);
+
+		// Okay, look, don't ask me why this works, but without this setup there's a disgusting-looking misalignment with the textures. -Red
+		fudge = ((1<<nflatshiftup)+1.0f)/(1<<nflatshiftup);
+
+		xoffs *= fudge;
+		yoffs /= fudge;
+
+		vx = FIXED_TO_FLOAT(viewx+xoffs);
+		vy = FIXED_TO_FLOAT(viewy-yoffs);
+		vz = FIXED_TO_FLOAT(viewz);
+
+		zeroheight = FIXED_TO_FLOAT(P_GetZAt(pl->slope, viewx, viewy));
+
+#define ANG2RAD(angle) ((float)((angle)*M_PI)/ANGLE_180)
+
+		// p is the texture origin in view space
+		// Don't add in the offsets at this stage, because doing so can result in
+		// errors if the flat is rotated.
+		ang = ANG2RAD(ANGLE_270 - viewangle);
+		p.x = vx * cos(ang) - vy * sin(ang);
+		p.z = vx * sin(ang) + vy * cos(ang);
+		p.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, -xoffs, yoffs)) - vz;
+
+		// m is the v direction vector in view space
+		ang = ANG2RAD(ANGLE_180 - viewangle - pl->plangle);
+		m.x = cos(ang);
+		m.z = sin(ang);
+
+		// n is the u direction vector in view space
+		n.x = sin(ang);
+		n.z = -cos(ang);
+
+		ang = ANG2RAD(pl->plangle);
+		m.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, viewx + FLOAT_TO_FIXED(sin(ang)), viewy + FLOAT_TO_FIXED(cos(ang)))) - zeroheight;
+		n.y = FIXED_TO_FLOAT(P_GetZAt(pl->slope, viewx + FLOAT_TO_FIXED(cos(ang)), viewy - FLOAT_TO_FIXED(sin(ang)))) - zeroheight;
+
+		m.x /= fudge;
+		m.y /= fudge;
+		m.z /= fudge;
+
+		n.x *= fudge;
+		n.y *= fudge;
+		n.z *= fudge;
+
+		// Eh. I tried making this stuff fixed-point and it exploded on me. Here's a macro for the only floating-point vector function I recall using.
+#define CROSS(d, v1, v2) \
+   d.x = (v1.y * v2.z) - (v1.z * v2.y);\
+   d.y = (v1.z * v2.x) - (v1.x * v2.z);\
+   d.z = (v1.x * v2.y) - (v1.y * v2.x)
+		CROSS(ds_su, p, m);
+		CROSS(ds_sv, p, n);
+		CROSS(ds_sz, m, n);
+#undef CROSS
+
+		ds_su.z *= focallengthf;
+		ds_sv.z *= focallengthf;
+		ds_sz.z *= focallengthf;
+
+		// Premultiply the texture vectors with the scale factors
+#define SFMULT 65536.f*(1<<nflatshiftup)
+		ds_su.x *= SFMULT;
+		ds_su.y *= SFMULT;
+		ds_su.z *= SFMULT;
+		ds_sv.x *= SFMULT;
+		ds_sv.y *= SFMULT;
+		ds_sv.z *= SFMULT;
+#undef SFMULT
+
+		if (spanfunc == R_DrawTranslucentSpan_8)
+			spanfunc = R_DrawTiltedTranslucentSpan_8;
+		else
+			spanfunc = R_DrawTiltedSpan_8;
+
+		planezlight = scalelight[light];
+	} else
+#endif // ESLOPE
+
 	planezlight = zlight[light];
 
 	// set the maximum value for unsigned
diff --git a/src/r_plane.h b/src/r_plane.h
index f3a7f573fe90c0201f944430953327f29c999e17..239723ed1d6316c33efa6a44ab97c719df330ea8 100644
--- a/src/r_plane.h
+++ b/src/r_plane.h
@@ -61,6 +61,9 @@ typedef struct visplane_s
 #ifdef POLYOBJECTS_PLANES
 	polyobj_t *polyobj;
 #endif
+#ifdef ESLOPE
+	pslope_t *slope;
+#endif
 } visplane_t;
 
 extern visplane_t *floorplane;
@@ -79,6 +82,8 @@ extern fixed_t cachedxstep[MAXVIDHEIGHT];
 extern fixed_t cachedystep[MAXVIDHEIGHT];
 extern fixed_t basexscale, baseyscale;
 
+extern lighttable_t **planezlight;
+
 extern fixed_t *yslope;
 extern fixed_t distscale[MAXVIDWIDTH];
 
@@ -91,7 +96,11 @@ void R_MapPlane(INT32 y, INT32 x1, INT32 x2);
 void R_MakeSpans(INT32 x, INT32 t1, INT32 b1, INT32 t2, INT32 b2);
 void R_DrawPlanes(void);
 visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel, fixed_t xoff, fixed_t yoff, angle_t plangle,
-	extracolormap_t *planecolormap, ffloor_t *ffloor);
+	extracolormap_t *planecolormap, ffloor_t *ffloor
+#ifdef ESLOPE
+	, pslope_t *slope
+#endif
+	);
 visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop);
 void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop);
 void R_PlaneBounds(visplane_t *plane);
@@ -110,6 +119,14 @@ typedef struct planemgr_s
 	INT16 f_clip[MAXVIDWIDTH];
 	INT16 c_clip[MAXVIDWIDTH];
 
+#ifdef ESLOPE
+	// For slope rendering; the height at the other end
+	fixed_t f_pos_slope;
+	fixed_t b_pos_slope;
+
+	struct pslope_s *slope;
+#endif
+
 	struct ffloor_s *ffloor;
 #ifdef POLYOBJECTS_PLANES
 	polyobj_t *polyobj;
diff --git a/src/r_segs.c b/src/r_segs.c
index 7467f532472ae35d9eca14373ee9faf95e2e7b45..2d41d702c2161e11a03406d843a59fc081e1d1da 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -50,12 +50,20 @@ static fixed_t rw_offset2; // for splats
 static fixed_t rw_scale, rw_scalestep;
 static fixed_t rw_midtexturemid, rw_toptexturemid, rw_bottomtexturemid;
 static INT32 worldtop, worldbottom, worldhigh, worldlow;
+#ifdef ESLOPE
+static INT32 worldtopslope, worldbottomslope, worldhighslope, worldlowslope; // worldtop/bottom at end of slope
+static fixed_t rw_toptextureslide, rw_midtextureslide, rw_bottomtextureslide; // Defines how to adjust Y offsets along the wall for slopes
+static fixed_t rw_midtextureback, rw_midtexturebackslide; // Values for masked midtexture height calculation
+#endif
 static fixed_t pixhigh, pixlow, pixhighstep, pixlowstep;
 static fixed_t topfrac, topstep;
 static fixed_t bottomfrac, bottomstep;
 
 static lighttable_t **walllights;
 static INT16 *maskedtexturecol;
+#ifdef ESLOPE
+static fixed_t *maskedtextureheight = NULL;
+#endif
 
 // ==========================================================================
 // R_Splats Wall Splats Drawer
@@ -474,6 +482,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
 		}
 
+
+#ifndef ESLOPE
 		if (curline->linedef->flags & ML_DONTPEGBOTTOM)
 		{
 			dc_texturemid = front->floorheight > back->floorheight
@@ -492,12 +502,21 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			dc_texturemid += (textureheight[texnum])*times;
 		else
 			dc_texturemid -= (textureheight[texnum])*times;
+#endif
 
 		dc_texheight = textureheight[texnum]>>FRACBITS;
 
 		// draw the columns
 		for (dc_x = x1; dc_x <= x2; dc_x++)
 		{
+#ifdef ESLOPE
+			dc_texturemid = ds->maskedtextureheight[dc_x];
+
+			if (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3))
+				dc_texturemid += (textureheight[texnum])*times + textureheight[texnum];
+			else
+				dc_texturemid -= (textureheight[texnum])*times;
+#endif
 			// calculate lighting
 			if (maskedtexturecol[dc_x] != INT16_MAX)
 			{
@@ -679,6 +698,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	r_lightlist_t   *rlight;
 	fixed_t         lheight;
 	line_t          *newline = NULL;
+#ifdef ESLOPE
+	// Render FOF sides kinda like normal sides, with the frac and step and everything
+	fixed_t         top_frac, top_step, bottom_frac, bottom_step;
+#endif
 
 	void (*colfunc_2s) (column_t *);
 
@@ -853,6 +876,34 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 		column2s_length = textures[texnum]->height;
 	}
 
+#ifdef ESLOPE
+	// Set heights according to plane, or slope, whichever
+	{
+		fixed_t left_top, right_top, left_bottom, right_bottom;
+
+		left_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->topheight;
+		right_top = *pfloor->t_slope ? P_GetZAt(*pfloor->t_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->topheight;
+		left_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->leftpos.x, ds->leftpos.y) : *pfloor->bottomheight;
+		right_bottom = *pfloor->b_slope ? P_GetZAt(*pfloor->b_slope, ds->rightpos.x, ds->rightpos.y) : *pfloor->bottomheight;
+
+		left_top -= viewz;
+		right_top -= viewz;
+		left_bottom -= viewz;
+		right_bottom -= viewz;
+
+		top_frac = centeryfrac - FixedMul(left_top, ds->scale1);
+		bottom_frac = centeryfrac - FixedMul(left_bottom, ds->scale1);
+		top_step = centeryfrac - FixedMul(right_top, ds->scale2);
+		bottom_step = centeryfrac - FixedMul(right_bottom, ds->scale2);
+
+		top_step = (top_step-top_frac)/(ds->x2-ds->x1+1);
+		bottom_step = (bottom_step-bottom_frac)/(ds->x2-ds->x1+1);
+
+		top_frac += top_step * (x1 - ds->x1);
+		bottom_frac += bottom_step * (x1 - ds->x1);
+	}
+#endif
+
 	// draw the columns
 	for (dc_x = x1; dc_x <= x2; dc_x++)
 	{
@@ -868,8 +919,16 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 				INT32 solid = 0;
 				INT32 lighteffect = 0;
 
+#ifdef ESLOPE
+				sprtopscreen = windowtop = top_frac;
+				sprbotscreen = windowbottom = bottom_frac;
+
+				top_frac += top_step;
+				bottom_frac += bottom_step;
+#else
 				sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
 				sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
+#endif
 
 				// SoM: If column is out of range, why bother with it??
 				if (windowbottom < topbounds || windowtop > bottombounds)
@@ -1011,11 +1070,24 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 			 || ((signed)dc_texturemid < 0 && (spryscale) && (signed)(dc_texturemid)>>FRACBITS < (INT32_MIN / spryscale)))
 			{
 				spryscale += rw_scalestep;
+#ifdef ESLOPE
+				top_frac += top_step;
+				bottom_frac += bottom_step;
+#endif
 				continue;
 			}
 
+#ifdef ESLOPE
+			sprtopscreen = windowtop = top_frac;
+			sprbotscreen = windowbottom = bottom_frac;
+
+			top_frac += top_step;
+			bottom_frac += bottom_step;
+#else
 			sprtopscreen = windowtop = (centeryfrac - FixedMul((dc_texturemid - offsetvalue), spryscale));
 			sprbotscreen = windowbottom = FixedMul(*pfloor->topheight - *pfloor->bottomheight, spryscale) + sprtopscreen;
+#endif
+
 			dc_iscale = 0xffffffffu / (unsigned)spryscale;
 
 			// draw the texture
@@ -1061,6 +1133,7 @@ static void R_RenderSegLoop (void)
 
 	INT32     mid;
 	fixed_t texturecolumn = 0;
+	fixed_t oldtexturecolumn = -1;
 	INT32     top;
 	INT32     bottom;
 	INT32     i;
@@ -1197,6 +1270,17 @@ static void R_RenderSegLoop (void)
 		// calculate texture offset
 		angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
 		texturecolumn = rw_offset-FixedMul(FINETANGENT(angle),rw_distance);
+
+#ifdef ESLOPE
+		if (oldtexturecolumn != -1) {
+			rw_bottomtexturemid += FixedMul(rw_bottomtextureslide,  oldtexturecolumn-texturecolumn);
+			rw_midtexturemid    += FixedMul(rw_midtextureslide,     oldtexturecolumn-texturecolumn);
+			rw_toptexturemid    += FixedMul(rw_toptextureslide,     oldtexturecolumn-texturecolumn);
+			rw_midtextureback   += FixedMul(rw_midtexturebackslide, oldtexturecolumn-texturecolumn);
+		}
+		oldtexturecolumn = texturecolumn;
+#endif
+
 		texturecolumn >>= FRACBITS;
 
 		// texturecolumn and lighting are independent of wall tiers
@@ -1345,6 +1429,14 @@ static void R_RenderSegLoop (void)
 			// save texturecol
 			//  for backdrawing of masked mid texture
 			maskedtexturecol[rw_x] = (INT16)texturecolumn;
+
+#ifdef ESLOPE
+			if (maskedtextureheight != NULL) {
+				maskedtextureheight[rw_x] = (!!(curline->linedef->flags & ML_DONTPEGBOTTOM) ^ !!(curline->linedef->flags & ML_EFFECT3) ?
+											max(rw_midtexturemid, rw_midtextureback) :
+											min(rw_midtexturemid, rw_midtextureback));
+			}
+#endif
 		}
 
 		if (dc_numlights)
@@ -1402,8 +1494,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	INT32           i, p;
 	lightlist_t   *light;
 	r_lightlist_t *rlight;
+#ifdef ESLOPE
+	vertex_t segleft, segright;
+	fixed_t ceilingfrontslide, floorfrontslide, ceilingbackslide, floorbackslide;
+#endif
 	static size_t maxdrawsegs = 0;
 
+	maskedtextureheight = NULL;
+
 	if (ds_p == drawsegs+maxdrawsegs)
 	{
 		size_t pos = ds_p - drawsegs;
@@ -1502,8 +1600,80 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 	// calculate texture boundaries
 	//  and decide if floor / ceiling marks are needed
-	worldtop = frontsector->ceilingheight - viewz;
-	worldbottom = frontsector->floorheight - viewz;
+#ifdef ESLOPE
+	// Figure out map coordinates of where start and end are mapping to on seg, so we can clip right for slope bullshit
+	if (frontsector->hasslope || (backsector && backsector->hasslope)) // Commenting this out for FOFslop. -Red
+	{
+		angle_t temp;
+
+		// left
+		temp = xtoviewangle[start]+viewangle;
+
+		{
+			// Both lines can be written in slope-intercept form, so figure out line intersection
+			float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
+			///TODO: convert to FPU
+
+			a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
+			b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
+			c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
+
+			a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
+			b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
+			c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
+
+			det = a1*b2 - a2*b1;
+
+			ds_p->leftpos.x = segleft.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
+			ds_p->leftpos.y = segleft.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
+		}
+
+		// right
+		temp = xtoviewangle[stop]+viewangle;
+
+		{
+			// Both lines can be written in slope-intercept form, so figure out line intersection
+			float a1, b1, c1, a2, b2, c2, det; // 1 is the seg, 2 is the view angle vector...
+			///TODO: convert to FPU
+
+			a1 = FIXED_TO_FLOAT(curline->v2->y-curline->v1->y);
+			b1 = FIXED_TO_FLOAT(curline->v1->x-curline->v2->x);
+			c1 = a1*FIXED_TO_FLOAT(curline->v1->x) + b1*FIXED_TO_FLOAT(curline->v1->y);
+
+			a2 = -FIXED_TO_FLOAT(FINESINE(temp>>ANGLETOFINESHIFT));
+			b2 = FIXED_TO_FLOAT(FINECOSINE(temp>>ANGLETOFINESHIFT));
+			c2 = a2*FIXED_TO_FLOAT(viewx) + b2*FIXED_TO_FLOAT(viewy);
+
+			det = a1*b2 - a2*b1;
+
+			ds_p->rightpos.x = segright.x = FLOAT_TO_FIXED((b2*c1 - b1*c2)/det);
+			ds_p->rightpos.y = segright.y = FLOAT_TO_FIXED((a1*c2 - a2*c1)/det);
+		}
+	}
+
+	if (frontsector->c_slope) {
+		worldtop = P_GetZAt(frontsector->c_slope, segleft.x, segleft.y) - viewz;
+		worldtopslope = P_GetZAt(frontsector->c_slope, segright.x, segright.y) - viewz;
+	} else {
+		worldtopslope =
+#else
+	{
+#endif
+		worldtop = frontsector->ceilingheight - viewz;
+	}
+
+
+#ifdef ESLOPE
+	if (frontsector->f_slope) {
+		worldbottom = P_GetZAt(frontsector->f_slope, segleft.x, segleft.y) - viewz;
+		worldbottomslope = P_GetZAt(frontsector->f_slope, segright.x, segright.y) - viewz;
+	} else {
+		worldbottomslope =
+#else
+	{
+#endif
+		worldbottom = frontsector->floorheight - viewz;
+	}
 
 	midtexture = toptexture = bottomtexture = maskedtexture = 0;
 	ds_p->maskedtexturecol = NULL;
@@ -1524,27 +1694,72 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			if (ffloor[i].polyobj && (!ds_p->curline->polyseg || ffloor[i].polyobj != ds_p->curline->polyseg))
 				continue;
 #endif
+
+#ifdef ESLOPE
+			if (ffloor[i].slope) {
+				ffloor[i].f_pos = P_GetZAt(ffloor[i].slope, segleft.x, segleft.y) - viewz;
+				ffloor[i].f_pos_slope = P_GetZAt(ffloor[i].slope, segright.x, segright.y) - viewz;
+			} else
+				ffloor[i].f_pos_slope =
+#endif
 			ffloor[i].f_pos = ffloor[i].height - viewz;
 		}
 	}
 
+#ifdef ESLOPE
+	// Set up texture Y offset slides for sloped walls
+	rw_toptextureslide = rw_midtextureslide = rw_bottomtextureslide = 0;
+	ceilingfrontslide = floorfrontslide = ceilingbackslide = floorbackslide = 0;
+
+	{
+		angle_t lineangle = R_PointToAngle2(curline->v1->x, curline->v1->y, curline->v2->x, curline->v2->y);
+
+		if (frontsector->f_slope)
+			floorfrontslide = FixedMul(frontsector->f_slope->zdelta, FINECOSINE((lineangle-frontsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
+
+		if (frontsector->c_slope)
+			ceilingfrontslide = FixedMul(frontsector->c_slope->zdelta, FINECOSINE((lineangle-frontsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
+
+		if (backsector && backsector->f_slope)
+			floorbackslide = FixedMul(backsector->f_slope->zdelta, FINECOSINE((lineangle-backsector->f_slope->xydirection)>>ANGLETOFINESHIFT));
+
+		if (backsector && backsector->c_slope)
+			ceilingbackslide = FixedMul(backsector->c_slope->zdelta, FINECOSINE((lineangle-backsector->c_slope->xydirection)>>ANGLETOFINESHIFT));
+	}
+#endif
+
 	if (!backsector)
 	{
 		// single sided line
 		midtexture = texturetranslation[sidedef->midtexture];
 		// a single sided line is terminal, so it must mark ends
 		markfloor = markceiling = true;
-
+#ifdef ESLOPE
+		if (!(linedef->flags & ML_EFFECT1)) {
+			if (linedef->flags & ML_DONTPEGBOTTOM)
+				rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
+			else
+				rw_midtexturemid = frontsector->ceilingheight;
+		}
+#endif
 		if (linedef->flags & ML_DONTPEGBOTTOM)
 		{
+#ifdef ESLOPE
+			rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
+			rw_midtextureslide = floorfrontslide;
+#else
 			vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
 			// bottom of texture at bottom
 			rw_midtexturemid = vtop - viewz;
+#endif
 		}
 		else
 		{
 			// top of texture at top
 			rw_midtexturemid = worldtop;
+#ifdef ESLOPE
+			rw_midtextureslide = ceilingfrontslide;
+#endif
 		}
 		rw_midtexturemid += sidedef->rowoffset;
 
@@ -1557,47 +1772,120 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	else
 	{
 		// two sided line
+
+#ifdef ESLOPE
+		if (backsector->c_slope) {
+			worldhigh = P_GetZAt(backsector->c_slope, segleft.x, segleft.y) - viewz;
+			worldhighslope = P_GetZAt(backsector->c_slope, segright.x, segright.y) - viewz;
+		} else {
+			worldhighslope =
+#else
+		{
+#endif
+			worldhigh = backsector->ceilingheight - viewz;
+		}
+
+
+#ifdef ESLOPE
+		if (backsector->f_slope) {
+			worldlow = P_GetZAt(backsector->f_slope, segleft.x, segleft.y) - viewz;
+			worldlowslope = P_GetZAt(backsector->f_slope, segright.x, segright.y) - viewz;
+		} else {
+			worldlowslope =
+#else
+		{
+#endif
+			worldlow = backsector->floorheight - viewz;
+		}
+
+
+		// hack to allow height changes in outdoor areas
+		if (frontsector->ceilingpic == skyflatnum
+			&& backsector->ceilingpic == skyflatnum)
+		{
+#ifdef ESLOPE
+			worldtopslope = worldhighslope =
+#endif
+			worldtop = worldhigh;
+		}
+
 		ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
 		ds_p->silhouette = 0;
 
-		if (frontsector->floorheight > backsector->floorheight)
+		if (
+#ifdef ESLOPE
+			worldbottomslope > worldlowslope ||
+#endif
+			worldbottom > worldlow)
 		{
 			ds_p->silhouette = SIL_BOTTOM;
+#ifdef ESLOPE
+			ds_p->bsilheight = (frontsector->f_slope ? INT32_MAX : frontsector->floorheight);
+#else
 			ds_p->bsilheight = frontsector->floorheight;
+#endif
 		}
+#ifdef ESLOPE
+		else if ((backsector->f_slope ? P_GetZAt(backsector->f_slope, viewx, viewy) : backsector->floorheight) > viewz)
+#else
 		else if (backsector->floorheight > viewz)
+#endif
 		{
 			ds_p->silhouette = SIL_BOTTOM;
 			ds_p->bsilheight = INT32_MAX;
 			// ds_p->sprbottomclip = negonearray;
 		}
 
-		if (frontsector->ceilingheight < backsector->ceilingheight)
+		if (
+#ifdef ESLOPE
+			worldtopslope < worldhighslope ||
+#endif
+			worldtop < worldhigh)
 		{
 			ds_p->silhouette |= SIL_TOP;
+#ifdef ESLOPE
+			ds_p->tsilheight = (frontsector->c_slope ? INT32_MIN : frontsector->ceilingheight);
+#else
 			ds_p->tsilheight = frontsector->ceilingheight;
+#endif
 		}
+#ifdef ESLOPE
+		else if ((backsector->c_slope ? P_GetZAt(backsector->c_slope, viewx, viewy) : backsector->ceilingheight) < viewz)
+#else
 		else if (backsector->ceilingheight < viewz)
+#endif
 		{
 			ds_p->silhouette |= SIL_TOP;
 			ds_p->tsilheight = INT32_MIN;
 			// ds_p->sprtopclip = screenheightarray;
 		}
 
-		if (backsector->ceilingheight <= frontsector->floorheight)
+#ifdef ESLOPE
+		if (worldhigh <= worldbottom && worldhighslope <= worldbottomslope)
+#else
+		if (worldhigh <= worldbottom)
+#endif
 		{
 			ds_p->sprbottomclip = negonearray;
 			ds_p->bsilheight = INT32_MAX;
 			ds_p->silhouette |= SIL_BOTTOM;
 		}
 
-		if (backsector->floorheight >= frontsector->ceilingheight)
+#ifdef ESLOPE
+		if (worldlow >= worldtop && worldlowslope >= worldtopslope)
+#else
+		if (worldlow >= worldtop)
+#endif
 		{
 			ds_p->sprtopclip = screenheightarray;
 			ds_p->tsilheight = INT32_MIN;
 			ds_p->silhouette |= SIL_TOP;
 		}
 
+#ifdef ESLOPE
+		// This causes issues with slopes.
+		if (!(frontsector->f_slope || frontsector->c_slope || backsector->f_slope || backsector->c_slope))
+#endif
 		//SoM: 3/25/2000: This code fixes an automap bug that didn't check
 		// frontsector->ceiling and backsector->floor to see if a door was closed.
 		// Without the following code, sprites get displayed behind closed doors.
@@ -1616,17 +1904,11 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			}
 		}
 
-		worldhigh = backsector->ceilingheight - viewz;
-		worldlow = backsector->floorheight - viewz;
-
-		// hack to allow height changes in outdoor areas
-		if (frontsector->ceilingpic == skyflatnum
-			&& backsector->ceilingpic == skyflatnum)
-		{
-			worldtop = worldhigh;
-		}
-
 		if (worldlow != worldbottom
+#ifdef ESLOPE
+			|| worldlowslope != worldbottomslope
+			|| backsector->f_slope != frontsector->f_slope
+#endif
 		    || backsector->floorpic != frontsector->floorpic
 		    || backsector->lightlevel != frontsector->lightlevel
 		    //SoM: 3/22/2000: Check floor x and y offsets.
@@ -1649,6 +1931,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		}
 
 		if (worldhigh != worldtop
+#ifdef ESLOPE
+			|| worldhighslope != worldtopslope
+			|| backsector->c_slope != frontsector->c_slope
+#endif
 		    || backsector->ceilingpic != frontsector->ceilingpic
 		    || backsector->lightlevel != frontsector->lightlevel
 		    //SoM: 3/22/2000: Check floor x and y offsets.
@@ -1678,7 +1964,11 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 		}
 
 		// check TOP TEXTURE
-		if (worldhigh < worldtop)
+		if (worldhigh < worldtop
+#ifdef ESLOPE
+				|| worldhighslope < worldtopslope
+#endif
+			)
 		{
 			// top texture
 			if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
@@ -1691,49 +1981,100 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 				if (!toptexture) //Second side has no texture, use the first side's instead.
 					toptexture = texturetranslation[sidedef->toptexture];
 
+#ifdef ESLOPE
+				if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
+					if (linedef->flags & ML_DONTPEGTOP)
+						rw_toptexturemid = frontsector->ceilingheight - viewz;
+					else
+						rw_toptexturemid = backsector->ceilingheight - viewz;
+				} else
+#endif
 				if (linedef->flags & ML_DONTPEGTOP)
 				{
 					// top of texture at top
 					rw_toptexturemid = worldtop;
+#ifdef ESLOPE
+					rw_toptextureslide = ceilingfrontslide;
+#endif
 				}
 				else
 				{
+#ifdef ESLOPE
+					rw_toptexturemid = worldhigh + textureheight[def->toptexture];
+					rw_toptextureslide = ceilingbackslide;
+#else
 					vtop = backsector->ceilingheight + textureheight[def->toptexture];
 					// bottom of texture
 					rw_toptexturemid = vtop - viewz;
+#endif
 				}
 			}
 			else
 			{
 				toptexture = texturetranslation[sidedef->toptexture];
 
+#ifdef ESLOPE
+				if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
+					if (linedef->flags & ML_DONTPEGTOP)
+						rw_toptexturemid = frontsector->ceilingheight - viewz;
+					else
+						rw_toptexturemid = backsector->ceilingheight - viewz;
+				} else
+#endif
 				if (linedef->flags & ML_DONTPEGTOP)
 				{
 					// top of texture at top
 					rw_toptexturemid = worldtop;
+#ifdef ESLOPE
+					rw_toptextureslide = ceilingfrontslide;
+#endif
 				}
 				else
 				{
+#ifdef ESLOPE
+					rw_toptexturemid = worldhigh + textureheight[sidedef->toptexture];
+					rw_toptextureslide = ceilingbackslide;
+#else
 					vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
 					// bottom of texture
 					rw_toptexturemid = vtop - viewz;
+#endif
 				}
 			}
 		}
 		// check BOTTOM TEXTURE
-		if (worldlow > worldbottom)     //seulement si VISIBLE!!!
+		if (worldlow > worldbottom
+#ifdef ESLOPE
+				|| worldlowslope > worldbottomslope
+#endif
+			)     //seulement si VISIBLE!!!
 		{
 			// bottom texture
 			bottomtexture = texturetranslation[sidedef->bottomtexture];
 
+#ifdef ESLOPE
+			if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
+				if (linedef->flags & ML_DONTPEGBOTTOM)
+					rw_bottomtexturemid = frontsector->floorheight - viewz;
+				else
+					rw_bottomtexturemid = backsector->floorheight - viewz;
+			} else
+#endif
 			if (linedef->flags & ML_DONTPEGBOTTOM)
 			{
 				// bottom of texture at bottom
 				// top of texture at top
-				rw_bottomtexturemid = worldtop;
+				rw_bottomtexturemid = worldbottom;
+#ifdef ESLOPE
+				rw_bottomtextureslide = floorfrontslide;
+#endif
 			}
-			else    // top of texture at top
+			else {   // top of texture at top
 				rw_bottomtexturemid = worldlow;
+#ifdef ESLOPE
+				rw_bottomtextureslide = floorbackslide;
+#endif
+			}
 		}
 
 		rw_toptexturemid += sidedef->rowoffset;
@@ -1745,6 +2086,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			ffloor_t *rover;
 			ffloor_t *r2;
 			fixed_t   lowcut, highcut;
+#ifdef ESLOPE
+			fixed_t lowcutslope, highcutslope;
+
+			// Used for height comparisons and etc across FOFs and slopes
+			fixed_t high1, highslope1, low1, lowslope1, high2, highslope2, low2, lowslope2;
+#endif
 
 			//markceiling = markfloor = true;
 			maskedtexture = true;
@@ -1752,8 +2099,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			ds_p->thicksidecol = maskedtexturecol = lastopening - rw_x;
 			lastopening += rw_stopx - rw_x;
 
-			lowcut = frontsector->floorheight > backsector->floorheight ? frontsector->floorheight : backsector->floorheight;
-			highcut = frontsector->ceilingheight < backsector->ceilingheight ? frontsector->ceilingheight : backsector->ceilingheight;
+			lowcut = max(worldbottom, worldlow) + viewz;
+			highcut = min(worldtop, worldhigh) + viewz;
+#ifdef ESLOPE
+			lowcutslope = max(worldbottomslope, worldlowslope) + viewz;
+			highcutslope = min(worldtopslope, worldhighslope) + viewz;
+#endif
 
 			if (frontsector->ffloors && backsector->ffloors)
 			{
@@ -1764,16 +2115,33 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 						continue;
 					if (rover->flags & FF_INVERTSIDES)
 						continue;
-					if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
-						continue;
 
 					if (rover->norender == leveltime)
 						continue;
 
+#ifdef ESLOPE
+					if (*rover->t_slope) {
+						high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y);
+						highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y);
+					} else
+						high1 = highslope1 = *rover->topheight;
+					if (*rover->b_slope) {
+						low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y);
+						lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y);
+					} else
+						low1 = lowslope1 = *rover->bottomheight;
+
+					if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
+						continue;
+#else
+					if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
+						continue;
+#endif
+
 					for (r2 = frontsector->ffloors; r2; r2 = r2->next)
 					{
 						if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)
-						    || *r2->topheight < lowcut || *r2->bottomheight > highcut)
+						    || *r2->topheight < lowcut || *r2->bottomheight > highcut) ///TODO: make these account for slopes -Red
 							continue;
 
 						if (r2->norender == leveltime)
@@ -1793,8 +2161,24 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 								continue;
 						}
 
+#ifdef ESLOPE
+						if (*r2->t_slope) {
+							high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y);
+							highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y);
+						} else
+							high2 = highslope2 = *r2->topheight;
+						if (*r2->b_slope) {
+							low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y);
+							lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y);
+						} else
+							low2 = lowslope2 = *r2->bottomheight;
+
+						if ((high1 > high2 && highslope1 > highslope2) || (low1 < low2 && lowslope1 < lowslope2))
+							continue;
+#else
 						if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight)
 							continue;
+#endif
 
 						break;
 					}
@@ -1811,16 +2195,33 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 						continue;
 					if (!(rover->flags & FF_ALLSIDES))
 						continue;
-					if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
-						continue;
 
 					if (rover->norender == leveltime)
 						continue;
 
+#ifdef ESLOPE
+					if (*rover->t_slope) {
+						high1 = P_GetZAt(*rover->t_slope, segleft.x, segleft.y);
+						highslope1 = P_GetZAt(*rover->t_slope, segright.x, segright.y);
+					} else
+						high1 = highslope1 = *rover->topheight;
+					if (*rover->b_slope) {
+						low1 = P_GetZAt(*rover->b_slope, segleft.x, segleft.y);
+						lowslope1 = P_GetZAt(*rover->b_slope, segright.x, segright.y);
+					} else
+						low1 = lowslope1 = *rover->bottomheight;
+
+					if ((high1 < lowcut && highslope1 < lowcutslope) || (low1 > highcut && lowslope1 > highcutslope))
+						continue;
+#else
+					if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
+						continue;
+#endif
+
 					for (r2 = backsector->ffloors; r2; r2 = r2->next)
 					{
 						if (!(r2->flags & FF_EXISTS) || !(r2->flags & FF_RENDERSIDES)
-						    || *r2->topheight < lowcut || *r2->bottomheight > highcut)
+						    || *r2->topheight < lowcut || *r2->bottomheight > highcut) ///TODO: make these account for slopes -Red
 							continue;
 
 						if (r2->norender == leveltime)
@@ -1840,8 +2241,24 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 								continue;
 						}
 
+#ifdef ESLOPE
+						if (*r2->t_slope) {
+							high2 = P_GetZAt(*r2->t_slope, segleft.x, segleft.y);
+							highslope2 = P_GetZAt(*r2->t_slope, segright.x, segright.y);
+						} else
+							high2 = highslope2 = *r2->topheight;
+						if (*r2->b_slope) {
+							low2 = P_GetZAt(*r2->b_slope, segleft.x, segleft.y);
+							lowslope2 = P_GetZAt(*r2->b_slope, segright.x, segright.y);
+						} else
+							low2 = lowslope2 = *r2->bottomheight;
+
+						if ((high1 > high2 && highslope1 > highslope2) || (low1 < low2 && lowslope1 < lowslope2))
+							continue;
+#else
 						if (*rover->topheight > *r2->topheight || *rover->bottomheight < *r2->bottomheight)
 							continue;
+#endif
 
 						break;
 					}
@@ -1858,11 +2275,21 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 				{
 					if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || rover->flags & FF_INVERTSIDES)
 						continue;
-					if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight)
-						continue;
 					if (rover->norender == leveltime)
 						continue;
 
+#ifdef ESLOPE
+					// Oy vey.
+					if ((	   (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz
+							&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz)
+							||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz
+							&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz))
+						continue;
+#else
+					if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight)
+						continue;
+#endif
+
 					ds_p->thicksides[i] = rover;
 					i++;
 				}
@@ -1873,12 +2300,27 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 				{
 					if (!(rover->flags & FF_RENDERSIDES) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_ALLSIDES))
 						continue;
+					if (rover->norender == leveltime)
+						continue;
+#ifdef ESLOPE
+					// Oy vey.
+					if ((	   (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldbottom+viewz
+							&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldbottomslope+viewz)
+							||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldtop+viewz
+							&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldtopslope+viewz))
+						continue;
+
+					if ((	   (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) <= worldlow+viewz
+							&& (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) <= worldlowslope+viewz)
+							||((*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) >= worldhigh+viewz
+							&& (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) >= worldhighslope+viewz))
+						continue;
+#else
 					if (*rover->topheight <= frontsector->floorheight || *rover->bottomheight >= frontsector->ceilingheight)
 						continue;
 					if (*rover->topheight <= backsector->floorheight || *rover->bottomheight >= backsector->ceilingheight)
 						continue;
-					if (rover->norender == leveltime)
-						continue;
+#endif
 
 					ds_p->thicksides[i] = rover;
 					i++;
@@ -1898,6 +2340,32 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			else
 				ds_p->maskedtexturecol = ds_p->thicksidecol;
 
+#ifdef ESLOPE
+			maskedtextureheight = &(ds_p->maskedtextureheight[0]); // ????
+
+			// Set midtexture starting height
+			if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing
+				rw_midtextureslide = rw_midtexturebackslide = 0;
+				if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3))
+					rw_midtexturemid = rw_midtextureback = max(frontsector->floorheight, backsector->floorheight) - viewz;
+				else
+					rw_midtexturemid = rw_midtextureback = min(frontsector->ceilingheight, backsector->ceilingheight) - viewz;
+
+			} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
+				rw_midtexturemid = worldbottom;
+				rw_midtextureslide = floorfrontslide;
+				rw_midtextureback = worldlow;
+				rw_midtexturebackslide = floorbackslide;
+			} else {
+				rw_midtexturemid = worldtop;
+				rw_midtextureslide = ceilingfrontslide;
+				rw_midtextureback = worldhigh;
+				rw_midtexturebackslide = ceilingbackslide;
+			}
+			rw_midtexturemid += sidedef->rowoffset;
+			rw_midtextureback += sidedef->rowoffset;
+#endif
+
 			maskedtexture = true;
 		}
 	}
@@ -1950,13 +2418,21 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	//  and doesn't need to be marked.
 	if (frontsector->heightsec == -1)
 	{
-		if (frontsector->floorheight >= viewz)
+		if ((
+#ifdef ESLOPE
+			frontsector->f_slope ? P_GetZAt(frontsector->f_slope, viewx, viewy) :
+#endif
+			frontsector->floorheight) >= viewz)
 		{
 			// above view plane
 			markfloor = false;
 		}
 
-		if (frontsector->ceilingheight <= viewz &&
+		if ((
+#ifdef ESLOPE
+			frontsector->c_slope ? P_GetZAt(frontsector->c_slope, viewx, viewy) :
+#endif
+			frontsector->ceilingheight) <= viewz &&
 		    frontsector->ceilingpic != skyflatnum)
 		{
 			// below view plane
@@ -1967,6 +2443,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	// calculate incremental stepping values for texture edges
 	worldtop >>= 4;
 	worldbottom >>= 4;
+#ifdef ESLOPE
+	worldtopslope >>= 4;
+	worldbottomslope >>= 4;
+#endif
 
 	topstep = -FixedMul (rw_scalestep, worldtop);
 	topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
@@ -1974,6 +2454,17 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	bottomstep = -FixedMul (rw_scalestep,worldbottom);
 	bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
 
+#ifdef ESLOPE
+	if (frontsector->c_slope) {
+		fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldtopslope, ds_p->scale2);
+		topstep = (topfracend-topfrac)/(stop-start+1);
+	}
+	if (frontsector->f_slope) {
+		fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldbottomslope, ds_p->scale2);
+		bottomstep = (bottomfracend-bottomfrac)/(stop-start+1);
+	}
+#endif
+
 	dc_numlights = 0;
 
 	if (frontsector->numlights)
@@ -1987,26 +2478,83 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 		for (i = p = 0; i < dc_numlights; i++)
 		{
+#ifdef ESLOPE
+			fixed_t leftheight, rightheight;
+#endif
+
 			light = &frontsector->lightlist[i];
 			rlight = &dc_lightlist[p];
 
+#ifdef ESLOPE
+			if (light->slope) {
+				leftheight = P_GetZAt(light->slope, segleft.x, segleft.y);
+				rightheight = P_GetZAt(light->slope, segright.x, segright.y);
+
+				// Flag sector as having slopes
+				frontsector->hasslope = true;
+			} else
+				leftheight = rightheight = light->height;
+
+			leftheight -= viewz;
+			rightheight -= viewz;
+
+			leftheight >>= 4;
+			rightheight >>= 4;
+#endif
+
 			if (i != 0)
 			{
+#ifdef ESLOPE
+				if (leftheight < worldbottom && rightheight < worldbottomslope)
+					continue;
+
+				if (leftheight > worldtop && rightheight > worldtopslope && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight)
+					continue;
+#else
 				if (light->height < frontsector->floorheight)
 					continue;
 
 				if (light->height > frontsector->ceilingheight && i+1 < dc_numlights && frontsector->lightlist[i+1].height > frontsector->ceilingheight)
 					continue;
+#endif
 			}
 
+#ifdef ESLOPE
+			rlight->height = (centeryfrac>>4) - FixedMul(leftheight, rw_scale);
+			rlight->heightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2);
+			rlight->heightstep = (rlight->heightstep-rlight->height)/(stop-start+1);
+#else
 			rlight->height = (centeryfrac>>4) - FixedMul((light->height - viewz) >> 4, rw_scale);
 			rlight->heightstep = -FixedMul (rw_scalestep, (light->height - viewz) >> 4);
+#endif
 			rlight->flags = light->flags;
 
 			if (light->caster && light->caster->flags & FF_SOLID)
 			{
+#ifdef ESLOPE
+				if (*light->caster->b_slope) {
+					leftheight = P_GetZAt(*light->caster->b_slope, segleft.x, segleft.y);
+					rightheight = P_GetZAt(*light->caster->b_slope, segright.x, segright.y);
+
+					// Flag sector as having slopes
+					frontsector->hasslope = true;
+				} else
+					leftheight = rightheight = *light->caster->bottomheight;
+
+				leftheight -= viewz;
+				rightheight -= viewz;
+
+				leftheight >>= 4;
+				rightheight >>= 4;
+
+				rlight->botheight = (centeryfrac>>4) - FixedMul(leftheight, rw_scale);
+				rlight->botheightstep = (centeryfrac>>4) - FixedMul(rightheight, ds_p->scale2);
+				rlight->botheightstep = (rlight->botheightstep-rlight->botheight)/(stop-start+1);
+
+#else
 				rlight->botheight = (centeryfrac >> 4) - FixedMul((*light->caster->bottomheight - viewz) >> 4, rw_scale);
 				rlight->botheightstep = -FixedMul (rw_scalestep, (*light->caster->bottomheight - viewz) >> 4);
+#endif
 			}
 
 			rlight->lightlevel = *light->lightlevel;
@@ -2027,8 +2575,14 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 #endif
 
 			ffloor[i].f_pos >>= 4;
+#ifdef ESLOPE
+			ffloor[i].f_pos_slope >>= 4;
+			ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
+			ffloor[i].f_step = ((centeryfrac>>4) - FixedMul(ffloor[i].f_pos_slope, ds_p->scale2) - ffloor[i].f_frac)/(stop-start+1);
+#else
 			ffloor[i].f_step = FixedMul(-rw_scalestep, ffloor[i].f_pos);
 			ffloor[i].f_frac = (centeryfrac>>4) - FixedMul(ffloor[i].f_pos, rw_scale);
+#endif
 		}
 	}
 
@@ -2036,22 +2590,51 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	{
 		worldhigh >>= 4;
 		worldlow >>= 4;
+#ifdef ESLOPE
+		worldhighslope >>= 4;
+		worldlowslope >>= 4;
+#endif
 
-		if (worldhigh < worldtop)
+		if (worldhigh < worldtop
+#ifdef ESLOPE
+			|| worldhighslope <= worldtopslope
+#endif
+			)
 		{
 			pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
 			pixhighstep = -FixedMul (rw_scalestep,worldhigh);
+
+#ifdef ESLOPE
+			if (backsector->c_slope) {
+				fixed_t topfracend = (centeryfrac>>4) - FixedMul (worldhighslope, ds_p->scale2);
+				pixhighstep = (topfracend-pixhigh)/(stop-start+1);
+			}
+#endif
 		}
 
-		if (worldlow > worldbottom)
+		if (worldlow > worldbottom
+#ifdef ESLOPE
+			|| worldlowslope >= worldbottomslope
+#endif
+			)
 		{
 			pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
 			pixlowstep = -FixedMul (rw_scalestep,worldlow);
+#ifdef ESLOPE
+			if (backsector->f_slope) {
+				fixed_t bottomfracend = (centeryfrac>>4) - FixedMul (worldlowslope, ds_p->scale2);
+				pixlowstep = (bottomfracend-pixlow)/(stop-start+1);
+			}
+#endif
 		}
 
 		{
 			ffloor_t * rover;
 			i = 0;
+#ifdef ESLOPE
+			fixed_t rovertest;
+			fixed_t planevistest;
+#endif
 
 			if (backsector->ffloors)
 			{
@@ -2062,6 +2645,52 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 					if (rover->norender == leveltime)
 						continue;
 
+#ifdef ESLOPE
+					// Let the renderer know this sector is sloped.
+					if (*rover->b_slope || *rover->t_slope)
+						backsector->hasslope = true;
+
+					rovertest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, backsector->soundorg.x, backsector->soundorg.y) : *rover->bottomheight) - viewz;
+					planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight);
+
+					if (rovertest>>4 <= worldhigh &&
+					    rovertest>>4 >= worldlow &&
+					    ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) ||
+					     (viewz > planevistest && (rover->flags & FF_BOTHPLANES))))
+					{
+						//ffloor[i].slope = *rover->b_slope;
+						ffloor[i].b_pos = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz;
+						ffloor[i].b_pos_slope = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz;
+						ffloor[i].b_pos >>= 4;
+						ffloor[i].b_pos_slope >>= 4;
+						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
+						ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2);
+						ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1);
+						i++;
+					}
+
+					if (i >= MAXFFLOORS)
+						break;
+
+					rovertest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, backsector->soundorg.x, backsector->soundorg.y) : *rover->topheight) - viewz;
+					planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight);
+
+					if (rovertest>>4 <= worldhigh &&
+					    rovertest>>4 >= worldlow &&
+					    ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) ||
+					     (viewz < planevistest && (rover->flags & FF_BOTHPLANES))))
+					{
+						//ffloor[i].slope = *rover->t_slope;
+						ffloor[i].b_pos = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz;
+						ffloor[i].b_pos_slope = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz;
+						ffloor[i].b_pos >>= 4;
+						ffloor[i].b_pos_slope >>= 4;
+						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
+						ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2);
+						ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1);
+						i++;
+					}
+#else
 					if (*rover->bottomheight <= backsector->ceilingheight &&
 					    *rover->bottomheight >= backsector->floorheight &&
 					    ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) ||
@@ -2073,8 +2702,10 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
 						i++;
 					}
+
 					if (i >= MAXFFLOORS)
 						break;
+
 					if (*rover->topheight >= backsector->floorheight &&
 					    *rover->topheight <= backsector->ceilingheight &&
 					    ((viewz > *rover->topheight && !(rover->flags & FF_INVERTPLANES)) ||
@@ -2086,6 +2717,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
 						i++;
 					}
+#endif
 				}
 			}
 			else if (frontsector && frontsector->ffloors)
@@ -2097,6 +2729,53 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 					if (rover->norender == leveltime)
 						continue;
 
+
+#ifdef ESLOPE
+					// Let the renderer know this sector is sloped.
+					if (*rover->b_slope || *rover->t_slope)
+						frontsector->hasslope = true;
+
+					rovertest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->bottomheight) - viewz;
+					planevistest = (*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) : *rover->bottomheight);
+
+					if (rovertest>>4 <= worldtop &&
+					    rovertest>>4 >= worldbottom &&
+					    ((viewz < planevistest && !(rover->flags & FF_INVERTPLANES)) ||
+					     (viewz > planevistest && (rover->flags & FF_BOTHPLANES))))
+					{
+						//ffloor[i].slope = *rover->b_slope;
+						ffloor[i].b_pos = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segleft.x, segleft.y) : *rover->bottomheight) - viewz;
+						ffloor[i].b_pos_slope = (*rover->b_slope ? P_GetZAt(*rover->b_slope, segright.x, segright.y) : *rover->bottomheight) - viewz;
+						ffloor[i].b_pos >>= 4;
+						ffloor[i].b_pos_slope >>= 4;
+						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
+						ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2);
+						ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1);
+						i++;
+					}
+
+					if (i >= MAXFFLOORS)
+						break;
+
+					rovertest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, frontsector->soundorg.x, frontsector->soundorg.y) : *rover->topheight) - viewz;
+					planevistest = (*rover->t_slope ? P_GetZAt(*rover->t_slope, viewx, viewy) : *rover->topheight);
+
+					if (rovertest>>4 <= worldtop &&
+					    rovertest>>4 >= worldbottom &&
+					    ((viewz > planevistest && !(rover->flags & FF_INVERTPLANES)) ||
+					     (viewz < planevistest && (rover->flags & FF_BOTHPLANES))))
+					{
+						//ffloor[i].slope = *rover->t_slope;
+						ffloor[i].b_pos = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segleft.x, segleft.y) : *rover->topheight) - viewz;
+						ffloor[i].b_pos_slope = (*rover->t_slope ? P_GetZAt(*rover->t_slope, segright.x, segright.y) : *rover->topheight) - viewz;
+						ffloor[i].b_pos >>= 4;
+						ffloor[i].b_pos_slope >>= 4;
+						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
+						ffloor[i].b_step = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos_slope, ds_p->scale2);
+						ffloor[i].b_step = (ffloor[i].b_step-ffloor[i].b_frac)/(stop-start+1);
+						i++;
+					}
+#else
 					if (*rover->bottomheight <= frontsector->ceilingheight &&
 					    *rover->bottomheight >= frontsector->floorheight &&
 					    ((viewz < *rover->bottomheight && !(rover->flags & FF_INVERTPLANES)) ||
@@ -2121,6 +2800,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 						ffloor[i].b_frac = (centeryfrac >> 4) - FixedMul(ffloor[i].b_pos, rw_scale);
 						i++;
 					}
+#endif
 				}
 			}
 #ifdef POLYOBJECTS_PLANES
@@ -2137,6 +2817,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 					if (ffloor[i].plane->maxx < ds_p->x2)
 						ffloor[i].plane->maxx = ds_p->x2;
 
+#ifdef ESLOPE
+					ffloor[i].slope = NULL;
+#endif
 					ffloor[i].b_pos = backsector->floorheight;
 					ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4;
 					ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos);
@@ -2153,6 +2836,9 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 					if (ffloor[i].plane->maxx < ds_p->x2)
 						ffloor[i].plane->maxx = ds_p->x2;
 
+#ifdef ESLOPE
+					ffloor[i].slope = NULL;
+#endif
 					ffloor[i].b_pos = backsector->ceilingheight;
 					ffloor[i].b_pos = (ffloor[i].b_pos - viewz) >> 4;
 					ffloor[i].b_step = FixedMul(-rw_scalestep, ffloor[i].b_pos);
diff --git a/src/r_things.c b/src/r_things.c
index 9a8b1319bd1ee226c5f238fae706233152d28483..3a38eb482238be4af7bfcf6ee565cb49b55a1dff 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -950,12 +950,22 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
 
 	for (i = 1; i < sector->numlights; i++)
 	{
-		if (sector->lightlist[i].height >= sprite->gzt || !(sector->lightlist[i].caster->flags & FF_CUTSPRITES))
+		fixed_t testheight = sector->lightlist[i].height;
+
+		if (!(sector->lightlist[i].caster->flags & FF_CUTSPRITES))
 			continue;
-		if (sector->lightlist[i].height <= sprite->gz)
+
+#ifdef ESLOPE
+		if (sector->lightlist[i].slope)
+			testheight = P_GetZAt(sector->lightlist[i].slope, sprite->gx, sprite->gy);
+#endif
+
+		if (testheight >= sprite->gzt)
+			continue;
+		if (testheight <= sprite->gz)
 			return;
 
-		cutfrac = (INT16)((centeryfrac - FixedMul(sector->lightlist[i].height - viewz, sprite->scale))>>FRACBITS);
+		cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->scale))>>FRACBITS);
 		if (cutfrac < 0)
 			continue;
 		if (cutfrac > vid.height)
@@ -966,15 +976,15 @@ static void R_SplitSprite(vissprite_t *sprite, mobj_t *thing)
 		newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t));
 
 		sprite->cut |= SC_BOTTOM;
-		sprite->gz = sector->lightlist[i].height;
+		sprite->gz = testheight;
 
 		newsprite->gzt = sprite->gz;
 
 		sprite->sz = cutfrac;
 		newsprite->szt = (INT16)(sprite->sz - 1);
 
-		if (sector->lightlist[i].height < sprite->pzt && sector->lightlist[i].height > sprite->pz)
-			sprite->pz = newsprite->pzt = sector->lightlist[i].height;
+		if (testheight < sprite->pzt && testheight > sprite->pz)
+			sprite->pz = newsprite->pzt = testheight;
 		else
 		{
 			newsprite->pz = newsprite->gz;
@@ -1191,7 +1201,20 @@ static void R_ProjectSprite(mobj_t *thing)
 	if (thing->subsector->sector->numlights)
 	{
 		INT32 lightnum;
+#ifdef ESLOPE // R_GetPlaneLight won't work on sloped lights!
+		light = thing->subsector->sector->numlights - 1;
+
+		for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
+			fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y)
+			            : thing->subsector->sector->lightlist[lightnum].height;
+			if (h <= gzt) {
+				light = lightnum - 1;
+				break;
+			}
+		}
+#else
 		light = R_GetPlaneLight(thing->subsector->sector, gzt, false);
+#endif
 		lightnum = (*thing->subsector->sector->lightlist[light].lightlevel >> LIGHTSEGSHIFT);
 
 		if (lightnum < 0)
@@ -1546,23 +1569,12 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 	// If a limit exists, handle things a tiny bit different.
 	if ((limit_dist = (fixed_t)((maptol & TOL_NIGHTS) ? cv_drawdist_nights.value : cv_drawdist.value) << FRACBITS))
 	{
-		if (!players[displayplayer].mo)
-			return; // Draw nothing if no player.
-			// todo: is this really the best option for this situation?
-
 		for (thing = sec->thinglist; thing; thing = thing->snext)
 		{
 			if (thing->sprite == SPR_NULL || thing->flags2 & MF2_DONTDRAW)
 				continue;
 
-			approx_dist = P_AproxDistance(
-				players[displayplayer].mo->x - thing->x,
-				players[displayplayer].mo->y - thing->y);
-
-			if (splitscreen && approx_dist > limit_dist && players[secondarydisplayplayer].mo)
-				approx_dist = P_AproxDistance(
-					players[secondarydisplayplayer].mo->x - thing->x,
-					players[secondarydisplayplayer].mo->y - thing->y);
+			approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
 
 			if (approx_dist <= limit_dist)
 				R_ProjectSprite(thing);
@@ -1579,23 +1591,12 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
 	// Someone seriously wants infinite draw distance for precipitation?
 	if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
 	{
-		if (!players[displayplayer].mo)
-			return; // Draw nothing if no player.
-			// todo: is this really the best option for this situation?
-
 		for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
 		{
 			if (precipthing->precipflags & PCF_INVISIBLE)
 				continue;
 
-			approx_dist = P_AproxDistance(
-				players[displayplayer].mo->x - precipthing->x,
-				players[displayplayer].mo->y - precipthing->y);
-
-			if (splitscreen && approx_dist > limit_dist && players[secondarydisplayplayer].mo)
-				approx_dist = P_AproxDistance(
-					players[secondarydisplayplayer].mo->x - precipthing->x,
-					players[secondarydisplayplayer].mo->y - precipthing->y);
+			approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
 
 			if (approx_dist <= limit_dist)
 				R_ProjectPrecipitationSprite(precipthing);
@@ -1704,6 +1705,19 @@ static void R_CreateDrawNodes(void)
 		}
 		if (ds->maskedtexturecol)
 		{
+#ifdef POLYOBJECTS_PLANES
+			// Check for a polyobject plane, but only if this is a front line
+			if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
+				// Put it in!
+
+				entry = R_CreateDrawNode(&nodehead);
+				entry->plane = ds->curline->polyseg->visplane;
+				entry->seg = ds;
+				ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
+				ds->curline->polyseg->visplane = NULL;
+			}
+#endif
+
 			entry = R_CreateDrawNode(&nodehead);
 			entry->seg = ds;
 		}
@@ -1720,7 +1734,7 @@ static void R_CreateDrawNodes(void)
 					plane = ds->ffloorplanes[p];
 					R_PlaneBounds(plane);
 
-					if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
+					if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low || plane->polyobj)
 					{
 						ds->ffloorplanes[p] = NULL;
 						continue;
@@ -1761,24 +1775,34 @@ static void R_CreateDrawNodes(void)
 		{
 			if (r2->plane)
 			{
+				fixed_t planeobjectz, planecameraz;
 				if (r2->plane->minx > rover->x2 || r2->plane->maxx < rover->x1)
 					continue;
 				if (rover->szt > r2->plane->low || rover->sz < r2->plane->high)
 					continue;
 
+#ifdef ESLOPE
+				// Effective height may be different for each comparison in the case of slopes
+				if (r2->plane->slope) {
+					planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy);
+					planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy);
+				} else
+#endif
+					planeobjectz = planecameraz = r2->plane->height;
+
 				if (rover->mobjflags & MF_NOCLIPHEIGHT)
 				{
 					//Objects with NOCLIPHEIGHT can appear halfway in.
-					if (r2->plane->height < viewz && rover->pz+(rover->thingheight/2) >= r2->plane->height)
+					if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz)
 						continue;
-					if (r2->plane->height > viewz && rover->pzt-(rover->thingheight/2) <= r2->plane->height)
+					if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz)
 						continue;
 				}
 				else
 				{
-					if (r2->plane->height < viewz && rover->pz >= r2->plane->height)
+					if (planecameraz < viewz && rover->pz >= planeobjectz)
 						continue;
-					if (r2->plane->height > viewz && rover->pzt <= r2->plane->height)
+					if (planecameraz > viewz && rover->pzt <= planeobjectz)
 						continue;
 				}
 
@@ -1808,6 +1832,7 @@ static void R_CreateDrawNodes(void)
 			}
 			else if (r2->thickseg)
 			{
+				fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz;
 				if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1)
 					continue;
 
@@ -1818,9 +1843,25 @@ static void R_CreateDrawNodes(void)
 				if (scale <= rover->scale)
 					continue;
 
-				if ((*r2->ffloor->topheight > viewz && *r2->ffloor->bottomheight < viewz) ||
-				    (*r2->ffloor->topheight < viewz && rover->gzt < *r2->ffloor->topheight) ||
-				    (*r2->ffloor->bottomheight > viewz && rover->gz > *r2->ffloor->bottomheight))
+#ifdef ESLOPE
+				if (*r2->ffloor->t_slope) {
+					topplaneobjectz = P_GetZAt(*r2->ffloor->t_slope, rover->gx, rover->gy);
+					topplanecameraz = P_GetZAt(*r2->ffloor->t_slope, viewx, viewy);
+				} else
+#endif
+					topplaneobjectz = topplanecameraz = *r2->ffloor->topheight;
+
+#ifdef ESLOPE
+				if (*r2->ffloor->b_slope) {
+					botplaneobjectz = P_GetZAt(*r2->ffloor->b_slope, rover->gx, rover->gy);
+					botplanecameraz = P_GetZAt(*r2->ffloor->b_slope, viewx, viewy);
+				} else
+#endif
+					botplaneobjectz = botplanecameraz = *r2->ffloor->bottomheight;
+
+				if ((topplanecameraz > viewz && botplanecameraz < viewz) ||
+				    (topplanecameraz < viewz && rover->gzt < topplaneobjectz) ||
+				    (botplanecameraz > viewz && rover->gz > botplaneobjectz))
 				{
 					entry = R_CreateDrawNode(NULL);
 					(entry->prev = r2->prev)->next = entry;
@@ -1831,7 +1872,7 @@ static void R_CreateDrawNodes(void)
 			}
 			else if (r2->seg)
 			{
-#ifdef POLYOBJECTS_PLANES
+#if 0 //#ifdef POLYOBJECTS_PLANES
 				if (r2->seg->curline->polyseg && rover->mobj && P_MobjInsidePolyobj(r2->seg->curline->polyseg, rover->mobj)) {
 					// Determine if we need to sort in front of the polyobj, based on the planes. This fixes the issue where
 					// polyobject planes render above the object standing on them. (A bit hacky... but it works.) -Red
@@ -2039,21 +2080,21 @@ void R_ClipSprites(void)
 			if (spr->gzt <= ds->tsilheight)
 				silhouette &= ~SIL_TOP;
 
-			if (silhouette == 1)
+			if (silhouette == SIL_BOTTOM)
 			{
 				// bottom sil
 				for (x = r1; x <= r2; x++)
 					if (spr->clipbot[x] == -2)
 						spr->clipbot[x] = ds->sprbottomclip[x];
 			}
-			else if (silhouette == 2)
+			else if (silhouette == SIL_TOP)
 			{
 				// top sil
 				for (x = r1; x <= r2; x++)
 					if (spr->cliptop[x] == -2)
 						spr->cliptop[x] = ds->sprtopclip[x];
 			}
-			else if (silhouette == 3)
+			else if (silhouette == (SIL_TOP|SIL_BOTTOM))
 			{
 				// both
 				for (x = r1; x <= r2; x++)
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index b4eeeeb5fb1c0e778be6a6a16758e0c116d9ad53..b3fa5390c50a748d60e87920073f46f5c28ff117 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -39,8 +39,7 @@ set(SRB2_SDL2_HEADERS
 	sdlmain.h
 )
 
-prepend_sources(SRB2_SDL2_SOURCES)
-prepend_sources(SRB2_SDL2_HEADERS)
+source_group("Interface Code" FILES ${SRB2_SDL2_SOURCES} ${SRB2_SDL2_HEADERS})
 
 # Dependency
 find_package(SDL2)
@@ -49,9 +48,22 @@ if(${SDL2_FOUND})
 	set(SRB2_SDL2_TOTAL_SOURCES
 		${SRB2_CORE_SOURCES}
 		${SRB2_CORE_HEADERS}
+		${SRB2_CORE_RENDER_SOURCES}
+		${SRB2_CORE_GAME_SOURCES}
+		${SRB2_LUA_SOURCES}
+		${SRB2_LUA_HEADERS}
+		${SRB2_BLUA_SOURCES}
+		${SRB2_BLUA_HEADERS}
 		${SRB2_SDL2_SOURCES}
 		${SRB2_SDL2_HEADERS}
 	)
+	
+	source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS})
+	source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES})
+	source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES})
+	source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES})
+	source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS})
+	source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS})
 
 	if(${SRB2_CONFIG_HWRENDER})
 		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
@@ -60,15 +72,9 @@ if(${SDL2_FOUND})
 			${SRB2_R_OPENGL_SOURCES}
 			${SRB2_R_OPENGL_HEADERS}
 		)
-	endif()
 
-	if(${SRB2_CONFIG_HAVE_BLUA})
-		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
-			${SRB2_LUA_SOURCES}
-			${SRB2_LUA_HEADERS}
-			${SRB2_BLUA_SOURCES}
-			${SRB2_BLUA_HEADERS}
-		)
+		source_group("Hardware" FILES ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS})
+		source_group("Hardware\\OpenGL Renderer" FILES ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS})
 	endif()
 
 	if(${SRB2_USEASM})
@@ -85,7 +91,6 @@ if(${SDL2_FOUND})
 			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES LANGUAGE C)
 			set_source_files_properties(${SRB2_ASM_SOURCES} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
 		endif()
-
 	endif()
 
 	if(${CMAKE_SYSTEM} MATCHES Windows)
@@ -94,39 +99,36 @@ if(${SDL2_FOUND})
 			${CMAKE_SOURCE_DIR}/src/win32/Srb2win.rc
 		)
 	endif()
-	if(NOT CLANG)
-		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
-			${CMAKE_SOURCE_DIR}/src/string.c
-		)
-	endif()
 
 	if(${CMAKE_SYSTEM} MATCHES Darwin)
 		set(MACOSX_BUNDLE_ICON_FILE Srb2mac.icns)
 		set_source_files_properties(macosx/Srb2mac.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
-		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
+		set(SRB2_SDL2_MAC_SOURCES
 			macosx/mac_alert.c
 			macosx/mac_alert.h
 			macosx/mac_resources.c
 			macosx/mac_resources.h
 			macosx/Srb2mac.icns
 		)
+		source_group("Interface Code\\OSX Compatibility" FILES ${SRB2_SDL2_MAC_SOURCES})
+		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES} ${SRB2_SDL2_MAC_SOURCES})
 	endif()
 
+	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
+	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
+
 	if(CLANG)
-		add_executable(${SRB2_SDL2_EXE_NAME} MACOSX_BUNDLE ${SRB2_SDL2_TOTAL_SOURCES})
-		add_framework(CoreFoundation ${SRB2_SDL2_EXE_NAME})
-		add_framework(SDL2 ${SRB2_SDL2_EXE_NAME})
-		add_framework(SDL2_mixer ${SRB2_SDL2_EXE_NAME})
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		add_framework(CoreFoundation SRB2SDL2)
+		add_framework(SDL2 SRB2SDL2)
+		add_framework(SDL2_mixer SRB2SDL2)
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${PNG_LIBRARIES}
 			${ZLIB_LIBRARIES}
 			${OPENGL_LIBRARIES}
 		)
-		set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
+		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "Sonic Robo Blast 2")
 	else()
-		add_executable(${SRB2_SDL2_EXE_NAME} WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
-
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_LIBRARIES}
 			${SDL2_MIXER_LIBRARIES}
 			${PNG_LIBRARIES}
@@ -135,14 +137,15 @@ if(${SDL2_FOUND})
 		)
 
 		if(${CMAKE_SYSTEM} MATCHES Linux)
-			target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+			target_link_libraries(SRB2SDL2 PRIVATE
 				m
 				rt
 			)
 		endif()
-
 	endif()
 
+	#target_link_libraries(SRB2SDL2 PRIVATE SRB2Core)
+
 	if(${SRB2_USEASM})
 		if(${SRB2_CONFIG_YASM})
 			set(ASM_ASSEMBLER_TEMP ${CMAKE_ASM_YASM_COMPILER})
@@ -159,7 +162,7 @@ if(${SDL2_FOUND})
 			foreach(ASMFILE ${SRB2_NASM_SOURCES})
 				get_filename_component(ASMFILE_NAME ${ASMFILE} NAME_WE)
 				set(ASMFILE_NAME ${ASMFILE_NAME}.obj)
-				add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} PRE_LINK
+				add_custom_command(TARGET SRB2SDL2 PRE_LINK
 					COMMAND ${ASM_ASSEMBLER_TEMP} ARGS -f ${ASM_ASSEMBLER_OBJFORMAT} -o ${CMAKE_CURRENT_BINARY_DIR}/${ASMFILE_NAME} ${ASMFILE}
 					COMMENT "assemble ${ASMFILE_NAME}."
 				)
@@ -167,23 +170,23 @@ if(${SDL2_FOUND})
 		endif()
 	endif()
 
-	set_target_properties(${SRB2_SDL2_EXE_NAME} PROPERTIES VERSION ${SRB2_VERSION})
+	set_target_properties(SRB2SDL2 PROPERTIES VERSION ${SRB2_VERSION})
 
 	if(${CMAKE_SYSTEM} MATCHES Windows)
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			ws2_32
 		)
-		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_compile_options(SRB2SDL2 PRIVATE
 			-U_WINDOWS
 		)
 	endif()
 
 	if(MSVC)
 		find_package(SDL2_MAIN REQUIRED)
-		target_link_libraries(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_link_libraries(SRB2SDL2 PRIVATE
 			${SDL2_MAIN_LIBRARIES}
 		)
-		target_compile_options(${SRB2_SDL2_EXE_NAME} PRIVATE
+		target_compile_options(SRB2SDL2 PRIVATE
 			/Umain
 			/D_CRT_SECURE_NO_WARNINGS # something about string functions.
 			/D_CRT_NONSTDC_NO_DEPRECATE
@@ -192,7 +195,7 @@ if(${SDL2_FOUND})
 		)
 	endif()
 
-	target_include_directories(${SRB2_SDL2_EXE_NAME} PRIVATE
+	target_include_directories(SRB2SDL2 PRIVATE
 		${SDL2_INCLUDE_DIRS}
 		${SDL2_MIXER_INCLUDE_DIRS}
 		${PNG_INCLUDE_DIRS}
@@ -201,10 +204,10 @@ if(${SDL2_FOUND})
 	)
 
 	if(${SRB2_HAVE_MIXER})
-		target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
+		target_compile_definitions(SRB2SDL2 PRIVATE -DHAVE_MIXER -DSOUND=SOUND_MIXER)
 	endif()
 
-	target_compile_definitions(${SRB2_SDL2_EXE_NAME} PRIVATE
+	target_compile_definitions(SRB2SDL2 PRIVATE
 		-DHAVE_SDL
 	)
 
@@ -212,21 +215,21 @@ if(${SDL2_FOUND})
 	if(CMAKE_COMPILER_IS_GNUCC)
 		if(${CMAKE_BUILD_TYPE} MATCHES Debug)
 			message(STATUS "Will make separate debug symbols in *.debug")
-			add_custom_command(TARGET ${SRB2_SDL2_EXE_NAME} POST_BUILD
-				COMMAND ${OBJCOPY} --only-keep-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}> $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>.debug
-				COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
-				COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE_NAME:${SRB2_SDL2_EXE_NAME}>.debug $<TARGET_FILE:${SRB2_SDL2_EXE_NAME}>
+			add_custom_command(TARGET SRB2SDL2 POST_BUILD
+				COMMAND ${OBJCOPY} --only-keep-debug $<TARGET_FILE:SRB2SDL2> $<TARGET_FILE:SRB2SDL2>.debug
+				COMMAND ${OBJCOPY} --strip-debug $<TARGET_FILE:SRB2SDL2>
+				COMMAND ${OBJCOPY} --add-gnu-debuglink=$<TARGET_FILE_NAME:SRB2SDL2>.debug $<TARGET_FILE:SRB2SDL2>
 			)
 		endif()
 	endif()
 
 	#### Installation ####
 	if (CLANG)
-		install(TARGETS ${SRB2_SDL2_EXE_NAME}
+		install(TARGETS SRB2SDL2
 			BUNDLE DESTINATION .
 		)
 	else()
-		install(TARGETS ${SRB2_SDL2_EXE_NAME} ${SRB2_SDL2_EXE_NAME}
+		install(TARGETS SRB2SDL2 SRB2SDL2
 			RUNTIME DESTINATION .
 		)
 	endif()
@@ -257,10 +260,10 @@ if(${SDL2_FOUND})
 
 		# We also want to copy those DLLs to build directories on MSVC.
 		# So we'll add a post_build step.
-		copy_files_to_build_dir(${SRB2_SDL2_EXE_NAME} win_extra_dll_list)
+		copy_files_to_build_dir(SRB2SDL2 win_extra_dll_list)
 	endif()
 
-	
+
 	# Mac bundle fixup
 	if(CLANG)
 		install(CODE "
@@ -271,6 +274,9 @@ if(${SDL2_FOUND})
 			)"
 		)
 	endif()
+
+	set(SRB2_SDL2_AVAILABLE YES PARENT_SCOPE)
 else()
-	message(WARNING "SDL2 wasn't found, so ${SRB2_SDL2_EXE_NAME} won't be available")
-endif()
+	message(WARNING "SDL2 was not found, so the SDL2 target will not be available.")
+	set(SRB2_SDL2_AVAILABLE NO PARENT_SCOPE)
+endif()
\ No newline at end of file
diff --git a/src/sdl/SDL_icon.xpm b/src/sdl/SDL_icon.xpm
index 70bb02d3c97a0ffe37a5e890c4736386779bcbb1..cf72960dfc9048d1ab23b3c59ed4d29d65f4c404 100644
--- a/src/sdl/SDL_icon.xpm
+++ b/src/sdl/SDL_icon.xpm
@@ -1,80 +1,425 @@
 /* XPM */
-static const char * SDL_icon_xpm[] = {
-"32 32 45 1",
-" 	c None",
-".	c #6B6BFF",
-"+	c #3D00B9",
-"@	c #4848FF",
-"#	c #2525FF",
-"$	c #310096",
-"%	c #003196",
-"&	c #003DB9",
-"*	c #620096",
-"=	c #6E6E6E",
-"-	c #966200",
-";	c #250073",
-">	c #626262",
-",	c #FF8F6B",
-"'	c #FFC66B",
-")	c #FFAB8E",
-"!	c #000080",
-"~	c #B6B6B6",
-"{	c #929292",
-"]	c #FFD48E",
-"^	c #0000B9",
-"/	c #565656",
-"(	c #868686",
-"_	c #808080",
-":	c #C0C0C0",
-"<	c #DADADA",
-"[	c #F2F2F2",
-"}	c #FFFFFF",
-"|	c #CECECE",
-"1	c #AAAAAA",
-"2	c #E6E6E6",
-"3	c #000096",
-"4	c #AB8EFF",
-"5	c #190050",
-"6	c #000000",
-"7	c #8E8EFF",
-"8	c #3E3E3E",
-"9	c #7A7A7A",
-"0	c #0E0E0E",
-"a	c #9E9E9E",
-"b	c #001950",
-"c	c #C2C2C2",
-"d	c #323232",
-"e	c #002573",
-"f	c #A0A0A4",
-"                                ",
-"                                ",
-"                                ",
-"             .+@##@.            ",
-"           @@.@#######@         ",
-"         @@....#########        ",
-" ..    .@.....@+##$%%%&&%       ",
-" ..@# @@....@+#*=-;%%%%%        ",
-"  ..@#@......@>,')!%%%$         ",
-" ~..$#.........{])^#+%/         ",
-"   +##@.........()^@@@@@_       ",
-"  $####@........#=#######+      ",
-"  +######....@@##^#########_    ",
-"  +#####=:<<:+##############/   ",
-"[<=####{<}}}}|###############=  ",
-" }1###=2}}}}}}.###############  ",
-" }<3#3~}}}}}}}4################ ",
-" }<5#6:}}}}}}}7################/",
-" }:6861}}}}}}}.########$$ 9  .@$",
-" }:0a6~}}}}}}}@######5b         ",
-"22cd262}}}}}}2######5b$         ",
-"  2>1a}}}}}}}{(*###%be##        ",
-"  860)1<[22c1)]]+##be###        ",
-"  ~)]]]))))]]]]]=#bb####        ",
-"   )]]]]]]]]](]]=eb$####        ",
-"    :]]]]]]]]]'9bbb$#####       ",
-"      ),'''''(    >db+###       ",
-"                      =##f      ",
-"                        {       ",
-"                                ",
-"                                ",
-"                                "};
+static char * C:\Repo\srb2\src\sdl\SDL_icon_xpm[] = {
+"32 32 390 2",
+"  	c None",
+". 	c #4F4F70",
+"+ 	c #4D4D87",
+"@ 	c #4D4D84",
+"# 	c #4E4E6C",
+"$ 	c #6C6C95",
+"% 	c #5E5EB2",
+"& 	c #6B6BE7",
+"* 	c #7373F9",
+"= 	c #7C7CFF",
+"- 	c #6F70E7",
+"; 	c #494BB2",
+"> 	c #4F4FA3",
+", 	c #6464D4",
+"' 	c #7979F5",
+") 	c #5F5FCA",
+"! 	c #5D5D93",
+"~ 	c #3A3A9F",
+"{ 	c #6060AC",
+"] 	c #777793",
+"^ 	c #5C5CB3",
+"/ 	c #7373EA",
+"( 	c #7A7AFF",
+"_ 	c #7575FF",
+": 	c #7979FF",
+"< 	c #6264DD",
+"[ 	c #47478C",
+"} 	c #564567",
+"| 	c #4647D0",
+"1 	c #5C5CAE",
+"2 	c #5E5EFF",
+"3 	c #2929FF",
+"4 	c #1D1DFF",
+"5 	c #1919D1",
+"6 	c #4F4F90",
+"7 	c #1E1ECE",
+"8 	c #5858FF",
+"9 	c #6767A8",
+"0 	c #4949A0",
+"a 	c #7070FB",
+"b 	c #7D7DFF",
+"c 	c #7777FF",
+"d 	c #7373FF",
+"e 	c #7272FF",
+"f 	c #7878FF",
+"g 	c #6465D8",
+"h 	c #363886",
+"i 	c #9F7655",
+"j 	c #C89B5C",
+"k 	c #1D1CB7",
+"l 	c #3031B1",
+"m 	c #1919F4",
+"n 	c #1111FF",
+"o 	c #1818FF",
+"p 	c #1B1BFF",
+"q 	c #1C1CFF",
+"r 	c #2626B3",
+"s 	c #1E1EC8",
+"t 	c #1A1AE8",
+"u 	c #24249F",
+"v 	c #2F2FD2",
+"w 	c #7676FF",
+"x 	c #6869E2",
+"y 	c #414290",
+"z 	c #8C6751",
+"A 	c #FCBA68",
+"B 	c #E9BD7D",
+"C 	c #201EB8",
+"D 	c #090AB8",
+"E 	c #1616EB",
+"F 	c #1818FD",
+"G 	c #1414EE",
+"H 	c #1010E1",
+"I 	c #0E0EE2",
+"J 	c #0E0EF4",
+"K 	c #0606B2",
+"L 	c #7A7A89",
+"M 	c #0C0C9A",
+"N 	c #0A0AA7",
+"O 	c #2424E4",
+"P 	c #6669E6",
+"Q 	c #4F4A8F",
+"R 	c #BF853B",
+"S 	c #FFD98D",
+"T 	c #CDAB76",
+"U 	c #1717C4",
+"V 	c #0F10BA",
+"W 	c #0909B6",
+"X 	c #0505C3",
+"Y 	c #0000B6",
+"Z 	c #0000BE",
+"` 	c #0000AD",
+" .	c #1D1D83",
+"..	c #63638E",
+"+.	c #090975",
+"@.	c #1414F3",
+"#.	c #5B5BFF",
+"$.	c #7B7BFF",
+"%.	c #7070FF",
+"&.	c #6E6EFF",
+"*.	c #7172F6",
+"=.	c #625DAF",
+"-.	c #BA9E6C",
+";.	c #887167",
+">.	c #090DF2",
+",.	c #1313BE",
+"'.	c #000085",
+").	c #0000AC",
+"!.	c #0202AA",
+"~.	c #242488",
+"{.	c #1414C7",
+"].	c #1717FF",
+"^.	c #5959FF",
+"/.	c #7F7FFF",
+"(.	c #7474FF",
+"_.	c #7171FF",
+":.	c #8686FF",
+"<.	c #7574FF",
+"[.	c #797CFF",
+"}.	c #5756B8",
+"|.	c #1C19A4",
+"1.	c #1617FF",
+"2.	c #1212BD",
+"3.	c #040485",
+"4.	c #0707A4",
+"5.	c #1B1B71",
+"6.	c #373797",
+"7.	c #1616FF",
+"8.	c #5050FF",
+"9.	c #8080FF",
+"0.	c #AAAAFF",
+"a.	c #AEAEF6",
+"b.	c #8A8AEF",
+"c.	c #6969FB",
+"d.	c #2728FF",
+"e.	c #1314FF",
+"f.	c #1919FF",
+"g.	c #1313E8",
+"h.	c #1F1FF4",
+"i.	c #5454FF",
+"j.	c #6D6DF0",
+"k.	c #6868B5",
+"l.	c #0B0BB8",
+"m.	c #1212C5",
+"n.	c #1616FC",
+"o.	c #1515FF",
+"p.	c #1212FF",
+"q.	c #2323FF",
+"r.	c #3636FF",
+"s.	c #4040FF",
+"t.	c #4343F9",
+"u.	c #5D5DB8",
+"v.	c #7F7F92",
+"w.	c #878793",
+"x.	c #4B4B94",
+"y.	c #0B0CE2",
+"z.	c #1313FF",
+"A.	c #4C4CFF",
+"B.	c #8282FF",
+"C.	c #7171ED",
+"D.	c #636394",
+"E.	c #575785",
+"F.	c #A9A99C",
+"G.	c #1414BC",
+"H.	c #1414FF",
+"I.	c #0707FD",
+"J.	c #2525AA",
+"K.	c #A8A8A4",
+"L.	c #EBEBE2",
+"M.	c #F9F9F2",
+"N.	c #E1E1CC",
+"O.	c #4D4D9F",
+"P.	c #0B0BF7",
+"Q.	c #2121FF",
+"R.	c #3232FF",
+"S.	c #5555FF",
+"T.	c #6161B4",
+"U.	c #B5B5B2",
+"V.	c #FFFFF8",
+"W.	c #4F4F9A",
+"X.	c #0B0BF5",
+"Y.	c #1616C5",
+"Z.	c #A8A8A1",
+"`.	c #FFFFFC",
+" +	c #FFFFFF",
+".+	c #C0C0C4",
+"++	c #1212D4",
+"@+	c #4444FF",
+"#+	c #6464FF",
+"$+	c #8383FF",
+"%+	c #6767C3",
+"&+	c #E4E4E4",
+"*+	c #9494AE",
+"=+	c #0808DF",
+"-+	c #0D0DF2",
+";+	c #61619A",
+">+	c #F1F1E0",
+",+	c #E8E8DD",
+"'+	c #2424BB",
+")+	c #1010FF",
+"!+	c #3434FF",
+"~+	c #6161FF",
+"{+	c #6969D2",
+"]+	c #EFEFF0",
+"^+	c #C2C2BA",
+"/+	c #1010B6",
+"(+	c #0909AC",
+"_+	c #A4A49A",
+":+	c #EAEADE",
+"<+	c #2525B8",
+"[+	c #2F2FFF",
+"}+	c #3C3CB5",
+"|+	c #EEEEEE",
+"1+	c #BBBBAD",
+"2+	c #0B0B56",
+"3+	c #0B0BFC",
+"4+	c #1212EF",
+"5+	c #0C0C3E",
+"6+	c #919187",
+"7+	c #DEDED6",
+"8+	c #1F1FC0",
+"9+	c #1A1AFF",
+"0+	c #1717FA",
+"a+	c #1515F8",
+"b+	c #1111FC",
+"c+	c #494992",
+"d+	c #999998",
+"e+	c #3E3E3B",
+"f+	c #3C3C99",
+"g+	c #535397",
+"h+	c #5A5A4D",
+"i+	c #6F6F70",
+"j+	c #BFBFC9",
+"k+	c #1111D6",
+"l+	c #1515F1",
+"m+	c #0F0FE2",
+"n+	c #0D0DD9",
+"o+	c #0909CD",
+"p+	c #0808C7",
+"q+	c #0505C7",
+"r+	c #0303CB",
+"s+	c #0101C0",
+"t+	c #0202AF",
+"u+	c #0606AC",
+"v+	c #121283",
+"w+	c #BBBBBB",
+"x+	c #BEBEBE",
+"y+	c #2F2F2E",
+"z+	c #C7C8BB",
+"A+	c #D8DAD1",
+"B+	c #272828",
+"C+	c #929292",
+"D+	c #8688C7",
+"E+	c #0506F6",
+"F+	c #1616F5",
+"G+	c #0B0BD3",
+"H+	c #0202B6",
+"I+	c #0000AF",
+"J+	c #0000B4",
+"K+	c #0000BD",
+"L+	c #0000BB",
+"M+	c #00009E",
+"N+	c #2C2C7E",
+"O+	c #6A6A8B",
+"P+	c #959595",
+"Q+	c #F0F0F1",
+"R+	c #E1E1E1",
+"S+	c #8C8E90",
+"T+	c #BEBEBF",
+"U+	c #C9C7C5",
+"V+	c #939699",
+"W+	c #E7EAED",
+"X+	c #CBCBC7",
+"Y+	c #413B9B",
+"Z+	c #0607DD",
+"`+	c #0C0CE2",
+" @	c #0303B9",
+".@	c #0000A8",
+"+@	c #181888",
+"@@	c #6A6A6A",
+"#@	c #626263",
+"$@	c #4B4B4C",
+"%@	c #3E3B36",
+"&@	c #9B805C",
+"*@	c #D9B07D",
+"=@	c #C9AE89",
+"-@	c #B9AF9E",
+";@	c #C7C5C4",
+">@	c #CBCCCF",
+",@	c #C7C6C6",
+"'@	c #AEA59A",
+")@	c #B69974",
+"!@	c #D8B87F",
+"~@	c #9B8272",
+"{@	c #0E0B9B",
+"]@	c #0000B7",
+"^@	c #0000B8",
+"/@	c #000082",
+"(@	c #00007A",
+"_@	c #636379",
+":@	c #62533E",
+"<@	c #B59B6C",
+"[@	c #DEB07B",
+"}@	c #FECC90",
+"|@	c #FFCE92",
+"1@	c #FEC98C",
+"2@	c #F1BD82",
+"3@	c #D1A979",
+"4@	c #BC9E73",
+"5@	c #CCA777",
+"6@	c #EAB980",
+"7@	c #FFCD90",
+"8@	c #FFD595",
+"9@	c #FDD782",
+"0@	c #413678",
+"a@	c #0000AE",
+"b@	c #000077",
+"c@	c #010193",
+"d@	c #0C0CE4",
+"e@	c #38389E",
+"f@	c #EEC585",
+"g@	c #FFDA9D",
+"h@	c #FFC992",
+"i@	c #FFC88F",
+"j@	c #FFC990",
+"k@	c #FFCE93",
+"l@	c #FFD094",
+"m@	c #FFCC92",
+"n@	c #C9A174",
+"o@	c #EDBD88",
+"p@	c #FAD287",
+"q@	c #3A2F7F",
+"r@	c #0000BA",
+"s@	c #0000B0",
+"t@	c #0101B2",
+"u@	c #1111ED",
+"v@	c #1919C1",
+"w@	c #95887C",
+"x@	c #DCAC6E",
+"y@	c #FFD393",
+"z@	c #FFCD94",
+"A@	c #FFCA93",
+"B@	c #FFC991",
+"C@	c #FFC78E",
+"D@	c #FFCB91",
+"E@	c #E0B581",
+"F@	c #BB9A6F",
+"G@	c #FFDC97",
+"H@	c #C1A173",
+"I@	c #0E0B9A",
+"J@	c #0000B5",
+"K@	c #0101B6",
+"L@	c #1010E0",
+"M@	c #1616EC",
+"N@	c #A68156",
+"O@	c #E7AC6B",
+"P@	c #FFC582",
+"Q@	c #FFCF8F",
+"R@	c #FFD195",
+"S@	c #FFD296",
+"T@	c #FFD396",
+"U@	c #FFD193",
+"V@	c #FFD28F",
+"W@	c #D2A96B",
+"X@	c #2F2482",
+"Y@	c #0000C1",
+"Z@	c #0000C0",
+"`@	c #0000BF",
+" #	c #0101BF",
+".#	c #1212F0",
+"+#	c #767698",
+"@#	c #9C866E",
+"##	c #A9865D",
+"$#	c #C0915D",
+"%#	c #C89760",
+"&#	c #C29360",
+"*#	c #AD8A61",
+"=#	c #9D8971",
+"-#	c #7F7A7A",
+";#	c #70708F",
+">#	c #6F6F91",
+",#	c #575788",
+"'#	c #464687",
+")#	c #2F2F87",
+"!#	c #15158F",
+"~#	c #0101A8",
+"{#	c #1313FB",
+"]#	c #57579F",
+"^#	c #343487",
+"/#	c #434388",
+"                                                                ",
+"                                                                ",
+"                                                                ",
+"                              . + @ #                           ",
+"                      $ % & * = - ; > , ' ) !                   ",
+"      ~ {       ] ^ / = ( _ : < [ } | 1 2 3 4 5 6               ",
+"      7 8 9   0 a b c d e f g h i j k l m n o p q r             ",
+"      s t u v _ f d d d w x y z A B C D E F G H I J K L         ",
+"      M N O _ c e d d d _ P Q R S T U V W X Y Z `  ...          ",
+"      +.@.#.$.d d d d %.&._ *.=.-.;.>.,.'.).!.~.                ",
+"      {.].^./.(.d d _.$.:._ <.[.}.|.1.2.3.4.5.                  ",
+"    6.7.7.4 8.e : w 9.0.a.b.c.2 d.e.f.g.h.i.j.k.                ",
+"    l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.o o z.A.B./.b C.D.            ",
+"    E.F.G.].o H.z.I.J.K.L.M.N.O.P.o o o Q.R.S._.b B.T.          ",
+"    U.V.W.X.f.f.7.Y.Z.`. + + +.+++].o o o.n z.q.@+#+$+%+        ",
+"    &+ +*+=+].o -+;+>+ + + + +,+'+H.o o o o o H.)+o !+~+{+      ",
+"    ]+ +^+/+H.o.(+_+ + + + + +:+<+z.o o o o o o o 7.n H.[+}+    ",
+"    |+ +1+2+3+4+5+6+ + + + + +7+8+H.o o f.9+f.9+f.F 0+a+b+o.c+  ",
+"    &+ +d+e+f+g+h+i+ + + + + +j+k+].f.9+l+m+n+o+p+q+r+s+t+u+v+  ",
+"    w+ +x+y+z+A+B+C+ + + + + +D+E+9+F+G+H+I+J+K+L+M+N+O+        ",
+"    P+Q+R+S+T+U+V+W+ + + + +X+Y+Z+`+ @I+J+Z .@+@E.              ",
+"    @@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@I+/@(@_@                ",
+"      :@<@[@}@|@1@2@3@4@5@6@7@8@9@0@L+a@b@c@d@e@                ",
+"        f@g@h@i@i@j@k@l@|@m@n@o@p@q@r@s@t@u@p v@                ",
+"        w@x@y@z@A@B@i@C@D@E@F@G@H@I@L+J@K@L@p M@                ",
+"            N@O@P@Q@R@S@T@U@V@W@X@Y@Z@Y@`@ #.#p +#              ",
+"                @###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#              ",
+"                                              ^#/#              ",
+"                                                                ",
+"                                                                ",
+"                                                                ",
+"                                                                "};
diff --git a/src/sdl/Srb2SDL.ico b/src/sdl/Srb2SDL.ico
index 5ab791af37f815c0164e6053c34879ecf0c3fff0..700276fd4b9ac2810a6981eb054921f3708c702b 100644
Binary files a/src/sdl/Srb2SDL.ico and b/src/sdl/Srb2SDL.ico differ
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index fa09dc343cdea0e5e054a0dc6c6a2b102d58b429..66e1ece1863887f21f6b07678542da6fde715b75 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -2759,8 +2759,8 @@ static const char *locateWad(void)
 	if (isWadPathOk(returnWadPath))
 		return NULL;
 #endif
-    
-    
+
+
 #ifdef CMAKECONFIG
 #ifndef NDEBUG
     I_OutputMsg(","CMAKE_ASSETS_DIR);
@@ -2771,7 +2771,7 @@ static const char *locateWad(void)
     }
 #endif
 #endif
-    
+
 #ifdef __APPLE__
     OSX_GetResourcesPath(returnWadPath);
     I_OutputMsg(",%s", returnWadPath);
@@ -2779,7 +2779,7 @@ static const char *locateWad(void)
     {
         return returnWadPath;
     }
-    
+
 #endif
 
 	// examine default dirs
diff --git a/src/sdl12/SDL_icon.xpm b/src/sdl12/SDL_icon.xpm
index 70bb02d3c97a0ffe37a5e890c4736386779bcbb1..cf72960dfc9048d1ab23b3c59ed4d29d65f4c404 100644
--- a/src/sdl12/SDL_icon.xpm
+++ b/src/sdl12/SDL_icon.xpm
@@ -1,80 +1,425 @@
 /* XPM */
-static const char * SDL_icon_xpm[] = {
-"32 32 45 1",
-" 	c None",
-".	c #6B6BFF",
-"+	c #3D00B9",
-"@	c #4848FF",
-"#	c #2525FF",
-"$	c #310096",
-"%	c #003196",
-"&	c #003DB9",
-"*	c #620096",
-"=	c #6E6E6E",
-"-	c #966200",
-";	c #250073",
-">	c #626262",
-",	c #FF8F6B",
-"'	c #FFC66B",
-")	c #FFAB8E",
-"!	c #000080",
-"~	c #B6B6B6",
-"{	c #929292",
-"]	c #FFD48E",
-"^	c #0000B9",
-"/	c #565656",
-"(	c #868686",
-"_	c #808080",
-":	c #C0C0C0",
-"<	c #DADADA",
-"[	c #F2F2F2",
-"}	c #FFFFFF",
-"|	c #CECECE",
-"1	c #AAAAAA",
-"2	c #E6E6E6",
-"3	c #000096",
-"4	c #AB8EFF",
-"5	c #190050",
-"6	c #000000",
-"7	c #8E8EFF",
-"8	c #3E3E3E",
-"9	c #7A7A7A",
-"0	c #0E0E0E",
-"a	c #9E9E9E",
-"b	c #001950",
-"c	c #C2C2C2",
-"d	c #323232",
-"e	c #002573",
-"f	c #A0A0A4",
-"                                ",
-"                                ",
-"                                ",
-"             .+@##@.            ",
-"           @@.@#######@         ",
-"         @@....#########        ",
-" ..    .@.....@+##$%%%&&%       ",
-" ..@# @@....@+#*=-;%%%%%        ",
-"  ..@#@......@>,')!%%%$         ",
-" ~..$#.........{])^#+%/         ",
-"   +##@.........()^@@@@@_       ",
-"  $####@........#=#######+      ",
-"  +######....@@##^#########_    ",
-"  +#####=:<<:+##############/   ",
-"[<=####{<}}}}|###############=  ",
-" }1###=2}}}}}}.###############  ",
-" }<3#3~}}}}}}}4################ ",
-" }<5#6:}}}}}}}7################/",
-" }:6861}}}}}}}.########$$ 9  .@$",
-" }:0a6~}}}}}}}@######5b         ",
-"22cd262}}}}}}2######5b$         ",
-"  2>1a}}}}}}}{(*###%be##        ",
-"  860)1<[22c1)]]+##be###        ",
-"  ~)]]]))))]]]]]=#bb####        ",
-"   )]]]]]]]]](]]=eb$####        ",
-"    :]]]]]]]]]'9bbb$#####       ",
-"      ),'''''(    >db+###       ",
-"                      =##f      ",
-"                        {       ",
-"                                ",
-"                                ",
-"                                "};
+static char * C:\Repo\srb2\src\sdl\SDL_icon_xpm[] = {
+"32 32 390 2",
+"  	c None",
+". 	c #4F4F70",
+"+ 	c #4D4D87",
+"@ 	c #4D4D84",
+"# 	c #4E4E6C",
+"$ 	c #6C6C95",
+"% 	c #5E5EB2",
+"& 	c #6B6BE7",
+"* 	c #7373F9",
+"= 	c #7C7CFF",
+"- 	c #6F70E7",
+"; 	c #494BB2",
+"> 	c #4F4FA3",
+", 	c #6464D4",
+"' 	c #7979F5",
+") 	c #5F5FCA",
+"! 	c #5D5D93",
+"~ 	c #3A3A9F",
+"{ 	c #6060AC",
+"] 	c #777793",
+"^ 	c #5C5CB3",
+"/ 	c #7373EA",
+"( 	c #7A7AFF",
+"_ 	c #7575FF",
+": 	c #7979FF",
+"< 	c #6264DD",
+"[ 	c #47478C",
+"} 	c #564567",
+"| 	c #4647D0",
+"1 	c #5C5CAE",
+"2 	c #5E5EFF",
+"3 	c #2929FF",
+"4 	c #1D1DFF",
+"5 	c #1919D1",
+"6 	c #4F4F90",
+"7 	c #1E1ECE",
+"8 	c #5858FF",
+"9 	c #6767A8",
+"0 	c #4949A0",
+"a 	c #7070FB",
+"b 	c #7D7DFF",
+"c 	c #7777FF",
+"d 	c #7373FF",
+"e 	c #7272FF",
+"f 	c #7878FF",
+"g 	c #6465D8",
+"h 	c #363886",
+"i 	c #9F7655",
+"j 	c #C89B5C",
+"k 	c #1D1CB7",
+"l 	c #3031B1",
+"m 	c #1919F4",
+"n 	c #1111FF",
+"o 	c #1818FF",
+"p 	c #1B1BFF",
+"q 	c #1C1CFF",
+"r 	c #2626B3",
+"s 	c #1E1EC8",
+"t 	c #1A1AE8",
+"u 	c #24249F",
+"v 	c #2F2FD2",
+"w 	c #7676FF",
+"x 	c #6869E2",
+"y 	c #414290",
+"z 	c #8C6751",
+"A 	c #FCBA68",
+"B 	c #E9BD7D",
+"C 	c #201EB8",
+"D 	c #090AB8",
+"E 	c #1616EB",
+"F 	c #1818FD",
+"G 	c #1414EE",
+"H 	c #1010E1",
+"I 	c #0E0EE2",
+"J 	c #0E0EF4",
+"K 	c #0606B2",
+"L 	c #7A7A89",
+"M 	c #0C0C9A",
+"N 	c #0A0AA7",
+"O 	c #2424E4",
+"P 	c #6669E6",
+"Q 	c #4F4A8F",
+"R 	c #BF853B",
+"S 	c #FFD98D",
+"T 	c #CDAB76",
+"U 	c #1717C4",
+"V 	c #0F10BA",
+"W 	c #0909B6",
+"X 	c #0505C3",
+"Y 	c #0000B6",
+"Z 	c #0000BE",
+"` 	c #0000AD",
+" .	c #1D1D83",
+"..	c #63638E",
+"+.	c #090975",
+"@.	c #1414F3",
+"#.	c #5B5BFF",
+"$.	c #7B7BFF",
+"%.	c #7070FF",
+"&.	c #6E6EFF",
+"*.	c #7172F6",
+"=.	c #625DAF",
+"-.	c #BA9E6C",
+";.	c #887167",
+">.	c #090DF2",
+",.	c #1313BE",
+"'.	c #000085",
+").	c #0000AC",
+"!.	c #0202AA",
+"~.	c #242488",
+"{.	c #1414C7",
+"].	c #1717FF",
+"^.	c #5959FF",
+"/.	c #7F7FFF",
+"(.	c #7474FF",
+"_.	c #7171FF",
+":.	c #8686FF",
+"<.	c #7574FF",
+"[.	c #797CFF",
+"}.	c #5756B8",
+"|.	c #1C19A4",
+"1.	c #1617FF",
+"2.	c #1212BD",
+"3.	c #040485",
+"4.	c #0707A4",
+"5.	c #1B1B71",
+"6.	c #373797",
+"7.	c #1616FF",
+"8.	c #5050FF",
+"9.	c #8080FF",
+"0.	c #AAAAFF",
+"a.	c #AEAEF6",
+"b.	c #8A8AEF",
+"c.	c #6969FB",
+"d.	c #2728FF",
+"e.	c #1314FF",
+"f.	c #1919FF",
+"g.	c #1313E8",
+"h.	c #1F1FF4",
+"i.	c #5454FF",
+"j.	c #6D6DF0",
+"k.	c #6868B5",
+"l.	c #0B0BB8",
+"m.	c #1212C5",
+"n.	c #1616FC",
+"o.	c #1515FF",
+"p.	c #1212FF",
+"q.	c #2323FF",
+"r.	c #3636FF",
+"s.	c #4040FF",
+"t.	c #4343F9",
+"u.	c #5D5DB8",
+"v.	c #7F7F92",
+"w.	c #878793",
+"x.	c #4B4B94",
+"y.	c #0B0CE2",
+"z.	c #1313FF",
+"A.	c #4C4CFF",
+"B.	c #8282FF",
+"C.	c #7171ED",
+"D.	c #636394",
+"E.	c #575785",
+"F.	c #A9A99C",
+"G.	c #1414BC",
+"H.	c #1414FF",
+"I.	c #0707FD",
+"J.	c #2525AA",
+"K.	c #A8A8A4",
+"L.	c #EBEBE2",
+"M.	c #F9F9F2",
+"N.	c #E1E1CC",
+"O.	c #4D4D9F",
+"P.	c #0B0BF7",
+"Q.	c #2121FF",
+"R.	c #3232FF",
+"S.	c #5555FF",
+"T.	c #6161B4",
+"U.	c #B5B5B2",
+"V.	c #FFFFF8",
+"W.	c #4F4F9A",
+"X.	c #0B0BF5",
+"Y.	c #1616C5",
+"Z.	c #A8A8A1",
+"`.	c #FFFFFC",
+" +	c #FFFFFF",
+".+	c #C0C0C4",
+"++	c #1212D4",
+"@+	c #4444FF",
+"#+	c #6464FF",
+"$+	c #8383FF",
+"%+	c #6767C3",
+"&+	c #E4E4E4",
+"*+	c #9494AE",
+"=+	c #0808DF",
+"-+	c #0D0DF2",
+";+	c #61619A",
+">+	c #F1F1E0",
+",+	c #E8E8DD",
+"'+	c #2424BB",
+")+	c #1010FF",
+"!+	c #3434FF",
+"~+	c #6161FF",
+"{+	c #6969D2",
+"]+	c #EFEFF0",
+"^+	c #C2C2BA",
+"/+	c #1010B6",
+"(+	c #0909AC",
+"_+	c #A4A49A",
+":+	c #EAEADE",
+"<+	c #2525B8",
+"[+	c #2F2FFF",
+"}+	c #3C3CB5",
+"|+	c #EEEEEE",
+"1+	c #BBBBAD",
+"2+	c #0B0B56",
+"3+	c #0B0BFC",
+"4+	c #1212EF",
+"5+	c #0C0C3E",
+"6+	c #919187",
+"7+	c #DEDED6",
+"8+	c #1F1FC0",
+"9+	c #1A1AFF",
+"0+	c #1717FA",
+"a+	c #1515F8",
+"b+	c #1111FC",
+"c+	c #494992",
+"d+	c #999998",
+"e+	c #3E3E3B",
+"f+	c #3C3C99",
+"g+	c #535397",
+"h+	c #5A5A4D",
+"i+	c #6F6F70",
+"j+	c #BFBFC9",
+"k+	c #1111D6",
+"l+	c #1515F1",
+"m+	c #0F0FE2",
+"n+	c #0D0DD9",
+"o+	c #0909CD",
+"p+	c #0808C7",
+"q+	c #0505C7",
+"r+	c #0303CB",
+"s+	c #0101C0",
+"t+	c #0202AF",
+"u+	c #0606AC",
+"v+	c #121283",
+"w+	c #BBBBBB",
+"x+	c #BEBEBE",
+"y+	c #2F2F2E",
+"z+	c #C7C8BB",
+"A+	c #D8DAD1",
+"B+	c #272828",
+"C+	c #929292",
+"D+	c #8688C7",
+"E+	c #0506F6",
+"F+	c #1616F5",
+"G+	c #0B0BD3",
+"H+	c #0202B6",
+"I+	c #0000AF",
+"J+	c #0000B4",
+"K+	c #0000BD",
+"L+	c #0000BB",
+"M+	c #00009E",
+"N+	c #2C2C7E",
+"O+	c #6A6A8B",
+"P+	c #959595",
+"Q+	c #F0F0F1",
+"R+	c #E1E1E1",
+"S+	c #8C8E90",
+"T+	c #BEBEBF",
+"U+	c #C9C7C5",
+"V+	c #939699",
+"W+	c #E7EAED",
+"X+	c #CBCBC7",
+"Y+	c #413B9B",
+"Z+	c #0607DD",
+"`+	c #0C0CE2",
+" @	c #0303B9",
+".@	c #0000A8",
+"+@	c #181888",
+"@@	c #6A6A6A",
+"#@	c #626263",
+"$@	c #4B4B4C",
+"%@	c #3E3B36",
+"&@	c #9B805C",
+"*@	c #D9B07D",
+"=@	c #C9AE89",
+"-@	c #B9AF9E",
+";@	c #C7C5C4",
+">@	c #CBCCCF",
+",@	c #C7C6C6",
+"'@	c #AEA59A",
+")@	c #B69974",
+"!@	c #D8B87F",
+"~@	c #9B8272",
+"{@	c #0E0B9B",
+"]@	c #0000B7",
+"^@	c #0000B8",
+"/@	c #000082",
+"(@	c #00007A",
+"_@	c #636379",
+":@	c #62533E",
+"<@	c #B59B6C",
+"[@	c #DEB07B",
+"}@	c #FECC90",
+"|@	c #FFCE92",
+"1@	c #FEC98C",
+"2@	c #F1BD82",
+"3@	c #D1A979",
+"4@	c #BC9E73",
+"5@	c #CCA777",
+"6@	c #EAB980",
+"7@	c #FFCD90",
+"8@	c #FFD595",
+"9@	c #FDD782",
+"0@	c #413678",
+"a@	c #0000AE",
+"b@	c #000077",
+"c@	c #010193",
+"d@	c #0C0CE4",
+"e@	c #38389E",
+"f@	c #EEC585",
+"g@	c #FFDA9D",
+"h@	c #FFC992",
+"i@	c #FFC88F",
+"j@	c #FFC990",
+"k@	c #FFCE93",
+"l@	c #FFD094",
+"m@	c #FFCC92",
+"n@	c #C9A174",
+"o@	c #EDBD88",
+"p@	c #FAD287",
+"q@	c #3A2F7F",
+"r@	c #0000BA",
+"s@	c #0000B0",
+"t@	c #0101B2",
+"u@	c #1111ED",
+"v@	c #1919C1",
+"w@	c #95887C",
+"x@	c #DCAC6E",
+"y@	c #FFD393",
+"z@	c #FFCD94",
+"A@	c #FFCA93",
+"B@	c #FFC991",
+"C@	c #FFC78E",
+"D@	c #FFCB91",
+"E@	c #E0B581",
+"F@	c #BB9A6F",
+"G@	c #FFDC97",
+"H@	c #C1A173",
+"I@	c #0E0B9A",
+"J@	c #0000B5",
+"K@	c #0101B6",
+"L@	c #1010E0",
+"M@	c #1616EC",
+"N@	c #A68156",
+"O@	c #E7AC6B",
+"P@	c #FFC582",
+"Q@	c #FFCF8F",
+"R@	c #FFD195",
+"S@	c #FFD296",
+"T@	c #FFD396",
+"U@	c #FFD193",
+"V@	c #FFD28F",
+"W@	c #D2A96B",
+"X@	c #2F2482",
+"Y@	c #0000C1",
+"Z@	c #0000C0",
+"`@	c #0000BF",
+" #	c #0101BF",
+".#	c #1212F0",
+"+#	c #767698",
+"@#	c #9C866E",
+"##	c #A9865D",
+"$#	c #C0915D",
+"%#	c #C89760",
+"&#	c #C29360",
+"*#	c #AD8A61",
+"=#	c #9D8971",
+"-#	c #7F7A7A",
+";#	c #70708F",
+">#	c #6F6F91",
+",#	c #575788",
+"'#	c #464687",
+")#	c #2F2F87",
+"!#	c #15158F",
+"~#	c #0101A8",
+"{#	c #1313FB",
+"]#	c #57579F",
+"^#	c #343487",
+"/#	c #434388",
+"                                                                ",
+"                                                                ",
+"                                                                ",
+"                              . + @ #                           ",
+"                      $ % & * = - ; > , ' ) !                   ",
+"      ~ {       ] ^ / = ( _ : < [ } | 1 2 3 4 5 6               ",
+"      7 8 9   0 a b c d e f g h i j k l m n o p q r             ",
+"      s t u v _ f d d d w x y z A B C D E F G H I J K L         ",
+"      M N O _ c e d d d _ P Q R S T U V W X Y Z `  ...          ",
+"      +.@.#.$.d d d d %.&._ *.=.-.;.>.,.'.).!.~.                ",
+"      {.].^./.(.d d _.$.:._ <.[.}.|.1.2.3.4.5.                  ",
+"    6.7.7.4 8.e : w 9.0.a.b.c.2 d.e.f.g.h.i.j.k.                ",
+"    l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.o o z.A.B./.b C.D.            ",
+"    E.F.G.].o H.z.I.J.K.L.M.N.O.P.o o o Q.R.S._.b B.T.          ",
+"    U.V.W.X.f.f.7.Y.Z.`. + + +.+++].o o o.n z.q.@+#+$+%+        ",
+"    &+ +*+=+].o -+;+>+ + + + +,+'+H.o o o o o H.)+o !+~+{+      ",
+"    ]+ +^+/+H.o.(+_+ + + + + +:+<+z.o o o o o o o 7.n H.[+}+    ",
+"    |+ +1+2+3+4+5+6+ + + + + +7+8+H.o o f.9+f.9+f.F 0+a+b+o.c+  ",
+"    &+ +d+e+f+g+h+i+ + + + + +j+k+].f.9+l+m+n+o+p+q+r+s+t+u+v+  ",
+"    w+ +x+y+z+A+B+C+ + + + + +D+E+9+F+G+H+I+J+K+L+M+N+O+        ",
+"    P+Q+R+S+T+U+V+W+ + + + +X+Y+Z+`+ @I+J+Z .@+@E.              ",
+"    @@#@$@%@&@*@=@-@;@>@,@'@)@!@~@{@]@^@I+/@(@_@                ",
+"      :@<@[@}@|@1@2@3@4@5@6@7@8@9@0@L+a@b@c@d@e@                ",
+"        f@g@h@i@i@j@k@l@|@m@n@o@p@q@r@s@t@u@p v@                ",
+"        w@x@y@z@A@B@i@C@D@E@F@G@H@I@L+J@K@L@p M@                ",
+"            N@O@P@Q@R@S@T@U@V@W@X@Y@Z@Y@`@ #.#p +#              ",
+"                @###$#%#&#*#=#-#;#>#,#'#)#!#~#{#]#              ",
+"                                              ^#/#              ",
+"                                                                ",
+"                                                                ",
+"                                                                ",
+"                                                                "};
diff --git a/src/sdl12/Srb2SDL.ico b/src/sdl12/Srb2SDL.ico
index 5ab791af37f815c0164e6053c34879ecf0c3fff0..700276fd4b9ac2810a6981eb054921f3708c702b 100644
Binary files a/src/sdl12/Srb2SDL.ico and b/src/sdl12/Srb2SDL.ico differ
diff --git a/src/st_stuff.c b/src/st_stuff.c
index a9bdacf7152f3a7683345ccd2ece8c0ed1b3e523..6e19b92ff05a3fe436c4e7ab5010ecb942ec12cf 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -1590,7 +1590,7 @@ static void ST_drawSpecialStageHUD(void)
 	if (sstimer)
 	{
 		V_DrawString(hudinfo[HUD_TIMELEFT].x, STRINGY(hudinfo[HUD_TIMELEFT].y), V_HUDTRANS, M_GetText("TIME LEFT"));
-		ST_DrawNightsOverlayNum(SCX(hudinfo[HUD_TIMELEFTNUM].x), SCY(hudinfo[HUD_TIMELEFTNUM].y), V_HUDTRANS, sstimer/TICRATE, tallnum, SKINCOLOR_WHITE);
+		ST_DrawNumFromHud(HUD_TIMELEFTNUM, sstimer/TICRATE);
 	}
 	else
 		ST_DrawPatchFromHud(HUD_TIMEUP, timeup);
diff --git a/src/tables.c b/src/tables.c
index fa71effef44bd50761014a2db52580f672421f56..3ee2685c893117a419cc7bcc073f0b4d9e85af03 100644
--- a/src/tables.c
+++ b/src/tables.c
@@ -2226,7 +2226,7 @@ angle_t tantoangle[2049] =
 };
 
 
-#ifdef NEED_FIXED_VECTOR
+#if 1 //#ifdef NEED_FIXED_VECTOR
 
 static angle_t fineacon[65536*2] = {
 	  ANGLE_MAX, 2143707442, 2142143280, 2140943052, 2139931208, 2139039753, 2138233813, 2137492672, 2136802831, 2136154917, 2135542102, 2134959233, 2134402306, 2133868139, 2133354148, 2132858208,
diff --git a/src/tables.h b/src/tables.h
index 219d668b9dac5bb01af79de80adb7d5106de78bc..b1de1a428cae1a032bf3bf0652c10f9562266187 100644
--- a/src/tables.h
+++ b/src/tables.h
@@ -97,7 +97,7 @@ FUNCMATH angle_t FixedAngle(fixed_t fa);
 FUNCMATH angle_t FixedAngleC(fixed_t fa, fixed_t factor);
 
 
-#ifdef NEED_FIXED_VECTOR
+#if 1 //#ifdef NEED_FIXED_VECTOR
 
 /// The FixedAcos function
 FUNCMATH angle_t FixedAcos(fixed_t x);
diff --git a/src/w_wad.c b/src/w_wad.c
index 79ed1f478b67741dd625418e10ef1ece6813c556..9d6a11fb5c9f863def81c261a5893aa4aded98a8 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -413,6 +413,7 @@ UINT16 W_LoadWadFile(const char *filename)
 				lump_p->disksize -= 4;
 			}
 			else lump_p->compressed = 0;
+			memset(lump_p->name, 0x00, 9);
 			strncpy(lump_p->name, fileinfo->name, 8);
 		}
 		free(fileinfov);
diff --git a/src/win32/CMakeLists.txt b/src/win32/CMakeLists.txt
index 94c198299add6162c63a69324207ba048d73cf01..39b01588b28c622a65f40ea63f9b2e541df220ec 100644
--- a/src/win32/CMakeLists.txt
+++ b/src/win32/CMakeLists.txt
@@ -1,11 +1,18 @@
-add_executable(${SRB2_WIN_EXE_NAME} EXCLUDE_FROM_ALL
-	${SRB2_CORE_SOURCES}
-	${SRB2_CORE_HEADERS}
-	${SRB2_LUA_SOURCES}
-	${SRB2_LUA_HEADERS}
-	${SRB2_BLUA_SOURCES}
-	${SRB2_BLUA_HEADERS})
-
-target_compile_definitions(${SRB2_WIN_EXE_NAME} PRIVATE
+file(GLOB SRB2_WIN_SOURCES *.c *.h *.rc)
+
+if(${SRB2_CONFIG_HWRENDER})
+	set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_HWRENDER_SOURCES} ${SRB2_HWRENDER_HEADERS})
+	set(SRB2_WIN_SOURCES ${SRB2_WIN_SOURCES} ${SRB2_R_OPENGL_SOURCES} ${SRB2_R_OPENGL_HEADERS})
+endif()
+
+add_executable(SRB2DD EXCLUDE_FROM_ALL WIN32
+	${SRB2_WIN_SOURCES}
+)
+
+target_compile_definitions(SRB2DD PRIVATE
 	-D_WINDOWS
-)
\ No newline at end of file
+)
+
+set_target_properties(SRB2DD PROPERTIES OUTPUT_NAME ${SRB2_WIN_EXE_NAME})
+
+target_link_libraries(SRB2DD PRIVATE SRB2Core)
diff --git a/src/win32/Srb2win.ico b/src/win32/Srb2win.ico
index e369735effcaec2be38a084c3ce7e89b94c9ee86..700276fd4b9ac2810a6981eb054921f3708c702b 100644
Binary files a/src/win32/Srb2win.ico and b/src/win32/Srb2win.ico differ
diff --git a/src/win32ce/Srb2win.ico b/src/win32ce/Srb2win.ico
index 0036a827a4625745397da1631e48101879a4f212..700276fd4b9ac2810a6981eb054921f3708c702b 100644
Binary files a/src/win32ce/Srb2win.ico and b/src/win32ce/Srb2win.ico differ