diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b5c43d0173b257c65622f434c7c82d4d80304526
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,63 @@
+version: 2
+jobs:
+  build:
+    working_directory: /root/SRB2
+    docker:
+      - image: debian:jessie
+        environment:
+          CC: ccache gcc -m32
+          PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
+          LIBGME_CFLAGS: -I/usr/include
+          LIBGME_LDFLAGS: -lgme
+          CCACHE_COMPRESS: true
+          WFLAGS: -Wno-unsuffixed-float-constants
+          GCC49: true
+      #- image: ubuntu:trusty
+      #  environment:
+      #    CC: ccache gcc -m32
+      #    PKG_CONFIG_LIBDIR: /usr/lib/i386-linux-gnu/pkgconfig
+      #    LIBGME_CFLAGS: -I/usr/include
+      #    LIBGME_LDFLAGS: -lgme
+      #    CCACHE_COMPRESS: true
+      #    WFLAGS: -Wno-unsuffixed-float-constants
+      #    GCC48: true
+    steps:
+      - run:
+          name: Add i386 arch
+          command: dpkg --add-architecture i386
+      - run:
+          name: Update APT listing
+          command: apt-get -qq update
+      - run:
+          name: Support S3 upload
+          command: apt-get -qq -y install ca-certificates
+      - restore_cache:
+          keys:
+            - v1-SRB2-APT
+      - run:
+          name: Install SDK
+          command: apt-get -qq -y install git build-essential nasm libpng12-dev:i386 libsdl2-mixer-dev:i386 libgme-dev:i386 gettext ccache wget gcc-multilib upx
+      - save_cache:
+          key: v1-SRB2-APT
+          paths:
+            - /var/cache/apt/archives
+      - checkout
+      - run:
+          name: Clean build
+          command: make -C src LINUX=1 clean
+      - restore_cache:
+          keys:
+            - v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
+      - run:
+          name: Compile
+          command: make -C src LINUX=1 ERRORMODE=1 -k
+      - store_artifacts:
+          path: /root/SRB2/bin/Linux/Release/
+          destination: bin
+      - save_cache:
+          key: v1-SRB2-{{ .Branch }}-{{ checksum "objs/Linux/SDL/Release/depend.dep" }}
+          paths:
+            - /root/.ccache
+
+
+
diff --git a/.travis.yml b/.travis.yml
index e3408cf6f1d28b1615a7aa4fde68349d8677f9aa..e5dbb58e42fedffc63db2ef06cd851b3cdac495e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -98,7 +98,7 @@ matrix:
               - p7zip-full
               - gcc-6
           compiler: gcc-6
-          env: WFLAGS="-Wno-error=tautological-compare"
+          env: WFLAGS="-Wno-tautological-compare"
           #gcc-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511
         - os: linux
           compiler: clang
@@ -162,28 +162,28 @@ matrix:
               - clang-3.8
           compiler: clang-3.8
           #clang version 3.8.1-svn271127-1~exp1 (branches/release_38)
-        - os: osx
-          osx_image: beta-xcode6.1
-          #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
-        - os: osx
-          osx_image: beta-xcode6.2
-          compiler: gcc
-          #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
 #        - os: osx
-#          osx_image: beta-xcode6.3
-#          #I think xcode.6.3 VM is broken, it does not boot
-        - os: osx
-          osx_image: xcode6.4
-          #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
-        - os: osx
-          osx_image: xcode7
-          #Apple LLVM version 7.0.0 (clang-700.0.72)
-        - os: osx
-          osx_image: xcode7.1
-          #Apple LLVM version 7.0.0 (clang-700.1.76)
-        - os: osx
-          osx_image: xcode7.2
-          #Apple LLVM version 7.0.2 (clang-700.1.81)
+#          osx_image: beta-xcode6.1
+#          #Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
+#        - os: osx
+#          osx_image: beta-xcode6.2
+#          compiler: gcc
+#          #Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn)
+##        - os: osx
+##          osx_image: beta-xcode6.3
+##          #I think xcode.6.3 VM is broken, it does not boot
+#        - os: osx
+#          osx_image: xcode6.4
+#          #Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
+#        - os: osx
+#          osx_image: xcode7
+#          #Apple LLVM version 7.0.0 (clang-700.0.72)
+#        - os: osx
+#          osx_image: xcode7.1
+#          #Apple LLVM version 7.0.0 (clang-700.1.76)
+#        - os: osx
+#          osx_image: xcode7.2
+#          #Apple LLVM version 7.0.2 (clang-700.1.81)
         - os: osx
           osx_image: xcode7.3
           #Apple LLVM version 7.3.0 (clang-703.0.31)
@@ -213,7 +213,7 @@ before_script:
   - 7z x $HOME/srb2_cache/SRB2-v2115-assets-2.7z -oassets
   - mkdir build
   - cd build
-  - export CFLAGS="-Wall -W $WFLAGS"
+  - export CFLAGS="-Wall -W -Werror $WFLAGS"
   - export CCACHE_COMPRESS=true
   - cmake .. -DCMAKE_BUILD_TYPE=Release
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb93d22f0d68148e3f9a60eef3bd37bccf9fdfb0..f9364fdd2c1b20ea8c3fa2afa744cbe8360a62de 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
 cmake_minimum_required(VERSION 3.0)
 project(SRB2
-	VERSION 2.1.14
+	VERSION 2.1.19
 	LANGUAGES C)
 
 if(${PROJECT_SOURCE_DIR} MATCHES ${PROJECT_BINARY_DIR})
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..d16071454876bc178222e778ca7c20f63821bb97
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Sonic Robo Blast 2
+
+[![Build status](https://ci.appveyor.com/api/projects/status/399d4hcw9yy7hg2y?svg=true)](https://ci.appveyor.com/project/STJr/srb2)
+[![Build status](https://travis-ci.org/STJr/SRB2.svg?branch=master)](https://travis-ci.org/STJr/SRB2)
+[![CircleCI](https://circleci.com/gh/STJr/SRB2/tree/master.svg?style=svg)](https://circleci.com/gh/STJr/SRB2/tree/master)
+
+[Sonic Robo Blast 2](https://srb2.org/) is a 3D Sonic the Hedgehog fangame based on a modified version of [Doom Legacy](http://doomlegacy.sourceforge.net/).
+
+## Dependencies
+- NASM (x86 builds only)
+- SDL2 (Linux/OS X only)
+- SDL2-Mixer (Linux/OS X only)
+- libupnp (Linux/OS X only)
+- libgme (Linux/OS X only)
+
+Warning: 64-bit builds are not netgame compatible with 32-bit builds. Use at your own risk.
+
+## Compiling
+
+See [SRB2 Wiki/Source code compiling](http://wiki.srb2.org/wiki/Source_code_compiling)
+
+## Disclaimer
+Sonic Team Junior is in no way affiliated with SEGA or Sonic Team. We do not claim ownership of any of SEGA's intellectual property used in SRB2.
diff --git a/SRB2.cbp b/SRB2.cbp
index 43696ee2e4b23a9ecf6eafafe51bfeaa834cb154..74ec96c6eeb8b0ee22b6260e883bc2d421bc57ad 100644
--- a/SRB2.cbp
+++ b/SRB2.cbp
@@ -14,7 +14,7 @@ If you are compiling for Windows, use Mingw targets
 Interface Defines:
 _WINDOWS for DirectX Interface
 SDL for SDL Interface
-HAVE_MIXER for SDL_Mixer
+HAVE_MIXER for SDL2_mixer
 
 HAVE_PNG for PNG support (for APNG support. compile libs/libpng-src)
 HWRENDER for hardware render support
@@ -31,7 +31,7 @@ HW3SOUND for 3D hardware sound  support
 				<Option compiler="gcc" />
 				<Compiler>
 					<Add option="-g" />
-					<Add option="`sdl-config --cflags`" />
+					<Add option="`sdl2-config --cflags`" />
 					<Add option="-DDIRECTFULLSCREEN" />
 					<Add option="-DHAVE_SDL" />
 					<Add option="-DPARANOIA" />
@@ -41,8 +41,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add option="-DHAVE_BLUA" />
 				</Compiler>
 				<Linker>
-					<Add option="`sdl-config --libs`" />
-					<Add library="SDL_mixer" />
+					<Add option="`sdl2-config --libs`" />
+					<Add library="SDL2_mixer" />
 				</Linker>
 			</Target>
 			<Target title="Release Native/SDL">
@@ -54,7 +54,7 @@ HW3SOUND for 3D hardware sound  support
 				<Compiler>
 					<Add option="-O2" />
 					<Add option="-g" />
-					<Add option="`sdl-config --cflags`" />
+					<Add option="`sdl2-config --cflags`" />
 					<Add option="-DDIRECTFULLSCREEN" />
 					<Add option="-DHAVE_SDL" />
 					<Add option="-DNDEBUG" />
@@ -62,8 +62,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add option="-DHAVE_BLUA" />
 				</Compiler>
 				<Linker>
-					<Add option="`sdl-config --libs`" />
-					<Add library="SDL_mixer" />
+					<Add option="`sdl2-config --libs`" />
+					<Add library="SDL2_mixer" />
 				</Linker>
 			</Target>
 			<Target title="Debug Linux/SDL">
@@ -74,7 +74,7 @@ HW3SOUND for 3D hardware sound  support
 				<Option compiler="gcc" />
 				<Compiler>
 					<Add option="-g" />
-					<Add option="`sdl-config --cflags`" />
+					<Add option="`sdl2-config --cflags`" />
 					<Add option="`libpng-config --cflags`" />
 					<Add option="-DDIRECTFULLSCREEN" />
 					<Add option="-DHAVE_SDL" />
@@ -89,9 +89,9 @@ HW3SOUND for 3D hardware sound  support
 					<Add option="-DHAVE_BLUA" />
 				</Compiler>
 				<Linker>
-					<Add option="`sdl-config --libs`" />
+					<Add option="`sdl2-config --libs`" />
 					<Add option="`libpng-config --libs`" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2_mixer" />
 					<Add library="rt" />
 				</Linker>
 			</Target>
@@ -104,7 +104,7 @@ HW3SOUND for 3D hardware sound  support
 				<Compiler>
 					<Add option="-O2" />
 					<Add option="-g" />
-					<Add option="`sdl-config --cflags`" />
+					<Add option="`sdl2-config --cflags`" />
 					<Add option="`libpng-config --cflags`" />
 					<Add option="-DDIRECTFULLSCREEN" />
 					<Add option="-DHAVE_SDL" />
@@ -117,9 +117,9 @@ HW3SOUND for 3D hardware sound  support
 					<Add option="-DHAVE_BLUA" />
 				</Compiler>
 				<Linker>
-					<Add option="`sdl-config --libs`" />
+					<Add option="`sdl2-config --libs`" />
 					<Add option="`libpng-config --libs`" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2_mixer" />
 					<Add library="rt" />
 				</Linker>
 			</Target>
@@ -152,6 +152,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/libpng-src" />
 					<Add directory="libs/zlib" />
 					<Add directory="libs/gme/include" />
+					<Add directory="libs/SDL2/include" />
+					<Add directory="libs/SDL2_mixer/include" />
 				</Compiler>
 				<Linker>
 					<Add library="SDL2" />
@@ -167,6 +169,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/zlib/win32" />
 					<Add directory="libs/libpng-src/projects" />
 					<Add directory="libs/gme/win32" />
+					<Add directory="libs/SDL2/lib/x86" />
+					<Add directory="libs/SDL2_mixer/lib/x86" />
 				</Linker>
 			</Target>
 			<Target title="Release Mingw/SDL">
@@ -198,6 +202,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/libpng-src" />
 					<Add directory="libs/zlib" />
 					<Add directory="libs/gme/include" />
+					<Add directory="libs/SDL2/include" />
+					<Add directory="libs/SDL2_mixer/include" />
 				</Compiler>
 				<Linker>
 					<Add library="SDL2" />
@@ -213,6 +219,8 @@ HW3SOUND for 3D hardware sound  support
 					<Add directory="libs/zlib/win32" />
 					<Add directory="libs/libpng-src/projects" />
 					<Add directory="libs/gme/win32" />
+					<Add directory="libs/SDL2/lib/x86" />
+					<Add directory="libs/SDL2_mixer/lib/x86" />
 				</Linker>
 			</Target>
 			<Target title="Debug Mingw/DirectX">
@@ -567,7 +575,7 @@ HW3SOUND for 3D hardware sound  support
 				<Linker>
 					<Add option="-g" />
 					<Add library="SDL" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2_mixer" />
 					<Add library="advapi32" />
 					<Add library="kernel32" />
 					<Add library="msvcrt" />
@@ -606,7 +614,7 @@ HW3SOUND for 3D hardware sound  support
 				<Linker>
 					<Add option="-g" />
 					<Add library="SDL" />
-					<Add library="SDL_mixer" />
+					<Add library="SDL2_mixer" />
 					<Add library="advapi32" />
 					<Add library="kernel32" />
 					<Add library="msvcrt" />
@@ -884,6 +892,206 @@ HW3SOUND for 3D hardware sound  support
 		<Unit filename="cpdebug.mk" />
 		<Unit filename="src/am_map.c">
 			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/am_map.h" />
+		<Unit filename="src/b_bot.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/b_bot.h" />
+		<Unit filename="src/blua/lapi.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lapi.h" />
+		<Unit filename="src/blua/lauxlib.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lauxlib.h" />
+		<Unit filename="src/blua/lbaselib.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lcode.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lcode.h" />
+		<Unit filename="src/blua/ldebug.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ldebug.h" />
+		<Unit filename="src/blua/ldo.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ldo.h" />
+		<Unit filename="src/blua/ldump.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lfunc.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lfunc.h" />
+		<Unit filename="src/blua/lgc.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lgc.h" />
+		<Unit filename="src/blua/linit.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/llex.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/llex.h" />
+		<Unit filename="src/blua/llimits.h" />
+		<Unit filename="src/blua/lmem.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lmem.h" />
+		<Unit filename="src/blua/lobject.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lobject.h" />
+		<Unit filename="src/blua/lopcodes.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lopcodes.h" />
+		<Unit filename="src/blua/lparser.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lparser.h" />
+		<Unit filename="src/blua/lstate.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lstate.h" />
+		<Unit filename="src/blua/lstring.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lstring.h" />
+		<Unit filename="src/blua/lstrlib.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ltable.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ltable.h" />
+		<Unit filename="src/blua/ltablib.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ltm.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/ltm.h" />
+		<Unit filename="src/blua/lua.h" />
+		<Unit filename="src/blua/luaconf.h" />
+		<Unit filename="src/blua/lualib.h" />
+		<Unit filename="src/blua/lundump.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lundump.h" />
+		<Unit filename="src/blua/lvm.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lvm.h" />
+		<Unit filename="src/blua/lzio.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/blua/lzio.h" />
+		<Unit filename="src/byteptr.h" />
+		<Unit filename="src/command.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/command.h" />
+		<Unit filename="src/comptime.c">
+			<Option compilerVar="CC" />
+			<Option weight="100" />
+		</Unit>
+		<Unit filename="src/comptime.h" />
+		<Unit filename="src/console.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/console.h" />
+		<Unit filename="src/d_clisrv.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/d_clisrv.h" />
+		<Unit filename="src/d_event.h" />
+		<Unit filename="src/d_main.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/d_main.h" />
+		<Unit filename="src/d_net.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/d_net.h" />
+		<Unit filename="src/d_netcmd.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/d_netcmd.h" />
+		<Unit filename="src/d_netfil.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/d_netfil.h" />
+		<Unit filename="src/d_player.h" />
+		<Unit filename="src/d_think.h" />
+		<Unit filename="src/d_ticcmd.h" />
+		<Unit filename="src/dehacked.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/dehacked.h" />
+		<Unit filename="src/doomdata.h" />
+		<Unit filename="src/doomdef.h" />
+		<Unit filename="src/doomstat.h" />
+		<Unit filename="src/doomtype.h" />
+		<Unit filename="src/dummy/i_cdmus.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/dummy/i_main.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/dummy/i_net.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/dummy/i_sound.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/dummy/i_system.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/dummy/i_video.c">
+			<Option compilerVar="CC" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+		</Unit>
+		<Unit filename="src/endian.h" />
+		<Unit filename="src/f_finale.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/f_finale.h" />
+		<Unit filename="src/f_wipe.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/fastcmp.h" />
+		<Unit filename="src/filesrch.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/filesrch.h" />
+		<Unit filename="src/g_game.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/g_game.h" />
+		<Unit filename="src/g_input.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/g_input.h" />
+		<Unit filename="src/g_state.h" />
+		<Unit filename="src/hardware/hw3dsdrv.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
@@ -899,7 +1107,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/am_map.h">
+		<Unit filename="src/hardware/hw3sound.c">
+			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
@@ -915,8 +1124,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/b_bot.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw3sound.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
@@ -932,24 +1140,24 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/b_bot.h" />
-		<Unit filename="src/blua/lapi.c">
+		<Unit filename="src/hardware/hw_bsp.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 Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+			<Option target="Debug Linux/SDL" />
+			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
 			<Option target="Release Mingw64/SDL" />
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lapi.h" />
-		<Unit filename="src/blua/lauxlib.c">
+		<Unit filename="src/hardware/hw_cache.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -957,6 +1165,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -964,15 +1174,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lauxlib.h" />
-		<Unit filename="src/blua/lbaselib.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_data.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -980,14 +1190,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lcode.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_defs.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -995,15 +1206,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lcode.h" />
-		<Unit filename="src/blua/ldebug.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_dll.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1011,8 +1222,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/ldebug.h" />
-		<Unit filename="src/blua/ldo.c">
+		<Unit filename="src/hardware/hw_draw.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -1020,6 +1230,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1027,15 +1239,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/ldo.h" />
-		<Unit filename="src/blua/ldump.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_drv.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1043,14 +1255,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lfunc.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_glide.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1058,15 +1271,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lfunc.h" />
-		<Unit filename="src/blua/lgc.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_glob.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1074,8 +1287,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lgc.h" />
-		<Unit filename="src/blua/linit.c">
+		<Unit filename="src/hardware/hw_light.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -1083,6 +1295,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1090,14 +1304,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/llex.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_light.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1105,9 +1320,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/llex.h" />
-		<Unit filename="src/blua/llimits.h" />
-		<Unit filename="src/blua/lmem.c">
+		<Unit filename="src/hardware/hw_main.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -1115,6 +1328,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1122,15 +1337,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lmem.h" />
-		<Unit filename="src/blua/lobject.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_main.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1138,8 +1353,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lobject.h" />
-		<Unit filename="src/blua/lopcodes.c">
+		<Unit filename="src/hardware/hw_md2.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -1147,6 +1361,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1154,15 +1370,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lopcodes.h" />
-		<Unit filename="src/blua/lparser.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hw_md2.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1170,8 +1386,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lparser.h" />
-		<Unit filename="src/blua/lstate.c">
+		<Unit filename="src/hardware/hw_trick.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -1179,6 +1394,8 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1186,15 +1403,15 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lstate.h" />
-		<Unit filename="src/blua/lstring.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/hws_data.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 			<Option target="Debug Mingw/DirectX" />
 			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
@@ -1202,2930 +1419,321 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw64/DirectX" />
 			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/blua/lstring.h" />
-		<Unit filename="src/blua/lstrlib.c">
+		<Unit filename="src/hardware/r_minigl/r_minigl.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw R_MiniGL" />
+			<Option target="Release Mingw R_MiniGL" />
+			<Option target="Debug Mingw64 R_MiniGL" />
+			<Option target="Release Mingw64 R_MiniGL" />
 		</Unit>
-		<Unit filename="src/blua/ltable.c">
+		<Unit filename="src/hardware/r_opengl/ogl_win.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw R_OpenGL" />
+			<Option target="Release Mingw R_OpenGL" />
+			<Option target="Debug Mingw64 R_OpenGL" />
+			<Option target="Release Mingw64 R_OpenGL" />
 		</Unit>
-		<Unit filename="src/blua/ltable.h" />
-		<Unit filename="src/blua/ltablib.c">
+		<Unit filename="src/hardware/r_opengl/r_opengl.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/blua/ltm.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
+			<Option target="Debug Mingw R_OpenGL" />
+			<Option target="Release Mingw R_OpenGL" />
 			<Option target="Debug Mingw64/SDL" />
 			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw64 R_OpenGL" />
+			<Option target="Release Mingw64 R_OpenGL" />
 		</Unit>
-		<Unit filename="src/blua/ltm.h" />
-		<Unit filename="src/blua/lua.h" />
-		<Unit filename="src/blua/luaconf.h" />
-		<Unit filename="src/blua/lualib.h" />
-		<Unit filename="src/blua/lundump.c">
-			<Option compilerVar="CC" />
+		<Unit filename="src/hardware/r_opengl/r_opengl.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
+			<Option target="Debug Any/Dummy" />
+			<Option target="Release Any/Dummy" />
+			<Option target="Debug Mingw R_OpenGL" />
+			<Option target="Release Mingw R_OpenGL" />
+			<Option target="Debug Mingw R_MiniGL" />
+			<Option target="Release Mingw R_MiniGL" />
 			<Option target="Debug Linux/SDL" />
 			<Option target="Release Linux/SDL" />
 			<Option target="Debug Mingw64/SDL" />
 			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw64 R_OpenGL" />
+			<Option target="Release Mingw64 R_OpenGL" />
+			<Option target="Debug Mingw64 R_MiniGL" />
+			<Option target="Release Mingw64 R_MiniGL" />
 		</Unit>
-		<Unit filename="src/blua/lundump.h" />
-		<Unit filename="src/blua/lvm.c">
+		<Unit filename="src/hardware/s_ds3d/s_ds3d.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw S_DS3D" />
+			<Option target="Release Mingw S_DS3D" />
+			<Option target="Debug Mingw64 S_DS3D" />
+			<Option target="Release Mingw64 S_DS3D" />
 		</Unit>
-		<Unit filename="src/blua/lvm.h" />
-		<Unit filename="src/blua/lzio.c">
+		<Unit filename="src/hardware/s_fmod/s_fmod.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/blua/lzio.h" />
-		<Unit filename="src/byteptr.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw S_FMOD" />
+			<Option target="Release Mingw S_FMOD" />
+			<Option target="Debug Mingw64 S_FMOD" />
+			<Option target="Release Mingw64 S_FMOD" />
 		</Unit>
-		<Unit filename="src/command.c">
+		<Unit filename="src/hardware/s_openal/s_openal.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option target="Debug Mingw S_OpenAL" />
+			<Option target="Release Mingw S_OpenAL" />
+			<Option target="Debug Shared S_OpenAL" />
+			<Option target="Release Shared S_OpenAL" />
+			<Option target="Debug Mingw64 S_OpenAL" />
+			<Option target="Release Mingw64 S_OpenAL" />
 		</Unit>
-		<Unit filename="src/command.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/hu_stuff.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/comptime.c">
+		<Unit filename="src/hu_stuff.h" />
+		<Unit filename="src/i_addrinfo.c">
 			<Option compilerVar="CC" />
-			<Option weight="100" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option compile="0" />
+			<Option link="0" />
 		</Unit>
-		<Unit filename="src/console.c">
+		<Unit filename="src/i_addrinfo.h" />
+		<Unit filename="src/i_joy.h" />
+		<Unit filename="src/i_net.h" />
+		<Unit filename="src/i_sound.h" />
+		<Unit filename="src/i_system.h" />
+		<Unit filename="src/i_tcp.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/console.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/i_tcp.h" />
+		<Unit filename="src/i_video.h" />
+		<Unit filename="src/info.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/d_clisrv.c">
+		<Unit filename="src/info.h" />
+		<Unit filename="src/keys.h" />
+		<Unit filename="src/lua_baselib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_clisrv.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_event.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_main.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_main.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_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 Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_net.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_netcmd.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_netcmd.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_netfil.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_netfil.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_player.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_think.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/d_ticcmd.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/dehacked.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/dehacked.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/doomdata.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/doomdef.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/doomstat.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/doomtype.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/dummy/i_cdmus.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/dummy/i_main.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/dummy/i_net.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/dummy/i_sound.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/dummy/i_system.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/dummy/i_video.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-		</Unit>
-		<Unit filename="src/f_finale.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/f_finale.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/f_wipe.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/fastcmp.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/filesrch.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/filesrch.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/g_game.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/g_game.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/g_input.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/g_input.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/g_state.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw3dsdrv.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw3sound.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw3sound.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_bsp.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_cache.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_data.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_defs.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_dll.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_draw.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_drv.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_glide.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_glob.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_light.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_light.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_main.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_main.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_md2.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_md2.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hw_trick.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/hws_data.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hardware/r_minigl/r_minigl.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Mingw R_MiniGL" />
-			<Option target="Release Mingw R_MiniGL" />
-			<Option target="Debug Mingw64 R_MiniGL" />
-			<Option target="Release Mingw64 R_MiniGL" />
-		</Unit>
-		<Unit filename="src/hardware/r_opengl/ogl_win.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Mingw R_OpenGL" />
-			<Option target="Release Mingw R_OpenGL" />
-			<Option target="Debug Mingw64 R_OpenGL" />
-			<Option target="Release Mingw64 R_OpenGL" />
-		</Unit>
-		<Unit filename="src/hardware/r_opengl/r_opengl.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw R_OpenGL" />
-			<Option target="Release Mingw R_OpenGL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64 R_OpenGL" />
-			<Option target="Release Mingw64 R_OpenGL" />
-		</Unit>
-		<Unit filename="src/hardware/r_opengl/r_opengl.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 Mingw R_OpenGL" />
-			<Option target="Release Mingw R_OpenGL" />
-			<Option target="Debug Mingw R_MiniGL" />
-			<Option target="Release Mingw R_MiniGL" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64 R_OpenGL" />
-			<Option target="Release Mingw64 R_OpenGL" />
-			<Option target="Debug Mingw64 R_MiniGL" />
-			<Option target="Release Mingw64 R_MiniGL" />
-		</Unit>
-		<Unit filename="src/hardware/s_ds3d/s_ds3d.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Mingw S_DS3D" />
-			<Option target="Release Mingw S_DS3D" />
-			<Option target="Debug Mingw64 S_DS3D" />
-			<Option target="Release Mingw64 S_DS3D" />
-		</Unit>
-		<Unit filename="src/hardware/s_fmod/s_fmod.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Mingw S_FMOD" />
-			<Option target="Release Mingw S_FMOD" />
-			<Option target="Debug Mingw64 S_FMOD" />
-			<Option target="Release Mingw64 S_FMOD" />
-		</Unit>
-		<Unit filename="src/hardware/s_openal/s_openal.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Mingw S_OpenAL" />
-			<Option target="Release Mingw S_OpenAL" />
-			<Option target="Debug Shared S_OpenAL" />
-			<Option target="Release Shared S_OpenAL" />
-			<Option target="Debug Mingw64 S_OpenAL" />
-			<Option target="Release Mingw64 S_OpenAL" />
-		</Unit>
-		<Unit filename="src/hu_stuff.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/hu_stuff.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_joy.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_net.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_sound.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_system.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_tcp.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_tcp.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/i_video.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/info.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/info.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/keys.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_baselib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_consolelib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_hook.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_hooklib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_hud.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_hudlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_infolib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_libs.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_maplib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_mathlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_mobjlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_playerlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_script.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_script.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_skinlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lua_thinkerlib.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lzf.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/lzf.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_anigif.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_anigif.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_argv.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_argv.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_bbox.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_bbox.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_cheat.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_cheat.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_cond.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 Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_cond.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_dllist.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_fixed.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_fixed.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_menu.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_menu.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_misc.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_misc.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_queue.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_queue.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_random.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_random.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/m_swap.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/md5.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/md5.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/mserv.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/mserv.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p5prof.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_ceilng.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_enemy.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_floor.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_inter.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_lights.c">
-			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/p_local.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_map.c">
+		<Unit filename="src/lua_consolelib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_maputl.c">
+		<Unit filename="src/lua_hook.h" />
+		<Unit filename="src/lua_hooklib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_maputl.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lua_hud.h" />
+		<Unit filename="src/lua_hudlib.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_mobj.c">
+		<Unit filename="src/lua_infolib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_mobj.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lua_libs.h" />
+		<Unit filename="src/lua_maplib.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_polyobj.c">
+		<Unit filename="src/lua_mathlib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_polyobj.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lua_mobjlib.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_pspr.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lua_playerlib.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_saveg.c">
+		<Unit filename="src/lua_script.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_saveg.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lua_script.h" />
+		<Unit filename="src/lua_skinlib.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_setup.c">
+		<Unit filename="src/lua_thinkerlib.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_setup.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/lzf.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_sight.c">
+		<Unit filename="src/lzf.h" />
+		<Unit filename="src/m_aatree.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_spec.c">
+		<Unit filename="src/m_aatree.h" />
+		<Unit filename="src/m_anigif.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_spec.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/m_anigif.h" />
+		<Unit filename="src/m_argv.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_telept.c">
+		<Unit filename="src/m_argv.h" />
+		<Unit filename="src/m_bbox.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/m_bbox.h" />
+		<Unit filename="src/m_cheat.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_tick.c">
+		<Unit filename="src/m_cheat.h" />
+		<Unit filename="src/m_cond.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/p_tick.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/m_cond.h" />
+		<Unit filename="src/m_dllist.h" />
+		<Unit filename="src/m_fixed.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/p_user.c">
+		<Unit filename="src/m_fixed.h" />
+		<Unit filename="src/m_menu.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_bsp.c">
+		<Unit filename="src/m_menu.h" />
+		<Unit filename="src/m_misc.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_bsp.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/m_misc.h" />
+		<Unit filename="src/m_queue.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_data.c">
+		<Unit filename="src/m_queue.h" />
+		<Unit filename="src/m_random.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_data.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/m_random.h" />
+		<Unit filename="src/m_swap.h" />
+		<Unit filename="src/md5.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_defs.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/md5.h" />
+		<Unit filename="src/mserv.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_draw.c">
+		<Unit filename="src/mserv.h" />
+		<Unit filename="src/p5prof.h" />
+		<Unit filename="src/p_ceilng.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_draw.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_enemy.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_draw16.c">
+		<Unit filename="src/p_floor.c">
 			<Option compilerVar="CC" />
-			<Option compile="0" />
-			<Option link="0" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_draw8.c">
+		<Unit filename="src/p_inter.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 Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_local.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_lights.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_main.c">
+		<Unit filename="src/p_local.h" />
+		<Unit filename="src/p_map.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_main.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_maputl.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_plane.c">
+		<Unit filename="src/p_maputl.h" />
+		<Unit filename="src/p_mobj.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_plane.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_mobj.h" />
+		<Unit filename="src/p_polyobj.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_segs.c">
+		<Unit filename="src/p_polyobj.h" />
+		<Unit filename="src/p_pspr.h" />
+		<Unit filename="src/p_saveg.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_segs.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_saveg.h" />
+		<Unit filename="src/p_setup.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_sky.c">
+		<Unit filename="src/p_setup.h" />
+		<Unit filename="src/p_sight.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_sky.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_slopes.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_splats.c">
+		<Unit filename="src/p_slopes.h" />
+		<Unit filename="src/p_spec.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_splats.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_spec.h" />
+		<Unit filename="src/p_telept.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_state.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/p_tick.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/r_things.c">
+		<Unit filename="src/p_tick.h" />
+		<Unit filename="src/p_user.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/r_things.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/r_bsp.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/s_sound.c">
+		<Unit filename="src/r_bsp.h" />
+		<Unit filename="src/r_data.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/s_sound.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/r_data.h" />
+		<Unit filename="src/r_defs.h" />
+		<Unit filename="src/r_draw.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/screen.c">
+		<Unit filename="src/r_draw.h" />
+		<Unit filename="src/r_draw16.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option compile="0" />
+			<Option link="0" />
 		</Unit>
-		<Unit filename="src/screen.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/r_draw8.c">
+			<Option compilerVar="CC" />
+			<Option compile="0" />
+			<Option link="0" />
+		</Unit>
+		<Unit filename="src/r_local.h" />
+		<Unit filename="src/r_main.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_main.h" />
+		<Unit filename="src/r_plane.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_plane.h" />
+		<Unit filename="src/r_segs.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_segs.h" />
+		<Unit filename="src/r_sky.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_sky.h" />
+		<Unit filename="src/r_splats.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_splats.h" />
+		<Unit filename="src/r_state.h" />
+		<Unit filename="src/r_things.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/r_things.h" />
+		<Unit filename="src/s_sound.c">
+			<Option compilerVar="CC" />
+		</Unit>
+		<Unit filename="src/s_sound.h" />
+		<Unit filename="src/screen.c">
+			<Option compilerVar="CC" />
 		</Unit>
-		<Unit filename="src/sdl2/IMG_xpm.c">
+		<Unit filename="src/screen.h" />
+		<Unit filename="src/sdl/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 Linux/SDL" />
@@ -4133,7 +1741,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/SDL_icon.xpm">
+		<Unit filename="src/sdl/SDL_icon.xpm">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4141,7 +1749,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/dosstr.c">
+		<Unit filename="src/sdl/dosstr.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4150,7 +1758,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/endtxt.c">
+		<Unit filename="src/sdl/endtxt.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4159,7 +1767,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/endtxt.h">
+		<Unit filename="src/sdl/endtxt.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4167,7 +1775,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/hwsym_sdl.c">
+		<Unit filename="src/sdl/hwsym_sdl.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4176,7 +1784,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/hwsym_sdl.h">
+		<Unit filename="src/sdl/hwsym_sdl.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4184,7 +1792,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_cdmus.c">
+		<Unit filename="src/sdl/i_cdmus.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4193,7 +1801,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_main.c">
+		<Unit filename="src/sdl/i_main.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4202,7 +1810,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_net.c">
+		<Unit filename="src/sdl/i_net.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4211,7 +1819,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_system.c">
+		<Unit filename="src/sdl/i_system.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4220,7 +1828,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_ttf.c">
+		<Unit filename="src/sdl/i_ttf.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4229,7 +1837,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_ttf.h">
+		<Unit filename="src/sdl/i_ttf.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4237,7 +1845,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/i_video.c">
+		<Unit filename="src/sdl/i_video.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4246,7 +1854,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/mixer_sound.c">
+		<Unit filename="src/sdl/mixer_sound.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4255,7 +1863,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/ogl_sdl.c">
+		<Unit filename="src/sdl/ogl_sdl.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4264,7 +1872,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/ogl_sdl.h">
+		<Unit filename="src/sdl/ogl_sdl.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4272,7 +1880,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/sdl_sound.c">
+		<Unit filename="src/sdl/sdl_sound.c">
 			<Option compilerVar="CC" />
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
@@ -4281,7 +1889,7 @@ HW3SOUND for 3D hardware sound  support
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
 		</Unit>
-		<Unit filename="src/sdl2/sdlmain.h">
+		<Unit filename="src/sdl/sdlmain.h">
 			<Option target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4291,120 +1899,39 @@ HW3SOUND for 3D hardware sound  support
 		</Unit>
 		<Unit filename="src/sounds.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/sounds.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/sounds.h" />
 		<Unit filename="src/st_stuff.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/st_stuff.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/st_stuff.h" />
 		<Unit filename="src/string.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
-		<Unit filename="src/tables.c">
+		<Unit filename="src/t_facon.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+			<Option compile="0" />
+			<Option link="0" />
 		</Unit>
-		<Unit filename="src/tables.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
+		<Unit filename="src/t_fsin.c">
+			<Option compilerVar="CC" />
+			<Option compile="0" />
+			<Option link="0" />
+		</Unit>
+		<Unit filename="src/t_ftan.c">
+			<Option compilerVar="CC" />
+			<Option compile="0" />
+			<Option link="0" />
+		</Unit>
+		<Unit filename="src/t_tan2a.c">
+			<Option compilerVar="CC" />
+			<Option compile="0" />
+			<Option link="0" />
+		</Unit>
+		<Unit filename="src/tables.c">
+			<Option compilerVar="CC" />
 		</Unit>
+		<Unit filename="src/tables.h" />
 		<Unit filename="src/tmap.nas">
 			<Option target="Debug Mingw/SDL" />
 			<Option target="Release Mingw/SDL" />
@@ -4427,46 +1954,17 @@ HW3SOUND for 3D hardware sound  support
 		</Unit>
 		<Unit filename="src/v_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 Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/v_video.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/v_video.h" />
 		<Unit filename="src/vid_copy.s">
 			<Option compilerVar="CC" />
-			<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="avrgcc" 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="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 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 target="Debug Native/SDL" />
 			<Option target="Release Native/SDL" />
 			<Option target="Debug Linux/SDL" />
@@ -4478,37 +1976,8 @@ HW3SOUND for 3D hardware sound  support
 		</Unit>
 		<Unit filename="src/w_wad.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/w_wad.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/w_wad.h" />
 		<Unit filename="src/win32/Srb2win.rc">
 			<Option compilerVar="WINDRES" />
 			<Option target="Debug Mingw/DirectX" />
@@ -4634,70 +2103,12 @@ HW3SOUND for 3D hardware sound  support
 		</Unit>
 		<Unit filename="src/y_inter.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/y_inter.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/y_inter.h" />
 		<Unit filename="src/z_zone.c">
 			<Option compilerVar="CC" />
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
-		</Unit>
-		<Unit filename="src/z_zone.h">
-			<Option target="Debug Native/SDL" />
-			<Option target="Release Native/SDL" />
-			<Option target="Debug Mingw/SDL" />
-			<Option target="Release Mingw/SDL" />
-			<Option target="Debug Mingw/DirectX" />
-			<Option target="Release Mingw/DirectX" />
-			<Option target="Debug Any/Dummy" />
-			<Option target="Release Any/Dummy" />
-			<Option target="Debug Linux/SDL" />
-			<Option target="Release Linux/SDL" />
-			<Option target="Debug Mingw64/SDL" />
-			<Option target="Release Mingw64/SDL" />
-			<Option target="Debug Mingw64/DirectX" />
-			<Option target="Release Mingw64/DirectX" />
 		</Unit>
+		<Unit filename="src/z_zone.h" />
 		<Extensions>
 			<envvars />
 			<code_completion />
diff --git a/appveyor.yml b/appveyor.yml
index 85cee6a3107a224213512eea0fba150d799c7232..23b9b62815b597867a56957bcdde2239808cbdb2 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: 2.1.14.{branch}-{build}
+version: 2.1.19.{branch}-{build}
 os: MinGW
 
 environment:
@@ -47,7 +47,7 @@ before_build:
 - upx -V
 - ccache -V
 - ccache -s
-- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC53=1 CCACHE=1
+- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 GCC63=1 CCACHE=1 NOOBJDUMP=1
 
 build_script:
 - cmd: mingw32-make.exe %SRB2_MFLAGS% %CONFIGURATION%=1 clean
@@ -58,26 +58,29 @@ after_build:
 - cmd: git rev-parse --short %APPVEYOR_REPO_COMMIT%>%TMP%/gitshort.txt
 - cmd: set /P GITSHORT=<%TMP%/gitshort.txt
 - set BUILD_ARCHIVE=%APPVEYOR_REPO_BRANCH%-%GITSHORT%-%CONFIGURATION%.7z
+- set BUILDSARCHIVE=%APPVEYOR_REPO_BRANCH%-%CONFIGURATION%.7z
 - cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
 - appveyor PushArtifact %BUILD_ARCHIVE%
+- cmd: copy %BUILD_ARCHIVE% %BUILDSARCHIVE%
+- appveyor PushArtifact %BUILDSARCHIVE%
 
 test: off
 
-deploy:
-  - provider: FTP
-    protocol: ftps
-    host: 
-      secure: NsLJEPIBvmwCOj8Tg8RoRQ==
-    username:
-      secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
-    password:
-      secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
-    folder: appveyor
-    application:
-    active_mode: false
-    on:
-      branch: master
-      appveyor_repo_tag: true
+#deploy:
+#  - provider: FTP
+#    protocol: ftps
+#    host: 
+#      secure: NsLJEPIBvmwCOj8Tg8RoRQ==
+#    username:
+#      secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
+#    password:
+#      secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
+#    folder: appveyor
+#    application:
+#    active_mode: false
+#    on:
+#      branch: master
+#      appveyor_repo_tag: true
 
 
 on_finish:
diff --git a/bin/Mingw/Debug/.gitignore b/bin/Mingw/Debug/.gitignore
index e431dca5d25bfe0ea739d34ca086c9e87b2c13ab..834f313e3eae612617885430c8071e6e41483d88 100644
--- a/bin/Mingw/Debug/.gitignore
+++ b/bin/Mingw/Debug/.gitignore
@@ -1,3 +1,3 @@
-/srb2sdl.exe
-/srb2win.exe
-/r_opengl.dll
+*.exe
+*.mo
+r_opengl.dll
diff --git a/bin/Mingw/Release/.gitignore b/bin/Mingw/Release/.gitignore
index e431dca5d25bfe0ea739d34ca086c9e87b2c13ab..834f313e3eae612617885430c8071e6e41483d88 100644
--- a/bin/Mingw/Release/.gitignore
+++ b/bin/Mingw/Release/.gitignore
@@ -1,3 +1,3 @@
-/srb2sdl.exe
-/srb2win.exe
-/r_opengl.dll
+*.exe
+*.mo
+r_opengl.dll
diff --git a/debian/docs b/debian/docs
index f3d4ef20e5a4ce3dd58bd8cf313bd95fcd7ec564..b43bf86b50fd8d3529a0dc062c30006ed38f309e 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1,2 +1 @@
-readme.txt
-readme.txt
+README.md
diff --git a/objs/.gitignore b/objs/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..35ecd6def21e7cdb60882510005e3b9833df5a08
--- /dev/null
+++ b/objs/.gitignore
@@ -0,0 +1,8 @@
+#All folders
+SRB2.res
+depend.dep
+depend.ped
+*.o
+#VC9 folder only
+/VC9/Win32
+/VC9/x64
diff --git a/objs/DC/SDL/Debug/.gitignore b/objs/DC/SDL/Debug/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/DC/SDL/Debug/.gitignore
+++ b/objs/DC/SDL/Debug/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/DC/SDL/Release/.gitignore b/objs/DC/SDL/Release/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/DC/SDL/Release/.gitignore
+++ b/objs/DC/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux/SDL/Debug/.gitignore b/objs/Linux/SDL/Debug/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Linux/SDL/Debug/.gitignore
+++ b/objs/Linux/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux/SDL/Release/.gitignore b/objs/Linux/SDL/Release/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Linux/SDL/Release/.gitignore
+++ b/objs/Linux/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux64/SDL/Debug/.gitignore b/objs/Linux64/SDL/Debug/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Linux64/SDL/Debug/.gitignore
+++ b/objs/Linux64/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Linux64/SDL/Release/.gitignore b/objs/Linux64/SDL/Release/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Linux64/SDL/Release/.gitignore
+++ b/objs/Linux64/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/Debug/.gitignore b/objs/Mingw/Debug/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw/Debug/.gitignore
+++ b/objs/Mingw/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/Release/.gitignore b/objs/Mingw/Release/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw/Release/.gitignore
+++ b/objs/Mingw/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/SDL/Debug/.gitignore b/objs/Mingw/SDL/Debug/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw/SDL/Debug/.gitignore
+++ b/objs/Mingw/SDL/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw/SDL/Release/.gitignore b/objs/Mingw/SDL/Release/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw/SDL/Release/.gitignore
+++ b/objs/Mingw/SDL/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/Debug/.gitignore b/objs/Mingw64/Debug/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw64/Debug/.gitignore
+++ b/objs/Mingw64/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/Release/.gitignore b/objs/Mingw64/Release/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw64/Release/.gitignore
+++ b/objs/Mingw64/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/SDL/Debug/.gitignore b/objs/Mingw64/SDL/Debug/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw64/SDL/Debug/.gitignore
+++ b/objs/Mingw64/SDL/Debug/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Mingw64/SDL/Release/.gitignore b/objs/Mingw64/SDL/Release/.gitignore
index da4b3e912326f064eec51832cf2455498147fada..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Mingw64/SDL/Release/.gitignore
+++ b/objs/Mingw64/SDL/Release/.gitignore
@@ -1,3 +1,2 @@
-/SRB2.res
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PS3/SDL/Debug/.gitignore b/objs/PS3/SDL/Debug/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/PS3/SDL/Debug/.gitignore
+++ b/objs/PS3/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PS3/SDL/Release/.gitignore b/objs/PS3/SDL/Release/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/PS3/SDL/Release/.gitignore
+++ b/objs/PS3/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/PSP/SDL/Release/.gitignore b/objs/PSP/SDL/Release/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/PSP/SDL/Release/.gitignore
+++ b/objs/PSP/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/SDL/Release/.gitignore b/objs/SDL/Release/.gitignore
index 4a262f94f9de50a50677b8bba7df91214b5d5684..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/SDL/Release/.gitignore
+++ b/objs/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.ped
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/VC/.gitignore b/objs/VC/.gitignore
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/VC/.gitignore
+++ b/objs/VC/.gitignore
@@ -0,0 +1,2 @@
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/VC9/.gitignore b/objs/VC9/.gitignore
index 205fe45deb9ebe556ff38988507a10183a30feb7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/VC9/.gitignore
+++ b/objs/VC9/.gitignore
@@ -1,2 +1,2 @@
-/Win32
-/x64
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Wii/SDL/Debug/.gitignore b/objs/Wii/SDL/Debug/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Wii/SDL/Debug/.gitignore
+++ b/objs/Wii/SDL/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/Wii/SDL/Release/.gitignore b/objs/Wii/SDL/Release/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/Wii/SDL/Release/.gitignore
+++ b/objs/Wii/SDL/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/WinCE/SDL/Release/.gitignore b/objs/WinCE/SDL/Release/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/WinCE/SDL/Release/.gitignore
+++ b/objs/WinCE/SDL/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/djgppdos/Debug/.gitignore b/objs/djgppdos/Debug/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/djgppdos/Debug/.gitignore
+++ b/objs/djgppdos/Debug/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/djgppdos/Release/.gitignore b/objs/djgppdos/Release/.gitignore
index 867fcb4e0398725385e346dbc7352fe8b3b9f0e7..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/djgppdos/Release/.gitignore
+++ b/objs/djgppdos/Release/.gitignore
@@ -1 +1,2 @@
-/depend.dep
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/nds/Debug/.gitignore b/objs/nds/Debug/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/nds/Debug/.gitignore
+++ b/objs/nds/Debug/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/objs/nds/Release/.gitignore b/objs/nds/Release/.gitignore
index 8f6d0bdcdcdb8a1f18112fb0893d8f1338f7088b..42c6dc2c662642792a8860e166dfd81126695e8f 100644
--- a/objs/nds/Release/.gitignore
+++ b/objs/nds/Release/.gitignore
@@ -1,2 +1,2 @@
-/depend.dep
-/*.o
+# DON'T REMOVE
+# This keeps the folder from disappearing
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index c1898d491f0291bbfad2bd09b8b2cbc7b673e9ee..0000000000000000000000000000000000000000
--- a/readme.txt
+++ /dev/null
@@ -1,155 +0,0 @@
-Here it is! SRB2 v2.1.14 source code!
-(why do we keep the version number up to date
-	when everything else in this file is hilariously old?
-	- Inuyasha)
-
-
-Win32 with Visual C (6SP6+Processor Pack OR 7)
-~~~
-
-2 VC++ 6.0 project files are included:
-
-Win32/DirectX/FMOD
-src\win32\wLegacy.dsw
-You'll need FMOD to compile this version (www.fmod.org)
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dsp
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-
-Both needs NASM (http://sourceforge.net/projects/nasm)
-For PNG screenshot, libPNG, and Zlib (from http://gnuwin32.sourceforge.net/)
-
-No warranty, support, etc. of any kind is offered,
-just plain old as is.
-Some bits of code are still really scary.
-Go nuts!
-
-
-Win32 with Dev-C++ (http://bloodshed.net/ free!)
-~~~
-2 Dev-C++ project files are included:
-
-Win32/DirectX/FMOD
-src\win32\SRB2.dev
-or
-Win32/SDL/SDL_mixer
-src\sdl\Win32SDL.dev
-You'll need SDL and SDL_mixer for this version (www.libsdl.org)
-libPNG and Zlib (from http://gnuwin32.sourceforge.net/)
-Note there are precompiled libpng.a and libz.a for Mingw
-
-you will need NASM for both SDL/SDL_mixer and DirectX/FMOD
-and you need DirectX 6 (or up) Dev-Paks to compile DirectX version
-
-GNU/Linux
-~~~
-
-Dependencies:
-  SDL 1.2.7 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-make -C src LINUX=1
-
-Build instructions (64 bit):
-
-make -C src LINUX64=1
-
-Build instructions to build for Wii Linux/SRB2Wii on a PowerPC system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src LINUX=1 WIILINUX=1
-
-Build instructions to build for Pandora (Linux) on a ARM system,
-follow cross-compiling instructions for cross-compiling on a x86 system:
-
-make -C src PANDORA=1
-
-Solaris
-~~~
-
-Dependencies:
-  SDL 1.2.5 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-  You can get all these programs/libraries from the Companion CD (except SDL_mixer and OpenGL)
-
-Build instructions:
-
-gmake -C src SOLARIS=1
-
-FreeBSD
-~~~
-
-Dependencies:
-  SDL 1.2.7 or better (from libsdl.org)
-  SDL_Mixer 1.2.2(.7 for file-less music playback) (from libsdl.org)
-  Nasm (use NOASM=1 if you don't have it or have an non-i386 system, I think)
-  libPNG 1.2.7
-  Zlib 1.2.3
-  The Xiph.org libogg and libvorbis libraries
-  The OpenGL headers (from Mesa, usually shipped with your X.org or XFree
-    installation, so you needn't worry, most likely)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-gmake -C src FREEBSD=1
-
-DJGPP/DOS
-~~~
-
-Dependencies:
-  Allegro 3.12 game programming library, (from
-  http://alleg.sourceforge.net/index.html)
-  Nasm (use NOASM=1 if you don't have it)
-  libsocket (from http://homepages.nildram.co.uk/~phekda/richdawe/lsck/) or
-  Watt-32 (from http://www.bgnett.no/~giva/)
-  GCC 3.x toolchain and binutils
-  GNU Make
-
-Build instructions:
-
-make -C src # to link with Watt-32, add WATTCP=1
-      # for remote debugging over the COM port, add RDB=1
-
-Notes:
- use tools\djgpp\all313.diff to update Allegro to a "more usable" version ;)
- Example: E:\djgpp\allegro>patch -p# < D:\SRB2Code\1.1\srb2\tools\djgpp\all313.diff
-
-Windows CE
-~~~
-
-Dependencies:
-  SDL 1.27
-
-Build instructions:
-
-use src\SDL\WinCE\SRB2CE.vcw
-
--------------------------------------------------------------------------------
-
-binaries will turn in up in bin/
-
-note: read the src/makefile for more options
-
-- Sonic Team Junior
-http://www.srb2.org
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 035b4655699bdf4c6d2830d6ab8dc358360948d1..46a42a92c7f06b826b1881cda6f5c4696d86ce67 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ set(SRB2_CORE_SOURCES
 	i_tcp.c
 	info.c
 	lzf.c
+	m_aatree.c
 	m_anigif.c
 	m_argv.c
 	m_bbox.c
@@ -83,6 +84,7 @@ set(SRB2_CORE_HEADERS
 	info.h
 	keys.h
 	lzf.h
+	m_aatree.h
 	m_anigif.h
 	m_argv.h
 	m_bbox.h
@@ -388,18 +390,25 @@ if(${SRB2_CONFIG_HWRENDER} AND ${SRB2_CONFIG_STATIC_OPENGL})
 endif()
 
 if(${SRB2_CONFIG_USEASM})
+	#SRB2_ASM_FLAGS can be used to pass flags to either nasm or yasm.
+	if(${CMAKE_SYSTEM} MATCHES "Linux")
+		set(SRB2_ASM_FLAGS "-DLINUX ${SRB2_ASM_FLAGS}")
+	endif()
+
 	if(${SRB2_CONFIG_YASM})
 		set(CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_YASM_SOURCE_FILE_EXTENSIONS} nas)
+		set(CMAKE_ASM_YASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
 		enable_language(ASM_YASM)
 	else()
 		set(CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS ${CMAKE_ASM_NASM_SOURCE_FILE_EXTENSIONS} nas)
+		set(CMAKE_ASM_NASM_FLAGS "${SRB2_ASM_FLAGS}" CACHE STRING "Flags used by the assembler during all build types.")
 		enable_language(ASM_NASM)
 	endif()
 	set(SRB2_USEASM ON)
 	add_definitions(-DUSEASM)
 else()
 	set(SRB2_USEASM OFF)
-	add_definitions(-DNOASM -DNONX86)
+	add_definitions(-DNONX86 -DNORUSEASM)
 endif()
 
 # Targets
diff --git a/src/Makefile b/src/Makefile
index f7a8c1b85effd05aa269687578e9ec39a085e808..426dc22898716a92ce7e6bc4330616939ad479a6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -179,6 +179,9 @@ endif
 
 ifdef LINUX
 UNIXCOMMON=1
+ifndef NOGME
+HAVE_LIBGME=1
+endif
 endif
 
 ifdef SOLARIS
@@ -189,6 +192,10 @@ ifdef FREEBSD
 UNIXCOMMON=1
 endif
 
+ifdef MACOSX
+UNIXCOMMON=1
+endif
+
 ifdef NDS
 NOPNG=1
 NONET=1
@@ -311,6 +318,13 @@ LIBS+=$(PNG_LDFLAGS)
 CFLAGS+=$(PNG_CFLAGS)
 endif
 
+ZLIB_PKGCONFIG?=zlib
+ZLIB_CFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --cflags)
+ZLIB_LDFLAGS?=$(shell $(PKG_CONFIG) $(ZLIB_PKGCONFIG) --libs)
+
+LIBS+=$(ZLIB_LDFLAGS)
+CFLAGS+=$(ZLIB_CFLAGS)
+
 ifdef HAVE_LIBGME
 OPTS+=-DHAVE_LIBGME
 
@@ -362,6 +376,14 @@ endif
 
 	OPTS:=-fno-exceptions $(OPTS)
 
+ifdef MOBJCONSISTANCY
+	OPTS+=-DMOBJCONSISTANCY
+endif
+
+ifdef PACKETDROP
+	OPTS+=-DPACKETDROP
+endif
+
 ifdef DEBUGMODE
 
 	# build with debugging information
@@ -371,7 +393,7 @@ ifdef GCC48
 else
 	CFLAGS+=-O0
 endif
-	CFLAGS+= -Wall -DPARANOIA -DRANGECHECK
+	CFLAGS+= -Wall -DPARANOIA -DRANGECHECK -DPACKETDROP -DMOBJCONSISTANCY
 else
 
 
@@ -429,6 +451,7 @@ OBJS:=$(i_main_o) \
 		$(OBJDIR)/hu_stuff.o \
 		$(OBJDIR)/y_inter.o  \
 		$(OBJDIR)/st_stuff.o \
+		$(OBJDIR)/m_aatree.o \
 		$(OBJDIR)/m_anigif.o \
 		$(OBJDIR)/m_argv.o   \
 		$(OBJDIR)/m_bbox.o   \
@@ -488,13 +511,11 @@ OBJS:=$(i_main_o) \
 # For reference, this is the command I use to build a srb2.pot file from the source code.
 # (The listed source files are the ones containing translated strings).
 # FILES=""; for file in `find ./ | grep "\.c" | grep -v svn`; do [ "`grep "M_GetText(" $file`" ] && FILES="$FILES $file"; done; xgettext -d srb2 -o locale/srb2.pot -kM_GetText -F --no-wrap $FILES
-ifndef NOGETTEXT
 ifdef GETTEXT
 POS:=$(BIN)/en.mo
 
 OPTS+=-DGETTEXT
 endif
-endif
 
 ifdef DJGPPDOS
 all:	 pre-build $(BIN)/$(EXENAME)
@@ -593,11 +614,15 @@ ifndef WINDOWSHELL
 	-$(GZIP) $(GZIP_OPT2) $(BIN)/$(DBGNAME).txt
 endif
 endif
+
+# mac os x lsdlsrb2 does not like objcopy
+ifndef MACOSX
 ifndef PSP
 	$(OBJCOPY) $(BIN)/$(EXENAME) $(BIN)/$(DBGNAME)
 	$(OBJCOPY) --strip-debug $(BIN)/$(EXENAME)
 	-$(OBJCOPY) --add-gnu-debuglink=$(BIN)/$(DBGNAME) $(BIN)/$(EXENAME)
 endif
+endif
 ifndef NOUPX
 	-$(UPX) $(UPX_OPTS) $(BIN)/$(EXENAME)
 endif
@@ -745,6 +770,11 @@ $(OBJDIR)/%.o: %.c
 $(OBJDIR)/%.o: $(INTERFACE)/%.c
 	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
 
+ifdef MACOSX
+$(OBJDIR)/%.o: sdl/macosx/%.c
+	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
+endif
+
 $(OBJDIR)/%.o: hardware/%.c
 	$(CC) $(CFLAGS) $(WFLAGS) -c $< -o $@
 
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 347efa5e4450651d679cec537522a9dd4c21d51b..5bf7f247dfc6c0f0dea25405eaa4eb8e36f8e75b 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -7,6 +7,23 @@
 # and other things
 #
 
+
+ifdef GCC63
+GCC62=1
+endif
+
+ifdef GCC62
+GCC61=1
+endif
+
+ifdef GCC61
+GCC54=1
+endif
+
+ifdef GCC54
+GCC53=1
+endif
+
 ifdef GCC53
 GCC52=1
 endif
@@ -164,19 +181,29 @@ ifdef GCC45
 WFLAGS+=-Wunsuffixed-float-constants
 endif
 endif
+
 ifdef NOLDWARNING
 LDFLAGS+=-Wl,--as-needed
 endif
+
 ifdef ERRORMODE
 WFLAGS+=-Werror
 endif
+
+WFLAGS+=$(OLDWFLAGS)
+
 ifdef GCC43
  #WFLAGS+=-Wno-error=clobbered
 endif
 ifdef GCC46
  WFLAGS+=-Wno-error=suggest-attribute=noreturn
 endif
-WFLAGS+=$(OLDWFLAGS)
+ifdef GCC54
+ WFLAGS+=-Wno-logical-op -Wno-error=logical-op
+endif
+ifdef GCC61
+ WFLAGS+=-Wno-tautological-compare -Wno-error=tautological-compare
+endif
 
 
 #indicate platform and what interface use with
@@ -256,9 +283,6 @@ else
 ifdef LINUX
 	NASMFORMAT=elf -DLINUX
 	SDL=1
-ifndef NOGETTEXT
-	GETTEXT=1
-endif
 ifdef LINUX64
 	OBJDIR:=$(OBJDIR)/Linux64
 	BIN:=$(BIN)/Linux64
@@ -294,9 +318,6 @@ else
 ifdef MINGW64
 	INTERFACE=win32
 	#NASMFORMAT=win64
-ifndef NOGETTEXT
-	#GETTEXT=1
-endif
 	OBJDIR:=$(OBJDIR)/Mingw64
 	BIN:=$(BIN)/Mingw64
 else
@@ -327,9 +348,6 @@ else
 ifdef MINGW
 	INTERFACE=win32
 	NASMFORMAT=win32
-ifndef NOGETTEXT
-	GETTEXT=1
-endif
 	OBJDIR:=$(OBJDIR)/Mingw
 	BIN:=$(BIN)/Mingw
 else
@@ -406,6 +424,15 @@ else
 	WINDRES=windres
 endif
 
+# because Apple screws with us on this
+# need to get bintools from homebrew
+ifdef MACOSX
+	CC=clang
+	CXX=clang
+	OBJCOPY=gobjcopy
+	OBJDUMP=gobjdump
+endif
+
 OBJDUMP_OPTS?=--wide --source --line-numbers
 LD=$(CC)
 
diff --git a/src/android/i_system.c b/src/android/i_system.c
index 150cbd505c1d40b40c1e5ac69bc911ec8eb849df..58fca7c1943448ff81ede9a67854f3791c93bc00 100644
--- a/src/android/i_system.c
+++ b/src/android/i_system.c
@@ -258,6 +258,18 @@ INT32 I_PutEnv(char *variable)
   return -1;
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 void I_RegisterSysCommands(void) {}
 
 #include "../sdl/dosstr.c"
diff --git a/src/blua/lvm.c b/src/blua/lvm.c
index a921d443773b90a83bc741f6b0b54646f85f6a1a..b654613f422550956782923e5a348b21acf1a821 100644
--- a/src/blua/lvm.c
+++ b/src/blua/lvm.c
@@ -732,7 +732,8 @@ void luaV_execute (lua_State *L, int nexeccalls) {
           luaG_runerror(L, LUA_QL("for") " limit must be a number");
         else if (!tonumber(pstep, ra+2))
           luaG_runerror(L, LUA_QL("for") " step must be a number");
-        setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
+        if (ra && pstep)
+          setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
         dojump(L, pc, GETARG_sBx(i));
         continue;
       }
diff --git a/src/command.c b/src/command.c
index 84d777acf30c8056f6b63676296867dbf158856d..a15471c8304ee5b0b3cc084aa64aa7dc7e1f9925 100644
--- a/src/command.c
+++ b/src/command.c
@@ -966,9 +966,11 @@ void CV_RegisterVar(consvar_t *variable)
 	// check net variables
 	if (variable->flags & CV_NETVAR)
 	{
+		const consvar_t *netvar;
 		variable->netid = CV_ComputeNetid(variable->name);
-		if (CV_FindNetVar(variable->netid))
-			I_Error("Variables %s and %s have same netid\n", variable->name, CV_FindNetVar(variable->netid)->name);
+		netvar = CV_FindNetVar(variable->netid);
+		if (netvar)
+			I_Error("Variables %s and %s have same netid\n", variable->name, netvar->name);
 	}
 
 	// link the variable in
diff --git a/src/console.c b/src/console.c
index 025bc1c19f2068812cf14ade4740eaeeaa3587c7..70f8ab6f8db5923b4a81e5d7768510ff0e81137b 100644
--- a/src/console.c
+++ b/src/console.c
@@ -84,19 +84,23 @@ UINT32 con_scalefactor;            // text size scale factor
 
 // hold 32 last lines of input for history
 #define CON_MAXPROMPTCHARS 256
-#define CON_PROMPTCHAR '>'
+#define CON_PROMPTCHAR '$'
 
 static char inputlines[32][CON_MAXPROMPTCHARS]; // hold last 32 prompt lines
 
 static INT32 inputline;    // current input line number
 static INT32 inputhist;    // line number of history input line to restore
-static size_t input_cx;  // position in current input line
+static size_t input_cur; // position of cursor in line
+static size_t input_sel; // position of selection marker (I.E.: anything between this and input_cur is "selected")
+static size_t input_len; // length of current line, used to bound cursor and such
+// notice: input does NOT include the "$" at the start of the line. - 11/3/16
 
 // protos.
 static void CON_InputInit(void);
 static void CON_RecalcSize(void);
 
 static void CONS_hudlines_Change(void);
+static void CONS_backcolor_Change(void);
 static void CON_DrawBackpic(patch_t *pic, INT32 startx, INT32 destwidth);
 //static void CON_DrawBackpic2(pic_t *pic, INT32 startx, INT32 destwidth);
 
@@ -129,10 +133,11 @@ static CV_PossibleValue_t backpic_cons_t[] = {{0, "translucent"}, {1, "picture"}
 // whether to use console background picture, or translucent mode
 static consvar_t cons_backpic = {"con_backpic", "translucent", CV_SAVE, backpic_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, {1, "Orange"},
-												{2, "Blue"}, {3, "Green"}, {4, "Gray"},
-												{5, "Red"}, {0, NULL}};
-consvar_t cons_backcolor = {"con_backcolor", "3", CV_SAVE, backcolor_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t backcolor_cons_t[] = {{0, "White"}, 	{1, "Gray"},	{2, "Brown"},
+												{3, "Red"},		{4, "Orange"},	{5, "Yellow"},
+												{6, "Green"},	{7, "Blue"},	{8,	"Cyan"},
+												{0, NULL}};
+consvar_t cons_backcolor = {"con_backcolor", "Green", CV_CALL|CV_SAVE, backcolor_cons_t, CONS_backcolor_Change, 0, NULL, NULL, 0, 0, NULL};
 
 static void CON_Print(char *msg);
 
@@ -219,8 +224,9 @@ static void CONS_Bind_f(void)
 //                          CONSOLE SETUP
 //======================================================================
 
-// Prepare a colormap for GREEN ONLY translucency over background
-//
+// Font colormap colors
+// TODO: This could probably be improved somehow...
+// These colormaps are 99% identical, with just a few changed bytes
 UINT8 *yellowmap;
 UINT8 *purplemap;
 UINT8 *lgreenmap;
@@ -229,44 +235,49 @@ UINT8 *graymap;
 UINT8 *redmap;
 UINT8 *orangemap;
 
-// Console BG colors
-UINT8 *cwhitemap;
-UINT8 *corangemap;
-UINT8 *cbluemap;
-UINT8 *cgreenmap;
-UINT8 *cgraymap;
-UINT8 *credmap;
+// Console BG color
+UINT8 *consolebgmap = NULL;
 
-void CON_ReSetupBackColormap(UINT16 num)
+void CON_SetupBackColormap(void)
 {
-	UINT16 i, j;
-	UINT8 k;
-	UINT8 *pal = W_CacheLumpName(R_GetPalname(num), PU_CACHE);
+	UINT16 i, palsum;
+	UINT8 j, palindex;
+	UINT8 *pal = W_CacheLumpName(GetPalette(), PU_CACHE);
+
+	if (!consolebgmap)
+		consolebgmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
+
+	switch (cons_backcolor.value)
+	{
+		case 0:		palindex = 15; 	break; // White
+		case 1:		palindex = 31;	break; // Gray
+		case 2:		palindex = 63;	break; // Brown
+		case 3:		palindex = 143;	break; // Red
+		case 4:		palindex = 95;	break; // Orange
+		case 5:		palindex = 111;	break; // Yellow
+		case 6:		palindex = 175;	break; // Green
+		case 7:		palindex = 239;	break; // Blue
+		case 8:		palindex = 219;	break; // Cyan
+		// Default green
+		default:	palindex = 175; break;
+}
 
-	// setup the green translucent background colormaps
-	for (i = 0, k = 0; i < 768; i += 3, k++)
+	// setup background colormap
+	for (i = 0, j = 0; i < 768; i += 3, j++)
 	{
-		j = pal[i] + pal[i+1] + pal[i+2];
-		cwhitemap[k] = (UINT8)(15 - (j>>6));
-		corangemap[k] = (UINT8)(95 - (j>>6));
-		cbluemap[k] = (UINT8)(239 - (j>>6));
-		cgreenmap[k] = (UINT8)(175 - (j>>6));
-		cgraymap[k] = (UINT8)(31 - (j>>6));
-		credmap[k] = (UINT8)(143 - (j>>6));
+		palsum = (pal[i] + pal[i+1] + pal[i+2]) >> 6;
+		consolebgmap[j] = (UINT8)(palindex - palsum);
 	}
 }
 
-static void CON_SetupBackColormap(void)
+static void CONS_backcolor_Change(void)
 {
-	INT32 i, j, k;
-	UINT8 *pal;
+	CON_SetupBackColormap();
+}
 
-	cwhitemap   = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
-	corangemap  = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
-	cbluemap    = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
-	cgreenmap   = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
-	cgraymap    = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
-	credmap     = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
+static void CON_SetupColormaps(void)
+{
+	INT32 i;
 
 	yellowmap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
 	graymap   = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
@@ -276,20 +287,6 @@ static void CON_SetupBackColormap(void)
 	redmap    = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
 	orangemap = (UINT8 *)Z_Malloc(256, PU_STATIC, NULL);
 
-	pal = W_CacheLumpName("PLAYPAL", PU_CACHE);
-
-	// setup the green translucent background colormaps
-	for (i = 0, k = 0; i < 768; i += 3, k++)
-	{
-		j = pal[i] + pal[i+1] + pal[i+2];
-		cwhitemap[k] = (UINT8)(15 - (j>>6));
-		corangemap[k] = (UINT8)(95 - (j>>6));
-		cbluemap[k] = (UINT8)(239 - (j>>6));
-		cgreenmap[k] = (UINT8)(175 - (j>>6));
-		cgraymap[k] = (UINT8)(31 - (j>>6));
-		credmap[k] = (UINT8)(143 - (j>>6));
-	}
-
 	// setup the other colormaps, for console text
 
 	// these don't need to be aligned, unless you convert the
@@ -320,6 +317,9 @@ static void CON_SetupBackColormap(void)
 	redmap[9]    = (UINT8)127;
 	orangemap[3] = (UINT8)85;
 	orangemap[9] = (UINT8)90;
+
+	// Init back colormap
+	CON_SetupBackColormap();
 }
 
 // Setup the console text buffer
@@ -343,7 +343,7 @@ void CON_Init(void)
 	con_width = 0;
 	CON_RecalcSize();
 
-	CON_SetupBackColormap();
+	CON_SetupColormaps();
 
 	//note: CON_Ticker should always execute at least once before D_Display()
 	con_clipviewtop = -1; // -1 does not clip
@@ -386,14 +386,10 @@ void CON_Init(void)
 //
 static void CON_InputInit(void)
 {
-	INT32 i;
-
 	// prepare the first prompt line
 	memset(inputlines, 0, sizeof (inputlines));
-	for (i = 0; i < 32; i++)
-		inputlines[i][0] = CON_PROMPTCHAR;
 	inputline = 0;
-	input_cx = 1;
+	input_cur = input_sel = input_len = 0;
 }
 
 //======================================================================
@@ -618,13 +614,91 @@ void CON_Ticker(void)
 	}
 }
 
+//
+// ----
+//
+// Shortcuts for adding and deleting characters, strings, and sections
+// Necessary due to moving cursor
+//
+
+static void CON_InputClear(void)
+{
+	memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+	input_cur = input_sel = input_len = 0;
+}
+
+static void CON_InputSetString(const char *c)
+{
+	memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+	strcpy(inputlines[inputline], c);
+	input_cur = input_sel = input_len = strlen(c);
+}
+
+static void CON_InputAddString(const char *c)
+{
+	size_t csize = strlen(c);
+	if (input_len + csize > CON_MAXPROMPTCHARS-1)
+		return;
+	if (input_cur != input_len)
+		memmove(&inputlines[inputline][input_cur+csize], &inputlines[inputline][input_cur], input_len-input_cur);
+	memcpy(&inputlines[inputline][input_cur], c, csize);
+	input_len += csize;
+	input_sel = (input_cur += csize);
+}
+
+static void CON_InputDelSelection(void)
+{
+	size_t start, end, len;
+	if (input_cur > input_sel)
+	{
+		start = input_sel;
+		end = input_cur;
+	}
+	else
+	{
+		start = input_cur;
+		end = input_sel;
+	}
+	len = (end - start);
+
+	if (end != input_len)
+		memmove(&inputlines[inputline][start], &inputlines[inputline][end], input_len-end);
+	memset(&inputlines[inputline][input_len - len], 0, len);
+
+	input_len -= len;
+	input_sel = input_cur = start;
+}
+
+static void CON_InputAddChar(char c)
+{
+	if (input_len >= CON_MAXPROMPTCHARS-1)
+		return;
+	if (input_cur != input_len)
+		memmove(&inputlines[inputline][input_cur+1], &inputlines[inputline][input_cur], input_len-input_cur);
+	inputlines[inputline][input_cur++] = c;
+	inputlines[inputline][++input_len] = 0;
+	input_sel = input_cur;
+}
+
+static void CON_InputDelChar(void)
+{
+	if (!input_cur)
+		return;
+	if (input_cur != input_len)
+		memmove(&inputlines[inputline][input_cur-1], &inputlines[inputline][input_cur], input_len-input_cur);
+	inputlines[inputline][--input_len] = 0;
+	input_sel = --input_cur;
+}
+
+//
+// ----
+//
+
 // Handles console key input
 //
 boolean CON_Responder(event_t *ev)
 {
-	static boolean consdown;
-	static boolean shiftdown;
-	static boolean ctrldown;
+	static UINT8 consdown = false; // console is treated differently due to rare usage
 
 	// sequential completions a la 4dos
 	static char completion[80];
@@ -639,13 +713,8 @@ boolean CON_Responder(event_t *ev)
 	// let go keyup events, don't eat them
 	if (ev->type != ev_keydown && ev->type != ev_console)
 	{
-		if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
-			shiftdown = false;
-		else if (ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL)
-			ctrldown = false;
-		else if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
+		if (ev->data1 == gamecontrol[gc_console][0] || ev->data1 == gamecontrol[gc_console][1])
 			consdown = false;
-
 		return false;
 	}
 
@@ -684,94 +753,110 @@ boolean CON_Responder(event_t *ev)
 			consoletoggle = true;
 			return true;
 		}
-
-	}
-
-	// eat shift only if console active
-	if (key == KEY_LSHIFT || key == KEY_RSHIFT)
-	{
-		shiftdown = true;
-		return true;
 	}
 
-	// same for ctrl
-	if (key == KEY_LCTRL || key == KEY_RCTRL)
-	{
-		ctrldown = true;
+	// Always eat ctrl/shift/alt if console open, so the menu doesn't get ideas
+	if (key == KEY_LSHIFT || key == KEY_RSHIFT
+	 || key == KEY_LCTRL || key == KEY_RCTRL
+	 || key == KEY_LALT || key == KEY_RALT)
 		return true;
-	}
 
-	// command completion forward (tab) and backward (shift-tab)
-	if (key == KEY_TAB)
+	// ctrl modifier -- changes behavior, adds shortcuts
+	if (ctrldown)
 	{
 		// show all cvars/commands that match what we have inputted
-		if (ctrldown)
+		if (key == KEY_TAB)
 		{
-			UINT32 i;
-			size_t stop = input_cx - 1;
-			char nameremainder[255];
+			size_t i, len;
 
-			if (input_cx < 2 || strlen(inputlines[inputline]+1) >= 80)
-				return true;
-
-			strcpy(completion, inputlines[inputline]+1);
-
-			// trimming: stop at the first newline
-			for (i = 0; i < input_cx - 1; ++i)
+			if (!completion[0])
 			{
-				if (completion[i] == ' ')
-				{
-					completion[i] = '\0';
-					stop = i;
-					break;
-				}
+				if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
+					return true;
+				strcpy(completion, inputlines[inputline]);
+				comskips = varskips = 0;
 			}
-
-			i = 0;
+			len = strlen(completion);
 
 			//first check commands
 			CONS_Printf("\nCommands:\n");
-
-			for (cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, i))
-			{
-				strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
-				nameremainder[strlen(cmd)-(stop)] = '\0';
-
-				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, nameremainder);
-				++i;
-			}
-			if (i == 0)
-				CONS_Printf("  (none)\n");
-
-			i = 0;
+			for (i = 0, cmd = COM_CompleteCommand(completion, i); cmd; cmd = COM_CompleteCommand(completion, ++i))
+				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, cmd+len);
+			if (i == 0) CONS_Printf("  (none)\n");
 
 			//now we move on to CVARs
 			CONS_Printf("Variables:\n");
+			for (i = 0, cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, ++i))
+				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, cmd+len);
+			if (i == 0) CONS_Printf("  (none)\n");
 
-			for (cmd = CV_CompleteVar(completion, i); cmd; cmd = CV_CompleteVar(completion, i))
-			{
-				strncpy(nameremainder, cmd+(stop), strlen(cmd)-(stop));
-				nameremainder[strlen(cmd)-(stop)] = '\0';
+			return true;
+		}
+		// ---
 
-				CONS_Printf("  \x83" "%s" "\x80" "%s\n", completion, nameremainder);
-				++i;
-			}
-			if (i == 0)
-				CONS_Printf("  (none)\n");
+		if (key == KEY_HOME) // oldest text in buffer
+		{
+			con_scrollup = (con_totallines-((con_curlines-16)>>3));
+			return true;
+		}
+		else if (key == KEY_END) // most recent text in buffer
+		{
+			con_scrollup = 0;
+			return true;
+		}
 
+		if (key == 'x' || key == 'X')
+		{
+			if (input_sel > input_cur)
+				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
+			else
+				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
+			CON_InputDelSelection();
+			completion[0] = 0;
+			return true;
+		}
+		else if (key == 'c' || key == 'C')
+		{
+			if (input_sel > input_cur)
+				I_ClipboardCopy(&inputlines[inputline][input_cur], input_sel-input_cur);
+			else
+				I_ClipboardCopy(&inputlines[inputline][input_sel], input_cur-input_sel);
+			return true;
+		}
+		else if (key == 'v' || key == 'V')
+		{
+			const char *paste = I_ClipboardPaste();
+			if (input_sel != input_cur)
+				CON_InputDelSelection();
+			if (paste != NULL)
+				CON_InputAddString(paste);
+			completion[0] = 0;
 			return true;
 		}
 
+		// Select all
+		if (key == 'a' || key == 'A')
+		{
+			input_sel = 0;
+			input_cur = input_len;
+			return true;
+		}
+
+		// don't eat the key
+		return false;
+	}
+
+	// command completion forward (tab) and backward (shift-tab)
+	if (key == KEY_TAB)
+	{
 		// sequential command completion forward and backward
 
 		// remember typing for several completions (a-la-4dos)
-		if (inputlines[inputline][input_cx-1] != ' ')
+		if (!completion[0])
 		{
-			if (strlen(inputlines[inputline]+1) < 80)
-				strcpy(completion, inputlines[inputline]+1);
-			else
-				completion[0] = 0;
-
+			if (!input_len || input_len >= 40 || strchr(inputlines[inputline], ' '))
+				return true;
+			strcpy(completion, inputlines[inputline]);
 			comskips = varskips = 0;
 		}
 		else
@@ -783,37 +868,26 @@ boolean CON_Responder(event_t *ev)
 					if (--varskips < 0)
 						comskips = -comskips - 2;
 				}
-				else if (comskips > 0)
-					comskips--;
+				else if (comskips > 0) comskips--;
 			}
 			else
 			{
-				if (comskips < 0)
-					varskips++;
-				else
-					comskips++;
+				if (comskips < 0) varskips++;
+				else              comskips++;
 			}
 		}
 
 		if (comskips >= 0)
 		{
 			cmd = COM_CompleteCommand(completion, comskips);
-			if (!cmd)
-				// dirty: make sure if comskips is zero, to have a neg value
+			if (!cmd) // dirty: make sure if comskips is zero, to have a neg value
 				comskips = -comskips - 1;
 		}
 		if (comskips < 0)
 			cmd = CV_CompleteVar(completion, varskips);
 
 		if (cmd)
-		{
-			memset(inputlines[inputline]+1, 0, CON_MAXPROMPTCHARS-1);
-			strcpy(inputlines[inputline]+1, cmd);
-			input_cx = strlen(cmd) + 1;
-			inputlines[inputline][input_cx] = ' ';
-			input_cx++;
-			inputlines[inputline][input_cx] = 0;
-		}
+			CON_InputSetString(va("%s ", cmd));
 		else
 		{
 			if (comskips > 0)
@@ -839,47 +913,80 @@ boolean CON_Responder(event_t *ev)
 		return true;
 	}
 
-	if (key == KEY_HOME) // oldest text in buffer
+	if (key == KEY_LEFTARROW)
+	{
+		if (input_cur != 0)
+			--input_cur;
+		if (!shiftdown)
+			input_sel = input_cur;
+		return true;
+	}
+	else if (key == KEY_RIGHTARROW)
+	{
+		if (input_cur < input_len)
+			++input_cur;
+		if (!shiftdown)
+			input_sel = input_cur;
+		return true;
+	}
+	else if (key == KEY_HOME)
 	{
-		con_scrollup = (con_totallines-((con_curlines-16)>>3));
+		input_cur = 0;
+		if (!shiftdown)
+			input_sel = input_cur;
 		return true;
 	}
-	else if (key == KEY_END) // most recent text in buffer
+	else if (key == KEY_END)
 	{
-		con_scrollup = 0;
+		input_cur = input_len;
+		if (!shiftdown)
+			input_sel = input_cur;
 		return true;
 	}
 
+	// At this point we're messing with input
+	// Clear completion
+	completion[0] = 0;
+
 	// command enter
 	if (key == KEY_ENTER)
 	{
-		if (input_cx < 2)
+		if (!input_len)
 			return true;
 
 		// push the command
-		COM_BufAddText(inputlines[inputline]+1);
+		COM_BufAddText(inputlines[inputline]);
 		COM_BufAddText("\n");
 
-		CONS_Printf("%s\n", inputlines[inputline]);
+		CONS_Printf("\x86""%c""\x80""%s\n", CON_PROMPTCHAR, inputlines[inputline]);
 
 		inputline = (inputline+1) & 31;
 		inputhist = inputline;
-
-		memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
-		inputlines[inputline][0] = CON_PROMPTCHAR;
-		input_cx = 1;
+		CON_InputClear();
 
 		return true;
 	}
 
-	// backspace command prompt
-	if (key == KEY_BACKSPACE)
+	// backspace and delete command prompt
+	if (input_sel != input_cur)
 	{
-		if (input_cx > 1)
+		if (key == KEY_BACKSPACE || key == KEY_DEL)
 		{
-			input_cx--;
-			inputlines[inputline][input_cx] = 0;
+			CON_InputDelSelection();
+			return true;
 		}
+	}
+	else if (key == KEY_BACKSPACE)
+	{
+		CON_InputDelChar();
+		return true;
+	}
+	else if (key == KEY_DEL)
+	{
+		if (input_cur == input_len)
+			return true;
+		++input_cur;
+		CON_InputDelChar();
 		return true;
 	}
 
@@ -888,18 +995,15 @@ boolean CON_Responder(event_t *ev)
 	{
 		// copy one of the previous inputlines to the current
 		do
-		{
 			inputhist = (inputhist - 1) & 31; // cycle back
-		} while (inputhist != inputline && !inputlines[inputhist][1]);
+		while (inputhist != inputline && !inputlines[inputhist][0]);
 
 		// stop at the last history input line, which is the
 		// current line + 1 because we cycle through the 32 input lines
 		if (inputhist == inputline)
 			inputhist = (inputline + 1) & 31;
 
-		M_Memcpy(inputlines[inputline], inputlines[inputhist], CON_MAXPROMPTCHARS);
-		input_cx = strlen(inputlines[inputline]);
-
+		CON_InputSetString(inputlines[inputhist]);
 		return true;
 	}
 
@@ -909,23 +1013,14 @@ boolean CON_Responder(event_t *ev)
 		if (inputhist == inputline)
 			return true;
 		do
-		{
 			inputhist = (inputhist + 1) & 31;
-		} while (inputhist != inputline && !inputlines[inputhist][1]);
-
-		memset(inputlines[inputline], 0, CON_MAXPROMPTCHARS);
+		while (inputhist != inputline && !inputlines[inputhist][0]);
 
 		// back to currentline
 		if (inputhist == inputline)
-		{
-			inputlines[inputline][0] = CON_PROMPTCHAR;
-			input_cx = 1;
-		}
+			CON_InputClear();
 		else
-		{
-			strcpy(inputlines[inputline], inputlines[inputhist]);
-			input_cx = strlen(inputlines[inputline]);
-		}
+			CON_InputSetString(inputlines[inputhist]);
 		return true;
 	}
 
@@ -950,15 +1045,12 @@ boolean CON_Responder(event_t *ev)
 		return false;
 
 	// add key to cmd line here
-	if (input_cx < CON_MAXPROMPTCHARS)
-	{
-		if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
-			key = key + 'a' - 'A';
+	if (key >= 'A' && key <= 'Z' && !shiftdown) //this is only really necessary for dedicated servers
+		key = key + 'a' - 'A';
 
-		inputlines[inputline][input_cx] = (char)key;
-		inputlines[inputline][input_cx + 1] = 0;
-		input_cx++;
-	}
+	if (input_sel != input_cur)
+		CON_InputDelSelection();
+	CON_InputAddChar(key);
 
 	return true;
 }
@@ -1242,26 +1334,89 @@ void CONS_Error(const char *msg)
 //
 static void CON_DrawInput(void)
 {
-	char *p;
-	size_t c;
-	INT32 x, y;
 	INT32 charwidth = (INT32)con_scalefactor << 3;
-
-	// input line scrolls left if it gets too long
-	p = inputlines[inputline];
-	if (input_cx >= con_width-11)
-		p += input_cx - (con_width-11) + 1;
+	const char *p = inputlines[inputline];
+	size_t c, clen, cend;
+	UINT8 lellip = 0, rellip = 0;
+	INT32 x, y, i;
 
 	y = con_curlines - 12 * con_scalefactor;
+	x = charwidth*2;
 
-	for (c = 0, x = charwidth; c < con_width-11; c++, x += charwidth)
-		V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+	clen = con_width-13;
 
-	// draw the blinking cursor
-	//
-	x = ((input_cx >= con_width-11) ? (INT32)(con_width-11) : (INT32)((input_cx + 1)) * charwidth);
-	if (con_tick < 4)
-		V_DrawCharacter(x, y, '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+	if (input_len <= clen)
+	{
+		c = 0;
+		clen = input_len;
+	}
+	else // input line scrolls left if it gets too long
+	{
+		clen -= 2; // There will always be some extra truncation -- but where is what we'll find out
+
+		if (input_cur <= clen/2)
+		{
+			// Close enough to right edge to show all
+			c = 0;
+			// Always will truncate right side from this position, so always draw right ellipsis
+			rellip = 1;
+		}
+		else
+		{
+			// Cursor in the middle (or right side) of input
+			// Move over for the ellipsis
+			c = input_cur - (clen/2) + 2;
+			x += charwidth*2;
+			lellip = 1;
+
+			if (c + clen >= input_len)
+			{
+				// Cursor in the right side of input
+				// We were too far over, so move back
+				c = input_len - clen;
+			}
+			else
+			{
+				// Cursor in the middle -- ellipses on both sides
+				clen -= 2;
+				rellip = 1;
+			}
+		}
+	}
+
+	if (lellip)
+	{
+		x -= charwidth*3;
+		if (input_sel < c)
+			V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+		for (i = 0; i < 3; ++i, x += charwidth)
+			V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+	}
+	else
+		V_DrawCharacter(x-charwidth, y, CON_PROMPTCHAR | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+
+	for (cend = c + clen; c < cend; ++c, x += charwidth)
+	{
+		if ((input_sel > c && input_cur <= c) || (input_sel <= c && input_cur > c))
+		{
+			V_DrawFill(x, y, charwidth, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+			V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_YELLOWMAP | V_NOSCALESTART, !cv_allcaps.value);
+		}
+		else
+			V_DrawCharacter(x, y, p[c] | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+
+		if (c == input_cur && con_tick >= 4)
+			V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+	}
+	if (cend == input_cur && con_tick >= 4)
+		V_DrawCharacter(x, y + (con_scalefactor*2), '_' | cv_constextsize.value | V_NOSCALESTART, !cv_allcaps.value);
+	if (rellip)
+	{
+		if (input_sel > cend)
+			V_DrawFill(x, y, charwidth*3, (10 * con_scalefactor), 107 | V_NOSCALESTART);
+		for (i = 0; i < 3; ++i, x += charwidth)
+			V_DrawCharacter(x, y, '.' | cv_constextsize.value | V_GRAYMAP | V_NOSCALESTART, !cv_allcaps.value);
+	}
 }
 
 // draw the last lines of console text to the top of the screen
@@ -1417,7 +1572,7 @@ static void CON_DrawConsole(void)
 	{
 		// inu: no more width (was always 0 and vid.width)
 		if (rendermode != render_none)
-			V_DrawFadeConsBack(con_curlines, cons_backcolor.value); // translucent background
+			V_DrawFadeConsBack(con_curlines); // translucent background
 	}
 
 	// draw console text lines from top to bottom
diff --git a/src/console.h b/src/console.h
index 47af65e21226319cd051712efdc329677b91fbea..8cf6483ff697914cff53b85ef7dbac5d0717c2c6 100644
--- a/src/console.h
+++ b/src/console.h
@@ -40,11 +40,10 @@ extern consvar_t cons_backcolor;
 
 extern UINT8 *yellowmap, *purplemap, *lgreenmap, *bluemap, *graymap, *redmap, *orangemap;
 
-// Console bg colors:
-extern UINT8 *cwhitemap, *corangemap, *cbluemap, *cgreenmap, *cgraymap,
-	*credmap;
+// Console bg color (auto updated to match)
+extern UINT8 *consolebgmap;
 
-void CON_ReSetupBackColormap(UINT16 num);
+void CON_SetupBackColormap(void);
 void CON_ClearHUD(void); // clear heads up messages
 
 void CON_Ticker(void);
diff --git a/src/d_clisrv.c b/src/d_clisrv.c
index c0f81ba3288be1ec87b1a91de83240bccbe73f6c..7c21d79fc928a1a486b77ff8a2f864f8fd01de20 100644
--- a/src/d_clisrv.c
+++ b/src/d_clisrv.c
@@ -58,28 +58,35 @@
 // NETWORKING
 //
 // gametic is the tic about to (or currently being) run
-// maketic is the tic that hasn't had control made for it yet
-// server:
+// Server:
+//   maketic is the tic that hasn't had control made for it yet
 //   nettics is the tic for each node
 //   firstticstosend is the lowest value of nettics
-// client:
-//   neededtic is the tic needed by the client for run the game
+// Client:
+//   neededtic is the tic needed by the client to run the game
 //   firstticstosend is used to optimize a condition
-// normally maketic >= gametic > 0
+// Normally maketic >= gametic > 0
 
 #define PREDICTIONQUEUE BACKUPTICS
 #define PREDICTIONMASK (PREDICTIONQUEUE-1)
 #define MAX_REASONLENGTH 30
 
 boolean server = true; // true or false but !server == client
+#define client (!server)
 boolean nodownload = false;
 static boolean serverrunning = false;
 INT32 serverplayer = 0;
 char motd[254], server_context[8]; // Message of the Day, Unique Context (even without Mumble support)
 
-// server specific vars
+// Server specific vars
 UINT8 playernode[MAXPLAYERS];
 
+// Minimum timeout for sending the savegame
+// The actual timeout will be longer depending on the savegame length
+tic_t jointimeout = (10*TICRATE);
+static boolean sendingsavegame[MAXNETNODES]; // Are we sending the savegame?
+static tic_t freezetimeout[MAXNETNODES]; // Until when can this node freeze the server before getting a timeout?
+
 #ifdef NEWPING
 UINT16 pingmeasurecount = 1;
 UINT32 realpingtable[MAXPLAYERS]; //the base table of ping where an average will be sent to everyone.
@@ -108,7 +115,7 @@ static UINT8 resynch_local_inprogress = false; // WE are desynched and getting p
 static UINT8 player_joining = false;
 UINT8 hu_resynching = 0;
 
-// client specific
+// Client specific
 static ticcmd_t localcmds;
 static ticcmd_t localcmds2;
 static boolean cl_packetmissed;
@@ -151,12 +158,6 @@ static consvar_t cv_showjoinaddress = {"showjoinaddress", "On", 0, CV_OnOff, NUL
 static CV_PossibleValue_t playbackspeed_cons_t[] = {{1, "MIN"}, {10, "MAX"}, {0, NULL}};
 consvar_t cv_playbackspeed = {"playbackspeed", "1", 0, playbackspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
-void D_ResetTiccmds(void)
-{
-	memset(&localcmds, 0, sizeof(ticcmd_t));
-	memset(&localcmds2, 0, sizeof(ticcmd_t));
-}
-
 static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
 {
 	const size_t d = n / sizeof(ticcmd_t);
@@ -185,11 +186,17 @@ static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n)
 
 
 
-// some software don't support largest packet
-// (original sersetup, not exactely, but the probabylity of sending a packet
-// of 512 octet is like 0.1)
+// Some software don't support largest packet
+// (original sersetup, not exactely, but the probability of sending a packet
+// of 512 bytes is like 0.1)
 UINT16 software_MAXPACKETLENGTH;
 
+/** Guesses the value of a tic from its lowest byte and from maketic
+  *
+  * \param low The lowest byte of the tic value
+  * \return The full tic value
+  *
+  */
 tic_t ExpandTics(INT32 low)
 {
 	INT32 delta;
@@ -214,7 +221,7 @@ void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum))
 {
 #ifdef PARANOIA
 	if (id >= MAXNETXCMD)
-		I_Error("command id %d too big", id);
+		I_Error("Command id %d too big", id);
 	if (listnetxcmd[id] != 0)
 		I_Error("Command id %d already used", id);
 #endif
@@ -378,7 +385,7 @@ static void ExtraDataTicker(void)
 					{
 						const UINT8 id = *curpos;
 						curpos++;
-						DEBFILE(va("executing x_cmd %u ply %u ", id, i));
+						DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
 						(listnetxcmd[id])(&curpos, i);
 						DEBFILE("done\n");
 					}
@@ -401,7 +408,11 @@ static void ExtraDataTicker(void)
 			}
 		}
 
-	D_FreeTextcmd(gametic);
+	// If you are a client, you can safely forget the net commands for this tic
+	// If you are the server, you need to remember them until every client has been aknowledged,
+	// because if you need to resend a PT_SERVERTICS packet, you need to put the commands in it
+	if (client)
+		D_FreeTextcmd(gametic);
 }
 
 static void D_Clearticcmd(tic_t tic)
@@ -416,6 +427,19 @@ static void D_Clearticcmd(tic_t tic)
 	DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS));
 }
 
+void D_ResetTiccmds(void)
+{
+	INT32 i;
+
+	memset(&localcmds, 0, sizeof(ticcmd_t));
+	memset(&localcmds2, 0, sizeof(ticcmd_t));
+
+	// Reset the net command list
+	for (i = 0; i < TEXTCMD_HASH_SIZE; i++)
+		while (textcmds[i])
+			D_Clearticcmd(textcmds[i]->tic);
+}
+
 // -----------------------------------------------------------------
 // end of extra data function
 // -----------------------------------------------------------------
@@ -851,12 +875,13 @@ static inline void resynch_write_others(resynchend_pak *rst)
 {
 	UINT8 i;
 
-	rst->ingame = rst->ctfteam = 0;
+	rst->ingame = 0;
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
 		if (!playeringame[i])
 		{
+			rst->ctfteam[i] = 0;
 			rst->score[i] = 0;
 			rst->numboxes[i] = 0;
 			rst->totalring[i] = 0;
@@ -866,11 +891,8 @@ static inline void resynch_write_others(resynchend_pak *rst)
 		}
 
 		if (!players[i].spectator)
-		{
 			rst->ingame |= (1<<i);
-			if (players[i].ctfteam > 1)
-				rst->ctfteam |= (1<<i);
-		}
+		rst->ctfteam[i] = (INT32)LONG(players[i].ctfteam);
 		rst->score[i] = (UINT32)LONG(players[i].score);
 		rst->numboxes[i] = SHORT(players[i].numboxes);
 		rst->totalring[i] = SHORT(players[i].totalring);
@@ -880,28 +902,18 @@ static inline void resynch_write_others(resynchend_pak *rst)
 
 	// endian safeness
 	rst->ingame = (UINT32)LONG(rst->ingame);
-	rst->ctfteam = (UINT32)LONG(rst->ctfteam);
 }
 
 static inline void resynch_read_others(resynchend_pak *p)
 {
 	UINT8 i;
 	UINT32 loc_ingame = (UINT32)LONG(p->ingame);
-	UINT32 loc_ctfteam = (UINT32)LONG(p->ctfteam);
 
 	for (i = 0; i < MAXPLAYERS; ++i)
 	{
 		// We don't care if they're in the game or not, just write all the data.
-		if (loc_ingame & (1<<i))
-		{
-			players[i].spectator = false;
-			players[i].ctfteam = (loc_ctfteam & (1<<i)) ? 2 : 1;
-		}
-		else
-		{
-			players[i].spectator = true;
-			players[i].ctfteam = 0;
-		}
+		players[i].spectator = !(loc_ingame & (1<<i));
+		players[i].ctfteam = (INT32)LONG(p->ctfteam[i]); // no, 0 does not mean spectator, at least not in Match
 		players[i].score = (UINT32)LONG(p->score[i]);
 		players[i].numboxes = SHORT(p->numboxes[i]);
 		players[i].totalring = SHORT(p->totalring[i]);
@@ -1021,6 +1033,9 @@ static void SV_AcknowledgeResynchAck(INT32 node, UINT8 rsg)
 		resynch_status[node] &= ~(1<<rsg);
 		--resynch_score[node]; // unpenalize
 	}
+
+	// Don't let resynch cause a timeout
+	freezetimeout[node] = I_GetTime() + connectiontimeout;
 }
 // -----------------------------------------------------------------
 // end resynch
@@ -1034,20 +1049,20 @@ static INT16 Consistancy(void);
 
 typedef enum
 {
-	cl_searching,
-	cl_downloadfiles,
-	cl_askjoin,
-	cl_waitjoinresponse,
+	CL_SEARCHING,
+	CL_DOWNLOADFILES,
+	CL_ASKJOIN,
+	CL_WAITJOINRESPONSE,
 #ifdef JOININGAME
-	cl_downloadsavegame,
+	CL_DOWNLOADSAVEGAME,
 #endif
-	cl_connected,
-	cl_aborted
+	CL_CONNECTED,
+	CL_ABORTED
 } cl_mode_t;
 
 static void GetPackets(void);
 
-static cl_mode_t cl_mode = cl_searching;
+static cl_mode_t cl_mode = CL_SEARCHING;
 
 // Player name send/load
 
@@ -1100,10 +1115,10 @@ static inline void CL_DrawConnectionStatus(void)
 	M_DrawTextBox(BASEVIDWIDTH/2-128-8, BASEVIDHEIGHT-24-8, 32, 1);
 	V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-24, V_YELLOWMAP, "Press ESC to abort");
 
-	if (cl_mode != cl_downloadfiles)
+	if (cl_mode != CL_DOWNLOADFILES)
 	{
 		INT32 i, animtime = ((ccstime / 4) & 15) + 16;
-		UINT8 palstart = (cl_mode == cl_searching) ? 128 : 160;
+		UINT8 palstart = (cl_mode == CL_SEARCHING) ? 128 : 160;
 		// 15 pal entries total.
 		const char *cltext;
 
@@ -1113,17 +1128,22 @@ static inline void CL_DrawConnectionStatus(void)
 		switch (cl_mode)
 		{
 #ifdef JOININGAME
-			case cl_downloadsavegame:
-				cltext = M_GetText("Downloading game state...");
-				Net_GetNetStat();
-				V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
-					va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
-				V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
-					va("%3.1fK/s ", ((double)getbps)/1024));
+			case CL_DOWNLOADSAVEGAME:
+				if (lastfilenum != -1)
+				{
+					cltext = M_GetText("Downloading game state...");
+					Net_GetNetStat();
+					V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+						va(" %4uK",fileneeded[lastfilenum].currentsize>>10));
+					V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+						va("%3.1fK/s ", ((double)getbps)/1024));
+				}
+				else
+					cltext = M_GetText("Waiting to download game state...");
 				break;
 #endif
-			case cl_askjoin:
-			case cl_waitjoinresponse:
+			case CL_ASKJOIN:
+			case CL_WAITJOINRESPONSE:
 				cltext = M_GetText("Requesting to join...");
 				break;
 			default:
@@ -1134,34 +1154,45 @@ static inline void CL_DrawConnectionStatus(void)
 	}
 	else
 	{
-		INT32 dldlength;
-		static char tempname[32];
-
-		Net_GetNetStat();
-		dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
-		if (dldlength > 256)
-			dldlength = 256;
-		V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
-		V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
-
-		memset(tempname, 0, sizeof(tempname));
-		nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
-
-		V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
-			va(M_GetText("Downloading \"%s\""), tempname));
-		V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
-			va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
-		V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
-			va("%3.1fK/s ", ((double)getbps)/1024));
+		if (lastfilenum != -1)
+		{
+			INT32 dldlength;
+			static char tempname[32];
+
+			Net_GetNetStat();
+			dldlength = (INT32)((fileneeded[lastfilenum].currentsize/(double)fileneeded[lastfilenum].totalsize) * 256);
+			if (dldlength > 256)
+				dldlength = 256;
+			V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, 256, 8, 175);
+			V_DrawFill(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, dldlength, 8, 160);
+
+			memset(tempname, 0, sizeof(tempname));
+			nameonly(strncpy(tempname, fileneeded[lastfilenum].filename, 31));
+
+			V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
+				va(M_GetText("Downloading \"%s\""), tempname));
+			V_DrawString(BASEVIDWIDTH/2-128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+				va(" %4uK/%4uK",fileneeded[lastfilenum].currentsize>>10,fileneeded[lastfilenum].totalsize>>10));
+			V_DrawRightAlignedString(BASEVIDWIDTH/2+128, BASEVIDHEIGHT-24, V_20TRANS|V_MONOSPACE,
+				va("%3.1fK/s ", ((double)getbps)/1024));
+		}
+		else
+			V_DrawCenteredString(BASEVIDWIDTH/2, BASEVIDHEIGHT-24-32, V_YELLOWMAP,
+				M_GetText("Waiting to download files..."));
 	}
 }
 #endif
 
-//
-// CL_SendJoin
-//
-// send a special packet for declare how many player in local
-// used only in arbitratrenetstart()
+/** Sends a special packet to declare how many players in local
+  * Used only in arbitratrenetstart()
+  * Sends a PT_CLIENTJOIN packet to the server
+  *
+  * \return True if the packet was successfully sent
+  * \todo Improve the description...
+  *       Because to be honest, I have no idea what arbitratrenetstart is...
+  *       Is it even used...?
+  *
+  */
 static boolean CL_SendJoin(void)
 {
 	UINT8 localplayers = 1;
@@ -1296,6 +1327,12 @@ static void SV_SendPlayerInfo(INT32 node)
 	HSendPacket(node, false, 0, sizeof(plrinfo) * MAXPLAYERS);
 }
 
+/** Sends a PT_SERVERCFG packet
+  *
+  * \param node The destination
+  * \return True if the packet was successfully sent
+  *
+  */
 static boolean SV_SendServerConfig(INT32 node)
 {
 	INT32 i;
@@ -1428,8 +1465,12 @@ static void SV_SendSaveGame(INT32 node)
 		WRITEUINT32(savebuffer, 0);
 	}
 
-	SendRam(node, buffertosend, length, SF_RAM, 0);
+	SV_SendRam(node, buffertosend, length, SF_RAM, 0);
 	save_p = NULL;
+
+	// Remember when we started sending the savegame so we can handle timeouts
+	sendingsavegame[node] = true;
+	freezetimeout[node] = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
 }
 
 #ifdef DUMPCONSISTENCY
@@ -1523,7 +1564,7 @@ static void CL_LoadReceivedSavegame(void)
 		{
 			CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
 			if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
-				CONS_Printf(M_GetText("ZONE"));
+				CONS_Printf(M_GetText(" ZONE"));
 			if (actnum > 0)
 				CONS_Printf(" %2d", actnum);
 		}
@@ -1679,11 +1720,263 @@ void CL_UpdateServerList(boolean internetsearch, INT32 room)
 
 #endif // ifndef NONET
 
-// use adaptive send using net_bandwidth and stat.sendbytes
+/** Called by CL_ServerConnectionTicker
+  *
+  * \param viams ???
+  * \param asksent ???
+  * \return False if the connection was aborted
+  * \sa CL_ServerConnectionTicker
+  * \sa CL_ConnectToServer
+  *
+  */
+static boolean CL_ServerConnectionSearchTicker(boolean viams, tic_t *asksent)
+{
+#ifndef NONET
+	INT32 i;
+
+	// serverlist is updated by GetPacket function
+	if (serverlistcount > 0)
+	{
+		// this can be a responce to our broadcast request
+		if (servernode == -1 || servernode >= MAXNETNODES)
+		{
+			i = 0;
+			servernode = serverlist[i].node;
+			CONS_Printf(M_GetText("Found, "));
+		}
+		else
+		{
+			i = SL_SearchServer(servernode);
+			if (i < 0)
+				return true;
+		}
+
+		// Quit here rather than downloading files and being refused later.
+		if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer)
+		{
+			D_QuitNetGame();
+			CL_Reset();
+			D_StartTitle();
+			M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
+			return false;
+		}
+
+		if (client)
+		{
+			D_ParseFileneeded(serverlist[i].info.fileneedednum,
+				serverlist[i].info.fileneeded);
+			CONS_Printf(M_GetText("Checking files...\n"));
+			i = CL_CheckFiles();
+			if (i == 3) // too many files
+			{
+				D_QuitNetGame();
+				CL_Reset();
+				D_StartTitle();
+				M_StartMessage(M_GetText(
+					"You have too many WAD files loaded\n"
+					"to add ones the server is using.\n"
+					"Please restart SRB2 before connecting.\n\n"
+					"Press ESC\n"
+				), NULL, MM_NOTHING);
+				return false;
+			}
+			else if (i == 2) // cannot join for some reason
+			{
+				D_QuitNetGame();
+				CL_Reset();
+				D_StartTitle();
+				M_StartMessage(M_GetText(
+					"You have WAD files loaded or have\n"
+					"modified the game in some way, and\n"
+					"your file list does not match\n"
+					"the server's file list.\n"
+					"Please restart SRB2 before connecting.\n\n"
+					"Press ESC\n"
+				), NULL, MM_NOTHING);
+				return false;
+			}
+			else if (i == 1)
+				cl_mode = CL_ASKJOIN;
+			else
+			{
+				// must download something
+				// can we, though?
+				if (!CL_CheckDownloadable()) // nope!
+				{
+					D_QuitNetGame();
+					CL_Reset();
+					D_StartTitle();
+					M_StartMessage(M_GetText(
+						"You cannot connect to this server\n"
+						"because you cannot download the files\n"
+						"that you are missing from the server.\n\n"
+						"See the console or log file for\n"
+						"more details.\n\n"
+						"Press ESC\n"
+					), NULL, MM_NOTHING);
+					return false;
+				}
+				// no problem if can't send packet, we will retry later
+				if (CL_SendRequestFile())
+					cl_mode = CL_DOWNLOADFILES;
+			}
+		}
+		else
+			cl_mode = CL_ASKJOIN; // files need not be checked for the server.
+
+		return true;
+	}
+
+	// Ask the info to the server (askinfo packet)
+	if (*asksent + NEWTICRATE < I_GetTime())
+	{
+		SendAskInfo(servernode, viams);
+		*asksent = I_GetTime();
+	}
+#else
+	(void)viams;
+	(void)asksent;
+	// No netgames, so we skip this state.
+	cl_mode = CL_ASKJOIN;
+#endif // ifndef NONET/else
+
+	return true;
+}
+
+/** Called by CL_ConnectToServer
+  *
+  * \param viams ???
+  * \param tmpsave The name of the gamestate file???
+  * \param oldtic Used for knowing when to poll events and redraw
+  * \param asksent ???
+  * \return False if the connection was aborted
+  * \sa CL_ServerConnectionSearchTicker
+  * \sa CL_ConnectToServer
+  *
+  */
+static boolean CL_ServerConnectionTicker(boolean viams, const char *tmpsave, tic_t *oldtic, tic_t *asksent)
+{
+	boolean waitmore;
+	INT32 i;
+
+#ifdef NONET
+	(void)tmpsave;
+#endif
+
+	switch (cl_mode)
+	{
+		case CL_SEARCHING:
+			if (!CL_ServerConnectionSearchTicker(viams, asksent))
+				return false;
+			break;
+
+		case CL_DOWNLOADFILES:
+			waitmore = false;
+			for (i = 0; i < fileneedednum; i++)
+				if (fileneeded[i].status == FS_DOWNLOADING
+					|| fileneeded[i].status == FS_REQUESTED)
+				{
+					waitmore = true;
+					break;
+				}
+			if (waitmore)
+				break; // exit the case
+
+			cl_mode = CL_ASKJOIN; // don't break case continue to cljoin request now
+
+		case CL_ASKJOIN:
+			CL_LoadServerFiles();
+#ifdef JOININGAME
+			// prepare structures to save the file
+			// WARNING: this can be useless in case of server not in GS_LEVEL
+			// but since the network layer doesn't provide ordered packets...
+			CL_PrepareDownloadSaveGame(tmpsave);
+#endif
+			if (CL_SendJoin())
+				cl_mode = CL_WAITJOINRESPONSE;
+			break;
+
+#ifdef JOININGAME
+		case CL_DOWNLOADSAVEGAME:
+			// At this state, the first (and only) needed file is the gamestate
+			if (fileneeded[0].status == FS_FOUND)
+			{
+				// Gamestate is now handled within CL_LoadReceivedSavegame()
+				CL_LoadReceivedSavegame();
+				cl_mode = CL_CONNECTED;
+			} // don't break case continue to CL_CONNECTED
+			else
+				break;
+#endif
+
+		case CL_WAITJOINRESPONSE:
+		case CL_CONNECTED:
+		default:
+			break;
+
+		// Connection closed by cancel, timeout or refusal.
+		case CL_ABORTED:
+			cl_mode = CL_SEARCHING;
+			return false;
+
+	}
+
+	GetPackets();
+	Net_AckTicker();
+
+	// Call it only once by tic
+	if (*oldtic != I_GetTime())
+	{
+		INT32 key;
+
+		I_OsPolling();
+		key = I_GetKey();
+		if (key == KEY_ESCAPE)
+		{
+			CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
+//				M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
+			D_QuitNetGame();
+			CL_Reset();
+			D_StartTitle();
+			return false;
+		}
+
+		// why are these here? this is for servers, we're a client
+		//if (key == 's' && server)
+		//	doomcom->numnodes = (INT16)pnumnodes;
+		//SV_FileSendTicker();
+		*oldtic = I_GetTime();
+
+#ifdef CLIENT_LOADINGSCREEN
+		if (client && cl_mode != CL_CONNECTED && cl_mode != CL_ABORTED)
+		{
+			F_TitleScreenTicker(true);
+			F_TitleScreenDrawer();
+			CL_DrawConnectionStatus();
+			I_UpdateNoVsync(); // page flip or blit buffer
+			if (moviemode)
+				M_SaveFrame();
+		}
+#else
+		CON_Drawer();
+		I_UpdateNoVsync();
+#endif
+	}
+	else
+		I_Sleep();
+
+	return true;
+}
+
+/** Use adaptive send using net_bandwidth and stat.sendbytes
+  *
+  * \param viams ???
+  * \todo Better description...
+  *
+  */
 static void CL_ConnectToServer(boolean viams)
 {
 	INT32 pnumnodes, nodewaited = doomcom->numnodes, i;
-	boolean waitmore;
 	tic_t oldtic;
 #ifndef NONET
 	tic_t asksent;
@@ -1694,14 +1987,14 @@ static void CL_ConnectToServer(boolean viams)
 	sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
 #endif
 
-	cl_mode = cl_searching;
+	cl_mode = CL_SEARCHING;
 
 #ifdef CLIENT_LOADINGSCREEN
-	lastfilenum = 0;
+	lastfilenum = -1;
 #endif
 
 #ifdef JOININGAME
-	// don't get a corrupt savegame error because tmpsave already exists
+	// Don't get a corrupt savegame error because tmpsave already exists
 	if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
 		I_Error("Can't delete %s\n", tmpsave);
 #endif
@@ -1725,7 +2018,7 @@ static void CL_ConnectToServer(boolean viams)
 	pnumnodes = 1;
 	oldtic = I_GetTime() - 1;
 #ifndef NONET
-	asksent = (tic_t)-TICRATE;
+	asksent = (tic_t) - TICRATE;
 
 	i = SL_SearchServer(servernode);
 
@@ -1752,197 +2045,23 @@ static void CL_ConnectToServer(boolean viams)
 
 	do
 	{
-		switch (cl_mode)
-		{
-			case cl_searching:
+		// If the connection was aborted for some reason, leave
 #ifndef NONET
-				// serverlist is updated by GetPacket function
-				if (serverlistcount > 0)
-				{
-					// this can be a responce to our broadcast request
-					if (servernode == -1 || servernode >= MAXNETNODES)
-					{
-						i = 0;
-						servernode = serverlist[i].node;
-						CONS_Printf(M_GetText("Found, "));
-					}
-					else
-					{
-						i = SL_SearchServer(servernode);
-						if (i < 0)
-							break; // the case
-					}
-
-					// Quit here rather than downloading files and being refused later.
-					if (serverlist[i].info.numberofplayer >= serverlist[i].info.maxplayer)
-					{
-						D_QuitNetGame();
-						CL_Reset();
-						D_StartTitle();
-						M_StartMessage(va(M_GetText("Maximum players reached: %d\n\nPress ESC\n"), serverlist[i].info.maxplayer), NULL, MM_NOTHING);
-						return;
-					}
-
-					if (!server)
-					{
-						D_ParseFileneeded(serverlist[i].info.fileneedednum,
-							serverlist[i].info.fileneeded);
-						CONS_Printf(M_GetText("Checking files...\n"));
-						i = CL_CheckFiles();
-						if (i == 2) // cannot join for some reason
-						{
-							D_QuitNetGame();
-							CL_Reset();
-							D_StartTitle();
-							M_StartMessage(M_GetText(
-								"You have WAD files loaded or have\n"
-								"modified the game in some way, and\n"
-								"your file list does not match\n"
-								"the server's file list.\n"
-								"Please restart SRB2 before connecting.\n\n"
-								"Press ESC\n"
-							), NULL, MM_NOTHING);
-							return;
-						}
-						else if (i == 1)
-							cl_mode = cl_askjoin;
-						else
-						{
-							// must download something
-							// can we, though?
-							if (!CL_CheckDownloadable()) // nope!
-							{
-								D_QuitNetGame();
-								CL_Reset();
-								D_StartTitle();
-								M_StartMessage(M_GetText(
-									"You cannot conect to this server\n"
-									"because you cannot download the files\n"
-									"that you are missing from the server.\n\n"
-									"See the console or log file for\n"
-									"more details.\n\n"
-									"Press ESC\n"
-								), NULL, MM_NOTHING);
-								return;
-							}
-							// no problem if can't send packet, we will retry later
-							if (CL_SendRequestFile())
-								cl_mode = cl_downloadfiles;
-						}
-					}
-					else
-						cl_mode = cl_askjoin; // files need not be checked for the server.
-					break;
-				}
-				// ask the info to the server (askinfo packet)
-				if (asksent + NEWTICRATE < I_GetTime())
-				{
-					SendAskInfo(servernode, viams);
-					asksent = I_GetTime();
-				}
-#else
-				(void)viams;
-				// No netgames, so we skip this state.
-				cl_mode = cl_askjoin;
-#endif // ifndef NONET/else
-				break;
-			case cl_downloadfiles:
-				waitmore = false;
-				for (i = 0; i < fileneedednum; i++)
-					if (fileneeded[i].status == FS_DOWNLOADING
-						|| fileneeded[i].status == FS_REQUESTED)
-					{
-						waitmore = true;
-						break;
-					}
-				if (waitmore)
-					break; // exit the case
-
-				cl_mode = cl_askjoin; // don't break case continue to cljoin request now
-			case cl_askjoin:
-				CL_LoadServerFiles();
-#ifdef JOININGAME
-				// prepare structures to save the file
-				// WARNING: this can be useless in case of server not in GS_LEVEL
-				// but since the network layer doesn't provide ordered packets...
-				CL_PrepareDownloadSaveGame(tmpsave);
-#endif
-				if (CL_SendJoin())
-					cl_mode = cl_waitjoinresponse;
-				break;
-#ifdef JOININGAME
-			case cl_downloadsavegame:
-				if (fileneeded[0].status == FS_FOUND)
-				{
-					// Gamestate is now handled within CL_LoadReceivedSavegame()
-					CL_LoadReceivedSavegame();
-					cl_mode = cl_connected;
-				} // don't break case continue to cl_connected
-				else
-					break;
-#endif
-			case cl_waitjoinresponse:
-			case cl_connected:
-			default:
-				break;
-
-			// Connection closed by cancel, timeout or refusal.
-			case cl_aborted:
-				cl_mode = cl_searching;
-				return;
-		}
-
-		GetPackets();
-		Net_AckTicker();
-
-		// call it only one by tic
-		if (oldtic != I_GetTime())
-		{
-			INT32 key;
-
-			I_OsPolling();
-			key = I_GetKey();
-			if (key == KEY_ESCAPE)
-			{
-				CONS_Printf(M_GetText("Network game synchronization aborted.\n"));
-//				M_StartMessage(M_GetText("Network game synchronization aborted.\n\nPress ESC\n"), NULL, MM_NOTHING);
-				D_QuitNetGame();
-				CL_Reset();
-				D_StartTitle();
-				return;
-			}
-
-			// why are these here? this is for servers, we're a client
-			//if (key == 's' && server)
-			//	doomcom->numnodes = (INT16)pnumnodes;
-			//FiletxTicker();
-			oldtic = I_GetTime();
-
-#ifdef CLIENT_LOADINGSCREEN
-			if (!server && cl_mode != cl_connected && cl_mode != cl_aborted)
-			{
-				F_TitleScreenTicker(true);
-				F_TitleScreenDrawer();
-				CL_DrawConnectionStatus();
-				I_UpdateNoVsync(); // page flip or blit buffer
-				if (moviemode)
-					M_SaveFrame();
-			}
+		if (!CL_ServerConnectionTicker(viams, tmpsave, &oldtic, &asksent))
 #else
-			CON_Drawer();
-			I_UpdateNoVsync();
+		if (!CL_ServerConnectionTicker(viams, (char*)NULL, &oldtic, (tic_t *)NULL))
 #endif
-		}
-		else I_Sleep();
+			return;
 
 		if (server)
 		{
 			pnumnodes = 0;
 			for (i = 0; i < MAXNETNODES; i++)
-				if (nodeingame[i]) pnumnodes++;
+				if (nodeingame[i])
+					pnumnodes++;
 		}
 	}
-	while (!(cl_mode == cl_connected && (!server || (server && nodewaited <= pnumnodes))));
+	while (!(cl_mode == CL_CONNECTED && (client || (server && nodewaited <= pnumnodes))));
 
 	DEBFILE(va("Synchronisation Finished\n"));
 
@@ -2199,7 +2318,6 @@ void CL_ClearPlayer(INT32 playernum)
 			P_RemoveMobj(players[playernum].mo->tracer);
 		P_RemoveMobj(players[playernum].mo);
 	}
-	players[playernum].mo = NULL;
 	memset(&players[playernum], 0, sizeof (player_t));
 }
 
@@ -2407,12 +2525,18 @@ static void Command_Nodes(void)
 
 static void Command_Ban(void)
 {
-	if (COM_Argc() == 1)
+	if (COM_Argc() < 2)
 	{
 		CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
 		return;
 	}
 
+	if (!netgame) // Don't kick Tails in splitscreen!
+	{
+		CONS_Printf(M_GetText("This only works in a netgame.\n"));
+		return;
+	}
+
 	if (server || adminplayer == consoleplayer)
 	{
 		XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
@@ -2422,9 +2546,10 @@ static void Command_Ban(void)
 
 		if (pn == -1 || pn == 0)
 			return;
-		else
-			WRITEUINT8(p, pn);
-		if (I_Ban && !I_Ban(node))
+
+		WRITEUINT8(p, pn);
+
+		if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
 		{
 			CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
 			WRITEUINT8(p, KICK_MSG_GO_AWAY);
@@ -2432,7 +2557,8 @@ static void Command_Ban(void)
 		}
 		else
 		{
-			Ban_Add(COM_Argv(2));
+			if (server) // only the server is allowed to do this right now
+				Ban_Add(COM_Argv(2));
 
 			if (COM_Argc() == 2)
 			{
@@ -2465,21 +2591,38 @@ static void Command_Ban(void)
 
 static void Command_Kick(void)
 {
-	XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
-	UINT8 *p = buf;
-
-	if (COM_Argc() == 1)
+	if (COM_Argc() < 2)
 	{
 		CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
 		return;
 	}
 
+	if (!netgame) // Don't kick Tails in splitscreen!
+	{
+		CONS_Printf(M_GetText("This only works in a netgame.\n"));
+		return;
+	}
+
 	if (server || adminplayer == consoleplayer)
 	{
+		XBOXSTATIC UINT8 buf[3 + MAX_REASONLENGTH];
+		UINT8 *p = buf;
 		const SINT8 pn = nametonum(COM_Argv(1));
-		WRITESINT8(p, pn);
+
 		if (pn == -1 || pn == 0)
 			return;
+
+		// Special case if we are trying to kick a player who is downloading the game state:
+		// trigger a timeout instead of kicking them, because a kick would only
+		// take effect after they have finished downloading
+		if (sendingsavegame[playernode[pn]])
+		{
+			Net_ConnectionTimeout(playernode[pn]);
+			return;
+		}
+
+		WRITESINT8(p, pn);
+
 		if (COM_Argc() == 2)
 		{
 			WRITEUINT8(p, KICK_MSG_GO_AWAY);
@@ -2581,12 +2724,14 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
 
 	// If a verified admin banned someone, the server needs to know about it.
 	// If the playernum isn't zero (the server) then the server needs to record the ban.
-	if (server && playernum && msg == KICK_MSG_BANNED)
+	if (server && playernum && (msg == KICK_MSG_BANNED || msg == KICK_MSG_CUSTOM_BAN))
 	{
 		if (I_Ban && !I_Ban(playernode[(INT32)pnum]))
-		{
 			CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
-		}
+#ifndef NONET
+		else
+			Ban_Add(reason);
+#endif
 	}
 
 	switch (msg)
@@ -2692,7 +2837,12 @@ consvar_t cv_blamecfail = {"blamecfail", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL
 
 // max file size to send to a player (in kilobytes)
 static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {51200, "MAX"}, {0, NULL}};
-consvar_t cv_maxsend = {"maxsend", "1024", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_maxsend = {"maxsend", "4096", CV_SAVE, maxsend_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_noticedownload = {"noticedownload", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+// Speed of file downloading (in packets per tic)
+static CV_PossibleValue_t downloadspeed_cons_t[] = {{0, "MIN"}, {32, "MAX"}, {0, NULL}};
+consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 static void Got_AddPlayer(UINT8 **p, INT32 playernum);
 
@@ -2711,6 +2861,13 @@ void D_ClientServerInit(void)
 	COM_AddCommand("reloadbans", Command_ReloadBan);
 	COM_AddCommand("connect", Command_connect);
 	COM_AddCommand("nodes", Command_Nodes);
+#ifdef PACKETDROP
+	COM_AddCommand("drop", Command_Drop);
+	COM_AddCommand("droprate", Command_Droprate);
+#endif
+#ifdef _DEBUG
+	COM_AddCommand("numnodes", Command_Numnodes);
+#endif
 #endif
 
 	RegisterNetXCmd(XD_KICK, Got_KickCmd);
@@ -2746,6 +2903,7 @@ static void ResetNode(INT32 node)
 	supposedtics[node] = gametic;
 	nodewaiting[node] = 0;
 	playerpernode[node] = 0;
+	sendingsavegame[node] = false;
 }
 
 void SV_ResetServer(void)
@@ -2754,7 +2912,7 @@ void SV_ResetServer(void)
 
 	// +1 because this command will be executed in com_executebuffer in
 	// tryruntic so gametic will be incremented, anyway maketic > gametic
-	// is not a issue
+	// is not an issue
 
 	maketic = gametic + 1;
 	neededtic = maketic;
@@ -2808,7 +2966,7 @@ static inline void SV_GenContext(void)
 	for (i = 0; i < 8; i++)
 	{
 		const char a = M_RandomKey(26*2);
-		if (a <= 26) // uppercase
+		if (a < 26) // uppercase
 			server_context[i] = 'A'+a;
 		else // lowercase
 			server_context[i] = 'a'+(a-26);
@@ -2843,7 +3001,7 @@ void D_QuitNetGame(void)
 		if (serverrunning && ms_RoomId > 0)
 			UnregisterServer();
 	}
-	else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode]!=0)
+	else if (servernode > 0 && servernode < MAXNETNODES && nodeingame[(UINT8)servernode])
 	{
 		netbuffer->packettype = PT_CLIENTQUIT;
 		HSendPacket(servernode, true, 0, 0);
@@ -2864,12 +3022,12 @@ void D_QuitNetGame(void)
 #endif
 }
 
-// add a node to the game (player will follow at map change or at savegame....)
+// Adds a node to the game (player will follow at map change or at savegame....)
 static inline void SV_AddNode(INT32 node)
 {
 	nettics[node] = gametic;
 	supposedtics[node] = gametic;
-	// little hack because the server connect to itself and put
+	// little hack because the server connects to itself and puts
 	// nodeingame when connected not here
 	if (node)
 		nodeingame[node] = true;
@@ -3019,7 +3177,7 @@ static boolean SV_AddWaitingPlayers(void)
 
 void CL_AddSplitscreenPlayer(void)
 {
-	if (cl_mode == cl_connected)
+	if (cl_mode == CL_CONNECTED)
 		CL_SendJoin();
 }
 
@@ -3027,7 +3185,7 @@ void CL_RemoveSplitscreenPlayer(void)
 {
 	XBOXSTATIC UINT8 buf[2];
 
-	if (cl_mode != cl_connected)
+	if (cl_mode != CL_CONNECTED)
 		return;
 
 	buf[0] = (UINT8)secondarydisplayplayer;
@@ -3038,7 +3196,7 @@ void CL_RemoveSplitscreenPlayer(void)
 // is there a game running
 boolean Playing(void)
 {
-	return (server && serverrunning) || (!server && cl_mode == cl_connected);
+	return (server && serverrunning) || (client && cl_mode == CL_CONNECTED);
 }
 
 boolean SV_SpawnServer(void)
@@ -3086,7 +3244,7 @@ void SV_StopServer(void)
 		D_Clearticcmd(i);
 
 	consoleplayer = 0;
-	cl_mode = cl_searching;
+	cl_mode = CL_SEARCHING;
 	maketic = gametic+1;
 	neededtic = maketic;
 	serverrunning = false;
@@ -3132,6 +3290,11 @@ static size_t TotalTextCmdPerTic(tic_t tic)
 	return total;
 }
 
+/** Called when a PT_CLIENTJOIN packet is received
+  *
+  * \param node The packet sender
+  *
+  */
 static void HandleConnect(SINT8 node)
 {
 	if (bannednode && bannednode[node])
@@ -3163,6 +3326,9 @@ static void HandleConnect(SINT8 node)
 #endif
 			SV_AddNode(node);
 
+			/// \note Wait what???
+			///       What if the gamestate takes more than one second to get downloaded?
+			///       Or if a lagspike happens?
 			// you get a free second before desynch checks. use it wisely.
 			SV_InitResynchVars(node);
 
@@ -3171,6 +3337,7 @@ static void HandleConnect(SINT8 node)
 			if (!SV_SendServerConfig(node))
 			{
 				G_SetGamestate(backupstate);
+				/// \note Shouldn't SV_SendRefuse be called before ResetNode?
 				ResetNode(node);
 				SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again"));
 				/// \todo fix this !!!
@@ -3201,6 +3368,11 @@ static void HandleConnect(SINT8 node)
 	}
 }
 
+/** Called when a PT_SERVERSHUTDOWN packet is received
+  *
+  * \param node The packet sender (should be the server)
+  *
+  */
 static void HandleShutdown(SINT8 node)
 {
 	(void)node;
@@ -3210,6 +3382,11 @@ static void HandleShutdown(SINT8 node)
 	M_StartMessage(M_GetText("Server has shutdown\n\nPress Esc\n"), NULL, MM_NOTHING);
 }
 
+/** Called when a PT_NODETIMEOUT packet is received
+  *
+  * \param node The packet sender (should be the server)
+  *
+  */
 static void HandleTimeout(SINT8 node)
 {
 	(void)node;
@@ -3220,6 +3397,12 @@ static void HandleTimeout(SINT8 node)
 }
 
 #ifndef NONET
+/** Called when a PT_SERVERINFO packet is received
+  *
+  * \param node The packet sender
+  * \note What happens if the packet comes from a client or something like that?
+  *
+  */
 static void HandleServerInfo(SINT8 node)
 {
 	// compute ping in ms
@@ -3233,527 +3416,664 @@ static void HandleServerInfo(SINT8 node)
 }
 #endif
 
-/**	\brief GetPackets
-
-  \todo  break this 300 line function into multiple functions
-*/
-static void GetPackets(void)
-{FILESTAMP
-	XBOXSTATIC INT32 netconsole;
-	XBOXSTATIC SINT8 node;
-	XBOXSTATIC tic_t realend,realstart;
-	XBOXSTATIC UINT8 *pak, *txtpak, numtxtpak;
-FILESTAMP
-
-	player_joining = false;
-
-	while (HGetPacket())
+/** Handles a packet received from a node that isn't in game
+  *
+  * \param node The packet sender
+  * \todo Choose a better name, as the packet can also come from the server apparently?
+  * \sa HandlePacketFromPlayer
+  * \sa GetPackets
+  *
+  */
+static void HandlePacketFromAwayNode(SINT8 node)
+{
+	if (node != servernode)
+		DEBFILE(va("Received packet from unknown host %d\n", node));
+
+// macro for packets that should only be sent by the server
+// if it is NOT from the server, bail out and close the connection!
+#define SERVERONLY \
+			if (node != servernode) \
+			{ \
+				Net_CloseConnection(node); \
+				break; \
+			}
+	switch (netbuffer->packettype)
 	{
-		node = (SINT8)doomcom->remotenode;
-		if (netbuffer->packettype == PT_CLIENTJOIN && server)
-		{
-			HandleConnect(node);
-			continue;
-		}
-		if (netbuffer->packettype == PT_SERVERSHUTDOWN && node == servernode
-			&& !server && cl_mode != cl_searching)
-		{
-			HandleShutdown(node);
-			continue;
-		}
-		if (netbuffer->packettype == PT_NODETIMEOUT && node == servernode
-			&& !server && cl_mode != cl_searching)
-		{
-			HandleTimeout(node);
-			continue;
-		}
-
-#ifndef NONET
-		if (netbuffer->packettype == PT_SERVERINFO)
-		{
-			HandleServerInfo(node);
-			continue;
-		}
+		case PT_ASKINFOVIAMS:
+#if 0
+			if (server && serverrunning)
+			{
+				INT32 clientnode;
+				if (ms_RoomId < 0) // ignore if we're not actually on the MS right now
+				{
+					Net_CloseConnection(node); // and yes, close connection
+					return;
+				}
+				clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
+				if (clientnode != -1)
+				{
+					SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
+					SV_SendPlayerInfo(clientnode); // Send extra info
+					Net_CloseConnection(clientnode);
+					// Don't close connection to MS...
+				}
+				else
+					Net_CloseConnection(node); // ...unless the IP address is not valid
+			}
+			else
+				Net_CloseConnection(node); // you're not supposed to get it, so ignore it
+#else
+			Net_CloseConnection(node);
 #endif
+			break;
 
-		if (netbuffer->packettype == PT_PLAYERINFO)
-			continue; // We do nothing with PLAYERINFO, that's for the MS browser.
-
-		if (!nodeingame[node])
-		{
-			if (node != servernode)
-				DEBFILE(va("Received packet from unknown host %d\n", node));
+		case PT_ASKINFO:
+			if (server && serverrunning)
+			{
+				SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
+				SV_SendPlayerInfo(node); // Send extra info
+			}
+			Net_CloseConnection(node);
+			break;
 
-			// anyone trying to join
-			switch (netbuffer->packettype)
+		case PT_SERVERREFUSE: // Negative response of client join request
+			if (server && serverrunning)
+			{ // But wait I thought I'm the server?
+				Net_CloseConnection(node);
+				break;
+			}
+			SERVERONLY
+			if (cl_mode == CL_WAITJOINRESPONSE)
 			{
-				case PT_ASKINFOVIAMS:
-					if (server && serverrunning)
-					{
-						INT32 clientnode = I_NetMakeNode(netbuffer->u.msaskinfo.clientaddr);
-						SV_SendServerInfo(clientnode, (tic_t)LONG(netbuffer->u.msaskinfo.time));
-						SV_SendPlayerInfo(clientnode); // send extra info
-						Net_CloseConnection(clientnode);
-						// Don't close connection to MS.
-					}
-					break;
+				// Save the reason so it can be displayed after quitting the netgame
+				char *reason = strdup(netbuffer->u.serverrefuse.reason);
+				if (!reason)
+					I_Error("Out of memory!\n");
 
-				case PT_ASKINFO:
-					if (server && serverrunning)
-					{
-						SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
-						SV_SendPlayerInfo(node); // send extra info
-						Net_CloseConnection(node);
-					}
-					break;
-				case PT_SERVERREFUSE: // negative response of client join request
-					if (server && serverrunning)
-					{ // but wait I thought I'm the server?
-						Net_CloseConnection(node);
-						break;
-					}
-					if (cl_mode == cl_waitjoinresponse)
-					{
-						D_QuitNetGame();
-						CL_Reset();
-						D_StartTitle();
+				D_QuitNetGame();
+				CL_Reset();
+				D_StartTitle();
 
-						M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
-							netbuffer->u.serverrefuse.reason), NULL, MM_NOTHING);
+				M_StartMessage(va(M_GetText("Server refuses connection\n\nReason:\n%s"),
+					reason), NULL, MM_NOTHING);
 
-						// Will be reset by caller. Signals refusal.
-						cl_mode = cl_aborted;
-					}
-					break;
-				case PT_SERVERCFG: // positive response of client join request
-				{
-					INT32 j;
-					UINT8 *scp;
+				free(reason);
 
-					if (server && serverrunning && node != servernode)
-					{ // but wait I thought I'm the server?
-						Net_CloseConnection(node);
-						break;
-					}
-					/// \note how would this happen? and is it doing the right thing if it does?
-					if (cl_mode != cl_waitjoinresponse)
-						break;
+				// Will be reset by caller. Signals refusal.
+				cl_mode = CL_ABORTED;
+			}
+			break;
 
-					if (!server)
-					{
-						maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
-						gametype = netbuffer->u.servercfg.gametype;
-						modifiedgame = netbuffer->u.servercfg.modifiedgame;
-						adminplayer = netbuffer->u.servercfg.adminplayer;
-						memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
-					}
+		case PT_SERVERCFG: // Positive response of client join request
+		{
+			INT32 j;
+			UINT8 *scp;
+
+			if (server && serverrunning && node != servernode)
+			{ // but wait I thought I'm the server?
+				Net_CloseConnection(node);
+				break;
+			}
+			SERVERONLY
+			/// \note how would this happen? and is it doing the right thing if it does?
+			if (cl_mode != CL_WAITJOINRESPONSE)
+				break;
 
-					nodeingame[(UINT8)servernode] = true;
-					serverplayer = netbuffer->u.servercfg.serverplayer;
-					doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum);
-					mynode = netbuffer->u.servercfg.clientnode;
-					if (serverplayer >= 0)
-						playernode[(UINT8)serverplayer] = servernode;
+			if (client)
+			{
+				maketic = gametic = neededtic = (tic_t)LONG(netbuffer->u.servercfg.gametic);
+				gametype = netbuffer->u.servercfg.gametype;
+				modifiedgame = netbuffer->u.servercfg.modifiedgame;
+				adminplayer = netbuffer->u.servercfg.adminplayer;
+				memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
+			}
 
-					if (netgame)
+			nodeingame[(UINT8)servernode] = true;
+			serverplayer = netbuffer->u.servercfg.serverplayer;
+			doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum);
+			mynode = netbuffer->u.servercfg.clientnode;
+			if (serverplayer >= 0)
+				playernode[(UINT8)serverplayer] = servernode;
+
+			if (netgame)
 #ifdef JOININGAME
-						CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n"));
+				CONS_Printf(M_GetText("Join accepted, waiting for complete game state...\n"));
 #else
-						CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n"));
+				CONS_Printf(M_GetText("Join accepted, waiting for next level change...\n"));
 #endif
-					DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode));
+			DEBFILE(va("Server accept join gametic=%u mynode=%d\n", gametic, mynode));
 
-					memset(playeringame, 0, sizeof(playeringame));
-					for (j = 0; j < MAXPLAYERS; j++)
-					{
-						if (netbuffer->u.servercfg.playerskins[j] == 0xFF
-						 && netbuffer->u.servercfg.playercolor[j] == 0xFF)
-							continue; // not in game
+			memset(playeringame, 0, sizeof(playeringame));
+			for (j = 0; j < MAXPLAYERS; j++)
+			{
+				if (netbuffer->u.servercfg.playerskins[j] == 0xFF
+				 && netbuffer->u.servercfg.playercolor[j] == 0xFF)
+					continue; // not in game
 
-						playeringame[j] = true;
-						SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
-						players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
-					}
+				playeringame[j] = true;
+				SetPlayerSkinByNum(j, (INT32)netbuffer->u.servercfg.playerskins[j]);
+				players[j].skincolor = netbuffer->u.servercfg.playercolor[j];
+			}
 
-					scp = netbuffer->u.servercfg.varlengthinputs;
-					CV_LoadPlayerNames(&scp);
-					CV_LoadNetVars(&scp);
+			scp = netbuffer->u.servercfg.varlengthinputs;
+			CV_LoadPlayerNames(&scp);
+			CV_LoadNetVars(&scp);
 #ifdef JOININGAME
-					if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* ||
-						netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/)
-						cl_mode = cl_downloadsavegame;
-					else
+			/// \note Wait. What if a Lua script uses some global custom variables synched with the NetVars hook?
+			///       Shouldn't them be downloaded even at intermission time?
+			///       Also, according to HandleConnect, the server will send the savegame even during intermission...
+			if (netbuffer->u.servercfg.gamestate == GS_LEVEL/* ||
+				netbuffer->u.servercfg.gamestate == GS_INTERMISSION*/)
+				cl_mode = CL_DOWNLOADSAVEGAME;
+			else
 #endif
-						cl_mode = cl_connected;
-					break;
-				}
-				// handled in d_netfil.c
-				case PT_FILEFRAGMENT:
-					if (server)
-					{ // but wait I thought I'm the server?
-						Net_CloseConnection(node);
-						break;
-					}
-					else
-						Got_Filetxpak();
-					break;
-				case PT_REQUESTFILE:
-					if (server)
-						Got_RequestFilePak(node);
-					break;
-				case PT_NODETIMEOUT:
-				case PT_CLIENTQUIT:
-					if (server)
-						Net_CloseConnection(node);
-					break;
-				case PT_CLIENTCMD:
-					break; // this is not an "unknown packet"
-				case PT_SERVERTICS:
-					// do not remove my own server (we have just get a out of order packet)
-					if (node == servernode)
-						break;
-				default:
-					DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
-					Net_CloseConnection(node);
-					break; // ignore it
-			} // switch
-			continue; //while
+				cl_mode = CL_CONNECTED;
+			break;
 		}
-		if (dedicated && node == 0) netconsole = 0;
-		else netconsole = nodetoplayer[node];
+
+		// Handled in d_netfil.c
+		case PT_FILEFRAGMENT:
+			if (server)
+			{ // But wait I thought I'm the server?
+				Net_CloseConnection(node);
+				break;
+			}
+			SERVERONLY
+			Got_Filetxpak();
+			break;
+
+		case PT_REQUESTFILE:
+			if (server)
+			{
+				if (!cv_downloading.value || !Got_RequestFilePak(node))
+					Net_CloseConnection(node); // close connection if one of the requested files could not be sent, or you disabled downloading anyway
+			}
+			else
+				Net_CloseConnection(node); // nope
+			break;
+
+		case PT_NODETIMEOUT:
+		case PT_CLIENTQUIT:
+			if (server)
+				Net_CloseConnection(node);
+			break;
+
+		case PT_CLIENTCMD:
+			break; // This is not an "unknown packet"
+
+		case PT_SERVERTICS:
+			// Do not remove my own server (we have just get a out of order packet)
+			if (node == servernode)
+				break;
+
+		default:
+			DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
+			Net_CloseConnection(node);
+			break; // Ignore it
+
+	}
+#undef SERVERONLY
+}
+
+/** Handles a packet received from a node that is in game
+  *
+  * \param node The packet sender
+  * \todo Choose a better name
+  * \sa HandlePacketFromAwayNode
+  * \sa GetPackets
+  *
+  */
+static void HandlePacketFromPlayer(SINT8 node)
+{FILESTAMP
+	XBOXSTATIC INT32 netconsole;
+	XBOXSTATIC tic_t realend, realstart;
+	XBOXSTATIC UINT8 *pak, *txtpak, numtxtpak;
+FILESTAMP
+
+	txtpak = NULL;
+
+	if (dedicated && node == 0)
+		netconsole = 0;
+	else
+		netconsole = nodetoplayer[node];
 #ifdef PARANOIA
-		if (netconsole >= MAXPLAYERS)
-			I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
+	if (netconsole >= MAXPLAYERS)
+		I_Error("bad table nodetoplayer: node %d player %d", doomcom->remotenode, netconsole);
 #endif
 
-		txtpak = NULL;
-
-		switch (netbuffer->packettype)
-		{
+	switch (netbuffer->packettype)
+	{
 // -------------------------------------------- SERVER RECEIVE ----------
-			case PT_RESYNCHGET:
-				SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
+		case PT_RESYNCHGET:
+			if (client)
+				break;
+			SV_AcknowledgeResynchAck(netconsole, netbuffer->u.resynchgot);
+			break;
+		case PT_CLIENTCMD:
+		case PT_CLIENT2CMD:
+		case PT_CLIENTMIS:
+		case PT_CLIENT2MIS:
+		case PT_NODEKEEPALIVE:
+		case PT_NODEKEEPALIVEMIS:
+			if (client)
 				break;
-			case PT_CLIENTCMD:
-			case PT_CLIENT2CMD:
-			case PT_CLIENTMIS:
-			case PT_CLIENT2MIS:
-			case PT_NODEKEEPALIVE:
-			case PT_NODEKEEPALIVEMIS:
-				if (!server)
-					break;
 
-				// ignore tics from those not synched
-				if (resynch_inprogress[node])
-					break;
+			// Ignore tics from those not synched
+			if (resynch_inprogress[node])
+				break;
 
-				// to save bytes, only the low byte of tic numbers are sent
-				// Figure out what the rest of the bytes are
-				realstart = ExpandTics(netbuffer->u.clientpak.client_tic);
-				realend = ExpandTics(netbuffer->u.clientpak.resendfrom);
+			// To save bytes, only the low byte of tic numbers are sent
+			// Use ExpandTics to figure out what the rest of the bytes are
+			realstart = ExpandTics(netbuffer->u.clientpak.client_tic);
+			realend = ExpandTics(netbuffer->u.clientpak.resendfrom);
 
-				if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
-					|| netbuffer->packettype == PT_NODEKEEPALIVEMIS
-					|| supposedtics[node] < realend)
-				{
-					supposedtics[node] = realend;
-				}
-				// discard out of order packet
-				if (nettics[node] > realend)
-				{
-					DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node]));
-					break;
-				}
+			if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
+				|| netbuffer->packettype == PT_NODEKEEPALIVEMIS
+				|| supposedtics[node] < realend)
+			{
+				supposedtics[node] = realend;
+			}
+			// Discard out of order packet
+			if (nettics[node] > realend)
+			{
+				DEBFILE(va("out of order ticcmd discarded nettics = %u\n", nettics[node]));
+				break;
+			}
 
-				// update the nettics
-				nettics[node] = realend;
+			// Update the nettics
+			nettics[node] = realend;
 
-				// don't do anything for packets of type NODEKEEPALIVE?
-				if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE
-					|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
-					break;
+			// Don't do anything for packets of type NODEKEEPALIVE?
+			if (netconsole == -1 || netbuffer->packettype == PT_NODEKEEPALIVE
+				|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
+				break;
 
-				// copy ticcmd
-				G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
+			// If a client sends a ticcmd it should mean they are done receiving the savegame
+			sendingsavegame[node] = false;
 
-				// check ticcmd for "speed hacks"
-				if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
-					|| netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE)
+			// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
+			/// \todo Use a separate cvar for that kind of timeout?
+			freezetimeout[node] = I_GetTime() + connectiontimeout;
+
+			// Copy ticcmd
+			G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
+
+			// Check ticcmd for "speed hacks"
+			if (netcmds[maketic%BACKUPTICS][netconsole].forwardmove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].forwardmove < -MAXPLMOVE
+				|| netcmds[maketic%BACKUPTICS][netconsole].sidemove > MAXPLMOVE || netcmds[maketic%BACKUPTICS][netconsole].sidemove < -MAXPLMOVE)
+			{
+				XBOXSTATIC char buf[2];
+				CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), netconsole);
+				//D_Clearticcmd(k);
+
+				buf[0] = (char)netconsole;
+				buf[1] = KICK_MSG_CON_FAIL;
+				SendNetXCmd(XD_KICK, &buf, 2);
+				break;
+			}
+
+			// Splitscreen cmd
+			if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
+				&& nodetoplayer2[node] >= 0)
+				G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
+					&netbuffer->u.client2pak.cmd2, 1);
+
+			// A delay before we check resynching
+			// Used on join or just after a synch fail
+			if (resynch_delay[node])
+			{
+				--resynch_delay[node];
+				break;
+			}
+			// Check player consistancy during the level
+			if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL
+				&& consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy))
+			{
+				SV_RequireResynch(node);
+
+				if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)
 				{
-					XBOXSTATIC char buf[2];
-					CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value recieved from node %d\n"), netconsole);
-					//D_Clearticcmd(k);
+					if (cv_blamecfail.value)
+						CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
+							netconsole+1, player_names[netconsole],
+							consistancy[realstart%BACKUPTICS],
+							SHORT(netbuffer->u.clientpak.consistancy));
+					DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
+						netconsole, realstart, consistancy[realstart%BACKUPTICS],
+						SHORT(netbuffer->u.clientpak.consistancy)));
+					break;
+				}
+				else
+				{
+					XBOXSTATIC UINT8 buf[3];
 
-					buf[0] = (char)netconsole;
+					buf[0] = (UINT8)netconsole;
 					buf[1] = KICK_MSG_CON_FAIL;
 					SendNetXCmd(XD_KICK, &buf, 2);
+					DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
+						netconsole, realstart, consistancy[realstart%BACKUPTICS],
+						SHORT(netbuffer->u.clientpak.consistancy)));
 					break;
 				}
+			}
+			else if (resynch_score[node])
+				--resynch_score[node];
+			break;
+		case PT_TEXTCMD2: // splitscreen special
+			netconsole = nodetoplayer2[node];
+		case PT_TEXTCMD:
+			if (client)
+				break;
 
-				// splitscreen cmd
-				if (netbuffer->packettype == PT_CLIENT2CMD && nodetoplayer2[node] >= 0)
-					G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]],
-						&netbuffer->u.client2pak.cmd2, 1);
+			if (netconsole < 0 || netconsole >= MAXPLAYERS)
+				Net_UnAcknowledgePacket(node);
+			else
+			{
+				size_t j;
+				tic_t tic = maketic;
+				UINT8 *textcmd;
 
-				// a delay before we check resynching
-				// used on join or just after a synch fail
-				if (resynch_delay[node])
+				// ignore if the textcmd has a reported size of zero
+				// this shouldn't be sent at all
+				if (!netbuffer->u.textcmd[0])
 				{
-					--resynch_delay[node];
+					DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
+						node, netconsole));
+					Net_UnAcknowledgePacket(node);
 					break;
 				}
-				// check player consistancy during the level
-				if (realstart <= gametic && realstart > gametic - BACKUPTICS+1 && gamestate == GS_LEVEL
-					&& consistancy[realstart%BACKUPTICS] != SHORT(netbuffer->u.clientpak.consistancy))
-				{
-					SV_RequireResynch(node);
 
-					if (cv_resynchattempts.value && resynch_score[node] <= (unsigned)cv_resynchattempts.value*250)
-					{
-						if (cv_blamecfail.value)
-							CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
-								netconsole+1, player_names[netconsole],
-								consistancy[realstart%BACKUPTICS],
-								SHORT(netbuffer->u.clientpak.consistancy));
-						DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
-							netconsole, realstart, consistancy[realstart%BACKUPTICS],
-							SHORT(netbuffer->u.clientpak.consistancy)));
-						break;
-					}
-					else
-					{
-						XBOXSTATIC UINT8 buf[3];
-
-						buf[0] = (UINT8)netconsole;
-						buf[1] = KICK_MSG_CON_FAIL;
-						SendNetXCmd(XD_KICK, &buf, 2);
-						DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
-							netconsole, realstart, consistancy[realstart%BACKUPTICS],
-							SHORT(netbuffer->u.clientpak.consistancy)));
-						break;
-					}
-				}
-				else if (resynch_score[node])
-					--resynch_score[node];
-				break;
-			case PT_TEXTCMD2: // splitscreen special
-				netconsole = nodetoplayer2[node];
-			case PT_TEXTCMD:
-				if (!server)
+				// ignore if the textcmd size var is actually larger than it should be
+				// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
+				if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
+				{
+					DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
+					netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
+						node, netconsole));
+					Net_UnAcknowledgePacket(node);
 					break;
+				}
 
-				if (netconsole < 0 || netconsole >= MAXPLAYERS)
-					Net_UnAcknowledgPacket(node);
-				else
+				// check if tic that we are making isn't too large else we cannot send it :(
+				// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
+				j = software_MAXPACKETLENGTH
+					- (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE
+					+ (doomcom->numslots+1)*sizeof(ticcmd_t));
+
+				// search a tic that have enougth space in the ticcmd
+				while ((textcmd = D_GetExistingTextcmd(tic, netconsole)),
+					(TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD)
+					&& tic < firstticstosend + BACKUPTICS)
+					tic++;
+
+				if (tic >= firstticstosend + BACKUPTICS)
 				{
-					size_t j;
-					tic_t tic = maketic;
-					UINT8 *textcmd;
-
-					// check if tic that we are making isn't too large else we cannot send it :(
-					// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
-					j = software_MAXPACKETLENGTH
-						- (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE
-						+ (doomcom->numslots+1)*sizeof(ticcmd_t));
-
-					// search a tic that have enougth space in the ticcmd
-					while ((textcmd = D_GetExistingTextcmd(tic, netconsole)),
-						(TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD)
-						&& tic < firstticstosend + BACKUPTICS)
-						tic++;
-
-					if (tic >= firstticstosend + BACKUPTICS)
-					{
-						DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, "
-							"tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)),
-							maketic, firstticstosend, node, netconsole));
-						Net_UnAcknowledgPacket(node);
-						break;
-					}
+					DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, "
+						"tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)),
+						maketic, firstticstosend, node, netconsole));
+					Net_UnAcknowledgePacket(node);
+					break;
+				}
 
-					// Make sure we have a buffer
-					if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole);
+				// Make sure we have a buffer
+				if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole);
 
-					DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n",
-						tic, textcmd[0]+1, netconsole, firstticstosend, maketic));
+				DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n",
+					tic, textcmd[0]+1, netconsole, firstticstosend, maketic));
 
-					M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
-					textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
-				}
+				M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
+				textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
+			}
+			break;
+		case PT_NODETIMEOUT:
+		case PT_CLIENTQUIT:
+			if (client)
 				break;
-			case PT_NODETIMEOUT:
-			case PT_CLIENTQUIT:
-				if (!server)
-					break;
 
-				// nodeingame will be put false in the execution of kick command
-				// this allow to send some packets to the quitting client to have their ack back
-				nodewaiting[node] = 0;
-				if (netconsole != -1 && playeringame[netconsole])
+			// nodeingame will be put false in the execution of kick command
+			// this allow to send some packets to the quitting client to have their ack back
+			nodewaiting[node] = 0;
+			if (netconsole != -1 && playeringame[netconsole])
+			{
+				XBOXSTATIC UINT8 buf[2];
+				buf[0] = (UINT8)netconsole;
+				if (netbuffer->packettype == PT_NODETIMEOUT)
+					buf[1] = KICK_MSG_TIMEOUT;
+				else
+					buf[1] = KICK_MSG_PLAYER_QUIT;
+				SendNetXCmd(XD_KICK, &buf, 2);
+				nodetoplayer[node] = -1;
+				if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0
+					&& playeringame[(UINT8)nodetoplayer2[node]])
 				{
-					XBOXSTATIC UINT8 buf[2];
-					buf[0] = (UINT8)netconsole;
-					if (netbuffer->packettype == PT_NODETIMEOUT)
-						buf[1] = KICK_MSG_TIMEOUT;
-					else
-						buf[1] = KICK_MSG_PLAYER_QUIT;
+					buf[0] = nodetoplayer2[node];
 					SendNetXCmd(XD_KICK, &buf, 2);
-					nodetoplayer[node] = -1;
-					if (nodetoplayer2[node] != -1 && nodetoplayer2[node] >= 0
-						&& playeringame[(UINT8)nodetoplayer2[node]])
-					{
-						buf[0] = nodetoplayer2[node];
-						SendNetXCmd(XD_KICK, &buf, 2);
-						nodetoplayer2[node] = -1;
-					}
+					nodetoplayer2[node] = -1;
 				}
-				Net_CloseConnection(node);
-				nodeingame[node] = false;
-				break;
+			}
+			Net_CloseConnection(node);
+			nodeingame[node] = false;
+			break;
 // -------------------------------------------- CLIENT RECEIVE ----------
-			case PT_RESYNCHEND:
-				// Only accept PT_RESYNCHEND from the server.
-				if (node != servernode)
+		case PT_RESYNCHEND:
+			// Only accept PT_RESYNCHEND from the server.
+			if (node != servernode)
+			{
+				CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHEND", node);
+
+				if (server)
 				{
-					CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHEND", node);
+					XBOXSTATIC UINT8 buf[2];
+					buf[0] = (UINT8)node;
+					buf[1] = KICK_MSG_CON_FAIL;
+					SendNetXCmd(XD_KICK, &buf, 2);
+				}
 
-					if (server)
-					{
-						XBOXSTATIC UINT8 buf[2];
-						buf[0] = (UINT8)node;
-						buf[1] = KICK_MSG_CON_FAIL;
-						SendNetXCmd(XD_KICK, &buf, 2);
-					}
+				break;
+			}
+			resynch_local_inprogress = false;
 
-					break;
-				}
-				resynch_local_inprogress = false;
+			P_SetRandSeed(netbuffer->u.resynchend.randomseed);
 
-				P_SetRandSeed(netbuffer->u.resynchend.randomseed);
+			if (gametype == GT_CTF)
+				resynch_read_ctf(&netbuffer->u.resynchend);
+			resynch_read_others(&netbuffer->u.resynchend);
 
-				if (gametype == GT_CTF)
-					resynch_read_ctf(&netbuffer->u.resynchend);
-				resynch_read_others(&netbuffer->u.resynchend);
+			break;
+		case PT_SERVERTICS:
+			// Only accept PT_SERVERTICS from the server.
+			if (node != servernode)
+			{
+				CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node);
 
-				break;
-			case PT_SERVERTICS:
-				// Only accept PT_SERVERTICS from the server.
-				if (node != servernode)
+				if (server)
 				{
-					CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_SERVERTICS", node);
+					XBOXSTATIC UINT8 buf[2];
+					buf[0] = (UINT8)node;
+					buf[1] = KICK_MSG_CON_FAIL;
+					SendNetXCmd(XD_KICK, &buf, 2);
+				}
 
-					if (server)
-					{
-						XBOXSTATIC UINT8 buf[2];
-						buf[0] = (UINT8)node;
-						buf[1] = KICK_MSG_CON_FAIL;
-						SendNetXCmd(XD_KICK, &buf, 2);
-					}
+				break;
+			}
 
-					break;
-				}
+			realstart = ExpandTics(netbuffer->u.serverpak.starttic);
+			realend = realstart + netbuffer->u.serverpak.numtics;
 
-				realstart = ExpandTics(netbuffer->u.serverpak.starttic);
-				realend = realstart + netbuffer->u.serverpak.numtics;
+			if (!txtpak)
+				txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots
+					* netbuffer->u.serverpak.numtics];
 
-				if (!txtpak)
-					txtpak = (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots
-						* netbuffer->u.serverpak.numtics];
+			if (realend > gametic + BACKUPTICS)
+				realend = gametic + BACKUPTICS;
+			cl_packetmissed = realstart > neededtic;
 
-				if (realend > gametic + BACKUPTICS)
-					realend = gametic + BACKUPTICS;
-				cl_packetmissed = realstart > neededtic;
+			if (realstart <= neededtic && realend > neededtic)
+			{
+				tic_t i, j;
+				pak = (UINT8 *)&netbuffer->u.serverpak.cmds;
 
-				if (realstart <= neededtic && realend > neededtic)
+				for (i = realstart; i < realend; i++)
 				{
-					tic_t i, j;
-					pak = (UINT8 *)&netbuffer->u.serverpak.cmds;
+					// clear first
+					D_Clearticcmd(i);
 
-					for (i = realstart; i < realend; i++)
-					{
-						// clear first
-						D_Clearticcmd(i);
+					// copy the tics
+					pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
+						netbuffer->u.serverpak.numslots*sizeof (ticcmd_t));
 
-						// copy the tics
-						pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
-							netbuffer->u.serverpak.numslots*sizeof (ticcmd_t));
-
-						// copy the textcmds
-						numtxtpak = *txtpak++;
-						for (j = 0; j < numtxtpak; j++)
-						{
-							INT32 k = *txtpak++; // playernum
-							const size_t txtsize = txtpak[0]+1;
+					// copy the textcmds
+					numtxtpak = *txtpak++;
+					for (j = 0; j < numtxtpak; j++)
+					{
+						INT32 k = *txtpak++; // playernum
+						const size_t txtsize = txtpak[0]+1;
 
-							M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
-							txtpak += txtsize;
-						}
+						M_Memcpy(D_GetTextcmd(i, k), txtpak, txtsize);
+						txtpak += txtsize;
 					}
-
-					neededtic = realend;
 				}
-				else
-					DEBFILE(va("frame not in bound: %u\n", neededtic));
-				break;
-			case PT_RESYNCHING:
-				// Only accept PT_RESYNCHING from the server.
-				if (node != servernode)
-				{
-					CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_RESYNCHING", node);
 
-					if (server)
-					{
-						XBOXSTATIC char buf[2];
-						buf[0] = (char)node;
-						buf[1] = KICK_MSG_CON_FAIL;
-						SendNetXCmd(XD_KICK, &buf, 2);
-					}
+				neededtic = realend;
+			}
+			else
+			{
+				DEBFILE(va("frame not in bound: %u\n", neededtic));
+				/*if (realend < neededtic - 2 * TICRATE || neededtic + 2 * TICRATE < realstart)
+					I_Error("Received an out of order PT_SERVERTICS packet!\n"
+							"Got tics %d-%d, needed tic %d\n\n"
+							"Please report this crash on the Master Board,\n"
+							"IRC or Discord so it can be fixed.\n", (INT32)realstart, (INT32)realend, (INT32)neededtic);*/
+			}
+			break;
+		case PT_RESYNCHING:
+			// Only accept PT_RESYNCHING from the server.
+			if (node != servernode)
+			{
+				CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_RESYNCHING", node);
 
-					break;
+				if (server)
+				{
+					XBOXSTATIC char buf[2];
+					buf[0] = (char)node;
+					buf[1] = KICK_MSG_CON_FAIL;
+					SendNetXCmd(XD_KICK, &buf, 2);
 				}
-				resynch_local_inprogress = true;
-				CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
+
 				break;
+			}
+			resynch_local_inprogress = true;
+			CL_AcknowledgeResynch(&netbuffer->u.resynchpak);
+			break;
 #ifdef NEWPING
-			case PT_PING:
-				// Only accept PT_PING from the server.
-				if (node != servernode)
+		case PT_PING:
+			// Only accept PT_PING from the server.
+			if (node != servernode)
+			{
+				CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_PING", node);
+
+				if (server)
 				{
-					CONS_Alert(CONS_WARNING, M_GetText("%s recieved from non-host %d\n"), "PT_PING", node);
+					XBOXSTATIC char buf[2];
+					buf[0] = (char)node;
+					buf[1] = KICK_MSG_CON_FAIL;
+					SendNetXCmd(XD_KICK, &buf, 2);
+				}
 
-					if (server)
-					{
-						XBOXSTATIC char buf[2];
-						buf[0] = (char)node;
-						buf[1] = KICK_MSG_CON_FAIL;
-						SendNetXCmd(XD_KICK, &buf, 2);
-					}
+				break;
+			}
 
-					break;
-				}
+			//Update client ping table from the server.
+			if (client)
+			{
+				INT32 i;
+				for (i = 0; i < MAXNETNODES; i++)
+					if (playeringame[i])
+						playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
+			}
 
-				//Update client ping table from the server.
-				if (!server)
+			break;
+#endif
+		case PT_SERVERCFG:
+			break;
+		case PT_FILEFRAGMENT:
+			// Only accept PT_FILEFRAGMENT from the server.
+			if (node != servernode)
+			{
+				CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
+
+				if (server)
 				{
-					INT32 i;
-					for (i = 0; i < MAXNETNODES; i++)
-						if (playeringame[i])
-							playerpingtable[i] = (tic_t)netbuffer->u.pingtable[i];
+					XBOXSTATIC UINT8 buf[2];
+					buf[0] = (UINT8)node;
+					buf[1] = KICK_MSG_CON_FAIL;
+					SendNetXCmd(XD_KICK, &buf, 2);
 				}
 
 				break;
+			}
+			if (client)
+				Got_Filetxpak();
+			break;
+		default:
+			DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n",
+				netbuffer->packettype, node));
+	} // end switch
+}
+
+/**	Handles all received packets, if any
+  *
+  * \todo Add details to this description (lol)
+  *
+  */
+static void GetPackets(void)
+{FILESTAMP
+	XBOXSTATIC SINT8 node; // The packet sender
+FILESTAMP
+
+	player_joining = false;
+
+	while (HGetPacket())
+	{
+		node = (SINT8)doomcom->remotenode;
+
+		if (netbuffer->packettype == PT_CLIENTJOIN && server)
+		{
+			HandleConnect(node);
+			continue;
+		}
+		if (node == servernode && client && cl_mode != CL_SEARCHING)
+		{
+			if (netbuffer->packettype == PT_SERVERSHUTDOWN)
+			{
+				HandleShutdown(node);
+				continue;
+			}
+			if (netbuffer->packettype == PT_NODETIMEOUT)
+			{
+				HandleTimeout(node);
+				continue;
+			}
+		}
+
+#ifndef NONET
+		if (netbuffer->packettype == PT_SERVERINFO)
+		{
+			HandleServerInfo(node);
+			continue;
+		}
 #endif
-			case PT_SERVERCFG:
-				break;
-			case PT_FILEFRAGMENT:
-				if (!server)
-					Got_Filetxpak();
-				break;
-			default:
-				DEBFILE(va("UNKNOWN PACKET TYPE RECEIVED %d from host %d\n",
-					netbuffer->packettype, node));
-		} // end switch
-	} // end while
+
+		if (netbuffer->packettype == PT_PLAYERINFO)
+			continue; // We do nothing with PLAYERINFO, that's for the MS browser.
+
+		// Packet received from someone already playing
+		if (nodeingame[node])
+			HandlePacketFromPlayer(node);
+		// Packet received from someone not playing
+		else
+			HandlePacketFromAwayNode(node);
+	}
 }
 
 //
@@ -3768,6 +4088,10 @@ static INT16 Consistancy(void)
 {
 	INT32 i;
 	UINT32 ret = 0;
+#ifdef MOBJCONSISTANCY
+	thinker_t *th;
+	mobj_t *mo;
+#endif
 
 	DEBFILE(va("TIC %u ", gametic));
 
@@ -3789,6 +4113,77 @@ static INT16 Consistancy(void)
 	if (!G_PlatformGametype())
 		ret += P_GetRandSeed();
 
+#ifdef MOBJCONSISTANCY
+	if (!thinkercap.next)
+		return ret;
+	for (th = thinkercap.next; th != &thinkercap; th = th->next)
+	{
+		if (th->function.acp1 != (actionf_p1)P_MobjThinker)
+			continue;
+
+		mo = (mobj_t *)th;
+
+		if (mo->flags & (MF_SPECIAL | MF_SOLID | MF_PUSHABLE | MF_BOSS | MF_MISSILE | MF_SPRING | MF_MONITOR | MF_FIRE | MF_ENEMY | MF_PAIN | MF_STICKY))
+		{
+			ret -= mo->type;
+			ret += mo->x;
+			ret -= mo->y;
+			ret += mo->z;
+			ret -= mo->momx;
+			ret += mo->momy;
+			ret -= mo->momz;
+			ret += mo->angle;
+			ret -= mo->flags;
+			ret += mo->flags2;
+			ret -= mo->eflags;
+			if (mo->target)
+			{
+				ret += mo->target->type;
+				ret -= mo->target->x;
+				ret += mo->target->y;
+				ret -= mo->target->z;
+				ret += mo->target->momx;
+				ret -= mo->target->momy;
+				ret += mo->target->momz;
+				ret -= mo->target->angle;
+				ret += mo->target->flags;
+				ret -= mo->target->flags2;
+				ret += mo->target->eflags;
+				ret -= mo->target->state - states;
+				ret += mo->target->tics;
+				ret -= mo->target->sprite;
+				ret += mo->target->frame;
+			}
+			else
+				ret ^= 0x3333;
+			if (mo->tracer && mo->tracer->type != MT_OVERLAY)
+			{
+				ret += mo->tracer->type;
+				ret -= mo->tracer->x;
+				ret += mo->tracer->y;
+				ret -= mo->tracer->z;
+				ret += mo->tracer->momx;
+				ret -= mo->tracer->momy;
+				ret += mo->tracer->momz;
+				ret -= mo->tracer->angle;
+				ret += mo->tracer->flags;
+				ret -= mo->tracer->flags2;
+				ret += mo->tracer->eflags;
+				ret -= mo->tracer->state - states;
+				ret += mo->tracer->tics;
+				ret -= mo->tracer->sprite;
+				ret += mo->tracer->frame;
+			}
+			else
+				ret ^= 0xAAAA;
+			ret -= mo->state - states;
+			ret += mo->tics;
+			ret -= mo->sprite;
+			ret += mo->frame;
+		}
+	}
+#endif
+
 	return (INT16)(ret & 0xFFFF);
 }
 
@@ -3806,7 +4201,7 @@ static void CL_SendClientCmd(void)
 
 	if (gamestate == GS_WAITINGPLAYERS)
 	{
-		// send NODEKEEPALIVE packet
+		// Send PT_NODEKEEPALIVE packet
 		netbuffer->packettype += 4;
 		packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
 		HSendPacket(servernode, false, 0, packetsize);
@@ -3816,7 +4211,7 @@ static void CL_SendClientCmd(void)
 		G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
 		netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
 
-		// send a special packet with 2 cmd for splitscreen
+		// Send a special packet with 2 cmd for splitscreen
 		if (splitscreen || botingame)
 		{
 			netbuffer->packettype += 2;
@@ -3829,25 +4224,25 @@ static void CL_SendClientCmd(void)
 		HSendPacket(servernode, false, 0, packetsize);
 	}
 
-	if (cl_mode == cl_connected || dedicated)
+	if (cl_mode == CL_CONNECTED || dedicated)
 	{
-		// send extra data if needed
+		// Send extra data if needed
 		if (localtextcmd[0])
 		{
 			netbuffer->packettype = PT_TEXTCMD;
 			M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
-			// all extra data have been sended
-			if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // send can fail...
+			// All extra data have been sent
+			if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
 				localtextcmd[0] = 0;
 		}
 
-		// send extra data if needed for player 2 (splitscreen)
+		// Send extra data if needed for player 2 (splitscreen)
 		if (localtextcmd2[0])
 		{
 			netbuffer->packettype = PT_TEXTCMD2;
 			M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
-			// all extra data have been sended
-			if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // send can fail...
+			// All extra data have been sent
+			if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
 				localtextcmd2[0] = 0;
 		}
 	}
@@ -4111,7 +4506,7 @@ static inline void PingUpdate(void)
 	//check for ping limit breakage.
 	if (cv_maxping.value)
 	{
-		for (i = 1; i < MAXNETNODES; i++)
+		for (i = 1; i < MAXPLAYERS; i++)
 		{
 			if (playeringame[i] && (realpingtable[i] / pingmeasurecount > (unsigned)cv_maxping.value))
 			{
@@ -4125,7 +4520,7 @@ static inline void PingUpdate(void)
 		//in that case, it is probably the server's fault.
 		if (numlaggers < D_NumPlayers() - 1)
 		{
-			for (i = 1; i < MAXNETNODES; i++)
+			for (i = 1; i < MAXPLAYERS; i++)
 			{
 				if (playeringame[i] && laggers[i])
 				{
@@ -4140,7 +4535,7 @@ static inline void PingUpdate(void)
 	}
 
 	//make the ping packet and clear server data for next one
-	for (i = 0; i < MAXNETNODES; i++)
+	for (i = 0; i < MAXPLAYERS; i++)
 	{
 		netbuffer->u.pingtable[i] = realpingtable[i] / pingmeasurecount;
 		//server takes a snapshot of the real ping for display.
@@ -4150,7 +4545,7 @@ static inline void PingUpdate(void)
 	}
 
 	//send out our ping packets
-	for (i = 0; i < MAXNETNODES; i++)
+	for (i = 0; i < MAXPLAYERS; i++)
 		if (playeringame[i])
 			HSendPacket(i, true, 0, sizeof(INT32) * MAXPLAYERS);
 
@@ -4199,7 +4594,7 @@ void NetUpdate(void)
 	}
 #endif
 
-	if (!server)
+	if (client)
 		maketic = neededtic;
 
 	Local_Maketic(realtics); // make local tic, and call menu?
@@ -4212,12 +4607,12 @@ FILESTAMP
 	// client send the command after a receive of the server
 	// the server send before because in single player is beter
 
-	MasterClient_Ticker(); // acking the master server
+	MasterClient_Ticker(); // Acking the Master Server
 
-	if (!server)
+	if (client)
 	{
 		if (!resynch_local_inprogress)
-			CL_SendClientCmd(); // send tic cmd
+			CL_SendClientCmd(); // Send tic cmd
 		hu_resynching = resynch_local_inprogress;
 	}
 	else
@@ -4243,27 +4638,32 @@ FILESTAMP
 					counts = -666;
 				}
 
-			// do not make tics while resynching
+			// Do not make tics while resynching
 			if (counts != -666)
 			{
 				if (maketic + counts >= firstticstosend + BACKUPTICS)
 					counts = firstticstosend+BACKUPTICS-maketic-1;
 
 				for (i = 0; i < counts; i++)
-					SV_Maketic(); // create missed tics and increment maketic
+					SV_Maketic(); // Create missed tics and increment maketic
 
-				for (; tictoclear < firstticstosend; tictoclear++) // clear only when acknoledged
-					D_Clearticcmd(tictoclear);                    // clear the maketic the new tic
+				for (; tictoclear < firstticstosend; tictoclear++) // Clear only when acknowledged
+					D_Clearticcmd(tictoclear);                    // Clear the maketic the new tic
 
 				SV_SendTics();
 
-				neededtic = maketic; // the server is a client too
+				neededtic = maketic; // The server is a client too
 			}
 			else
 				hu_resynching = true;
 		}
 	}
 	Net_AckTicker();
+	// Handle timeouts to prevent definitive freezes from happenning
+	if (server)
+		for (i = 1; i < MAXNETNODES; i++)
+			if (nodeingame[i] && freezetimeout[i] < I_GetTime())
+				Net_ConnectionTimeout(i);
 	nowtime /= NEWTICRATERATIO;
 	if (nowtime > resptime)
 	{
@@ -4271,7 +4671,7 @@ FILESTAMP
 		M_Ticker();
 		CON_Ticker();
 	}
-	FiletxTicker();
+	SV_FileSendTicker();
 }
 
 /** Returns the number of players playing.
diff --git a/src/d_clisrv.h b/src/d_clisrv.h
index 14b590926fdd476cf3705d2c63fd30f803d041e7..e7f1e8433dad04bb4865c91aa8b118d9b6f9b10f 100644
--- a/src/d_clisrv.h
+++ b/src/d_clisrv.h
@@ -59,7 +59,7 @@ typedef enum
 	// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
 
 	PT_CANFAIL,       // This is kind of a priority. Anything bigger than CANFAIL
-	                  // allows HSendPacket(,true,,) to return false.
+	                  // allows HSendPacket(*, true, *, *) to return false.
 	                  // In addition, this packet can't occupy all the available slots.
 
 	PT_FILEFRAGMENT = PT_CANFAIL, // A part of a file.
@@ -76,11 +76,19 @@ typedef enum
 	NUMPACKETTYPE
 } packettype_t;
 
+#ifdef PACKETDROP
+void Command_Drop(void);
+void Command_Droprate(void);
+#endif
+#ifdef _DEBUG
+void Command_Numnodes(void);
+#endif
+
 #if defined(_MSC_VER)
 #pragma pack(1)
 #endif
 
-// client to server packet
+// Client to server packet
 typedef struct
 {
 	UINT8 client_tic;
@@ -89,7 +97,7 @@ typedef struct
 	ticcmd_t cmd;
 } ATTRPACK clientcmd_pak;
 
-// splitscreen packet
+// Splitscreen packet
 // WARNING: must have the same format of clientcmd_pak, for more easy use
 typedef struct
 {
@@ -110,16 +118,16 @@ typedef struct
 	UINT8 starttic;
 	UINT8 numtics;
 	UINT8 numslots; // "Slots filled": Highest player number in use plus one.
-	ticcmd_t cmds[45]; // normally [BACKUPTIC][MAXPLAYERS] but too large
+	ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large
 } ATTRPACK servertics_pak;
 
-// sent to client when all consistency data
+// Sent to client when all consistency data
 // for players has been restored
 typedef struct
 {
 	UINT32 randomseed;
 
-	//ctf flag stuff
+	// CTF flag stuff
 	SINT8 flagplayer[2];
 	INT32 flagloose[2];
 	INT32 flagflags[2];
@@ -127,11 +135,11 @@ typedef struct
 	fixed_t flagy[2];
 	fixed_t flagz[2];
 
-	UINT32 ingame;  // spectator bit for each player
-	UINT32 ctfteam; // if not spectator, then which team?
+	UINT32 ingame;  // Spectator bit for each player
+	INT32 ctfteam[MAXPLAYERS]; // Which team? (can't be 1 bit, since in regular Match there are no teams)
 
 	// Resynch game scores and the like all at once
-	UINT32 score[MAXPLAYERS]; // Everyone's score.
+	UINT32 score[MAXPLAYERS]; // Everyone's score
 	INT16 numboxes[MAXPLAYERS];
 	INT16 totalring[MAXPLAYERS];
 	tic_t realtime[MAXPLAYERS];
@@ -140,14 +148,14 @@ typedef struct
 
 typedef struct
 {
-	//player stuff
+	// Player stuff
 	UINT8 playernum;
 
 	// Do not send anything visual related.
 	// Only send data that we need to know for physics.
-	UINT8 playerstate; //playerstate_t
-	UINT32 pflags; //pflags_t
-	UINT8 panim; //panim_t
+	UINT8 playerstate; // playerstate_t
+	UINT32 pflags; // pflags_t
+	UINT8 panim; // panim_t
 
 	angle_t aiming;
 	INT32 currentweapon;
@@ -174,9 +182,9 @@ typedef struct
 	UINT8 charability;
 	UINT8 charability2;
 	UINT32 charflags;
-	UINT32 thokitem; //mobjtype_t
-	UINT32 spinitem; //mobjtype_t
-	UINT32 revitem; //mobjtype_t
+	UINT32 thokitem; // mobjtype_t
+	UINT32 spinitem; // mobjtype_t
+	UINT32 revitem; // mobjtype_t
 	fixed_t actionspd;
 	fixed_t mindash;
 	fixed_t maxdash;
@@ -230,7 +238,7 @@ typedef struct
 	INT32 onconveyor;
 
 	//player->mo stuff
-	UINT8 hasmo; //boolean
+	UINT8 hasmo; // Boolean
 
 	angle_t angle;
 	fixed_t x;
@@ -257,10 +265,10 @@ typedef struct
 
 typedef struct
 {
-	UINT8 version; // different versions don't work
-	UINT8 subversion; // contains build version
+	UINT8 version; // Different versions don't work
+	UINT8 subversion; // Contains build version
 
-	// server launch stuffs
+	// Server launch stuffs
 	UINT8 serverplayer;
 	UINT8 totalslotnum; // "Slots": highest player number in use plus one.
 
@@ -274,18 +282,18 @@ typedef struct
 
 	UINT8 gametype;
 	UINT8 modifiedgame;
-	SINT8 adminplayer; // needs to be signed
+	SINT8 adminplayer; // Needs to be signed
 
-	char server_context[8]; // unique context id, generated at server startup.
+	char server_context[8]; // Unique context id, generated at server startup.
 
-	UINT8 varlengthinputs[0]; // playernames and netvars
+	UINT8 varlengthinputs[0]; // Playernames and netvars
 } ATTRPACK serverconfig_pak;
 
 typedef struct {
 	UINT8 fileid;
 	UINT32 position;
 	UINT16 size;
-	UINT8 data[0]; // size is variable using hardware_MAXPACKETLENGTH
+	UINT8 data[0]; // Size is variable using hardware_MAXPACKETLENGTH
 } ATTRPACK filetx_pak;
 
 #ifdef _MSC_VER
@@ -294,14 +302,14 @@ typedef struct {
 
 typedef struct
 {
-	UINT8 version; // different versions don't work
-	UINT8 subversion; // contains build version
+	UINT8 version; // Different versions don't work
+	UINT8 subversion; // Contains build version
 	UINT8 localplayers;
 	UINT8 mode;
 } ATTRPACK clientconfig_pak;
 
 #define MAXSERVERNAME 32
-// this packet is too large
+// This packet is too large
 typedef struct
 {
 	UINT8 version;
@@ -367,45 +375,45 @@ typedef struct
 } ATTRPACK plrconfig;
 
 //
-// Network packet data.
+// Network packet data
 //
 typedef struct
 {
 	UINT32 checksum;
-	UINT8 ack; // if not null the node asks for acknowledgement, the receiver must resend the ack
-	UINT8 ackreturn; // the return of the ack number
+	UINT8 ack; // If not zero the node asks for acknowledgement, the receiver must resend the ack
+	UINT8 ackreturn; // The return of the ack number
 
 	UINT8 packettype;
-	UINT8 reserved; // padding
+	UINT8 reserved; // Padding
 	union
 	{
-		clientcmd_pak clientpak;    //      144 bytes
-		client2cmd_pak client2pak;  //      200 bytes
-		servertics_pak serverpak;   //   132495 bytes
-		serverconfig_pak servercfg; //      773 bytes
-		resynchend_pak resynchend;  //
-		resynch_pak resynchpak;     //
-		UINT8 resynchgot;           //
-		UINT8 textcmd[MAXTEXTCMD+1]; //   66049 bytes
-		filetx_pak filetxpak;       //      139 bytes
-		clientconfig_pak clientcfg; //      136 bytes
-		serverinfo_pak serverinfo;  //     1024 bytes
-		serverrefuse_pak serverrefuse; // 65025 bytes
-		askinfo_pak askinfo;        //       61 bytes
-		msaskinfo_pak msaskinfo;    //       22 bytes
-		plrinfo playerinfo[MAXPLAYERS]; // 1152 bytes
-		plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes
+		clientcmd_pak clientpak;            //         144 bytes
+		client2cmd_pak client2pak;          //         200 bytes
+		servertics_pak serverpak;           //      132495 bytes (more around 360, no?)
+		serverconfig_pak servercfg;         //         773 bytes
+		resynchend_pak resynchend;          //
+		resynch_pak resynchpak;             //
+		UINT8 resynchgot;                   //
+		UINT8 textcmd[MAXTEXTCMD+1];        //       66049 bytes (wut??? 64k??? More like 257 bytes...)
+		filetx_pak filetxpak;               //         139 bytes
+		clientconfig_pak clientcfg;         //         136 bytes
+		serverinfo_pak serverinfo;          //        1024 bytes
+		serverrefuse_pak serverrefuse;      //       65025 bytes (somehow I feel like those values are garbage...)
+		askinfo_pak askinfo;                //          61 bytes
+		msaskinfo_pak msaskinfo;            //          22 bytes
+		plrinfo playerinfo[MAXPLAYERS];     //        1152 bytes (I'd say 36~38)
+		plrconfig playerconfig[MAXPLAYERS]; // (up to) 896 bytes (welp they ARE)
 #ifdef NEWPING
-		UINT32 pingtable[MAXPLAYERS]; //    128 bytes
+		UINT32 pingtable[MAXPLAYERS];       //         128 bytes
 #endif
-	} u; // this is needed to pack diff packet types data together
+	} u; // This is needed to pack diff packet types data together
 } ATTRPACK doomdata_t;
 
 #if defined(_MSC_VER)
 #pragma pack()
 #endif
 
-#define MAXSERVERLIST 64 // depends only on the display
+#define MAXSERVERLIST 64 // Depends only on the display
 typedef struct
 {
 	SINT8 node;
@@ -416,7 +424,7 @@ extern serverelem_t serverlist[MAXSERVERLIST];
 extern UINT32 serverlistcount;
 extern INT32 mapchangepending;
 
-// points inside doomcom
+// Points inside doomcom
 extern doomdata_t *netbuffer;
 
 extern consvar_t cv_playbackspeed;
@@ -437,26 +445,28 @@ extern consvar_t cv_playbackspeed;
 #define KICK_MSG_CUSTOM_BAN  8
 
 extern boolean server;
-extern boolean dedicated; // for dedicated server
+#define client (!server)
+extern boolean dedicated; // For dedicated server
 extern UINT16 software_MAXPACKETLENGTH;
 extern boolean acceptnewnode;
 extern SINT8 servernode;
 
 void Command_Ping_f(void);
 extern tic_t connectiontimeout;
+extern tic_t jointimeout;
 #ifdef NEWPING
 extern UINT16 pingmeasurecount;
 extern UINT32 realpingtable[MAXPLAYERS];
 extern UINT32 playerpingtable[MAXPLAYERS];
 #endif
 
-extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend;
+extern consvar_t cv_joinnextround, cv_allownewplayer, cv_maxplayers, cv_resynchattempts, cv_blamecfail, cv_maxsend, cv_noticedownload, cv_downloadspeed;
 
-// used in d_net, the only dependence
+// Used in d_net, the only dependence
 tic_t ExpandTics(INT32 low);
 void D_ClientServerInit(void);
 
-// initialise the other field
+// Initialise the other field
 void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
 void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
 void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
@@ -474,14 +484,14 @@ void CL_RemoveSplitscreenPlayer(void);
 void CL_Reset(void);
 void CL_ClearPlayer(INT32 playernum);
 void CL_UpdateServerList(boolean internetsearch, INT32 room);
-// is there a game running
+// Is there a game running
 boolean Playing(void);
 
 // Broadcasts special packets to other players
 //  to notify of game exit
 void D_QuitNetGame(void);
 
-//? how many ticks to run?
+//? How many ticks to run?
 void TryRunTics(tic_t realtic);
 
 // extra data for lmps
diff --git a/src/d_main.c b/src/d_main.c
index 14a8a06e1356f2e7270927d6de9c126f5a26a3b4..4080087c1245d71ecc07e65a9613df365e316883 100644
--- a/src/d_main.c
+++ b/src/d_main.c
@@ -73,6 +73,7 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 #include "dehacked.h" // Dehacked list test
 #include "m_cond.h" // condition initialization
 #include "fastcmp.h"
+#include "keys.h"
 
 #ifdef CMAKECONFIG
 #include "config.h"
@@ -176,6 +177,38 @@ void D_PostEvent(const event_t *ev)
 void D_PostEvent_end(void) {};
 #endif
 
+// modifier keys
+UINT8 shiftdown = 0; // 0x1 left, 0x2 right
+UINT8 ctrldown = 0; // 0x1 left, 0x2 right
+UINT8 altdown = 0; // 0x1 left, 0x2 right
+//
+// D_ModifierKeyResponder
+// Sets global shift/ctrl/alt variables, never actually eats events
+//
+static inline void D_ModifierKeyResponder(event_t *ev)
+{
+	if (ev->type == ev_keydown || ev->type == ev_console) switch (ev->data1)
+	{
+		case KEY_LSHIFT: shiftdown |= 0x1; return;
+		case KEY_RSHIFT: shiftdown |= 0x2; return;
+		case KEY_LCTRL: ctrldown |= 0x1; return;
+		case KEY_RCTRL: ctrldown |= 0x2; return;
+		case KEY_LALT: altdown |= 0x1; return;
+		case KEY_RALT: altdown |= 0x2; return;
+		default: return;
+	}
+	else if (ev->type == ev_keyup) switch (ev->data1)
+	{
+		case KEY_LSHIFT: shiftdown &= ~0x1; return;
+		case KEY_RSHIFT: shiftdown &= ~0x2; return;
+		case KEY_LCTRL: ctrldown &= ~0x1; return;
+		case KEY_RCTRL: ctrldown &= ~0x2; return;
+		case KEY_LALT: altdown &= ~0x1; return;
+		case KEY_RALT: altdown &= ~0x2; return;
+		default: return;
+	}
+}
+
 //
 // D_ProcessEvents
 // Send all the events of the given timestamp down the responder chain
@@ -188,6 +221,9 @@ void D_ProcessEvents(void)
 	{
 		ev = &events[eventtail];
 
+		// Set global shift/ctrl/alt down variables
+		D_ModifierKeyResponder(ev); // never eats events
+
 		// Screenshots over everything so that they can be taken anywhere.
 		if (M_ScreenshotResponder(ev))
 			continue; // ate the event
@@ -1060,10 +1096,11 @@ void D_SRB2Main(void)
 	if (M_CheckParm("-warp") && M_IsNextParm())
 	{
 		const char *word = M_GetNextParm();
-		if (fastncmp(word, "MAP", 3))
+		char ch; // use this with sscanf to catch non-digits with
+		if (fastncmp(word, "MAP", 3)) // MAPxx name
 			pstartmap = M_MapNumber(word[3], word[4]);
-		else
-			pstartmap = atoi(word);
+		else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
+			I_Error("Cannot warp to map %s (invalid map name)\n", word);
 		// Don't check if lump exists just yet because the wads haven't been loaded!
 		// Just do a basic range check here.
 		if (pstartmap < 1 || pstartmap > NUMMAPS)
diff --git a/src/d_main.h b/src/d_main.h
index 88387a579955a4f0456a1ac789c119d35ec7bfea..6dc273b1558d8ac6329a15100946dc889095eebf 100644
--- a/src/d_main.h
+++ b/src/d_main.h
@@ -41,7 +41,7 @@ void D_SRB2Main(void);
 // Called by IO functions when input is detected.
 void D_PostEvent(const event_t *ev);
 #ifndef DOXYGEN
-void D_PostEvent_end(void);    // delimiter for locking memory
+FUNCMATH void D_PostEvent_end(void);    // delimiter for locking memory
 #endif
 
 void D_ProcessEvents(void);
diff --git a/src/d_net.c b/src/d_net.c
index 03e126b50156db43db88cb42fd5e7ce82f1875bd..50b6c8cf692f35561e8ad4a5695775895c603345 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -31,18 +31,18 @@
 //
 // NETWORKING
 //
-// gametic is the tic about to be (or currently being) run
-// server:
+// gametic is the tic about to (or currently being) run
+// Server:
 //   maketic is the tic that hasn't had control made for it yet
-//   nettics: is the tic for each node
-//   firsttictosend: is the lowest value of nettics
-// client:
-//   neededtic: is the tic needed by the client to run the game
-//   firsttictosend: is used to optimize a condition
-// normally maketic >= gametic > 0
+//   nettics is the tic for each node
+//   firstticstosend is the lowest value of nettics
+// Client:
+//   neededtic is the tic needed by the client to run the game
+//   firstticstosend is used to optimize a condition
+// Normally maketic >= gametic > 0
 
 #define FORCECLOSE 0x8000
-tic_t connectiontimeout = (15*TICRATE);
+tic_t connectiontimeout = (10*TICRATE);
 
 /// \brief network packet
 doomcom_t *doomcom = NULL;
@@ -62,7 +62,7 @@ INT32 net_bandwidth;
 /// \brief max length per packet
 INT16 hardware_MAXPACKETLENGTH;
 
-void (*I_NetGet)(void) = NULL;
+boolean (*I_NetGet)(void) = NULL;
 void (*I_NetSend)(void) = NULL;
 boolean (*I_NetCanSend)(void) = NULL;
 boolean (*I_NetCanGet)(void) = NULL;
@@ -129,9 +129,9 @@ boolean Net_GetNetStat(void)
 // -----------------------------------------------------------------
 // Some structs and functions for acknowledgement of packets
 // -----------------------------------------------------------------
-#define MAXACKPACKETS 96 // minimum number of nodes
+#define MAXACKPACKETS 96 // Minimum number of nodes (wat)
 #define MAXACKTOSEND 96
-#define URGENTFREESLOTENUM 10
+#define URGENTFREESLOTNUM 10
 #define ACKTOSENDTIMEOUT (TICRATE/11)
 
 #ifndef NONET
@@ -139,10 +139,10 @@ typedef struct
 {
 	UINT8 acknum;
 	UINT8 nextacknum;
-	UINT8 destinationnode;
-	tic_t senttime;
-	UINT16 length;
-	UINT16 resentnum;
+	UINT8 destinationnode; // The node to send the ack to
+	tic_t senttime; // The time when the ack was sent
+	UINT16 length; // The packet size
+	UINT16 resentnum; // The number of times the ack has been resent
 	union {
 		SINT8 raw[MAXPACKETLENGTH];
 		doomdata_t data;
@@ -152,11 +152,12 @@ typedef struct
 
 typedef enum
 {
-	CLOSE = 1, // flag is set when connection is closing
+	NF_CLOSE = 1, // Flag is set when connection is closing
+	NF_TIMEOUT = 2, // Flag is set when the node got a timeout
 } node_flags_t;
 
 #ifndef NONET
-// table of packet that was not acknowleged can be resend (the sender window)
+// Table of packets that were not acknowleged can be resent (the sender window)
 static ackpak_t ackpak[MAXACKPACKETS];
 #endif
 
@@ -212,11 +213,16 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
 	return d;
 }
 
-// return a free acknum and copy netbuffer in the ackpak table
+/** Sets freeack to a free acknum and copies the netbuffer in the ackpak table
+  *
+  * \param freeack  The address to store the free acknum at
+  * \param lowtimer ???
+  * \return True if a free acknum was found
+  */
 static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
 {
 	node_t *node = &nodes[doomcom->remotenode];
-	INT32 i, numfreeslote = 0;
+	INT32 i, numfreeslot = 0;
 
 	if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
 	{
@@ -227,10 +233,13 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
 	for (i = 0; i < MAXACKPACKETS; i++)
 		if (!ackpak[i].acknum)
 		{
-			// for low priority packet, make sure let freeslotes so urgents packets can be sent
-			numfreeslote++;
-			if (netbuffer->packettype >= PT_CANFAIL && numfreeslote < URGENTFREESLOTENUM)
-				continue;
+			// For low priority packets, make sure to let freeslots so urgent packets can be sent
+			if (netbuffer->packettype >= PT_CANFAIL)
+			{
+				numfreeslot++;
+				if (numfreeslot <= URGENTFREESLOTNUM)
+					continue;
+			}
 
 			ackpak[i].acknum = node->nextacknum;
 			ackpak[i].nextacknum = node->nextacknum;
@@ -241,7 +250,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
 			ackpak[i].length = doomcom->datalength;
 			if (lowtimer)
 			{
-				// lowtime mean can't be sent now so try it soon as possible
+				// Lowtime means can't be sent now so try it as soon as possible
 				ackpak[i].senttime = 0;
 				ackpak[i].resentnum = 1;
 			}
@@ -254,7 +263,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
 
 			*freeack = ackpak[i].acknum;
 
-			sendackpacket++; // for stat
+			sendackpacket++; // For stat
 
 			return true;
 		}
@@ -266,14 +275,46 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
 	return false;
 }
 
-// Get a ack to send in the queu of this node
+/** Counts how many acks are free
+  *
+  * \param urgent True if the type of the packet meant to
+  *               use an ack is lower than PT_CANFAIL
+  *               If for some reason you don't want use it
+  *               for any packet type in particular,
+  *               just set to false
+  * \return The number of free acks
+  *
+  */
+INT32 Net_GetFreeAcks(boolean urgent)
+{
+	INT32 i, numfreeslot = 0;
+	INT32 n = 0; // Number of free acks found
+
+	for (i = 0; i < MAXACKPACKETS; i++)
+		if (!ackpak[i].acknum)
+		{
+			// For low priority packets, make sure to let freeslots so urgent packets can be sent
+			if (!urgent)
+			{
+				numfreeslot++;
+				if (numfreeslot <= URGENTFREESLOTNUM)
+					continue;
+			}
+
+			n++;
+		}
+
+	return n;
+}
+
+// Get a ack to send in the queue of this node
 static UINT8 GetAcktosend(INT32 node)
 {
 	nodes[node].lasttimeacktosend_sent = I_GetTime();
 	return nodes[node].firstacktosend;
 }
 
-static void Removeack(INT32 i)
+static void RemoveAck(INT32 i)
 {
 	INT32 node = ackpak[i].destinationnode;
 #ifndef NEWPING
@@ -290,31 +331,31 @@ static void Removeack(INT32 i)
 	DEBFILE(va("Remove ack %d\n",ackpak[i].acknum));
 #endif
 	ackpak[i].acknum = 0;
-	if (nodes[node].flags & CLOSE)
+	if (nodes[node].flags & NF_CLOSE)
 		Net_CloseConnection(node);
 }
 
-// we have got a packet proceed the ack request and ack return
+// We have got a packet, proceed the ack request and ack return
 static boolean Processackpak(void)
 {
 	INT32 i;
 	boolean goodpacket = true;
 	node_t *node = &nodes[doomcom->remotenode];
 
-	// received an ack return, so remove the ack in the list
+	// Received an ack return, so remove the ack in the list
 	if (netbuffer->ackreturn && cmpack(node->remotefirstack, netbuffer->ackreturn) < 0)
 	{
 		node->remotefirstack = netbuffer->ackreturn;
-		// search the ackbuffer and free it
+		// Search the ackbuffer and free it
 		for (i = 0; i < MAXACKPACKETS; i++)
 			if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
 				&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
 			{
-				Removeack(i);
+				RemoveAck(i);
 			}
 	}
 
-	// received a packet with ack, queue it to send the ack back
+	// Received a packet with ack, queue it to send the ack back
 	if (netbuffer->ack)
 	{
 		UINT8 ack = netbuffer->ack;
@@ -323,23 +364,23 @@ static boolean Processackpak(void)
 		{
 			DEBFILE(va("Discard(1) ack %d (duplicated)\n", ack));
 			duppacket++;
-			goodpacket = false; // discard packet (duplicate)
+			goodpacket = false; // Discard packet (duplicate)
 		}
 		else
 		{
-			// check if it is not already in the queue
+			// Check if it is not already in the queue
 			for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
 				if (node->acktosend[i] == ack)
 				{
 					DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
 					duppacket++;
-					goodpacket = false; // discard packet (duplicate)
+					goodpacket = false; // Discard packet (duplicate)
 					break;
 				}
 			if (goodpacket)
 			{
-				// is a good packet so increment the acknowledge number,
-				// then search for a "hole" in the queue
+				// Is a good packet so increment the acknowledge number,
+				// Then search for a "hole" in the queue
 				UINT8 nextfirstack = (UINT8)(node->firstacktosend + 1);
 				if (!nextfirstack)
 					nextfirstack = 1;
@@ -383,10 +424,10 @@ static boolean Processackpak(void)
 						}
 					}
 				}
-				else // out of order packet
+				else // Out of order packet
 				{
-					// don't increment firsacktosend, put it in asktosend queue
-					// will be incremented when the nextfirstack comes (code above)
+					// Don't increment firsacktosend, put it in asktosend queue
+					// Will be incremented when the nextfirstack comes (code above)
 					UINT8 newhead = (UINT8)((node->acktosend_head+1) % MAXACKTOSEND);
 					DEBFILE(va("out of order packet (%d expected)\n", nextfirstack));
 					if (newhead != node->acktosend_tail)
@@ -394,8 +435,8 @@ static boolean Processackpak(void)
 						node->acktosend[node->acktosend_head] = ack;
 						node->acktosend_head = newhead;
 					}
-					else // buffer full discard packet, sender will resend it
-					{ // we can admit the packet but we will not detect the duplication after :(
+					else // Buffer full discard packet, sender will resend it
+					{ // We can admit the packet but we will not detect the duplication after :(
 						DEBFILE("no more freeackret\n");
 						goodpacket = false;
 					}
@@ -430,25 +471,29 @@ static void GotAcks(void)
 				if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
 				{
 					if (ackpak[i].acknum == netbuffer->u.textcmd[j])
-						Removeack(i);
-					else
-						// nextacknum is first equal to acknum, then when receiving bigger ack
-						// there is big chance the packet is lost
-						// when resent, nextacknum = nodes[node].nextacknum
-						//    will redo the same but with different value
-					if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
-						&& ackpak[i].senttime > 0)
-					{
-						ackpak[i].senttime--; // hurry up
-					}
+						RemoveAck(i);
+					// nextacknum is first equal to acknum, then when receiving bigger ack
+					// there is big chance the packet is lost
+					// When resent, nextacknum = nodes[node].nextacknum
+					// will redo the same but with different value
+					else if (cmpack(ackpak[i].nextacknum, netbuffer->u.textcmd[j]) <= 0
+							&& ackpak[i].senttime > 0)
+						{
+							ackpak[i].senttime--; // hurry up
+						}
 				}
 }
 #endif
 
-static inline void Net_ConnectionTimeout(INT32 node)
+void Net_ConnectionTimeout(INT32 node)
 {
-	// send a very special packet to self (hack the reboundstore queue)
-	// main code will handle it
+	// Don't timeout several times
+	if (nodes[node].flags & NF_TIMEOUT)
+		return;
+	nodes[node].flags |= NF_TIMEOUT;
+
+	// Send a very special packet to self (hack the reboundstore queue)
+	// Main code will handle it
 	reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
 	reboundstore[rebound_head].ack = 0;
 	reboundstore[rebound_head].ackreturn = 0;
@@ -456,12 +501,12 @@ static inline void Net_ConnectionTimeout(INT32 node)
 	reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
 	rebound_head = (rebound_head+1) % MAXREBOUND;
 
-	// do not redo it quickly (if we do not close connection it is
+	// Do not redo it quickly (if we do not close connection it is
 	// for a good reason!)
 	nodes[node].lasttimepacketreceived = I_GetTime();
 }
 
-// resend the data if needed
+// Resend the data if needed
 void Net_AckTicker(void)
 {
 #ifndef NONET
@@ -477,7 +522,7 @@ void Net_AckTicker(void)
 		if (ackpak[i].acknum && ackpak[i].senttime + node->timeout < I_GetTime())
 #endif
 		{
-			if (ackpak[i].resentnum > 10 && (node->flags & CLOSE))
+			if (ackpak[i].resentnum > 10 && (node->flags & NF_CLOSE))
 			{
 				DEBFILE(va("ack %d sent 10 times so connection is supposed lost: node %d\n",
 					i, nodei));
@@ -497,7 +542,7 @@ void Net_AckTicker(void)
 			ackpak[i].senttime = I_GetTime();
 			ackpak[i].resentnum++;
 			ackpak[i].nextacknum = node->nextacknum;
-			retransmit++; // for stat
+			retransmit++; // For stat
 			HSendPacket((INT32)(node - nodes), false, ackpak[i].acknum,
 				(size_t)(ackpak[i].length - BASEPACKETSIZE));
 		}
@@ -505,15 +550,15 @@ void Net_AckTicker(void)
 
 	for (i = 1; i < MAXNETNODES; i++)
 	{
-		// this is something like node open flag
+		// This is something like node open flag
 		if (nodes[i].firstacktosend)
 		{
-			// we haven't sent a packet for a long time
-			// acknowledge packet if needed
+			// We haven't sent a packet for a long time
+			// Acknowledge packet if needed
 			if (nodes[i].lasttimeacktosend_sent + ACKTOSENDTIMEOUT < I_GetTime())
 				Net_SendAcks(i);
 
-			if (!(nodes[i].flags & CLOSE)
+			if (!(nodes[i].flags & NF_CLOSE)
 				&& nodes[i].lasttimepacketreceived + connectiontimeout < I_GetTime())
 			{
 				Net_ConnectionTimeout(i);
@@ -523,9 +568,9 @@ void Net_AckTicker(void)
 #endif
 }
 
-// remove last packet received ack before resending the ackret
+// Remove last packet received ack before resending the ackreturn
 // (the higher layer doesn't have room, or something else ....)
-void Net_UnAcknowledgPacket(INT32 node)
+void Net_UnAcknowledgePacket(INT32 node)
 {
 #ifdef NONET
 	(void)node;
@@ -564,20 +609,29 @@ void Net_UnAcknowledgPacket(INT32 node)
 #endif
 }
 
-boolean Net_AllAckReceived(void)
-{
 #ifndef NONET
+/** Checks if all acks have been received
+  *
+  * \return True if all acks have been received
+  *
+  */
+static boolean Net_AllAcksReceived(void)
+{
 	INT32 i;
 
 	for (i = 0; i < MAXACKPACKETS; i++)
 		if (ackpak[i].acknum)
 			return false;
-#endif
 
 	return true;
 }
+#endif
 
-// wait for all ackreturns with timeout in seconds
+/** Waits for all ackreturns
+  *
+  * \param timeout Timeout in seconds
+  *
+  */
 void Net_WaitAllAckReceived(UINT32 timeout)
 {
 #ifdef NONET
@@ -587,7 +641,7 @@ void Net_WaitAllAckReceived(UINT32 timeout)
 	timeout = tictac + timeout*NEWTICRATE;
 
 	HGetPacket();
-	while (timeout > I_GetTime() && !Net_AllAckReceived())
+	while (timeout > I_GetTime() && !Net_AllAcksReceived())
 	{
 		while (tictac == I_GetTime())
 			I_Sleep();
@@ -598,18 +652,18 @@ void Net_WaitAllAckReceived(UINT32 timeout)
 #endif
 }
 
-static void InitNode(INT32 node)
+static void InitNode(node_t *node)
 {
-	nodes[node].acktosend_head = nodes[node].acktosend_tail = 0;
+	node->acktosend_head = node->acktosend_tail = 0;
 #ifndef NEWPING
-	nodes[node].ping = PINGDEFAULT;
-	nodes[node].varping = VARPINGDEFAULT;
-	nodes[node].timeout = TIMEOUT(nodes[node].ping,nodes[node].varping);
+	node->ping = PINGDEFAULT;
+	node->varping = VARPINGDEFAULT;
+	node->timeout = TIMEOUT(node->ping, node->varping);
 #endif
-	nodes[node].firstacktosend = 0;
-	nodes[node].nextacknum = 1;
-	nodes[node].remotefirstack = 0;
-	nodes[node].flags = 0;
+	node->firstacktosend = 0;
+	node->nextacknum = 1;
+	node->remotefirstack = 0;
+	node->flags = 0;
 }
 
 static void InitAck(void)
@@ -622,9 +676,14 @@ static void InitAck(void)
 #endif
 
 	for (i = 0; i < MAXNETNODES; i++)
-		InitNode(i);
+		InitNode(&nodes[i]);
 }
 
+/** Removes all acks of a given packet type
+  *
+  * \param packettype The packet type to forget
+  *
+  */
 void Net_AbortPacketType(UINT8 packettype)
 {
 #ifdef NONET
@@ -652,12 +711,25 @@ void Net_CloseConnection(INT32 node)
 #else
 	INT32 i;
 	boolean forceclose = (node & FORCECLOSE) != 0;
+
+	if (node == -1)
+	{
+		DEBFILE(M_GetText("Net_CloseConnection: node -1 detected!\n"));
+		return; // nope, just ignore it
+	}
+
 	node &= ~FORCECLOSE;
 
 	if (!node)
 		return;
 
-	nodes[node].flags |= CLOSE;
+	if (node < 0 || node >= MAXNETNODES) // prevent invalid nodes from crashing the game
+	{
+		DEBFILE(va(M_GetText("Net_CloseConnection: invalid node %d detected!\n"), node));
+		return;
+	}
+
+	nodes[node].flags |= NF_CLOSE;
 
 	// try to Send ack back (two army problem)
 	if (GetAcktosend(node))
@@ -676,8 +748,8 @@ void Net_CloseConnection(INT32 node)
 				ackpak[i].acknum = 0;
 		}
 
-	InitNode(node);
-	AbortSendFiles(node);
+	InitNode(&nodes[node]);
+	SV_AbortSendFiles(node);
 	I_NetFreeNodenum(node);
 #endif
 }
@@ -729,9 +801,15 @@ static void fprintfstring(char *s, size_t len)
 		}
 	if (mode)
 		fprintf(debugfile, "]");
+}
+
+static void fprintfstringnewline(char *s, size_t len)
+{
+	fprintfstring(s, len);
 	fprintf(debugfile, "\n");
 }
 
+/// \warning Keep this up-to-date if you add/remove/rename packet types
 static const char *packettypename[NUMPACKETTYPE] =
 {
 	"NOTHING",
@@ -749,15 +827,22 @@ static const char *packettypename[NUMPACKETTYPE] =
 
 	"ASKINFO",
 	"SERVERINFO",
+	"PLAYERINFO",
 	"REQUESTFILE",
 	"ASKINFOVIAMS",
 
-	"PLAYERCONFIGS",
+	"RESYNCHEND",
+	"RESYNCHGET",
+
 	"FILEFRAGMENT",
 	"TEXTCMD",
 	"TEXTCMD2",
 	"CLIENTJOIN",
 	"NODETIMEOUT",
+	"RESYNCHING",
+#ifdef NEWPING
+	"PING"
+#endif
 };
 
 static void DebugPrintpacket(const char *header)
@@ -770,20 +855,31 @@ static void DebugPrintpacket(const char *header)
 	{
 		case PT_ASKINFO:
 		case PT_ASKINFOVIAMS:
-			fprintf(debugfile, "    time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time)				);
+			fprintf(debugfile, "    time %u\n", (tic_t)LONG(netbuffer->u.askinfo.time));
 			break;
 		case PT_CLIENTJOIN:
 			fprintf(debugfile, "    number %d mode %d\n", netbuffer->u.clientcfg.localplayers,
 				netbuffer->u.clientcfg.mode);
 			break;
 		case PT_SERVERTICS:
+		{
+			servertics_pak *serverpak = &netbuffer->u.serverpak;
+			UINT8 *cmd = (UINT8 *)(&serverpak->cmds[serverpak->numslots * serverpak->numtics]);
+			size_t ntxtcmd = &((UINT8 *)netbuffer)[doomcom->datalength] - cmd;
+
 			fprintf(debugfile, "    firsttic %u ply %d tics %d ntxtcmd %s\n    ",
-				(UINT32)ExpandTics(netbuffer->u.serverpak.starttic), netbuffer->u.serverpak.numslots,
-				netbuffer->u.serverpak.numtics,
-				sizeu1((size_t)(&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics])));
-			fprintfstring((char *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics],(size_t)(
-				&((UINT8 *)netbuffer)[doomcom->datalength] - (UINT8 *)&netbuffer->u.serverpak.cmds[netbuffer->u.serverpak.numslots*netbuffer->u.serverpak.numtics]));
+				(UINT32)ExpandTics(serverpak->starttic), serverpak->numslots, serverpak->numtics, sizeu1(ntxtcmd));
+			/// \todo Display more readable information about net commands
+			fprintfstringnewline((char *)cmd, ntxtcmd);
+			/*fprintfstring((char *)cmd, 3);
+			if (ntxtcmd > 4)
+			{
+				fprintf(debugfile, "[%s]", netxcmdnames[*((cmd) + 3) - 1]);
+				fprintfstring(((char *)cmd) + 4, ntxtcmd - 4);
+			}
+			fprintf(debugfile, "\n");*/
 			break;
+		}
 		case PT_CLIENTCMD:
 		case PT_CLIENT2CMD:
 		case PT_CLIENTMIS:
@@ -797,7 +893,8 @@ static void DebugPrintpacket(const char *header)
 		case PT_TEXTCMD:
 		case PT_TEXTCMD2:
 			fprintf(debugfile, "    length %d\n    ", netbuffer->u.textcmd[0]);
-			fprintfstring((char *)netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
+			fprintf(debugfile, "[%s]", netxcmdnames[netbuffer->u.textcmd[1] - 1]);
+			fprintfstringnewline((char *)netbuffer->u.textcmd + 2, netbuffer->u.textcmd[0] - 1);
 			break;
 		case PT_SERVERCFG:
 			fprintf(debugfile, "    playerslots %d clientnode %d serverplayer %d "
@@ -813,7 +910,7 @@ static void DebugPrintpacket(const char *header)
 				netbuffer->u.serverinfo.maxplayer, netbuffer->u.serverinfo.mapname,
 				netbuffer->u.serverinfo.fileneedednum,
 				(UINT32)LONG(netbuffer->u.serverinfo.time));
-			fprintfstring((char *)netbuffer->u.serverinfo.fileneeded,
+			fprintfstringnewline((char *)netbuffer->u.serverinfo.fileneeded,
 				(UINT8)((UINT8 *)netbuffer + doomcom->datalength
 				- (UINT8 *)netbuffer->u.serverinfo.fileneeded));
 			break;
@@ -827,20 +924,102 @@ static void DebugPrintpacket(const char *header)
 			break;
 		case PT_REQUESTFILE:
 		default: // write as a raw packet
-			fprintfstring((char *)netbuffer->u.textcmd,
+			fprintfstringnewline((char *)netbuffer->u.textcmd,
 				(UINT8)((UINT8 *)netbuffer + doomcom->datalength - (UINT8 *)netbuffer->u.textcmd));
 			break;
 	}
 }
 #endif
 
+#ifdef PACKETDROP
+static INT32 packetdropquantity[NUMPACKETTYPE] = {0};
+static INT32 packetdroprate = 0;
+
+void Command_Drop(void)
+{
+	INT32 packetquantity;
+	const char *packetname;
+	size_t i;
+
+	if (COM_Argc() < 2)
+	{
+		CONS_Printf("drop <packettype> [quantity]: drop packets\n"
+					"drop reset: cancel all packet drops\n");
+		return;
+	}
+
+	if (!(stricmp(COM_Argv(1), "reset") && stricmp(COM_Argv(1), "cancel") && stricmp(COM_Argv(1), "stop")))
+	{
+		memset(packetdropquantity, 0, sizeof(packetdropquantity));
+		return;
+	}
+
+	if (COM_Argc() >= 3)
+	{
+		packetquantity = atoi(COM_Argv(2));
+		if (packetquantity <= 0 && COM_Argv(2)[0] != '0')
+		{
+			CONS_Printf("Invalid quantity\n");
+			return;
+		}
+	}
+	else
+		packetquantity = -1;
+
+	packetname = COM_Argv(1);
+
+	if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
+		for (i = 0; i < NUMPACKETTYPE; i++)
+			packetdropquantity[i] = packetquantity;
+	else
+	{
+		for (i = 0; i < NUMPACKETTYPE; i++)
+			if (!stricmp(packetname, packettypename[i]))
+			{
+				packetdropquantity[i] = packetquantity;
+				return;
+			}
+
+		CONS_Printf("Unknown packet name\n");
+	}
+}
+
+void Command_Droprate(void)
+{
+	INT32 droprate;
+
+	if (COM_Argc() < 2)
+	{
+		CONS_Printf("Packet drop rate: %d%%\n", packetdroprate);
+		return;
+	}
+
+	droprate = atoi(COM_Argv(1));
+	if ((droprate <= 0 && COM_Argv(1)[0] != '0') || droprate > 100)
+	{
+		CONS_Printf("Packet drop rate must be between 0 and 100!\n");
+		return;
+	}
+
+	packetdroprate = droprate;
+}
+
+#ifndef NONET
+static boolean ShouldDropPacket(void)
+{
+	return (packetdropquantity[netbuffer->packettype])
+		|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
+}
+#endif
+#endif
+
 //
 // HSendPacket
 //
 boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlength)
 {
 	doomcom->datalength = (INT16)(packetlength + BASEPACKETSIZE);
-	if (node == 0) // packet is to go back to us
+	if (node == 0) // Packet is to go back to us
 	{
 		if ((rebound_head+1) % MAXREBOUND == rebound_tail)
 		{
@@ -871,7 +1050,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
 	(void)reliable;
 	(void)acknum;
 #else
-	// do this before GetFreeAcknum because this function backup
+	// do this before GetFreeAcknum because this function backups
 	// the current packet
 	doomcom->remotenode = (INT16)node;
 	if (doomcom->datalength <= 0)
@@ -884,7 +1063,7 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
 		return false;
 	}
 
-	if (node < MAXNETNODES) // can be a broadcast
+	if (node < MAXNETNODES) // Can be a broadcast
 		netbuffer->ackreturn = GetAcktosend(node);
 	else
 		netbuffer->ackreturn = 0;
@@ -905,20 +1084,30 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
 		netbuffer->ack = acknum;
 
 	netbuffer->checksum = NetbufferChecksum();
-	sendbytes += packetheaderlength + doomcom->datalength; // for stat
+	sendbytes += packetheaderlength + doomcom->datalength; // For stat
 
-	// simulate internet :)
-	if (true || rand()<(INT32)RAND_MAX/5)
+#ifdef PACKETDROP
+	// Simulate internet :)
+	//if (rand() >= (INT32)(RAND_MAX * (PACKETLOSSRATE / 100.f)))
+	if (!ShouldDropPacket())
 	{
+#endif
 #ifdef DEBUGFILE
 		if (debugfile)
-			DebugPrintpacket("SEND");
+			DebugPrintpacket("SENT");
 #endif
 		I_NetSend();
+#ifdef PACKETDROP
 	}
+	else
+	{
+		if (packetdropquantity[netbuffer->packettype] > 0)
+			packetdropquantity[netbuffer->packettype]--;
 #ifdef DEBUGFILE
-	else if (debugfile)
-		DebugPrintpacket("NOTSEND");
+		if (debugfile)
+			DebugPrintpacket("NOT SENT");
+#endif
+	}
 #endif
 
 #endif // ndef NONET
@@ -933,7 +1122,9 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
 //
 boolean HGetPacket(void)
 {
-	// get a packet from self
+	//boolean nodejustjoined;
+
+	// Get a packet from self
 	if (rebound_tail != rebound_head)
 	{
 		M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
@@ -958,16 +1149,17 @@ boolean HGetPacket(void)
 
 	while(true)
 	{
+		//nodejustjoined = I_NetGet();
 		I_NetGet();
 
-		if (doomcom->remotenode == -1)
+		if (doomcom->remotenode == -1) // No packet received
 			return false;
 
-		getbytes += packetheaderlength + doomcom->datalength; // for stat
+		getbytes += packetheaderlength + doomcom->datalength; // For stat
 
 		if (doomcom->remotenode >= MAXNETNODES)
 		{
-			DEBFILE(va("receive packet from node %d !\n", doomcom->remotenode));
+			DEBFILE(va("Received packet from node %d!\n", doomcom->remotenode));
 			continue;
 		}
 
@@ -976,6 +1168,7 @@ boolean HGetPacket(void)
 		if (netbuffer->checksum != NetbufferChecksum())
 		{
 			DEBFILE("Bad packet checksum\n");
+			//Net_CloseConnection(nodejustjoined ? (doomcom->remotenode | FORCECLOSE) : doomcom->remotenode);
 			Net_CloseConnection(doomcom->remotenode);
 			continue;
 		}
@@ -985,11 +1178,26 @@ boolean HGetPacket(void)
 			DebugPrintpacket("GET");
 #endif
 
-		// proceed the ack and ackreturn field
+		/*// If a new node sends an unexpected packet, just ignore it
+		if (nodejustjoined && server
+			&& !(netbuffer->packettype == PT_ASKINFO
+				|| netbuffer->packettype == PT_SERVERINFO
+				|| netbuffer->packettype == PT_PLAYERINFO
+				|| netbuffer->packettype == PT_REQUESTFILE
+				|| netbuffer->packettype == PT_ASKINFOVIAMS
+				|| netbuffer->packettype == PT_CLIENTJOIN))
+		{
+			DEBFILE(va("New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]));
+			//CONS_Alert(CONS_NOTICE, "New node sent an unexpected %s packet\n", packettypename[netbuffer->packettype]);
+			Net_CloseConnection(doomcom->remotenode | FORCECLOSE);
+			continue;
+		}*/
+
+		// Proceed the ack and ackreturn field
 		if (!Processackpak())
 			continue; // discarded (duplicated)
 
-		// a packet with just ackreturn
+		// A packet with just ackreturn
 		if (netbuffer->packettype == PT_NOTHING)
 		{
 			GotAcks();
@@ -1002,9 +1210,10 @@ boolean HGetPacket(void)
 	return true;
 }
 
-static void Internal_Get(void)
+static boolean Internal_Get(void)
 {
 	doomcom->remotenode = -1;
+	return false;
 }
 
 FUNCNORETURN static ATTRNORETURN void Internal_Send(void)
@@ -1089,7 +1298,7 @@ boolean D_CheckNetGame(void)
 
 	if (netgame)
 		ret = true;
-	if (!server && netgame)
+	if (client && netgame)
 		netgame = false;
 	server = true; // WTF? server always true???
 		// no! The deault mode is server. Client is set elsewhere
@@ -1230,4 +1439,6 @@ void D_CloseConnection(void)
 		netgame = false;
 		addedtogame = false;
 	}
+
+	D_ResetTiccmds();
 }
diff --git a/src/d_net.h b/src/d_net.h
index 285b44235b1f2758d671ead084de3f24fd26cc6e..84814ce39327573a176716a02eec9d77bab52643 100644
--- a/src/d_net.h
+++ b/src/d_net.h
@@ -18,10 +18,10 @@
 #ifndef __D_NET__
 #define __D_NET__
 
-// Max computers in a game.
+// Max computers in a game
 #define MAXNETNODES 32
 #define BROADCASTADDR MAXNETNODES
-#define MAXSPLITSCREENPLAYERS 2 // max number of players on a single computer
+#define MAXSPLITSCREENPLAYERS 2 // Max number of players on a single computer
 
 #define STATLENGTH (TICRATE*2)
 
@@ -32,17 +32,17 @@ extern float lostpercent, duppercent, gamelostpercent;
 extern INT32 packetheaderlength;
 boolean Net_GetNetStat(void);
 extern INT32 getbytes;
-extern INT64 sendbytes; // realtime updated
+extern INT64 sendbytes; // Realtime updated
 
 extern SINT8 nodetoplayer[MAXNETNODES];
-extern SINT8 nodetoplayer2[MAXNETNODES]; // say the numplayer for this node if any (splitscreen)
-extern UINT8 playerpernode[MAXNETNODES]; // used specialy for scplitscreen
-extern boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
+extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
+extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
+extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
 
+INT32 Net_GetFreeAcks(boolean urgent);
 void Net_AckTicker(void);
-boolean Net_AllAckReceived(void);
 
-// if reliable return true if packet sent, 0 else
+// If reliable return true if packet sent, 0 else
 boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
 	size_t packetlength);
 boolean HGetPacket(void);
@@ -52,9 +52,11 @@ void D_SaveBan(void);
 #endif
 boolean D_CheckNetGame(void);
 void D_CloseConnection(void);
-void Net_UnAcknowledgPacket(INT32 node);
+void Net_UnAcknowledgePacket(INT32 node);
 void Net_CloseConnection(INT32 node);
+void Net_ConnectionTimeout(INT32 node);
 void Net_AbortPacketType(UINT8 packettype);
 void Net_SendAcks(INT32 node);
 void Net_WaitAllAckReceived(UINT32 timeout);
+
 #endif
diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 4f73a25648db4c56d99f8fbb97e7c3e2773a7dc6..b5563f4e89f78be595cf7398ee30c242c8474584 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -82,6 +82,7 @@ static void AutoBalance_OnChange(void);
 static void TeamScramble_OnChange(void);
 
 static void NetTimeout_OnChange(void);
+static void JoinTimeout_OnChange(void);
 
 static void Ringslinger_OnChange(void);
 static void Gravity_OnChange(void);
@@ -340,7 +341,9 @@ consvar_t cv_killingdead = {"killingdead", "Off", CV_NETVAR, CV_OnOff, NULL, 0,
 
 consvar_t cv_netstat = {"netstat", "Off", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; // show bandwidth statistics
 static CV_PossibleValue_t nettimeout_cons_t[] = {{TICRATE/7, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
-consvar_t cv_nettimeout = {"nettimeout", "525", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
+consvar_t cv_nettimeout = {"nettimeout", "350", CV_CALL|CV_SAVE, nettimeout_cons_t, NetTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static CV_PossibleValue_t jointimeout_cons_t[] = {{5*TICRATE, "MIN"}, {60*TICRATE, "MAX"}, {0, NULL}};
+consvar_t cv_jointimeout = {"jointimeout", "350", CV_CALL|CV_SAVE, jointimeout_cons_t, JoinTimeout_OnChange, 0, NULL, NULL, 0, 0, NULL};
 #ifdef NEWPING
 consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
@@ -365,6 +368,35 @@ boolean splitscreen = false;
 boolean circuitmap = false;
 INT32 adminplayer = -1;
 
+/// \warning Keep this up-to-date if you add/remove/rename net text commands
+const char *netxcmdnames[MAXNETXCMD - 1] =
+{
+	"NAMEANDCOLOR",
+	"WEAPONPREF",
+	"KICK",
+	"NETVAR",
+	"SAY",
+	"MAP",
+	"EXITLEVEL",
+	"ADDFILE",
+	"PAUSE",
+	"ADDPLAYER",
+	"TEAMCHANGE",
+	"CLEARSCORES",
+	"LOGIN",
+	"VERIFIED",
+	"RANDOMSEED",
+	"RUNSOC",
+	"REQADDFILE",
+	"DELFILE",
+	"SETMOTD",
+	"SUICIDE",
+#ifdef HAVE_BLUA
+	"LUACMD",
+	"LUAVAR"
+#endif
+};
+
 // =========================================================================
 //                           SERVER STARTUP
 // =========================================================================
@@ -517,9 +549,12 @@ void D_RegisterServerCommands(void)
 	// d_clisrv
 	CV_RegisterVar(&cv_maxplayers);
 	CV_RegisterVar(&cv_maxsend);
+	CV_RegisterVar(&cv_noticedownload);
+	CV_RegisterVar(&cv_downloadspeed);
 
 	COM_AddCommand("ping", Command_Ping_f);
 	CV_RegisterVar(&cv_nettimeout);
+	CV_RegisterVar(&cv_jointimeout);
 
 	CV_RegisterVar(&cv_skipmapcheck);
 	CV_RegisterVar(&cv_sleep);
@@ -976,7 +1011,7 @@ UINT8 CanChangeSkin(INT32 playernum)
 		return true;
 
 	// Force skin in effect.
-	if (!server && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
+	if (client && (cv_forceskin.value != -1) && !(adminplayer == playernum && serverplayer == -1))
 		return false;
 
 	// Can change skin in intermission and whatnot.
@@ -1534,8 +1569,13 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
 		mapchangepending = 0;
 		// spawn the server if needed
 		// reset players if there is a new one
-		if (!(adminplayer == consoleplayer) && SV_SpawnServer())
-			buf[0] &= ~(1<<1);
+		if (!(adminplayer == consoleplayer))
+		{
+			if (SV_SpawnServer())
+				buf[0] &= ~(1<<1);
+			if (!Playing()) // you failed to start a server somehow, so cancel the map change
+				return;
+		}
 
 		// Kick bot from special stages
 		if (botskin)
@@ -1587,7 +1627,7 @@ static void Command_Map_f(void)
 		return;
 	}
 
-	if (!server && !(adminplayer == consoleplayer))
+	if (client && !(adminplayer == consoleplayer))
 	{
 		CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
 		return;
@@ -1914,7 +1954,7 @@ static void Got_Suicide(UINT8 **cp, INT32 playernum)
 	// You can't suicide someone else.  Nice try, there.
 	if (suicideplayer != playernum || (!G_PlatformGametype()))
 	{
-		CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command recieved from %s\n"), player_names[playernum]);
+		CONS_Alert(CONS_WARNING, M_GetText("Illegal suicide command received from %s\n"), player_names[playernum]);
 		if (server)
 		{
 			XBOXSTATIC UINT8 buf[2];
@@ -2081,7 +2121,7 @@ static void Command_Teamchange_f(void)
 		return;
 	}
 
-	if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
+	if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
 		return;
@@ -2178,7 +2218,7 @@ static void Command_Teamchange2_f(void)
 		return;
 	}
 
-	if (!cv_allowteamchange.value && !NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
+	if (!cv_allowteamchange.value && NetPacket.packet.newteam) // allow swapping to spectator even in locked teams.
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("The server is not allowing team changes at the moment.\n"));
 		return;
@@ -2629,7 +2669,7 @@ static void Command_Changepassword_f(void)
 	// If we have no MD5 support then completely disable XD_LOGIN responses for security.
 	CONS_Alert(CONS_NOTICE, "Remote administration commands are not supported in this build.\n");
 #else
-	if (!server) // cannot change remotely
+	if (client) // cannot change remotely
 	{
 		CONS_Printf(M_GetText("Only the server can use this.\n"));
 		return;
@@ -2688,7 +2728,7 @@ static void Got_Login(UINT8 **cp, INT32 playernum)
 
 	READMEM(*cp, sentmd5, 16);
 
-	if (!server)
+	if (client)
 		return;
 
 	// Do the final pass to compare with the sent md5
@@ -2710,7 +2750,7 @@ static void Command_Verify_f(void)
 	char *temp;
 	INT32 playernum;
 
-	if (!server)
+	if (client)
 	{
 		CONS_Printf(M_GetText("Only the server can use this.\n"));
 		return;
@@ -2794,7 +2834,7 @@ static void Command_MotD_f(void)
 			return;
 		}
 
-	if ((netgame || multiplayer) && !server)
+	if ((netgame || multiplayer) && client)
 		SendNetXCmd(XD_SETMOTD, mymotd, sizeof(motd));
 	else
 	{
@@ -2932,6 +2972,7 @@ static void Command_Addfile(void)
 	XBOXSTATIC char buf[256];
 	char *buf_p = buf;
 	INT32 i;
+	int musiconly; // W_VerifyNMUSlumps isn't boolean
 
 	if (COM_Argc() != 2)
 	{
@@ -2946,7 +2987,9 @@ static void Command_Addfile(void)
 		if (!isprint(fn[i]) || fn[i] == ';')
 			return;
 
-	if (!W_VerifyNMUSlumps(fn))
+	musiconly = W_VerifyNMUSlumps(fn);
+
+	if (!musiconly)
 	{
 		// ... But only so long as they contain nothing more then music and sprites.
 		if (netgame && !(server || adminplayer == consoleplayer))
@@ -2958,7 +3001,7 @@ static void Command_Addfile(void)
 	}
 
 	// Add file on your client directly if it is trivial, or you aren't in a netgame.
-	if (!(netgame || multiplayer) || W_VerifyNMUSlumps(fn))
+	if (!(netgame || multiplayer) || musiconly)
 	{
 		P_AddWadFile(fn, NULL);
 		return;
@@ -2978,9 +3021,7 @@ static void Command_Addfile(void)
 #else
 		FILE *fhandle;
 
-		fhandle = fopen(fn, "rb");
-
-		if (fhandle)
+		if ((fhandle = W_OpenWadFile(&fn, true)) != NULL)
 		{
 			tic_t t = I_GetTime();
 			CONS_Debug(DBG_SETUP, "Making MD5 for %s\n",fn);
@@ -2988,11 +3029,8 @@ static void Command_Addfile(void)
 			CONS_Debug(DBG_SETUP, "MD5 calc for %s took %f second\n", fn, (float)(I_GetTime() - t)/TICRATE);
 			fclose(fhandle);
 		}
-		else
-		{
-			CONS_Printf(M_GetText("File %s not found.\n"), fn);
+		else // file not found
 			return;
-		}
 #endif
 		WRITEMEM(buf_p, md5sum, 16);
 	}
@@ -3045,13 +3083,19 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
 	filestatus_t ncs = FS_NOTFOUND;
 	UINT8 md5sum[16];
 	boolean kick = false;
+	boolean toomany = false;
 	INT32 i;
+	size_t packetsize = 0;
+	serverinfo_pak *dummycheck = NULL;
+
+	// Shut the compiler up.
+	(void)dummycheck;
 
 	READSTRINGN(*cp, filename, 240);
 	READMEM(*cp, md5sum, 16);
 
 	// Only the server processes this message.
-	if (!server)
+	if (client)
 		return;
 
 	// Disallow non-printing characters and semicolons.
@@ -3071,13 +3115,25 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
 		return;
 	}
 
-	ncs = findfile(filename,md5sum,true);
+	// See W_LoadWadFile in w_wad.c
+	for (i = 0; i < numwadfiles; i++)
+		packetsize += nameonlylength(wadfiles[i]->filename) + 22;
+
+	packetsize += nameonlylength(filename) + 22;
 
-	if (ncs != FS_FOUND)
+	if ((numwadfiles >= MAX_WADFILES)
+	|| (packetsize > sizeof(dummycheck->fileneeded)))
+		toomany = true;
+	else
+		ncs = findfile(filename,md5sum,true);
+
+	if (ncs != FS_FOUND || toomany)
 	{
 		char message[256];
 
-		if (ncs == FS_NOTFOUND)
+		if (toomany)
+			sprintf(message, M_GetText("Too many files loaded to add %s\n"), filename);
+		else if (ncs == FS_NOTFOUND)
 			sprintf(message, M_GetText("The server doesn't have %s\n"), filename);
 		else if (ncs == FS_MD5SUMBAD)
 			sprintf(message, M_GetText("Checksum mismatch on %s\n"), filename);
@@ -3147,10 +3203,15 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
 
 	ncs = findfile(filename,md5sum,true);
 
-	if (ncs != FS_FOUND)
+	if (ncs != FS_FOUND || !P_AddWadFile(filename, NULL))
 	{
 		Command_ExitGame_f();
-		if (ncs == FS_NOTFOUND)
+		if (ncs == FS_FOUND)
+		{
+			CONS_Printf(M_GetText("The server tried to add %s,\nbut you have too many files added.\nRestart the game to clear loaded files\nand play on this server."), filename);
+			M_StartMessage(va("The server added a file \n(%s)\nbut you have too many files added.\nRestart the game to clear loaded files.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
+		}
+		else if (ncs == FS_NOTFOUND)
 		{
 			CONS_Printf(M_GetText("The server tried to add %s,\nbut you don't have this file.\nYou need to find it in order\nto play on this server."), filename);
 			M_StartMessage(va("The server added a file \n(%s)\nthat you do not have.\n\nPress ESC\n",filename), NULL, MM_NOTHING);
@@ -3168,7 +3229,6 @@ static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
 		return;
 	}
 
-	P_AddWadFile(filename, NULL);
 	G_SetGameModified(true);
 }
 
@@ -3318,6 +3378,11 @@ static void NetTimeout_OnChange(void)
 	connectiontimeout = (tic_t)cv_nettimeout.value;
 }
 
+static void JoinTimeout_OnChange(void)
+{
+	jointimeout = (tic_t)cv_jointimeout.value;
+}
+
 UINT32 timelimitintics = 0;
 
 /** Deals with a timelimit change by printing the change to the console.
@@ -3960,7 +4025,7 @@ static void Command_Archivetest_f(void)
 	}
 
 	// assign mobjnum
-	i = 0;
+	i = 1;
 	for (th = thinkercap.next; th != &thinkercap; th = th->next)
 		if (th->function.acp1 == (actionf_p1)P_MobjThinker)
 			((mobj_t *)th)->mobjnum = i++;
@@ -4063,7 +4128,7 @@ static void Skin_OnChange(void)
 		return; // do whatever you want
 
 	if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
-		&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
+		&& (gamestate != GS_WAITINGPLAYERS)) // allows command line -warp x +skin y
 	{
 		CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
 		return;
@@ -4106,8 +4171,7 @@ static void Color_OnChange(void)
 	if (!Playing())
 		return; // do whatever you want
 
-	if (!(cv_debug || devparm) && !(multiplayer || netgame) // In single player.
-		&& (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_CONTINUING))
+	if (!(cv_debug || devparm) && !(multiplayer || netgame)) // In single player.
 	{
 		CV_StealthSet(&cv_skin, skins[players[consoleplayer].skin].name);
 		return;
diff --git a/src/d_netcmd.h b/src/d_netcmd.h
index c090699f125703b3fc154bd377b88289108533d2..d8fae72f798ff874e17d630628f3e269a37fe7a3 100644
--- a/src/d_netcmd.h
+++ b/src/d_netcmd.h
@@ -162,6 +162,8 @@ typedef enum
 	MAXNETXCMD
 } netxcmd_t;
 
+extern const char *netxcmdnames[MAXNETXCMD - 1];
+
 #if defined(_MSC_VER)
 #pragma pack(1)
 #endif
diff --git a/src/d_netfil.c b/src/d_netfil.c
index 85196217ff4551fbda4820fc6d4755ad5d65e1b4..172624ad297a753c43abf0e348c3a6df07d8c1f6 100644
--- a/src/d_netfil.c
+++ b/src/d_netfil.c
@@ -62,44 +62,49 @@
 
 #include <errno.h>
 
-static void SendFile(INT32 node, const char *filename, UINT8 fileid);
+// Prototypes
+static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
 
-// sender structure
+// Sender structure
 typedef struct filetx_s
 {
 	INT32 ram;
-	char *filename; // name of the file or ptr of the data in ram
-	UINT32 size;
+	union {
+		char *filename; // Name of the file
+		char *ram; // Pointer to the data in RAM
+	} id;
+	UINT32 size; // Size of the file
 	UINT8 fileid;
-	INT32 node; // destination
-	struct filetx_s *next; // a queue
+	INT32 node; // Destination
+	struct filetx_s *next; // Next file in the list
 } filetx_t;
 
-// current transfers (one for each node)
+// Current transfers (one for each node)
 typedef struct filetran_s
 {
-	filetx_t *txlist;
-	UINT32 position;
-	FILE *currentfile;
+	filetx_t *txlist; // Linked list of all files for the node
+	UINT32 position; // The current position in the file
+	FILE *currentfile; // The file currently being sent/received
 } filetran_t;
 static filetran_t transfer[MAXNETNODES];
 
-// read time of file: stat _stmtime
-// write time of file: utime
+// Read time of file: stat _stmtime
+// Write time of file: utime
 
-// receiver structure
-INT32 fileneedednum;
-fileneeded_t fileneeded[MAX_WADFILES];
+// Receiver structure
+INT32 fileneedednum; // Number of files needed to join the server
+fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
 char downloaddir[256] = "DOWNLOAD";
 
 #ifdef CLIENT_LOADINGSCREEN
 // for cl loading screen
-INT32 lastfilenum = 0;
+INT32 lastfilenum = -1;
 #endif
 
 /** Fills a serverinfo packet with information about wad files loaded.
   *
   * \todo Give this function a better name since it is in global scope.
+  *
   */
 UINT8 *PutFileNeeded(void)
 {
@@ -111,19 +116,19 @@ UINT8 *PutFileNeeded(void)
 
 	for (i = 0; i < numwadfiles; i++)
 	{
-		// if it has only music/sound lumps, mark it as unimportant
+		// If it has only music/sound lumps, mark it as unimportant
 		if (W_VerifyNMUSlumps(wadfiles[i]->filename))
 			filestatus = 0;
 		else
-			filestatus = 1; // important
+			filestatus = 1; // Important
 
 		// Store in the upper four bits
 		if (!cv_downloading.value)
-			filestatus += (2 << 4); // won't send
+			filestatus += (2 << 4); // Won't send
 		else if ((wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024))
-			filestatus += (0 << 4); // won't send
+			filestatus += (0 << 4); // Won't send
 		else
-			filestatus += (1 << 4); // will send if requested
+			filestatus += (1 << 4); // Will send if requested
 
 		bytesused += (nameonlylength(wadfilename) + 22);
 
@@ -144,7 +149,12 @@ UINT8 *PutFileNeeded(void)
 	return p;
 }
 
-// parse the serverinfo packet and fill fileneeded table on client
+/** Parses the serverinfo packet and fills the fileneeded table on client
+  *
+  * \param fileneedednum_parm The number of files needed to join the server
+  * \param fileneededstr The memory block containing the list of needed files
+  *
+  */
 void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
 {
 	INT32 i;
@@ -155,14 +165,14 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
 	p = (UINT8 *)fileneededstr;
 	for (i = 0; i < fileneedednum; i++)
 	{
-		fileneeded[i].status = FS_NOTFOUND;
-		filestatus = READUINT8(p);
+		fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
+		filestatus = READUINT8(p); // The first byte is the file status
 		fileneeded[i].important = (UINT8)(filestatus & 3);
 		fileneeded[i].willsend = (UINT8)(filestatus >> 4);
-		fileneeded[i].totalsize = READUINT32(p);
-		fileneeded[i].phandle = NULL;
-		READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
-		READMEM(p, fileneeded[i].md5sum, 16);
+		fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
+		fileneeded[i].file = NULL; // The file isn't open yet
+		READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
+		READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
 	}
 }
 
@@ -171,13 +181,16 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
 	fileneedednum = 1;
 	fileneeded[0].status = FS_REQUESTED;
 	fileneeded[0].totalsize = UINT32_MAX;
-	fileneeded[0].phandle = NULL;
+	fileneeded[0].file = NULL;
 	memset(fileneeded[0].md5sum, 0, 16);
 	strcpy(fileneeded[0].filename, tmpsave);
 }
 
 /** Checks the server to see if we CAN download all the files,
   * before starting to create them and requesting.
+  *
+  * \return True if we can download all the files
+  *
   */
 boolean CL_CheckDownloadable(void)
 {
@@ -239,8 +252,12 @@ boolean CL_CheckDownloadable(void)
 	return false;
 }
 
-/** Send requests for files in the ::fileneeded table with a status of
+/** Sends requests for files in the ::fileneeded table with a status of
   * ::FS_NOTFOUND.
+  *
+  * \return True if the packet was successfully sent
+  * \note Sends a PT_REQUESTFILE packet
+  *
   */
 boolean CL_SendRequestFile(void)
 {
@@ -287,7 +304,8 @@ boolean CL_SendRequestFile(void)
 }
 
 // get request filepak and put it on the send queue
-void Got_RequestFilePak(INT32 node)
+// returns false if a requested file was not found or cannot be sent
+boolean Got_RequestFilePak(INT32 node)
 {
 	char wad[MAX_WADPATH+1];
 	UINT8 *p = netbuffer->u.textcmd;
@@ -298,16 +316,33 @@ void Got_RequestFilePak(INT32 node)
 		if (id == 0xFF)
 			break;
 		READSTRINGN(p, wad, MAX_WADPATH);
-		SendFile(node, wad, id);
+		if (!SV_SendFile(node, wad, id))
+		{
+			SV_AbortSendFiles(node);
+			return false; // don't read the rest of the files
+		}
 	}
+	return true; // no problems with any files
 }
 
-// client check if the fileneeded aren't already loaded or on the disk
+/** Checks if the files needed aren't already loaded or on the disk
+  *
+  * \return 0 if some files are missing
+  *         1 if all files exist
+  *         2 if some already loaded files are not requested or are in a different order
+  *
+  */
 INT32 CL_CheckFiles(void)
 {
 	INT32 i, j;
 	char wadfilename[MAX_WADPATH];
 	INT32 ret = 1;
+	size_t packetsize = 0;
+	size_t filestoget = 0;
+	serverinfo_pak *dummycheck = NULL;
+
+	// Shut the compiler up.
+	(void)dummycheck;
 
 //	if (M_CheckParm("-nofiles"))
 //		return 1;
@@ -333,7 +368,7 @@ INT32 CL_CheckFiles(void)
 			}
 			if (j < numwadfiles && W_VerifyNMUSlumps(wadfiles[j]->filename))
 			{
-				// unimportant on our side. still don't care.
+				// Unimportant on our side. still don't care.
 				++j;
 				continue;
 			}
@@ -343,11 +378,11 @@ INT32 CL_CheckFiles(void)
 			if (i >= fileneedednum || j >= numwadfiles)
 				return 2;
 
-			// for the sake of speed, only bother with a md5 check
+			// For the sake of speed, only bother with a md5 check
 			if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
 				return 2;
 
-			// it's accounted for! let's keep going.
+			// It's accounted for! let's keep going.
 			CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
 			fileneeded[i].status = FS_OPEN;
 			++i;
@@ -356,11 +391,15 @@ INT32 CL_CheckFiles(void)
 		return 1;
 	}
 
+	// See W_LoadWadFile in w_wad.c
+	for (i = 0; i < numwadfiles; i++)
+		packetsize += nameonlylength(wadfiles[i]->filename) + 22;
+
 	for (i = 1; i < fileneedednum; i++)
 	{
 		CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
 
-		// check in allready loaded files
+		// Check in already loaded files
 		for (j = 1; wadfiles[j]; j++)
 		{
 			nameonly(strcpy(wadfilename, wadfiles[j]->filename));
@@ -375,6 +414,14 @@ INT32 CL_CheckFiles(void)
 		if (fileneeded[i].status != FS_NOTFOUND || !fileneeded[i].important)
 			continue;
 
+		packetsize += nameonlylength(fileneeded[i].filename) + 22;
+
+		if ((numwadfiles+filestoget >= MAX_WADFILES)
+		|| (packetsize > sizeof(dummycheck->fileneeded)))
+			return 3;
+
+		filestoget++;
+
 		fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
 		CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
 		if (fileneeded[i].status != FS_FOUND)
@@ -383,7 +430,7 @@ INT32 CL_CheckFiles(void)
 	return ret;
 }
 
-// load it now
+// Load it now
 void CL_LoadServerFiles(void)
 {
 	INT32 i;
@@ -394,7 +441,7 @@ void CL_LoadServerFiles(void)
 	for (i = 1; i < fileneedednum; i++)
 	{
 		if (fileneeded[i].status == FS_OPEN)
-			continue; // already loaded
+			continue; // Already loaded
 		else if (fileneeded[i].status == FS_FOUND)
 		{
 			P_AddWadFile(fileneeded[i].filename, NULL);
@@ -423,172 +470,270 @@ void CL_LoadServerFiles(void)
 			DEBFILE(va("File %s found but with different md5sum\n", fileneeded[i].filename));
 		}
 		else if (fileneeded[i].important)
-			I_Error("Try to load file %s with status of %d\n", fileneeded[i].filename,
-				fileneeded[i].status);
+		{
+			const char *s;
+			switch(fileneeded[i].status)
+			{
+			case FS_NOTFOUND:
+				s = "FS_NOTFOUND";
+				break;
+			case FS_REQUESTED:
+				s = "FS_REQUESTED";
+				break;
+			case FS_DOWNLOADING:
+				s = "FS_DOWNLOADING";
+				break;
+			default:
+				s = "unknown";
+				break;
+			}
+			I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
+				fileneeded[i].status, s);
+		}
 	}
 }
 
-// little optimization to test if there is a file in the queue
-static INT32 filetosend = 0;
+// Number of files to send
+// Little optimization to quickly test if there is a file in the queue
+static INT32 filestosend = 0;
 
-static void SendFile(INT32 node, const char *filename, UINT8 fileid)
+/** Adds a file to the file list for a node
+  *
+  * \param node The node to send the file to
+  * \param filename The file to send
+  * \param fileid ???
+  * \sa SV_SendRam
+  *
+  */
+static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
 {
-	filetx_t **q;
-	filetx_t *p;
+	filetx_t **q; // A pointer to the "next" field of the last file in the list
+	filetx_t *p; // The new file request
 	INT32 i;
 	char wadfilename[MAX_WADPATH];
 
+	if (cv_noticedownload.value)
+		CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
+
+	// Find the last file in the list and set a pointer to its "next" field
 	q = &transfer[node].txlist;
 	while (*q)
 		q = &((*q)->next);
+
+	// Allocate a file request and append it to the file list
 	p = *q = (filetx_t *)malloc(sizeof (filetx_t));
-	if (p)
-		memset(p, 0, sizeof (filetx_t));
-	else
-		I_Error("SendFile: No more ram\n");
-	p->filename = (char *)malloc(MAX_WADPATH);
-	if (!p->filename)
-		I_Error("SendFile: No more ram\n");
+	if (!p)
+		I_Error("SV_SendFile: No more memory\n");
+
+	// Initialise with zeros
+	memset(p, 0, sizeof (filetx_t));
 
-	// a minimum of security, can get only file in srb2 direcory
-	strlcpy(p->filename, filename, MAX_WADPATH);
-	nameonly(p->filename);
+	// Allocate the file name
+	p->id.filename = (char *)malloc(MAX_WADPATH);
+	if (!p->id.filename)
+		I_Error("SV_SendFile: No more memory\n");
 
-	// check first in wads loaded the majority of case
+	// Set the file name and get rid of the path
+	strlcpy(p->id.filename, filename, MAX_WADPATH);
+	nameonly(p->id.filename);
+
+	// Look for the requested file through all loaded files
 	for (i = 0; wadfiles[i]; i++)
 	{
 		strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
 		nameonly(wadfilename);
-		if (!stricmp(wadfilename, p->filename))
+		if (!stricmp(wadfilename, p->id.filename))
 		{
-			// copy filename with full path
-			strlcpy(p->filename, wadfiles[i]->filename, MAX_WADPATH);
+			// Copy file name with full path
+			strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
 			break;
 		}
 	}
 
+	// Handle non-loaded file requests
 	if (!wadfiles[i])
 	{
 		DEBFILE(va("%s not found in wadfiles\n", filename));
-		// this formerly checked if (!findfile(p->filename, NULL, true))
+		// This formerly checked if (!findfile(p->id.filename, NULL, true))
 
-		// not found
-		// don't inform client (probably hacker)
+		// Not found
+		// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
 		DEBFILE(va("Client %d request %s: not found\n", node, filename));
-		free(p->filename);
+		free(p->id.filename);
 		free(p);
 		*q = NULL;
-		return;
+		return false; // cancel the rest of the requests
 	}
 
+	// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
 	if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
 	{
-		// too big
-		// don't inform client (client sucks, man)
+		// Too big
+		// Don't inform client (client sucks, man)
 		DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
-		free(p->filename);
+		free(p->id.filename);
 		free(p);
 		*q = NULL;
-		return;
+		return false; // cancel the rest of the requests
 	}
 
 	DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
-	p->ram = SF_FILE;
+	p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
 	p->fileid = fileid;
-	p->next = NULL; // end of list
-	filetosend++;
+	p->next = NULL; // End of list
+	filestosend++;
+	return true;
 }
 
-void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
+/** Adds a memory block to the file list for a node
+  *
+  * \param node The node to send the memory block to
+  * \param data The memory block to send
+  * \param size The size of the block in bytes
+  * \param freemethod How to free the block after it has been sent
+  * \param fileid ???
+  * \sa SV_SendFile
+  *
+  */
+void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
 {
-	filetx_t **q;
-	filetx_t *p;
+	filetx_t **q; // A pointer to the "next" field of the last file in the list
+	filetx_t *p; // The new file request
 
+	// Find the last file in the list and set a pointer to its "next" field
 	q = &transfer[node].txlist;
 	while (*q)
 		q = &((*q)->next);
+
+	// Allocate a file request and append it to the file list
 	p = *q = (filetx_t *)malloc(sizeof (filetx_t));
-	if (p)
-		memset(p, 0, sizeof (filetx_t));
-	else
-		I_Error("SendRam: No more ram\n");
-	p->ram = freemethod;
-	p->filename = data;
+	if (!p)
+		I_Error("SV_SendRam: No more memory\n");
+
+	// Initialise with zeros
+	memset(p, 0, sizeof (filetx_t));
+
+	p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
+	p->id.ram = data;
 	p->size = (UINT32)size;
 	p->fileid = fileid;
-	p->next = NULL; // end of list
+	p->next = NULL; // End of list
 
-	DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->filename,p->size,node,fileid));
+	DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
 
-	filetosend++;
+	filestosend++;
 }
 
-static void EndSend(INT32 node)
+/** Stops sending a file for a node, and removes the file request from the list,
+  * either because the file has been fully sent or because the node was disconnected
+  *
+  * \param node The destination
+  *
+  */
+static void SV_EndFileSend(INT32 node)
 {
 	filetx_t *p = transfer[node].txlist;
+
+	// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
 	switch (p->ram)
 	{
-		case SF_FILE:
+		case SF_FILE: // It's a file, close it and free its filename
+			if (cv_noticedownload.value)
+				CONS_Printf("Ending file transfer for node %d\n", node);
 			if (transfer[node].currentfile)
 				fclose(transfer[node].currentfile);
-			free(p->filename);
+			free(p->id.filename);
 			break;
-		case SF_Z_RAM:
-			Z_Free(p->filename);
+		case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
+			Z_Free(p->id.ram);
 			break;
-		case SF_RAM:
-			free(p->filename);
-		case SF_NOFREERAM:
+		case SF_RAM: // It's a memory block allocated with malloc, use free
+			free(p->id.ram);
+		case SF_NOFREERAM: // Nothing to free
 			break;
 	}
+
+	// Remove the file request from the list
 	transfer[node].txlist = p->next;
-	transfer[node].currentfile = NULL;
 	free(p);
-	filetosend--;
+
+	// Indicate that the transmission is over
+	transfer[node].currentfile = NULL;
+
+	filestosend--;
 }
 
 #define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
 
-void FiletxTicker(void)
+/** Handles file transmission
+  *
+  * \todo Use an acknowledging method more adapted to file transmission
+  *       The current download speed suffers from lack of ack packets,
+  *       especially when the one downloading has high latency
+  *
+  */
+void SV_FileSendTicker(void)
 {
 	static INT32 currentnode = 0;
 	filetx_pak *p;
 	size_t size;
 	filetx_t *f;
-	INT32 packetsent = PACKETPERTIC, ram, i;
+	INT32 packetsent, ram, i, j;
+	INT32 maxpacketsent;
 
-	if (!filetosend)
+	if (!filestosend) // No file to send
 		return;
-	if (!packetsent)
-		packetsent++;
+
+	if (cv_downloadspeed.value) // New (and experimental) behavior
+	{
+		packetsent = cv_downloadspeed.value;
+		// Don't send more packets than we have free acks
+#ifndef NONET
+		maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case
+#else
+		maxpacketsent = 1;
+#endif
+		if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
+			packetsent = maxpacketsent;
+	}
+	else // Old behavior
+	{
+		packetsent = PACKETPERTIC;
+		if (!packetsent)
+			packetsent = 1;
+	}
+
+	netbuffer->packettype = PT_FILEFRAGMENT;
+
 	// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
-	while (packetsent-- && filetosend != 0)
+	while (packetsent-- && filestosend != 0)
 	{
-		for (i = currentnode, ram = 0; ram < MAXNETNODES;
-			i = (i+1) % MAXNETNODES, ram++)
+		for (i = currentnode, j = 0; j < MAXNETNODES;
+			i = (i+1) % MAXNETNODES, j++)
 		{
 			if (transfer[i].txlist)
 				goto found;
 		}
 		// no transfer to do
-		I_Error("filetosend=%d but no filetosend found\n", filetosend);
+		I_Error("filestosend=%d but no file to send found\n", filestosend);
 	found:
 		currentnode = (i+1) % MAXNETNODES;
 		f = transfer[i].txlist;
 		ram = f->ram;
 
-		if (!transfer[i].currentfile) // file not already open
+		// Open the file if it isn't open yet, or
+		if (!transfer[i].currentfile)
 		{
-			if (!ram)
+			if (!ram) // Sending a file
 			{
 				long filesize;
 
 				transfer[i].currentfile =
-					fopen(f->filename, "rb");
+					fopen(f->id.filename, "rb");
 
 				if (!transfer[i].currentfile)
 					I_Error("File %s does not exist",
-						f->filename);
+						f->id.filename);
 
 				fseek(transfer[i].currentfile, 0, SEEK_END);
 				filesize = ftell(transfer[i].currentfile);
@@ -596,101 +741,138 @@ void FiletxTicker(void)
 				// Nobody wants to transfer a file bigger
 				// than 4GB!
 				if (filesize >= LONG_MAX)
-					I_Error("filesize of %s is too large", f->filename);
-				if (-1 == filesize)
-					I_Error("Error getting filesize of %s", f->filename);
+					I_Error("filesize of %s is too large", f->id.filename);
+				if (filesize == -1)
+					I_Error("Error getting filesize of %s", f->id.filename);
 
 				f->size = (UINT32)filesize;
 				fseek(transfer[i].currentfile, 0, SEEK_SET);
 			}
-			else
-				transfer[i].currentfile = (FILE *)1;
+			else // Sending RAM
+				transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
 			transfer[i].position = 0;
 		}
 
+		// Build a packet containing a file fragment
 		p = &netbuffer->u.filetxpak;
 		size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
 		if (f->size-transfer[i].position < size)
 			size = f->size-transfer[i].position;
 		if (ram)
-			M_Memcpy(p->data, &f->filename[transfer[i].position], size);
+			M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
 		else if (fread(p->data, 1, size, transfer[i].currentfile) != size)
-			I_Error("FiletxTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
+			I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(size), f->id.filename, transfer[i].position, strerror(ferror(transfer[i].currentfile)));
 		p->position = LONG(transfer[i].position);
-		// put flag so receiver know the totalsize
+		// Put flag so receiver knows the total size
 		if (transfer[i].position + size == f->size)
 			p->position |= LONG(0x80000000);
 		p->fileid = f->fileid;
 		p->size = SHORT((UINT16)size);
-		netbuffer->packettype = PT_FILEFRAGMENT;
-		if (!HSendPacket(i, true, 0, FILETXHEADER + size)) // reliable SEND
-		{ // not sent for some odd reason, retry at next call
+
+		// Send the packet
+		if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
+		{ // Success
+			transfer[i].position = (UINT32)(transfer[i].position + size);
+			if (transfer[i].position == f->size) // Finish?
+				SV_EndFileSend(i);
+		}
+		else
+		{ // Not sent for some odd reason, retry at next call
 			if (!ram)
-				fseek(transfer[i].currentfile,transfer[i].position,SEEK_SET);
-			// exit the while (can't send this one so why should i send the next?)
+				fseek(transfer[i].currentfile,transfer[i].position, SEEK_SET);
+			// Exit the while (can't send this one so why should i send the next?)
 			break;
 		}
-		else // success
-		{
-			transfer[i].position = (UINT32)(size+transfer[i].position);
-			if (transfer[i].position == f->size) //  finish ?
-				EndSend(i);
-		}
 	}
 }
 
 void Got_Filetxpak(void)
 {
 	INT32 filenum = netbuffer->u.filetxpak.fileid;
+	fileneeded_t *file = &fileneeded[filenum];
+	char *filename = file->filename;
 	static INT32 filetime = 0;
 
+	if (!(strcmp(filename, "srb2.srb")
+		&& strcmp(filename, "srb2.wad")
+		&& strcmp(filename, "zones.dta")
+		&& strcmp(filename, "player.dta")
+		&& strcmp(filename, "rings.dta")
+		&& strcmp(filename, "patch.dta")
+		&& strcmp(filename, "music.dta")
+		))
+		I_Error("Tried to download \"%s\"", filename);
+
 	if (filenum >= fileneedednum)
 	{
-		DEBFILE(va("fileframent not needed %d>%d\n",filenum, fileneedednum));
+		DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
+		//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
 		return;
 	}
 
-	if (fileneeded[filenum].status == FS_REQUESTED)
+	if (file->status == FS_REQUESTED)
 	{
-		if (fileneeded[filenum].phandle) I_Error("Got_Filetxpak: allready open file\n");
-			fileneeded[filenum].phandle = fopen(fileneeded[filenum].filename, "wb");
-		if (!fileneeded[filenum].phandle) I_Error("Can't create file %s: %s",fileneeded[filenum].filename, strerror(errno));
-			CONS_Printf("\r%s...\n",fileneeded[filenum].filename);
-		fileneeded[filenum].currentsize = 0;
-		fileneeded[filenum].status = FS_DOWNLOADING;
+		if (file->file)
+			I_Error("Got_Filetxpak: already open file\n");
+		file->file = fopen(filename, "wb");
+		if (!file->file)
+			I_Error("Can't create file %s: %s", filename, strerror(errno));
+		CONS_Printf("\r%s...\n",filename);
+		file->currentsize = 0;
+		file->status = FS_DOWNLOADING;
 	}
 
-	if (fileneeded[filenum].status == FS_DOWNLOADING)
+	if (file->status == FS_DOWNLOADING)
 	{
 		UINT32 pos = LONG(netbuffer->u.filetxpak.position);
 		UINT16 size = SHORT(netbuffer->u.filetxpak.size);
-		// use a special tric to know when file is finished (not allways used)
-		// WARNING: filepak can arrive out of order so don't stop now !
+		// Use a special trick to know when the file is complete (not always used)
+		// WARNING: file fragments can arrive out of order so don't stop yet!
 		if (pos & 0x80000000)
 		{
 			pos &= ~0x80000000;
-			fileneeded[filenum].totalsize = pos + size;
+			file->totalsize = pos + size;
 		}
-		// we can receive packet in the wrong order, anyway all os support gaped file
-		fseek(fileneeded[filenum].phandle,pos,SEEK_SET);
-		if (fwrite(netbuffer->u.filetxpak.data,size,1,fileneeded[filenum].phandle)!=1)
-			I_Error("Can't write to %s: %s\n",fileneeded[filenum].filename, strerror(ferror(fileneeded[filenum].phandle)));
-		fileneeded[filenum].currentsize += size;
-
-		// finished?
-		if (fileneeded[filenum].currentsize == fileneeded[filenum].totalsize)
+		// We can receive packet in the wrong order, anyway all os support gaped file
+		fseek(file->file, pos, SEEK_SET);
+		if (fwrite(netbuffer->u.filetxpak.data,size,1,file->file) != 1)
+			I_Error("Can't write to %s: %s\n",filename, strerror(ferror(file->file)));
+		file->currentsize += size;
+
+		// Finished?
+		if (file->currentsize == file->totalsize)
 		{
-			fclose(fileneeded[filenum].phandle);
-			fileneeded[filenum].phandle = NULL;
-			fileneeded[filenum].status = FS_FOUND;
+			fclose(file->file);
+			file->file = NULL;
+			file->status = FS_FOUND;
 			CONS_Printf(M_GetText("Downloading %s...(done)\n"),
-				fileneeded[filenum].filename);
+				filename);
 		}
 	}
 	else
-		I_Error("Received a file not requested\n");
-	// send ack back quickly
-
+	{
+		const char *s;
+		switch(file->status)
+		{
+		case FS_NOTFOUND:
+			s = "FS_NOTFOUND";
+			break;
+		case FS_FOUND:
+			s = "FS_FOUND";
+			break;
+		case FS_OPEN:
+			s = "FS_OPEN";
+			break;
+		case FS_MD5SUMBAD:
+			s = "FS_MD5SUMBAD";
+			break;
+		default:
+			s = "unknown";
+			break;
+		}
+		I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
+	}
+	// Send ack back quickly
 	if (++filetime == 3)
 	{
 		Net_SendAcks(servernode);
@@ -702,33 +884,50 @@ void Got_Filetxpak(void)
 #endif
 }
 
-void AbortSendFiles(INT32 node)
+/** \brief Checks if a node is downloading a file
+ *
+ * \param node The node to check for
+ * \return True if the node is downloading a file
+ *
+ */
+boolean SV_SendingFile(INT32 node)
+{
+	return transfer[node].txlist != NULL;
+}
+
+/** Cancels all file requests for a node
+  *
+  * \param node The destination
+  * \sa SV_EndFileSend
+  *
+  */
+void SV_AbortSendFiles(INT32 node)
 {
 	while (transfer[node].txlist)
-		EndSend(node);
+		SV_EndFileSend(node);
 }
 
 void CloseNetFile(void)
 {
 	INT32 i;
-	// is sending?
+	// Is sending?
 	for (i = 0; i < MAXNETNODES; i++)
-		AbortSendFiles(i);
+		SV_AbortSendFiles(i);
 
-	// receiving a file?
+	// Receiving a file?
 	for (i = 0; i < MAX_WADFILES; i++)
-		if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].phandle)
+		if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
 		{
-			fclose(fileneeded[i].phandle);
-			// file is not complete delete it
+			fclose(fileneeded[i].file);
+			// File is not complete delete it
 			remove(fileneeded[i].filename);
 		}
 
-	// remove FILEFRAGMENT from acknledge list
+	// Remove PT_FILEFRAGMENT from acknowledge list
 	Net_AbortPacketType(PT_FILEFRAGMENT);
 }
 
-// functions cut and pasted from doomatic :)
+// Functions cut and pasted from Doomatic :)
 
 void nameonly(char *s)
 {
diff --git a/src/d_netfil.h b/src/d_netfil.h
index a68119f10dc59cd6fec1406abda9f7fa0fa0591a..b9b7b2f2ea389c977b26cfb970502f3b5ee67333 100644
--- a/src/d_netfil.h
+++ b/src/d_netfil.h
@@ -29,21 +29,21 @@ typedef enum
 	FS_FOUND,
 	FS_REQUESTED,
 	FS_DOWNLOADING,
-	FS_OPEN, // is opened and used in w_wad
+	FS_OPEN, // Is opened and used in w_wad
 	FS_MD5SUMBAD
 } filestatus_t;
 
 typedef struct
 {
 	UINT8 important;
-	UINT8 willsend; // is the server willing to send it?
+	UINT8 willsend; // Is the server willing to send it?
 	char filename[MAX_WADPATH];
 	UINT8 md5sum[16];
-	// used only for download
-	FILE *phandle;
+	// Used only for download
+	FILE *file;
 	UINT32 currentsize;
 	UINT32 totalsize;
-	filestatus_t status; // the value returned by recsearch
+	filestatus_t status; // The value returned by recsearch
 } fileneeded_t;
 
 extern INT32 fileneedednum;
@@ -58,28 +58,25 @@ UINT8 *PutFileNeeded(void);
 void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr);
 void CL_PrepareDownloadSaveGame(const char *tmpsave);
 
-// check file list in wadfiles return 0 when a file is not found
-//                                    1 if all file are found
-//                                    2 if you cannot connect (different wad version or
-//                                                   no enought space to download files)
 INT32 CL_CheckFiles(void);
 void CL_LoadServerFiles(void);
-void SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
+void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod,
 	UINT8 fileid);
 
-void FiletxTicker(void);
+void SV_FileSendTicker(void);
 void Got_Filetxpak(void);
+boolean SV_SendingFile(INT32 node);
 
 boolean CL_CheckDownloadable(void);
 boolean CL_SendRequestFile(void);
-void Got_RequestFilePak(INT32 node);
+boolean Got_RequestFilePak(INT32 node);
 
-void AbortSendFiles(INT32 node);
+void SV_AbortSendFiles(INT32 node);
 void CloseNetFile(void);
 
 boolean fileexist(char *filename, time_t ptime);
 
-// search a file in the wadpath, return FS_FOUND when found
+// Search a file in the wadpath, return FS_FOUND when found
 filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum,
 	boolean completepath);
 filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum);
diff --git a/src/dehacked.c b/src/dehacked.c
index 199ea43ca89160879676a05f2325806d2301ab07..f03dd73b474f975317e644bf180697960e31764f 100644
--- a/src/dehacked.c
+++ b/src/dehacked.c
@@ -6717,12 +6717,14 @@ static const char *const MOBJEFLAG_LIST[] = {
 	NULL
 };
 
+#ifdef HAVE_BLUA
 static const char *const MAPTHINGFLAG_LIST[4] = {
 	NULL,
 	"OBJECTFLIP", // Reverse gravity flag for objects.
 	"OBJECTSPECIAL", // Special flag used with certain objects.
 	"AMBUSH" // Deaf monsters/do not react to sound.
 };
+#endif
 
 static const char *const PLAYERFLAG_LIST[] = {
 	// Flip camera angle with gravity flip prefrence.
@@ -6795,6 +6797,7 @@ static const char *const PLAYERFLAG_LIST[] = {
 	NULL // stop loop here.
 };
 
+#ifdef HAVE_BLUA
 // Linedef flags
 static const char *const ML_LIST[16] = {
 	"IMPASSIBLE",
@@ -6814,6 +6817,7 @@ static const char *const ML_LIST[16] = {
 	"BOUNCY",
 	"TFERLINE"
 };
+#endif
 
 // This DOES differ from r_draw's Color_Names, unfortunately.
 // Also includes Super colors
@@ -7762,7 +7766,7 @@ fixed_t get_number(const char *word)
 #endif
 }
 
-void DEH_Check(void)
+void FUNCMATH DEH_Check(void)
 {
 #if defined(_DEBUG) || defined(PARANOIA)
 	const size_t dehstates = sizeof(STATE_LIST)/sizeof(const char*);
@@ -8276,6 +8280,9 @@ static inline int lib_getenum(lua_State *L)
 	} else if (fastcmp(word,"VERSIONSTRING")) {
 		lua_pushstring(L, VERSIONSTRING);
 		return 1;
+	} else if (fastcmp(word, "token")) {
+		lua_pushinteger(L, token);
+		return 1;
 	}
 
 	return 0;
diff --git a/src/djgppdos/i_system.c b/src/djgppdos/i_system.c
index 854d68f4d5b98ac3e145468ef3eaac4949af69a6..dae9ed16e3b426d195bf91c8ee62890fc42d7f48 100644
--- a/src/djgppdos/i_system.c
+++ b/src/djgppdos/i_system.c
@@ -1721,6 +1721,18 @@ INT32 I_PutEnv(char *variable)
 	return putenv(variable);
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 const CPUInfoFlags *I_CPUInfo(void)
 {
 	static CPUInfoFlags DOS_CPUInfo;
diff --git a/src/doomdef.h b/src/doomdef.h
index 9a1e5af9ee5a6e5ce5c1bc7063a918354a4b17ab..cdb1a7dbf4b685f7c9b01d9a6a607d63d83d3e8c 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -60,6 +60,7 @@
 #endif
 
 #ifdef _WINDOWS
+#define NONET
 #if !defined (HWRENDER) && !defined (NOHW)
 #define HWRENDER
 #endif
@@ -149,9 +150,9 @@ extern FILE *logstream;
 // we use comprevision and compbranch instead.
 #else
 #define VERSION    201 // Game version
-#define SUBVERSION 15  // more precise version number
-#define VERSIONSTRING "v2.1.15"
-#define VERSIONSTRINGW L"v2.1.15"
+#define SUBVERSION 19  // more precise version number
+#define VERSIONSTRING "v2.1.19"
+#define VERSIONSTRINGW L"v2.1.19"
 // Hey! If you change this, add 1 to the MODVERSION below!
 // Otherwise we can't force updates!
 #endif
@@ -213,7 +214,7 @@ extern FILE *logstream;
 // it's only for detection of the version the player is using so the MS can alert them of an update.
 // Only set it higher, not lower, obviously.
 // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
-#define MODVERSION 20
+#define MODVERSION 24
 
 // =========================================================================
 
@@ -393,6 +394,9 @@ extern INT32 cv_debug;
 // Misc stuff for later...
 // =======================
 
+// Modifier key variables, accessible anywhere
+extern UINT8 shiftdown, ctrldown, altdown;
+
 // if we ever make our alloc stuff...
 #define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
 
@@ -431,6 +435,12 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
 /// Kalaron/Eternity Engine slope code (SRB2CB ported)
 #define ESLOPE
 
+#ifdef ESLOPE
+/// Backwards compatibility with SRB2CB's slope linedef types.
+///	\note	A simple shim that prints a warning.
+#define ESLOPE_TYPESHIM
+#endif
+
 ///	Delete file while the game is running.
 ///	\note	EXTREMELY buggy, tends to crash game.
 //#define DELFILE
diff --git a/src/doomtype.h b/src/doomtype.h
index 2d9d363282047afd76c12dc177ebd1279c4d52c8..a711b466d6ccf61d8262534cb585f0a7a3ef7c2e 100644
--- a/src/doomtype.h
+++ b/src/doomtype.h
@@ -92,7 +92,7 @@ typedef long ssize_t;
 #endif
 
 #ifdef __APPLE_CC__
-#define DIRECTFULLSCREEN
+#define DIRECTFULLSCREEN 1
 #define DEBUG_LOG
 #define NOIPX
 #endif
diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c
index c1e48b60bb0239de595447dc9999ecb4ec949073..a3fe3077c2a46f6956a5723eb1de40127da7e798 100644
--- a/src/dummy/i_system.c
+++ b/src/dummy/i_system.c
@@ -162,6 +162,18 @@ INT32 I_PutEnv(char *variable)
 	return -1;
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 void I_RegisterSysCommands(void) {}
 
 #include "../sdl/dosstr.c"
diff --git a/src/f_finale.c b/src/f_finale.c
index 776bec9812f602f9bab2987ef28e213471279837..692abb35f4837a921a97ff0a8fefb13189e10a9c 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -974,7 +974,7 @@ static const char *credits[] = {
 	"Scott \"Graue\" Feeney",
 	"Nathan \"Jazz\" Giroux",
 	"Thomas \"Shadow Hog\" Igoe",
-	"\"Monster\" Iestyn Jealous",
+	"Iestyn \"Monster Iestyn\" Jealous",
 	"Ronald \"Furyhunter\" Kinard", // The SDL2 port
 	"John \"JTE\" Muniz",
 	"Ehab \"Wolfy\" Saeed",
@@ -986,6 +986,8 @@ static const char *credits[] = {
 	"\"chi.miru\"", // Red's secret weapon, the REAL reason slopes exist (also helped port drawing code from ZDoom)
 	"Andrew \"orospakr\" Clunis",
 	"Gregor \"Oogaland\" Dick",
+	"Louis-Antoine \"LJSonic\" de Moulins", // for fixing 2.1's netcode (de Rochefort doesn't quite fit on the screen sorry lol)
+	"Vivian \"toaster\" Grannell",
 	"Julio \"Chaos Zero 64\" Guir",
 	"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
 	"Matthew \"Shuffle\" Marsalko",
@@ -1019,7 +1021,7 @@ static const char *credits[] = {
 	"Paul \"Boinciel\" Clempson",
 	"Cyan Helkaraxe",
 	"Kepa \"Nev3r\" Iceta",
-	"\"Monster\" Iestyn Jealous",
+	"Iestyn \"Monster Iestyn\" Jealous",
 	"Jarel \"Arrow\" Jones",
 	"Stefan \"Stuf\" Rimalia",
 	"Shane Mychal Sexton",
@@ -1724,6 +1726,7 @@ static void F_AdvanceToNextScene(void)
 
 void F_EndCutScene(void)
 {
+	cutsceneover = true; // do this first, just in case Y_EndGame or something wants to turn it back false later
 	if (runningprecutscene)
 	{
 		if (server)
@@ -1740,7 +1743,6 @@ void F_EndCutScene(void)
 		else
 			Y_EndGame();
 	}
-	cutsceneover = true;
 }
 
 void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean resetplayer)
diff --git a/src/f_finale.h b/src/f_finale.h
index 8ee02bdf3d6687d774baaac7f1139b84ec999115..1f23643bec2bd52a91cd3477ded284eb2a842484 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -35,7 +35,7 @@ void F_CutsceneTicker(void);
 void F_TitleDemoTicker(void);
 
 // Called by main loop.
-void F_GameEndDrawer(void);
+FUNCMATH void F_GameEndDrawer(void);
 void F_IntroDrawer(void);
 void F_TitleScreenDrawer(void);
 
diff --git a/src/g_game.c b/src/g_game.c
index 8931f8b6b23ff57decef67ce57c9aaf4a8b3b0ae..7499fe7a0e362209d4f27cb96c98243262c008e5 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -711,6 +711,10 @@ void G_SetGameModified(boolean silent)
 
 	if (!silent)
 		CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n"));
+
+	// If in record attack recording, cancel it.
+	if (modeattacking)
+		M_EndModeAttackRun();
 }
 
 /** Builds an original game map name from a map number.
@@ -2884,7 +2888,7 @@ static void G_DoCompleted(void)
 	if (nextmap < NUMMAPS && !mapheaderinfo[nextmap])
 		P_AllocMapHeader(nextmap);
 
-	if (skipstats)
+	if (skipstats && !modeattacking) // Don't skip stats if we're in record attack
 		G_AfterIntermission();
 	else
 	{
@@ -5575,7 +5579,7 @@ boolean G_CheckDemoStatus(void)
 		WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker
 		md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file.
 #endif
-		saved = FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer); // finally output the file.
+		saved = FIL_WriteFile(va(pandf, srb2home, demoname), demobuffer, demo_p - demobuffer); // finally output the file.
 		free(demobuffer);
 		demorecording = false;
 
diff --git a/src/hardware/hw_dll.h b/src/hardware/hw_dll.h
index d9620be0299ae8e133f01ecb48e50660bb608a7b..6b9f4d538860d29a61967ccd7e2c538d65fecdaa 100644
--- a/src/hardware/hw_dll.h
+++ b/src/hardware/hw_dll.h
@@ -54,7 +54,7 @@
  #endif
 #endif
 
-typedef void (*I_Error_t) (const char *error, ...);
+typedef void (*I_Error_t) (const char *error, ...) FUNCIERROR;
 
 // ==========================================================================
 //                                                                      MATHS
diff --git a/src/hardware/hw_draw.c b/src/hardware/hw_draw.c
index 60183b58e72a168ceea2a2971f6b18f3e8fe5831..f23753ee53ff4ef65833cd3c661b80391e45526a 100644
--- a/src/hardware/hw_draw.c
+++ b/src/hardware/hw_draw.c
@@ -656,6 +656,7 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 {
 	FOutVector v[4];
 	FSurfaceInfo Surf;
+	float sdupx, sdupy;
 
 	if (w < 0 || h < 0)
 		return; // consistency w/ software
@@ -664,10 +665,16 @@ void HWR_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 color)
 //  | /|
 //  |/ |
 //  0--1
-	v[0].x = v[3].x = (x - 160.0f)/160.0f;
-	v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
-	v[0].y = v[1].y = -(y - 100.0f)/100.0f;
-	v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;
+	sdupx = FIXED_TO_FLOAT(vid.fdupx)*2.0f;
+	sdupy = FIXED_TO_FLOAT(vid.fdupy)*2.0f;
+
+	if (color & V_NOSCALESTART)
+		sdupx = sdupy = 2.0f;
+
+	v[0].x = v[3].x = (x*sdupx)/vid.width - 1;
+	v[2].x = v[1].x = (x*sdupx + w*sdupx)/vid.width - 1;
+	v[0].y = v[1].y = 1-(y*sdupy)/vid.height;
+	v[2].y = v[3].y = 1-(y*sdupy + h*sdupy)/vid.height;
 
 	//Hurdler: do we still use this argb color? if not, we should remove it
 	v[0].argb = v[1].argb = v[2].argb = v[3].argb = 0xff00ff00; //;
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 35a01ffd11ed25d0d7943ddd37a95e82238fd132..05391f4d051ed0fd8c2b4a63cefdcbd53e39ad1d 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -45,7 +45,7 @@
 #include "hw_md2.h"
 
 #define R_FAKEFLOORS
-//#define HWPRECIP
+#define HWPRECIP
 #define SORTING
 //#define POLYSKY
 
@@ -66,9 +66,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing);
 #endif
 
 #ifdef SORTING
-void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
+void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
                              INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap);
-void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, fixed_t fixedheight,
+void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
                              INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap);
 #else
 static void HWR_Add3DWater(lumpnum_t lumpnum, extrasubsector_t *xsub, fixed_t fixedheight,
@@ -521,7 +521,7 @@ static UINT8 HWR_FogBlockAlpha(INT32 light, UINT32 color, UINT32 fadecolor) // L
 // -----------------+
 // HWR_RenderPlane  : Render a floor or ceiling convex polygon
 // -----------------+
-static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fixedheight,
+static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight,
                            FBITFIELD PolyFlags, INT32 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector, UINT8 alpha, boolean fogplane, extracolormap_t *planecolormap)
 {
 	polyvertex_t *  pv;
@@ -554,17 +554,16 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
 	// Get the slope pointer to simplify future code
 	if (FOFsector)
 	{
-		if (FOFsector->f_slope && FOFsector->floorheight == fixedheight)
+		if (FOFsector->f_slope && !isceiling)
 			slope = FOFsector->f_slope;
-		else if (FOFsector->c_slope && FOFsector->ceilingheight == fixedheight)
+		else if (FOFsector->c_slope && isceiling)
 			slope = FOFsector->c_slope;
 	}
 	else
 	{
-		// Use fixedheight to determine whether to check floor or ceiling because I hate my life
-		if (gr_frontsector->f_slope && gr_frontsector->floorheight == fixedheight)
+		if (gr_frontsector->f_slope && !isceiling)
 			slope = gr_frontsector->f_slope;
-		else if (gr_frontsector->c_slope && gr_frontsector->ceilingheight == fixedheight)
+		else if (gr_frontsector->c_slope && isceiling)
 			slope = gr_frontsector->c_slope;
 	}
 
@@ -638,12 +637,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
 
 	if (FOFsector != NULL)
 	{
-#ifdef ESLOPE
-		if ((slope && slope == FOFsector->f_slope)
-			|| fixedheight == FOFsector->floorheight) // it's a floor
-#else
-		if (fixedheight == FOFsector->floorheight) // it's a floor
-#endif
+		if (!isceiling) // it's a floor
 		{
 			scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
 			scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
@@ -658,12 +652,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, fixed_t fi
 	}
 	else if (gr_frontsector)
 	{
-#ifdef ESLOPE
-		if ((slope && slope == gr_frontsector->f_slope)
-			|| fixedheight == gr_frontsector->floorheight) // it's a floor
-#else
-		if (fixedheight < dup_viewz) // it's a floor
-#endif
+		if (!isceiling) // it's a floor
 		{
 			scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
 			scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
@@ -1095,9 +1084,9 @@ static void HWR_SplitWall(sector_t *sector, wallVert3D *wallVerts, INT32 texnum,
 	float endheight = 0.0f, endbheight = 0.0f;
 
 	fixed_t v1x = FLOAT_TO_FIXED(wallVerts[0].x);
-	fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].y);
+	fixed_t v1y = FLOAT_TO_FIXED(wallVerts[0].z); // not a typo
 	fixed_t v2x = FLOAT_TO_FIXED(wallVerts[1].x);
-	fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].y);
+	fixed_t v2y = FLOAT_TO_FIXED(wallVerts[1].z); // not a typo
 	// compiler complains when P_GetZAt is used in FLOAT_TO_FIXED directly
 	// use this as a temp var to store P_GetZAt's return value each time
 	fixed_t temp;
@@ -1569,6 +1558,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 
 	if (gr_backsector)
 	{
+		INT32 gr_toptexture, gr_bottomtexture;
 		// two sided line
 		if (gr_backsector->heightsec != -1)
 		{
@@ -1619,19 +1609,22 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 		}
 
+		gr_toptexture = R_GetTextureNum(gr_sidedef->toptexture);
+		gr_bottomtexture = R_GetTextureNum(gr_sidedef->bottomtexture);
+
 		// check TOP TEXTURE
 		if ((
 #ifdef ESLOPE
 			worldhighslope < worldtopslope ||
 #endif
             worldhigh < worldtop
-            ) && texturetranslation[gr_sidedef->toptexture])
+            ) && gr_toptexture)
 		{
 			if (drawtextured)
 			{
 				fixed_t texturevpegtop; // top
 
-				grTex = HWR_GetTexture(texturetranslation[gr_sidedef->toptexture]);
+				grTex = HWR_GetTexture(gr_toptexture);
 
 				// PEGGING
 				if (gr_linedef->flags & ML_DONTPEGTOP)
@@ -1649,7 +1642,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				texturevpegtop += gr_sidedef->rowoffset;
 
 				// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
-				texturevpegtop %= SHORT(textures[texturetranslation[gr_sidedef->toptexture]]->height)<<FRACBITS;
+				texturevpegtop %= SHORT(textures[gr_toptexture]->height)<<FRACBITS;
 
 				wallVerts[3].t = wallVerts[2].t = texturevpegtop * grTex->scaleY;
 				wallVerts[0].t = wallVerts[1].t = (texturevpegtop + gr_frontsector->ceilingheight - gr_backsector->ceilingheight) * grTex->scaleY;
@@ -1694,9 +1687,9 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->toptexture], &Surf, FF_CUTSOLIDS);
+				HWR_SplitWall(gr_frontsector, wallVerts, gr_toptexture, &Surf, FF_CUTSOLIDS);
 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
-				HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->toptexture], PF_Environment, false, lightnum, colormap);
+				HWR_AddTransparentWall(wallVerts, &Surf, gr_toptexture, PF_Environment, false, lightnum, colormap);
 			else
 				HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
 		}
@@ -1706,13 +1699,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #ifdef ESLOPE
 			worldlowslope > worldbottomslope ||
 #endif
-            worldlow > worldbottom) && texturetranslation[gr_sidedef->bottomtexture]) //only if VISIBLE!!!
+            worldlow > worldbottom) && gr_bottomtexture) //only if VISIBLE!!!
 		{
 			if (drawtextured)
 			{
 				fixed_t texturevpegbottom = 0; // bottom
 
-				grTex = HWR_GetTexture(texturetranslation[gr_sidedef->bottomtexture]);
+				grTex = HWR_GetTexture(gr_bottomtexture);
 
 				// PEGGING
 #ifdef ESLOPE
@@ -1732,7 +1725,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				texturevpegbottom += gr_sidedef->rowoffset;
 
 				// This is so that it doesn't overflow and screw up the wall, it doesn't need to go higher than the texture's height anyway
-				texturevpegbottom %= SHORT(textures[texturetranslation[gr_sidedef->bottomtexture]]->height)<<FRACBITS;
+				texturevpegbottom %= SHORT(textures[gr_bottomtexture]->height)<<FRACBITS;
 
 				wallVerts[3].t = wallVerts[2].t = texturevpegbottom * grTex->scaleY;
 				wallVerts[0].t = wallVerts[1].t = (texturevpegbottom + gr_backsector->floorheight - gr_frontsector->floorheight) * grTex->scaleY;
@@ -1777,13 +1770,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 #endif
 
 			if (gr_frontsector->numlights)
-				HWR_SplitWall(gr_frontsector, wallVerts, texturetranslation[gr_sidedef->bottomtexture], &Surf, FF_CUTSOLIDS);
+				HWR_SplitWall(gr_frontsector, wallVerts, gr_bottomtexture, &Surf, FF_CUTSOLIDS);
 			else if (grTex->mipmap.flags & TF_TRANSPARENT)
-				HWR_AddTransparentWall(wallVerts, &Surf, texturetranslation[gr_sidedef->bottomtexture], PF_Environment, false, lightnum, colormap);
+				HWR_AddTransparentWall(wallVerts, &Surf, gr_bottomtexture, PF_Environment, false, lightnum, colormap);
 			else
 				HWR_ProjectWall(wallVerts, &Surf, PF_Masked, lightnum, colormap);
 		}
-		gr_midtexture = texturetranslation[gr_sidedef->midtexture];
+		gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
 		if (gr_midtexture)
 		{
 			FBITFIELD blendmode;
@@ -2145,7 +2138,7 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 	else
 	{
 		// Single sided line... Deal only with the middletexture (if one exists)
-		gr_midtexture = texturetranslation[gr_sidedef->midtexture];
+		gr_midtexture = R_GetTextureNum(gr_sidedef->midtexture);
 		if (gr_midtexture)
 		{
 			if (drawtextured)
@@ -2243,13 +2236,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
 					continue;
 
-				texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
+				texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
 					size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
 					newline = rover->master->frontsector->lines[0] + linenum;
-					texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+					texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
 				}
 
 #ifdef ESLOPE
@@ -2377,13 +2370,13 @@ static void HWR_StoreWallRange(double startfrac, double endfrac)
 				if (*rover->topheight < lowcut || *rover->bottomheight > highcut)
 					continue;
 
-				texnum = texturetranslation[sides[rover->master->sidenum[0]].midtexture];
+				texnum = R_GetTextureNum(sides[rover->master->sidenum[0]].midtexture);
 
 				if (rover->master->flags & ML_TFERLINE)
 				{
 					size_t linenum = gr_curline->linedef-gr_backsector->lines[0];
 					newline = rover->master->frontsector->lines[0] + linenum;
-					texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+					texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
 				}
 #ifdef ESLOPE //backsides
 				h  = *rover->t_slope ? P_GetZAt(*rover->t_slope, v1x, v1y) : *rover->topheight;
@@ -3111,7 +3104,7 @@ static inline void HWR_AddPolyObjectSegs(void)
 }
 
 #ifdef POLYOBJECTS_PLANES
-static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight,
+static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fixed_t fixedheight,
 									FBITFIELD blendmode, UINT8 lightlevel, lumpnum_t lumpnum, sector_t *FOFsector,
 									UINT8 alpha, extracolormap_t *planecolormap)
 {
@@ -3195,7 +3188,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
 
 	if (FOFsector != NULL)
 	{
-		if (fixedheight == FOFsector->floorheight) // it's a floor
+		if (!isceiling) // it's a floor
 		{
 			scrollx = FIXED_TO_FLOAT(FOFsector->floor_xoffs)/fflatsize;
 			scrolly = FIXED_TO_FLOAT(FOFsector->floor_yoffs)/fflatsize;
@@ -3210,7 +3203,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, fixed_t fixedheight
 	}
 	else if (gr_frontsector)
 	{
-		if (fixedheight < dup_viewz) // it's a floor
+		if (!isceiling) // it's a floor
 		{
 			scrollx = FIXED_TO_FLOAT(gr_frontsector->floor_xoffs)/fflatsize;
 			scrolly = FIXED_TO_FLOAT(gr_frontsector->floor_yoffs)/fflatsize;
@@ -3303,13 +3296,13 @@ static void HWR_AddPolyObjectPlanes(void)
 			{
 				FSurfaceInfo Surf;
 				FBITFIELD blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
-				HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], polyobjsector->floorheight,
+				HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->floorpic].lumpnum, po_ptrs[i], false, polyobjsector->floorheight,
 													polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
 			}
 			else
 			{
 				HWR_GetFlat(levelflats[polyobjsector->floorpic].lumpnum);
-				HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->floorheight, PF_Occlude,
+				HWR_RenderPolyObjectPlane(po_ptrs[i], false, polyobjsector->floorheight, PF_Occlude,
 										polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
 										polyobjsector, 255, NULL);
 			}
@@ -3325,13 +3318,13 @@ static void HWR_AddPolyObjectPlanes(void)
 				FBITFIELD blendmode;
 				memset(&Surf, 0x00, sizeof(Surf));
 				blendmode = HWR_TranstableToAlpha(po_ptrs[i]->translucency, &Surf);
-				HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], polyobjsector->ceilingheight,
+				HWR_AddTransparentPolyobjectFloor(levelflats[polyobjsector->ceilingpic].lumpnum, po_ptrs[i], true, polyobjsector->ceilingheight,
 				                                  polyobjsector->lightlevel, Surf.FlatColor.s.alpha, polyobjsector, blendmode, NULL);
 			}
 			else
 			{
 				HWR_GetFlat(levelflats[polyobjsector->ceilingpic].lumpnum);
-				HWR_RenderPolyObjectPlane(po_ptrs[i], polyobjsector->ceilingheight, PF_Occlude,
+				HWR_RenderPolyObjectPlane(po_ptrs[i], true, polyobjsector->ceilingheight, PF_Occlude,
 				                          polyobjsector->lightlevel, levelflats[polyobjsector->floorpic].lumpnum,
 				                          polyobjsector, 255, NULL);
 			}
@@ -3485,7 +3478,7 @@ static void HWR_Subsector(size_t num)
 			if (sub->validcount != validcount)
 			{
 				HWR_GetFlat(levelflats[gr_frontsector->floorpic].lumpnum);
-				HWR_RenderPlane(gr_frontsector, &extrasubsectors[num],
+				HWR_RenderPlane(gr_frontsector, &extrasubsectors[num], false,
 					// Hack to make things continue to work around slopes.
 					locFloorHeight == cullFloorHeight ? locFloorHeight : gr_frontsector->floorheight,
 					// We now return you to your regularly scheduled rendering.
@@ -3507,7 +3500,7 @@ static void HWR_Subsector(size_t num)
 			if (sub->validcount != validcount)
 			{
 				HWR_GetFlat(levelflats[gr_frontsector->ceilingpic].lumpnum);
-				HWR_RenderPlane(NULL, &extrasubsectors[num],
+				HWR_RenderPlane(NULL, &extrasubsectors[num], true,
 					// Hack to make things continue to work around slopes.
 					locCeilingHeight == cullCeilingHeight ? locCeilingHeight : gr_frontsector->ceilingheight,
 					// We now return you to your regularly scheduled rendering.
@@ -3576,6 +3569,7 @@ static void HWR_Subsector(size_t num)
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
+										   false,
 					                       *rover->bottomheight,
 					                       *gr_frontsector->lightlist[light].lightlevel,
 					                       alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
@@ -3593,6 +3587,7 @@ static void HWR_Subsector(size_t num)
 #else
 					HWR_AddTransparentFloor(levelflats[*rover->bottompic].lumpnum,
 					                       &extrasubsectors[num],
+										   false,
 					                       *rover->bottomheight,
 					                       *gr_frontsector->lightlist[light].lightlevel,
 					                       rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
@@ -3603,7 +3598,7 @@ static void HWR_Subsector(size_t num)
 				{
 					HWR_GetFlat(levelflats[*rover->bottompic].lumpnum);
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
-					HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
+					HWR_RenderPlane(NULL, &extrasubsectors[num], false, *rover->bottomheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->bottompic].lumpnum,
 					                rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
 				}
 			}
@@ -3637,6 +3632,7 @@ static void HWR_Subsector(size_t num)
 
 					HWR_AddTransparentFloor(0,
 					                       &extrasubsectors[num],
+										   true,
 					                       *rover->topheight,
 					                       *gr_frontsector->lightlist[light].lightlevel,
 					                       alpha, rover->master->frontsector, PF_Translucent|PF_NoTexture,
@@ -3654,6 +3650,7 @@ static void HWR_Subsector(size_t num)
 #else
 					HWR_AddTransparentFloor(levelflats[*rover->toppic].lumpnum,
 					                        &extrasubsectors[num],
+											true,
 					                        *rover->topheight,
 					                        *gr_frontsector->lightlist[light].lightlevel,
 					                        rover->alpha-1 > 255 ? 255 : rover->alpha-1, rover->master->frontsector, PF_Translucent,
@@ -3665,7 +3662,7 @@ static void HWR_Subsector(size_t num)
 				{
 					HWR_GetFlat(levelflats[*rover->toppic].lumpnum);
 					light = R_GetPlaneLight(gr_frontsector, centerHeight, dup_viewz < cullHeight ? true : false);
-					HWR_RenderPlane(NULL, &extrasubsectors[num], *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
+					HWR_RenderPlane(NULL, &extrasubsectors[num], true, *rover->topheight, PF_Occlude, *gr_frontsector->lightlist[light].lightlevel, levelflats[*rover->toppic].lumpnum,
 					                  rover->master->frontsector, 255, false, gr_frontsector->lightlist[light].extra_colormap);
 				}
 			}
@@ -3725,6 +3722,9 @@ static void HWR_Subsector(size_t num)
 
 		while (count--)
 		{
+#ifdef POLYOBJECTS
+				if (!line->polyseg) // ignore segs that belong to polyobjects
+#endif
 				HWR_AddLine(line);
 				line++;
 		}
@@ -4408,7 +4408,6 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 	FOutVector *wv;
 	GLPatch_t *gpatch; // sprite patch converted to hardware
 	FSurfaceInfo Surf;
-	sector_t *sector;
 
 	if (!spr->mobj)
 		return;
@@ -4462,19 +4461,38 @@ static inline void HWR_DrawPrecipitationSprite(gr_vissprite_t *spr)
 	//Hurdler: 25/04/2000: now support colormap in hardware mode
 	HWR_GetMappedPatch(gpatch, spr->colormap);
 
-	sector = spr->mobj->subsector->sector;
-
-	if (sector->ffloors)
+	// colormap test
 	{
-		ffloor_t *caster = sector->lightlist[R_GetPlaneLight(sector, spr->mobj->z, false)].caster;
-		sector = caster ? &sectors[caster->secnum] : sector;
-	}
+		sector_t *sector = spr->mobj->subsector->sector;
+		UINT8 lightlevel = 255;
+		extracolormap_t *colormap = sector->extra_colormap;
 
-	// sprite lighting by modulating the RGB components
-	if (sector->extra_colormap)
-			Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,sector->extra_colormap->rgba,sector->extra_colormap->fadergba, false, false);
+		if (sector->numlights)
+		{
+			INT32 light;
+
+			light = R_GetPlaneLight(sector, spr->mobj->z + spr->mobj->height, false); // Always use the light at the top instead of whatever I was doing before
+
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = *sector->lightlist[light].lightlevel;
+
+			if (sector->lightlist[light].extra_colormap)
+				colormap = sector->lightlist[light].extra_colormap;
+		}
+		else
+		{
+			if (!(spr->mobj->frame & FF_FULLBRIGHT))
+				lightlevel = sector->lightlevel;
+
+			if (sector->extra_colormap)
+				colormap = sector->extra_colormap;
+		}
+
+		if (colormap)
+			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, colormap->rgba, colormap->fadergba, false, false);
 		else
-			Surf.FlatColor.rgba = HWR_Lighting(spr->sectorlight,NORMALFOG,FADEFOG, false, false);
+			Surf.FlatColor.rgba = HWR_Lighting(lightlevel, NORMALFOG, FADEFOG, false, false);
+	}
 
 	if (spr->mobj->flags2 & MF2_SHADOW)
 	{
@@ -4508,8 +4526,8 @@ static void HWR_SortVisSprites(void)
 	gr_vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
 	gr_vissprite_t *best = NULL;
 	gr_vissprite_t unsorted;
-	float bestdist;
-	INT32 bestdispoffset;
+	float bestdist = 0.0f;
+	INT32 bestdispoffset = 0;
 
 	if (!gr_visspritecount)
 		return;
@@ -4529,7 +4547,8 @@ static void HWR_SortVisSprites(void)
 	// Fix first and last. ds still points to the last one after the loop
 	dsfirst->prev = &unsorted;
 	unsorted.next = dsfirst;
-	ds->next = &unsorted;
+	if (ds)
+		ds->next = &unsorted;
 	unsorted.prev = ds;
 
 	// pull the vissprites out by scale
@@ -4552,10 +4571,13 @@ static void HWR_SortVisSprites(void)
 				best = ds;
 			}
 		}
-		best->next->prev = best->prev;
-		best->prev->next = best->next;
-		best->next = &gr_vsprsortedhead;
-		best->prev = gr_vsprsortedhead.prev;
+		if (best)
+		{
+			best->next->prev = best->prev;
+			best->prev->next = best->next;
+			best->next = &gr_vsprsortedhead;
+			best->prev = gr_vsprsortedhead.prev;
+		}
 		gr_vsprsortedhead.prev->next = best;
 		gr_vsprsortedhead.prev = best;
 	}
@@ -4588,6 +4610,7 @@ static void HWR_RenderWall(wallVert3D   *wallVerts, FSurfaceInfo *pSurf, FBITFIE
 typedef struct
 {
 	extrasubsector_t *xsub;
+	boolean isceiling;
 	fixed_t fixedheight;
 	INT32 lightlevel;
 	lumpnum_t lumpnum;
@@ -4605,6 +4628,7 @@ static planeinfo_t *planeinfo = NULL;
 typedef struct
 {
 	polyobj_t *polysector;
+	boolean isceiling;
 	fixed_t fixedheight;
 	INT32 lightlevel;
 	lumpnum_t lumpnum;
@@ -4640,7 +4664,7 @@ static INT32 drawcount = 0;
 #define MAX_TRANSPARENTFLOOR 512
 
 // This will likely turn into a copy of HWR_Add3DWater and replace it.
-void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
+void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub, boolean isceiling,
 	fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, boolean fogplane, extracolormap_t *planecolormap)
 {
 	static size_t allocedplanes = 0;
@@ -4655,6 +4679,7 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
 		Z_Realloc(planeinfo, allocedplanes * sizeof (*planeinfo), PU_LEVEL, &planeinfo);
 	}
 
+	planeinfo[numplanes].isceiling = isceiling;
 	planeinfo[numplanes].fixedheight = fixedheight;
 	planeinfo[numplanes].lightlevel = lightlevel;
 	planeinfo[numplanes].lumpnum = lumpnum;
@@ -4665,12 +4690,13 @@ void HWR_AddTransparentFloor(lumpnum_t lumpnum, extrasubsector_t *xsub,
 	planeinfo[numplanes].fogplane = fogplane;
 	planeinfo[numplanes].planecolormap = planecolormap;
 	planeinfo[numplanes].drawcount = drawcount++;
+
 	numplanes++;
 }
 
 // Adding this for now until I can create extrasubsector info for polyobjects
 // When that happens it'll just be done through HWR_AddTransparentFloor and HWR_RenderPlane
-void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
+void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector, boolean isceiling,
 	fixed_t fixedheight, INT32 lightlevel, INT32 alpha, sector_t *FOFSector, FBITFIELD blend, extracolormap_t *planecolormap)
 {
 	static size_t allocedpolyplanes = 0;
@@ -4685,6 +4711,7 @@ void HWR_AddTransparentPolyobjectFloor(lumpnum_t lumpnum, polyobj_t *polysector,
 		Z_Realloc(polyplaneinfo, allocedpolyplanes * sizeof (*polyplaneinfo), PU_LEVEL, &polyplaneinfo);
 	}
 
+	polyplaneinfo[numpolyplanes].isceiling = isceiling;
 	polyplaneinfo[numpolyplanes].fixedheight = fixedheight;
 	polyplaneinfo[numpolyplanes].lightlevel = lightlevel;
 	polyplaneinfo[numpolyplanes].lumpnum = lumpnum;
@@ -4850,7 +4877,7 @@ static void HWR_CreateDrawNodes(void)
 
 			if (!(sortnode[sortindex[i]].plane->blend & PF_NoTexture))
 				HWR_GetFlat(sortnode[sortindex[i]].plane->lumpnum);
-			HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
+			HWR_RenderPlane(NULL, sortnode[sortindex[i]].plane->xsub, sortnode[sortindex[i]].plane->isceiling, sortnode[sortindex[i]].plane->fixedheight, sortnode[sortindex[i]].plane->blend, sortnode[sortindex[i]].plane->lightlevel,
 				sortnode[sortindex[i]].plane->lumpnum, sortnode[sortindex[i]].plane->FOFSector, sortnode[sortindex[i]].plane->alpha, sortnode[sortindex[i]].plane->fogplane, sortnode[sortindex[i]].plane->planecolormap);
 		}
 		else if (sortnode[sortindex[i]].polyplane)
@@ -4860,7 +4887,7 @@ static void HWR_CreateDrawNodes(void)
 
 			if (!(sortnode[sortindex[i]].polyplane->blend & PF_NoTexture))
 				HWR_GetFlat(sortnode[sortindex[i]].polyplane->lumpnum);
-			HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
+			HWR_RenderPolyObjectPlane(sortnode[sortindex[i]].polyplane->polysector, sortnode[sortindex[i]].polyplane->isceiling, sortnode[sortindex[i]].polyplane->fixedheight, sortnode[sortindex[i]].polyplane->blend, sortnode[sortindex[i]].polyplane->lightlevel,
 				sortnode[sortindex[i]].polyplane->lumpnum, sortnode[sortindex[i]].polyplane->FOFSector, sortnode[sortindex[i]].polyplane->alpha, sortnode[sortindex[i]].polyplane->planecolormap);
 		}
 		else if (sortnode[sortindex[i]].wall)
@@ -5287,6 +5314,11 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 	//
 	vis = HWR_NewVisSprite();
 	vis->x1 = x1;
+#if 0
+	vis->x2 = x2;
+#else
+	(void)x2;
+#endif
 	vis->x2 = tx;
 	vis->tz = tz;
 	vis->dispoffset = 0; // Monster Iestyn: 23/11/15: HARDWARE SUPPORT AT LAST
@@ -5299,7 +5331,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
 	// set top/bottom coords
 	vis->ty = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset) - gr_viewz;
 
-	vis->sectorlight = 0xff;
 	vis->precip = true;
 }
 #endif
@@ -6157,7 +6188,7 @@ static void HWR_Render3DWater(void)
 	for (i = 0; i < numfloors; i++)
 	{
 		HWR_GetFlat(planeinfo[i].lumpnum);
-		HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
+		HWR_RenderPlane(NULL, planeinfo[i].xsub, planeinfo[i].isceiling, planeinfo[i].fixedheight, PF_Translucent, planeinfo[i].lightlevel, planeinfo[i].lumpnum,
 			planeinfo[i].FOFSector, planeinfo[i].alpha, planeinfo[i].fogplane, planeinfo[i].planecolormap);
 	}
 	numfloors = 0;
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 8e48ec110388c6f3082b7a0b928a7b83c58af81b..4ec2e346a54b227f806ecf210e84085cc16e1a4e 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -308,6 +308,23 @@ static md2_model_t *md2_readModel(const char *filename)
 
 	model->header.numSkins = 1;
 
+#define MD2LIMITCHECK(field, max, msgname) \
+	if (field > max) \
+	{ \
+		CONS_Alert(CONS_ERROR, "md2_readModel: %s has too many " msgname " (# found: %d, maximum: %d)\n", filename, field, max); \
+		md2_freeModel (model); \
+		return 0; \
+	}
+
+	// Uncomment if these are actually needed
+//	MD2LIMITCHECK(model->header.numSkins,     MD2_MAX_SKINS,     "skins")
+//	MD2LIMITCHECK(model->header.numTexCoords, MD2_MAX_TEXCOORDS, "texture coordinates")
+	MD2LIMITCHECK(model->header.numTriangles, MD2_MAX_TRIANGLES, "triangles")
+	MD2LIMITCHECK(model->header.numFrames,    MD2_MAX_FRAMES,    "frames")
+	MD2LIMITCHECK(model->header.numVertices,  MD2_MAX_VERTICES,  "vertices")
+
+#undef MD2LIMITCHECK
+
 	// read skins
 	fseek(file, model->header.offsetSkins, SEEK_SET);
 	if (model->header.numSkins > 0)
@@ -319,8 +336,6 @@ static md2_model_t *md2_readModel(const char *filename)
 			md2_freeModel (model);
 			return 0;
 		}
-
-		;
 	}
 
 	// read texture coordinates
@@ -334,8 +349,6 @@ static md2_model_t *md2_readModel(const char *filename)
 			md2_freeModel (model);
 			return 0;
 		}
-
-
 	}
 
 	// read triangles
@@ -769,6 +782,7 @@ void HWR_InitMD2(void)
 		md2_playermodels[s].grpatch = NULL;
 		md2_playermodels[s].skin = -1;
 		md2_playermodels[s].notfound = true;
+		md2_playermodels[s].error = false;
 	}
 	for (i = 0; i < NUMSPRITES; i++)
 	{
@@ -777,6 +791,7 @@ void HWR_InitMD2(void)
 		md2_models[i].grpatch = NULL;
 		md2_models[i].skin = -1;
 		md2_models[i].notfound = true;
+		md2_models[i].error = false;
 	}
 
 	// read the md2.dat file
@@ -1269,6 +1284,8 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		else
 			md2 = &md2_models[spr->mobj->sprite];
 
+		if (md2->error)
+			return; // we already failed loading this before :(
 		if (!md2->model)
 		{
 			//CONS_Debug(DBG_RENDER, "Loading MD2... (%s)", sprnames[spr->mobj->sprite]);
@@ -1282,6 +1299,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 			else
 			{
 				//CONS_Debug(DBG_RENDER, " FAILED\n");
+				md2->error = true; // prevent endless fail
 				return;
 			}
 		}
diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h
index 36078268b50d590114e5025833b0197b0c3a0b19..5a7e6d2b3cdaf0c3ae7d5813e835d5cf8711403e 100644
--- a/src/hardware/hw_md2.h
+++ b/src/hardware/hw_md2.h
@@ -123,6 +123,7 @@ typedef struct
 	void        *blendgrpatch;
 	boolean     notfound;
 	INT32       skin;
+	boolean     error;
 } md2_t;
 
 extern md2_t md2_models[NUMSPRITES];
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index 1a81fe796251a5a40ef213e30bb4b01a8f3a205f..e6ff83e89698439c947fb7b73833e551c55387fd 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -244,6 +244,7 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 #define pglMaterialfv glMaterialfv
 
 /* Raster functions */
+#define pglPixelStorei glPixelStorei
 #define pglReadPixels glReadPixels
 
 /* Texture mapping */
@@ -262,15 +263,8 @@ FUNCPRINTF void DBG_Printf(const char *lpFmt, ...)
 /* texture mapping */ //GL_EXT_copy_texture
 #ifndef KOS_GL_COMPATIBILITY
 #define pglCopyTexImage2D glCopyTexImage2D
-
-/* GLU functions */
-#define pgluBuild2DMipmaps gluBuild2DMipmaps
-#endif
-#ifndef MINI_GL_COMPATIBILITY
-/* 1.3 functions for multitexturing */
-#define pglActiveTexture glActiveTexture
-#define pglMultiTexCoord2f glMultiTexCoord2f
 #endif
+
 #else //!STATIC_OPENGL
 
 /* 1.0 functions */
@@ -365,6 +359,8 @@ typedef void (APIENTRY * PFNglMaterialfv) (GLint face, GLenum pname, GLfloat *pa
 static PFNglMaterialfv pglMaterialfv;
 
 /* Raster functions */
+typedef void (APIENTRY * PFNglPixelStorei) (GLenum pname, GLint param);
+static PFNglPixelStorei pglPixelStorei;
 typedef void (APIENTRY  * PFNglReadPixels) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
 static PFNglReadPixels pglReadPixels;
 
@@ -391,7 +387,7 @@ static PFNglBindTexture pglBindTexture;
 /* texture mapping */ //GL_EXT_copy_texture
 typedef void (APIENTRY * PFNglCopyTexImage2D) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
 static PFNglCopyTexImage2D pglCopyTexImage2D;
-
+#endif
 /* GLU functions */
 typedef GLint (APIENTRY * PFNgluBuild2DMipmaps) (GLenum target, GLint internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *data);
 static PFNgluBuild2DMipmaps pgluBuild2DMipmaps;
@@ -403,7 +399,6 @@ static PFNglActiveTexture pglActiveTexture;
 typedef void (APIENTRY *PFNglMultiTexCoord2f) (GLenum, GLfloat, GLfloat);
 static PFNglMultiTexCoord2f pglMultiTexCoord2f;
 #endif
-#endif
 
 #ifndef MINI_GL_COMPATIBILITY
 /* 1.2 Parms */
@@ -494,6 +489,7 @@ boolean SetupGLfunc(void)
 	GETOPENGLFUNC(pglLightModelfv , glLightModelfv)
 	GETOPENGLFUNC(pglMaterialfv , glMaterialfv)
 
+	GETOPENGLFUNC(pglPixelStorei , glPixelStorei)
 	GETOPENGLFUNC(pglReadPixels , glReadPixels)
 
 	GETOPENGLFUNC(pglTexEnvi , glTexEnvi)
@@ -519,35 +515,23 @@ boolean SetupGLfunc(void)
 // This has to be done after the context is created so the version number can be obtained
 boolean SetupGLFunc13(void)
 {
-	const GLubyte *version = pglGetString(GL_VERSION);
-	int glmajor, glminor;
-
-	gl13 = false;
 #ifdef MINI_GL_COMPATIBILITY
 	return false;
 #else
-#ifdef STATIC_OPENGL
-	gl13 = true;
-#else
+	const GLubyte *version = pglGetString(GL_VERSION);
+	int glmajor, glminor;
 
+	gl13 = false;
 	// Parse the GL version
 	if (version != NULL)
 	{
 		if (sscanf((const char*)version, "%d.%d", &glmajor, &glminor) == 2)
 		{
 			// Look, we gotta prepare for the inevitable arrival of GL 2.0 code...
-			switch (glmajor)
-			{
-				case 1:
-					if (glminor == 3) gl13 = true;
-					break;
-				case 2:
-				case 3:
-				case 4:
-					gl13 = true;
-				default:
-					break;
-			}
+			if (glmajor == 1 && glminor >= 3)
+				gl13 = true;
+			else if (glmajor > 1)
+				gl13 = true;
 		}
 	}
 
@@ -568,9 +552,6 @@ boolean SetupGLFunc13(void)
 	}
 	else
 		DBG_Printf("GL_ARB_multitexture support: disabled\n");
-#undef GETOPENGLFUNC
-
-#endif
 	return true;
 #endif
 }
@@ -897,7 +878,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
 		GLubyte*top = (GLvoid*)dst_data, *bottom = top + dst_stride * (height - 1);
 		GLubyte *row = malloc(dst_stride);
 		if (!row) return;
+		pglPixelStorei(GL_PACK_ALIGNMENT, 1);
 		pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, dst_data);
+		pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 		for(i = 0; i < height/2; i++)
 		{
 			memcpy(row, top, dst_stride);
@@ -913,7 +896,9 @@ EXPORT void HWRAPI(ReadRect) (INT32 x, INT32 y, INT32 width, INT32 height,
 		INT32 j;
 		GLubyte *image = malloc(width*height*3*sizeof (*image));
 		if (!image) return;
+		pglPixelStorei(GL_PACK_ALIGNMENT, 1);
 		pglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, image);
+		pglPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 		for (i = height-1; i >= 0; i--)
 		{
 			for (j = 0; j < width; j++)
@@ -1815,13 +1800,11 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
 					min_filter = GL_NEAREST;
 #endif
 			}
-#ifndef STATIC_OPENGL
 			if (!pgluBuild2DMipmaps)
 			{
 				MipMap = GL_FALSE;
 				min_filter = GL_LINEAR;
 			}
-#endif
 			Flush(); //??? if we want to change filter mode by texture, remove this
 			break;
 
@@ -1836,10 +1819,7 @@ EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value)
 	}
 }
 
-// -----------------+
-// HWRAPI DrawMD2   : Draw an MD2 model with glcommands
-// -----------------+
-EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
+static  void DrawMD2Ex(INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
 {
 	INT32     val, count, pindex;
 	GLfloat s, t;
@@ -1931,7 +1911,7 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
 	//pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
 
 	// Remove depth mask when the model is transparent so it doesn't cut thorugh sprites // SRB2CBTODO: For all stuff too?!
-	if (color[3] < 255)
+	if (color && color[3] < 255)
 	{
 		pglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // alpha = level of transparency
 		pglDepthMask(GL_FALSE);
@@ -2007,11 +1987,20 @@ EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 d
 	pglDisable(GL_CULL_FACE);
 }
 
+// -----------------+
+// HWRAPI DrawMD2   : Draw an MD2 model with glcommands
+// -----------------+
+EXPORT void HWRAPI(DrawMD2i) (INT32 *gl_cmd_buffer, md2_frame_t *frame, UINT32 duration, UINT32 tics, md2_frame_t *nextframe, FTransform *pos, float scale, UINT8 flipped, UINT8 *color)
+{
+	DrawMD2Ex(gl_cmd_buffer, frame, duration, tics,  nextframe, pos, scale, flipped, color);
+}
+
 EXPORT void HWRAPI(DrawMD2) (INT32 *gl_cmd_buffer, md2_frame_t *frame, FTransform *pos, float scale)
 {
-	DrawMD2i(gl_cmd_buffer, frame, 0, 0,  NULL, pos, scale, false, NULL);
+	DrawMD2Ex(gl_cmd_buffer, frame, 0, 0,  NULL, pos, scale, false, NULL);
 }
 
+
 // -----------------+
 // SetTransform     :
 // -----------------+
diff --git a/src/hu_stuff.c b/src/hu_stuff.c
index ec747305ea5b1cac5201ef425bd0d2f520b8c0c0..646bdcbad6d0ba9299fea195e735a67c3f9d22c9 100644
--- a/src/hu_stuff.c
+++ b/src/hu_stuff.c
@@ -470,7 +470,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
 	boolean action = false;
 	char *ptr;
 
-	CONS_Debug(DBG_NETPLAY,"Recieved SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
+	CONS_Debug(DBG_NETPLAY,"Received SAY cmd from Player %d (%s)\n", playernum+1, player_names[playernum]);
 
 	target = READSINT8(*p);
 	flags = READUINT8(*p);
@@ -757,15 +757,8 @@ void HU_clearChatChars(void)
 //
 boolean HU_Responder(event_t *ev)
 {
-	static boolean shiftdown = false;
 	UINT8 c;
 
-	if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT)
-	{
-		shiftdown = (ev->type == ev_keydown);
-		return chat_on;
-	}
-
 	if (ev->type != ev_keydown)
 		return false;
 
@@ -797,6 +790,14 @@ boolean HU_Responder(event_t *ev)
 	}
 	else // if chat_on
 	{
+		// Ignore modifier keys
+		// Note that we do this here so users can still set
+		// their chat keys to one of these, if they so desire.
+		if (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT
+		 || ev->data1 == KEY_LCTRL || ev->data1 == KEY_RCTRL
+		 || ev->data1 == KEY_LALT || ev->data1 == KEY_RALT)
+			return true;
+
 		c = (UINT8)ev->data1;
 
 		// use console translations
@@ -1101,7 +1102,19 @@ void HU_Drawer(void)
 
 	// draw desynch text
 	if (hu_resynching)
-		V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP, "Resynching...");
+	{
+		static UINT32 resynch_ticker = 0;
+		char resynch_text[14];
+		UINT32 i;
+
+		// Animate the dots
+		resynch_ticker++;
+		strcpy(resynch_text, "Resynching");
+		for (i = 0; i < (resynch_ticker / 16) % 4; i++)
+			strcat(resynch_text, ".");
+
+		V_DrawCenteredString(BASEVIDWIDTH/2, 180, V_YELLOWMAP | V_ALLOWLOWERCASE, resynch_text);
+	}
 }
 
 //======================================================================
diff --git a/src/hu_stuff.h b/src/hu_stuff.h
index f0dd400960251a40eed43a916db11e879ba6457c..7b22f33f189b5a602ca043862b21ca2e8cc0d678 100644
--- a/src/hu_stuff.h
+++ b/src/hu_stuff.h
@@ -87,7 +87,7 @@ void HU_Init(void);
 void HU_LoadGraphics(void);
 
 // reset heads up when consoleplayer respawns.
-void HU_Start(void);
+FUNCMATH void HU_Start(void);
 
 boolean HU_Responder(event_t *ev);
 
diff --git a/src/i_net.h b/src/i_net.h
index e378f5723bffd37c33398120c040ecc771fdc876..2bfa5eac7d14a1f567a99f406aaec5afdcee23d7 100644
--- a/src/i_net.h
+++ b/src/i_net.h
@@ -85,7 +85,7 @@ extern doomcom_t *doomcom;
 
 /**	\brief return packet in doomcom struct
 */
-extern void (*I_NetGet)(void);
+extern boolean (*I_NetGet)(void);
 
 /**	\brief ask to driver if there is data waiting
 */
diff --git a/src/i_system.h b/src/i_system.h
index c161851e05ce93c6c460da4575f1c14f8dc5bbc4..d61f2d16e7730c8516b556d3d1f9705e5fb565fc 100644
--- a/src/i_system.h
+++ b/src/i_system.h
@@ -296,6 +296,14 @@ char *I_GetEnv(const char *name);
 
 INT32 I_PutEnv(char *variable);
 
+/** \brief Put data in system clipboard
+*/
+INT32 I_ClipboardCopy(const char *data, size_t size);
+
+/** \brief Retrieve data from system clipboard
+*/
+const char *I_ClipboardPaste(void);
+
 void I_RegisterSysCommands(void);
 
 #endif
diff --git a/src/i_tcp.c b/src/i_tcp.c
index eca218c804dde4eabf59963d6a752d2c3aed0fa6..c65a536a8577bef3e132b15d4eaab4ad6aa4374f 100644
--- a/src/i_tcp.c
+++ b/src/i_tcp.c
@@ -56,7 +56,9 @@
 //#define NONET
 #endif
 
-#ifndef NONET
+#ifdef NONET
+#undef HAVE_MINIUPNPC
+#else
 #ifdef USE_WINSOCK1
 #include <winsock.h>
 #elif !defined (SCOUW2) && !defined (SCOUW7) && !defined (__OS2__)
@@ -177,6 +179,7 @@ static UINT8 UPNP_support = TRUE;
 #include "i_system.h"
 #include "i_net.h"
 #include "d_net.h"
+#include "d_netfil.h"
 #include "i_tcp.h"
 #include "m_argv.h"
 
@@ -480,37 +483,96 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
 		return false;
 }
 
+// This is a hack. For some reason, nodes aren't being freed properly.
+// This goes through and cleans up what nodes were supposed to be freed.
+/** \warning This function causes the file downloading to stop if someone joins.
+  *          How? Because it removes nodes that are connected but not in game,
+  *          which is exactly what clients downloading a file are.
+  */
+static void cleanupnodes(void)
+{
+	SINT8 j;
+
+	if (!Playing())
+		return;
+
+	// Why can't I start at zero?
+	for (j = 1; j < MAXNETNODES; j++)
+		//if (!(nodeingame[j] || SV_SendingFile(j)))
+		if (!nodeingame[j])
+			nodeconnected[j] = false;
+}
+
 static SINT8 getfreenode(void)
 {
 	SINT8 j;
 
+	cleanupnodes();
+
 	for (j = 0; j < MAXNETNODES; j++)
 		if (!nodeconnected[j])
 		{
 			nodeconnected[j] = true;
 			return j;
 		}
+
+	/** \warning No free node? Just in case a node might not have been freed properly,
+	  *          look if there are connected nodes that aren't in game, and forget them.
+	  *          It's dirty, and might result in a poor guy having to restart
+	  *          downloading a needed wad, but it's better than not letting anyone join...
+	  */
+	/*I_Error("No more free nodes!!1!11!11!!1111\n");
+	for (j = 1; j < MAXNETNODES; j++)
+		if (!nodeingame[j])
+			return j;*/
+
 	return -1;
 }
 
-// This is a hack. For some reason, nodes aren't being freed properly.
-// This goes through and cleans up what nodes were supposed to be freed.
-static void cleanupnodes(void)
+#ifdef _DEBUG
+void Command_Numnodes(void)
 {
-	SINT8 j;
+	INT32 connected = 0;
+	INT32 ingame = 0;
+	INT32 i;
 
-	if (!Playing())
-		return;
+	for (i = 1; i < MAXNETNODES; i++)
+	{
+		if (!(nodeconnected[i] || nodeingame[i]))
+			continue;
 
-	// Why can't I start at zero?
-	for (j = 1; j < MAXNETNODES; j++)
-		if (!nodeingame[j])
-			nodeconnected[j] = false;
+		if (nodeconnected[i])
+			connected++;
+		if (nodeingame[i])
+			ingame++;
+
+		CONS_Printf("%2d - ", i);
+		if (nodetoplayer[i] != -1)
+			CONS_Printf("player %.2d", nodetoplayer[i]);
+		else
+			CONS_Printf("         ");
+		if (nodeconnected[i])
+			CONS_Printf(" - connected");
+		else
+			CONS_Printf(" -          ");
+		if (nodeingame[i])
+			CONS_Printf(" - ingame");
+		else
+			CONS_Printf(" -       ");
+		CONS_Printf(" - %s\n", I_GetNodeAddress(i));
+	}
+
+	CONS_Printf("\n"
+				"Connected: %d\n"
+				"Ingame:    %d\n",
+				connected, ingame);
 }
 #endif
+#endif
 
 #ifndef NONET
-static void SOCK_Get(void)
+// Returns true if a packet was received from a new node, false in all other cases
+static boolean SOCK_Get(void)
 {
 	size_t i, n;
 	int j;
@@ -533,13 +595,12 @@ static void SOCK_Get(void)
 					doomcom->remotenode = (INT16)j; // good packet from a game player
 					doomcom->datalength = (INT16)c;
 					nodesocket[j] = mysockets[n];
-					return;
+					return false;
 				}
 			}
 			// not found
 
 			// find a free slot
-			cleanupnodes();
 			j = getfreenode();
 			if (j > 0)
 			{
@@ -562,14 +623,15 @@ static void SOCK_Get(void)
 				}
 				if (i == numbans)
 					SOCK_bannednode[j] = false;
-				return;
+				return true;
 			}
 			else
 				DEBFILE("New node detected: No more free slots\n");
-
 		}
 	}
+
 	doomcom->remotenode = -1; // no packet
+	return false;
 }
 #endif
 
@@ -1254,7 +1316,6 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
 	gaie = I_getaddrinfo(address, port, &hints, &ai);
 	if (gaie == 0)
 	{
-		cleanupnodes();
 		newnode = getfreenode();
 	}
 	if (newnode == -1)
diff --git a/src/lua_baselib.c b/src/lua_baselib.c
index 7678c7c49c26c150caac4623934b0916bde090b5..e8e8fd02044320e495d11d00310a5ee292b9b625 100644
--- a/src/lua_baselib.c
+++ b/src/lua_baselib.c
@@ -437,6 +437,16 @@ static int lib_pMobjFlip(lua_State *L)
 	return 1;
 }
 
+static int lib_pGetMobjGravity(lua_State *L)
+{
+	mobj_t *mobj = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
+	//HUDSAFE
+	if (!mobj)
+		return LUA_ErrInvalid(L, "mobj_t");
+	lua_pushfixed(L, P_GetMobjGravity(mobj));
+	return 1;
+}
+
 static int lib_pWeaponOrPanel(lua_State *L)
 {
 	mobjtype_t type = luaL_checkinteger(L, 1);
@@ -2008,6 +2018,7 @@ static luaL_Reg lib[] = {
 	{"P_SPMAngle",lib_pSPMAngle},
 	{"P_SpawnPlayerMissile",lib_pSpawnPlayerMissile},
 	{"P_MobjFlip",lib_pMobjFlip},
+	{"P_GetMobjGravity",lib_pGetMobjGravity},
 	{"P_WeaponOrPanel",lib_pWeaponOrPanel},
 	{"P_FlashPal",lib_pFlashPal},
 	{"P_GetClosestAxis",lib_pGetClosestAxis},
diff --git a/src/lua_hook.h b/src/lua_hook.h
index 804d99e12e5728a49015829644b6b827ce649613..53e0a7d8e8bf2eb402ed50c62e89bb49704bdec8 100644
--- a/src/lua_hook.h
+++ b/src/lua_hook.h
@@ -60,7 +60,7 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which);
 #define LUAh_MobjMoveCollide(thing1, thing2) LUAh_MobjCollideHook(thing1, thing2, hook_MobjMoveCollide) // Hook for PIT_CheckThing by (tmthing) mobj type
 boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher); // Hook for P_TouchSpecialThing by mobj type
 #define LUAh_MobjFuse(mo) LUAh_MobjHook(mo, hook_MobjFuse) // Hook for mobj->fuse == 0 by mobj type
-#define LUAh_MobjThinker(mo) LUAh_MobjHook(mo, hook_MobjThinker) // Hook for P_MobjThinker or P_SceneryThinker by mobj type
+boolean LUAh_MobjThinker(mobj_t *mo); // Hook for P_MobjThinker or P_SceneryThinker by mobj type
 #define LUAh_BossThinker(mo) LUAh_MobjHook(mo, hook_BossThinker) // Hook for P_GenericBossThinker by mobj type
 UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Should mobj take damage?)
 boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage); // Hook for P_DamageMobj by mobj type (Mobj actually takes damage!)
diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c
index 1b9652571164a9de45056cf62d1fc66958efa01f..a24473bad47b69fd9cf11608773357cd605efc19 100644
--- a/src/lua_hooklib.c
+++ b/src/lua_hooklib.c
@@ -74,12 +74,30 @@ typedef struct hook_s* hook_p;
 
 #define FMT_HOOKID "hook_%d"
 
+// For each mobj type, a linked list to its thinker and collision hooks.
+// That way, we don't have to iterate through all the hooks.
+// We could do that with all other mobj hooks, but it would probably just be
+// a waste of memory since they are only called occasionally. Probably...
+static hook_p mobjthinkerhooks[NUMMOBJTYPES];
+static hook_p mobjcollidehooks[NUMMOBJTYPES];
+
+// For each mobj type, a linked list for other mobj hooks
+static hook_p mobjhooks[NUMMOBJTYPES];
+
+// A linked list for player hooks
+static hook_p playerhooks;
+
+// A linked list for linedef executor hooks
+static hook_p linedefexecutorhooks;
+
+// For other hooks, a unique linked list
 hook_p roothook;
 
 // Takes hook, function, and additional arguments (mobj type to act on, etc.)
 static int lib_addHook(lua_State *L)
 {
 	static struct hook_s hook = {NULL, 0, 0, {0}, false};
+	static UINT32 nextid;
 	hook_p hookp, *lastp;
 
 	hook.type = luaL_checkoption(L, 1, NULL, hookNames);
@@ -109,6 +127,7 @@ static int lib_addHook(lua_State *L)
 		hook.s.mt = MT_NULL;
 		if (lua_isnumber(L, 2))
 			hook.s.mt = lua_tonumber(L, 2);
+		luaL_argcheck(L, hook.s.mt < NUMMOBJTYPES, 2, "invalid mobjtype_t");
 		break;
 	case hook_BotAI:
 		hook.s.skinname = NULL;
@@ -141,18 +160,49 @@ static int lib_addHook(lua_State *L)
 
 	hooksAvailable[hook.type/8] |= 1<<(hook.type%8);
 
-	// iterate the hook metadata structs
 	// set hook.id to the highest id + 1
-	// set lastp to the last hook struct's "next" pointer.
-	lastp = &roothook;
-	hook.id = 0;
-	for (hookp = roothook; hookp; hookp = hookp->next)
+	hook.id = nextid++;
+
+	// Special cases for some hook types (see the comments above mobjthinkerhooks declaration)
+	switch(hook.type)
 	{
-		if (hookp->id >= hook.id)
-			hook.id = hookp->id+1;
-		lastp = &hookp->next;
+	case hook_MobjThinker:
+		lastp = &mobjthinkerhooks[hook.s.mt];
+		break;
+	case hook_MobjCollide:
+	case hook_MobjMoveCollide:
+		lastp = &mobjcollidehooks[hook.s.mt];
+		break;
+	case hook_MobjSpawn:
+	case hook_TouchSpecial:
+	case hook_MobjFuse:
+	case hook_BossThinker:
+	case hook_ShouldDamage:
+	case hook_MobjDamage:
+	case hook_MobjDeath:
+	case hook_BossDeath:
+	case hook_MobjRemoved:
+		lastp = &mobjhooks[hook.s.mt];
+		break;
+	case hook_JumpSpecial:
+	case hook_AbilitySpecial:
+	case hook_SpinSpecial:
+	case hook_JumpSpinSpecial:
+	case hook_PlayerSpawn:
+		lastp = &playerhooks;
+		break;
+	case hook_LinedefExecute:
+		lastp = &linedefexecutorhooks;
+		break;
+	default:
+		lastp = &roothook;
+		break;
 	}
 
+	// iterate the hook metadata structs
+	// set lastp to the last hook struct's "next" pointer.
+	for (hookp = *lastp; hookp; hookp = hookp->next)
+		lastp = &hookp->next;
 	// allocate a permanent memory struct to stuff hook.
 	hookp = ZZ_Alloc(sizeof(struct hook_s));
 	memcpy(hookp, &hook, sizeof(struct hook_s));
@@ -183,9 +233,29 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == which
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == mo->type))
+	// Look for all generic mobj hooks
+	for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == which)
+		{
+			if (lua_gettop(gL) == 0)
+				LUA_PushUserdata(gL, mo, META_MOBJ);
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -2);
+			if (lua_pcall(gL, 1, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
+		if (hookp->type == which)
 		{
 			if (lua_gettop(gL) == 0)
 				LUA_PushUserdata(gL, mo, META_MOBJ);
@@ -217,7 +287,7 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
+	for (hookp = playerhooks; hookp; hookp = hookp->next)
 		if (hookp->type == which)
 		{
 			if (lua_gettop(gL) == 0)
@@ -338,9 +408,38 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == which
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == thing1->type))
+	// Look for all generic mobj collision hooks
+	for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == which)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, thing1, META_MOBJ);
+				LUA_PushUserdata(gL, thing2, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (!lua_isnil(gL, -1))
+			{ // if nil, leave shouldCollide = 0.
+				if (lua_toboolean(gL, -1))
+					shouldCollide = 1; // Force yes
+				else
+					shouldCollide = 2; // Force no
+			}
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next)
+		if (hookp->type == which)
 		{
 			if (lua_gettop(gL) == 0)
 			{
@@ -372,6 +471,59 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
 	return shouldCollide;
 }
 
+// Hook for mobj thinkers
+boolean LUAh_MobjThinker(mobj_t *mo)
+{
+	hook_p hookp;
+	boolean hooked = false;
+	if (!gL || !(hooksAvailable[hook_MobjThinker/8] & (1<<(hook_MobjThinker%8))))
+		return false;
+
+	lua_settop(gL, 0);
+
+	// Look for all generic mobj thinker hooks
+	for (hookp = mobjthinkerhooks[MT_NULL]; hookp; hookp = hookp->next)
+	{
+		if (lua_gettop(gL) == 0)
+			LUA_PushUserdata(gL, mo, META_MOBJ);
+		lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+		lua_gettable(gL, LUA_REGISTRYINDEX);
+		lua_pushvalue(gL, -2);
+		if (lua_pcall(gL, 1, 1, 0)) {
+			if (!hookp->error || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			hookp->error = true;
+			continue;
+		}
+		if (lua_toboolean(gL, -1))
+			hooked = true;
+		lua_pop(gL, 1);
+	}
+
+	for (hookp = mobjthinkerhooks[mo->type]; hookp; hookp = hookp->next)
+	{
+		if (lua_gettop(gL) == 0)
+			LUA_PushUserdata(gL, mo, META_MOBJ);
+		lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+		lua_gettable(gL, LUA_REGISTRYINDEX);
+		lua_pushvalue(gL, -2);
+		if (lua_pcall(gL, 1, 1, 0)) {
+			if (!hookp->error || cv_debug & DBG_LUA)
+				CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+			lua_pop(gL, 1);
+			hookp->error = true;
+			continue;
+		}
+		if (lua_toboolean(gL, -1))
+			hooked = true;
+		lua_pop(gL, 1);
+	}
+
+	lua_settop(gL, 0);
+	return hooked;
+}
+
 // Hook for P_TouchSpecialThing by mobj type
 boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
 {
@@ -382,9 +534,33 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == hook_TouchSpecial
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == special->type))
+	// Look for all generic touch special hooks
+	for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_TouchSpecial)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, special, META_MOBJ);
+				LUA_PushUserdata(gL, toucher, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -3);
+			lua_pushvalue(gL, -3);
+			if (lua_pcall(gL, 2, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_TouchSpecial)
 		{
 			if (lua_gettop(gL) == 0)
 			{
@@ -421,9 +597,42 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == hook_ShouldDamage
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+	// Look for all generic should damage hooks
+	for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_ShouldDamage)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+				lua_pushinteger(gL, damage);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			if (lua_pcall(gL, 4, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (!lua_isnil(gL, -1))
+			{
+				if (lua_toboolean(gL, -1))
+					shouldDamage = 1; // Force yes
+				else
+					shouldDamage = 2; // Force no
+			}
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_ShouldDamage)
 		{
 			if (lua_gettop(gL) == 0)
 			{
@@ -469,9 +678,37 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == hook_MobjDamage
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+	// Look for all generic mobj damage hooks
+	for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDamage)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+				lua_pushinteger(gL, damage);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			lua_pushvalue(gL, -5);
+			if (lua_pcall(gL, 4, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDamage)
 		{
 			if (lua_gettop(gL) == 0)
 			{
@@ -512,9 +749,35 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == hook_MobjDeath
-		&& (hookp->s.mt == MT_NULL || hookp->s.mt == target->type))
+	// Look for all generic mobj death hooks
+	for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDeath)
+		{
+			if (lua_gettop(gL) == 0)
+			{
+				LUA_PushUserdata(gL, target, META_MOBJ);
+				LUA_PushUserdata(gL, inflictor, META_MOBJ);
+				LUA_PushUserdata(gL, source, META_MOBJ);
+			}
+			lua_pushfstring(gL, FMT_HOOKID, hookp->id);
+			lua_gettable(gL, LUA_REGISTRYINDEX);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			lua_pushvalue(gL, -4);
+			if (lua_pcall(gL, 3, 1, 0)) {
+				if (!hookp->error || cv_debug & DBG_LUA)
+					CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
+				lua_pop(gL, 1);
+				hookp->error = true;
+				continue;
+			}
+			if (lua_toboolean(gL, -1))
+				hooked = true;
+			lua_pop(gL, 1);
+		}
+
+	for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
+		if (hookp->type == hook_MobjDeath)
 		{
 			if (lua_gettop(gL) == 0)
 			{
@@ -652,9 +915,8 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
 
 	lua_settop(gL, 0);
 
-	for (hookp = roothook; hookp; hookp = hookp->next)
-		if (hookp->type == hook_LinedefExecute
-		&& !strcmp(hookp->s.funcname, line->text))
+	for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
+		if (!strcmp(hookp->s.funcname, line->text))
 		{
 			if (lua_gettop(gL) == 0)
 			{
diff --git a/src/lua_hud.h b/src/lua_hud.h
index 799ce2fbf54ca60a83b39b02ed599f16cc2cb6e4..ba0a1d8941deff4c5b19e40cae1368c19ad86b18 100644
--- a/src/lua_hud.h
+++ b/src/lua_hud.h
@@ -18,6 +18,9 @@ enum hud {
 	hud_time,
 	hud_rings,
 	hud_lives,
+	// Match / CTF / Tag / Ringslinger
+	hud_weaponrings,
+	hud_powerstones,
 	// NiGHTS mode
 	hud_nightslink,
 	hud_nightsdrill,
diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c
index 31549afa7680564d4001ae6273611ffb1c239c90..60cbbe5018f28fb657cee6ec608d275386b53411 100644
--- a/src/lua_hudlib.c
+++ b/src/lua_hudlib.c
@@ -44,6 +44,9 @@ static const char *const hud_disable_options[] = {
 	"rings",
 	"lives",
 
+	"weaponrings",
+	"powerstones",
+
 	"nightslink",
 	"nightsdrill",
 	"nightsrings",
@@ -366,6 +369,8 @@ static int libd_drawScaled(lua_State *L)
 	x = luaL_checkinteger(L, 1);
 	y = luaL_checkinteger(L, 2);
 	scale = luaL_checkinteger(L, 3);
+	if (scale < 0)
+		return luaL_error(L, "negative scale");
 	patch = *((patch_t **)luaL_checkudata(L, 4, META_PATCH));
 	flags = luaL_optinteger(L, 5, 0);
 	if (!lua_isnoneornil(L, 6))
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index c512bf3c5292cdb1030209b6aca5277fded6dd9c..208aebe37951b484b5212637f774ea837f701729 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -348,22 +348,12 @@ static int sector_get(lua_State *L)
 	case sector_ceilingheight:
 		lua_pushfixed(L, sector->ceilingheight);
 		return 1;
-	case sector_floorpic: { // floorpic
-		levelflat_t *levelflat;
-		INT16 i;
-		for (i = 0, levelflat = levelflats; i != sector->floorpic; i++, levelflat++)
-			;
-		lua_pushlstring(L, levelflat->name, 8);
+	case sector_floorpic: // floorpic
+		lua_pushlstring(L, levelflats[sector->floorpic].name, 8);
 		return 1;
-	}
-	case sector_ceilingpic: { // ceilingpic
-		levelflat_t *levelflat;
-		INT16 i;
-		for (i = 0, levelflat = levelflats; i != sector->ceilingpic; i++, levelflat++)
-			;
-		lua_pushlstring(L, levelflat->name, 8);
+	case sector_ceilingpic: // ceilingpic
+		lua_pushlstring(L, levelflats[sector->ceilingpic].name, 8);
 		return 1;
-	}
 	case sector_lightlevel:
 		lua_pushinteger(L, sector->lightlevel);
 		return 1;
@@ -400,46 +390,6 @@ static int sector_get(lua_State *L)
 	return 0;
 }
 
-// help function for P_LoadSectors, find a flat in the active wad files,
-// allocate an id for it, and set the levelflat (to speedup search)
-//
-static INT32 P_AddLevelFlatRuntime(const char *flatname)
-{
-	size_t i;
-	levelflat_t *levelflat = levelflats;
-
-	//
-	//  first scan through the already found flats
-	//
-	for (i = 0; i < numlevelflats; i++, levelflat++)
-		if (strnicmp(levelflat->name,flatname,8)==0)
-			break;
-
-	// that flat was already found in the level, return the id
-	if (i == numlevelflats)
-	{
-		// allocate new flat memory
-		levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
-		levelflat = levelflats+i;
-
-		// store the name
-		strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
-		strupr(levelflat->name);
-
-		// store the flat lump number
-		levelflat->lumpnum = R_GetFlatNumForName(flatname);
-
-#ifndef ZDEBUG
-		CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
-#endif
-
-		numlevelflats++;
-	}
-
-	// level flat id
-	return (INT32)i;
-}
-
 static int sector_set(lua_State *L)
 {
 	sector_t *sector = *((sector_t **)luaL_checkudata(L, 1, META_SECTOR));
diff --git a/src/lzf.c b/src/lzf.c
index 33a1b2dcdfc237490dbe0cce2d0a702dbab8f505..272174f30a54a6c04b64c864dff2304f57cad6cc 100644
--- a/src/lzf.c
+++ b/src/lzf.c
@@ -59,7 +59,11 @@
  * Unconditionally aligning does not cost very much, so do it if unsure
  */
 #ifndef STRICT_ALIGN
-# define STRICT_ALIGN !(defined(__i386) || defined (__amd64)) || defined (__clang__)
+#if !(defined(__i386) || defined (__amd64)) || defined (__clang__)
+#define STRICT_ALIGN 1
+#else
+#define STRICT_ALIGN 0
+#endif
 #endif
 
 /*
diff --git a/src/m_aatree.c b/src/m_aatree.c
new file mode 100644
index 0000000000000000000000000000000000000000..6cb3a32cb927aac773db7739b6a0dc6887e14294
--- /dev/null
+++ b/src/m_aatree.c
@@ -0,0 +1,167 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  m_aatree.h
+/// \brief AA trees code
+
+#include "m_aatree.h"
+#include "z_zone.h"
+
+// A partial implementation of AA trees,
+// according to the algorithms given on Wikipedia.
+// http://en.wikipedia.org/wiki/AA_tree
+
+typedef struct aatree_node_s
+{
+	INT32	level;
+	INT32	key;
+	void*	value;
+
+	struct aatree_node_s *left, *right;
+} aatree_node_t;
+
+struct aatree_s
+{
+	aatree_node_t	*root;
+	UINT32		flags;
+};
+
+aatree_t *M_AATreeAlloc(UINT32 flags)
+{
+	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
+	aatree->root = NULL;
+	aatree->flags = flags;
+	return aatree;
+}
+
+static void M_AATreeFree_Node(aatree_node_t *node)
+{
+	if (node->left) M_AATreeFree_Node(node->left);
+	if (node->right) M_AATreeFree_Node(node->right);
+	Z_Free(node);
+}
+
+void M_AATreeFree(aatree_t *aatree)
+{
+	if (aatree->root)
+		M_AATreeFree_Node(aatree->root);
+
+	Z_Free(aatree);
+}
+
+static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
+{
+	if (node && node->left && node->left->level == node->level)
+	{
+		// Not allowed: horizontal left-link. Reverse the
+		// horizontal link and hook the orphan back in.
+		aatree_node_t *oldleft = node->left;
+		node->left = oldleft->right;
+		oldleft->right = node;
+
+		return oldleft;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
+{
+	if (node && node->right && node->right->right && node->level == node->right->right->level)
+	{
+		// Not allowed: two consecutive horizontal right-links.
+		// The middle one becomes the new root at this point,
+		// with suitable adjustments below.
+
+		aatree_node_t *oldright = node->right;
+		node->right = oldright->left;
+		oldright->left = node;
+		oldright->level++;
+
+		return oldright;
+	}
+
+	// No change needed.
+	return node;
+}
+
+static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
+{
+	if (!node)
+	{
+		// Nothing here, so just add where we are
+
+		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
+		node->level = 1;
+		node->key = key;
+		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+		else node->value = value;
+		node->left = node->right = NULL;
+	}
+	else
+	{
+		if (key < node->key)
+			node->left = M_AATreeSet_Node(node->left, flags, key, value);
+		else if (key > node->key)
+			node->right = M_AATreeSet_Node(node->right, flags, key, value);
+		else
+		{
+			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
+			else node->value = value;
+		}
+
+		node = M_AATreeSkew(node);
+		node = M_AATreeSplit(node);
+	}
+
+	return node;
+}
+
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
+{
+	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
+}
+
+// Caveat: we don't distinguish between nodes that don't exists
+// and nodes with value == NULL.
+static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
+{
+	if (node)
+	{
+		if (node->key == key)
+			return node->value;
+		else if(node->key < key)
+			return M_AATreeGet_Node(node->right, key);
+		else
+			return M_AATreeGet_Node(node->left, key);
+	}
+
+	return NULL;
+}
+
+void *M_AATreeGet(aatree_t *aatree, INT32 key)
+{
+	return M_AATreeGet_Node(aatree->root, key);
+}
+
+
+static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
+{
+	if (node->left) M_AATreeIterate_Node(node->left, callback);
+	callback(node->key, node->value);
+	if (node->right) M_AATreeIterate_Node(node->right, callback);
+}
+
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
+{
+	if (aatree->root)
+		M_AATreeIterate_Node(aatree->root, callback);
+}
diff --git a/src/m_aatree.h b/src/m_aatree.h
new file mode 100644
index 0000000000000000000000000000000000000000..eeaebca3b94320fb71c5b85579caf2c355503e00
--- /dev/null
+++ b/src/m_aatree.h
@@ -0,0 +1,31 @@
+// SONIC ROBO BLAST 2
+//-----------------------------------------------------------------------------
+// Copyright (C) 1993-1996 by id Software, Inc.
+// Copyright (C) 1998-2000 by DooM Legacy Team.
+// Copyright (C) 1999-2016 by Sonic Team Junior.
+//
+// This program is free software distributed under the
+// terms of the GNU General Public License, version 2.
+// See the 'LICENSE' file for more details.
+//-----------------------------------------------------------------------------
+/// \file  m_aatree.h
+/// \brief AA trees code
+
+#ifndef __M_AATREE__
+#define __M_AATREE__
+
+#include "doomtype.h"
+
+// Flags for AA trees.
+#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
+
+typedef struct aatree_s aatree_t;
+typedef void (*aatree_iter_t)(INT32 key, void *value);
+
+aatree_t *M_AATreeAlloc(UINT32 flags);
+void M_AATreeFree(aatree_t *aatree);
+void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
+void *M_AATreeGet(aatree_t *aatree, INT32 key);
+void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
+
+#endif
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 89334596ec777599c89a005472764c3a1dedbab0..3bbaadc5b05f4e48273b7267b0b44523becf1af8 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -452,7 +452,7 @@ void Command_RTeleport_f(void)
 	else
 		inty = 0;
 
-	ss = R_PointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
+	ss = R_IsPointInSubsector(p->mo->x + intx*FRACUNIT, p->mo->y + inty*FRACUNIT);
 	if (!ss || ss->sector->ceilingheight - ss->sector->floorheight < p->mo->height)
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("Not a valid location.\n"));
diff --git a/src/m_fixed.h b/src/m_fixed.h
index 70402f27a0eafbe61eec8fa6e5f15a4d6e8363cc..1cf9abbae3c97e076e391bc41954eefaf0aa6b2c 100644
--- a/src/m_fixed.h
+++ b/src/m_fixed.h
@@ -46,41 +46,6 @@ typedef INT32 fixed_t;
 #define FLOAT_TO_FIXED(f) (fixed_t)((f) * ((float)FRACUNIT))
 
 
-/**	\brief	The TMulScale16 function
-
-	\param	a	a parameter of type fixed_t
-	\param	b	a parameter of type fixed_t
-	\param	c	a parameter of type fixed_t
-	\param	d	a parameter of type fixed_t
-	\param	e	a parameter of type fixed_t
-	\param	f	a parameter of type fixed_t
-
-	\return	fixed_t
-
-
-*/
-FUNCMATH FUNCINLINE static ATTRINLINE fixed_t TMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d, fixed_t e, fixed_t f) \
-{ \
-	return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d) \
-		+ ((INT64)e * (INT64)f)) >> 16); \
-}
-
-/**	\brief	The DMulScale16 function
-
-	\param	a	a parameter of type fixed_t
-	\param	b	a parameter of type fixed_t
-	\param	c	a parameter of type fixed_t
-	\param	d	a parameter of type fixed_t
-
-	\return	fixed_t
-
-
-*/
-FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DMulScale16(fixed_t a, fixed_t b, fixed_t c, fixed_t d) \
-{ \
-	return (fixed_t)((((INT64)a * (INT64)b) + ((INT64)c * (INT64)d)) >> 16); \
-}
-
 #if defined (__WATCOMC__) && FRACBITS == 16
 	#pragma aux FixedMul =  \
 		"imul ebx",         \
@@ -283,9 +248,16 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedFloor(fixed_t x)
 {
 	const fixed_t a = abs(x); //absolute of x
 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
-	const fixed_t f = i-a; // cut out the integral part
+	const fixed_t f = a-i; // cut out the integral part
+	if (f == 0)
+		return x;
 	if (x != INT32_MIN)
-		return x-f; // return largest integral value not greater than argument
+	{ // return rounded down to nearest whole number
+		if (x > 0)
+			return x-f;
+		else
+			return x-(FRACUNIT-f);
+	}
 	return INT32_MIN;
 }
 
@@ -301,7 +273,7 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedTrunc(fixed_t x)
 {
 	const fixed_t a = abs(x); //absolute of x
 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
-	const fixed_t f = i-a; // cut out the integral part
+	const fixed_t f = a-i; // cut out the integral part
 	if (x != INT32_MIN)
 	{ // return rounded to nearest whole number, towards zero
 		if (x > 0)
@@ -324,11 +296,18 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedCeil(fixed_t x)
 {
 	const fixed_t a = abs(x); //absolute of x
 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
-	const fixed_t f = i-a; // cut out the integral part
+	const fixed_t f = a-i; // cut out the integral part
+	if (f == 0)
+		return x;
 	if (x == INT32_MIN)
 		return INT32_MIN;
 	else if (x < FixedFloor(INT32_MAX))
-		return x+(FRACUNIT-f); // return smallest integral value not less than argument
+	{ // return rounded up to nearest whole number
+		if (x > 0)
+			return x+(FRACUNIT-f);
+		else
+			return x+f;
+	}
 	return INT32_MAX;
 }
 
@@ -344,7 +323,9 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t FixedRound(fixed_t x)
 {
 	const fixed_t a = abs(x); //absolute of x
 	const fixed_t i = (a>>FRACBITS)<<FRACBITS; // cut out the fractional part
-	const fixed_t f = i-a; // cut out the integral part
+	const fixed_t f = a-i; // cut out the integral part
+	if (f == 0)
+		return x;
 	if (x == INT32_MIN)
 		return INT32_MIN;
 	else if (x < FixedFloor(INT32_MAX))
diff --git a/src/m_menu.c b/src/m_menu.c
index 6c12944444983cebec788b92f5afce699f35eda8..45b3d7e57810429764b07902a4a6449d0ef05cf0 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -182,9 +182,6 @@ static INT32 vidm_selected = 0;
 static INT32 vidm_nummodes;
 static INT32 vidm_column_size;
 
-// what a headache.
-static boolean shiftdown = false;
-
 //
 // PROTOTYPES
 //
@@ -705,7 +702,7 @@ static menuitem_t SP_TimeAttackMenu[] =
 	{IT_DISABLED,              NULL, "Guest Option...", &SP_GuestReplayDef, 100},
 	{IT_DISABLED,              NULL, "Replay...",     &SP_ReplayDef,        110},
 	{IT_DISABLED,              NULL, "Ghosts...",     &SP_GhostDef,         120},
-	{IT_WHITESTRING|IT_CALL,   NULL, "Start",         M_ChooseTimeAttack,   130},
+	{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED,   NULL, "Start",         M_ChooseTimeAttack,   130},
 };
 
 enum
@@ -797,7 +794,7 @@ static menuitem_t SP_NightsAttackMenu[] =
 	{IT_DISABLED,              NULL, "Guest Option...",  &SP_NightsGuestReplayDef,   108},
 	{IT_DISABLED,              NULL, "Replay...",        &SP_NightsReplayDef,        118},
 	{IT_DISABLED,              NULL, "Ghosts...",        &SP_NightsGhostDef,         128},
-	{IT_WHITESTRING|IT_CALL,   NULL, "Start",            M_ChooseNightsAttack, 138},
+	{IT_WHITESTRING|IT_CALL|IT_CALL_NOTMODIFIED,   NULL, "Start",            M_ChooseNightsAttack, 138},
 };
 
 enum
@@ -2080,11 +2077,6 @@ boolean M_Responder(event_t *ev)
 	|| gamestate == GS_CREDITS || gamestate == GS_EVALUATION)
 		return false;
 
-	if (ev->type == ev_keyup && (ev->data1 == KEY_LSHIFT || ev->data1 == KEY_RSHIFT))
-	{
-		shiftdown = false;
-		return false;
-	}
 	if (noFurtherInput)
 	{
 		// Ignore input after enter/escape/other buttons
@@ -2098,10 +2090,6 @@ boolean M_Responder(event_t *ev)
 		// added 5-2-98 remap virtual keys (mouse & joystick buttons)
 		switch (ch)
 		{
-			case KEY_LSHIFT:
-			case KEY_RSHIFT:
-				shiftdown = true;
-				break; //return false;
 			case KEY_MOUSE1:
 			case KEY_JOY1:
 			case KEY_JOY1 + 2:
@@ -3702,6 +3690,11 @@ static void M_DrawMessageMenu(void)
 
 	mlines = currentMenu->lastOn>>8;
 	max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
+
+	// hack: draw RA background in RA menus
+	if (gamestate == GS_TIMEATTACK)
+		V_DrawPatchFill(W_CachePatchName("SRB2BACK", PU_CACHE));
+
 	M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines);
 
 	while (*(msg+start))
@@ -3856,6 +3849,7 @@ static void M_ChangeLevel(INT32 choice)
 static void M_ConfirmSpectate(INT32 choice)
 {
 	(void)choice;
+	// We allow switching to spectator even if team changing is not allowed
 	M_ClearMenus(true);
 	COM_ImmedExecute("changeteam spectator");
 }
@@ -3863,6 +3857,11 @@ static void M_ConfirmSpectate(INT32 choice)
 static void M_ConfirmEnterGame(INT32 choice)
 {
 	(void)choice;
+	if (!cv_allowteamchange.value)
+	{
+		M_StartMessage(M_GetText("The server is not allowing\nteam changes at this time.\nPress a key.\n"), NULL, MM_NOTHING);
+		return;
+	}
 	M_ClearMenus(true);
 	COM_ImmedExecute("changeteam playing");
 }
@@ -4310,9 +4309,9 @@ static void M_SinglePlayerMenu(INT32 choice)
 {
 	(void)choice;
 	SP_MainMenu[sprecordattack].status =
-		(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+		(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
 	SP_MainMenu[spnightsmode].status =
-		(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING|IT_CALL_NOTMODIFIED : IT_SECRET;
+		(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;
 
 	M_SetupNextMenu(&SP_MainDef);
 }
diff --git a/src/m_misc.c b/src/m_misc.c
index 64054d4f9cada065577d1293d09fed5823460730..d88643ec463373bd2f72f582432ac2126b49416b 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -585,7 +585,7 @@ static const char *Newsnapshotfile(const char *pathname, const char *ext)
 
 		i += add * result;
 
-		if (add < 0 || add > 9999)
+		if (i < 0 || i > 9999)
 			return NULL;
 	}
 
@@ -1675,6 +1675,7 @@ char *M_GetToken(const char *inputString)
 			|| stringToUse[startPos] == '\r'
 			|| stringToUse[startPos] == '\n'
 			|| stringToUse[startPos] == '\0'
+			|| stringToUse[startPos] == '"' // we're treating this as whitespace because SLADE likes adding it for no good reason
 			|| inComment != 0)
 			&& startPos < stringLength)
 	{
@@ -1742,6 +1743,7 @@ char *M_GetToken(const char *inputString)
 			&& stringToUse[endPos] != ','
 			&& stringToUse[endPos] != '{'
 			&& stringToUse[endPos] != '}'
+			&& stringToUse[endPos] != '"' // see above
 			&& inComment == 0)
 			&& endPos < stringLength)
 	{
@@ -2323,158 +2325,3 @@ void M_SetupMemcpy(void)
 	M_Memcpy = cpu_cpy;
 #endif
 }
-
-
-// A partial implementation of AA trees,
-// according to the algorithms given on Wikipedia.
-// http://en.wikipedia.org/wiki/AA_tree
-
-
-
-typedef struct aatree_node_s
-{
-	INT32	level;
-	INT32	key;
-	void*	value;
-
-	struct aatree_node_s *left, *right;
-} aatree_node_t;
-
-struct aatree_s
-{
-	aatree_node_t	*root;
-	UINT32		flags;
-};
-
-aatree_t *M_AATreeAlloc(UINT32 flags)
-{
-	aatree_t *aatree = Z_Malloc(sizeof (aatree_t), PU_STATIC, NULL);
-	aatree->root = NULL;
-	aatree->flags = flags;
-	return aatree;
-}
-
-static void M_AATreeFree_Node(aatree_node_t *node)
-{
-	if (node->left) M_AATreeFree_Node(node->left);
-	if (node->right) M_AATreeFree_Node(node->right);
-	Z_Free(node);
-}
-
-void M_AATreeFree(aatree_t *aatree)
-{
-	if (aatree->root)
-		M_AATreeFree_Node(aatree->root);
-
-	Z_Free(aatree);
-}
-
-static aatree_node_t *M_AATreeSkew(aatree_node_t *node)
-{
-	if (node && node->left && node->left->level == node->level)
-	{
-		// Not allowed: horizontal left-link. Reverse the
-		// horizontal link and hook the orphan back in.
-		aatree_node_t *oldleft = node->left;
-		node->left = oldleft->right;
-		oldleft->right = node;
-
-		return oldleft;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSplit(aatree_node_t *node)
-{
-	if (node && node->right && node->right->right && node->level == node->right->right->level)
-	{
-		// Not allowed: two consecutive horizontal right-links.
-		// The middle one becomes the new root at this point,
-		// with suitable adjustments below.
-
-		aatree_node_t *oldright = node->right;
-		node->right = oldright->left;
-		oldright->left = node;
-		oldright->level++;
-
-		return oldright;
-	}
-
-	// No change needed.
-	return node;
-}
-
-static aatree_node_t *M_AATreeSet_Node(aatree_node_t *node, UINT32 flags, INT32 key, void* value)
-{
-	if (!node)
-	{
-		// Nothing here, so just add where we are
-
-		node = Z_Malloc(sizeof (aatree_node_t), PU_STATIC, NULL);
-		node->level = 1;
-		node->key = key;
-		if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-		else node->value = value;
-		node->left = node->right = NULL;
-	}
-	else
-	{
-		if (key < node->key)
-			node->left = M_AATreeSet_Node(node->left, flags, key, value);
-		else if (key > node->key)
-			node->right = M_AATreeSet_Node(node->right, flags, key, value);
-		else
-		{
-			if (value && (flags & AATREE_ZUSER)) Z_SetUser(value, &node->value);
-			else node->value = value;
-		}
-
-		node = M_AATreeSkew(node);
-		node = M_AATreeSplit(node);
-	}
-
-	return node;
-}
-
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value)
-{
-	aatree->root = M_AATreeSet_Node(aatree->root, aatree->flags, key, value);
-}
-
-// Caveat: we don't distinguish between nodes that don't exists
-// and nodes with value == NULL.
-static void *M_AATreeGet_Node(aatree_node_t *node, INT32 key)
-{
-	if (node)
-	{
-		if (node->key == key)
-			return node->value;
-		else if(node->key < key)
-			return M_AATreeGet_Node(node->right, key);
-		else
-			return M_AATreeGet_Node(node->left, key);
-	}
-
-	return NULL;
-}
-
-void *M_AATreeGet(aatree_t *aatree, INT32 key)
-{
-	return M_AATreeGet_Node(aatree->root, key);
-}
-
-
-static void M_AATreeIterate_Node(aatree_node_t *node, aatree_iter_t callback)
-{
-	if (node->left) M_AATreeIterate_Node(node->left, callback);
-	callback(node->key, node->value);
-	if (node->right) M_AATreeIterate_Node(node->right, callback);
-}
-
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback)
-{
-	if (aatree->root)
-		M_AATreeIterate_Node(aatree->root, callback);
-}
diff --git a/src/m_misc.h b/src/m_misc.h
index fa1f3b33ca78032e64620bcc139d7cf365680c07..dc540dc16325ffca245ba194393463067823c083 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -96,19 +96,6 @@ void M_SetupMemcpy(void);
 // counting bits, for weapon ammo code, usually
 FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);
 
-// Flags for AA trees.
-#define AATREE_ZUSER	1		// Treat values as z_zone-allocated blocks and set their user fields
-
-typedef struct aatree_s aatree_t;
-typedef void (*aatree_iter_t)(INT32 key, void *value);
-
-aatree_t *M_AATreeAlloc(UINT32 flags);
-void M_AATreeFree(aatree_t *aatree);
-void M_AATreeSet(aatree_t *aatree, INT32 key, void* value);
-void *M_AATreeGet(aatree_t *aatree, INT32 key);
-void M_AATreeIterate(aatree_t *aatree, aatree_iter_t callback);
-
-// Nasty cyclic dependency workaround. This must come after aatree stuff.
 #include "w_wad.h"
 extern char configfile[MAX_WADPATH];
 
diff --git a/src/nds/i_system.c b/src/nds/i_system.c
index 0ed58029c194c12ce43c977c54b4cc0a18250b58..3e5c4b8c6d33fb6d266d12aad24e3d50748a9769 100644
--- a/src/nds/i_system.c
+++ b/src/nds/i_system.c
@@ -269,6 +269,18 @@ INT32 I_PutEnv(char *variable)
 	return -1;
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 void I_RegisterSysCommands(void) {}
 
 #include "../sdl/dosstr.c"
diff --git a/src/p_enemy.c b/src/p_enemy.c
index 025a259735ceeb1708f0d14a5455754d804d917c..649c7883828c57f75a8cb49caa77698c25151e9a 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -1102,7 +1102,7 @@ void A_JetJawChomp(mobj_t *actor)
 	if (!actor->target || !(actor->target->flags & MF_SHOOTABLE)
 		|| actor->target->health <= 0 || !P_CheckSight(actor, actor->target))
 	{
-		P_SetMobjState(actor, actor->info->spawnstate);
+		P_SetMobjStateNF(actor, actor->info->spawnstate);
 		return;
 	}
 
@@ -7644,7 +7644,7 @@ void A_SetObjectFlags(mobj_t *actor)
 	else if (locvar2 == 1)
 		locvar1 = actor->flags & ~locvar1;
 
-	if ((locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
+	if ((UINT32)(locvar1 & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (actor->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) // Blockmap/sector status has changed, so reset the links
 		unlinkthings = true;
 
 	if (unlinkthings) {
diff --git a/src/p_floor.c b/src/p_floor.c
index 1c396c8773ab93aeb1a2ef164d1a429c2d9cfe3c..9112130145cc7df7bca88b34cd74620e8f9670ed 100644
--- a/src/p_floor.c
+++ b/src/p_floor.c
@@ -1163,7 +1163,7 @@ void T_SpikeSector(levelspecthink_t *spikes)
 
 	node = spikes->sector->touching_thinglist; // things touching this sector
 
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (!thing->player)
@@ -1316,7 +1316,7 @@ void T_BridgeThinker(levelspecthink_t *bridge)
 			controlsec = &sectors[k];
 
 			// Is a player standing on me?
-			for (node = sector->touching_thinglist; node; node = node->m_snext)
+			for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
 			{
 				thing = node->m_thing;
 
@@ -1739,7 +1739,7 @@ wegotit:
 static mobj_t *SearchMarioNode(msecnode_t *node)
 {
 	mobj_t *thing = NULL;
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		// Things which should NEVER be ejected from a MarioBlock, by type.
 		switch (node->m_thing->type)
@@ -2003,7 +2003,7 @@ void T_NoEnemiesSector(levelspecthink_t *nobaddies)
 						goto foundenemy;
 					}
 
-					node = node->m_snext;
+					node = node->m_thinglist_next;
 				}
 			}
 		}
@@ -2288,7 +2288,7 @@ void T_RaiseSector(levelspecthink_t *raise)
 		sector = &sectors[i];
 
 		// Is a player standing on me?
-		for (node = sector->touching_thinglist; node; node = node->m_snext)
+		for (node = sector->touching_thinglist; node; node = node->m_thinglist_next)
 		{
 			thing = node->m_thing;
 
diff --git a/src/p_inter.c b/src/p_inter.c
index 884b22ad3973c5c4bd0f089a187e1fa2d60c9644..4892d977519a3c31f57b83bbad2f345adba4f01e 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1684,7 +1684,7 @@ void P_CheckTimeLimit(void)
 		return;
 
 	//Tagmode round end but only on the tic before the
-	//XD_EXITLEVEL packet is recieved by all players.
+	//XD_EXITLEVEL packet is received by all players.
 	if (G_TagGametype())
 	{
 		if (leveltime == (timelimitintics + 1))
@@ -1695,7 +1695,7 @@ void P_CheckTimeLimit(void)
 				 || (players[i].pflags & PF_TAGGED) || (players[i].pflags & PF_TAGIT))
 					continue;
 
-				CONS_Printf(M_GetText("%s recieved double points for surviving the round.\n"), player_names[i]);
+				CONS_Printf(M_GetText("%s received double points for surviving the round.\n"), player_names[i]);
 				P_AddPlayerScore(&players[i], players[i].score);
 			}
 		}
@@ -3626,7 +3626,7 @@ void P_PlayerFlagBurst(player_t *player, boolean toss)
 	// Flag text
 	{
 		char plname[MAXPLAYERNAME+4];
-		char *flagtext;
+		const char *flagtext;
 		char flagcolor;
 
 		snprintf(plname, sizeof(plname), "%s%s%s",
diff --git a/src/p_local.h b/src/p_local.h
index c8930aeda6ce50a8ba07fbcedd8f063a1fa3eed0..1fd7ada04219b928fe1619e2398fb4fef5ba500a 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -251,7 +251,8 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 aimtype
 #endif
 void P_ColorTeamMissile(mobj_t *missile, player_t *source);
 SINT8 P_MobjFlip(mobj_t *mobj);
-boolean P_WeaponOrPanel(mobjtype_t type);
+fixed_t P_GetMobjGravity(mobj_t *mo);
+FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
 
 boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);
 
diff --git a/src/p_map.c b/src/p_map.c
index 71adf2e1631a6a0cb2fab6aafe124638c42a7e54..86776f8d1b701dbea22992e6ae77b3fee122621a 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -129,6 +129,10 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
 		return false;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // Okay, now we can't return - no launching off at silly angles for you.
+#endif
+
 	object->eflags |= MFE_SPRUNG; // apply this flag asap!
 	spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
 
@@ -232,20 +236,24 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object)
 	if (p && object->state == &states[object->info->painstate]) // can't use fans and gas jets when player is in pain!
 		return;
 
-	// is object below thruster's position? if not, calculate distance between their bottoms
+	// is object's top below thruster's position? if not, calculate distance between their bottoms
 	if (spring->eflags & MFE_VERTICALFLIP)
 	{
-		if (object->z + object->height > spring->z + spring->height)
+		if (object->z > spring->z + spring->height)
 			return;
 		zdist = (spring->z + spring->height) - (object->z + object->height);
 	}
 	else
 	{
-		if (object->z < spring->z)
+		if (object->z + object->height < spring->z)
 			return;
 		zdist = object->z - spring->z;
 	}
 
+#ifdef ESLOPE
+	object->standingslope = NULL; // No launching off at silly angles for you.
+#endif
+
 	switch (spring->type)
 	{
 		case MT_FAN: // fan
@@ -977,18 +985,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
 				return true;
 			}
 
-			topz = thing->z - FixedMul(FRACUNIT, thing->scale);
+			topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
 
 			// block only when jumping not high enough,
 			// (dont climb max. 24units while already in air)
-			// if not in air, let P_TryMove() decide if it's not too high
+			// since return false doesn't handle momentum properly,
+			// we lie to P_TryMove() so it's always too high
 			if (tmthing->player && tmthing->z + tmthing->height > topz
 				&& tmthing->z + tmthing->height < tmthing->ceilingz)
-				return false; // block while in air
-
-			if (thing->flags & MF_SPRING)
+			{
+				tmfloorz = tmceilingz = topz; // block while in air
+#ifdef ESLOPE
+				tmceilingslope = NULL;
+#endif
+				tmfloorthing = thing; // needed for side collision
+			}
+			else if (thing->flags & MF_SPRING)
 				;
-			else if (topz < tmceilingz && tmthing->z+tmthing->height <= thing->z+thing->height)
+			else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
 			{
 				tmceilingz = topz;
 #ifdef ESLOPE
@@ -1014,17 +1028,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
 				return true;
 			}
 
-			topz = thing->z + thing->height + FixedMul(FRACUNIT, thing->scale);
+			topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
 
 			// block only when jumping not high enough,
 			// (dont climb max. 24units while already in air)
-			// if not in air, let P_TryMove() decide if it's not too high
-			if (tmthing->player && tmthing->z < topz && tmthing->z > tmthing->floorz)
-				return false; // block while in air
-
-			if (thing->flags & MF_SPRING)
+			// since return false doesn't handle momentum properly,
+			// we lie to P_TryMove() so it's always too high
+			if (tmthing->player && tmthing->z < topz
+				&& tmthing->z > tmthing->floorz)
+			{
+				tmfloorz = tmceilingz = topz; // block while in air
+#ifdef ESLOPE
+				tmfloorslope = NULL;
+#endif
+				tmfloorthing = thing; // needed for side collision
+			}
+			else if (thing->flags & MF_SPRING)
 				;
-			else if (topz > tmfloorz && tmthing->z >= thing->z)
+			else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
 			{
 				tmfloorz = topz;
 #ifdef ESLOPE
@@ -1145,7 +1166,7 @@ static boolean PIT_CheckLine(line_t *ld)
 	}
 
 	// set openrange, opentop, openbottom
-	P_LineOpening(ld);
+	P_LineOpening(ld, tmthing);
 
 	// adjust floor / ceiling heights
 	if (opentop < tmceilingz)
@@ -1263,7 +1284,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
 			topheight = P_GetFOFTopZ(thing, newsubsec->sector, rover, x, y, NULL);
 			bottomheight = P_GetFOFBottomZ(thing, newsubsec->sector, rover, x, y, NULL);
 
-			if (rover->flags & FF_GOOWATER && !(thing->flags & MF_NOGRAVITY))
+			if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER) && !(thing->flags & MF_NOGRAVITY))
 			{
 				// If you're inside goowater and slowing down
 				fixed_t sinklevel = FixedMul(thing->info->height/6, thing->scale);
@@ -1962,8 +1983,12 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
 			}
 
 			// Ramp test
-			if (thing->player && maxstep > 0
-			&& !(P_PlayerTouchingSectorSpecial(thing->player, 1, 14) || GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14))
+			if (maxstep > 0 && !(
+				thing->player && (
+				P_PlayerTouchingSectorSpecial(thing->player, 1, 14)
+				|| GETSECSPECIAL(R_PointInSubsector(x, y)->sector->special, 1) == 14)
+				)
+			)
 			{
 				// If the floor difference is MAXSTEPMOVE or less, and the sector isn't Section1:14, ALWAYS
 				// step down! Formerly required a Section1:13 sector for the full MAXSTEPMOVE, but no more.
@@ -2423,6 +2448,8 @@ isblocking:
 //
 // P_IsClimbingValid
 //
+// Unlike P_DoClimbing, don't use when up against a one-sided linedef.
+//
 static boolean P_IsClimbingValid(player_t *player, angle_t angle)
 {
 	fixed_t platx, platy;
@@ -2571,7 +2598,7 @@ static boolean PTR_SlideTraverse(intercept_t *in)
 	}
 
 	// set openrange, opentop, openbottom
-	P_LineOpening(li);
+	P_LineOpening(li, slidemo);
 
 	if (openrange < slidemo->height)
 		goto isblocking; // doesn't fit
@@ -2647,6 +2674,7 @@ isblocking:
 		// see about climbing on the wall
 		if (!(checkline->flags & ML_NOCLIMB))
 		{
+			boolean canclimb;
 			angle_t climbangle, climbline;
 			INT32 whichside = P_PointOnLineSide(slidemo->x, slidemo->y, li);
 
@@ -2657,9 +2685,11 @@ isblocking:
 
 			climbangle += (ANGLE_90 * (whichside ? -1 : 1));
 
+			canclimb = (li->backsector ? P_IsClimbingValid(slidemo->player, climbangle) : true);
+
 			if (((!slidemo->player->climbing && abs((signed)(slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
 			|| (slidemo->player->climbing == 1 && abs((signed)(slidemo->angle - climbline)) < ANGLE_135))
-			&& P_IsClimbingValid(slidemo->player, climbangle))
+			&& canclimb)
 			{
 				slidemo->angle = climbangle;
 				if (!demoplayback || P_AnalogMove(slidemo->player))
@@ -3365,7 +3395,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 		for (i = 0; i < sector->numattached; i++)
 		{
 			sec = &sectors[sector->attached[i]];
-			for (n = sec->touching_thinglist; n; n = n->m_snext)
+			for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				n->visited = false;
 
 			sec->moved = true;
@@ -3377,7 +3407,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 
 			do
 			{
-				for (n = sec->touching_thinglist; n; n = n->m_snext)
+				for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				if (!n->visited)
 				{
 					n->visited = true;
@@ -3398,12 +3428,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 	// Mark all things invalid
 	sector->moved = true;
 
-	for (n = sector->touching_thinglist; n; n = n->m_snext)
+	for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
 		n->visited = false;
 
 	do
 	{
-		for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+		for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
 			if (!n->visited) // unprocessed thing found
 			{
 				n->visited = true; // mark thing as processed
@@ -3427,7 +3457,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 		for (i = 0; i < sector->numattached; i++)
 		{
 			sec = &sectors[sector->attached[i]];
-			for (n = sec->touching_thinglist; n; n = n->m_snext)
+			for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				n->visited = false;
 
 			sec->moved = true;
@@ -3439,7 +3469,7 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 
 			do
 			{
-				for (n = sec->touching_thinglist; n; n = n->m_snext)
+				for (n = sec->touching_thinglist; n; n = n->m_thinglist_next)
 				if (!n->visited)
 				{
 					n->visited = true;
@@ -3457,12 +3487,12 @@ boolean P_CheckSector(sector_t *sector, boolean crunch)
 	// Mark all things invalid
 	sector->moved = true;
 
-	for (n = sector->touching_thinglist; n; n = n->m_snext)
+	for (n = sector->touching_thinglist; n; n = n->m_thinglist_next)
 		n->visited = false;
 
 	do
 	{
-		for (n = sector->touching_thinglist; n; n = n->m_snext) // go through list
+		for (n = sector->touching_thinglist; n; n = n->m_thinglist_next) // go through list
 			if (!n->visited) // unprocessed thing found
 			{
 				n->visited = true; // mark thing as processed
@@ -3502,7 +3532,7 @@ static msecnode_t *P_GetSecnode(void)
 	if (headsecnode)
 	{
 		node = headsecnode;
-		headsecnode = headsecnode->m_snext;
+		headsecnode = headsecnode->m_thinglist_next;
 	}
 	else
 		node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3516,7 +3546,7 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
 	if (headprecipsecnode)
 	{
 		node = headprecipsecnode;
-		headprecipsecnode = headprecipsecnode->m_snext;
+		headprecipsecnode = headprecipsecnode->m_thinglist_next;
 	}
 	else
 		node = Z_Calloc(sizeof (*node), PU_LEVEL, NULL);
@@ -3527,14 +3557,14 @@ static mprecipsecnode_t *P_GetPrecipSecnode(void)
 
 static inline void P_PutSecnode(msecnode_t *node)
 {
-	node->m_snext = headsecnode;
+	node->m_thinglist_next = headsecnode;
 	headsecnode = node;
 }
 
 // Tails 08-25-2002
 static inline void P_PutPrecipSecnode(mprecipsecnode_t *node)
 {
-	node->m_snext = headprecipsecnode;
+	node->m_thinglist_next = headprecipsecnode;
 	headprecipsecnode = node;
 }
 
@@ -3555,7 +3585,7 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
 			node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
 			return nextnode;
 		}
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	// Couldn't find an existing node for this sector. Add one at the head
@@ -3568,17 +3598,17 @@ static msecnode_t *P_AddSecnode(sector_t *s, mobj_t *thing, msecnode_t *nextnode
 
 	node->m_sector = s; // sector
 	node->m_thing = thing; // mobj
-	node->m_tprev = NULL; // prev node on Thing thread
-	node->m_tnext = nextnode; // next node on Thing thread
+	node->m_sectorlist_prev = NULL; // prev node on Thing thread
+	node->m_sectorlist_next = nextnode; // next node on Thing thread
 	if (nextnode)
-		nextnode->m_tprev = node; // set back link on Thing
+		nextnode->m_sectorlist_prev = node; // set back link on Thing
 
 	// Add new node at head of sector thread starting at s->touching_thinglist
 
-	node->m_sprev = NULL; // prev node on sector thread
-	node->m_snext = s->touching_thinglist; // next node on sector thread
+	node->m_thinglist_prev = NULL; // prev node on sector thread
+	node->m_thinglist_next = s->touching_thinglist; // next node on sector thread
 	if (s->touching_thinglist)
-		node->m_snext->m_sprev = node;
+		node->m_thinglist_next->m_thinglist_prev = node;
 	s->touching_thinglist = node;
 	return node;
 }
@@ -3596,7 +3626,7 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
 			node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
 			return nextnode;
 		}
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	// Couldn't find an existing node for this sector. Add one at the head
@@ -3609,17 +3639,17 @@ static mprecipsecnode_t *P_AddPrecipSecnode(sector_t *s, precipmobj_t *thing, mp
 
 	node->m_sector = s; // sector
 	node->m_thing = thing; // mobj
-	node->m_tprev = NULL; // prev node on Thing thread
-	node->m_tnext = nextnode; // next node on Thing thread
+	node->m_sectorlist_prev = NULL; // prev node on Thing thread
+	node->m_sectorlist_next = nextnode; // next node on Thing thread
 	if (nextnode)
-		nextnode->m_tprev = node; // set back link on Thing
+		nextnode->m_sectorlist_prev = node; // set back link on Thing
 
 	// Add new node at head of sector thread starting at s->touching_thinglist
 
-	node->m_sprev = NULL; // prev node on sector thread
-	node->m_snext = s->touching_preciplist; // next node on sector thread
+	node->m_thinglist_prev = NULL; // prev node on sector thread
+	node->m_thinglist_next = s->touching_preciplist; // next node on sector thread
 	if (s->touching_preciplist)
-		node->m_snext->m_sprev = node;
+		node->m_thinglist_next->m_thinglist_prev = node;
 	s->touching_preciplist = node;
 	return node;
 }
@@ -3641,24 +3671,24 @@ static msecnode_t *P_DelSecnode(msecnode_t *node)
 	// Unlink from the Thing thread. The Thing thread begins at
 	// sector_list and not from mobj_t->touching_sectorlist.
 
-	tp = node->m_tprev;
-	tn = node->m_tnext;
+	tp = node->m_sectorlist_prev;
+	tn = node->m_sectorlist_next;
 	if (tp)
-		tp->m_tnext = tn;
+		tp->m_sectorlist_next = tn;
 	if (tn)
-		tn->m_tprev = tp;
+		tn->m_sectorlist_prev = tp;
 
 	// Unlink from the sector thread. This thread begins at
 	// sector_t->touching_thinglist.
 
-	sp = node->m_sprev;
-	sn = node->m_snext;
+	sp = node->m_thinglist_prev;
+	sn = node->m_thinglist_next;
 	if (sp)
-		sp->m_snext = sn;
+		sp->m_thinglist_next = sn;
 	else
 		node->m_sector->touching_thinglist = sn;
 	if (sn)
-		sn->m_sprev = sp;
+		sn->m_thinglist_prev = sp;
 
 	// Return this node to the freelist
 
@@ -3680,24 +3710,24 @@ static mprecipsecnode_t *P_DelPrecipSecnode(mprecipsecnode_t *node)
 	// Unlink from the Thing thread. The Thing thread begins at
 	// sector_list and not from mobj_t->touching_sectorlist.
 
-	tp = node->m_tprev;
-	tn = node->m_tnext;
+	tp = node->m_sectorlist_prev;
+	tn = node->m_sectorlist_next;
 	if (tp)
-		tp->m_tnext = tn;
+		tp->m_sectorlist_next = tn;
 	if (tn)
-		tn->m_tprev = tp;
+		tn->m_sectorlist_prev = tp;
 
 	// Unlink from the sector thread. This thread begins at
 	// sector_t->touching_thinglist.
 
-	sp = node->m_sprev;
-	sn = node->m_snext;
+	sp = node->m_thinglist_prev;
+	sn = node->m_thinglist_next;
 	if (sp)
-		sp->m_snext = sn;
+		sp->m_thinglist_next = sn;
 	else
 		node->m_sector->touching_preciplist = sn;
 	if (sn)
-		sn->m_sprev = sp;
+		sn->m_thinglist_prev = sp;
 
 	// Return this node to the freelist
 
@@ -3812,7 +3842,7 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 	while (node)
 	{
 		node->m_thing = NULL;
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	P_SetTarget(&tmthing, thing);
@@ -3850,11 +3880,11 @@ void P_CreateSecNodeList(mobj_t *thing, fixed_t x, fixed_t y)
 		if (!node->m_thing)
 		{
 			if (node == sector_list)
-				sector_list = node->m_tnext;
+				sector_list = node->m_sectorlist_next;
 			node = P_DelSecnode(node);
 		}
 		else
-			node = node->m_tnext;
+			node = node->m_sectorlist_next;
 	}
 
 	/* cph -
@@ -3895,7 +3925,7 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 	while (node)
 	{
 		node->m_thing = NULL;
-		node = node->m_tnext;
+		node = node->m_sectorlist_next;
 	}
 
 	tmprecipthing = thing;
@@ -3929,11 +3959,11 @@ void P_CreatePrecipSecNodeList(precipmobj_t *thing,fixed_t x,fixed_t y)
 		if (!node->m_thing)
 		{
 			if (node == precipsector_list)
-				precipsector_list = node->m_tnext;
+				precipsector_list = node->m_sectorlist_next;
 			node = P_DelPrecipSecnode(node);
 		}
 		else
-			node = node->m_tnext;
+			node = node->m_sectorlist_next;
 	}
 
 	/* cph -
diff --git a/src/p_maputl.c b/src/p_maputl.c
index c3a6fa842b08a12267d7904368fd6e49120816fc..46b033386410c2119d1af74292e7684ecfac5e36 100644
--- a/src/p_maputl.c
+++ b/src/p_maputl.c
@@ -489,7 +489,7 @@ void P_CameraLineOpening(line_t *linedef)
 	}
 }
 
-void P_LineOpening(line_t *linedef)
+void P_LineOpening(line_t *linedef, mobj_t *mobj)
 {
 	sector_t *front, *back;
 
@@ -520,8 +520,8 @@ void P_LineOpening(line_t *linedef)
 	{ // Set open and high/low values here
 		fixed_t frontheight, backheight;
 
-		frontheight = P_GetCeilingZ(tmthing, front, tmx, tmy, linedef);
-		backheight = P_GetCeilingZ(tmthing, back, tmx, tmy, linedef);
+		frontheight = P_GetCeilingZ(mobj, front, tmx, tmy, linedef);
+		backheight = P_GetCeilingZ(mobj, back, tmx, tmy, linedef);
 
 		if (frontheight < backheight)
 		{
@@ -540,8 +540,8 @@ void P_LineOpening(line_t *linedef)
 #endif
 		}
 
-		frontheight = P_GetFloorZ(tmthing, front, tmx, tmy, linedef);
-		backheight = P_GetFloorZ(tmthing, back, tmx, tmy, linedef);
+		frontheight = P_GetFloorZ(mobj, front, tmx, tmy, linedef);
+		backheight = P_GetFloorZ(mobj, back, tmx, tmy, linedef);
 
 		if (frontheight > backheight)
 		{
@@ -561,52 +561,65 @@ void P_LineOpening(line_t *linedef)
 		}
 	}
 
-	if (tmthing)
+	if (mobj)
 	{
-		fixed_t thingtop = tmthing->z + tmthing->height;
+		fixed_t thingtop = mobj->z + mobj->height;
 
 		// Check for collision with front side's midtexture if Effect 4 is set
-		if (linedef->flags & ML_EFFECT4) {
+		if (linedef->flags & ML_EFFECT4
+			&& !linedef->polyobj // don't do anything for polyobjects! ...for now
+			) {
 			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
+			INT32 texnum = R_GetTextureNum(side->midtexture); // make sure the texture is actually valid
+
+			if (texnum) {
+				// Get the midtexture's height
+				texheight = textures[texnum]->height << FRACBITS;
+
+				// Set texbottom and textop to the Z coordinates of the texture's boundaries
+#if 0 // #ifdef POLYOBJECTS
+				// don't remove this code unless solid midtextures
+				// on non-solid polyobjects should NEVER happen in the future
+				if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT)) {
+					if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+						texbottom = back->floorheight + side->rowoffset;
+						textop = back->ceilingheight + side->rowoffset;
+					} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
+						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);
+				{
+					if (linedef->flags & ML_EFFECT5 && !side->repeatcnt) { // "infinite" repeat
+						texbottom = openbottom + side->rowoffset;
+						textop = opentop + side->rowoffset;
+					} else if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3)) {
+						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;
+				texmid = texbottom+(textop-texbottom)/2;
 
-			delta1 = abs(tmthing->z - texmid);
-			delta2 = abs(thingtop - texmid);
+				delta1 = abs(mobj->z - texmid);
+				delta2 = abs(thingtop - texmid);
 
-			if (delta1 > delta2) { // Below
-				if (opentop > texbottom)
-					opentop = texbottom;
-			} else { // Above
-				if (openbottom < textop)
-					openbottom = textop;
+				if (delta1 > delta2) { // Below
+					if (opentop > texbottom)
+						opentop = texbottom;
+				} else { // Above
+					if (openbottom < textop)
+						openbottom = textop;
+				}
 			}
 		}
 
@@ -636,16 +649,16 @@ void P_LineOpening(line_t *linedef)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
-				else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
-					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
 					continue;
 
-				topheight = P_GetFOFTopZ(tmthing, front, rover, tmx, tmy, linedef);
-				bottomheight = P_GetFOFBottomZ(tmthing, front, rover, tmx, tmy, linedef);
+				topheight = P_GetFOFTopZ(mobj, front, rover, tmx, tmy, linedef);
+				bottomheight = P_GetFOFBottomZ(mobj, front, rover, tmx, tmy, linedef);
 
-				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
 				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -680,16 +693,16 @@ void P_LineOpening(line_t *linedef)
 				if (!(rover->flags & FF_EXISTS))
 					continue;
 
-				if (tmthing->player && (P_CheckSolidLava(tmthing, rover) || P_CanRunOnWater(tmthing->player, rover)))
+				if (mobj->player && (P_CheckSolidLava(mobj, rover) || P_CanRunOnWater(mobj->player, rover)))
 					;
-				else if (!((rover->flags & FF_BLOCKPLAYER && tmthing->player)
-					|| (rover->flags & FF_BLOCKOTHERS && !tmthing->player)))
+				else if (!((rover->flags & FF_BLOCKPLAYER && mobj->player)
+					|| (rover->flags & FF_BLOCKOTHERS && !mobj->player)))
 					continue;
 
-				topheight = P_GetFOFTopZ(tmthing, back, rover, tmx, tmy, linedef);
-				bottomheight = P_GetFOFBottomZ(tmthing, back, rover, tmx, tmy, linedef);
+				topheight = P_GetFOFTopZ(mobj, back, rover, tmx, tmy, linedef);
+				bottomheight = P_GetFOFBottomZ(mobj, back, rover, tmx, tmy, linedef);
 
-				delta1 = abs(tmthing->z - (bottomheight + ((topheight - bottomheight)/2)));
+				delta1 = abs(mobj->z - (bottomheight + ((topheight - bottomheight)/2)));
 				delta2 = abs(thingtop - (bottomheight + ((topheight - bottomheight)/2)));
 
 				if (delta1 >= delta2 && !(rover->flags & FF_PLATFORM)) // thing is below FOF
@@ -723,7 +736,7 @@ void P_LineOpening(line_t *linedef)
 			{
 				const sector_t *polysec = linedef->backsector;
 
-				delta1 = abs(tmthing->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
+				delta1 = abs(mobj->z - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
 				delta2 = abs(thingtop - (polysec->floorheight + ((polysec->ceilingheight - polysec->floorheight)/2)));
 				if (polysec->floorheight < lowestceiling && delta1 >= delta2) {
 					lowestceiling = polysec->floorheight;
diff --git a/src/p_maputl.h b/src/p_maputl.h
index c160bfa288f7ed5ca36275ee9eb0cc9ff8385583..3d74e927b3ba44c76585c513dcbd941369c76377 100644
--- a/src/p_maputl.h
+++ b/src/p_maputl.h
@@ -59,7 +59,7 @@ extern fixed_t opentop, openbottom, openrange, lowfloor, highceiling;
 extern pslope_t *opentopslope, *openbottomslope;
 #endif
 
-void P_LineOpening(line_t *plinedef);
+void P_LineOpening(line_t *plinedef, mobj_t *mobj);
 
 boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *));
 boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *));
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4122619d1d06929db0ce5810d283aba12a3adaf4..9fdbc37fb848a33c401d02f518c0fe76d5888a0f 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -1252,13 +1252,12 @@ static void P_PlayerFlip(mobj_t *mo)
 }
 
 //
-// P_CheckGravity
+// P_GetMobjGravity
 //
-// Checks the current gravity state
-// of the object. If affect is true,
-// a gravity force will be applied.
+// Returns the current gravity
+// value of the object.
 //
-void P_CheckGravity(mobj_t *mo, boolean affect)
+fixed_t P_GetMobjGravity(mobj_t *mo)
 {
 	fixed_t gravityadd = 0;
 	boolean no3dfloorgrav = true; // Custom gravity
@@ -1279,25 +1278,23 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 
 		for (rover = mo->subsector->sector->ffloors; rover; rover = rover->next)
 		{
-			if (!(rover->flags & FF_EXISTS))
+			if (!(rover->flags & FF_EXISTS) || !P_InsideANonSolidFFloor(mo, rover)) // P_InsideANonSolidFFloor checks for FF_EXISTS itself, but let's not always call this function
 				continue;
 
-			if (P_InsideANonSolidFFloor(mo, rover))
-			{
-				if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
-					goopgravity = true;
-				if (rover->master->frontsector->gravity)
-				{
-					gravityadd = -FixedMul(gravity,
-						(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+			if ((rover->flags & (FF_SWIMMABLE|FF_GOOWATER)) == (FF_SWIMMABLE|FF_GOOWATER))
+				goopgravity = true;
 
-					if (rover->master->frontsector->verticalflip && gravityadd > 0)
-						mo->eflags |= MFE_VERTICALFLIP;
+			if (!(rover->master->frontsector->gravity))
+				continue;
 
-					no3dfloorgrav = false;
-					break;
-				}
-			}
+			gravityadd = -FixedMul(gravity,
+				(FixedDiv(*rover->master->frontsector->gravity>>FRACBITS, 1000)));
+
+			if (rover->master->frontsector->verticalflip && gravityadd > 0)
+				mo->eflags |= MFE_VERTICALFLIP;
+
+			no3dfloorgrav = false;
+			break;
 		}
 	}
 
@@ -1317,33 +1314,22 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 	if (mo->eflags & MFE_UNDERWATER && !goopgravity)
 		gravityadd = gravityadd/3;
 
-	if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
-		gravityadd <<= 1;
-
 	if (mo->player)
 	{
-		if (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
-		|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4])))
-			gravityadd = gravityadd/3; // less gravity while flying
-		if (mo->player->pflags & PF_GLIDING)
-			gravityadd = gravityadd/3; // less gravity while gliding
-		if (mo->player->climbing)
-			gravityadd = 0;
-		if (mo->player->pflags & PF_NIGHTSMODE)
+		if ((mo->player->pflags & PF_GLIDING)
+		|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
+			|| (mo->state >= &states[S_PLAY_SPC1] && mo->state <= &states[S_PLAY_SPC4]))))
+			gravityadd = gravityadd/3; // less gravity while flying/gliding
+		if (mo->player->climbing || (mo->player->pflags & PF_NIGHTSMODE))
 			gravityadd = 0;
 
+		if (!(mo->flags2 & MF2_OBJECTFLIP) != !(mo->player->powers[pw_gravityboots])) // negated to turn numeric into bool - would be double negated, but not needed if both would be
 		{
-			UINT8 bits = 0;
-			if (mo->flags2 & MF2_OBJECTFLIP)
-				bits ^= 1;
-			if (mo->player->powers[pw_gravityboots])
-				bits ^= 1;
-			if (bits & 1)
-			{
-				gravityadd = -gravityadd;
-				mo->eflags ^= MFE_VERTICALFLIP;
-			}
+			gravityadd = -gravityadd;
+			mo->eflags ^= MFE_VERTICALFLIP;
 		}
+		if (wasflip == !(mo->eflags & MFE_VERTICALFLIP)) // note!! == ! is not equivalent to != here - turns numeric into bool this way
+			P_PlayerFlip(mo);
 	}
 	else
 	{
@@ -1351,10 +1337,10 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 		if (mo->flags2 & MF2_OBJECTFLIP)
 		{
 			mo->eflags |= MFE_VERTICALFLIP;
-			if (gravityadd < 0) // Don't sink, only rise up
-				gravityadd *= -1;
 			if (mo->z + mo->height >= mo->ceilingz)
 				gravityadd = 0;
+			else if (gravityadd < 0) // Don't sink, only rise up
+				gravityadd *= -1;
 		}
 		else //Otherwise, sort through the other exceptions.
 		{
@@ -1400,11 +1386,27 @@ void P_CheckGravity(mobj_t *mo, boolean affect)
 	if (goopgravity)
 		gravityadd = -gravityadd/5;
 
-	if (affect)
-		mo->momz += FixedMul(gravityadd, mo->scale);
+	gravityadd = FixedMul(gravityadd, mo->scale);
+
+	return gravityadd;
+}
+
+//
+// P_CheckGravity
+//
+// Checks the current gravity state
+// of the object. If affect is true,
+// a gravity force will be applied.
+//
+void P_CheckGravity(mobj_t *mo, boolean affect)
+{
+	fixed_t gravityadd = P_GetMobjGravity(mo);
 
-	if (mo->player && !!(mo->eflags & MFE_VERTICALFLIP) != wasflip)
-		P_PlayerFlip(mo);
+	if (!mo->momz) // mobj at stop, no floor, so feel the push of gravity!
+		gravityadd <<= 1;
+
+	if (affect)
+		mo->momz += gravityadd;
 
 	if (mo->type == MT_SKIM && mo->z + mo->momz <= mo->watertop && mo->z >= mo->watertop)
 	{
@@ -1480,7 +1482,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy)
 		    && abs(player->rmomy) < FixedMul(STOPSPEED, mo->scale)
 		    && (!(player->cmd.forwardmove && !(twodlevel || mo->flags2 & MF2_TWOD)) && !player->cmd.sidemove && !(player->pflags & PF_SPINNING))
 #ifdef ESLOPE
-			&& !(player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+			&& !(player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && (abs(player->mo->standingslope->zdelta) >= FRACUNIT/2))
 #endif
 				)
 		{
@@ -1530,7 +1532,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 	mo->y += mo->momy;
 	P_SetThingPosition(mo);
 
-	for (node = mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -1538,6 +1540,7 @@ static void P_PushableCheckBustables(mobj_t *mo)
 		if (node->m_sector->ffloors)
 		{
 			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 			{
@@ -1550,37 +1553,39 @@ static void P_PushableCheckBustables(mobj_t *mo)
 
 				if (!rover->master->frontsector->crumblestate)
 				{
+					topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
+					bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL);
 					// Height checks
 					if (rover->flags & FF_SHATTERBOTTOM)
 					{
-						if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+						if (mo->z+mo->momz + mo->height < bottomheight)
 							continue;
 
-						if (mo->z+mo->height > *rover->bottomheight)
+						if (mo->z+mo->height > bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SPINBUST)
 					{
-						if (mo->z+mo->momz > *rover->topheight)
+						if (mo->z+mo->momz > topheight)
 							continue;
 
-						if (mo->z+mo->height < *rover->bottomheight)
+						if (mo->z+mo->height < bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SHATTER)
 					{
-						if (mo->z+mo->momz > *rover->topheight)
+						if (mo->z+mo->momz > topheight)
 							continue;
 
-						if (mo->z+mo->momz + mo->height < *rover->bottomheight)
+						if (mo->z+mo->momz + mo->height < bottomheight)
 							continue;
 					}
 					else
 					{
-						if (mo->z >= *rover->topheight)
+						if (mo->z >= topheight)
 							continue;
 
-						if (mo->z+mo->height < *rover->bottomheight)
+						if (mo->z+mo->height < bottomheight)
 							continue;
 					}
 
@@ -1635,8 +1640,6 @@ void P_XYMovement(mobj_t *mo)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-	moved = true;
-
 	// if it's stopped
 	if (!mo->momx && !mo->momy)
 	{
@@ -1693,9 +1696,9 @@ void P_XYMovement(mobj_t *mo)
 	if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true) && !(mo->eflags & MFE_SPRUNG))
 	{
 		// blocked move
+		moved = false;
 
 		if (player) {
-			moved = false;
 			if (player->bot)
 				B_MoveBlocked(player);
 		}
@@ -1800,7 +1803,7 @@ void P_XYMovement(mobj_t *mo)
 		else
 			mo->momx = mo->momy = 0;
 	}
-	else if (player)
+	else
 		moved = true;
 
 	if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;;
@@ -2013,12 +2016,14 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp
 		delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2));
 		delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2));
 		if (topheight > mo->floorz && abs(delta1) < abs(delta2)
-			&& !(rover->flags & FF_REVERSEPLATFORM))
+			&& !(rover->flags & FF_REVERSEPLATFORM)
+			&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference)
 		{
 			mo->floorz = topheight;
 		}
 		if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2)
-			&& !(rover->flags & FF_PLATFORM))
+			&& !(rover->flags & FF_PLATFORM)
+			&& ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below
 		{
 			mo->ceilingz = bottomheight;
 		}
@@ -2152,16 +2157,6 @@ static boolean P_ZMovement(mobj_t *mo)
 	I_Assert(mo != NULL);
 	I_Assert(!P_MobjWasRemoved(mo));
 
-#ifdef ESLOPE
-	if (mo->standingslope)
-	{
-		if (mo->flags & MF_NOCLIPHEIGHT)
-			mo->standingslope = NULL;
-		else if (!P_IsObjectOnGround(mo))
-			P_SlopeLaunch(mo);
-	}
-#endif
-
 	// Intercept the stupid 'fall through 3dfloors' bug
 	if (mo->subsector->sector->ffloors)
 		P_AdjustMobjFloorZ_FFloors(mo, mo->subsector->sector, 0);
@@ -2176,6 +2171,16 @@ static boolean P_ZMovement(mobj_t *mo)
 	}
 	mo->z += mo->momz;
 
+#ifdef ESLOPE
+	if (mo->standingslope)
+	{
+		if (mo->flags & MF_NOCLIPHEIGHT)
+			mo->standingslope = NULL;
+		else if (!P_IsObjectOnGround(mo))
+			P_SlopeLaunch(mo);
+	}
+#endif
+
 	switch (mo->type)
 	{
 		case MT_THROWNBOUNCE:
@@ -2245,6 +2250,7 @@ static boolean P_ZMovement(mobj_t *mo)
 		case MT_BLUETEAMRING:
 		case MT_FLINGRING:
 		case MT_FLINGCOIN:
+		case MT_FLINGEMERALD:
 			// Remove flinged stuff from death pits.
 			if (P_CheckDeathPitCollide(mo))
 			{
@@ -2276,7 +2282,6 @@ static boolean P_ZMovement(mobj_t *mo)
 			if (!(mo->momx || mo->momy || mo->momz))
 				return true;
 			break;
-		case MT_FLINGEMERALD:
 		case MT_NIGHTSWING:
 			if (!(mo->momx || mo->momy || mo->momz))
 				return true;
@@ -2358,14 +2363,17 @@ static boolean P_ZMovement(mobj_t *mo)
 			mo->z = mo->floorz;
 
 #ifdef ESLOPE
+		if (!(mo->flags & MF_MISSILE) && mo->standingslope) // You're still on the ground; why are we here?
+		{
+			mo->momz = 0;
+			return true;
+		}
+
 		P_CheckPosition(mo, mo->x, mo->y); // Sets mo->standingslope correctly
-		if ((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) {
+		if (((mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope) && (mo->type != MT_STEAM))
+		{
 			mo->standingslope = (mo->eflags & MFE_VERTICALFLIP) ? tmceilingslope : tmfloorslope;
-
-			// Reverse quantizing might could use its own function later
-			mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
-			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
-			mo->standingslope->zangle = ANGLE_MAX-mo->standingslope->zangle;
+			P_ReverseQuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif
 
@@ -2518,7 +2526,7 @@ static boolean P_ZMovement(mobj_t *mo)
 			mom.z = tmfloorthing->momz;
 
 #ifdef ESLOPE
-		if (mo->standingslope) {
+		if (mo->standingslope) { // MT_STEAM will never have a standingslope, see above.
 			P_QuantizeMomentumToSlope(&mom, mo->standingslope);
 		}
 #endif
@@ -2703,7 +2711,7 @@ static void P_PlayerZMovement(mobj_t *mo)
 					msecnode_t *node;
 					boolean stopmovecut = false;
 
-					for (node = mo->touching_sectorlist; node; node = node->m_snext)
+					for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 					{
 						sector_t *sec = node->m_sector;
 						subsector_t *newsubsec;
@@ -2880,7 +2888,7 @@ nightsdone:
 			if (CheckForMarioBlocks && !(netgame && mo->player->spectator)) // Only let the player punch
 			{
 				// Search the touching sectors, from side-to-side...
-				for (node = mo->touching_sectorlist; node; node = node->m_snext)
+				for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 				{
 					ffloor_t *rover;
 					if (!node->m_sector->ffloors)
@@ -3648,7 +3656,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	if (!(netgame && mobj->player->spectator))
 	{
 		// Crumbling platforms
-		for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+		for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			fixed_t topheight, bottomheight;
 			ffloor_t *rover;
@@ -3673,7 +3681,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 	{
 		boolean thereiswater = false;
 
-		for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+		for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			if (node->m_sector->ffloors)
 			{
@@ -3694,7 +3702,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj)
 		}
 		if (thereiswater)
 		{
-			for (node = mobj->touching_sectorlist; node; node = node->m_snext)
+			for (node = mobj->touching_sectorlist; node; node = node->m_sectorlist_next)
 			{
 				if (node->m_sector->ffloors)
 				{
@@ -3807,7 +3815,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
 
 	sector->moved = true; // Recalc lighting and things too, maybe
 
-	for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_snext)
+	for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
 		CalculatePrecipFloor(psecnode->m_thing);
 }
 
@@ -4428,7 +4436,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
 {
 	INT32 s;
 	mobj_t *base = mobj, *seg;
-	fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
+	fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
 	while ((base = base->tracer))
 	{
 		for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
@@ -4442,7 +4450,7 @@ static void P_Boss4PinchSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
 {
 	INT32 s;
 	mobj_t *base = mobj, *seg;
-	fixed_t dist, bz = (mobj->spawnpoint->z+16)<<FRACBITS;
+	fixed_t dist, bz = mobj->watertop+(16<<FRACBITS);
 	while ((base = base->tracer))
 	{
 		for (seg = base, dist = 112*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 132*FRACUNIT, --s)
@@ -4558,7 +4566,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
 			INT32 i, arm;
 			mobj_t *seg, *base = mobj;
 			// First frame init, spawn all the things.
-			mobj->spawnpoint->z = mobj->z>>FRACBITS;
+			mobj->watertop = mobj->z;
 			z = mobj->z + mobj->height/2 - mobjinfo[MT_EGGMOBILE4_MACE].height/2;
 			for (arm = 0; arm <3 ; arm++)
 			{
@@ -4614,7 +4622,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
 	case 3:
 	{
 		fixed_t z;
-		if (mobj->z < (mobj->spawnpoint->z+512)<<FRACBITS)
+		if (mobj->z < mobj->watertop+(512<<FRACBITS))
 			mobj->momz = 8*FRACUNIT;
 		else
 		{
@@ -4623,7 +4631,7 @@ static void P_Boss4Thinker(mobj_t *mobj)
 		}
 		mobj->movecount += 400<<(FRACBITS>>1);
 		mobj->movecount %= 360*FRACUNIT;
-		z = mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
+		z = mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2;
 		if (z < 0) // We haven't risen high enough to pull the spikeballs along yet
 			P_Boss4MoveSpikeballs(mobj, FixedAngle(mobj->movecount), 0); // So don't pull the spikeballs along yet.
 		else
@@ -4633,13 +4641,13 @@ static void P_Boss4Thinker(mobj_t *mobj)
 	// Pinch phase!
 	case 4:
 	{
-		if (mobj->z < (mobj->spawnpoint->z+512+128*(mobj->info->damage-mobj->health))<<FRACBITS)
+		if (mobj->z < (mobj->watertop + ((512+128*(mobj->info->damage-mobj->health))<<FRACBITS)))
 			mobj->momz = 8*FRACUNIT;
 		else
 			mobj->momz = 0;
 		mobj->movecount += (800+800*(mobj->info->damage-mobj->health))<<(FRACBITS>>1);
 		mobj->movecount %= 360*FRACUNIT;
-		P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - (mobj->spawnpoint->z<<FRACBITS) - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
+		P_Boss4PinchSpikeballs(mobj, FixedAngle(mobj->movecount), mobj->z - mobj->watertop - mobjinfo[MT_EGGMOBILE4_MACE].height - mobj->height/2);
 
 		if (!mobj->target || !mobj->target->health)
 			P_SupermanLook4Players(mobj);
@@ -6040,6 +6048,8 @@ void P_RunOverlays(void)
 		P_UnsetThingPosition(mo);
 		mo->x = destx;
 		mo->y = desty;
+		mo->radius = mo->target->radius;
+		mo->height = mo->target->height;
 		if (mo->eflags & MFE_VERTICALFLIP)
 			mo->z = (mo->target->z + mo->target->height - mo->height) - zoffs;
 		else
@@ -6638,6 +6648,18 @@ void P_MobjThinker(mobj_t *mobj)
 		}
 	else switch (mobj->type)
 	{
+		case MT_FALLINGROCK:
+			// Despawn rocks here in case zmovement code can't do so (blame slopes)
+			if (!mobj->momx && !mobj->momy && !mobj->momz
+			&& ((mobj->eflags & MFE_VERTICALFLIP) ?
+				  mobj->z + mobj->height >= mobj->ceilingz
+				: mobj->z <= mobj->floorz))
+			{
+				P_RemoveMobj(mobj);
+				return;
+			}
+			P_MobjCheckWater(mobj);
+			break;
 		case MT_EMERALDSPAWN:
 			if (mobj->threshold)
 			{
@@ -6917,6 +6939,7 @@ void P_MobjThinker(mobj_t *mobj)
 					{
 						mobj->flags &= ~MF_NOGRAVITY;
 						P_SetMobjState(mobj, S_NIGHTSDRONE1);
+						mobj->flags2 |= MF2_DONTDRAW;
 					}
 				}
 				else if (mobj->tracer && mobj->tracer->player)
@@ -7674,6 +7697,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 
 		if (mobj->type == MT_UNIDUS)
 			mobj->z -= FixedMul(mobj->info->mass, mobj->scale);
+
+		// defaults onground
+		if (mobj->z + mobj->height == mobj->ceilingz)
+			mobj->eflags |= MFE_ONGROUND;
 	}
 	else
 		mobj->z = z;
@@ -7780,6 +7807,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
 			break;
 		case MT_EGGCAPSULE:
 			mobj->extravalue1 = -1; // timer for how long a player has been at the capsule
+			break;
 		case MT_REDTEAMRING:
 			mobj->color = skincolor_redteam;
 			break;
diff --git a/src/p_mobj.h b/src/p_mobj.h
index 9542ce8ba1e26fc3bad29d3970f165c88dc1aa9b..79cffae894651ef5a0d31f1583b24d748f8f8b14 100644
--- a/src/p_mobj.h
+++ b/src/p_mobj.h
@@ -441,7 +441,7 @@ boolean P_SupermanLook4Players(mobj_t *actor);
 void P_DestroyRobots(void);
 void P_SnowThinker(precipmobj_t *mobj);
 void P_RainThinker(precipmobj_t *mobj);
-void P_NullPrecipThinker(precipmobj_t *mobj);
+FUNCMATH void P_NullPrecipThinker(precipmobj_t *mobj);
 void P_RemovePrecipMobj(precipmobj_t *mobj);
 void P_SetScale(mobj_t *mobj, fixed_t newscale);
 void P_XYMovement(mobj_t *mo);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index 5e457ca3ab30a62f354ff908f0cbb29bcf7eda6c..75f7b3e514e53cb250b40f1969f7b02a3b4d5126 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -460,6 +460,7 @@ static void P_NetUnArchivePlayers(void)
 #define SD_TAG       0x10
 #define SD_FLOORANG  0x20
 #define SD_CEILANG   0x40
+#define SD_TAGLIST   0x80
 
 #define LD_FLAG     0x01
 #define LD_SPECIAL  0x02
@@ -509,10 +510,9 @@ static void P_NetArchiveWorld(void)
 		//
 		// flats
 		//
-		// P_AddLevelFlat should not add but just return the number
-		if (ss->floorpic != P_AddLevelFlat(ms->floorpic, levelflats))
+		if (ss->floorpic != P_CheckLevelFlat(ms->floorpic))
 			diff |= SD_FLOORPIC;
-		if (ss->ceilingpic != P_AddLevelFlat(ms->ceilingpic, levelflats))
+		if (ss->ceilingpic != P_CheckLevelFlat(ms->ceilingpic))
 			diff |= SD_CEILPIC;
 
 		if (ss->lightlevel != SHORT(ms->lightlevel))
@@ -535,6 +535,8 @@ static void P_NetArchiveWorld(void)
 
 		if (ss->tag != SHORT(ms->tag))
 			diff2 |= SD_TAG;
+		if (ss->nexttag != ss->spawn_nexttag || ss->firsttag != ss->spawn_firsttag)
+			diff2 |= SD_TAGLIST;
 
 		// Check if any of the sector's FOFs differ from how they spawned
 		if (ss->ffloors)
@@ -582,16 +584,17 @@ static void P_NetArchiveWorld(void)
 				WRITEFIXED(put, ss->ceiling_xoffs);
 			if (diff2 & SD_CYOFFS)
 				WRITEFIXED(put, ss->ceiling_yoffs);
-			if (diff2 & SD_TAG)
-			{
+			if (diff2 & SD_TAG) // save only the tag
 				WRITEINT16(put, ss->tag);
-				WRITEINT32(put, ss->firsttag);
-				WRITEINT32(put, ss->nexttag);
-			}
 			if (diff2 & SD_FLOORANG)
 				WRITEANGLE(put, ss->floorpic_angle);
 			if (diff2 & SD_CEILANG)
 				WRITEANGLE(put, ss->ceilingpic_angle);
+			if (diff2 & SD_TAGLIST) // save both firsttag and nexttag
+			{ // either of these could be changed even if tag isn't
+				WRITEINT32(put, ss->firsttag);
+				WRITEINT32(put, ss->nexttag);
+			}
 
 			// Special case: save the stats of all modified ffloors along with their ffloor "number"s
 			// we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed
@@ -752,12 +755,12 @@ static void P_NetUnArchiveWorld(void)
 			sectors[i].ceilingheight = READFIXED(get);
 		if (diff & SD_FLOORPIC)
 		{
-			sectors[i].floorpic = P_AddLevelFlat((char *)get, levelflats);
+			sectors[i].floorpic = P_AddLevelFlatRuntime((char *)get);
 			get += 8;
 		}
 		if (diff & SD_CEILPIC)
 		{
-			sectors[i].ceilingpic = P_AddLevelFlat((char *)get, levelflats);
+			sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)get);
 			get += 8;
 		}
 		if (diff & SD_LIGHT)
@@ -774,12 +777,11 @@ static void P_NetUnArchiveWorld(void)
 		if (diff2 & SD_CYOFFS)
 			sectors[i].ceiling_yoffs = READFIXED(get);
 		if (diff2 & SD_TAG)
+			sectors[i].tag = READINT16(get); // DON'T use P_ChangeSectorTag
+		if (diff2 & SD_TAGLIST)
 		{
-			INT16 tag;
-			tag = READINT16(get);
 			sectors[i].firsttag = READINT32(get);
 			sectors[i].nexttag = READINT32(get);
-			P_ChangeSectorTag(i, tag);
 		}
 		if (diff2 & SD_FLOORANG)
 			sectors[i].floorpic_angle  = READANGLE(get);
@@ -2607,6 +2609,7 @@ static void P_NetUnArchiveThinkers(void)
 	thinker_t *next;
 	UINT8 tclass;
 	UINT8 restoreNum = false;
+	UINT32 i;
 
 	if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS)
 		I_Error("Bad $$$.sav at archive block Thinkers");
@@ -2627,6 +2630,12 @@ static void P_NetUnArchiveThinkers(void)
 	iquetail = iquehead = 0;
 	P_InitThinkers();
 
+	// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
+	for (i = 0; i < numsectors; i++)
+	{
+		sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = NULL;
+	}
+
 	// read in saved thinkers
 	for (;;)
 	{
@@ -3285,7 +3294,7 @@ void P_SaveNetGame(void)
 {
 	thinker_t *th;
 	mobj_t *mobj;
-	INT32 i = 0;
+	INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
 
 	CV_SaveNetVars(&save_p);
 	P_NetArchiveMisc();
diff --git a/src/p_setup.c b/src/p_setup.c
index b36bf0b809c877ba06f86dba599e5564a71bae8a..8e746457be9216e8fec73e43bc2dbc24a0d5ea6e 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -574,6 +574,69 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
 	return (INT32)i;
 }
 
+// help function for Lua and $$$.sav reading
+// same as P_AddLevelFlat, except this is not setup so we must realloc levelflats to fit in the new flat
+// no longer a static func in lua_maplib.c because p_saveg.c also needs it
+//
+INT32 P_AddLevelFlatRuntime(const char *flatname)
+{
+	size_t i;
+	levelflat_t *levelflat = levelflats;
+
+	//
+	//  first scan through the already found flats
+	//
+	for (i = 0; i < numlevelflats; i++, levelflat++)
+		if (strnicmp(levelflat->name,flatname,8)==0)
+			break;
+
+	// that flat was already found in the level, return the id
+	if (i == numlevelflats)
+	{
+		// allocate new flat memory
+		levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
+		levelflat = levelflats+i;
+
+		// store the name
+		strlcpy(levelflat->name, flatname, sizeof (levelflat->name));
+		strupr(levelflat->name);
+
+		// store the flat lump number
+		levelflat->lumpnum = R_GetFlatNumForName(flatname);
+
+#ifndef ZDEBUG
+		CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
+#endif
+
+		numlevelflats++;
+	}
+
+	// level flat id
+	return (INT32)i;
+}
+
+// help function for $$$.sav checking
+// this simply returns the flat # for the name given
+//
+INT32 P_CheckLevelFlat(const char *flatname)
+{
+	size_t i;
+	levelflat_t *levelflat = levelflats;
+
+	//
+	//  scan through the already found flats
+	//
+	for (i = 0; i < numlevelflats; i++, levelflat++)
+		if (strnicmp(levelflat->name,flatname,8)==0)
+			break;
+
+	if (i == numlevelflats)
+		return 0; // ??? flat was not found, this should not happen!
+
+	// level flat id
+	return (INT32)i;
+}
+
 static void P_LoadSectors(lumpnum_t lumpnum)
 {
 	UINT8 *data;
@@ -614,6 +677,7 @@ static void P_LoadSectors(lumpnum_t lumpnum)
 		ss->special = SHORT(ms->special);
 		ss->tag = SHORT(ms->tag);
 		ss->nexttag = ss->firsttag = -1;
+		ss->spawn_nexttag = ss->spawn_firsttag = -1;
 
 		memset(&ss->soundorg, 0, sizeof(ss->soundorg));
 		ss->validcount = 0;
@@ -1931,10 +1995,18 @@ static void P_GroupLines(void)
 	// allocate linebuffers for each sector
 	for (i = 0, sector = sectors; i < numsectors; i++, sector++)
 	{
-		sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
+		if (sector->linecount == 0) // no lines found?
+		{
+			sector->lines = NULL;
+			CONS_Debug(DBG_SETUP, "P_GroupLines: sector %s has no lines\n", sizeu1(i));
+		}
+		else
+		{
+			sector->lines = Z_Calloc(sector->linecount * sizeof(line_t*), PU_LEVEL, NULL);
 
-		// zero the count, since we'll later use this to track how many we've recorded
-		sector->linecount = 0;
+			// zero the count, since we'll later use this to track how many we've recorded
+			sector->linecount = 0;
+		}
 	}
 
 	// iterate through lines, assigning them to sectors' linebuffers,
@@ -1952,11 +2024,14 @@ static void P_GroupLines(void)
 	{
 		M_ClearBox(bbox);
 
-		for (j = 0; j < sector->linecount; j++)
+		if (sector->linecount != 0)
 		{
-			li = sector->lines[j];
-			M_AddToBox(bbox, li->v1->x, li->v1->y);
-			M_AddToBox(bbox, li->v2->x, li->v2->y);
+			for (j = 0; j < sector->linecount; j++)
+			{
+				li = sector->lines[j];
+				M_AddToBox(bbox, li->v1->x, li->v1->y);
+				M_AddToBox(bbox, li->v2->x, li->v2->y);
+			}
 		}
 
 		// set the degenmobj_t to the middle of the bounding box
@@ -1966,6 +2041,35 @@ static void P_GroupLines(void)
 	}
 }
 
+//
+// P_LoadReject
+//
+// Detect if the REJECT lump is valid,
+// if not, rejectmatrix will be NULL
+static void P_LoadReject(lumpnum_t lumpnum)
+{
+	size_t count;
+	const char *lumpname = W_CheckNameForNum(lumpnum);
+
+	// Check if the lump exists, and if it's named "REJECT"
+	if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n");
+		return;
+	}
+
+	count = W_LumpLength(lumpnum);
+
+	if (!count) // zero length, someone probably used ZDBSP
+	{
+		rejectmatrix = NULL;
+		CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n");
+	}
+	else
+		rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
+}
+
 #if 0
 static char *levellumps[] =
 {
@@ -2545,11 +2649,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	lastloadedmaplumpnum = W_GetNumForName(maplumpname = G_BuildMapName(gamemap));
 
 	R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
-	CON_ReSetupBackColormap(mapheaderinfo[gamemap-1]->palette);
-
-	// now part of level loading since in future each level may have
-	// its own anim texture sequences, switches etc.
-	P_InitPicAnims();
+	CON_SetupBackColormap();
 
 	// SRB2 determines the sky texture to be used depending on the map header.
 	P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
@@ -2574,7 +2674,7 @@ boolean P_SetupLevel(boolean skipprecip)
 	P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
 	P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
 	P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
-	rejectmatrix = W_CacheLumpNum(lastloadedmaplumpnum + ML_REJECT, PU_LEVEL);
+	P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
 	P_GroupLines();
 
 	numdmstarts = numredctfstarts = numbluectfstarts = 0;
@@ -2961,6 +3061,9 @@ boolean P_AddWadFile(const char *wadfilename, char **firstmapname)
 	else
 		R_FlushTextureCache(); // just reload it from file
 
+	// Reload ANIMATED / ANIMDEFS
+	P_InitPicAnims();
+
 	// Flush and reload HUD graphics
 	ST_UnloadGraphics();
 	HU_LoadGraphics();
diff --git a/src/p_setup.h b/src/p_setup.h
index 0d735fd71caa8813f6a9c50660efdc753a8c305a..3bca11047c7cf43a8fc1dd535de0d23d46ed6d49 100644
--- a/src/p_setup.h
+++ b/src/p_setup.h
@@ -47,6 +47,8 @@ typedef struct
 extern size_t numlevelflats;
 extern levelflat_t *levelflats;
 INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
+INT32 P_AddLevelFlatRuntime(const char *flatname);
+INT32 P_CheckLevelFlat(const char *flatname);
 
 extern size_t nummapthings;
 extern mapthing_t *mapthings;
diff --git a/src/p_sight.c b/src/p_sight.c
index 14c1c945fb9ec0a551fcf77a19bbe4764d23ad7f..bd6ab4d730f308973b011af421f147384ecbd648 100644
--- a/src/p_sight.c
+++ b/src/p_sight.c
@@ -325,9 +325,12 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
 	s2 = t2->subsector->sector;
 	pnum = (s1-sectors)*numsectors + (s2-sectors);
 
-	// Check in REJECT table.
-	if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
-		return false;
+	if (rejectmatrix != NULL)
+	{
+		// Check in REJECT table.
+		if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
+			return false;
+	}
 
 	// killough 11/98: shortcut for melee situations
 	// same subsector? obviously visible
diff --git a/src/p_slopes.c b/src/p_slopes.c
index 6393ca4b558514e0616dc0423f60d899e29342c9..d939fee98b9cb36f015da6cb187131acc6407eb6 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -199,7 +199,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
 
 	// Find furthest vertex from the reference line. It, along with the two ends
 	// of the line, will define the plane.
-	// SRB2CBTODO: Use a formula to get the slope to slide objects depending on how steep
 	for(i = 0; i < sector->linecount; i++)
 	{
 		line_t *li = sector->lines[i];
@@ -231,7 +230,6 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
 //
 // Creates one or more slopes based on the given line type and front/back
 // sectors.
-// Kalaron: Check if dynamic slopes need recalculation
 //
 void P_SpawnSlope_Line(int linenum)
 {
@@ -276,7 +274,6 @@ void P_SpawnSlope_Line(int linenum)
 		ny = -FixedDiv(line->dx, len);
 	}
 
-	// SRB2CBTODO: Transform origin relative to the bounds of an individual FOF
 	origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
 	origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
 
@@ -327,7 +324,7 @@ void P_SpawnSlope_Line(int linenum)
 			// fslope->normal is a 3D line perpendicular to the 3D vector
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			fslope->sourceline = line;
 
 			// To find the real highz/lowz of a slope, you need to check all the vertexes
@@ -379,7 +376,7 @@ void P_SpawnSlope_Line(int linenum)
             cslope->refpos = 2;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			cslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -445,7 +442,7 @@ void P_SpawnSlope_Line(int linenum)
             fslope->refpos = 3;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			fslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -488,7 +485,7 @@ void P_SpawnSlope_Line(int linenum)
             cslope->refpos = 4;
 
 			// Sync the linedata of the line that started this slope
-			// SRB2CBTODO: Anything special for remote(control sector)-based slopes later?
+			// TODO: Anything special for control sector based slopes later?
 			cslope->sourceline = line;
 
 			// Remember the way the slope is formed
@@ -554,16 +551,11 @@ static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
 			ret->vertices[2] = mt;
 	}
 
-	if (!ret->vertices[0])
-		CONS_Printf("PANIC 0\n");
-	if (!ret->vertices[1])
-		CONS_Printf("PANIC 1\n");
-	if (!ret->vertices[2])
-		CONS_Printf("PANIC 2\n");
-
 	// Now set heights for each vertex, because they haven't been set yet
 	for (i = 0; i < 3; i++) {
 		mt = ret->vertices[i];
+		if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
+			I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
 		if (mt->extrainfo)
 			mt->z = mt->options;
 		else
@@ -623,265 +615,10 @@ pslope_t *P_SlopeById(UINT16 id)
 	return ret;
 }
 
-#ifdef SPRINGCLEAN
-#include "byteptr.h"
-
-#include "p_setup.h"
-#include "p_local.h"
-
-//==========================================================================
-//
-//	P_SetSlopesFromVertexHeights
-//
-//==========================================================================
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum)
-{
-	mapthing_t *mt;
-	boolean vt_found = false;
-	size_t i, j, k, l, q;
-
-	//size_t i;
-	//mapthing_t *mt;
-	char *data;
-	char *datastart;
-
-	// SRB2CBTODO: WHAT IS (5 * sizeof (short))?! It = 10
-	// anything else seems to make a map not load properly,
-	// but this hard-coded value MUST have some reason for being what it is
-	size_t snummapthings = W_LumpLength(lumpnum) / (5 * sizeof (short));
-	mapthing_t *smapthings = Z_Calloc(snummapthings * sizeof (*smapthings), PU_LEVEL, NULL);
-	fixed_t x, y;
-	sector_t *sector;
-	// Spawn axis points first so they are
-	// at the front of the list for fast searching.
-	data = datastart = W_CacheLumpNum(lumpnum, PU_LEVEL);
-	mt = smapthings;
-	for (i = 0; i < snummapthings; i++, mt++)
-	{
-		mt->x = READINT16(data);
-		mt->y = READINT16(data);
-		mt->angle = READINT16(data);
-		mt->type = READINT16(data);
-		mt->options = READINT16(data);
-		// mt->z hasn't been set yet!
-		//mt->extrainfo = (byte)(mt->type >> 12); // slope things are special, they have a bigger range of types
-
-		//mt->type &= 4095; // SRB2CBTODO: WHAT IS THIS???? Mobj type limits?!!!!
-		x = mt->x*FRACUNIT;
-		y = mt->y*FRACUNIT;
-		sector = R_PointInSubsector(x, y)->sector;
-		// Z for objects
-#ifdef ESLOPE
-		if (sector->f_slope)
-			mt->z = (short)(P_GetZAt(sector->f_slope, x, y)>>FRACBITS);
-		else
-#endif
-			mt->z = (short)(sector->floorheight>>FRACBITS);
-
-		mt->z = mt->z + (mt->options >> ZSHIFT);
-
-		if (mt->type == THING_VertexFloorZ || mt->type == THING_VertexCeilingZ) // THING_VertexFloorZ
-		{
-			for(l = 0; l < numvertexes; l++)
-			{
-				if (vertexes[l].x == mt->x*FRACUNIT && vertexes[l].y == mt->y*FRACUNIT)
-				{
-					if (mt->type == THING_VertexFloorZ)
-					{
-						vertexes[l].z = mt->z*FRACUNIT;
-						//I_Error("Z value: %i", vertexes[l].z/FRACUNIT);
-
-					}
-					else
-					{
-						vertexes[l].z = mt->z*FRACUNIT; // celing floor
-					}
-					vt_found = true;
-				}
-			}
-			//mt->type = 0; // VPHYSICS: Dynamic slopes
-
-
-
-
-
-
-			if (vt_found)
-			{
-				for (k = 0; k < numsectors; k++)
-				{
-					sector_t *sec = &sectors[k];
-					if (sec->linecount != 3) continue;	// only works with triangular sectors
-
-					v3float_t vt1, vt2, vt3; // cross = ret->normalf
-					v3float_t vec1, vec2;
-
-					int vi1, vi2, vi3;
-
-					vi1 = (int)(sec->lines[0]->v1 - vertexes);
-					vi2 = (int)(sec->lines[0]->v2 - vertexes);
-					vi3 = (sec->lines[1]->v1 == sec->lines[0]->v1 || sec->lines[1]->v1 == sec->lines[0]->v2)?
-					(int)(sec->lines[1]->v2 - vertexes) : (int)(sec->lines[1]->v1 - vertexes);
-
-					//if (vertexes[vi1].z)
-					//	I_Error("OSNAP %i", vertexes[vi1].z/FRACUNIT);
-					//if (vertexes[vi2].z)
-					//	I_Error("OSNAP %i", vertexes[vi2].z/FRACUNIT);
-					//if (vertexes[vi3].z)
-					//	I_Error("OSNAP %i", vertexes[vi3].z/FRACUNIT);
-
-					//I_Error("%i, %i", mt->z*FRACUNIT, vertexes[vi1].z);
-
-					//I_Error("%i, %i, %i", mt->x, mt->y, mt->z);
-					//P_SpawnMobj(mt->x*FRACUNIT, mt->y*FRACUNIT, mt->z*FRACUNIT, MT_RING);
-
-					// TODO: Make sure not to spawn in the same place 2x! (we need an object in every vertex of the
-					// triangle sector to setup the real vertex slopes
-					// Check for the vertexes of all sectors
-					for(q = 0; q < numvertexes; q++)
-					{
-						if (vertexes[q].x == mt->x*FRACUNIT && vertexes[q].y == mt->y*FRACUNIT)
-						{
-							//I_Error("yeah %i", vertexes[q].z);
-							P_SpawnMobj(vertexes[q].x, vertexes[q].y, vertexes[q].z, MT_RING);
-#if 0
-					if ((mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
-						P_SpawnMobj(vertexes[vi1].x, vertexes[vi1].y, vertexes[vi1].z, MT_RING);
-					else if ((mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z))
-						P_SpawnMobj(vertexes[vi2].x, vertexes[vi2].y, vertexes[vi2].z, MT_BOUNCETV);
-					else if ((mt->y*FRACUNIT == vertexes[vi3].y && mt->x*FRACUNIT == vertexes[vi3].x && mt->z*FRACUNIT == vertexes[vi3].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi2].y && mt->x*FRACUNIT == vertexes[vi2].x && mt->z*FRACUNIT == vertexes[vi2].z)
-						&& !(mt->y*FRACUNIT == vertexes[vi1].y && mt->x*FRACUNIT == vertexes[vi1].x && mt->z*FRACUNIT == vertexes[vi1].z))
-						P_SpawnMobj(vertexes[vi3].x, vertexes[vi3].y, vertexes[vi3].z, MT_GFZFLOWER1);
-					else
-#endif
-						continue;
-						}
-					}
-
-					vt1.x = FIXED_TO_FLOAT(vertexes[vi1].x);
-					vt1.y = FIXED_TO_FLOAT(vertexes[vi1].y);
-					vt2.x = FIXED_TO_FLOAT(vertexes[vi2].x);
-					vt2.y = FIXED_TO_FLOAT(vertexes[vi2].y);
-					vt3.x = FIXED_TO_FLOAT(vertexes[vi3].x);
-					vt3.y = FIXED_TO_FLOAT(vertexes[vi3].y);
-
-					for(j = 0; j < 2; j++)
-					{
-
-						fixed_t z3;
-						//I_Error("Lo hicimos");
-
-						vt1.z = mt->z;//FIXED_TO_FLOAT(j==0 ? sec->floorheight : sec->ceilingheight);
-						vt2.z = mt->z;//FIXED_TO_FLOAT(j==0? sec->floorheight : sec->ceilingheight);
-						z3 = mt->z;//j==0? sec->floorheight : sec->ceilingheight; // Destination height
-						vt3.z = FIXED_TO_FLOAT(z3);
-
-						if (P_PointOnLineSide(vertexes[vi3].x, vertexes[vi3].y, sec->lines[0]) == 0)
-						{
-							vec1.x = vt2.x - vt3.x;
-							vec1.y = vt2.y - vt3.y;
-							vec1.z = vt2.z - vt3.z;
-
-							vec2.x = vt1.x - vt3.x;
-							vec2.y = vt1.y - vt3.y;
-							vec2.z = vt1.z - vt3.z;
-						}
-						else
-						{
-							vec1.x = vt1.x - vt3.x;
-							vec1.y = vt1.y - vt3.y;
-							vec1.z = vt1.z - vt3.z;
-
-							vec2.x = vt2.x - vt3.x;
-							vec2.y = vt2.y - vt3.y;
-							vec2.z = vt2.z - vt3.z;
-						}
-
-
-						pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
-						memset(ret, 0, sizeof(*ret));
-
-						{
-							M_CrossProduct3f(&ret->normalf, &vec1, &vec2);
-
-							// Cross product length
-							float len = (float)sqrt(ret->normalf.x * ret->normalf.x +
-													ret->normalf.y * ret->normalf.y +
-													ret->normalf.z * ret->normalf.z);
-
-							if (len == 0)
-							{
-								// Only happens when all vertices in this sector are on the same line.
-								// Let's just ignore this case.
-								//CONS_Printf("Slope thing at (%d,%d) lies directly on its target line.\n", (int)(x>>16), (int)(y>>16));
-								return;
-							}
-							// cross/len
-							ret->normalf.x /= len;
-							ret->normalf.y /= len;
-							ret->normalf.z /= len;
-
-							// ZDoom cross = ret->normalf
-							// Fix backward normals
-							if ((ret->normalf.z < 0 && j == 0) || (ret->normalf.z > 0 && j == 1))
-							{
-								// cross = -cross
-								ret->normalf.x = -ret->normalf.x;
-								ret->normalf.y = -ret->normalf.x;
-								ret->normalf.z = -ret->normalf.x;
-							}
-						}
-
-						secplane_t *srcplane = Z_Calloc(sizeof(*srcplane), PU_LEVEL, NULL);
-
-						srcplane->a = FLOAT_TO_FIXED (ret->normalf.x);
-						srcplane->b = FLOAT_TO_FIXED (ret->normalf.y);
-						srcplane->c = FLOAT_TO_FIXED (ret->normalf.z);
-						//srcplane->ic = FixedDiv(FRACUNIT, srcplane->c);
-						srcplane->d = -TMulScale16 (srcplane->a, vertexes[vi3].x,
-													srcplane->b, vertexes[vi3].y,
-													srcplane->c, z3);
-
-						if (j == 0)
-						{
-							sec->f_slope = ret;
-							sec->f_slope->secplane = *srcplane;
-						}
-						else if (j == 1)
-						{
-							sec->c_slope = ret;
-							sec->c_slope->secplane = *srcplane;
-						}
-					}
-				}
-			}
-
-
-
-
-
-
-
-
-		}
-	}
-	Z_Free(datastart);
-
-
-
-
-}
-#endif
-
 // Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes
 void P_ResetDynamicSlopes(void) {
 	size_t i;
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
 	boolean warned = false;
 #endif
 
@@ -894,7 +631,7 @@ void P_ResetDynamicSlopes(void) {
 	{
 		switch (lines[i].special)
 		{
-#if 1 // Rewrite old specials to new ones, and give a console warning
+#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
 #define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
 			case 386:
 			case 387:
@@ -1018,7 +755,11 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y)
 // When given a vector, rotates it and aligns it to a slope
 void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
 {
-	vector3_t axis;
+	vector3_t axis; // Fuck you, C90.
+
+	if (slope->flags & SL_NOPHYSICS)
+		return; // No physics, no quantizing.
+
 	axis.x = -slope->d.y;
 	axis.y = slope->d.x;
 	axis.z = 0;
@@ -1026,24 +767,38 @@ void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
 	FV3_Rotate(momentum, &axis, slope->zangle >> ANGLETOFINESHIFT);
 }
 
+//
+// P_ReverseQuantizeMomentumToSlope
+//
+// When given a vector, rotates and aligns it to a flat surface (from being relative to a given slope)
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope)
+{
+	slope->zangle = InvAngle(slope->zangle);
+	P_QuantizeMomentumToSlope(momentum, slope);
+	slope->zangle = InvAngle(slope->zangle);
+}
+
 //
 // P_SlopeLaunch
 //
 // Handles slope ejection for objects
 void P_SlopeLaunch(mobj_t *mo)
 {
-	// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
-	// vertical launch given from slopes while increasing the horizontal launch
-	// given. Good for SRB2's gravity and horizontal speeds.
-	vector3_t slopemom;
-	slopemom.x = mo->momx;
-	slopemom.y = mo->momy;
-	slopemom.z = mo->momz*2;
-	P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
-
-	mo->momx = slopemom.x;
-	mo->momy = slopemom.y;
-	mo->momz = slopemom.z/2;
+	if (!(mo->standingslope->flags & SL_NOPHYSICS)) // If there's physics, time for launching.
+	{
+		// Double the pre-rotation Z, then halve the post-rotation Z. This reduces the
+		// vertical launch given from slopes while increasing the horizontal launch
+		// given. Good for SRB2's gravity and horizontal speeds.
+		vector3_t slopemom;
+		slopemom.x = mo->momx;
+		slopemom.y = mo->momy;
+		slopemom.z = mo->momz*2;
+		P_QuantizeMomentumToSlope(&slopemom, mo->standingslope);
+
+		mo->momx = slopemom.x;
+		mo->momy = slopemom.y;
+		mo->momz = slopemom.z/2;
+	}
 
 	//CONS_Printf("Launched off of slope.\n");
 	mo->standingslope = NULL;
@@ -1052,17 +807,21 @@ void P_SlopeLaunch(mobj_t *mo)
 // Function to help handle landing on slopes
 void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope)
 {
-	vector3_t mom;
+	vector3_t mom; // Ditto.
+
+	if (slope->flags & SL_NOPHYSICS) { // No physics, no need to make anything complicated.
+		if (P_MobjFlip(thing)*(thing->momz) < 0) { // falling, land on slope
+			thing->momz = -P_MobjFlip(thing);
+			thing->standingslope = slope;
+		}
+		return;
+	}
+
 	mom.x = thing->momx;
 	mom.y = thing->momy;
 	mom.z = thing->momz*2;
 
-	//CONS_Printf("langing on slope\n");
-
-	// Reverse quantizing might could use its own function later
-	slope->zangle = ANGLE_MAX-slope->zangle;
-	P_QuantizeMomentumToSlope(&mom, slope);
-	slope->zangle = ANGLE_MAX-slope->zangle;
+	P_ReverseQuantizeMomentumToSlope(&mom, slope);
 
 	if (P_MobjFlip(thing)*mom.z < 0) { // falling, land on slope
 		thing->momx = mom.x;
@@ -1082,6 +841,9 @@ void P_ButteredSlope(mobj_t *mo)
 	if (!mo->standingslope)
 		return;
 
+	if (mo->standingslope->flags & SL_NOPHYSICS)
+		return; // No physics, no butter.
+
 	if (mo->flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY))
 		return; // don't slide down slopes if you can't touch them or you're not affected by gravity
 
@@ -1106,8 +868,6 @@ void P_ButteredSlope(mobj_t *mo)
 			mult = FINECOSINE(angle >> ANGLETOFINESHIFT);
 		}
 
-		//CONS_Printf("%d\n", mult);
-
 		thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8);
 	}
 
@@ -1115,10 +875,11 @@ void P_ButteredSlope(mobj_t *mo)
 		thrust = FixedMul(thrust, FRACUNIT+P_AproxDistance(mo->momx, mo->momy)/16);
 	// This makes it harder to zigzag up steep slopes, as well as allows greater top speed when rolling down
 
-	// Multiply by gravity
-	thrust = FixedMul(thrust, gravity); // TODO account for per-sector gravity etc
-	// Multiply by scale (gravity strength depends on mobj scale)
-	thrust = FixedMul(thrust, mo->scale);
+	// Let's get the gravity strength for the object...
+	thrust = FixedMul(thrust, abs(P_GetMobjGravity(mo)));
+
+	// ... and its friction against the ground for good measure (divided by original friction to keep behaviour for normal slopes the same).
+	thrust = FixedMul(thrust, FixedDiv(mo->friction, ORIG_FRICTION));
 
 	P_Thrust(mo, mo->standingslope->xydirection, thrust);
 }
diff --git a/src/p_slopes.h b/src/p_slopes.h
index 80921a84b49ce9bc38e76f7fdf6186426dc05bd0..de38f1d9ed279be0059a8c0a283a337d8e4e7bb8 100644
--- a/src/p_slopes.h
+++ b/src/p_slopes.h
@@ -21,26 +21,6 @@ void P_RunDynamicSlopes(void);
 // sectors.
 void P_SpawnSlope_Line(int linenum);
 
-#ifdef SPRINGCLEAN
-// Loads just map objects that make slopes,
-// terrain affecting objects have to be spawned first
-void P_SetSlopesFromVertexHeights(lumpnum_t lumpnum);
-
-typedef enum
-{
-	THING_SlopeFloorPointLine = 9500,
-	THING_SlopeCeilingPointLine = 9501,
-	THING_SetFloorSlope = 9502,
-	THING_SetCeilingSlope = 9503,
-	THING_CopyFloorPlane = 9510,
-	THING_CopyCeilingPlane = 9511,
-	THING_VavoomFloor=1500,
-	THING_VavoomCeiling=1501,
-	THING_VertexFloorZ=1504,
-	THING_VertexCeilingZ=1505,
-} slopething_e;
-#endif
-
 //
 // P_CopySectorSlope
 //
@@ -55,6 +35,7 @@ fixed_t P_GetZAt(pslope_t *slope, fixed_t x, fixed_t y);
 
 // Lots of physics-based bullshit
 void P_QuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
+void P_ReverseQuantizeMomentumToSlope(vector3_t *momentum, pslope_t *slope);
 void P_SlopeLaunch(mobj_t *mo);
 void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
 void P_ButteredSlope(mobj_t *mo);
diff --git a/src/p_spec.c b/src/p_spec.c
index fbcb8b4f0eb02417a025cf64384b0d60e5ecf782..48c0f58b3c9cdb3ff6ce8a4e49bd51a7eb7d5c19 100644
--- a/src/p_spec.c
+++ b/src/p_spec.c
@@ -221,8 +221,8 @@ static animdef_t harddefs[] =
 static animdef_t *animdefs = NULL;
 
 // A prototype; here instead of p_spec.h, so they're "private"
-void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i);
-void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
+void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum);
+void P_ParseAnimationDefintion(SINT8 istexture);
 
 /** Sets up texture and flat animations.
   *
@@ -232,24 +232,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i);
   * Issues an error if any animation cycles are invalid.
   *
   * \sa P_FindAnimatedFlat, P_SetupLevelFlatAnims
-  * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs)
+  * \author Steven McGranahan (original), Shadow Hog (had to rewrite it to handle multiple WADs), JTE (had to rewrite it to handle multiple WADs _correctly_)
   */
 void P_InitPicAnims(void)
 {
 	// Init animation
-	INT32 i; // Position in the animdefs array
 	INT32 w; // WAD
-	UINT8 *wadAnimdefs; // not to be confused with animdefs, the combined total of every ANIMATED lump in every WAD, or ANIMDEFS, the ZDoom lump I intend to implement later
+	UINT8 *animatedLump;
 	UINT8 *currentPos;
+	size_t i;
+
+	I_Assert(animdefs == NULL);
 
 	if (W_CheckNumForName("ANIMATED") != LUMPERROR || W_CheckNumForName("ANIMDEFS") != LUMPERROR)
 	{
-		if (animdefs)
-		{
-			Z_Free(animdefs);
-			animdefs = NULL;
-		}
-		for (w = 0, i = 0, maxanims = 0; w < numwadfiles; w++)
+		for (w = numwadfiles-1, maxanims = 0; w >= 0; w--)
 		{
 			UINT16 animatedLumpNum;
 			UINT16 animdefsLumpNum;
@@ -258,20 +255,20 @@ void P_InitPicAnims(void)
 			animatedLumpNum = W_CheckNumForNamePwad("ANIMATED", w, 0);
 			if (animatedLumpNum != INT16_MAX)
 			{
-				wadAnimdefs = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
+				animatedLump = (UINT8 *)W_CacheLumpNumPwad(w, animatedLumpNum, PU_STATIC);
 
 				// Get the number of animations in the file
-				for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
+				i = maxanims;
+				for (currentPos = animatedLump; *currentPos != UINT8_MAX; maxanims++, currentPos+=23);
 
 				// Resize animdefs (or if it hasn't been created, create it)
 				animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
 				// Sanity check it
-				if (!animdefs) {
+				if (!animdefs)
 					I_Error("Not enough free memory for ANIMATED data");
-				}
 
 				// Populate the new array
-				for (currentPos = wadAnimdefs; *currentPos != UINT8_MAX; i++, currentPos+=23)
+				for (currentPos = animatedLump; *currentPos != UINT8_MAX; i++, currentPos+=23)
 				{
 					M_Memcpy(&(animdefs[i].istexture), currentPos, 1); // istexture, 1 byte
 					M_Memcpy(animdefs[i].endname, (currentPos + 1), 9); // endname, 9 bytes
@@ -279,15 +276,13 @@ void P_InitPicAnims(void)
 					M_Memcpy(&(animdefs[i].speed), (currentPos + 19), 4); // speed, 4 bytes
 				}
 
-				Z_Free(wadAnimdefs);
+				Z_Free(animatedLump);
 			}
 
 			// Now find ANIMDEFS
 			animdefsLumpNum = W_CheckNumForNamePwad("ANIMDEFS", w, 0);
 			if (animdefsLumpNum != INT16_MAX)
-			{
-				P_ParseANIMDEFSLump(w, animdefsLumpNum, &i);
-			}
+				P_ParseANIMDEFSLump(w, animdefsLumpNum);
 		}
 		// Define the last one
 		animdefs[maxanims].istexture = -1;
@@ -347,16 +342,20 @@ void P_InitPicAnims(void)
 	lastanim->istexture = -1;
 	R_ClearTextureNumCache(false);
 
+	// Clear animdefs now that we're done with it.
+	// We'll only be using anims from now on.
 	if (animdefs != harddefs)
-		Z_ChangeTag(animdefs, PU_CACHE);
+		Z_Free(animdefs);
+	animdefs = NULL;
 }
 
-void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
+void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum)
 {
 	char *animdefsLump;
 	size_t animdefsLumpLength;
 	char *animdefsText;
 	char *animdefsToken;
+	char *p;
 
 	// Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll
 	// need to make a space of memory where I can ensure that it will terminate
@@ -376,18 +375,19 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
 	Z_Free(animdefsLump);
 
 	// Now, let's start parsing this thing
-	animdefsToken = M_GetToken(animdefsText);
+	p = animdefsText;
+	animdefsToken = M_GetToken(p);
 	while (animdefsToken != NULL)
 	{
 		if (stricmp(animdefsToken, "TEXTURE") == 0)
 		{
 			Z_Free(animdefsToken);
-			P_ParseAnimationDefintion(1, i);
+			P_ParseAnimationDefintion(1);
 		}
 		else if (stricmp(animdefsToken, "FLAT") == 0)
 		{
 			Z_Free(animdefsToken);
-			P_ParseAnimationDefintion(0, i);
+			P_ParseAnimationDefintion(0);
 		}
 		else if (stricmp(animdefsToken, "OSCILLATE") == 0)
 		{
@@ -398,23 +398,22 @@ void P_ParseANIMDEFSLump(INT32 wadNum, UINT16 lumpnum, INT32 *i)
 		{
 			I_Error("Error parsing ANIMDEFS lump: Expected \"TEXTURE\" or \"FLAT\", got \"%s\"",animdefsToken);
 		}
-		animdefsToken = M_GetToken(NULL);
+		// parse next line
+		while (*p != '\0' && *p != '\n') ++p;
+		if (*p == '\n') ++p;
+		animdefsToken = M_GetToken(p);
 	}
 	Z_Free(animdefsToken);
 	Z_Free((void *)animdefsText);
 }
 
-void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
+void P_ParseAnimationDefintion(SINT8 istexture)
 {
 	char *animdefsToken;
 	size_t animdefsTokenLength;
 	char *endPos;
 	INT32 animSpeed;
-
-	// Increase the size to make room for the new animation definition
-	maxanims++;
-	animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
-	animdefs[*i].istexture = istexture;
+	size_t i;
 
 	// Startname
 	animdefsToken = M_GetToken(NULL);
@@ -448,14 +447,39 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 	{
 		I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
 	}
-	strncpy(animdefs[*i].startname, animdefsToken, 9);
+
+	// Search for existing animdef
+	for (i = 0; i < maxanims; i++)
+		if (stricmp(animdefsToken, animdefs[i].startname) == 0)
+		{
+			//CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken);
+
+			// If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found.
+			// Instead, we're just going to skip parsing the rest of this line entirely.
+			Z_Free(animdefsToken);
+			return;
+		}
+
+	// Not found
+	if (i == maxanims)
+	{
+		// Increase the size to make room for the new animation definition
+		maxanims++;
+		animdefs = (animdef_t *)Z_Realloc(animdefs, sizeof(animdef_t)*(maxanims + 1), PU_STATIC, NULL);
+		strncpy(animdefs[i].startname, animdefsToken, 9);
+	}
+
+	// animdefs[i].startname is now set to animdefsToken either way.
 	Z_Free(animdefsToken);
 
+	// set texture type
+	animdefs[i].istexture = istexture;
+
 	// "RANGE"
 	animdefsToken = M_GetToken(NULL);
 	if (animdefsToken == NULL)
 	{
-		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[*i].startname);
+		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname);
 	}
 	if (stricmp(animdefsToken, "ALLOWDECALS") == 0)
 	{
@@ -470,7 +494,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 	}
 	if (stricmp(animdefsToken, "RANGE") != 0)
 	{
-		I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[*i].startname, animdefsToken);
+		I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken);
 	}
 	Z_Free(animdefsToken);
 
@@ -478,21 +502,21 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 	animdefsToken = M_GetToken(NULL);
 	if (animdefsToken == NULL)
 	{
-		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[*i].startname);
+		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname);
 	}
 	animdefsTokenLength = strlen(animdefsToken);
 	if (animdefsTokenLength>8)
 	{
 		I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken);
 	}
-	strncpy(animdefs[*i].endname, animdefsToken, 9);
+	strncpy(animdefs[i].endname, animdefsToken, 9);
 	Z_Free(animdefsToken);
 
 	// "TICS"
 	animdefsToken = M_GetToken(NULL);
 	if (animdefsToken == NULL)
 	{
-		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[*i].startname);
+		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname);
 	}
 	if (stricmp(animdefsToken, "RAND") == 0)
 	{
@@ -501,7 +525,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 	}
 	if (stricmp(animdefsToken, "TICS") != 0)
 	{
-		I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[*i].startname, animdefsToken);
+		I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken);
 	}
 	Z_Free(animdefsToken);
 
@@ -509,7 +533,7 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 	animdefsToken = M_GetToken(NULL);
 	if (animdefsToken == NULL)
 	{
-		I_Error("Error parsing TEXTURES lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[*i].startname);
+		I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname);
 	}
 	endPos = NULL;
 #ifndef AVOID_ERRNO
@@ -523,13 +547,10 @@ void P_ParseAnimationDefintion(SINT8 istexture, INT32 *i)
 #endif
 		|| animSpeed < 0) // Number is not positive
 	{
-		I_Error("Error parsing TEXTURES lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[*i].startname, animdefsToken);
+		I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken);
 	}
-	animdefs[*i].speed = animSpeed;
+	animdefs[i].speed = animSpeed;
 	Z_Free(animdefsToken);
-
-	// Increment i before we go, so this doesn't cause issues later
-	(*i)++;
 }
 
 
@@ -1188,7 +1209,12 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start)
 	{
 		start++;
 
-		while (lines[start].special != special)
+		// This redundant check stops the compiler from complaining about function expansion
+		// elsewhere for some reason and everything is awful
+		if (start >= (INT32)numlines)
+			return -1;
+
+		while (start < (INT32)numlines && lines[start].special != special)
 			start++;
 
 		if (start >= (INT32)numlines)
@@ -1493,6 +1519,8 @@ static inline void P_InitTagLists(void)
 		size_t j = (unsigned)sectors[i].tag % numsectors;
 		sectors[i].nexttag = sectors[j].firsttag;
 		sectors[j].firsttag = (INT32)i;
+		sectors[i].spawn_nexttag = sectors[i].nexttag;
+		sectors[j].spawn_firsttag = sectors[j].firsttag;
 	}
 
 	for (i = numlines - 1; i != (size_t)-1; i--)
@@ -1642,7 +1670,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
 			mo = node->m_thing;
 			if (mo->flags & MF_PUSHABLE)
 				numpush++;
-			node = node->m_snext;
+			node = node->m_thinglist_next;
 		}
 
 		if (triggerline->flags & ML_NOCLIMB) // Need at least or more
@@ -2434,10 +2462,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 						if (rover->master->frontsector->tag != line->tag)
 							continue;
 
-						if (mo->z > *rover->topheight)
+						if (mo->z > P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector))
 							continue;
 
-						if (mo->z + mo->height < *rover->bottomheight)
+						if (mo->z + mo->height < P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
 							continue;
 
 						foundit = true;
@@ -3011,7 +3039,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
 
 		case 443: // Calls a named Lua function
 #ifdef HAVE_BLUA
-			LUAh_LinedefExecute(line, mo, callsec);
+			if (line->text)
+				LUAh_LinedefExecute(line, mo, callsec);
+			else
+				CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(line-lines));
 #else
 			CONS_Alert(CONS_ERROR, "The map is trying to run a Lua script, but this exe was not compiled with Lua support!\n");
 #endif
@@ -3144,7 +3175,7 @@ void P_SetupSignExit(player_t *player)
 	thinker_t *think;
 	INT32 numfound = 0;
 
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (thing->type != MT_SIGN)
@@ -3227,8 +3258,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
 				if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
 					continue;
 
-				if (mo->z <= *rover->topheight
-					&& mo->z >= *rover->bottomheight)
+				if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
+					&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
 					return true;
 			}
 		}
@@ -3262,12 +3293,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 	// Hmm.. maybe there's a FOF that has it...
 	for (rover = player->mo->subsector->sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+		bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
@@ -3275,27 +3311,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != *rover->bottomheight)
+					|| player->mo->z + player->mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and DEATH FOG!!! heh
-			if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+			if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 				continue;
 		}
 
@@ -3303,7 +3339,7 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 		return rover->master->frontsector;
 	}
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (GETSECSPECIAL(node->m_sector->special, section) == number)
 		{
@@ -3317,12 +3353,17 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 		// Hmm.. maybe there's a FOF that has it...
 		for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 		{
+			fixed_t topheight, bottomheight;
+
 			if (GETSECSPECIAL(rover->master->frontsector->special, section) != number)
 				continue;
 
 			if (!(rover->flags & FF_EXISTS))
 				continue;
 
+			topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+			bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, player->mo->subsector->sector);
+
 			// Check the 3D floor's type...
 			if (rover->flags & FF_BLOCKPLAYER)
 			{
@@ -3330,27 +3371,27 @@ sector_t *P_PlayerTouchingSectorSpecial(player_t *player, INT32 section, INT32 n
 				if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 				{
-					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != *rover->topheight)
+					if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 						continue;
 				}
 				else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 					&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 				{
 					if (!(player->mo->eflags & MFE_VERTICALFLIP)
-						|| player->mo->z + player->mo->height != *rover->bottomheight)
+						|| player->mo->z + player->mo->height != bottomheight)
 						continue;
 				}
 				else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 				{
-					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == *rover->bottomheight)
-						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == *rover->topheight)))
+					if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+						|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 						continue;
 				}
 			}
 			else
 			{
 				// Water and DEATH FOG!!! heh
-				if (player->mo->z > *rover->topheight || (player->mo->z + player->mo->height) < *rover->bottomheight)
+				if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 					continue;
 			}
 
@@ -4335,12 +4376,17 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
 
 	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (!rover->master->frontsector->special)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(mo, sectors + rover->secnum, sector);
+		bottomheight = P_GetSpecialBottomZ(mo, sectors + rover->secnum, sector);
+
 		// Check the 3D floor's type...
 		if (((rover->flags & FF_BLOCKPLAYER) && mo->player)
 			|| ((rover->flags & FF_BLOCKOTHERS) && !mo->player))
@@ -4349,27 +4395,27 @@ sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo)
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != *rover->topheight)
+				if ((mo->eflags & MFE_VERTICALFLIP) || mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(mo->eflags & MFE_VERTICALFLIP)
-					|| mo->z + mo->height != *rover->bottomheight)
+					|| mo->z + mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == *rover->bottomheight)
-					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == *rover->topheight)))
+				if (!((mo->eflags & MFE_VERTICALFLIP && mo->z + mo->height == bottomheight)
+					|| (!(mo->eflags & MFE_VERTICALFLIP) && mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and intangible FOFs
-			if (mo->z > *rover->topheight || (mo->z + mo->height) < *rover->bottomheight)
+			if (mo->z > topheight || (mo->z + mo->height) < bottomheight)
 				continue;
 		}
 
@@ -4391,12 +4437,17 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 
 	for (rover = sector->ffloors; rover; rover = rover->next)
 	{
+		fixed_t topheight, bottomheight;
+
 		if (!rover->master->frontsector->special)
 			continue;
 
 		if (!(rover->flags & FF_EXISTS))
 			continue;
 
+		topheight = P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector);
+		bottomheight = P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector);
+
 		// Check the 3D floor's type...
 		if (rover->flags & FF_BLOCKPLAYER)
 		{
@@ -4404,27 +4455,27 @@ static void P_PlayerOnSpecial3DFloor(player_t *player, sector_t *sector)
 			if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING))
 			{
-				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))
+				if ((player->mo->eflags & MFE_VERTICALFLIP) || player->mo->z != topheight)
 					continue;
 			}
 			else if ((rover->master->frontsector->flags & SF_FLIPSPECIAL_CEILING)
 				&& !(rover->master->frontsector->flags & SF_FLIPSPECIAL_FLOOR))
 			{
 				if (!(player->mo->eflags & MFE_VERTICALFLIP)
-					|| player->mo->z + player->mo->height != P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+					|| player->mo->z + player->mo->height != bottomheight)
 					continue;
 			}
 			else if (rover->master->frontsector->flags & SF_FLIPSPECIAL_BOTH)
 			{
-				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
-					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector))))
+				if (!((player->mo->eflags & MFE_VERTICALFLIP && player->mo->z + player->mo->height == bottomheight)
+					|| (!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z == topheight)))
 					continue;
 			}
 		}
 		else
 		{
 			// Water and DEATH FOG!!! heh
-			if (player->mo->z > P_GetSpecialTopZ(player->mo, sectors + rover->secnum, sector) || (player->mo->z + player->mo->height) < P_GetSpecialBottomZ(player->mo, sectors + rover->secnum, sector))
+			if (player->mo->z > topheight || (player->mo->z + player->mo->height) < bottomheight)
 				continue;
 		}
 
@@ -4637,7 +4688,7 @@ void P_PlayerInSpecialSector(player_t *player)
 		P_RunSpecialSectorCheck(player, sector);
 
 	// Iterate through touching_sectorlist
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		sector = node->m_sector;
 
@@ -5276,11 +5327,19 @@ void T_LaserFlash(laserthink_t *flash)
 
 	sourcesec = ffloor->master->frontsector; // Less to type!
 
+#ifdef ESLOPE
+	top = (*ffloor->t_slope) ? P_GetZAt(*ffloor->t_slope, sector->soundorg.x, sector->soundorg.y)
+			: *ffloor->topheight;
+	bottom = (*ffloor->b_slope) ? P_GetZAt(*ffloor->b_slope, sector->soundorg.x, sector->soundorg.y)
+			: *ffloor->bottomheight;
+	sector->soundorg.z = (top + bottom)/2;
+#else
 	sector->soundorg.z = (*ffloor->topheight + *ffloor->bottomheight)/2;
+#endif
 	S_StartSound(&sector->soundorg, sfx_laser);
 
 	// Seek out objects to DESTROY! MUAHAHHAHAHAA!!!*cough*
-	for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_snext)
+	for (node = sector->touching_thinglist; node && node->m_thing; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 
@@ -5288,6 +5347,10 @@ void T_LaserFlash(laserthink_t *flash)
 			&& thing->flags & MF_BOSS)
 			continue; // Don't hurt bosses
 
+		// Don't endlessly kill egg guard shields (or anything else for that matter)
+		if (thing->health <= 0)
+			continue;
+
 		top = P_GetSpecialTopZ(thing, sourcesec, sector);
 		bottom = P_GetSpecialBottomZ(thing, sourcesec, sector);
 
@@ -6551,7 +6614,7 @@ void T_Scroll(scroll_t *s)
 					sector_t *psec;
 					psec = sectors + sect;
 
-					for (node = psec->touching_thinglist; node; node = node->m_snext)
+					for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
 					{
 						thing = node->m_thing;
 
@@ -6573,7 +6636,7 @@ void T_Scroll(scroll_t *s)
 
 			if (!is3dblock)
 			{
-				for (node = sec->touching_thinglist; node; node = node->m_snext)
+				for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
 				{
 					thing = node->m_thing;
 
@@ -6614,7 +6677,7 @@ void T_Scroll(scroll_t *s)
 					sector_t *psec;
 					psec = sectors + sect;
 
-					for (node = psec->touching_thinglist; node; node = node->m_snext)
+					for (node = psec->touching_thinglist; node; node = node->m_thinglist_next)
 					{
 						thing = node->m_thing;
 
@@ -6636,7 +6699,7 @@ void T_Scroll(scroll_t *s)
 
 			if (!is3dblock)
 			{
-				for (node = sec->touching_thinglist; node; node = node->m_snext)
+				for (node = sec->touching_thinglist; node; node = node->m_thinglist_next)
 				{
 					thing = node->m_thing;
 
@@ -6875,6 +6938,11 @@ void T_Disappear(disappear_t *d)
 
 					if (!(lines[d->sourceline].flags & ML_NOCLIMB))
 					{
+#ifdef ESLOPE
+						if (*rover->t_slope)
+							sectors[s].soundorg.z = P_GetZAt(*rover->t_slope, sectors[s].soundorg.x, sectors[s].soundorg.y);
+						else
+#endif
 						sectors[s].soundorg.z = *rover->topheight;
 						S_StartSound(&sectors[s].soundorg, sfx_appear);
 					}
@@ -6981,7 +7049,7 @@ void T_Friction(friction_t *f)
 			{
 				if (thing->floorz != P_GetSpecialTopZ(thing, referrer, sec))
 				{
-					node = node->m_snext;
+					node = node->m_thinglist_next;
 					continue;
 				}
 
@@ -6999,7 +7067,7 @@ void T_Friction(friction_t *f)
 				thing->movefactor = f->movefactor;
 			}
 		}
-		node = node->m_snext;
+		node = node->m_thinglist_next;
 	}
 }
 
@@ -7339,7 +7407,7 @@ void T_Pusher(pusher_t *p)
 
 	// constant pushers p_wind and p_current
 	node = sec->touching_thinglist; // things touching this sector
-	for (; node; node = node->m_snext)
+	for (; node; node = node->m_thinglist_next)
 	{
 		thing = node->m_thing;
 		if (thing->flags & (MF_NOGRAVITY | MF_NOCLIP)
@@ -7390,7 +7458,7 @@ void T_Pusher(pusher_t *p)
 			}
 			else
 			{
-				if (top < thing->z || referrer->floorheight > (thing->z + (thing->height >> 1)))
+				if (top < thing->z || bottom > (thing->z + (thing->height >> 1)))
 					continue;
 				if (thing->z + thing->height > top)
 					touching = true;
diff --git a/src/p_user.c b/src/p_user.c
index 0ee5a36b463b645f63c610b5293377f951d79370..cb52358544d7a6f4e38fa116b1f5ea1ab717b5f8 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -1684,7 +1684,7 @@ static void P_CheckBustableBlocks(player_t *player)
 	player->mo->y += player->mo->momy;
 	P_SetThingPosition(player->mo);
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -1692,6 +1692,7 @@ static void P_CheckBustableBlocks(player_t *player)
 		if (node->m_sector->ffloors)
 		{
 			ffloor_t *rover;
+			fixed_t topheight, bottomheight;
 
 			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 			{
@@ -1717,42 +1718,45 @@ static void P_CheckBustableBlocks(player_t *player)
 					if (!(rover->flags & FF_SHATTER) && (rover->flags & FF_ONLYKNUX) && !(player->charability == CA_GLIDEANDCLIMB))
 						continue;
 
+					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);
+
 					// Height checks
 					if (rover->flags & FF_SHATTERBOTTOM)
 					{
-						if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+						if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
 							continue;
 
-						if (player->mo->z+player->mo->height > *rover->bottomheight)
+						if (player->mo->z+player->mo->height > bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SPINBUST)
 					{
-						if (player->mo->z+player->mo->momz > *rover->topheight)
+						if (player->mo->z+player->mo->momz > topheight)
 							continue;
 
-						if (player->mo->z + player->mo->height < *rover->bottomheight)
+						if (player->mo->z + player->mo->height < bottomheight)
 							continue;
 					}
 					else if (rover->flags & FF_SHATTER)
 					{
-						if (player->mo->z + player->mo->momz > *rover->topheight)
+						if (player->mo->z + player->mo->momz > topheight)
 							continue;
 
-						if (player->mo->z+player->mo->momz + player->mo->height < *rover->bottomheight)
+						if (player->mo->z+player->mo->momz + player->mo->height < bottomheight)
 							continue;
 					}
 					else
 					{
-						if (player->mo->z >= *rover->topheight)
+						if (player->mo->z >= topheight)
 							continue;
 
-						if (player->mo->z + player->mo->height < *rover->bottomheight)
+						if (player->mo->z + player->mo->height < bottomheight)
 							continue;
 					}
 
 					// Impede the player's fall a bit
-					if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= *rover->topheight)
+					if (((rover->flags & FF_SPINBUST) || (rover->flags & FF_SHATTER)) && player->mo->z >= topheight)
 						player->mo->momz >>= 1;
 					else if (rover->flags & FF_SHATTER)
 					{
@@ -1801,7 +1805,7 @@ static void P_CheckBouncySectors(player_t *player)
 	player->mo->z += player->mo->momz;
 	P_SetThingPosition(player->mo);
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 	{
 		if (!node->m_sector)
 			break;
@@ -1851,12 +1855,8 @@ static void P_CheckBouncySectors(player_t *player)
 						momentum.y = player->mo->momy;
 						momentum.z = player->mo->momz*2;
 
-						if (slope) {
-							// Reverse quantizing might could use its own function later
-							slope->zangle = ANGLE_MAX-slope->zangle;
-							P_QuantizeMomentumToSlope(&momentum, slope);
-							slope->zangle = ANGLE_MAX-slope->zangle;
-						}
+						if (slope)
+							P_ReverseQuantizeMomentumToSlope(&momentum, slope);
 
 						newmom = momentum.z = -FixedMul(momentum.z,linedist)/2;
 #else
@@ -2284,309 +2284,310 @@ static void P_DoClimbing(player_t *player)
 	platx = P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 	platy = P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius + FixedMul(8*FRACUNIT, player->mo->scale));
 
-	glidesector = R_PointInSubsector(player->mo->x + platx, player->mo->y + platy);
+	glidesector = R_IsPointInSubsector(player->mo->x + platx, player->mo->y + platy);
 
-	if (glidesector->sector != player->mo->subsector->sector)
+	if (!glidesector || glidesector->sector != player->mo->subsector->sector)
 	{
-		boolean floorclimb;
-		boolean thrust;
-		boolean boostup;
-		boolean skyclimber;
+		boolean floorclimb = false;
+		boolean thrust = false;
+		boolean boostup = false;
+		boolean skyclimber = false;
 		fixed_t floorheight, ceilingheight; // ESLOPE
-		thrust = false;
-		floorclimb = false;
-		boostup = false;
-		skyclimber = false;
 
+		if (!glidesector)
+			floorclimb = true;
+		else
+		{
 #ifdef ESLOPE
-		floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
-		                                           : glidesector->sector->floorheight;
-		ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
-		                                             : glidesector->sector->ceilingheight;
+			floorheight = glidesector->sector->f_slope ? P_GetZAt(glidesector->sector->f_slope, player->mo->x, player->mo->y)
+													   : glidesector->sector->floorheight;
+			ceilingheight = glidesector->sector->c_slope ? P_GetZAt(glidesector->sector->c_slope, player->mo->x, player->mo->y)
+														 : glidesector->sector->ceilingheight;
 #else
-		floorheight = glidesector->sector->floorheight;
-		ceilingheight = glidesector->sector->ceilingheight;
+			floorheight = glidesector->sector->floorheight;
+			ceilingheight = glidesector->sector->ceilingheight;
 #endif
 
-		if (glidesector->sector->ffloors)
-		{
-			ffloor_t *rover;
-			fixed_t topheight, bottomheight; // ESLOPE
-
-			for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+			if (glidesector->sector->ffloors)
 			{
-				if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-					continue;
+				ffloor_t *rover;
+				fixed_t topheight, bottomheight; // ESLOPE
 
-				floorclimb = true;
+				for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+				{
+					if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+						continue;
+
+					floorclimb = true;
 
 #ifdef ESLOPE
-				bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
-				topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
+					bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+					topheight = *rover->t_slope ? P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y) : *rover->topheight;
 #else
-				bottomheight = *rover->bottomheight;
-				topheight = *rover->topheight;
+					bottomheight = *rover->bottomheight;
+					topheight = *rover->topheight;
 #endif
 
-				// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
-				if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
-				{
-					if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
-						&& (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
-					|| ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
-						&& (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
+					// Only supports rovers that are moving like an 'elevator', not just the top or bottom.
+					if (rover->master->frontsector->floorspeed && rover->master->frontsector->ceilspeed == 42)
 					{
-						if (cmd->forwardmove != 0)
-							player->mo->momz += rover->master->frontsector->floorspeed;
-						else
+						if ((!(player->mo->eflags & MFE_VERTICALFLIP) && (bottomheight < player->mo->z+player->mo->height)
+							&& (topheight >= player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)))
+						|| ((player->mo->eflags & MFE_VERTICALFLIP) && (topheight > player->mo->z)
+							&& (bottomheight <= player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))))
 						{
-							player->mo->momz = rover->master->frontsector->floorspeed;
-							climb = false;
+							if (cmd->forwardmove != 0)
+								player->mo->momz += rover->master->frontsector->floorspeed;
+							else
+							{
+								player->mo->momz = rover->master->frontsector->floorspeed;
+								climb = false;
+							}
 						}
 					}
-				}
 
-				// Gravity is flipped, so the comments are, too.
-				if (player->mo->eflags & MFE_VERTICALFLIP)
-				{
-					// Trying to climb down past the bottom of the FOF
-					if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
+					// Gravity is flipped, so the comments are, too.
+					if (player->mo->eflags & MFE_VERTICALFLIP)
 					{
-						fixed_t bottomheight2;
-						ffloor_t *roverbelow;
-						boolean foundfof = false;
-						floorclimb = true;
-						boostup = false;
-
-						// Is there a FOF directly below this one that we can move onto?
-						for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+						// Trying to climb down past the bottom of the FOF
+						if ((topheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= topheight))
 						{
-							if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
-								continue;
+							fixed_t bottomheight2;
+							ffloor_t *roverbelow;
+							boolean foundfof = false;
+							floorclimb = true;
+							boostup = false;
+
+							// Is there a FOF directly below this one that we can move onto?
+							for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+							{
+								if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+									continue;
 
-							if (roverbelow == rover)
-								continue;
+								if (roverbelow == rover)
+									continue;
 
 #ifdef ESLOPE
-							bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
+								bottomheight2 = *roverbelow->b_slope ? P_GetZAt(*roverbelow->b_slope, player->mo->x, player->mo->y) : *roverbelow->bottomheight;
 #else
-							bottomheight2 = *roverbelow->bottomheight;
+								bottomheight2 = *roverbelow->bottomheight;
 #endif
 
-							if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
-								foundfof = true;
-						}
+								if (bottomheight2 < topheight + FixedMul(16*FRACUNIT, player->mo->scale))
+									foundfof = true;
+							}
 
-						if (!foundfof)
-							player->mo->momz = 0;
-					}
+							if (!foundfof)
+								player->mo->momz = 0;
+						}
 
-					// Below the FOF
-					if (topheight <= player->mo->z)
-					{
-						floorclimb = false;
-						boostup = false;
-						thrust = false;
-					}
+						// Below the FOF
+						if (topheight <= player->mo->z)
+						{
+							floorclimb = false;
+							boostup = false;
+							thrust = false;
+						}
 
-					// Above the FOF
-					if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
-					{
-						floorclimb = false;
-						thrust = true;
-						boostup = true;
+						// Above the FOF
+						if (bottomheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale))
+						{
+							floorclimb = false;
+							thrust = true;
+							boostup = true;
+						}
 					}
-				}
-				else
-				{
-					// Trying to climb down past the bottom of a FOF
-					if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
+					else
 					{
-						fixed_t topheight2;
-						ffloor_t *roverbelow;
-						boolean foundfof = false;
-						floorclimb = true;
-						boostup = false;
-
-						// Is there a FOF directly below this one that we can move onto?
-						for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+						// Trying to climb down past the bottom of a FOF
+						if ((bottomheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= bottomheight))
 						{
-							if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
-								continue;
+							fixed_t topheight2;
+							ffloor_t *roverbelow;
+							boolean foundfof = false;
+							floorclimb = true;
+							boostup = false;
+
+							// Is there a FOF directly below this one that we can move onto?
+							for (roverbelow = glidesector->sector->ffloors; roverbelow; roverbelow = roverbelow->next)
+							{
+								if (!(roverbelow->flags & FF_EXISTS) || !(roverbelow->flags & FF_BLOCKPLAYER) || (roverbelow->flags & FF_BUSTUP))
+									continue;
 
-							if (roverbelow == rover)
-								continue;
+								if (roverbelow == rover)
+									continue;
 
 #ifdef ESLOPE
-							topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
+								topheight2 = *roverbelow->t_slope ? P_GetZAt(*roverbelow->t_slope, player->mo->x, player->mo->y) : *roverbelow->topheight;
 #else
-							topheight2 = *roverbelow->topheight;
+								topheight2 = *roverbelow->topheight;
 #endif
 
-							if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
-								foundfof = true;
+								if (topheight2 > bottomheight - FixedMul(16*FRACUNIT, player->mo->scale))
+									foundfof = true;
+							}
+
+							if (!foundfof)
+								player->mo->momz = 0;
 						}
 
-						if (!foundfof)
-							player->mo->momz = 0;
-					}
+						// Below the FOF
+						if (bottomheight >= player->mo->z + player->mo->height)
+						{
+							floorclimb = false;
+							boostup = false;
+							thrust = false;
+						}
 
-					// Below the FOF
-					if (bottomheight >= player->mo->z + player->mo->height)
-					{
-						floorclimb = false;
-						boostup = false;
-						thrust = false;
+						// Above the FOF
+						if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+						{
+							floorclimb = false;
+							thrust = true;
+							boostup = true;
+						}
 					}
 
-					// Above the FOF
-					if (topheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale))
+					if (floorclimb)
 					{
-						floorclimb = false;
-						thrust = true;
-						boostup = true;
+						if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
+							EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
+						break;
 					}
 				}
-
-				if (floorclimb)
-				{
-					if (rover->flags & FF_CRUMBLE && !(netgame && player->spectator))
-						EV_StartCrumble(rover->master->frontsector, rover, (rover->flags & FF_FLOATBOB), player, rover->alpha, !(rover->flags & FF_NORETURN));
-					break;
-				}
 			}
-		}
 
-		// Gravity is flipped, so are comments.
-		if (player->mo->eflags & MFE_VERTICALFLIP)
-		{
-			// Trying to climb down past the upper texture area
-			if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
+			// Gravity is flipped, so are comments.
+			if (player->mo->eflags & MFE_VERTICALFLIP)
 			{
-				boolean foundfof = false;
-				floorclimb = true;
-
-				// Is there a FOF directly below that we can move onto?
-				if (glidesector->sector->ffloors)
+				// Trying to climb down past the upper texture area
+				if ((floorheight >= player->mo->z + player->mo->height) && ((player->mo->z + player->mo->height + player->mo->momz) >= floorheight))
 				{
-					fixed_t bottomheight;
-					ffloor_t *rover;
-					for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+					boolean foundfof = false;
+					floorclimb = true;
+
+					// Is there a FOF directly below that we can move onto?
+					if (glidesector->sector->ffloors)
 					{
-						if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-							continue;
+						fixed_t bottomheight;
+						ffloor_t *rover;
+						for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
+						{
+							if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+								continue;
 
 #ifdef ESLOPE
-						bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
+							bottomheight = *rover->b_slope ? P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y) : *rover->bottomheight;
 #else
-						bottomheight = *rover->bottomheight;
+							bottomheight = *rover->bottomheight;
 #endif
 
-						if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
-						{
-							foundfof = true;
-							break;
+							if (bottomheight < floorheight + FixedMul(16*FRACUNIT, player->mo->scale))
+							{
+								foundfof = true;
+								break;
+							}
 						}
 					}
-				}
 
-				if (!foundfof)
-					player->mo->momz = 0;
-			}
+					if (!foundfof)
+						player->mo->momz = 0;
+				}
 
-			// Reached the top of the lower texture area
-			if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
-			{
-				thrust = true;
-				boostup = true;
-				// Play climb-up animation here
+				// Reached the top of the lower texture area
+				if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
+					&& (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
+				{
+					thrust = true;
+					boostup = true;
+					// Play climb-up animation here
+				}
 			}
-		}
-		else
-		{
-			// Trying to climb down past the upper texture area
-			if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
+			else
 			{
-				boolean foundfof = false;
-				floorclimb = true;
-
-				// Is there a FOF directly below that we can move onto?
-				if (glidesector->sector->ffloors)
+				// Trying to climb down past the upper texture area
+				if ((ceilingheight <= player->mo->z) && ((player->mo->z + player->mo->momz) <= ceilingheight))
 				{
-					ffloor_t *rover;
-					for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
-					{
-						if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
-							continue;
+					boolean foundfof = false;
+					floorclimb = true;
 
-						if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+					// Is there a FOF directly below that we can move onto?
+					if (glidesector->sector->ffloors)
+					{
+						ffloor_t *rover;
+						for (rover = glidesector->sector->ffloors; rover; rover = rover->next)
 						{
-							foundfof = true;
-							break;
+							if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER) || (rover->flags & FF_BUSTUP))
+								continue;
+
+							if (*rover->topheight > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+							{
+								foundfof = true;
+								break;
+							}
 						}
 					}
+
+					if (!foundfof)
+						player->mo->momz = 0;
 				}
 
-				if (!foundfof)
-					player->mo->momz = 0;
-			}
+				// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
+				if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
+				{
+					floorclimb = true;
+					thrust = false;
+					boostup = false;
+				}
 
-			// Allow climbing from a FOF or lower texture onto the upper texture and vice versa.
-			if (player->mo->z > ceilingheight - FixedMul(16*FRACUNIT, player->mo->scale))
-			{
-				floorclimb = true;
-				thrust = false;
-				boostup = false;
+				// Reached the top of the lower texture area
+				if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
+					&& (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+				{
+					thrust = true;
+					boostup = true;
+					// Play climb-up animation here
+				}
 			}
 
-			// Reached the top of the lower texture area
-			if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
-				&& (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
+			// Trying to climb on the sky
+			if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
 			{
-				thrust = true;
-				boostup = true;
-				// Play climb-up animation here
+				skyclimber = true;
 			}
-		}
-
-		// Trying to climb on the sky
-		if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
-		{
-			skyclimber = true;
-		}
-
-		// Climbing on the lower texture area?
-		if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
-		{
-			floorclimb = true;
 
-			if (glidesector->sector->floorspeed)
+			// Climbing on the lower texture area?
+			if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale) < floorheight)
+				|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height <= floorheight))
 			{
-				if (cmd->forwardmove != 0)
-					player->mo->momz += glidesector->sector->floorspeed;
-				else
+				floorclimb = true;
+
+				if (glidesector->sector->floorspeed)
 				{
-					player->mo->momz = glidesector->sector->floorspeed;
-					climb = false;
+					if (cmd->forwardmove != 0)
+						player->mo->momz += glidesector->sector->floorspeed;
+					else
+					{
+						player->mo->momz = glidesector->sector->floorspeed;
+						climb = false;
+					}
 				}
 			}
-		}
-		// Climbing on the upper texture area?
-		else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
-			|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
-		{
-			floorclimb = true;
-
-			if (glidesector->sector->ceilspeed)
+			// Climbing on the upper texture area?
+			else if ((!(player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z >= ceilingheight)
+				|| ((player->mo->eflags & MFE_VERTICALFLIP) && player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale) > ceilingheight))
 			{
-				if (cmd->forwardmove != 0)
-					player->mo->momz += glidesector->sector->ceilspeed;
-				else
+				floorclimb = true;
+
+				if (glidesector->sector->ceilspeed)
 				{
-					player->mo->momz = glidesector->sector->ceilspeed;
-					climb = false;
+					if (cmd->forwardmove != 0)
+						player->mo->momz += glidesector->sector->ceilspeed;
+					else
+					{
+						player->mo->momz = glidesector->sector->ceilspeed;
+						climb = false;
+					}
 				}
 			}
 		}
@@ -2849,94 +2850,20 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
 //
 static void P_DoTeeter(player_t *player)
 {
-	msecnode_t *node;
 	boolean teeter = false;
 	boolean roverfloor; // solid 3d floors?
-	boolean checkedforteeter = false;
+	fixed_t floorheight, ceilingheight;
+	fixed_t topheight, bottomheight; // for 3d floor usage
 	const fixed_t tiptop = FixedMul(MAXSTEPMOVE, player->mo->scale); // Distance you have to be above the ground in order to teeter.
 
-	for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+	if (player->mo->standingslope && player->mo->standingslope->zdelta >= (FRACUNIT/2)) // Always teeter if the slope is too steep.
+		teeter = true;
+	else // Let's do some checks...
 	{
-		// Ledge teetering. Check if any nearby sectors are low enough from your current one.
-		checkedforteeter = true;
-		roverfloor = false;
-		if (node->m_sector->ffloors)
-		{
-			ffloor_t *rover;
-			for (rover = node->m_sector->ffloors; rover; rover = rover->next)
-			{
-				if (!(rover->flags & FF_EXISTS)) continue;
-
-				if (P_CheckSolidLava(player->mo, rover))
-					;
-				else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
-					continue; // intangible 3d floor
-
-				if (player->mo->eflags & MFE_VERTICALFLIP)
-				{
-					if (*rover->bottomheight > node->m_sector->ceilingheight) // Above the ceiling
-						continue;
-
-					if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
-						|| (*rover->topheight < player->mo->z
-						&& player->mo->z + player->mo->height < node->m_sector->ceilingheight - tiptop))
-					{
-						teeter = true;
-						roverfloor = true;
-					}
-					else
-					{
-						teeter = false;
-						roverfloor = true;
-						break;
-					}
-				}
-				else
-				{
-					if (*rover->topheight < node->m_sector->floorheight) // Below the floor
-						continue;
-
-					if (*rover->topheight < player->mo->z - tiptop
-						|| (*rover->bottomheight > player->mo->z + player->mo->height
-						&& player->mo->z > node->m_sector->floorheight + tiptop))
-					{
-						teeter = true;
-						roverfloor = true;
-					}
-					else
-					{
-						teeter = false;
-						roverfloor = true;
-						break;
-					}
-				}
-			}
-		}
-
-		if (!teeter && !roverfloor)
-		{
-			if (player->mo->eflags & MFE_VERTICALFLIP)
-			{
-				if (node->m_sector->ceilingheight > player->mo->z + player->mo->height + tiptop)
-					teeter = true;
-			}
-			else
-			{
-				if (node->m_sector->floorheight < player->mo->z - tiptop)
-					teeter = true;
-			}
-		}
-	}
-
-	if (checkedforteeter && !teeter) // Backup code
-	{
-		subsector_t *subsec[4]; // changed abcd into array instead
 		UINT8 i;
-
-		subsec[0] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[1] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y + FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[2] = R_PointInSubsector(player->mo->x + FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
-		subsec[3] = R_PointInSubsector(player->mo->x - FixedMul(5*FRACUNIT, player->mo->scale), player->mo->y - FixedMul(5*FRACUNIT, player->mo->scale));
+		sector_t *sec;
+		fixed_t highestceilingheight = INT32_MIN;
+		fixed_t lowestfloorheight = INT32_MAX;
 
 		teeter = false;
 		roverfloor = false;
@@ -2944,13 +2871,43 @@ static void P_DoTeeter(player_t *player)
 		{
 			ffloor_t *rover;
 
-			if (!(subsec[i]->sector->ffloors))
+#define xsign ((i & 1) ? -1 : 1) // 0 -> 1 | 1 -> -1 | 2 -> 1 | 3 -> -1
+#define ysign ((i & 2) ? 1 : -1) // 0 -> 1 | 1 -> 1 | 2 -> -1 | 3 -> -1
+			fixed_t checkx = player->mo->x + (xsign*FixedMul(5*FRACUNIT, player->mo->scale));
+			fixed_t checky = player->mo->y + (ysign*FixedMul(5*FRACUNIT, player->mo->scale));
+#undef xsign
+#undef ysign
+
+			sec = R_PointInSubsector(checkx, checky)->sector;
+
+			ceilingheight = sec->ceilingheight;
+			floorheight = sec->floorheight;
+#ifdef ESLOPE
+			if (sec->c_slope)
+				ceilingheight = P_GetZAt(sec->c_slope, checkx, checky);
+			if (sec->f_slope)
+				floorheight = P_GetZAt(sec->f_slope, checkx, checky);
+#endif
+			highestceilingheight = (ceilingheight > highestceilingheight) ? ceilingheight : highestceilingheight;
+			lowestfloorheight = (floorheight < lowestfloorheight) ? floorheight : lowestfloorheight;
+
+			if (!(sec->ffloors))
 				continue; // move on to the next subsector
 
-			for (rover = subsec[i]->sector->ffloors; rover; rover = rover->next)
+			for (rover = sec->ffloors; rover; rover = rover->next)
 			{
 				if (!(rover->flags & FF_EXISTS)) continue;
 
+				topheight = *rover->topheight;
+				bottomheight = *rover->bottomheight;
+
+#ifdef ESLOPE
+				if (*rover->t_slope)
+					topheight = P_GetZAt(*rover->t_slope, player->mo->x, player->mo->y);
+				if (*rover->b_slope)
+					bottomheight = P_GetZAt(*rover->b_slope, player->mo->x, player->mo->y);
+#endif
+
 				if (P_CheckSolidLava(player->mo, rover))
 					;
 				else if (!(rover->flags & FF_BLOCKPLAYER || rover->flags & FF_QUICKSAND))
@@ -2958,12 +2915,12 @@ static void P_DoTeeter(player_t *player)
 
 				if (player->mo->eflags & MFE_VERTICALFLIP)
 				{
-					if (*rover->bottomheight > subsec[i]->sector->ceilingheight) // Above the ceiling
+					if (bottomheight > ceilingheight) // Above the ceiling
 						continue;
 
-					if (*rover->bottomheight > player->mo->z + player->mo->height + tiptop
-						|| (*rover->topheight < player->mo->z
-						&& player->mo->z + player->mo->height < subsec[i]->sector->ceilingheight - tiptop))
+					if (bottomheight > player->mo->z + player->mo->height + tiptop
+						|| (topheight < player->mo->z
+						&& player->mo->z + player->mo->height < ceilingheight - tiptop))
 					{
 						teeter = true;
 						roverfloor = true;
@@ -2977,12 +2934,12 @@ static void P_DoTeeter(player_t *player)
 				}
 				else
 				{
-					if (*rover->topheight < subsec[i]->sector->floorheight) // Below the floor
+					if (topheight < floorheight) // Below the floor
 						continue;
 
-					if (*rover->topheight < player->mo->z - tiptop
-						|| (*rover->bottomheight > player->mo->z + player->mo->height
-						&& player->mo->z > subsec[i]->sector->floorheight + tiptop))
+					if (topheight < player->mo->z - tiptop
+						|| (bottomheight > player->mo->z + player->mo->height
+						&& player->mo->z > floorheight + tiptop))
 					{
 						teeter = true;
 						roverfloor = true;
@@ -3000,18 +2957,12 @@ static void P_DoTeeter(player_t *player)
 
 		if (player->mo->eflags & MFE_VERTICALFLIP)
 		{
-			if (!teeter && !roverfloor && (subsec[0]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[1]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[2]->sector->ceilingheight > player->mo->ceilingz + tiptop
-				|| subsec[3]->sector->ceilingheight > player->mo->ceilingz + tiptop))
+			if (!teeter && !roverfloor && (highestceilingheight > player->mo->ceilingz + tiptop))
 					teeter = true;
 		}
 		else
 		{
-			if (!teeter && !roverfloor && (subsec[0]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[1]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[2]->sector->floorheight < player->mo->floorz - tiptop
-				|| subsec[3]->sector->floorheight < player->mo->floorz - tiptop))
+			if (!teeter && !roverfloor && (lowestfloorheight < player->mo->floorz - tiptop))
 					teeter = true;
 		}
 	}
@@ -3147,7 +3098,7 @@ teeterdone:
 		if ((player->mo->state == &states[S_PLAY_STND] || player->mo->state == &states[S_PLAY_TAP1] || player->mo->state == &states[S_PLAY_TAP2] || player->mo->state == &states[S_PLAY_SUPERSTAND]))
 			P_SetPlayerMobjState(player->mo, S_PLAY_TEETER1);
 	}
-	else if (checkedforteeter && (player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
+	else if ((player->mo->state == &states[S_PLAY_TEETER1] || player->mo->state == &states[S_PLAY_TEETER2] || player->mo->state == &states[S_PLAY_SUPERTEETER]))
 		P_SetPlayerMobjState(player->mo, S_PLAY_STND);
 }
 
@@ -3741,7 +3692,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 	{
 		if ((cmd->buttons & BT_USE) && player->speed < FixedMul(5<<FRACBITS, player->mo->scale) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING)
 #ifdef ESLOPE
-			&& (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+			&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
 #endif
 			)
 		{
@@ -3774,7 +3725,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 		else if ((cmd->buttons & BT_USE || ((twodlevel || (player->mo->flags2 & MF2_TWOD)) && cmd->forwardmove < -20))
 			&& !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<<FRACBITS, player->mo->scale)
 #ifdef ESLOPE
-			|| (player->mo->standingslope && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
+			|| (player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) >= FRACUNIT/2)
 #endif
 			) && !(player->pflags & PF_USEDOWN) && !(player->pflags & PF_SPINNING))
 		{
@@ -3790,7 +3741,7 @@ static void P_DoSpinDash(player_t *player, ticcmd_t *cmd)
 	if (onground && player->pflags & PF_SPINNING && !(player->pflags & PF_STARTDASH)
 		&& player->speed < FixedMul(5*FRACUNIT,player->mo->scale)
 #ifdef ESLOPE
-			&& (!player->mo->standingslope || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
+			&& (!player->mo->standingslope || (player->mo->standingslope->flags & SL_NOPHYSICS) || abs(player->mo->standingslope->zdelta) < FRACUNIT/2)
 #endif
 			)
 	{
@@ -4776,7 +4727,7 @@ static void P_3dMovement(player_t *player)
 
 #ifdef ESLOPE
 	if ((totalthrust.x || totalthrust.y)
-		&& player->mo->standingslope && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
+		&& player->mo->standingslope && (!(player->mo->standingslope->flags & SL_NOPHYSICS)) && abs(player->mo->standingslope->zdelta) > FRACUNIT/2) {
 		// Factor thrust to slope, but only for the part pushing up it!
 		// The rest is unaffected.
 		angle_t thrustangle = R_PointToAngle2(0, 0, totalthrust.x, totalthrust.y)-player->mo->standingslope->xydirection;
@@ -7028,6 +6979,7 @@ static void P_MovePlayer(player_t *player)
 		msecnode_t *node; // only place it's being used in P_MovePlayer now
 		fixed_t oldx;
 		fixed_t oldy;
+		fixed_t floorz, ceilingz;
 
 		oldx = player->mo->x;
 		oldy = player->mo->y;
@@ -7037,7 +6989,7 @@ static void P_MovePlayer(player_t *player)
 		player->mo->y += player->mo->momy;
 		P_SetThingPosition(player->mo);
 
-		for (node = player->mo->touching_sectorlist; node; node = node->m_snext)
+		for (node = player->mo->touching_sectorlist; node; node = node->m_sectorlist_next)
 		{
 			if (!node->m_sector)
 				break;
@@ -7045,31 +6997,34 @@ static void P_MovePlayer(player_t *player)
 			if (node->m_sector->ffloors)
 			{
 				ffloor_t *rover;
+				fixed_t topheight, bottomheight;
 
 				for (rover = node->m_sector->ffloors; rover; rover = rover->next)
 				{
-					if (!(rover->flags & FF_EXISTS)) continue;
+					if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
+						continue;
 
-					if ((rover->flags & FF_BLOCKPLAYER))
+					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 (topheight > player->mo->z && bottomheight < player->mo->z)
 					{
-						if (*rover->topheight > player->mo->z && *rover->bottomheight < player->mo->z)
-						{
-							P_ResetPlayer(player);
-							S_StartSound(player->mo, sfx_s3k4a);
-							player->climbing = 5;
-							player->mo->momx = player->mo->momy = player->mo->momz = 0;
-							break;
-						}
+						P_ResetPlayer(player);
+						S_StartSound(player->mo, sfx_s3k4a);
+						player->climbing = 5;
+						player->mo->momx = player->mo->momy = player->mo->momz = 0;
+						break;
 					}
 				}
 			}
 
-			if (player->mo->z+player->mo->height > node->m_sector->ceilingheight
+			floorz = P_GetFloorZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+			ceilingz = P_GetCeilingZ(player->mo, node->m_sector, player->mo->x, player->mo->y, NULL);
+
+			if (player->mo->z+player->mo->height > ceilingz
 				&& node->m_sector->ceilingpic == skyflatnum)
 				continue;
 
-			if (node->m_sector->floorheight > player->mo->z
-				|| node->m_sector->ceilingheight < player->mo->z)
+			if (floorz > player->mo->z || ceilingz < player->mo->z)
 			{
 				P_ResetPlayer(player);
 				S_StartSound(player->mo, sfx_s3k4a);
@@ -7102,7 +7057,6 @@ static void P_DoZoomTube(player_t *player)
 	mobj_t *waypoint = NULL;
 	fixed_t dist;
 	boolean reverse;
-	fixed_t speedx,speedy,speedz;
 
 	player->mo->height = P_GetPlayerSpinHeight(player);
 
@@ -7123,17 +7077,17 @@ static void P_DoZoomTube(player_t *player)
 	if (dist < 1)
 		dist = 1;
 
-	speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
-	speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
-	speedz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
+	player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
+	player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
+	player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
 
 	// Calculate the distance between the player and the waypoint
 	// 'dist' already equals this.
 
-	// Will the player be FURTHER away if the momx/momy/momz is added to
-	// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
-	if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - player->mo->z - speedz)>>FRACBITS)
+	// Will the player go past the waypoint?
+	if (speed > dist)
 	{
+		speed -= dist;
 		// If further away, set XYZ of player to waypoint location
 		P_UnsetThingPosition(player->mo);
 		player->mo->x = player->mo->tracer->x;
@@ -7173,14 +7127,9 @@ static void P_DoZoomTube(player_t *player)
 		{
 			CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
 
-			// calculate MOMX/MOMY/MOMZ for next waypoint
-			// change angle
-			player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->tracer->x, player->mo->tracer->y);
+			P_SetTarget(&player->mo->tracer, waypoint);
 
-			if (player == &players[consoleplayer])
-				localangle = player->mo->angle;
-			else if (player == &players[secondarydisplayplayer])
-				localangle2 = player->mo->angle;
+			// calculate MOMX/MOMY/MOMZ for next waypoint
 
 			// change slope
 			dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - player->mo->z);
@@ -7191,22 +7140,14 @@ static void P_DoZoomTube(player_t *player)
 			player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
 			player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
 			player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - player->mo->z, dist), (speed));
-
-			P_SetTarget(&player->mo->tracer, waypoint);
 		}
 		else
 		{
-			P_SetTarget(&player->mo->tracer, NULL); // Else, we just let him fly.
+			P_SetTarget(&player->mo->tracer, NULL); // Else, we just let them fly.
 
 			CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, releasing from track...\n");
 		}
 	}
-	else
-	{
-		player->mo->momx = speedx;
-		player->mo->momy = speedy;
-		player->mo->momz = speedz;
-	}
 
 	// change angle
 	if (player->mo->tracer)
@@ -7234,24 +7175,10 @@ static void P_DoRopeHang(player_t *player)
 	mobj_t *mo2;
 	mobj_t *waypoint = NULL;
 	fixed_t dist;
-	fixed_t speedx,speedy,speedz;
 	fixed_t playerz;
 
 	player->mo->height = P_GetPlayerHeight(player);
 
-	if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
-	{
-		P_SetTarget(&player->mo->tracer, NULL);
-
-		player->pflags |= PF_JUMPED;
-		player->pflags &= ~PF_ROPEHANG;
-
-		if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
-		&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
-			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
-		return;
-	}
-
 	// Play the 'clink' sound only if the player is moving.
 	if (!(leveltime & 7) && player->speed)
 		S_StartSound(player->mo, sfx_s3k55);
@@ -7268,9 +7195,22 @@ static void P_DoRopeHang(player_t *player)
 	if (dist < 1)
 		dist = 1;
 
-	speedx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
-	speedy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
-	speedz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
+	player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
+	player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
+	player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
+
+	if (player->cmd.buttons & BT_USE && !(player->pflags & PF_STASIS)) // Drop off of the rope
+	{
+		P_SetTarget(&player->mo->tracer, NULL);
+
+		player->pflags |= PF_JUMPED;
+		player->pflags &= ~PF_ROPEHANG;
+
+		if (!(player->pflags & PF_SLIDING) && (player->pflags & PF_JUMPED)
+		&& !(player->panim == PA_ROLL) && player->charability2 == CA2_SPINDASH)
+			P_SetPlayerMobjState(player->mo, S_PLAY_ATK1);
+		return;
+	}
 
 	// If not allowed to move, we're done here.
 	if (!speed)
@@ -7279,15 +7219,16 @@ static void P_DoRopeHang(player_t *player)
 	// Calculate the distance between the player and the waypoint
 	// 'dist' already equals this.
 
-	// Will the player be FURTHER away if the momx/momy/momz is added to
-	// his current coordinates, or closer? (shift down to fracunits to avoid approximation errors)
-	if (dist>>FRACBITS <= P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x - speedx, player->mo->tracer->y - player->mo->y - speedy), player->mo->tracer->z - playerz - speedz)>>FRACBITS)
+	// Will the player go past the waypoint?
+	if (speed > dist)
 	{
+		speed -= dist;
 		// If further away, set XYZ of player to waypoint location
 		P_UnsetThingPosition(player->mo);
 		player->mo->x = player->mo->tracer->x;
 		player->mo->y = player->mo->tracer->y;
 		player->mo->z = player->mo->tracer->z - player->mo->height;
+		playerz = player->mo->tracer->z;
 		P_SetThingPosition(player->mo);
 
 		CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
@@ -7343,6 +7284,8 @@ static void P_DoRopeHang(player_t *player)
 		{
 			CONS_Debug(DBG_GAMELOGIC, "Found waypoint (sequence %d, number %d).\n", waypoint->threshold, waypoint->health);
 
+			P_SetTarget(&player->mo->tracer, waypoint);
+
 			// calculate MOMX/MOMY/MOMZ for next waypoint
 			// change slope
 			dist = P_AproxDistance(P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y), player->mo->tracer->z - playerz);
@@ -7353,8 +7296,6 @@ static void P_DoRopeHang(player_t *player)
 			player->mo->momx = FixedMul(FixedDiv(player->mo->tracer->x - player->mo->x, dist), (speed));
 			player->mo->momy = FixedMul(FixedDiv(player->mo->tracer->y - player->mo->y, dist), (speed));
 			player->mo->momz = FixedMul(FixedDiv(player->mo->tracer->z - playerz, dist), (speed));
-
-			P_SetTarget(&player->mo->tracer, waypoint);
 		}
 		else
 		{
@@ -7373,12 +7314,6 @@ static void P_DoRopeHang(player_t *player)
 			CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found!\n");
 		}
 	}
-	else
-	{
-		player->mo->momx = speedx;
-		player->mo->momy = speedy;
-		player->mo->momz = speedz;
-	}
 }
 
 #if 0
@@ -8123,6 +8058,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 	{
 		fixed_t myfloorz, myceilingz;
 		fixed_t midz = thiscam->z + (thiscam->z - mo->z)/2;
+		fixed_t midx = ((mo->x>>FRACBITS) + (thiscam->x>>FRACBITS))<<(FRACBITS-1);
+		fixed_t midy = ((mo->y>>FRACBITS) + (thiscam->y>>FRACBITS))<<(FRACBITS-1);
 
 		// Cameras use the heightsec's heights rather then the actual sector heights.
 		// If you can see through it, why not move the camera through it too?
@@ -8138,8 +8075,8 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		}
 		else
 		{
-			myfloorz = newsubsec->sector->floorheight;
-			myceilingz = newsubsec->sector->ceilingheight;
+			myfloorz = P_CameraGetFloorZ(thiscam, newsubsec->sector, midx, midy, NULL);
+			myceilingz = P_CameraGetCeilingZ(thiscam, newsubsec->sector, midx, midy, NULL);
 		}
 
 		// Check list of fake floors and see if floorz/ceilingz need to be altered.
@@ -8151,17 +8088,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 
 			for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
 			{
+				fixed_t topheight, bottomheight;
 				if (!(rover->flags & FF_BLOCKOTHERS) || !(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERALL) || GETSECSPECIAL(rover->master->frontsector->special, 4) == 12)
 					continue;
 
-				delta1 = midz - (*rover->bottomheight
-					+ ((*rover->topheight - *rover->bottomheight)/2));
-				delta2 = thingtop - (*rover->bottomheight
-					+ ((*rover->topheight - *rover->bottomheight)/2));
-				if (*rover->topheight > myfloorz && abs(delta1) < abs(delta2))
-					myfloorz = *rover->topheight;
-				if (*rover->bottomheight < myceilingz && abs(delta1) >= abs(delta2))
-					myceilingz = *rover->bottomheight;
+				topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+				bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+
+				delta1 = midz - (bottomheight
+					+ ((topheight - bottomheight)/2));
+				delta2 = thingtop - (bottomheight
+					+ ((topheight - bottomheight)/2));
+				if (topheight > myfloorz && abs(delta1) < abs(delta2))
+					myfloorz = topheight;
+				if (bottomheight < myceilingz && abs(delta1) >= abs(delta2))
+					myceilingz = bottomheight;
 			}
 		}
 
@@ -8275,18 +8216,22 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 
 			for (rover = newsubsec->sector->ffloors; rover; rover = rover->next)
 			{
+				fixed_t topheight, bottomheight;
 				if ((rover->flags & FF_BLOCKOTHERS) && (rover->flags & FF_RENDERALL) && (rover->flags & FF_EXISTS) && GETSECSPECIAL(rover->master->frontsector->special, 4) != 12)
 				{
-					if (*rover->bottomheight - thiscam->height < z
-						&& midz < *rover->bottomheight)
-						z = *rover->bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
+					topheight = P_CameraGetFOFTopZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+					bottomheight = P_CameraGetFOFBottomZ(thiscam, newsubsec->sector, rover, midx, midy, NULL);
+
+					if (bottomheight - thiscam->height < z
+						&& midz < bottomheight)
+						z = bottomheight - thiscam->height-FixedMul(11*FRACUNIT, mo->scale);
 
-					else if (*rover->topheight + thiscam->height > z
-						&& midz > *rover->topheight)
-						z = *rover->topheight;
+					else if (topheight + thiscam->height > z
+						&& midz > topheight)
+						z = topheight;
 
-					if ((mo->z >= *rover->topheight && midz < *rover->bottomheight)
-						|| ((mo->z < *rover->bottomheight && mo->z+mo->height < *rover->topheight) && midz >= *rover->topheight))
+					if ((mo->z >= topheight && midz < bottomheight)
+						|| ((mo->z < bottomheight && mo->z+mo->height < topheight) && midz >= topheight))
 					{
 						// Can't see
 						if (!resetcalled)
diff --git a/src/r_bsp.c b/src/r_bsp.c
index 69aa7be2902770ecb89a1c8b683a6039fae9b5e4..abb11204a60233a8e59faf5f6618fc4fe09938b0 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -210,7 +210,7 @@ void R_PortalClearClipSegs(INT32 start, INT32 end)
 //
 // It assumes that Doom has already ruled out a door being closed because
 // of front-back closure (e.g. front floor is taller than back ceiling).
-static inline INT32 R_DoorClosed(void)
+static INT32 R_DoorClosed(void)
 {
 	return
 
@@ -859,6 +859,7 @@ static void R_Subsector(size_t num)
 	static sector_t tempsec; // Deep water hack
 	extracolormap_t *floorcolormap;
 	extracolormap_t *ceilingcolormap;
+	fixed_t floorcenterz, ceilingcenterz;
 
 #ifdef RANGECHECK
 	if (num >= numsubsectors)
@@ -879,6 +880,18 @@ static void R_Subsector(size_t num)
 
 	floorcolormap = ceilingcolormap = frontsector->extra_colormap;
 
+	floorcenterz =
+#ifdef ESLOPE
+		frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+		frontsector->floorheight;
+
+	ceilingcenterz =
+#ifdef ESLOPE
+		frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
+#endif
+		frontsector->ceilingheight;
+
 	// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
 	if (frontsector->ffloors)
 	{
@@ -891,19 +904,11 @@ static void R_Subsector(size_t num)
 			sub->sector->moved = frontsector->moved = 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);
+		light = R_GetPlaneLight(frontsector, floorcenterz, false);
 		if (frontsector->floorlightsec == -1)
 			floorlightlevel = *frontsector->lightlist[light].lightlevel;
 		floorcolormap = frontsector->lightlist[light].extra_colormap;
-		light = R_GetPlaneLight(frontsector,
-#ifdef ESLOPE
-								frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
-								frontsector->ceilingheight, false);
+		light = R_GetPlaneLight(frontsector, ceilingcenterz, false);
 		if (frontsector->ceilinglightsec == -1)
 			ceilinglightlevel = *frontsector->lightlist[light].lightlevel;
 		ceilingcolormap = frontsector->lightlist[light].extra_colormap;
@@ -920,6 +925,9 @@ static void R_Subsector(size_t num)
 	{
 		floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
 			frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL
+#ifdef POLYOBJECTS_PLANES
+			, NULL
+#endif
 #ifdef ESLOPE
 			, frontsector->f_slope
 #endif
@@ -939,6 +947,9 @@ static void R_Subsector(size_t num)
 		ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
 			ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
 			ceilingcolormap, NULL
+#ifdef POLYOBJECTS_PLANES
+			, NULL
+#endif
 #ifdef ESLOPE
 			, frontsector->c_slope
 #endif
@@ -956,7 +967,7 @@ static void R_Subsector(size_t num)
 	if (frontsector->ffloors)
 	{
 		ffloor_t *rover;
-		fixed_t heightcheck, planecenterz, floorcenterz, ceilingcenterz;
+		fixed_t heightcheck, planecenterz;
 
 		for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)
 		{
@@ -975,18 +986,6 @@ static void R_Subsector(size_t num)
 			ffloor[numffloors].plane = NULL;
 			ffloor[numffloors].polyobj = NULL;
 
-			floorcenterz =
-#ifdef ESLOPE
-				frontsector->f_slope ? P_GetZAt(frontsector->f_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
-				frontsector->floorheight;
-
-			ceilingcenterz =
-#ifdef ESLOPE
-				frontsector->c_slope ? P_GetZAt(frontsector->c_slope, frontsector->soundorg.x, frontsector->soundorg.y) :
-#endif
-				frontsector->ceilingheight;
-
 			heightcheck =
 #ifdef ESLOPE
 				*rover->b_slope ? P_GetZAt(*rover->b_slope, viewx, viewy) :
@@ -1009,6 +1008,9 @@ static void R_Subsector(size_t num)
 				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
+#ifdef POLYOBJECTS_PLANES
+					, NULL
+#endif
 #ifdef ESLOPE
 					, *rover->b_slope
 #endif
@@ -1052,6 +1054,9 @@ static void R_Subsector(size_t num)
 				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
+#ifdef POLYOBJECTS_PLANES
+					, NULL
+#endif
 #ifdef ESLOPE
 					, *rover->t_slope
 #endif
@@ -1093,8 +1098,8 @@ static void R_Subsector(size_t num)
 			polysec = po->lines[0]->backsector;
 			ffloor[numffloors].plane = NULL;
 
-			if (polysec->floorheight <= frontsector->ceilingheight
-				&& polysec->floorheight >= frontsector->floorheight
+			if (polysec->floorheight <= ceilingcenterz
+				&& polysec->floorheight >= floorcenterz
 				&& (viewz < polysec->floorheight))
 			{
 				fixed_t xoff, yoff;
@@ -1118,11 +1123,13 @@ static void R_Subsector(size_t num)
 						polysec->floorpic_angle-po->angle,
 						NULL,
 						NULL
+#ifdef POLYOBJECTS_PLANES
+					, po
+#endif
 #ifdef ESLOPE
 					, NULL // will ffloors be slopable eventually?
 #endif
 					);
-				//ffloor[numffloors].plane->polyobj = po;
 
 				ffloor[numffloors].height = polysec->floorheight;
 				ffloor[numffloors].polyobj = po;
@@ -1139,8 +1146,8 @@ static void R_Subsector(size_t num)
 
 			ffloor[numffloors].plane = NULL;
 
-			if (polysec->ceilingheight >= frontsector->floorheight
-				&& polysec->ceilingheight <= frontsector->ceilingheight
+			if (polysec->ceilingheight >= floorcenterz
+				&& polysec->ceilingheight <= ceilingcenterz
 				&& (viewz > polysec->ceilingheight))
 			{
 				fixed_t xoff, yoff;
@@ -1162,11 +1169,13 @@ static void R_Subsector(size_t num)
 				ffloor[numffloors].plane = R_FindPlane(polysec->ceilingheight, polysec->ceilingpic,
 					polysec->lightlevel, xoff, yoff, polysec->ceilingpic_angle-po->angle,
 					NULL, NULL
+#ifdef POLYOBJECTS_PLANES
+					, po
+#endif
 #ifdef ESLOPE
 					, NULL // will ffloors be slopable eventually?
 #endif
 					);
-				//ffloor[numffloors].plane->polyobj = po;
 
 				ffloor[numffloors].polyobj = po;
 				ffloor[numffloors].height = polysec->ceilingheight;
@@ -1213,6 +1222,9 @@ static void R_Subsector(size_t num)
 	while (count--)
 	{
 //		CONS_Debug(DBG_GAMELOGIC, "Adding normal line %d...(%d)\n", line->linedef-lines, leveltime);
+#ifdef POLYOBJECTS
+		if (!line->polyseg) // ignore segs that belong to polyobjects
+#endif
 		R_AddLine(line);
 		line++;
 		curline = NULL; /* cph 2001/11/18 - must clear curline now we're done with it, so stuff doesn't try using it for other things */
diff --git a/src/r_data.c b/src/r_data.c
index cb5cf3591486abc8ca14b7cc5caf656021e55e54..d19882dd395379abe81fe5e3924193cb4b2d3811 100644
--- a/src/r_data.c
+++ b/src/r_data.c
@@ -303,6 +303,32 @@ done:
 	return blocktex;
 }
 
+//
+// R_GetTextureNum
+//
+// Returns the actual texture id that we should use.
+// This can either be texnum, the current frame for texnum's anim (if animated),
+// or 0 if not valid.
+//
+INT32 R_GetTextureNum(INT32 texnum)
+{
+	if (texnum < 0 || texnum >= numtextures)
+		return 0;
+	return texturetranslation[texnum];
+}
+
+//
+// R_CheckTextureCache
+//
+// Use this if you need to make sure the texture is cached before R_GetColumn calls
+// e.g.: midtextures and FOF walls
+//
+void R_CheckTextureCache(INT32 tex)
+{
+	if (!texturecache[tex])
+		R_GenerateTexture(tex);
+}
+
 //
 // R_GetColumn
 //
@@ -918,23 +944,24 @@ static void R_InitExtraColormaps(void)
 	for (cfile = clump = 0; cfile < numwadfiles; cfile++, clump = 0)
 	{
 		startnum = W_CheckNumForNamePwad("C_START", cfile, clump);
-		if (startnum == LUMPERROR)
+		if (startnum == INT16_MAX)
 			continue;
 
 		endnum = W_CheckNumForNamePwad("C_END", cfile, clump);
 
-		if (endnum == LUMPERROR)
+		if (endnum == INT16_MAX)
 			I_Error("R_InitExtraColormaps: C_START without C_END\n");
 
-		if (WADFILENUM(startnum) != WADFILENUM(endnum))
-			I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
+		// This shouldn't be possible when you use the Pwad function, silly
+		//if (WADFILENUM(startnum) != WADFILENUM(endnum))
+			//I_Error("R_InitExtraColormaps: C_START and C_END in different wad files!\n");
 
 		if (numcolormaplumps >= maxcolormaplumps)
 			maxcolormaplumps *= 2;
 		colormaplumps = Z_Realloc(colormaplumps,
 			sizeof (*colormaplumps) * maxcolormaplumps, PU_STATIC, NULL);
-		colormaplumps[numcolormaplumps].wadfile = WADFILENUM(startnum);
-		colormaplumps[numcolormaplumps].firstlump = LUMPNUM(startnum+1);
+		colormaplumps[numcolormaplumps].wadfile = cfile;
+		colormaplumps[numcolormaplumps].firstlump = startnum+1;
 		colormaplumps[numcolormaplumps].numlumps = endnum - (startnum + 1);
 		numcolormaplumps++;
 	}
@@ -1499,6 +1526,9 @@ void R_InitData(void)
 	CONS_Printf("R_LoadTextures()...\n");
 	R_LoadTextures();
 
+	CONS_Printf("P_InitPicAnims()...\n");
+	P_InitPicAnims();
+
 	CONS_Printf("R_InitSprites()...\n");
 	R_InitSpriteLumps();
 	R_InitSprites();
diff --git a/src/r_data.h b/src/r_data.h
index 4a37f82c3dd9815551670204fd1cd1a8f2c4779c..1e9e0eb5edce620cfa9b4bd3a9123bc18f95c231 100644
--- a/src/r_data.h
+++ b/src/r_data.h
@@ -30,7 +30,7 @@ typedef struct
 {
 	// Block origin (always UL), which has already accounted for the internal origin of the patch.
 	INT16 originx, originy;
-	INT16 wad, lump;
+	UINT16 wad, lump;
 } texpatch_t;
 
 // A maptexturedef_t describes a rectangular texture,
@@ -65,6 +65,9 @@ extern CV_PossibleValue_t Color_cons_t[];
 void R_LoadTextures(void);
 void R_FlushTextureCache(void);
 
+INT32 R_GetTextureNum(INT32 texnum);
+void R_CheckTextureCache(INT32 tex);
+
 // Retrieve column data for span blitting.
 UINT8 *R_GetColumn(fixed_t tex, INT32 col);
 
diff --git a/src/r_defs.h b/src/r_defs.h
index 84870816419c757f33eed663d79f088d863b97d1..b8c21764ec1ffde78d66138201320a434a47cb1b 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -203,6 +203,7 @@ typedef struct r_lightlist_s
 	fixed_t heightstep;
 	fixed_t botheight;
 	fixed_t botheightstep;
+	fixed_t startheight; // for repeating midtextures
 	INT16 lightlevel;
 	extracolormap_t *extra_colormap;
 	lighttable_t *rcolormap;
@@ -224,15 +225,6 @@ typedef struct linechain_s
 
 
 
-// ZDoom C++ to Legacy C conversion Tails 04-29-2002 (for slopes)
-typedef struct secplane_t
-{
-	// the plane is defined as a*x + b*y + c*z + d = 0
-	// ic is 1/c, for faster Z calculations
-
-	fixed_t a, b, c, d, ic;
-} secplane_t;
-
 // Slopes
 #ifdef ESLOPE
 typedef enum {
@@ -392,6 +384,7 @@ typedef struct sector_s
 #endif
 
 	// these are saved for netgames, so do not let Lua touch these!
+	INT32 spawn_nexttag, spawn_firsttag; // the actual nexttag/firsttag values may differ if the sector's tag was changed
 
 	// offsets sector spawned with (via linedef type 7)
 	fixed_t spawn_flr_xoffs, spawn_flr_yoffs;
@@ -500,10 +493,10 @@ typedef struct subsector_s
 // Sector list node showing all sectors an object appears in.
 //
 // There are two threads that flow through these nodes. The first thread
-// starts at touching_thinglist in a sector_t and flows through the m_snext
+// starts at touching_thinglist in a sector_t and flows through the m_thinglist_next
 // links to find all mobjs that are entirely or partially in the sector.
 // The second thread starts at touching_sectorlist in an mobj_t and flows
-// through the m_tnext links to find all sectors a thing touches. This is
+// through the m_sectorlist_next links to find all sectors a thing touches. This is
 // useful when applying friction or push effects to sectors. These effects
 // can be done as thinkers that act upon all objects touching their sectors.
 // As an mobj moves through the world, these nodes are created and
@@ -515,10 +508,10 @@ typedef struct msecnode_s
 {
 	sector_t *m_sector; // a sector containing this object
 	struct mobj_s *m_thing;  // this object
-	struct msecnode_s *m_tprev;  // prev msecnode_t for this thing
-	struct msecnode_s *m_tnext;  // next msecnode_t for this thing
-	struct msecnode_s *m_sprev;  // prev msecnode_t for this sector
-	struct msecnode_s *m_snext;  // next msecnode_t for this sector
+	struct msecnode_s *m_sectorlist_prev;  // prev msecnode_t for this thing
+	struct msecnode_s *m_sectorlist_next;  // next msecnode_t for this thing
+	struct msecnode_s *m_thinglist_prev;  // prev msecnode_t for this sector
+	struct msecnode_s *m_thinglist_next;  // next msecnode_t for this sector
 	boolean visited; // used in search algorithms
 } msecnode_t;
 
@@ -526,10 +519,10 @@ typedef struct mprecipsecnode_s
 {
 	sector_t *m_sector; // a sector containing this object
 	struct precipmobj_s *m_thing;  // this object
-	struct mprecipsecnode_s *m_tprev;  // prev msecnode_t for this thing
-	struct mprecipsecnode_s *m_tnext;  // next msecnode_t for this thing
-	struct mprecipsecnode_s *m_sprev;  // prev msecnode_t for this sector
-	struct mprecipsecnode_s *m_snext;  // next msecnode_t for this sector
+	struct mprecipsecnode_s *m_sectorlist_prev;  // prev msecnode_t for this thing
+	struct mprecipsecnode_s *m_sectorlist_next;  // next msecnode_t for this thing
+	struct mprecipsecnode_s *m_thinglist_prev;  // prev msecnode_t for this sector
+	struct mprecipsecnode_s *m_thinglist_next;  // next msecnode_t for this sector
 	boolean visited; // used in search algorithms
 } mprecipsecnode_t;
 
diff --git a/src/r_draw8.c b/src/r_draw8.c
index c22cd23629a4c394a4429989be5c737f850ec1c7..39585f58798dcd6ebd39cdd87d07f1acb90247a6 100644
--- a/src/r_draw8.c
+++ b/src/r_draw8.c
@@ -874,9 +874,9 @@ void R_DrawTiltedSplat_8(void)
 
 		colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
 
-		val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+		val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			*dest = val;
+			*dest = colormap[val];
 		dest++;
 		iz += ds_sz.x;
 		uz += ds_su.x;
@@ -913,9 +913,9 @@ void R_DrawTiltedSplat_8(void)
 		for (i = SPANSIZE-1; i >= 0; i--)
 		{
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
-				*dest = val;
+				*dest = colormap[val];
 			dest++;
 			u += stepu;
 			v += stepv;
@@ -931,9 +931,9 @@ void R_DrawTiltedSplat_8(void)
 			u = (INT64)(startu);
 			v = (INT64)(startv);
 			colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-			val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+			val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 			if (val != TRANSPARENTPIXEL)
-				*dest = val;
+				*dest = colormap[val];
 		}
 		else
 		{
@@ -954,9 +954,9 @@ void R_DrawTiltedSplat_8(void)
 			for (; width != 0; width--)
 			{
 				colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
-				val = colormap[source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)]];
+				val = source[((v >> nflatyshift) & nflatmask) | (u >> nflatxshift)];
 				if (val != TRANSPARENTPIXEL)
-					*dest = val;
+					*dest = colormap[val];
 				dest++;
 				u += stepu;
 				v += stepv;
@@ -1124,49 +1124,49 @@ void R_DrawTranslucentSplat_8 (void)
 		// need!
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[0] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[0])];
+			dest[0] = colormap[*(ds_transmap + (val << 8) + dest[0])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[1] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[1])];
+			dest[1] = colormap[*(ds_transmap + (val << 8) + dest[1])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[2] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[2])];
+			dest[2] = colormap[*(ds_transmap + (val << 8) + dest[2])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[3] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[3])];
+			dest[3] = colormap[*(ds_transmap + (val << 8) + dest[3])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[4] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[4])];
+			dest[4] = colormap[*(ds_transmap + (val << 8) + dest[4])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[5] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[5])];
+			dest[5] = colormap[*(ds_transmap + (val << 8) + dest[5])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[6] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[6])];
+			dest[6] = colormap[*(ds_transmap + (val << 8) + dest[6])];
 		xposition += xstep;
 		yposition += ystep;
 
 		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			dest[7] = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + dest[7])];
+			dest[7] = colormap[*(ds_transmap + (val << 8) + dest[7])];
 		xposition += xstep;
 		yposition += ystep;
 
@@ -1175,9 +1175,9 @@ void R_DrawTranslucentSplat_8 (void)
 	}
 	while (count--)
 	{
-		val =colormap[source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)]];
+		val = source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)];
 		if (val != TRANSPARENTPIXEL)
-			*dest = colormap[*(ds_transmap + (source[((yposition >> nflatyshift) & nflatmask) | (xposition >> nflatxshift)] << 8) + *dest)];
+			*dest = colormap[*(ds_transmap + (val << 8) + *dest)];
 
 		dest++;
 		xposition += xstep;
@@ -1363,7 +1363,19 @@ void R_DrawColumnShadowed_8(void)
 
 		height = dc_lightlist[i].height >> LIGHTSCALESHIFT;
 		if (solid)
+		{
 			bheight = dc_lightlist[i].botheight >> LIGHTSCALESHIFT;
+			if (bheight < height)
+			{
+				// confounded slopes sometimes allow partial invertedness,
+				// even including cases where the top and bottom heights
+				// should actually be the same!
+				// swap the height values as a workaround for this quirk
+				INT32 temp = height;
+				height = bheight;
+				bheight = temp;
+			}
+		}
 		if (height <= dc_yl)
 		{
 			dc_colormap = dc_lightlist[i].rcolormap;
diff --git a/src/r_main.c b/src/r_main.c
index e7c37cce97938dffa7f43c098081e1b66433883a..e50e80013006cf6ad36b86ff72812464cb21377c 100644
--- a/src/r_main.c
+++ b/src/r_main.c
@@ -366,69 +366,6 @@ fixed_t R_PointToDist(fixed_t x, fixed_t y)
 	return R_PointToDist2(viewx, viewy, x, y);
 }
 
-/***************************************
-*** Zdoom C++ to Legacy C conversion ***
-****************************************/
-
-// Utility to find the Z height at an XY location in a sector (for slopes)
-fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y)
-{
-	return FixedMul(secplane->ic, -secplane->d - DMulScale16(secplane->a, x, secplane->b, y));
-}
-
-// Returns the value of z at (x,y) if d is equal to dist
-fixed_t R_SecplaneZatPointDist (secplane_t *secplane, fixed_t x, fixed_t y, fixed_t dist)
-{
-	return FixedMul(secplane->ic, -dist - DMulScale16(secplane->a, x, secplane->b, y));
-}
-
-// Flips the plane's vertical orientiation, so that if it pointed up,
-// it will point down, and vice versa.
-void R_SecplaneFlipVert(secplane_t *secplane)
-{
-	secplane->a = -secplane->a;
-	secplane->b = -secplane->b;
-	secplane->c = -secplane->c;
-	secplane->d = -secplane->d;
-	secplane->ic = -secplane->ic;
-}
-
-// Returns true if 2 planes are the same
-boolean R_ArePlanesSame(secplane_t *original, secplane_t *other)
-{
-	return original->a == other->a && original->b == other->b
-		&& original->c == other->c && original->d == other->d;
-}
-
-// Returns true if 2 planes are different
-boolean R_ArePlanesDifferent(secplane_t *original, secplane_t *other)
-{
-	return original->a != other->a || original->b != other->b
-		|| original->c != other->c || original->d != other->d;
-}
-
-// Moves a plane up/down by hdiff units
-void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff)
-{
-	secplane->d = secplane->d - FixedMul(hdiff, secplane->c);
-}
-
-// Returns how much this plane's height would change if d were set to oldd
-fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd)
-{
-	return FixedMul(oldd - secplane->d, secplane->ic);
-}
-
-fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
-{
-	return -TMulScale16(secplane->a, x, y, secplane->b, z, secplane->c);
-}
-
-fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z)
-{
-	return -TMulScale16(secplane->a, x, secplane->b, y, z, secplane->c);
-}
-
 //
 // R_ScaleFromGlobalAngle
 // Returns the texture mapping scale for the current line (horizontal span)
@@ -795,7 +732,8 @@ subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y)
 
 	ret = &subsectors[nodenum & ~NF_SUBSECTOR];
 	for (i = 0; i < ret->numlines; i++)
-		if (R_PointOnSegSide(x, y, &segs[ret->firstline + i]))
+		//if (R_PointOnSegSide(x, y, &segs[ret->firstline + i])) -- breaks in ogl because polyvertex_t cast over vertex pointers
+		if (P_PointOnLineSide(x, y, segs[ret->firstline + i].linedef) != segs[ret->firstline + i].side)
 			return 0;
 
 	return ret;
@@ -919,9 +857,9 @@ void R_SkyboxFrame(player_t *player)
 				}
 			}
 			if (mh->skybox_scalez > 0)
-				viewz += player->awayviewmobj->z / mh->skybox_scalez;
+				viewz += (player->awayviewmobj->z + 20*FRACUNIT) / mh->skybox_scalez;
 			else if (mh->skybox_scalez < 0)
-				viewz += player->awayviewmobj->z * -mh->skybox_scalez;
+				viewz += (player->awayviewmobj->z + 20*FRACUNIT) * -mh->skybox_scalez;
 		}
 		else if (thiscam->chase)
 		{
@@ -966,9 +904,9 @@ void R_SkyboxFrame(player_t *player)
 				}
 			}
 			if (mh->skybox_scalez > 0)
-				viewz += thiscam->z / mh->skybox_scalez;
+				viewz += (thiscam->z + (thiscam->height>>1)) / mh->skybox_scalez;
 			else if (mh->skybox_scalez < 0)
-				viewz += thiscam->z * -mh->skybox_scalez;
+				viewz += (thiscam->z + (thiscam->height>>1)) * -mh->skybox_scalez;
 		}
 		else
 		{
@@ -1324,6 +1262,7 @@ void R_RenderPlayerView(player_t *player)
 #endif
 
 		R_RenderBSPNode((INT32)numnodes - 1);
+		R_ClipSprites();
 		R_DrawPlanes();
 #ifdef FLOORSPLATS
 		R_DrawVisibleFloorSplats();
diff --git a/src/r_main.h b/src/r_main.h
index 8f46a938e525f00bd08147b3ff2c5dbcc0fced1b..2e768cb9c91cfeff09f67f6ce520427aefc292b1 100644
--- a/src/r_main.h
+++ b/src/r_main.h
@@ -61,18 +61,6 @@ angle_t R_PointToAngle2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
 fixed_t R_PointToDist(fixed_t x, fixed_t y);
 fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
 
-// ZDoom C++ to Legacy C conversion Tails 04-29-2002
-fixed_t R_SecplaneZatPoint(secplane_t *secplane, fixed_t x, fixed_t y);
-fixed_t R_SecplaneZatPointDist(secplane_t *secplane, fixed_t x, fixed_t y,
-	fixed_t dist);
-void R_SecplaneFlipVert(secplane_t *secplane);
-boolean R_ArePlanesSame(secplane_t *original,  secplane_t *other);
-boolean R_ArePlanesDifferent(secplane_t *original,  secplane_t *other);
-void R_SecplaneChangeHeight(secplane_t *secplane, fixed_t hdiff);
-fixed_t R_SecplaneHeightDiff(secplane_t *secplane, fixed_t oldd);
-fixed_t R_SecplanePointToDist(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
-fixed_t R_SecplanePointToDist2(secplane_t *secplane, fixed_t x, fixed_t y, fixed_t z);
-
 fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
 subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
 subsector_t *R_IsPointInSubsector(fixed_t x, fixed_t y);
diff --git a/src/r_plane.c b/src/r_plane.c
index 19007d88fa349f3b355b85aa58f0516759cbe5f0..b7b9eaff3388ba7c042ece77748b539b08cad70d 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -431,6 +431,9 @@ 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
+#ifdef POLYOBJECTS_PLANES
+			, polyobj_t *polyobj
+#endif
 #ifdef ESLOPE
 			, pslope_t *slope
 #endif
@@ -470,6 +473,8 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 #ifdef POLYOBJECTS_PLANES
 		if (check->polyobj && pfloor)
 			continue;
+		if (polyobj != check->polyobj)
+			continue;
 #endif
 		if (height == check->height && picnum == check->picnum
 			&& lightlevel == check->lightlevel
@@ -504,7 +509,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 	check->viewangle = viewangle;
 	check->plangle = plangle;
 #ifdef POLYOBJECTS_PLANES
-	check->polyobj = NULL;
+	check->polyobj = polyobj;
 #endif
 #ifdef ESLOPE
 	check->slope = slope;
@@ -719,7 +724,11 @@ void R_DrawPlanes(void)
 				continue;
 			}
 
-			if (pl->ffloor != NULL)
+			if (pl->ffloor != NULL
+#ifdef POLYOBJECTS_PLANES
+			|| pl->polyobj != NULL
+#endif
+			)
 				continue;
 
 			R_DrawSinglePlane(pl);
diff --git a/src/r_plane.h b/src/r_plane.h
index 8730bcefd9e530cf99bfbe83b93895fb7026de11..16c8c12a448e6cd5b905b066391404889b0b8eb9 100644
--- a/src/r_plane.h
+++ b/src/r_plane.h
@@ -87,7 +87,7 @@ extern lighttable_t **planezlight;
 extern fixed_t *yslope;
 extern fixed_t distscale[MAXVIDWIDTH];
 
-void R_InitPlanes(void);
+FUNCMATH void R_InitPlanes(void);
 void R_PortalStoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
 void R_PortalRestoreClipValues(INT32 start, INT32 end, INT16 *ceil, INT16 *floor, fixed_t *scale);
 void R_ClearPlanes(void);
@@ -97,6 +97,9 @@ 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
+#ifdef POLYOBJECTS_PLANES
+	, polyobj_t *polyobj
+#endif
 #ifdef ESLOPE
 	, pslope_t *slope
 #endif
diff --git a/src/r_segs.c b/src/r_segs.c
index 11b4c8aefd7b031755478bfd99bc661b0b35de0b..502ff3304dab17ec4f54283608ee33fb74145b60 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -300,7 +300,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	curline = ds->curline;
 	frontsector = curline->frontsector;
 	backsector = curline->backsector;
-	texnum = texturetranslation[curline->sidedef->midtexture];
+	texnum = R_GetTextureNum(curline->sidedef->midtexture);
 	windowbottom = windowtop = sprbotscreen = INT32_MAX;
 
 	// hack translucent linedef types (900-909 for transtables 1-9)
@@ -344,6 +344,9 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 	rw_scalestep = ds->scalestep;
 	spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
 
+	// Texture must be cached before setting colfunc_2s,
+	// otherwise texture[texnum]->holes may be false when it shouldn't be
+	R_CheckTextureCache(texnum);
 	// handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
 	// are not stored per-column with post info in SRB2
 	if (textures[texnum]->holes)
@@ -391,6 +394,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 			rlight->height = (centeryfrac) - FixedMul((light->height - viewz), spryscale);
 			rlight->heightstep = -FixedMul(rw_scalestep, (light->height - viewz));
 #endif
+			rlight->startheight = rlight->height; // keep starting value here to reset for each repeat
 			rlight->lightlevel = *light->lightlevel;
 			rlight->extra_colormap = light->extra_colormap;
 			rlight->flags = light->flags;
@@ -484,6 +488,14 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 		{
 			rw_scalestep = ds->scalestep;
 			spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
+			if (dc_numlights)
+			{ // reset all lights to their starting heights
+				for (i = 0; i < dc_numlights; i++)
+				{
+					rlight = &dc_lightlist[i];
+					rlight->height = rlight->startheight;
+				}
+			}
 		}
 
 #ifndef ESLOPE
@@ -694,10 +706,13 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 // Loop through R_DrawMaskedColumn calls
 static void R_DrawRepeatMaskedColumn(column_t *col)
 {
-	do {
+	while (sprtopscreen < sprbotscreen) {
 		R_DrawMaskedColumn(col);
-		sprtopscreen += dc_texheight*spryscale;
-	} while (sprtopscreen < sprbotscreen);
+		if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow
+			sprtopscreen = INT32_MAX;
+		else
+			sprtopscreen += dc_texheight*spryscale;
+	}
 }
 
 //
@@ -740,7 +755,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	curline = ds->curline;
 	backsector = pfloor->target;
 	frontsector = curline->frontsector == pfloor->target ? curline->backsector : curline->frontsector;
-	texnum = texturetranslation[sides[pfloor->master->sidenum[0]].midtexture];
+	texnum = R_GetTextureNum(sides[pfloor->master->sidenum[0]].midtexture);
 
 	colfunc = wallcolfunc;
 
@@ -748,7 +763,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 	{
 		size_t linenum = curline->linedef-backsector->lines[0];
 		newline = pfloor->master->frontsector->lines[0] + linenum;
-		texnum = texturetranslation[sides[newline->sidenum[0]].midtexture];
+		texnum = R_GetTextureNum(sides[newline->sidenum[0]].midtexture);
 	}
 
 	if (pfloor->flags & FF_TRANSLUCENT)
@@ -968,6 +983,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
 
 	dc_texturemid += offsetvalue;
 
+	// Texture must be cached before setting colfunc_2s,
+	// otherwise texture[texnum]->holes may be false when it shouldn't be
+	R_CheckTextureCache(texnum);
 	//faB: handle case where multipatch texture is drawn on a 2sided wall, multi-patch textures
 	//     are not stored per-column with post info anymore in Doom Legacy
 	if (textures[texnum]->holes)
@@ -1453,34 +1471,45 @@ static void R_RenderSegLoop (void)
 		frontscale[rw_x] = rw_scale;
 
 		// draw the wall tiers
-		if (midtexture && yl <= yh && yh < vid.height && yh > 0)
+		if (midtexture)
 		{
 			// single sided line
-			dc_yl = yl;
-			dc_yh = yh;
-			dc_texturemid = rw_midtexturemid;
-			dc_source = R_GetColumn(midtexture,texturecolumn);
-			dc_texheight = textureheight[midtexture]>>FRACBITS;
+			if (yl <= yh && yh >= 0 && yl < viewheight)
+			{
+				dc_yl = yl;
+				dc_yh = yh;
+				dc_texturemid = rw_midtexturemid;
+				dc_source = R_GetColumn(midtexture,texturecolumn);
+				dc_texheight = textureheight[midtexture]>>FRACBITS;
 
-			//profile stuff ---------------------------------------------------------
+				//profile stuff ---------------------------------------------------------
 #ifdef TIMING
-			ProfZeroTimer();
+				ProfZeroTimer();
 #endif
-			colfunc();
+				colfunc();
 #ifdef TIMING
-			RDMSR(0x10,&mycount);
-			mytotal += mycount;      //64bit add
+				RDMSR(0x10,&mycount);
+				mytotal += mycount;      //64bit add
 
-			if (nombre--==0)
-				I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
-					(INT32)mytotal);
+				if (nombre--==0)
+					I_Error("R_DrawColumn CPU Spy reports: 0x%d %d\n", *((INT32 *)&mytotal+1),
+						(INT32)mytotal);
 #endif
-			//profile stuff ---------------------------------------------------------
+				//profile stuff ---------------------------------------------------------
 
-			// dont draw anything more for this column, since
-			// a midtexture blocks the view
-			ceilingclip[rw_x] = (INT16)viewheight;
-			floorclip[rw_x] = -1;
+				// dont draw anything more for this column, since
+				// a midtexture blocks the view
+				ceilingclip[rw_x] = (INT16)viewheight;
+				floorclip[rw_x] = -1;
+			}
+			else
+			{
+				// note: don't use min/max macros, since casting from INT32 to INT16 is involved here
+				if (markceiling)
+					ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
+				if (markfloor)
+					floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
+			}
 		}
 		else
 		{
@@ -1494,21 +1523,28 @@ static void R_RenderSegLoop (void)
 				if (mid >= floorclip[rw_x])
 					mid = floorclip[rw_x]-1;
 
-				if (mid >= yl && yh < vid.height && yh > 0)
+				if (mid >= yl) // back ceiling lower than front ceiling ?
 				{
-					dc_yl = yl;
-					dc_yh = mid;
-					dc_texturemid = rw_toptexturemid;
-					dc_source = R_GetColumn(toptexture,texturecolumn);
-					dc_texheight = textureheight[toptexture]>>FRACBITS;
-					colfunc();
-					ceilingclip[rw_x] = (INT16)mid;
+					if (yl >= viewheight) // entirely off bottom of screen
+						ceilingclip[rw_x] = (INT16)viewheight;
+					else if (mid >= 0) // safe to draw top texture
+					{
+						dc_yl = yl;
+						dc_yh = mid;
+						dc_texturemid = rw_toptexturemid;
+						dc_source = R_GetColumn(toptexture,texturecolumn);
+						dc_texheight = textureheight[toptexture]>>FRACBITS;
+						colfunc();
+						ceilingclip[rw_x] = (INT16)mid;
+					}
+					else // entirely off top of screen
+						ceilingclip[rw_x] = -1;
 				}
 				else
-					ceilingclip[rw_x] = (INT16)((INT16)yl - 1);
+					ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
 			}
 			else if (markceiling) // no top wall
-				ceilingclip[rw_x] = (INT16)((INT16)yl - 1);
+				ceilingclip[rw_x] = (yl >= 0) ? ((yl > viewheight) ? (INT16)viewheight : (INT16)((INT16)yl - 1)) : -1;
 
 			if (bottomtexture)
 			{
@@ -1520,22 +1556,29 @@ static void R_RenderSegLoop (void)
 				if (mid <= ceilingclip[rw_x])
 					mid = ceilingclip[rw_x]+1;
 
-				if (mid <= yh && yh < vid.height && yh > 0)
+				if (mid <= yh) // back floor higher than front floor ?
 				{
-					dc_yl = mid;
-					dc_yh = yh;
-					dc_texturemid = rw_bottomtexturemid;
-					dc_source = R_GetColumn(bottomtexture,
-						texturecolumn);
-					dc_texheight = textureheight[bottomtexture]>>FRACBITS;
-					colfunc();
-					floorclip[rw_x] = (INT16)mid;
+					if (yh < 0) // entirely off top of screen
+						floorclip[rw_x] = -1;
+					else if (mid < viewheight) // safe to draw bottom texture
+					{
+						dc_yl = mid;
+						dc_yh = yh;
+						dc_texturemid = rw_bottomtexturemid;
+						dc_source = R_GetColumn(bottomtexture,
+							texturecolumn);
+						dc_texheight = textureheight[bottomtexture]>>FRACBITS;
+						colfunc();
+						floorclip[rw_x] = (INT16)mid;
+					}
+					else  // entirely off bottom of screen
+						floorclip[rw_x] = (INT16)viewheight;
 				}
 				else
-					floorclip[rw_x] = (INT16)((INT16)yh + 1);
+					floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
 			}
 			else if (markfloor) // no bottom wall
-				floorclip[rw_x] = (INT16)((INT16)yh + 1);
+				floorclip[rw_x] = (yh < viewheight) ? ((yh < -1) ? -1 : (INT16)((INT16)yh + 1)) : (INT16)viewheight;
 		}
 
 		if (maskedtexture || numthicksides)
@@ -1853,25 +1896,28 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 	if (!backsector)
 	{
+		fixed_t texheight;
 		// single sided line
-		midtexture = texturetranslation[sidedef->midtexture];
+		midtexture = R_GetTextureNum(sidedef->midtexture);
+		texheight = textureheight[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_EFFECT2) {
 			if (linedef->flags & ML_DONTPEGBOTTOM)
-				rw_midtexturemid = frontsector->floorheight + textureheight[sidedef->midtexture] - viewz;
+				rw_midtexturemid = frontsector->floorheight + texheight - viewz;
 			else
-				rw_midtexturemid = frontsector->ceilingheight;
+				rw_midtexturemid = frontsector->ceilingheight - viewz;
 		}
+		else
 #endif
 		if (linedef->flags & ML_DONTPEGBOTTOM)
 		{
 #ifdef ESLOPE
-			rw_midtexturemid = worldbottom + textureheight[sidedef->midtexture];
+			rw_midtexturemid = worldbottom + texheight;
 			rw_midtextureslide = floorfrontslide;
 #else
-			vtop = frontsector->floorheight + textureheight[sidedef->midtexture];
+			vtop = frontsector->floorheight + texheight;
 			// bottom of texture at bottom
 			rw_midtexturemid = vtop - viewz;
 #endif
@@ -2103,76 +2149,50 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 #endif
 			)
 		{
+			fixed_t texheight;
 			// top texture
 			if ((linedef->flags & (ML_DONTPEGTOP) && (linedef->flags & ML_DONTPEGBOTTOM))
 				&& linedef->sidenum[1] != 0xffff)
 			{
 				// Special case... use offsets from 2nd side but only if it has a texture.
 				side_t *def = &sides[linedef->sidenum[1]];
-				toptexture = texturetranslation[def->toptexture];
+				toptexture = R_GetTextureNum(def->toptexture);
 
 				if (!toptexture) //Second side has no texture, use the first side's instead.
-					toptexture = texturetranslation[sidedef->toptexture];
-
+					toptexture = R_GetTextureNum(sidedef->toptexture);
+				texheight = textureheight[toptexture];
+			}
+			else
+			{
+				toptexture = R_GetTextureNum(sidedef->toptexture);
+				texheight = textureheight[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_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
 				if (linedef->flags & ML_DONTPEGTOP)
-				{
-					// top of texture at top
-					rw_toptexturemid = worldtop;
-#ifdef ESLOPE
-					rw_toptextureslide = ceilingfrontslide;
-#endif
-				}
+					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_toptexturemid = worldhigh + textureheight[def->toptexture];
-					rw_toptextureslide = ceilingbackslide;
-#else
-					vtop = backsector->ceilingheight + textureheight[def->toptexture];
-					// bottom of texture
-					rw_toptexturemid = vtop - viewz;
+				rw_toptextureslide = ceilingfrontslide;
 #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;
+				rw_toptexturemid = worldhigh + texheight;
+				rw_toptextureslide = ceilingbackslide;
 #else
-					vtop = backsector->ceilingheight + textureheight[sidedef->toptexture];
-					// bottom of texture
-					rw_toptexturemid = vtop - viewz;
+				vtop = backsector->ceilingheight + texheight;
+				// bottom of texture
+				rw_toptexturemid = vtop - viewz;
 #endif
-				}
 			}
 		}
 		// check BOTTOM TEXTURE
@@ -2183,7 +2203,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 			)     //seulement si VISIBLE!!!
 		{
 			// bottom texture
-			bottomtexture = texturetranslation[sidedef->bottomtexture];
+			bottomtexture = R_GetTextureNum(sidedef->bottomtexture);
 
 #ifdef ESLOPE
 			if (!(linedef->flags & ML_EFFECT1)) { // Ignore slopes for lower/upper textures unless flag is checked
@@ -2468,7 +2488,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 
 			ds_p->numthicksides = numthicksides = i;
 		}
-		if (sidedef->midtexture)
+		if (sidedef->midtexture > 0 && sidedef->midtexture < numtextures)
 		{
 			// masked midtexture
 			if (!ds_p->thicksidecol)
@@ -2482,6 +2502,15 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 #ifdef ESLOPE
 			maskedtextureheight = ds_p->maskedtextureheight; // note to red, this == &(ds_p->maskedtextureheight[0])
 
+#ifdef POLYOBJECTS
+			if (curline->polyseg) { // use REAL front and back floors please, so midtexture rendering isn't mucked up
+				rw_midtextureslide = rw_midtexturebackslide = 0;
+				if (!!(linedef->flags & ML_DONTPEGBOTTOM) ^ !!(linedef->flags & ML_EFFECT3))
+					rw_midtexturemid = rw_midtextureback = max(curline->frontsector->floorheight, curline->backsector->floorheight) - viewz;
+				else
+					rw_midtexturemid = rw_midtextureback = min(curline->frontsector->ceilingheight, curline->backsector->ceilingheight) - viewz;
+			} else
+#endif
 			// Set midtexture starting height
 			if (linedef->flags & ML_EFFECT2) { // Ignore slopes when texturing
 				rw_midtextureslide = rw_midtexturebackslide = 0;
@@ -3066,12 +3095,12 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	if (maskedtexture && !(ds_p->silhouette & SIL_TOP))
 	{
 		ds_p->silhouette |= SIL_TOP;
-		ds_p->tsilheight = sidedef->midtexture ? INT32_MIN: INT32_MAX;
+		ds_p->tsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MIN: INT32_MAX;
 	}
 	if (maskedtexture && !(ds_p->silhouette & SIL_BOTTOM))
 	{
 		ds_p->silhouette |= SIL_BOTTOM;
-		ds_p->bsilheight = sidedef->midtexture ? INT32_MAX: INT32_MIN;
+		ds_p->bsilheight = (sidedef->midtexture > 0 && sidedef->midtexture < numtextures) ? INT32_MAX: INT32_MIN;
 	}
 	ds_p++;
 }
diff --git a/src/r_splats.h b/src/r_splats.h
index 349d8fa7a4653cbb65874ca87950451f18ac9bbb..c0ba6881c7b384126796a30b9a9c8b5526419844 100644
--- a/src/r_splats.h
+++ b/src/r_splats.h
@@ -63,7 +63,11 @@ typedef struct floorsplat_s
 fixed_t P_SegLength(seg_t *seg);
 
 // call at P_SetupLevel()
+#if !(defined (WALLSPLATS) || defined (FLOORSPLATS))
+FUNCMATH void R_ClearLevelSplats(void);
+#else
 void R_ClearLevelSplats(void);
+#endif
 
 #ifdef WALLSPLATS
 void R_AddWallSplat(line_t *wallline, INT16 sectorside, const char *patchname, fixed_t top,
diff --git a/src/r_things.c b/src/r_things.c
index eaab536137177b46388bf9ed56c51c24a8f4a00a..331febabd41c4a5bda0e77c574f31548fcc9c19d 100644
--- a/src/r_things.c
+++ b/src/r_things.c
@@ -280,7 +280,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
 		{
 			case 0xff:
 			// no rotations were found for that frame at all
-			I_Error("R_AddSingleSpriteDef: No patches found for %s frame %c", sprname, R_Frame2Char(frame));
+			I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
 			break;
 
 			case 0:
@@ -293,7 +293,7 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef,
 				// we test the patch lump, or the id lump whatever
 				// if it was not loaded the two are LUMPERROR
 				if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
-					I_Error("R_AddSingleSpriteDef: Sprite %s frame %c is missing rotations",
+					I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations",
 					        sprname, R_Frame2Char(frame));
 			break;
 		}
@@ -891,12 +891,18 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
 #endif
 	fixed_t frac;
 	patch_t *patch;
+	INT64 overflow_test;
 
 	//Fab : R_InitSprites now sets a wad lump number
 	patch = W_CacheLumpNum(vis->patch, PU_CACHE);
 	if (!patch)
 		return;
 
+	// Check for overflow
+	overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
+	if (overflow_test < 0) overflow_test = -overflow_test;
+	if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
+
 	if (vis->transmap)
 	{
 		colfunc = fuzzcolfunc;
@@ -1634,7 +1640,8 @@ void R_SortVisSprites(void)
 	// Fix first and last. ds still points to the last one after the loop
 	dsfirst->prev = &unsorted;
 	unsorted.next = dsfirst;
-	ds->next = &unsorted;
+	if (ds)
+		ds->next = &unsorted;
 	unsorted.prev = ds;
 
 	// pull the vissprites out by scale
@@ -1698,21 +1705,25 @@ static void R_CreateDrawNodes(void)
 				entry->ffloor = ds->thicksides[i];
 			}
 		}
-		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!
+		// Check for a polyobject plane, but only if this is a front line
+		if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
+			plane = ds->curline->polyseg->visplane;
+			R_PlaneBounds(plane);
 
+			if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
+				;
+			else {
+				// Put it in!
 				entry = R_CreateDrawNode(&nodehead);
-				entry->plane = ds->curline->polyseg->visplane;
+				entry->plane = plane;
 				entry->seg = ds;
-				ds->curline->polyseg->visplane->polyobj = ds->curline->polyseg;
-				ds->curline->polyseg->visplane = NULL;
 			}
+			ds->curline->polyseg->visplane = NULL;
+		}
 #endif
-
+		if (ds->maskedtexturecol)
+		{
 			entry = R_CreateDrawNode(&nodehead);
 			entry->seg = ds;
 		}
@@ -1755,6 +1766,29 @@ static void R_CreateDrawNodes(void)
 		}
 	}
 
+#ifdef POLYOBJECTS_PLANES
+	// find all the remaining polyobject planes and add them on the end of the list
+	// probably this is a terrible idea if we wanted them to be sorted properly
+	// but it works getting them in for now
+	for (i = 0; i < numPolyObjects; i++)
+	{
+		if (!PolyObjects[i].visplane)
+			continue;
+		plane = PolyObjects[i].visplane;
+		R_PlaneBounds(plane);
+
+		if (plane->low < con_clipviewtop || plane->high > vid.height || plane->high > plane->low)
+		{
+			PolyObjects[i].visplane = NULL;
+			continue;
+		}
+		entry = R_CreateDrawNode(&nodehead);
+		entry->plane = plane;
+		// note: no seg is set, for what should be obvious reasons
+		PolyObjects[i].visplane = NULL;
+	}
+#endif
+
 	if (visspritecount == 0)
 		return;
 
@@ -1811,13 +1845,16 @@ static void R_CreateDrawNodes(void)
 				if (x1 < r2->plane->minx) x1 = r2->plane->minx;
 				if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
 
-				for (i = x1; i <= x2; i++)
+				if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
 				{
-					if (r2->seg->frontscale[i] > rover->scale)
-						break;
+					for (i = x1; i <= x2; i++)
+					{
+						if (r2->seg->frontscale[i] > rover->scale)
+							break;
+					}
+					if (i > x2)
+						continue;
 				}
-				if (i > x2)
-					continue;
 
 				entry = R_CreateDrawNode(NULL);
 				(entry->prev = r2->prev)->next = entry;
diff --git a/src/s_sound.h b/src/s_sound.h
index bcc7979a1fe8527306ffa0b38ffea70b8db0b985..39ec769a68b6aa13ac4056e26c4edec3c8af59fb 100644
--- a/src/s_sound.h
+++ b/src/s_sound.h
@@ -119,7 +119,7 @@ void S_ResumeAudio(void);
 //
 void S_UpdateSounds(void);
 
-fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);
+FUNCMATH fixed_t S_CalculateSoundDistance(fixed_t px1, fixed_t py1, fixed_t pz1, fixed_t px2, fixed_t py2, fixed_t pz2);
 
 void S_SetDigMusicVolume(INT32 volume);
 void S_SetMIDIMusicVolume(INT32 volume);
diff --git a/src/screen.c b/src/screen.c
index 3834f72d5cd783f66c1f4cb4fcd9fc9530b88de4..2780edb6088534f7b20a75643179f24e79fdab12 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -30,7 +30,7 @@
 #include "f_finale.h"
 
 
-#if defined (USEASM) //&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
+#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
 #define RUSEASM //MSC.NET can't patch itself
 #endif
 
@@ -69,6 +69,13 @@ consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, N
 consvar_t cv_scr_depth = {"scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 #endif
 consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
+
+#ifdef DIRECTFULLSCREEN
+static FUNCMATH void SCR_ChangeFullscreen (void);
+#else
+static void SCR_ChangeFullscreen (void);
+#endif
+
 consvar_t cv_fullscreen = {"fullscreen", "Yes", CV_SAVE|CV_CALL, CV_YesNo, SCR_ChangeFullscreen, 0, NULL, NULL, 0, 0, NULL};
 
 // =========================================================================
diff --git a/src/screen.h b/src/screen.h
index bdf8e5a7d69b45a34fbddb671f642b0cabbf7989..2dff4590ed6e35f54682ea5a335063582da2ae48 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -175,9 +175,7 @@ void SCR_SetDefaultMode (void);
 
 void SCR_Startup (void);
 
-void SCR_ChangeFullscreen (void);
-
-boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
+FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
 
 // move out to main code for consistency
 void SCR_DisplayTicRate(void);
diff --git a/src/sdl/MakeNIX.cfg b/src/sdl/MakeNIX.cfg
index f5c9b20750ec560ea144ee797eab492e5b6c9ec8..1a0b5421048ac134924e8b47e7d606e0abcf37e3 100644
--- a/src/sdl/MakeNIX.cfg
+++ b/src/sdl/MakeNIX.cfg
@@ -56,6 +56,15 @@ ifdef FREEBSD
 	LIBS+=-lipx -lkvm
 endif
 
+#
+#here is Mac OS X
+#
+ifdef MACOSX
+	OBJS+=$(OBJDIR)/mac_resources.o
+	OBJS+=$(OBJDIR)/mac_alert.o
+	LIBS+=-framework CoreFoundation
+endif
+
 #
 #here is GP2x (arm-gp2x-linux)
 #
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj
index d12a7efbf86acf4ae461b101c4024ab13708e88b..820192649d981adeaa477f0791d200f46d3ddfe9 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj
+++ b/src/sdl/Srb2SDL-vc10.vcxproj
@@ -167,6 +167,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
@@ -308,6 +309,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters
index 9396b4823bf5ed60465fc8fef72fcb86e989b64e..d04007dd77d026e48e8480bf93a54b86d279b7c5 100644
--- a/src/sdl/Srb2SDL-vc10.vcxproj.filters
+++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters
@@ -294,6 +294,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
@@ -666,6 +669,9 @@
     <ClCompile Include="..\md5.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
diff --git a/src/sdl/i_cdmus.c b/src/sdl/i_cdmus.c
index f3f7036677dfb1092dc23170e64bd60cd7287619..3105f512278e98536de12c9f27e02c5a884e4321 100644
--- a/src/sdl/i_cdmus.c
+++ b/src/sdl/i_cdmus.c
@@ -12,25 +12,25 @@ consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NUL
 consvar_t cdUpdate  = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 
-void I_InitCD(void){}
+FUNCMATH void I_InitCD(void){}
 
-void I_StopCD(void){}
+FUNCMATH void I_StopCD(void){}
 
-void I_PauseCD(void){}
+FUNCMATH void I_PauseCD(void){}
 
-void I_ResumeCD(void){}
+FUNCMATH void I_ResumeCD(void){}
 
-void I_ShutdownCD(void){}
+FUNCMATH void I_ShutdownCD(void){}
 
-void I_UpdateCD(void){}
+FUNCMATH void I_UpdateCD(void){}
 
-void I_PlayCD(UINT8 track, UINT8 looping)
+FUNCMATH void I_PlayCD(UINT8 track, UINT8 looping)
 {
 	(void)track;
 	(void)looping;
 }
 
-boolean I_SetVolumeCD(int volume)
+FUNCMATH boolean I_SetVolumeCD(int volume)
 {
 	(void)volume;
 	return false;
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index 0212e620bf3388bba03ec54bfb124823ab85973c..f72a9857d694d82c3f3d40c3ae3f06ee741cfcd8 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -590,70 +590,78 @@ static BOOL I_ReadyConsole(HANDLE ci)
 
 static boolean entering_con_command = false;
 
+static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
+{
+	event_t event;
+	CONSOLE_SCREEN_BUFFER_INFO CSBI;
+	DWORD t;
+
+	memset(&event,0x00,sizeof (event));
+
+	if (evt.bKeyDown)
+	{
+		event.type = ev_console;
+		entering_con_command = true;
+		switch (evt.wVirtualKeyCode)
+		{
+			case VK_ESCAPE:
+			case VK_TAB:
+				event.data1 = KEY_NULL;
+				break;
+			case VK_SHIFT:
+				event.data1 = KEY_LSHIFT;
+				break;
+			case VK_RETURN:
+				entering_con_command = false;
+				// Fall through.
+			default:
+				event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
+		}
+		if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
+		{
+			if (event.data1 && event.data1 != KEY_LSHIFT && event.data1 != KEY_RSHIFT)
+			{
+#ifdef _UNICODE
+				WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL);
+#else
+				WriteConsole(co, &evt.uChar.AsciiChar, 1 , &t, NULL);
+#endif
+			}
+			if (evt.wVirtualKeyCode == VK_BACK
+				&& GetConsoleScreenBufferInfo(co,&CSBI))
+			{
+				WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
+			}
+		}
+	}
+	else
+	{
+		event.type = ev_keyup;
+		switch (evt.wVirtualKeyCode)
+		{
+			case VK_SHIFT:
+				event.data1 = KEY_LSHIFT;
+				break;
+			default:
+				break;
+		}
+	}
+	if (event.data1) D_PostEvent(&event);
+}
+
 void I_GetConsoleEvents(void)
 {
-	event_t ev = {0,0,0,0};
 	HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
 	HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
-	CONSOLE_SCREEN_BUFFER_INFO CSBI;
 	INPUT_RECORD input;
 	DWORD t;
 
 	while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t)
 	{
-		memset(&ev,0x00,sizeof (ev));
 		switch (input.EventType)
 		{
 			case KEY_EVENT:
-				if (input.Event.KeyEvent.bKeyDown)
-				{
-					ev.type = ev_console;
-					entering_con_command = true;
-					switch (input.Event.KeyEvent.wVirtualKeyCode)
-					{
-						case VK_ESCAPE:
-						case VK_TAB:
-							ev.data1 = KEY_NULL;
-							break;
-						case VK_SHIFT:
-							ev.data1 = KEY_LSHIFT;
-							break;
-						case VK_RETURN:
-							entering_con_command = false;
-							// Fall through.
-						default:
-							ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char
-					}
-					if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
-					{
-						if (ev.data1 && ev.data1 != KEY_LSHIFT && ev.data1 != KEY_RSHIFT)
-						{
-#ifdef _UNICODE
-							WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL);
-#else
-							WriteConsole(co, &input.Event.KeyEvent.uChar.AsciiChar, 1 , &t, NULL);
-#endif
-						}
-						if (input.Event.KeyEvent.wVirtualKeyCode == VK_BACK
-							&& GetConsoleScreenBufferInfo(co,&CSBI))
-						{
-							WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
-						}
-					}
-				}
-				else
-				{
-					ev.type = ev_keyup;
-					switch (input.Event.KeyEvent.wVirtualKeyCode)
-					{
-						case VK_SHIFT:
-							ev.data1 = KEY_LSHIFT;
-							break;
-						default:
-							break;
-					}
-				}
-				if (ev.data1) D_PostEvent(&ev);
+				Impl_HandleKeyboardConsoleEvent(input.Event.KeyEvent, co);
 				break;
 			case MOUSE_EVENT:
 			case WINDOW_BUFFER_SIZE_EVENT:
@@ -2049,14 +2057,14 @@ void I_StartupMouse2(void)
 //
 // I_Tactile
 //
-void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
+FUNCMATH void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
 {
 	// UNUSED.
 	(void)pFFType;
 	(void)FFEffect;
 }
 
-void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
+FUNCMATH void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
 {
 	// UNUSED.
 	(void)pFFType;
@@ -2067,7 +2075,7 @@ void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
 */
 static ticcmd_t emptycmd;
 
-ticcmd_t *I_BaseTiccmd(void)
+FUNCMATH ticcmd_t *I_BaseTiccmd(void)
 {
 	return &emptycmd;
 }
@@ -2076,7 +2084,7 @@ ticcmd_t *I_BaseTiccmd(void)
 */
 static ticcmd_t emptycmd2;
 
-ticcmd_t *I_BaseTiccmd2(void)
+FUNCMATH ticcmd_t *I_BaseTiccmd2(void)
 {
 	return &emptycmd2;
 }
@@ -2179,7 +2187,7 @@ tic_t I_GetTime (void)
 //
 //I_StartupTimer
 //
-void I_StartupTimer(void)
+FUNCMATH void I_StartupTimer(void)
 {
 #if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX)
 	// for win2k time bug
@@ -2313,11 +2321,11 @@ void I_WaitVBL(INT32 count)
 	SDL_Delay(count);
 }
 
-void I_BeginRead(void)
+FUNCMATH void I_BeginRead(void)
 {
 }
 
-void I_EndRead(void)
+FUNCMATH void I_EndRead(void)
 {
 }
 
@@ -2647,6 +2655,47 @@ INT32 I_PutEnv(char *variable)
 #endif
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	char storage[256];
+	if (size > 255)
+		size = 255;
+	memcpy(storage, data, size);
+	storage[size] = 0;
+
+	if (SDL_SetClipboardText(storage))
+		return 0;
+	return -1;
+}
+
+const char *I_ClipboardPaste(void)
+{
+	static char clipboard_modified[256];
+	char *clipboard_contents, *i = clipboard_modified;
+
+	if (!SDL_HasClipboardText())
+		return NULL;
+	clipboard_contents = SDL_GetClipboardText();
+	memcpy(clipboard_modified, clipboard_contents, 255);
+	SDL_free(clipboard_contents);
+	clipboard_modified[255] = 0;
+
+	while (*i)
+	{
+		if (*i == '\n' || *i == '\r')
+		{ // End on newline
+			*i = 0;
+			break;
+		}
+		else if (*i == '\t')
+			*i = ' '; // Tabs become spaces
+		else if (*i < 32 || (unsigned)*i > 127)
+			*i = '?'; // Nonprintable chars become question marks
+		++i;
+	}
+	return (const char *)&clipboard_modified;
+}
+
 /**	\brief	The isWadPathOk function
 
 	\param	path	string path to check
@@ -3067,5 +3116,5 @@ const CPUInfoFlags *I_CPUInfo(void)
 }
 
 // note CPUAFFINITY code used to reside here
-void I_RegisterSysCommands(void) {}
+FUNCMATH void I_RegisterSysCommands(void) {}
 #endif
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index 9800c8cc730b72ce5bb323214a9bf8b7bb5cbee9..1f1fd8a11883efda2ca1747beba12f4d3ac6075b 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -33,14 +33,6 @@
 #pragma warning(default : 4214 4244)
 #endif
 
-#if SDL_VERSION_ATLEAST(1,3,0)
-#define SDLK_EQUALS SDLK_KP_EQUALSAS400
-#define SDLK_LMETA SDLK_LGUI
-#define SDLK_RMETA SDLK_RGUI
-#else
-#define HAVE_SDLMETAKEYS
-#endif
-
 #ifdef HAVE_TTF
 #include "i_ttf.h"
 #endif
@@ -190,15 +182,13 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen)
 			wasfullscreen = SDL_TRUE;
 			SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
 		}
-		else if (!fullscreen && wasfullscreen)
-		{
-			wasfullscreen = SDL_FALSE;
-			SDL_SetWindowFullscreen(window, 0);
-			SDL_SetWindowSize(window, width, height);
-			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
-		}
-		else if (!wasfullscreen)
+		else // windowed mode
 		{
+			if (wasfullscreen)
+			{
+				wasfullscreen = SDL_FALSE;
+				SDL_SetWindowFullscreen(window, 0);
+			}
 			// Reposition window only in windowed mode
 			SDL_SetWindowSize(window, width, height);
 			SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED_DISPLAY(1), SDL_WINDOWPOS_CENTERED_DISPLAY(1));
@@ -283,129 +273,70 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
 	}
 	switch (code)
 	{
-		case SDL_SCANCODE_F11: // F11 and F12 are
-			return KEY_F11;    // separated from the
-		case SDL_SCANCODE_F12: // rest of the function
-			return KEY_F12;    // keys
-
-		case SDL_SCANCODE_KP_0:
-			return KEY_KEYPAD0;
-		case SDL_SCANCODE_KP_1:
-			return KEY_KEYPAD1;
-		case SDL_SCANCODE_KP_2:
-			return KEY_KEYPAD2;
-		case SDL_SCANCODE_KP_3:
-			return KEY_KEYPAD3;
-		case SDL_SCANCODE_KP_4:
-			return KEY_KEYPAD4;
-		case SDL_SCANCODE_KP_5:
-			return KEY_KEYPAD5;
-		case SDL_SCANCODE_KP_6:
-			return KEY_KEYPAD6;
-		case SDL_SCANCODE_KP_7:
-			return KEY_KEYPAD7;
-		case SDL_SCANCODE_KP_8:
-			return KEY_KEYPAD8;
-		case SDL_SCANCODE_KP_9:
-			return KEY_KEYPAD9;
-
-		case SDL_SCANCODE_RETURN:
-			return KEY_ENTER;
-		case SDL_SCANCODE_ESCAPE:
-			return KEY_ESCAPE;
-		case SDL_SCANCODE_BACKSPACE:
-			return KEY_BACKSPACE;
-		case SDL_SCANCODE_TAB:
-			return KEY_TAB;
-		case SDL_SCANCODE_SPACE:
-			return KEY_SPACE;
-		case SDL_SCANCODE_MINUS:
-			return KEY_MINUS;
-		case SDL_SCANCODE_EQUALS:
-			return KEY_EQUALS;
-		case SDL_SCANCODE_LEFTBRACKET:
-			return '[';
-		case SDL_SCANCODE_RIGHTBRACKET:
-			return ']';
-		case SDL_SCANCODE_BACKSLASH:
-			return '\\';
-		case SDL_SCANCODE_NONUSHASH:
-			return '#';
-		case SDL_SCANCODE_SEMICOLON:
-			return ';';
-		case SDL_SCANCODE_APOSTROPHE:
-			return '\'';
-		case SDL_SCANCODE_GRAVE:
-			return '`';
-		case SDL_SCANCODE_COMMA:
-			return ',';
-		case SDL_SCANCODE_PERIOD:
-			return '.';
-		case SDL_SCANCODE_SLASH:
-			return '/';
-		case SDL_SCANCODE_CAPSLOCK:
-			return KEY_CAPSLOCK;
-		case SDL_SCANCODE_PRINTSCREEN:
-			return 0; // undefined?
-		case SDL_SCANCODE_SCROLLLOCK:
-			return KEY_SCROLLLOCK;
-		case SDL_SCANCODE_PAUSE:
-			return KEY_PAUSE;
-		case SDL_SCANCODE_INSERT:
-			return KEY_INS;
-		case SDL_SCANCODE_HOME:
-			return KEY_HOME;
-		case SDL_SCANCODE_PAGEUP:
-			return KEY_PGUP;
-		case SDL_SCANCODE_DELETE:
-			return KEY_DEL;
-		case SDL_SCANCODE_END:
-			return KEY_END;
-		case SDL_SCANCODE_PAGEDOWN:
-			return KEY_PGDN;
-		case SDL_SCANCODE_RIGHT:
-			return KEY_RIGHTARROW;
-		case SDL_SCANCODE_LEFT:
-			return KEY_LEFTARROW;
-		case SDL_SCANCODE_DOWN:
-			return KEY_DOWNARROW;
-		case SDL_SCANCODE_UP:
-			return KEY_UPARROW;
-		case SDL_SCANCODE_NUMLOCKCLEAR:
-			return KEY_NUMLOCK;
-		case SDL_SCANCODE_KP_DIVIDE:
-			return KEY_KPADSLASH;
-		case SDL_SCANCODE_KP_MULTIPLY:
-			return '*'; // undefined?
-		case SDL_SCANCODE_KP_MINUS:
-			return KEY_MINUSPAD;
-		case SDL_SCANCODE_KP_PLUS:
-			return KEY_PLUSPAD;
-		case SDL_SCANCODE_KP_ENTER:
-			return KEY_ENTER;
-		case SDL_SCANCODE_KP_PERIOD:
-			return KEY_KPADDEL;
-		case SDL_SCANCODE_NONUSBACKSLASH:
-			return '\\';
-
-		case SDL_SCANCODE_LSHIFT:
-			return KEY_LSHIFT;
-		case SDL_SCANCODE_RSHIFT:
-			return KEY_RSHIFT;
-		case SDL_SCANCODE_LCTRL:
-			return KEY_LCTRL;
-		case SDL_SCANCODE_RCTRL:
-			return KEY_RCTRL;
-		case SDL_SCANCODE_LALT:
-			return KEY_LALT;
-		case SDL_SCANCODE_RALT:
-			return KEY_RALT;
-		case SDL_SCANCODE_LGUI:
-			return KEY_LEFTWIN;
-		case SDL_SCANCODE_RGUI:
-			return KEY_RIGHTWIN;
-		default:
-			break;
+		// F11 and F12 are separated from the rest of the function keys
+		case SDL_SCANCODE_F11: return KEY_F11;
+		case SDL_SCANCODE_F12: return KEY_F12;
+
+		case SDL_SCANCODE_KP_0: return KEY_KEYPAD0;
+		case SDL_SCANCODE_KP_1: return KEY_KEYPAD1;
+		case SDL_SCANCODE_KP_2: return KEY_KEYPAD2;
+		case SDL_SCANCODE_KP_3: return KEY_KEYPAD3;
+		case SDL_SCANCODE_KP_4: return KEY_KEYPAD4;
+		case SDL_SCANCODE_KP_5: return KEY_KEYPAD5;
+		case SDL_SCANCODE_KP_6: return KEY_KEYPAD6;
+		case SDL_SCANCODE_KP_7: return KEY_KEYPAD7;
+		case SDL_SCANCODE_KP_8: return KEY_KEYPAD8;
+		case SDL_SCANCODE_KP_9: return KEY_KEYPAD9;
+
+		case SDL_SCANCODE_RETURN:         return KEY_ENTER;
+		case SDL_SCANCODE_ESCAPE:         return KEY_ESCAPE;
+		case SDL_SCANCODE_BACKSPACE:      return KEY_BACKSPACE;
+		case SDL_SCANCODE_TAB:            return KEY_TAB;
+		case SDL_SCANCODE_SPACE:          return KEY_SPACE;
+		case SDL_SCANCODE_MINUS:          return KEY_MINUS;
+		case SDL_SCANCODE_EQUALS:         return KEY_EQUALS;
+		case SDL_SCANCODE_LEFTBRACKET:    return '[';
+		case SDL_SCANCODE_RIGHTBRACKET:   return ']';
+		case SDL_SCANCODE_BACKSLASH:      return '\\';
+		case SDL_SCANCODE_NONUSHASH:      return '#';
+		case SDL_SCANCODE_SEMICOLON:      return ';';
+		case SDL_SCANCODE_APOSTROPHE:     return '\'';
+		case SDL_SCANCODE_GRAVE:          return '`';
+		case SDL_SCANCODE_COMMA:          return ',';
+		case SDL_SCANCODE_PERIOD:         return '.';
+		case SDL_SCANCODE_SLASH:          return '/';
+		case SDL_SCANCODE_CAPSLOCK:       return KEY_CAPSLOCK;
+		case SDL_SCANCODE_PRINTSCREEN:    return 0; // undefined?
+		case SDL_SCANCODE_SCROLLLOCK:     return KEY_SCROLLLOCK;
+		case SDL_SCANCODE_PAUSE:          return KEY_PAUSE;
+		case SDL_SCANCODE_INSERT:         return KEY_INS;
+		case SDL_SCANCODE_HOME:           return KEY_HOME;
+		case SDL_SCANCODE_PAGEUP:         return KEY_PGUP;
+		case SDL_SCANCODE_DELETE:         return KEY_DEL;
+		case SDL_SCANCODE_END:            return KEY_END;
+		case SDL_SCANCODE_PAGEDOWN:       return KEY_PGDN;
+		case SDL_SCANCODE_RIGHT:          return KEY_RIGHTARROW;
+		case SDL_SCANCODE_LEFT:           return KEY_LEFTARROW;
+		case SDL_SCANCODE_DOWN:           return KEY_DOWNARROW;
+		case SDL_SCANCODE_UP:             return KEY_UPARROW;
+		case SDL_SCANCODE_NUMLOCKCLEAR:   return KEY_NUMLOCK;
+		case SDL_SCANCODE_KP_DIVIDE:      return KEY_KPADSLASH;
+		case SDL_SCANCODE_KP_MULTIPLY:    return '*'; // undefined?
+		case SDL_SCANCODE_KP_MINUS:       return KEY_MINUSPAD;
+		case SDL_SCANCODE_KP_PLUS:        return KEY_PLUSPAD;
+		case SDL_SCANCODE_KP_ENTER:       return KEY_ENTER;
+		case SDL_SCANCODE_KP_PERIOD:      return KEY_KPADDEL;
+		case SDL_SCANCODE_NONUSBACKSLASH: return '\\';
+
+		case SDL_SCANCODE_LSHIFT: return KEY_LSHIFT;
+		case SDL_SCANCODE_RSHIFT: return KEY_RSHIFT;
+		case SDL_SCANCODE_LCTRL:  return KEY_LCTRL;
+		case SDL_SCANCODE_RCTRL:  return KEY_RCTRL;
+		case SDL_SCANCODE_LALT:   return KEY_LALT;
+		case SDL_SCANCODE_RALT:   return KEY_RALT;
+		case SDL_SCANCODE_LGUI:   return KEY_LEFTWIN;
+		case SDL_SCANCODE_RGUI:   return KEY_RIGHTWIN;
+		default:                  break;
 	}
 #ifdef HWRENDER
 	DBG_Printf("Unknown incoming scancode: %d, represented %c\n",
@@ -437,15 +368,10 @@ static void VID_Command_NumModes_f (void)
 	CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes());
 }
 
+// SDL2 doesn't have SDL_GetVideoSurface or a lot of the SDL_Surface flags that SDL 1.2 had
 static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
 {
-#if 1
-	(void)infoSurface;
-	(void)SurfaceText;
-	SDL2STUB();
-#else
 	INT32 vfBPP;
-	const SDL_Surface *VidSur = SDL_GetVideoSurface();
 
 	if (!infoSurface)
 		return;
@@ -458,49 +384,12 @@ static void SurfaceInfo(const SDL_Surface *infoSurface, const char *SurfaceText)
 	CONS_Printf("\x82" "%s\n", SurfaceText);
 	CONS_Printf(M_GetText(" %ix%i at %i bit color\n"), infoSurface->w, infoSurface->h, vfBPP);
 
-	if (infoSurface->flags&SDL_HWSURFACE)
-		CONS_Printf("%s", M_GetText(" Stored in video memory\n"));
-	else if (infoSurface->flags&SDL_OPENGL)
-		CONS_Printf("%s", M_GetText(" Stored in an OpenGL context\n"));
-	else if (infoSurface->flags&SDL_PREALLOC)
+	if (infoSurface->flags&SDL_PREALLOC)
 		CONS_Printf("%s", M_GetText(" Uses preallocated memory\n"));
 	else
 		CONS_Printf("%s", M_GetText(" Stored in system memory\n"));
-
-	if (infoSurface->flags&SDL_ASYNCBLIT)
-		CONS_Printf("%s", M_GetText(" Uses asynchronous blits if possible\n"));
-	else
-		CONS_Printf("%s", M_GetText(" Uses synchronous blits if possible\n"));
-
-	if (infoSurface->flags&SDL_ANYFORMAT)
-		CONS_Printf("%s", M_GetText(" Allows any pixel-format\n"));
-
-	if (infoSurface->flags&SDL_HWPALETTE)
-		CONS_Printf("%s", M_GetText(" Has exclusive palette access\n"));
-	else if (VidSur == infoSurface)
-		CONS_Printf("%s", M_GetText(" Has nonexclusive palette access\n"));
-
-	if (infoSurface->flags&SDL_DOUBLEBUF)
-		CONS_Printf("%s", M_GetText(" Double buffered\n"));
-	else if (VidSur == infoSurface)
-		CONS_Printf("%s", M_GetText(" No hardware flipping\n"));
-
-	if (infoSurface->flags&SDL_FULLSCREEN)
-		CONS_Printf("%s", M_GetText(" Full screen\n"));
-	else if (infoSurface->flags&SDL_RESIZABLE)
-		CONS_Printf("%s", M_GetText(" Resizable window\n"));
-	else if (VidSur == infoSurface)
-		CONS_Printf("%s", M_GetText(" Nonresizable window\n"));
-
-	if (infoSurface->flags&SDL_HWACCEL)
-		CONS_Printf("%s", M_GetText(" Uses hardware acceleration blit\n"));
-	if (infoSurface->flags&SDL_SRCCOLORKEY)
-		CONS_Printf("%s", M_GetText(" Use colorkey blitting\n"));
 	if (infoSurface->flags&SDL_RLEACCEL)
 		CONS_Printf("%s", M_GetText(" Colorkey RLE acceleration blit\n"));
-	if (infoSurface->flags&SDL_SRCALPHA)
-		CONS_Printf("%s", M_GetText(" Use alpha blending acceleration blit\n"));
-#endif
 }
 
 static void VID_Command_Info_f (void)
@@ -584,23 +473,6 @@ static void VID_Command_Mode_f (void)
 		setmodeneeded = modenum+1; // request vid mode change
 }
 
-#if 0
-#if defined(RPC_NO_WINDOWS_H)
-static VOID MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
-	UNREFERENCED_PARAMETER(hWnd);
-	UNREFERENCED_PARAMETER(message);
-	UNREFERENCED_PARAMETER(wParam);
-	switch (message)
-	{
-		case WM_SETTEXT:
-			COM_BufAddText((LPCSTR)lParam);
-			break;
-	}
-}
-#endif
-#endif
-
 static inline void SDLJoyRemap(event_t *event)
 {
 	(void)event;
@@ -966,218 +838,6 @@ void I_GetEvent(void)
 	// In order to make wheels act like buttons, we have to set their state to Up.
 	// This is because wheel messages don't have an up/down state.
 	gamekeydown[KEY_MOUSEWHEELDOWN] = gamekeydown[KEY_MOUSEWHEELUP] = 0;
-
-#if 0
-	SDL_Event inputEvent;
-	static SDL_bool sdlquit = SDL_FALSE; //Alam: once, just once
-	event_t event;
-
-	if (!graphics_started)
-		return;
-
-	memset(&inputEvent, 0x00, sizeof(inputEvent));
-	while (SDL_PollEvent(&inputEvent))
-	{
-		memset(&event,0x00,sizeof (event_t));
-		switch (inputEvent.type)
-		{
-			case SDL_ACTIVEEVENT:
-				if (inputEvent.active.state  & (SDL_APPACTIVE|SDL_APPINPUTFOCUS))
-				{
-					// pause music when alt-tab
-					if (inputEvent.active.gain /*&& !paused */)
-					{
-						static SDL_bool firsttimeonmouse = SDL_TRUE;
-						if (!firsttimeonmouse)
-						{
-							if (cv_usemouse.value) I_StartupMouse();
-						}
-						else firsttimeonmouse = SDL_FALSE;
-						//if (!netgame && !con_destlines) paused = false;
-						if (gamestate == GS_LEVEL)
-							if (!paused) I_ResumeSong(0); //resume it
-					}
-					else /*if (!paused)*/
-					{
-						if (!disable_mouse)
-							SDLforceUngrabMouse();
-						if (!netgame && gamestate == GS_LEVEL) paused = true;
-						memset(gamekeydown, 0, NUMKEYS);
-						//S_PauseSound();
-						if (gamestate == GS_LEVEL)
-							I_PauseSong(0); //pause it
-					}
-				}
-				if (MOUSE_MENU)
-				{
-					SDLdoUngrabMouse();
-					break;
-				}
-				if ((SDL_APPMOUSEFOCUS&inputEvent.active.state) && USE_MOUSEINPUT && inputEvent.active.gain)
-					HalfWarpMouse(realwidth, realheight);
-				break;
-			case SDL_KEYDOWN:
-			case SDL_KEYUP:
-				/// \todo inputEvent.key.which?
-				if (inputEvent.type == SDL_KEYUP)
-					event.type = ev_keyup;
-				else if (inputEvent.type == SDL_KEYDOWN)
-					event.type = ev_keydown;
-				else break;
-				event.data1 = SDLatekey(inputEvent.key.keysym.sym);
-				if (event.data1) D_PostEvent(&event);
-				break;
-			case SDL_MOUSEMOTION:
-				/// \todo inputEvent.motion.which
-				if (MOUSE_MENU)
-				{
-					SDLdoUngrabMouse();
-					break;
-				}
-				//if (USE_MOUSEINPUT) TODO SDL2 stub
-				{
-					// If the event is from warping the pointer back to middle
-					// of the screen then ignore it.
-					if ((inputEvent.motion.x == realwidth/2) &&
-					    (inputEvent.motion.y == realheight/2))
-					{
-						break;
-					}
-					else
-					{
-						event.data2 = +inputEvent.motion.xrel;
-						event.data3 = -inputEvent.motion.yrel;
-					}
-					event.type = ev_mouse;
-					D_PostEvent(&event);
-					// Warp the pointer back to the middle of the window
-					//  or we cannot move any further if it's at a border.
-					if ((inputEvent.motion.x < (realwidth/2 )-(realwidth/4 )) ||
-					    (inputEvent.motion.y < (realheight/2)-(realheight/4)) ||
-					    (inputEvent.motion.x > (realwidth/2 )+(realwidth/4 )) ||
-					    (inputEvent.motion.y > (realheight/2)+(realheight/4) ) )
-					{
-						//if (SDL_GRAB_ON == SDL_WM_GrabInput(SDL_GRAB_QUERY) || !mousegrabok)
-							HalfWarpMouse(realwidth, realheight);
-					}
-				}
-				break;
-			case SDL_MOUSEBUTTONDOWN:
-			case SDL_MOUSEBUTTONUP:
-				/// \todo inputEvent.button.which
-				if (USE_MOUSEINPUT)
-				{
-					if (inputEvent.type == SDL_MOUSEBUTTONUP)
-						event.type = ev_keyup;
-					else if (inputEvent.type == SDL_MOUSEBUTTONDOWN)
-						event.type = ev_keydown;
-					else break;
-					if (inputEvent.button.button==SDL_BUTTON_WHEELUP || inputEvent.button.button==SDL_BUTTON_WHEELDOWN)
-					{
-						if (inputEvent.type == SDL_MOUSEBUTTONUP)
-							event.data1 = 0; //Alam: dumb! this could be a real button with some mice
-						else
-							event.data1 = KEY_MOUSEWHEELUP + inputEvent.button.button - SDL_BUTTON_WHEELUP;
-					}
-					else if (inputEvent.button.button == SDL_BUTTON_MIDDLE)
-						event.data1 = KEY_MOUSE1+2;
-					else if (inputEvent.button.button == SDL_BUTTON_RIGHT)
-						event.data1 = KEY_MOUSE1+1;
-					else if (inputEvent.button.button <= MOUSEBUTTONS)
-						event.data1 = KEY_MOUSE1 + inputEvent.button.button - SDL_BUTTON_LEFT;
-					if (event.data1) D_PostEvent(&event);
-				}
-				break;
-			case SDL_JOYAXISMOTION:
-				inputEvent.jaxis.which++;
-				inputEvent.jaxis.axis++;
-				event.data1 = event.data2 = event.data3 = INT32_MAX;
-				if (cv_usejoystick.value == inputEvent.jaxis.which)
-				{
-					event.type = ev_joystick;
-				}
-				else if (cv_usejoystick.value == inputEvent.jaxis.which)
-				{
-					event.type = ev_joystick2;
-				}
-				else break;
-				//axis
-				if (inputEvent.jaxis.axis > JOYAXISSET*2)
-					break;
-				//vaule
-				if (inputEvent.jaxis.axis%2)
-				{
-					event.data1 = inputEvent.jaxis.axis / 2;
-					event.data2 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
-				}
-				else
-				{
-					inputEvent.jaxis.axis--;
-					event.data1 = inputEvent.jaxis.axis / 2;
-					event.data3 = SDLJoyAxis(inputEvent.jaxis.value, event.type);
-				}
-				D_PostEvent(&event);
-				break;
-			case SDL_JOYBALLMOTION:
-			case SDL_JOYHATMOTION:
-				break; //NONE
-			case SDL_JOYBUTTONDOWN:
-			case SDL_JOYBUTTONUP:
-				inputEvent.jbutton.which++;
-				if (cv_usejoystick.value == inputEvent.jbutton.which)
-					event.data1 = KEY_JOY1;
-				else if (cv_usejoystick.value == inputEvent.jbutton.which)
-					event.data1 = KEY_2JOY1;
-				else break;
-				if (inputEvent.type == SDL_JOYBUTTONUP)
-					event.type = ev_keyup;
-				else if (inputEvent.type == SDL_JOYBUTTONDOWN)
-					event.type = ev_keydown;
-				else break;
-				if (inputEvent.jbutton.button < JOYBUTTONS)
-					event.data1 += inputEvent.jbutton.button;
-				else
-					break;
-				SDLJoyRemap(&event);
-				if (event.type != ev_console) D_PostEvent(&event);
-				break;
-			case SDL_QUIT:
-				if (!sdlquit)
-				{
-					sdlquit = SDL_TRUE;
-					M_QuitResponse('y');
-				}
-				break;
-#if defined(RPC_NO_WINDOWS_H)
-			case SDL_SYSWMEVENT:
-				MainWndproc(inputEvent.syswm.msg->hwnd,
-					inputEvent.syswm.msg->msg,
-					inputEvent.syswm.msg->wParam,
-					inputEvent.syswm.msg->lParam);
-				break;
-#endif
-			case SDL_VIDEORESIZE:
-				if (gamestate == GS_LEVEL || gamestate == GS_TITLESCREEN || gamestate == GS_EVALUATION)
-				    setmodeneeded = VID_GetModeForSize(inputEvent.resize.w,inputEvent.resize.h)+1;
-				if (render_soft == rendermode)
-				{
-					SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
-					if (vidSurface) SDL_SetColors(vidSurface, localPalette, 0, 256);
-				}
-				else
-					SDLSetMode(realwidth, realheight, vid.bpp*8, surfaceFlagsW);
-				if (!vidSurface)
-					I_Error("Could not reset vidmode: %s\n",SDL_GetError());
-				break;
-			case SDL_VIDEOEXPOSE:
-				exposevideo = SDL_TRUE;
-				break;
-			default:
-				break;
-		}
-	}
-	//reset wheel like in win32, I don't understand it but works
-#endif
 }
 
 void I_StartupMouse(void)
@@ -1251,7 +911,7 @@ static inline boolean I_SkipFrame(void)
 {
 	static boolean skip = false;
 
-	if (render_soft != rendermode)
+	if (rendermode != render_soft)
 		return false;
 
 	skip = !skip;
@@ -1283,7 +943,7 @@ void I_FinishUpdate(void)
 	if (cv_ticrate.value)
 		SCR_DisplayTicRate();
 
-	if (render_soft == rendermode && screens[0])
+	if (rendermode == render_soft && screens[0])
 	{
 		SDL_Rect rect;
 
@@ -1310,7 +970,7 @@ void I_FinishUpdate(void)
 	}
 
 #ifdef HWRENDER
-	else
+	else if (rendermode == render_opengl)
 	{
 		OglSdlFinishUpdate(cv_vidwait.value);
 	}
@@ -1360,7 +1020,7 @@ void I_SetPalette(RGBA_t *palette)
 }
 
 // return number of fullscreen + X11 modes
-INT32 VID_NumModes(void)
+FUNCMATH INT32 VID_NumModes(void)
 {
 	if (USE_FULLSCREEN && numVidModes != -1)
 		return numVidModes - firstEntry;
@@ -1368,7 +1028,7 @@ INT32 VID_NumModes(void)
 		return MAXWINMODES;
 }
 
-const char *VID_GetModeName(INT32 modeNum)
+FUNCMATH const char *VID_GetModeName(INT32 modeNum)
 {
 #if 0
 	if (USE_FULLSCREEN && numVidModes != -1) // fullscreen modes
@@ -1398,7 +1058,7 @@ const char *VID_GetModeName(INT32 modeNum)
 	return &vidModeName[modeNum][0];
 }
 
-INT32 VID_GetModeForSize(INT32 w, INT32 h)
+FUNCMATH INT32 VID_GetModeForSize(INT32 w, INT32 h)
 {
 	int i;
 	for (i = 0; i < MAXWINMODES; i++)
@@ -1508,11 +1168,6 @@ void VID_PrepareModeList(void)
 #endif
 }
 
-static inline void SDLESSet(void)
-{
-	SDL2STUB();
-}
-
 INT32 VID_SetMode(INT32 modeNum)
 {
 	SDLdoUngrabMouse();
@@ -1545,9 +1200,9 @@ INT32 VID_SetMode(INT32 modeNum)
 	}
 	Impl_SetWindowName("SRB2 "VERSIONSTRING);
 
-	SDLSetMode(windowedModes[modeNum][0], windowedModes[modeNum][1], USE_FULLSCREEN);
+	SDLSetMode(vid.width, vid.height, USE_FULLSCREEN);
 
-	if (render_soft == rendermode)
+	if (rendermode == render_soft)
 	{
 		if (bufSurface)
 		{
@@ -1564,56 +1219,63 @@ INT32 VID_SetMode(INT32 modeNum)
 static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
 {
 	int flags = 0;
+
+	if (rendermode == render_none) // dedicated
+		return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh
+
 	if (window != NULL)
-	{
 		return SDL_FALSE;
-	}
 
 	if (fullscreen)
-	{
 		flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
-	}
 
 	if (borderlesswindow)
-	{
 		flags |= SDL_WINDOW_BORDERLESS;
+
+#ifdef HWRENDER
+	if (rendermode == render_opengl)
+		flags |= SDL_WINDOW_OPENGL;
+#endif
+
+	// Create a window
+	window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+			realwidth, realheight, flags);
+
+	if (window == NULL)
+	{
+		CONS_Printf(M_GetText("Couldn't create window: %s\n"), SDL_GetError());
+		return SDL_FALSE;
 	}
 
+	// Renderer-specific stuff
 #ifdef HWRENDER
 	if (rendermode == render_opengl)
 	{
-		window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-				realwidth, realheight, flags | SDL_WINDOW_OPENGL);
-		if (window != NULL)
+		sdlglcontext = SDL_GL_CreateContext(window);
+		if (sdlglcontext == NULL)
 		{
-			sdlglcontext = SDL_GL_CreateContext(window);
-			if (sdlglcontext == NULL)
-			{
-				SDL_DestroyWindow(window);
-				I_Error("Failed to create a GL context: %s\n", SDL_GetError());
-			}
-			else
-			{
-				SDL_GL_MakeCurrent(window, sdlglcontext);
-			}
+			SDL_DestroyWindow(window);
+			I_Error("Failed to create a GL context: %s\n", SDL_GetError());
 		}
-		else return SDL_FALSE;
+		SDL_GL_MakeCurrent(window, sdlglcontext);
 	}
+	else
 #endif
 	if (rendermode == render_soft)
 	{
-		window = SDL_CreateWindow("SRB2 "VERSIONSTRING, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
-				realwidth, realheight, flags);
-		if (window != NULL)
+		flags = 0; // Use this to set SDL_RENDERER_* flags now
+		if (usesdl2soft)
+			flags |= SDL_RENDERER_SOFTWARE;
+		else if (cv_vidwait.value)
+			flags |= SDL_RENDERER_PRESENTVSYNC;
+
+		renderer = SDL_CreateRenderer(window, -1, flags);
+		if (renderer == NULL)
 		{
-			renderer = SDL_CreateRenderer(window, -1, (usesdl2soft ? SDL_RENDERER_SOFTWARE : 0) | (cv_vidwait.value && !usesdl2soft ? SDL_RENDERER_PRESENTVSYNC : 0));
-			if (renderer != NULL)
-			{
-				SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
-			}
-			else return SDL_FALSE;
+			CONS_Printf(M_GetText("Couldn't create rendering context: %s\n"), SDL_GetError());
+			return SDL_FALSE;
 		}
-		else return SDL_FALSE;
+		SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT);
 	}
 
 	return SDL_TRUE;
@@ -1634,7 +1296,7 @@ static void Impl_SetWindowIcon(void)
 	{
 		return;
 	}
-	SDL2STUB();
+	//SDL2STUB(); // Monster Iestyn: why is this stubbed?
 	SDL_SetWindowIcon(window, icoSurface);
 }
 
@@ -1732,7 +1394,6 @@ void I_StartupGraphics(void)
 	borderlesswindow = M_CheckParm("-borderless");
 
 	//SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY>>1,SDL_DEFAULT_REPEAT_INTERVAL<<2);
-	SDLESSet();
 	VID_Command_ModeList_f();
 #ifdef HWRENDER
 	if (M_CheckParm("-opengl") || rendermode == render_opengl)
@@ -1830,7 +1491,7 @@ void I_ShutdownGraphics(void)
 	rendermode = render_none;
 	if (icoSurface) SDL_FreeSurface(icoSurface);
 	icoSurface = NULL;
-	if (render_soft == oldrendermode)
+	if (oldrendermode == render_soft)
 	{
 		if (vidSurface) SDL_FreeSurface(vidSurface);
 		vidSurface = NULL;
diff --git a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
index c3f0d3b38ca398116070f687881a551969feefbb..68391f99ca9168b9f5c68d62657df71fae5ba167 100644
--- a/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1214,7 +1214,7 @@
 		C01FCF4B08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.14;
+				CURRENT_PROJECT_VERSION = 2.1.19;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					NORMALSRB2,
@@ -1226,7 +1226,7 @@
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.14;
+				CURRENT_PROJECT_VERSION = 2.1.19;
 				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
 				GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/sdl/macosx/mac_alert.c b/src/sdl/macosx/mac_alert.c
index 455e36509547e40af0a4a65f13f0e5517fb5dc24..2a139041a65157d8852951156413a29eaaa3c943 100644
--- a/src/sdl/macosx/mac_alert.c
+++ b/src/sdl/macosx/mac_alert.c
@@ -25,19 +25,38 @@
 #include "mac_alert.h"
 #include <CoreFoundation/CoreFoundation.h>
 
+#define CFSTRINGIFY(x) CFStringCreateWithCString(NULL, x, kCFStringEncodingASCII)
+
 int MacShowAlert(const char *title, const char *message, const char *button1, const char *button2, const char *button3)
 {
 	CFOptionFlags results;
 
-	CFUserNotificationDisplayAlert(0,
-	 kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag,
-	 NULL, NULL, NULL,
-	 CFStringCreateWithCString(NULL, title, kCFStringEncodingASCII),
-	 CFStringCreateWithCString(NULL, message, kCFStringEncodingASCII),
-	 button1 != NULL ? CFStringCreateWithCString(NULL, button1, kCFStringEncodingASCII) : NULL,
-	 button2 != NULL ? CFStringCreateWithCString(NULL, button2, kCFStringEncodingASCII) : NULL,
-	 button3 != NULL ? CFStringCreateWithCString(NULL, button3, kCFStringEncodingASCII) : NULL,
-	 &results);
+        CFStringRef cf_title   = CFSTRINGIFY(title);
+        CFStringRef cf_message = CFSTRINGIFY(message);
+        CFStringRef cf_button1 = NULL;
+        CFStringRef cf_button2 = NULL;
+        CFStringRef cf_button3 = NULL;
+
+        if (button1 != NULL)
+            cf_button1 = CFSTRINGIFY(button1);
+        if (button2 != NULL)
+            cf_button2 = CFSTRINGIFY(button2);
+        if (button3 != NULL)
+            cf_button3 = CFSTRINGIFY(button3);
+
+        CFOptionFlags alert_flags = kCFUserNotificationStopAlertLevel | kCFUserNotificationNoDefaultButtonFlag;
+
+	CFUserNotificationDisplayAlert(0, alert_flags, NULL, NULL, NULL, cf_title, cf_message,
+                                       cf_button1, cf_button2, cf_button3, &results);
+
+        if (cf_button1 != NULL)
+           CFRelease(cf_button1);
+        if (cf_button2 != NULL)
+           CFRelease(cf_button2);
+        if (cf_button3 != NULL)
+           CFRelease(cf_button3);
+        CFRelease(cf_message);
+        CFRelease(cf_title);
 
 	return (int)results;
 }
diff --git a/src/sdl/macosx/mac_resources.c b/src/sdl/macosx/mac_resources.c
index dacc8014ba8da8fcd48ccbfe56a7772c4ec6c0fc..d67b925802666207160e9d75d3d0179042ca34ff 100644
--- a/src/sdl/macosx/mac_resources.c
+++ b/src/sdl/macosx/mac_resources.c
@@ -9,23 +9,29 @@ void OSX_GetResourcesPath(char * buffer)
     mainBundle = CFBundleGetMainBundle();
     if (mainBundle)
     {
+        const int BUF_SIZE = 256; // because we somehow always know that
+
         CFURLRef appUrlRef = CFBundleCopyBundleURL(mainBundle);
-        CFStringRef macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
-        CFStringRef resources = CFStringCreateWithCString(kCFAllocatorMalloc, "/Contents/Resources", kCFStringEncodingASCII);
-        const void* rawarray[2] = {macPath, resources};
-        CFArrayRef array = CFArrayCreate(kCFAllocatorMalloc, rawarray, 2, NULL);
-        CFStringRef separator = CFStringCreateWithCString(kCFAllocatorMalloc, "", kCFStringEncodingASCII);
-        CFStringRef fullPath = CFStringCreateByCombiningStrings(kCFAllocatorMalloc, array, separator);
-        const char * path = CFStringGetCStringPtr(fullPath, kCFStringEncodingASCII);
-        strcpy(buffer, path);
-        CFRelease(fullPath);
-        path = NULL;
-        CFRelease(array);
-        CFRelease(resources);
+        CFStringRef macPath;
+        if (appUrlRef != NULL)
+            macPath = CFURLCopyFileSystemPath(appUrlRef, kCFURLPOSIXPathStyle);
+        else
+            macPath = NULL;
+
+        const char* rawPath;
+
+        if (macPath != NULL)
+            rawPath = CFStringGetCStringPtr(macPath, kCFStringEncodingASCII);
+        else
+            rawPath = NULL;
+
+        if (rawPath != NULL && (CFStringGetLength(macPath) + strlen("/Contents/Resources") < BUF_SIZE))
+        {
+            strcpy(buffer, rawPath);
+            strcat(buffer, "/Contents/Resources");
+        }
+
         CFRelease(macPath);
         CFRelease(appUrlRef);
-        //CFRelease(mainBundle);
-        CFRelease(separator);
     }
-
-}
\ No newline at end of file
+}
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index faebca6b467125913aca2d8262d9b49d878ea324..88bbadd20ad91ecd1aa7a41230700539bd7b7fca 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -126,7 +126,7 @@ void I_ShutdownSound(void)
 #endif
 }
 
-void I_UpdateSound(void)
+FUNCMATH void I_UpdateSound(void)
 {
 }
 
@@ -220,7 +220,7 @@ static Mix_Chunk *ds2chunk(void *stream)
 		break;
 	default: // convert arbitrary hz to 44100.
 		step = 0;
-		frac = ((UINT32)freq << FRACBITS) / 44100;
+		frac = ((UINT32)freq << FRACBITS) / 44100 + 1; //Add 1 to counter truncation.
 		while (i < samples)
 		{
 			o = (INT16)(*s+0x80)<<8; // changed signedness and shift up to 16 bits
@@ -464,7 +464,7 @@ static void mix_gme(void *udata, Uint8 *stream, int len)
 }
 #endif
 
-void I_InitMusic(void)
+FUNCMATH void I_InitMusic(void)
 {
 }
 
@@ -769,7 +769,7 @@ boolean I_SetSongTrack(int track)
 // MIDI Music
 //
 
-void I_InitMIDIMusic(void)
+FUNCMATH void I_InitMIDIMusic(void)
 {
 }
 
diff --git a/src/sdl/ogl_sdl.c b/src/sdl/ogl_sdl.c
index 21afd831dc1b6f74070c828680f6f0a02bc81753..cd7ced7cab1eed7886af073f1c187b40ee18fd7e 100644
--- a/src/sdl/ogl_sdl.c
+++ b/src/sdl/ogl_sdl.c
@@ -71,7 +71,6 @@ INT32 oglflags = 0;
 void *GLUhandle = NULL;
 SDL_GLContext sdlglcontext = 0;
 
-#ifndef STATIC_OPENGL
 void *GetGLFunc(const char *proc)
 {
 	if (strncmp(proc, "glu", 3) == 0)
@@ -83,7 +82,6 @@ void *GetGLFunc(const char *proc)
 	}
 	return SDL_GL_GetProcAddress(proc);
 }
-#endif
 
 boolean LoadGL(void)
 {
diff --git a/src/sdl/ogl_sdl.h b/src/sdl/ogl_sdl.h
index 7e144644ce325d7c18b1d0916ad3fdae3f384421..2d6209f2bb94c1e28e35e96e949c5ddb641f567c 100644
--- a/src/sdl/ogl_sdl.h
+++ b/src/sdl/ogl_sdl.h
@@ -24,7 +24,6 @@ boolean OglSdlSurface(INT32 w, INT32 h);
 
 void OglSdlFinishUpdate(boolean vidwait);
 
-extern SDL_Window *window;
 extern SDL_Renderer *renderer;
 extern SDL_GLContext sdlglcontext;
 extern Uint16      realwidth;
diff --git a/src/sdl/sdlmain.h b/src/sdl/sdlmain.h
index 7ac32f4b3bf0268be5aaada164426a207195d790..fea1e16487dd8f5c4f7acfbbcf2de94d9ea77b1b 100644
--- a/src/sdl/sdlmain.h
+++ b/src/sdl/sdlmain.h
@@ -71,4 +71,7 @@ void I_GetConsoleEvents(void);
 
 void SDLforceUngrabMouse(void);
 
+// Needed for some WIN32 functions
+extern SDL_Window *window;
+
 #endif
diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c
index 888a6a507637e5a6c5d4e2c5de9099fcf34933d1..ed0db653d1f51df07ae714199f5bd9f68c05de21 100644
--- a/src/sdl12/i_system.c
+++ b/src/sdl12/i_system.c
@@ -2666,6 +2666,18 @@ INT32 I_PutEnv(char *variable)
 #endif
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 /**	\brief	The isWadPathOk function
 
 	\param	path	string path to check
diff --git a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
index 98599fb60b7ad0a89046d317f63292bc461dbae3..fada7849c2a2305aed694cd3ebb52f10597f5217 100644
--- a/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
+++ b/src/sdl12/macosx/Srb2mac.xcodeproj/project.pbxproj
@@ -1214,7 +1214,7 @@
 		C01FCF4B08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.14;
+				CURRENT_PROJECT_VERSION = 2.1.19;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					NORMALSRB2,
@@ -1226,7 +1226,7 @@
 		C01FCF4C08A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				CURRENT_PROJECT_VERSION = 2.1.14;
+				CURRENT_PROJECT_VERSION = 2.1.19;
 				GCC_ENABLE_FIX_AND_CONTINUE = NO;
 				GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
 				GCC_PREPROCESSOR_DEFINITIONS = (
diff --git a/src/st_stuff.c b/src/st_stuff.c
index aac6b09d2e4fc33fd347b47cbffac0b6eb843ed3..3562a9b713ef11bfec43436917ca56afbfa700bb 100644
--- a/src/st_stuff.c
+++ b/src/st_stuff.c
@@ -974,7 +974,7 @@ static void ST_drawNiGHTSHUD(void)
 	if (cv_debug & DBG_NIGHTSBASIC)
 		minlink = 0;
 
-	// Cheap hack: don't display when the score is showing
+	// Cheap hack: don't display when the score is showing (it popping up for a split second when exiting a map is intentional)
 	if (stplyr->texttimer && stplyr->textvar == 4)
 		minlink = INT32_MAX;
 
@@ -1385,6 +1385,10 @@ static void ST_drawMatchHUD(void)
 	if (G_TagGametype() && !(stplyr->pflags & PF_TAGIT))
 		return;
 
+#ifdef HAVE_BLUA
+	if (LUA_HudEnabled(hud_weaponrings)) {
+#endif
+
 	if (stplyr->powers[pw_infinityring])
 		ST_drawWeaponRing(pw_infinityring, 0, 0, offset, infinityring);
 	else if (stplyr->health > 1)
@@ -1408,6 +1412,12 @@ static void ST_drawMatchHUD(void)
 	offset += 20;
 	ST_drawWeaponRing(pw_railring, RW_RAIL, WEP_RAIL, offset, railring);
 
+#ifdef HAVE_BLUA
+	}
+
+	if (LUA_HudEnabled(hud_powerstones)) {
+#endif
+
 	// Power Stones collected
 	offset = 136; // Used for Y now
 
@@ -1439,6 +1449,10 @@ static void ST_drawMatchHUD(void)
 
 	if (stplyr->powers[pw_emeralds] & EMERALD7)
 		V_DrawScaledPatch(28, STRINGY(offset), V_SNAPTOLEFT, tinyemeraldpics[6]);
+
+#ifdef HAVE_BLUA
+	}
+#endif
 }
 
 static inline void ST_drawRaceHUD(void)
diff --git a/src/st_stuff.h b/src/st_stuff.h
index 6fafca4040f1585c43c50f6449c485e1c1e28e3d..c11559d2b4f73853972b333d7f4d8dee1d6c9490 100644
--- a/src/st_stuff.h
+++ b/src/st_stuff.h
@@ -24,7 +24,7 @@
 //
 
 // Called by main loop.
-void ST_Ticker(void);
+FUNCMATH void ST_Ticker(void);
 
 // Called by main loop.
 void ST_Drawer(void);
diff --git a/src/tables.h b/src/tables.h
index 0e4853cb9738bb620d954621c0f8adca55ef5702..e05b81845168a5b40505bcc57792714f9735db1e 100644
--- a/src/tables.h
+++ b/src/tables.h
@@ -82,7 +82,7 @@ typedef UINT32 angle_t;
 extern angle_t tantoangle[SLOPERANGE+1];
 
 // Utility function, called by R_PointToAngle.
-unsigned SlopeDiv(unsigned num, unsigned den);
+FUNCMATH unsigned SlopeDiv(unsigned num, unsigned den);
 
 // 360 - angle_t(ANGLE_45) = ANGLE_315
 FUNCMATH FUNCINLINE static ATTRINLINE angle_t InvAngle(angle_t a)
diff --git a/src/v_video.c b/src/v_video.c
index 3cc6d195f51e5b879e2704320cc65c70744a2615..64bb3214e0de5aa06fce57c08b4385e2dc2ca6c0 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -267,7 +267,7 @@ static void CV_Gammaxxx_ONChange(void)
 #endif
 
 
-#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__)
+#if defined (__GNUC__) && defined (__i386__) && !defined (NOASM) && !defined (__APPLE__) && !defined (NORUSEASM)
 void VID_BlitLinearScreen_ASM(const UINT8 *srcptr, UINT8 *destptr, INT32 width, INT32 height, size_t srcrowbytes,
 	size_t destrowbytes);
 #define HAVE_VIDCOPY
@@ -758,71 +758,80 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c)
 {
 	UINT8 *dest;
 	const UINT8 *deststop;
-	INT32 u, v, dupx, dupy;
+
+	if (rendermode == render_none)
+		return;
 
 #ifdef HWRENDER
-	if (rendermode != render_soft && rendermode != render_none)
+	if (rendermode != render_soft && !con_startup)
 	{
 		HWR_DrawFill(x, y, w, h, c);
 		return;
 	}
 #endif
 
-	dupx = vid.dupx;
-	dupy = vid.dupy;
-
-	if (!screens[0])
-		return;
-
-	if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
-	{ // Clear the entire screen, from dest to deststop. Yes, this really works.
-		memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
-		return;
-	}
+	if (!(c & V_NOSCALESTART))
+	{
+		INT32 dupx = vid.dupx, dupy = vid.dupy;
 
-	dest = screens[0] + y*dupy*vid.width + x*dupx;
-	deststop = screens[0] + vid.rowbytes * vid.height;
+		if (x == 0 && y == 0 && w == BASEVIDWIDTH && h == BASEVIDHEIGHT)
+		{ // Clear the entire screen, from dest to deststop. Yes, this really works.
+			memset(screens[0], (UINT8)(c&255), vid.width * vid.height * vid.bpp);
+			return;
+		}
 
-	if (w == BASEVIDWIDTH)
-		w = vid.width;
-	else
+		x *= dupx;
+		y *= dupy;
 		w *= dupx;
-	if (h == BASEVIDHEIGHT)
-		h = vid.height;
-	else
 		h *= dupy;
 
-	if (x && y && x + w < vid.width && y + h < vid.height)
-	{
 		// Center it if necessary
 		if (vid.width != BASEVIDWIDTH * dupx)
 		{
 			// dupx adjustments pretend that screen width is BASEVIDWIDTH * dupx,
 			// so center this imaginary screen
 			if (c & V_SNAPTORIGHT)
-				dest += (vid.width - (BASEVIDWIDTH * dupx));
+				x += (vid.width - (BASEVIDWIDTH * dupx));
 			else if (!(c & V_SNAPTOLEFT))
-				dest += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
+				x += (vid.width - (BASEVIDWIDTH * dupx)) / 2;
 		}
 		if (vid.height != BASEVIDHEIGHT * dupy)
 		{
 			// same thing here
 			if (c & V_SNAPTOBOTTOM)
-				dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width;
+				y += (vid.height - (BASEVIDHEIGHT * dupy));
 			else if (!(c & V_SNAPTOTOP))
-				dest += (vid.height - (BASEVIDHEIGHT * dupy)) * vid.width / 2;
+				y += (vid.height - (BASEVIDHEIGHT * dupy)) / 2;
 		}
 	}
 
+	if (x >= vid.width || y >= vid.height)
+		return; // off the screen
+	if (x < 0)
+	{
+		w += x;
+		x = 0;
+	}
+	if (y < 0)
+	{
+		h += y;
+		y = 0;
+	}
+
+	if (w <= 0 || h <= 0)
+		return; // zero width/height wouldn't draw anything
+	if (x + w > vid.width)
+		w = vid.width - x;
+	if (y + h > vid.height)
+		h = vid.height - y;
+
+	dest = screens[0] + y*vid.width + x;
+	deststop = screens[0] + vid.rowbytes * vid.height;
+
 	c &= 255;
 
-	for (v = 0; v < h; v++, dest += vid.width)
-		for (u = 0; u < w; u++)
-		{
-			if (dest > deststop)
-				return;
-			dest[u] = (UINT8)c;
-		}
+	for (;(--h >= 0) && dest < deststop; dest += vid.width)
+		memset(dest, (UINT8)(c&255), w * vid.bpp);
 }
 
 //
@@ -968,45 +977,38 @@ void V_DrawFadeScreen(void)
 }
 
 // Simple translucency with one color, over a set number of lines starting from the top.
-void V_DrawFadeConsBack(INT32 plines, INT32 pcolor)
+void V_DrawFadeConsBack(INT32 plines)
 {
-	UINT8 *deststop, *colormap, *buf;
+	UINT8 *deststop, *buf;
 
 #ifdef HWRENDER // not win32 only 19990829 by Kin
 	if (rendermode != render_soft && rendermode != render_none)
 	{
 		UINT32 hwcolor;
-		switch (pcolor)
+		switch (cons_backcolor.value)
 		{
-			case 0:		hwcolor = 0xffffff00;	break;	//white
-			case 1:		hwcolor = 0xff800000;	break;	//orange
-			case 2:		hwcolor = 0x0000ff00;	break;	//blue
-			case 3:		hwcolor = 0x00800000;	break;	//green
-			case 4:		hwcolor = 0x80808000;	break;	//gray
-			case 5:		hwcolor = 0xff000000;	break;	//red
-			default:	hwcolor = 0x00800000;	break;	//green
+			case 0:		hwcolor = 0xffffff00;	break; // White
+			case 1:		hwcolor = 0x80808000;	break; // Gray
+			case 2:		hwcolor = 0x40201000;	break; // Brown
+			case 3:		hwcolor = 0xff000000;	break; // Red
+			case 4:		hwcolor = 0xff800000;	break; // Orange
+			case 5:		hwcolor = 0x80800000;	break; // Yellow
+			case 6:		hwcolor = 0x00800000;	break; // Green
+			case 7:		hwcolor = 0x0000ff00;	break; // Blue
+			case 8:		hwcolor = 0x4080ff00;	break; // Cyan
+			// Default green
+			default:	hwcolor = 0x00800000;	break;
 		}
 		HWR_DrawConsoleBack(hwcolor, plines);
 		return;
 	}
 #endif
 
-	switch (pcolor)
-	{
-		case 0:		colormap = cwhitemap; 	break;
-		case 1:		colormap = corangemap;	break;
-		case 2:		colormap = cbluemap;	break;
-		case 3:		colormap = cgreenmap;	break;
-		case 4:		colormap = cgraymap;	break;
-		case 5:		colormap = credmap;		break;
-		default:	colormap = cgreenmap;	break;
-	}
-
 	// heavily simplified -- we don't need to know x or y position,
 	// just the stop position
 	deststop = screens[0] + vid.rowbytes * min(plines, vid.height);
 	for (buf = screens[0]; buf < deststop; ++buf)
-		*buf = colormap[*buf];
+		*buf = consolebgmap[*buf];
 }
 
 // Gets string colormap, used for 0x80 color codes
diff --git a/src/v_video.h b/src/v_video.h
index 70255d0ef9c72c80cd866eb65051d0b403dcf2d8..353f84c1d973223e642436000f1464211fdeb7a0 100644
--- a/src/v_video.h
+++ b/src/v_video.h
@@ -145,7 +145,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum);
 // fade down the screen buffer before drawing the menu over
 void V_DrawFadeScreen(void);
 
-void V_DrawFadeConsBack(INT32 plines, INT32 pcolor);
+void V_DrawFadeConsBack(INT32 plines);
 
 // draw a single character
 void V_DrawCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed);
diff --git a/src/w_wad.c b/src/w_wad.c
index 40fea52230c20ef4cdac76a22a162158314c080b..3a8285593e81cf067750712cce9468a57fce771c 100644
--- a/src/w_wad.c
+++ b/src/w_wad.c
@@ -133,6 +133,47 @@ void W_Shutdown(void)
 
 static char filenamebuf[MAX_WADPATH];
 
+// W_OpenWadFile
+// Helper function for opening the WAD file.
+// Returns the FILE * handle for the file, or NULL if not found or could not be opened
+// If "useerrors" is true then print errors in the console, else just don't bother
+// "filename" may be modified to have the correct path the actual file is located in, if necessary
+FILE *W_OpenWadFile(const char **filename, boolean useerrors)
+{
+	FILE *handle;
+
+	strncpy(filenamebuf, *filename, MAX_WADPATH);
+	filenamebuf[MAX_WADPATH - 1] = '\0';
+	*filename = filenamebuf;
+
+	// open wad file
+	if ((handle = fopen(*filename, "rb")) == NULL)
+	{
+		// If we failed to load the file with the path as specified by
+		// the user, strip the directories and search for the file.
+		nameonly(filenamebuf);
+
+		// If findfile finds the file, the full path will be returned
+		// in filenamebuf == *filename.
+		if (findfile(filenamebuf, NULL, true))
+		{
+			if ((handle = fopen(*filename, "rb")) == NULL)
+			{
+				if (useerrors)
+					CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), *filename);
+				return NULL;
+			}
+		}
+		else
+		{
+			if (useerrors)
+				CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), *filename);
+			return NULL;
+		}
+	}
+	return handle;
+}
+
 // search for all DEHACKED lump in all wads and load it
 static inline void W_LoadDehackedLumps(UINT16 wadnum)
 {
@@ -234,7 +275,6 @@ static void W_InvalidateLumpnumCache(void)
 	memset(lumpnumcache, 0, sizeof (lumpnumcache));
 }
 
-
 //  Allocate a wadfile, setup the lumpinfo (directory) and
 //  lumpcache, add the wadfile to the current active wadfiles
 //
@@ -271,33 +311,9 @@ UINT16 W_LoadWadFile(const char *filename)
 		return INT16_MAX;
 	}
 
-	strncpy(filenamebuf, filename, MAX_WADPATH);
-	filenamebuf[MAX_WADPATH - 1] = '\0';
-	filename = filenamebuf;
-
 	// open wad file
-	if ((handle = fopen(filename, "rb")) == NULL)
-	{
-		// If we failed to load the file with the path as specified by
-		// the user, strip the directories and search for the file.
-		nameonly(filenamebuf);
-
-		// If findfile finds the file, the full path will be returned
-		// in filenamebuf == filename.
-		if (findfile(filenamebuf, NULL, true))
-		{
-			if ((handle = fopen(filename, "rb")) == NULL)
-			{
-				CONS_Alert(CONS_ERROR, M_GetText("Can't open %s\n"), filename);
-				return INT16_MAX;
-			}
-		}
-		else
-		{
-			CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), filename);
-			return INT16_MAX;
-		}
-	}
+	if ((handle = W_OpenWadFile(&filename, true)) == NULL)
+		return INT16_MAX;
 
 	// Check if wad files will overflow fileneededbuffer. Only the filename part
 	// is send in the packet; cf.
@@ -475,11 +491,11 @@ UINT16 W_LoadWadFile(const char *filename)
 	//
 	CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps);
 	wadfiles[numwadfiles] = wadfile;
-	W_LoadDehackedLumps(numwadfiles);
+	numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
+	W_LoadDehackedLumps(numwadfiles-1);
 
 	W_InvalidateLumpnumCache();
 
-	numwadfiles++;
 	return wadfile->numlumps;
 }
 
@@ -1115,21 +1131,11 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
 	size_t i, j;
 	int goodfile = false;
 
-	if (!checklist) I_Error("No checklist for %s\n", filename);
-	strlcpy(filenamebuf, filename, MAX_WADPATH);
-	filename = filenamebuf;
+	if (!checklist)
+		I_Error("No checklist for %s\n", filename);
 	// open wad file
-	if ((handle = fopen(filename, "rb")) == NULL)
-	{
-		nameonly(filenamebuf); // leave full path here
-		if (findfile(filenamebuf, NULL, true))
-		{
-			if ((handle = fopen(filename, "rb")) == NULL)
-				return -1;
-		}
-		else
-			return -1;
-	}
+	if ((handle = W_OpenWadFile(&filename, false)) == NULL)
+		return -1;
 
 	// detect dehacked file with the "soc" extension
 	if (stricmp(&filename[strlen(filename) - 4], ".soc") != 0
@@ -1223,6 +1229,7 @@ int W_VerifyNMUSlumps(const char *filename)
 		{"COLORMAP", 8},
 		{"PAL", 3},
 		{"CLM", 3},
+		{"TRANS", 5},
 		{NULL, 0},
 	};
 	return W_VerifyFile(filename, NMUSlist, false);
diff --git a/src/w_wad.h b/src/w_wad.h
index c13f6933816ec1fe0091eebca00f65c6393f3880..f7ea64a565098c4d7e3df0ab0ff30c37f1ba05e2 100644
--- a/src/w_wad.h
+++ b/src/w_wad.h
@@ -54,10 +54,8 @@ typedef struct
 
 #define lumpcache_t void *
 
-// Annoying cyclic dependency workaround: this inlcusion must come after
-// the definition of MAX_WADPATH.
 #ifdef HWRENDER
-#include "m_misc.h"
+#include "m_aatree.h"
 #endif
 
 typedef struct wadfile_s
@@ -84,6 +82,8 @@ extern wadfile_t *wadfiles[MAX_WADFILES];
 
 void W_Shutdown(void);
 
+// Opens a WAD file. Returns the FILE * handle for the file, or NULL if not found or could not be opened
+FILE *W_OpenWadFile(const char **filename, boolean useerrors);
 // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error
 UINT16 W_LoadWadFile(const char *filename);
 #ifdef DELFILE
diff --git a/src/win32/Makefile.cfg b/src/win32/Makefile.cfg
index f309f7db11d158fb878eaa8a4615bed1b9dbf6b3..99b8bc9b2ca4b6949944429546b3e379808e804a 100644
--- a/src/win32/Makefile.cfg
+++ b/src/win32/Makefile.cfg
@@ -85,13 +85,21 @@ endif
 	OBJS=$(OBJDIR)/dx_error.o $(OBJDIR)/fabdxlib.o $(OBJDIR)/win_vid.o $(OBJDIR)/win_dll.o
 endif
 
+
+ZLIB_CFLAGS?=-I../libs/zlib
+ifdef MINGW64
+ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz64
+else
+ZLIB_LDFLAGS?=-L../libs/zlib/win32 -lz32
+endif
+
 ifndef NOPNG
 ifndef PNG_CONFIG
-	PNG_CFLAGS?=-I../libs/libpng-src -I../libs/zlib
+	PNG_CFLAGS?=-I../libs/libpng-src
 ifdef MINGW64
-	PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64 -L../libs/zlib/win32 -lz64
+	PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng64
 else
-	PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32 -L../libs/zlib/win32 -lz32
+	PNG_LDFLAGS?=-L../libs/libpng-src/projects -lpng32
 endif #MINGW64
 endif #PNG_CONFIG
 endif #NOPNG
diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj
index 1e9d8241ede783576e7463246d5730164f54b836..064f75d7d06cdee1aa62d70dda03e9e28d53e6f2 100644
--- a/src/win32/Srb2win-vc10.vcxproj
+++ b/src/win32/Srb2win-vc10.vcxproj
@@ -145,6 +145,7 @@
     <ClCompile Include="..\lzf.c" />
     <ClCompile Include="..\md5.c" />
     <ClCompile Include="..\mserv.c" />
+    <ClCompile Include="..\m_aatree.c" />
     <ClCompile Include="..\m_anigif.c" />
     <ClCompile Include="..\m_argv.c" />
     <ClCompile Include="..\m_bbox.c" />
@@ -300,6 +301,7 @@
     <ClInclude Include="..\lzf.h" />
     <ClInclude Include="..\md5.h" />
     <ClInclude Include="..\mserv.h" />
+    <ClInclude Include="..\m_aatree.h" />
     <ClInclude Include="..\m_anigif.h" />
     <ClInclude Include="..\m_argv.h" />
     <ClInclude Include="..\m_bbox.h" />
diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters
index 3f5b84bfb7d131fef86d800acffcb53c4b9d6e4d..b2647ea1c21518389b7061276f6464d05998721b 100644
--- a/src/win32/Srb2win-vc10.vcxproj.filters
+++ b/src/win32/Srb2win-vc10.vcxproj.filters
@@ -255,6 +255,9 @@
     <ClCompile Include="..\lua_skinlib.c">
       <Filter>LUA</Filter>
     </ClCompile>
+    <ClCompile Include="..\m_aatree.c">
+      <Filter>M_Misc</Filter>
+    </ClCompile>
     <ClCompile Include="..\m_anigif.c">
       <Filter>M_Misc</Filter>
     </ClCompile>
@@ -662,6 +665,9 @@
     <ClInclude Include="..\md5.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
+    <ClInclude Include="..\m_aatree.h">
+      <Filter>M_Misc</Filter>
+    </ClInclude>
     <ClInclude Include="..\m_anigif.h">
       <Filter>M_Misc</Filter>
     </ClInclude>
diff --git a/src/win32/win_cd.c b/src/win32/win_cd.c
index d73b95523e69ac9599463f590e6db5adbae55a30..ae13d3e574895db68c1389f4151b1e4db1ce717a 100644
--- a/src/win32/win_cd.c
+++ b/src/win32/win_cd.c
@@ -180,9 +180,9 @@ static LPSTR hms(UINT seconds)
 	hours = minutes / 60;
 	minutes %= 60;
 	if (hours > 0)
-		sprintf (s, "%lu:%02lu:%02lu", hours, minutes, seconds);
+		sprintf (s, "%lu:%02lu:%02lu", (long unsigned int)hours, (long unsigned int)minutes, (long unsigned int)seconds);
 	else
-		sprintf (s, "%2lu:%02lu", minutes, seconds);
+		sprintf (s, "%2lu:%02lu", (long unsigned int)minutes, (long unsigned int)seconds);
 	return s;
 }
 
diff --git a/src/win32/win_dbg.c b/src/win32/win_dbg.c
index 23416af1b26672c71232c57cc057467d481f51a2..fe6ebb04ae6545bce5d2c89abf8c8f0a4f882f71 100644
--- a/src/win32/win_dbg.c
+++ b/src/win32/win_dbg.c
@@ -20,7 +20,9 @@
 
 
 #include <tchar.h>
+#ifndef HAVE_SDL
 #include "win_main.h"
+#endif
 #include "../doomdef.h" //just for VERSION
 #include "win_dbg.h"
 #include "../m_argv.h" //print the parameter in the log
diff --git a/src/win32/win_main.c b/src/win32/win_main.c
index 663eddbd443d7b3e5f7a2fffc09b74e2c4e6a508..4ac05f94f4cc02d88cebc2ec9dc645d0c0031476 100644
--- a/src/win32/win_main.c
+++ b/src/win32/win_main.c
@@ -69,7 +69,7 @@ static HCURSOR windowCursor = NULL; // main window cursor
 
 static LPCSTR wClassName = "SRB2WC";
 
-boolean appActive = false; // app window is active
+INT appActive = false; // app window is active
 
 #ifdef LOGMESSAGES
 FILE *logstream;
@@ -470,7 +470,7 @@ static inline BOOL tlErrorMessage(const TCHAR *err)
 	//
 	// warn user if there is one
 	//
-	printf("Error %Ts..\n", err);
+	printf("Error %s..\n", err);
 	fflush(stdout);
 
 	MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK);
diff --git a/src/win32/win_main.h b/src/win32/win_main.h
index ed55246ab2cc24aa0275893668477a97c93c4408..326a813ddd07952d412765a2c9aa282b74cf0fc9 100644
--- a/src/win32/win_main.h
+++ b/src/win32/win_main.h
@@ -23,7 +23,7 @@
 
 extern HWND hWndMain;
 
-extern boolean appActive;
+extern INT appActive;
 
 VOID I_GetSysMouseEvents(INT mouse_state);
 extern UINT MSHWheelMessage;
diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c
index 0331080c8e42acf6941f20ce39588a71e416acc3..80b89a6e64ccc549242b60ee216d0721c4f0096f 100644
--- a/src/win32/win_sys.c
+++ b/src/win32/win_sys.c
@@ -3598,6 +3598,18 @@ INT32 I_PutEnv(char *variable)
 	return putenv(variable);
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+const char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD);
 
 const CPUInfoFlags *I_CPUInfo(void)
diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c
index 88764ef733c70f2400ce9101433f69b7fd441337..3b6a472587cc161f214736005c48df406dde9925 100644
--- a/src/win32ce/win_sys.c
+++ b/src/win32ce/win_sys.c
@@ -3470,6 +3470,18 @@ INT32 I_PutEnv(char *variable)
 	return putenv(variable);
 }
 
+INT32 I_ClipboardCopy(const char *data, size_t size)
+{
+	(void)data;
+	(void)size;
+	return -1;
+}
+
+char *I_ClipboardPaste(void)
+{
+	return NULL;
+}
+
 typedef BOOL (WINAPI *MyFunc3) (DWORD);
 
 const CPUInfoFlags *I_CPUInfo(void)
diff --git a/src/y_inter.c b/src/y_inter.c
index b2e1cdf9fa7884a9867ba884921066690eb73210..42f1e2235861f29a4d2c28572e4629c88653a7e6 100644
--- a/src/y_inter.c
+++ b/src/y_inter.c
@@ -159,6 +159,20 @@ static void Y_CalculateMatchWinners(void);
 static void Y_FollowIntermission(void);
 static void Y_UnloadData(void);
 
+// Stuff copy+pasted from st_stuff.c
+static INT32 SCX(INT32 x)
+{
+	return FixedInt(FixedMul(x<<FRACBITS, vid.fdupx));
+}
+static INT32 SCY(INT32 z)
+{
+	return FixedInt(FixedMul(z<<FRACBITS, vid.fdupy));
+}
+
+#define ST_DrawNumFromHud(h,n)        V_DrawTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n)
+#define ST_DrawPadNumFromHud(h,n,q)   V_DrawPaddedTallNum(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, n, q)
+#define ST_DrawPatchFromHud(h,p)      V_DrawScaledPatch(SCX(hudinfo[h].x), SCY(hudinfo[h].y), V_NOSCALESTART, p)
+
 //
 // Y_IntermissionDrawer
 //
@@ -204,28 +218,31 @@ void Y_IntermissionDrawer(void)
 		INT32 bonusy;
 
 		// draw score
-		V_DrawScaledPatch(hudinfo[HUD_SCORE].x, hudinfo[HUD_SCORE].y, V_SNAPTOLEFT, sboscore);
-		V_DrawTallNum(hudinfo[HUD_SCORENUM].x, hudinfo[HUD_SCORENUM].y, V_SNAPTOLEFT, data.coop.score);
+		ST_DrawPatchFromHud(HUD_SCORE, sboscore);
+		ST_DrawNumFromHud(HUD_SCORENUM, data.coop.score);
 
 		// draw time
-		V_DrawScaledPatch(hudinfo[HUD_TIME].x, hudinfo[HUD_TIME].y, V_SNAPTOLEFT, sbotime);
+		ST_DrawPatchFromHud(HUD_TIME, sbotime);
 		if (cv_timetic.value == 1)
-			V_DrawTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT, data.coop.tics);
+			ST_DrawNumFromHud(HUD_SECONDS, data.coop.tics);
 		else
 		{
+			INT32 seconds, minutes, tictrn;
+
+			seconds = G_TicsToSeconds(data.coop.tics);
+			minutes = G_TicsToMinutes(data.coop.tics, true);
+			tictrn  = G_TicsToCentiseconds(data.coop.tics);
+
+			ST_DrawNumFromHud(HUD_MINUTES, minutes); // Minutes
+			ST_DrawPatchFromHud(HUD_TIMECOLON, sbocolon); // Colon
+			ST_DrawPadNumFromHud(HUD_SECONDS, seconds, 2); // Seconds
+
 			// we should show centiseconds on the intermission screen too, if the conditions are right.
 			if (modeattacking || cv_timetic.value == 2)
 			{
-				V_DrawPaddedTallNum(hudinfo[HUD_TICS].x, hudinfo[HUD_TICS].y, V_SNAPTOLEFT,
-					G_TicsToCentiseconds(data.coop.tics), 2);
-				V_DrawScaledPatch(hudinfo[HUD_TIMETICCOLON].x, hudinfo[HUD_TIMETICCOLON].y, V_SNAPTOLEFT, sboperiod);
+				ST_DrawPatchFromHud(HUD_TIMETICCOLON, sboperiod); // Period
+				ST_DrawPadNumFromHud(HUD_TICS, tictrn, 2); // Tics
 			}
-
-			V_DrawPaddedTallNum(hudinfo[HUD_SECONDS].x, hudinfo[HUD_SECONDS].y, V_SNAPTOLEFT,
-				G_TicsToSeconds(data.coop.tics), 2);
-			V_DrawScaledPatch(hudinfo[HUD_TIMECOLON].x, hudinfo[HUD_TIMECOLON].y, V_SNAPTOLEFT, sbocolon);
-			V_DrawTallNum(hudinfo[HUD_MINUTES].x, hudinfo[HUD_MINUTES].y, V_SNAPTOLEFT,
-				G_TicsToMinutes(data.coop.tics, false));
 		}
 
 		// draw the "got through act" lines and act number
@@ -965,7 +982,8 @@ void Y_StartIntermission(void)
 	}
 
 	// We couldn't display the intermission even if we wanted to.
-	if (dedicated) return;
+	// But we still need to give the players their score bonuses, dummy.
+	//if (dedicated) return;
 
 	// This should always exist, but just in case...
 	if(!mapheaderinfo[prevmap])