diff --git a/.gitattributes b/.gitattributes
index 777bf189aefad727b647f5024a447734739e8358..ef775b91288dbb8043d94d61f54796491938489e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -29,4 +29,6 @@
 /libs/zlib/nintendods/README -whitespace
 /libs/zlib/watcom/watcom_f.mak -crlf -whitespace
 /libs/zlib/watcom/watcom_l.mak -crlf -whitespace
+#Appveyor
+/appveyor.yml -crlf -whitespace
 # Other
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000000000000000000000000000000000..db44edb5d080ff3d3518575c304f8c761d5ee832
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,33 @@
+language: c
+sudo: required
+dist: trusty
+
+env:
+- CFLAGS=-Wno-absolute-value -Werror
+
+compiler:
+  - gcc
+  - clang
+
+cache:
+  directories:
+  - $HOME/srb2_cache
+
+addons:
+  apt:
+    packages:
+    - libsdl2-mixer-dev
+    - libpng-dev
+    - libgl1-mesa-dev
+    - libgme-dev
+    - p7zip-full
+
+before_script:
+  - mkdir $HOME/srb2_cache
+  - wget --verbose --server-response -c http://rosenthalcastle.org/srb2/SRB2-v2114-assets.7z -O $HOME/srb2_cache/SRB2-v2114-assets.7z
+  - 7z x $HOME/srb2_cache/SRB2-v2114-assets.7z -oassets
+  - mkdir build
+  - cd build
+  - cmake ..
+
+script: make
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b8fe0ab5731f219e3661c9f8316c873986ec98d5..cb93d22f0d68148e3f9a60eef3bd37bccf9fdfb0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,13 +23,13 @@ endfunction()
 # Macro to add OSX framework
 macro(add_framework fwname appname)
 	find_library(FRAMEWORK_${fwname}
-    	NAMES ${fwname}
-    	PATHS ${CMAKE_OSX_SYSROOT}/System/Library
-    		${CMAKE_OSX_SYSROOT}/Library
-    		/System/Library
-    		/Library
-    	PATH_SUFFIXES Frameworks
-    	NO_DEFAULT_PATH)
+	NAMES ${fwname}
+	PATHS ${CMAKE_OSX_SYSROOT}/System/Library
+		${CMAKE_OSX_SYSROOT}/Library
+		/System/Library
+		/Library
+	ATH_SUFFIXES Frameworks
+	NO_DEFAULT_PATH)
     if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
         MESSAGE(ERROR ": Framework ${fwname} not found")
     else()
@@ -80,9 +80,6 @@ endif()
 
 if(${CMAKE_SYSTEM} MATCHES "Darwin")
 	add_definitions(-DMACOSX)
-	if(${CMAKE_C_COMPILER_ID} MATCHES "Clang")
-		set(CLANG ON)
-	endif()
 endif()
 
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000000000000000000000000000000000000..4edcd7a7f422f45b84159f2a07dc8248e552b12a
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,71 @@
+version: 2.1.14.{branch}-{build}
+os: MinGW
+
+environment:
+ CC: i686-w64-mingw32-gcc
+ WINDRES: windres
+ MINGW_SDK: c:\msys64\mingw32
+ SDL2_URL: http://libsdl.org/release/SDL2-devel-2.0.4-mingw.tar.gz
+ SDL2_ARCHIVE: SDL2-devel-2.0.4-mingw.tar
+ SDL2_MOVE: SDL2-2.0.4\i686-w64-mingw32
+ SDL2_MIXER_URL: https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-devel-2.0.1-mingw.tar.gz
+ SDL2_MIXER_ARCHIVE: SDL2_mixer-devel-2.0.1-mingw.tar
+ SDL2_MIXER_MOVE: SDL2_mixer-2.0.1\i686-w64-mingw32
+
+cache:
+- SDL2-devel-2.0.4-mingw.tar.gz
+- SDL2_mixer-devel-2.0.1-mingw.tar.gz
+
+install:
+#Download SDL2
+- if not exist "%SDL2_ARCHIVE%.gz" appveyor DownloadFile "%SDL2_URL%" -FileName "%SDL2_ARCHIVE%.gz"
+- 7z x -y "%SDL2_ARCHIVE%.gz" -o%TMP% >null
+- 7z x -y "%TMP%\%SDL2_ARCHIVE%" -o%TMP% >null
+- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs %TMP%\%SDL2_MOVE% %MINGW_SDK% || exit 0
+- ps: (Get-Content ([System.Environment]::ExpandEnvironmentVariables("%TMP%\%SDL2_MOVE%\bin\sdl2-config")))                  | ForEach-Object { $_ -replace "/usr/local/cross-tools/i686-w64-mingw32", ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%")) } | Set-Content ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%\bin\sdl2-config"))
+- ps: (Get-Content ([System.Environment]::ExpandEnvironmentVariables("%TMP%\%SDL2_MOVE%\lib\cmake\SDL2\sdl2-config.cmake"))) | ForEach-Object { $_ -replace "/usr/local/cross-tools/i686-w64-mingw32", ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%")) } | Set-Content ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%\lib\cmake\SDL2\sdl2-config.cmake"))
+- ps: (Get-Content ([System.Environment]::ExpandEnvironmentVariables("%TMP%\%SDL2_MOVE%\lib\pkgconfig\sdl2.pc")))            | ForEach-Object { $_ -replace "/usr/local/cross-tools/i686-w64-mingw32", ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%")) } | Set-Content ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%\lib\pkgconfig\sdl2.pc"))
+#Download SDL2_Mixer
+- if not exist "%SDL2_MIXER_ARCHIVE%.gz" appveyor DownloadFile "%SDL2_MIXER_URL%" -FileName "%SDL2_MIXER_ARCHIVE%.gz"
+- 7z x -y "%SDL2_MIXER_ARCHIVE%.gz" -o%TMP% >null
+- 7z x -y "%TMP%\%SDL2_MIXER_ARCHIVE%" -o%TMP% >null
+- robocopy /S /xx /ns /nc /nfl /ndl /np /njh /njs %TMP%\%SDL2_MIXER_MOVE% %MINGW_SDK% || exit 0
+- ps: (Get-Content ([System.Environment]::ExpandEnvironmentVariables("%TMP%\%SDL2_MIXER_MOVE%\lib\pkgconfig\SDL2_mixer.pc")))| ForEach-Object { $_ -replace "/usr/local/cross-tools/i686-w64-mingw32", ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%")) } | Set-Content ([System.Environment]::ExpandEnvironmentVariables("%MINGW_SDK%\lib\pkgconfig\SDL2_mixer.pc"))
+
+before_build:
+- set SDL_PKGCONFIG=%MINGW_SDK%\lib\pkgconfig\sdl2.pc
+- set Path=%MINGW_SDK%\bin;%Path%
+- i686-w64-mingw32-gcc --version
+- mingw32-make --version
+- set SRB2_MFLAGS=-C src MINGW=1 WARNINGMODE=1 NOASM=1 NOUPX=1 GCC53=1
+
+build_script:
+- cmd: mingw32-make.exe %SRB2_MFLAGS% SDL=1 clean
+- cmd: mingw32-make.exe %SRB2_MFLAGS% SDL=1 ERRORMODE=1
+
+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%.7z
+- cmd: 7z a %BUILD_ARCHIVE% bin\Mingw\Release -xr!.gitignore
+- appveyor PushArtifact %BUILD_ARCHIVE%
+
+test: off
+
+deploy:
+  - provider: FTP
+    protocol: ftps
+    host: 
+      secure: NsLJEPIBvmwCOj8Tg8RoRQ==
+    username:
+      secure: ejxi5mvk7oLYu7QtbYojajEPigMy0mokaKhuEVuDZcA=
+    password:
+      secure: Hbn6Uy3lT0YZ88yFJ3aW4w==
+    folder: appveyor
+    application:
+    active_mode: false
+
+
+on_finish:
+#- cmd: echo xfreerdp /u:appveyor /cert-ignore +clipboard /v:<ip>:<port>
+#- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
diff --git a/bin/Resources/debian/README.Debian b/assets/debian/README.Debian
similarity index 100%
rename from bin/Resources/debian/README.Debian
rename to assets/debian/README.Debian
diff --git a/bin/Resources/debian/README.source b/assets/debian/README.source
similarity index 100%
rename from bin/Resources/debian/README.source
rename to assets/debian/README.source
diff --git a/assets/debian/changelog b/assets/debian/changelog
new file mode 100644
index 0000000000000000000000000000000000000000..a316b7df73f0a0f4e865d71416464f95358d6e3f
--- /dev/null
+++ b/assets/debian/changelog
@@ -0,0 +1,12 @@
+srb2-data (2.1.14~1) unstable; urgency=low
+
+  * Updated for SRB2 v2.1.14
+
+ -- Alam Arias <alam+debian@srb2.org>  Sat, 6 Jan 2016 11:00:00 -0500
+
+
+srb2-data (2.0.6-2) maverick; urgency=high
+
+  * Initial proper release..
+
+ -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Sat,  29 Jan 2011 01:18:42 +1300
diff --git a/bin/Resources/debian/compat b/assets/debian/compat
similarity index 100%
rename from bin/Resources/debian/compat
rename to assets/debian/compat
diff --git a/bin/Resources/debian/control b/assets/debian/control
similarity index 100%
rename from bin/Resources/debian/control
rename to assets/debian/control
diff --git a/bin/Resources/debian/copyright b/assets/debian/copyright
similarity index 100%
rename from bin/Resources/debian/copyright
rename to assets/debian/copyright
diff --git a/bin/Resources/debian/rules b/assets/debian/rules
similarity index 95%
rename from bin/Resources/debian/rules
rename to assets/debian/rules
index 514d8e07c5f7361659914ae167a9a070adc741d7..d86f92af2f81a8f63755431b95911ee2c2dfd204 100755
--- a/bin/Resources/debian/rules
+++ b/assets/debian/rules
@@ -37,7 +37,7 @@ RM	:= rm -rf
 DIR	:= $(shell pwd)
 
 PACKAGE := $(shell cat $(DIR)/debian/control | grep 'Package:' | sed -e 's/Package: //g')
-DATAFILES := drill.dta music.dta soar.dta zones.dta player.dta rings.wpn srb2.wad
+DATAFILES := srb2.srb zones.dta player.dta rings.dta music.dta
 
 DATADIR	:= usr/games/SRB2
 RESOURCEDIR := .
@@ -48,7 +48,7 @@ build:
 	# This will need to be updated every time SRB2 official version is
 	# Copy data files to their install locations, and add data files to include-binaries
 	for file in $(DATAFILES); do \
-		$(WGET) http://alam.srb2.org/SRB2/2.0.6-Final/Resources/$$file; \
+		$(WGET) http://alam.srb2.org/SRB2/2.1.14-Final/Resources/$$file; \
 		if test "$$file" = "srb2.wad"; then \
 			$(INSTALL) $(RESOURCEDIR)/$$file $(DIR)/debian/tmp/$(DATADIR)/srb2.srb; \
 		else \
diff --git a/assets/debian/source/format b/assets/debian/source/format
new file mode 100644
index 0000000000000000000000000000000000000000..89ae9db8f88b823b6a7eabf55e203658739da122
--- /dev/null
+++ b/assets/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/bin/Resources/debian/changelog b/bin/Resources/debian/changelog
deleted file mode 100644
index 0c514d4d22fc73af8471e425df66d83bc17777e0..0000000000000000000000000000000000000000
--- a/bin/Resources/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-srb2-data (2.0.6-2) maverick; urgency=high
-
-  * Initial proper release..
-
- -- Callum Dickinson <gcfreak_ag20@hotmail.com>  Sat, 29 Jan 2011 01:18:42 +1300
diff --git a/bin/Resources/debian/source/format b/bin/Resources/debian/source/format
deleted file mode 100644
index 163aaf8d82b6c54f23c45f32895dbdfdcc27b047..0000000000000000000000000000000000000000
--- a/bin/Resources/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/cmake/Modules/FindSDL2.cmake b/cmake/Modules/FindSDL2.cmake
index 9e789e19cc85e547bca49e7d23810421ba48dc1f..2fc833cefcd01c34e2430c2ecd2bd999ca85d82b 100644
--- a/cmake/Modules/FindSDL2.cmake
+++ b/cmake/Modules/FindSDL2.cmake
@@ -1,6 +1,6 @@
 # Find SDL2
 # Once done, this will define
-# 
+#
 #  SDL2_FOUND - system has SDL2
 #  SDL2_INCLUDE_DIRS - SDL2 include directories
 #  SDL2_LIBRARIES - link libraries
diff --git a/cmake/Modules/FindSDL2_main.cmake b/cmake/Modules/FindSDL2_main.cmake
index 280e51e2e47b9555584af340b62d880422a21c3e..d4cbdeb11e199517fe53a6669e0850a6018dd11b 100644
--- a/cmake/Modules/FindSDL2_main.cmake
+++ b/cmake/Modules/FindSDL2_main.cmake
@@ -1,6 +1,6 @@
 # Find SDL2
 # Once done, this will define
-# 
+#
 #  SDL2_MAIN_FOUND - system has SDL2
 #  SDL2_MAIN_INCLUDE_DIRS - SDL2 include directories
 #  SDL2_MAIN_LIBRARIES - link libraries
diff --git a/cmake/Modules/FindSDL2_mixer.cmake b/cmake/Modules/FindSDL2_mixer.cmake
index 59b4823ed8ddb4406fd8dc8036675025c43d6fff..9af3e26dd85895d2ebac39030eb3b0f2b3cfea0f 100644
--- a/cmake/Modules/FindSDL2_mixer.cmake
+++ b/cmake/Modules/FindSDL2_mixer.cmake
@@ -1,6 +1,6 @@
 # Find SDL2
 # Once done, this will define
-# 
+#
 #  SDL2_MIXER_FOUND - system has SDL2
 #  SDL2_MIXER_INCLUDE_DIRS - SDL2 include directories
 #  SDL2_MIXER_LIBRARIES - link libraries
diff --git a/cmake/Modules/LibFindMacros.cmake b/cmake/Modules/LibFindMacros.cmake
index f6800aa7bd277e85ffa4297d27fbc980f0fda281..81fef7d8e7bd5e9adcfd42cc3fe6a06924b8ab38 100644
--- a/cmake/Modules/LibFindMacros.cmake
+++ b/cmake/Modules/LibFindMacros.cmake
@@ -123,7 +123,7 @@ function (libfind_process PREFIX)
   set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
   set(libraryopts ${${PREFIX}_PROCESS_LIBS})
 
-  # Process deps to add to 
+  # Process deps to add to
   foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
     if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
       # The package seems to export option lists that we can use, woohoo!
@@ -146,11 +146,11 @@ function (libfind_process PREFIX)
       endif()
     endif()
   endforeach()
-  
+
   if (includeopts)
     list(REMOVE_DUPLICATES includeopts)
   endif()
-  
+
   if (libraryopts)
     list(REMOVE_DUPLICATES libraryopts)
   endif()
@@ -215,7 +215,7 @@ function (libfind_process PREFIX)
       set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
       set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
     endif()
-    return()    
+    return()
   endif()
 
   # Format messages for debug info and the type of error
diff --git a/debian/control b/debian/control
index c64a85c4811d314e2657895b841cbd6d0b57ab0a..63b075f17d9eaa8c18680629cc9fab1cf0652ce3 100644
--- a/debian/control
+++ b/debian/control
@@ -4,13 +4,19 @@ Source: srb2
 Section: games
 Priority: extra
 Maintainer: Callum Dickinson <gcfreak_ag20@hotmail.com>
-Build-Depends: debhelper (>= 7.0.50~), libsdl1.2-dev (>= 1.2.7), libsdl-mixer1.2-dev (>= 1.2.7), libpng12-dev (>= 1.2.7), libglu1-dev | libglu-dev, libosmesa6-dev | libgl-dev, nasm [i386]
+Build-Depends: debhelper (>= 7.0.50~),
+ libsdl2-dev,
+ libsdl2-mixer-dev,
+ libpng12-dev (>= 1.2.7),
+ libglu1-dev | libglu-dev,
+ libosmesa6-dev | libgl-dev,
+ nasm [i386]
 Standards-Version: 3.8.4
 Homepage: http://www.srb2.org
 
 Package: srb2
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.0.6)
+Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.1.14)
 Description: A cross-platform 3D Sonic fangame
  Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog
  fangame built using a modified version of the Doom Legacy
@@ -22,8 +28,8 @@ Description: A cross-platform 3D Sonic fangame
 
 Package: srb2-dbg
 Architecture: any
-# FIXME: should be Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.0.6), srb2 but dh_shlibdeps is being an asshat
-Depends: libc6, ${misc:Depends}, srb2-data (= 2.0.6), srb2
+# FIXME: should be Depends: ${shlibs:Depends}, ${misc:Depends}, srb2-data (= 2.1.14), srb2 but dh_shlibdeps is being an asshat
+Depends: libc6, ${misc:Depends}, srb2-data (= 2.1.14), srb2
 Description: A cross-platform 3D Sonic fangame
  Sonic Robo Blast 2 is a 3D open-source Sonic the Hedgehog
  fangame built using a modified version of the Doom Legacy
diff --git a/debian/rules b/debian/rules
index 33ade54c8fe2aea2303df5a034c8c6574cc21f1f..e49784a0f21925400271c273bd547a1ffac93faf 100755
--- a/debian/rules
+++ b/debian/rules
@@ -59,16 +59,18 @@ DBGNAME	= debug/$(EXENAME)
 
 PKGDIR	= usr/games
 DBGDIR	= usr/lib/debug/$(PKGDIR)
+PIXMAPS_DIR = usr/share/pixmaps
+DESKTOP_DIR = usr/share/applications
 PREFIX	= $(shell test "$(CROSS_COMPILE_BUILD)" != "$(CROSS_COMPILE_HOST)" && echo "PREFIX=$(CROSS_COMPILE_HOST)")
 OS	= LINUX=1
 NONX86	= $(shell test "`echo $(CROSS_COMPILE_HOST) | grep 'i[3-6]86'`" || echo "NONX86=1")
-MAKEARGS = $(OS) $(NONX86) $(PREFIX) EXENAME=$(EXENAME) DBGNAME=$(DBGNAME) SDL_PKGCONFIG=sdl PNG_PKGCONFIG=libpng NOOBJDUMP=1
+MAKEARGS = $(OS) $(NONX86) $(PREFIX) EXENAME=$(EXENAME) DBGNAME=$(DBGNAME) SDL_PKGCONFIG=sdl2 PNG_PKGCONFIG=libpng NOOBJDUMP=1
 MENUFILE1 = ?package($(PACKAGE)):needs="X11" section="$(SECTION)"
 MENUFILE2 = title="$(TITLE)" command="/$(PKGDIR)/$(PACKAGE)"
 # FIXME pkg-config dir hacks
-export PKG_CONFIG_LIBDIR = /usr/$(CROSS_COMPILE_HOST)/lib/pkgconfig
+export PKG_CONFIG_LIBDIR = /usr/lib/$(CROSS_COMPILE_HOST)/pkgconfig
 BINDIR :=  $(DIR)/bin/Linux/Release
-LDFLAGS += "-Wl,-rpath=/usr/$(CROSS_COMPILE_HOST)/lib/"
+LDFLAGS += "-Wl,-rpath=/usr/lib/$(CROSS_COMPILE_HOST)"
 
 build:
 	$(MKDIR) $(BINDIR)/debug
@@ -80,14 +82,23 @@ binary-indep:
 	echo "no need to do any arch-independent stuff"
 
 binary-arch:
+	# create ddirs
 	$(MKDIR) $(DIR)/debian/tmp/$(PKGDIR) $(DIR)/debian/tmp/$(DBGDIR)
+	$(MKDIR) $(DIR)/debian/tmp/$(PKGDIR) $(DIR)/debian/tmp/$(DESKTOP_DIR)
+	$(MKDIR) $(DIR)/debian/tmp/$(PKGDIR) $(DIR)/debian/tmp/$(PIXMAPS_DIR)
+	# install main binaries
 	$(INSTALL) $(BINDIR)/$(EXENAME) $(DIR)/debian/tmp/$(PKGDIR)/$(PACKAGE)
 	$(INSTALL) $(BINDIR)/$(DBGNAME) $(DIR)/debian/tmp/$(DBGDIR)/$(PACKAGE)
+	# Install desktop file and banner image
+	$(INSTALL) $(DIR)/srb2.png $(DIR)/debian/tmp/usr/share/pixmaps
+	$(INSTALL) $(DIR)/debian/srb2.desktop $(DIR)/debian/tmp/usr/share/applications
 	# add compiled binaries to include-binaries
 	echo $(BINDIR)/$(EXENAME) >> $(DIR)/debian/source/include-binaries
 	echo $(BINDIR)/$(EXENAME) >> $(DIR)/debian/source/include-binaries
 	# Generate install folder files
 	echo $(PKGDIR) > $(DIR)/debian/$(PACKAGE).install
+	echo $(DESKTOP_DIR) >> $(DIR)/debian/$(PACKAGE).install
+	echo $(PIXMAPS_DIR) >> $(DIR)/debian/$(PACKAGE).install
 	echo $(DBGDIR) > $(DIR)/debian/$(DBGPKG).install
 
 binary: binary-arch
diff --git a/debian/srb2.desktop b/debian/srb2.desktop
new file mode 100644
index 0000000000000000000000000000000000000000..661832b93d4364c8011e08c841df415b6131553e
--- /dev/null
+++ b/debian/srb2.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Name=Sonic Robo Blast 2
+Comment=A free 3D Sonic the Hedgehog fan-game built using a modified ver. of the Doom Legacy source port
+Encoding=UTF-8
+Exec=srb2
+Icon=/usr/share/pixmaps/srb2.png
+Terminal=false
+Type=Application
+StartupNotify=false
+Categories=Application;Game;
diff --git a/srb2.png b/srb2.png
new file mode 100644
index 0000000000000000000000000000000000000000..9c13eae9a5d1ca26167abfe56486e2e7a642cd6c
Binary files /dev/null and b/srb2.png differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9a8b3baca4d9d1529e35ed4515ee23b9a8797742..5347fcd2f83de8d4308184ee168d3dd30a247b21 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -168,7 +168,7 @@ set(SRB2_CORE_GAME_SOURCES
 	p_tick.h
 )
 
-if(NOT CLANG)
+if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
 	set(SRB2_CORE_SOURCES ${SRB2_CORE_SOURCES} string.c)
 endif()
 
@@ -407,10 +407,14 @@ endif()
 
 # Compatibility flag with later versions of GCC
 # We should really fix our code to not need this
-if(NOT CLANG AND NOT MSVC)
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 	set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -mno-ms-bitfields)
 endif()
 
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+	set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wno-absolute-value)
+endif()
+
 add_definitions(-DCMAKECONFIG)
 
 #add_library(SRB2Core STATIC
@@ -432,4 +436,4 @@ endif()
 
 if(NOT ${SRB2_SDL2_AVAILABLE} AND NOT ${SRB2_WIN32_AVAILABLE})
 	message(FATAL_ERROR "There are no targets available to build an SRB2 executable. :(")
-endif()
\ No newline at end of file
+endif()
diff --git a/src/Makefile.cfg b/src/Makefile.cfg
index 1ea96df925c1d8594bd026698e1e8d253f209000..fa8896a7c200f03acea8fa722568dd0da11d0075 100644
--- a/src/Makefile.cfg
+++ b/src/Makefile.cfg
@@ -7,6 +7,22 @@
 # and other things
 #
 
+ifdef GCC53
+GCC52=1
+endif
+
+ifdef GCC52
+GCC51=1
+endif
+
+ifdef GCC51
+GCC49=1
+endif
+
+ifdef GCC49
+GCC48=1
+endif
+
 ifdef GCC48
 GCC47=1
 endif
@@ -139,6 +155,10 @@ WFLAGS+=-Wformat-security
 ifndef GCC29
 #WFLAGS+=-Winit-self
 endif
+ifdef GCC46
+WFLAGS+=-Wno-suggest-attribute=noreturn
+endif
+
 ifndef MINGW
 ifdef GCC45
 WFLAGS+=-Wunsuffixed-float-constants
@@ -155,6 +175,7 @@ ifdef GCC43
 endif
 WFLAGS+=$(OLDWFLAGS)
 
+
 #indicate platform and what interface use with
 ifndef WINCE
 ifndef XBOX
diff --git a/src/b_bot.c b/src/b_bot.c
index 5e62e58e6d38230f82b874fddd4cec5a9f8e0aff..3072b1d75785d2b2834760c166e08fb10f28e99f 100644
--- a/src/b_bot.c
+++ b/src/b_bot.c
@@ -49,7 +49,7 @@ static inline void B_BuildTailsTiccmd(mobj_t *sonic, mobj_t *tails, ticcmd_t *cm
 		if (sonic->player->pflags & (PF_MACESPIN|PF_ITEMHANG))
 		{
 			cmd->forwardmove = sonic->player->cmd.forwardmove;
-			cmd->angleturn = abs(tails->angle - sonic->angle)>>16;
+			cmd->angleturn = abs((tails->angle - sonic->angle))>>16;
 			if (sonic->angle < tails->angle)
 				cmd->angleturn = -cmd->angleturn;
 		} else if (dist > FixedMul(512*FRACUNIT, tails->scale))
diff --git a/src/console.c b/src/console.c
index e77c400b3fa98552f0c405b8c3acc96ed65c92cc..fcac0e6de99669b1c407e33ee6575ac4ec3cd088 100644
--- a/src/console.c
+++ b/src/console.c
@@ -202,7 +202,7 @@ static void CONS_Bind_f(void)
 	}
 
 	key = G_KeyStringtoNum(COM_Argv(1));
-	if (!key)
+	if (key <= 0 || key >= NUMINPUTS)
 	{
 		CONS_Alert(CONS_NOTICE, M_GetText("Invalid key name\n"));
 		return;
diff --git a/src/doomdef.h b/src/doomdef.h
index 558a9e115b5d14c99040d121689b74c32667312a..8935eb1179b866b1e105007feb44c3e261203442 100644
--- a/src/doomdef.h
+++ b/src/doomdef.h
@@ -210,13 +210,6 @@ extern FILE *logstream;
 // Note that we use this to help keep internal testing in check; this is why v2.1.0 is not version "1".
 #define MODVERSION 19
 
-
-
-
-
-// some tests, enable or disable it if it run or not
-#define SPLITSCREEN
-
 // =========================================================================
 
 // The maximum number of players, multiplayer/networking.
@@ -352,11 +345,7 @@ void CONS_Debug(INT32 debugflags, const char *fmt, ...) FUNCDEBUG;
 #include "m_swap.h"
 
 // Things that used to be in dstrings.h
-#define DEVMAPS "devmaps"
-#define DEVDATA "devdata"
-
 #define SAVEGAMENAME "srb2sav"
-
 char savegamename[256];
 
 // m_misc.h
diff --git a/src/f_finale.c b/src/f_finale.c
index a85fd11cb0438fb3950401339007f55cb8f71858..507616f3ca37c841802d6ec455dcebc9f7adf539 100644
--- a/src/f_finale.c
+++ b/src/f_finale.c
@@ -603,7 +603,7 @@ static void F_IntroDrawScene(void)
 
 				if (finalecount-84 < 58) { // Pure Fat is driving up!
 					int ftime = (finalecount-84);
-					x = (-189<<FRACBITS) + (FixedMul((6<<FRACBITS)+FRACUNIT/3, ftime<<FRACBITS) - FixedMul((6<<FRACBITS)+FRACUNIT/3, FixedDiv(FixedMul(ftime<<FRACBITS, ftime<<FRACBITS), 120<<FRACBITS)));
+					x = (-189*FRACUNIT) + (FixedMul((6<<FRACBITS)+FRACUNIT/3, ftime<<FRACBITS) - FixedMul((6<<FRACBITS)+FRACUNIT/3, FixedDiv(FixedMul(ftime<<FRACBITS, ftime<<FRACBITS), 120<<FRACBITS)));
 					y = (BASEVIDHEIGHT<<FRACBITS) - FixedMul(417<<FRACBITS, aspect);
 					// Draw the body
 					V_DrawSciencePatch(x, y, V_SNAPTOLEFT|V_SNAPTOBOTTOM, (patch = W_CachePatchName("PUREFAT1", PU_CACHE)), aspect);
diff --git a/src/g_game.c b/src/g_game.c
index 6d0ef5a5b3e61fce2c2eac60aae4541f4cbb4f7c..72cfe4a57727dcc3adb9e086dff0a49b3b0657d1 100644
--- a/src/g_game.c
+++ b/src/g_game.c
@@ -5571,7 +5571,7 @@ boolean G_CheckDemoStatus(void)
 		free(demobuffer);
 		demorecording = false;
 
-		if (!modeattacking == ATTACKING_RECORD)
+		if (modeattacking != ATTACKING_RECORD)
 		{
 			if (saved)
 				CONS_Printf(M_GetText("Demo %s recorded\n"), demoname);
diff --git a/src/g_input.c b/src/g_input.c
index f12ddb7114c4b935e79877de7195ee248c47f6c2..e9010b39d0580f14000bd802a61aabfe063efda7 100644
--- a/src/g_input.c
+++ b/src/g_input.c
@@ -16,7 +16,6 @@
 #include "g_input.h"
 #include "keys.h"
 #include "hu_stuff.h" // need HUFONT start & end
-#include "keys.h"
 #include "d_net.h"
 #include "console.h"
 
@@ -1042,13 +1041,13 @@ INT32 G_KeyStringtoNum(const char *keystr)
 	if (!keystr[1] && keystr[0] > ' ' && keystr[0] <= 'z')
 		return keystr[0];
 
+	if (!strncmp(keystr, "KEY", 3) && keystr[3] >= '0' && keystr[3] <= '9')
+		return atoi(&keystr[3]);
+
 	for (j = 0; j < NUMKEYNAMES; j++)
 		if (!stricmp(keynames[j].name, keystr))
 			return keynames[j].keynum;
 
-	if (strlen(keystr) > 3)
-		return atoi(&keystr[3]);
-
 	return 0;
 }
 
diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 7d6caa049c7548f95d11435d4e88ad96d1e8ed21..409900b986f989b7a001bfd262ec1bf33a394eba 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -2856,7 +2856,6 @@ static void HWR_AddPolyObjectPlanes(void)
 //                  : Draw one or more line segments.
 // Notes            : Sets gr_cursectorlight to the light of the parent sector, to modulate wall textures
 // -----------------+
-static lumpnum_t doomwaterflat;  //set by R_InitFlats hack
 static void HWR_Subsector(size_t num)
 {
 	INT16 count;
@@ -2867,7 +2866,6 @@ static void HWR_Subsector(size_t num)
 	INT32 ceilinglightlevel;
 	INT32 locFloorHeight, locCeilingHeight;
 	INT32 light = 0;
-	fixed_t wh;
 	extracolormap_t *floorcolormap;
 	extracolormap_t *ceilingcolormap;
 
@@ -3193,26 +3191,6 @@ static void HWR_Subsector(size_t num)
 		}
 	}
 
-//20/08/99: Changed by Hurdler (taken from faB's code)
-#ifdef DOPLANES
-	// -------------------- WATER IN DEV. TEST ------------------------
-	//dck hack : use abs(tag) for waterheight
-	//ilag : Since we changed to UINT16 for sector tags, simulate INT16
-	if (gr_frontsector->tag > 32767)
-	{
-		wh = ((65535-gr_frontsector->tag) <<FRACBITS) + (FRACUNIT/2);
-		if (wh > gr_frontsector->floorheight &&
-			wh < gr_frontsector->ceilingheight)
-		{
-			HWR_GetFlat(doomwaterflat);
-			HWR_RenderPlane(gr_frontsector,
-				&extrasubsectors[num], wh, PF_Translucent,
-				gr_frontsector->lightlevel, doomwaterflat,
-				NULL, 255, false, gr_frontsector->lightlist[light].extra_colormap);
-		}
-	}
-	// -------------------- WATER IN DEV. TEST ------------------------
-#endif
 	sub->validcount = validcount;
 }
 
@@ -5499,11 +5477,6 @@ void HWR_Startup(void)
 		HWR_AddEngineCommands();
 		HWR_InitTextureCache();
 
-		// for test water translucent surface
-		doomwaterflat  = W_CheckNumForName("FWATER1");
-		if (doomwaterflat == LUMPERROR) // if FWATER1 not found (in doom shareware)
-			doomwaterflat = W_GetNumForName("WATER0");
-
 		HWR_InitMD2();
 
 #ifdef ALAM_LIGHTING
diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c
index 77795ccc044d3f8f86b8501feaf1a1c41090a77a..6a315d88171b61b50371c89731a6d3a2d6b2879e 100644
--- a/src/hardware/hw_md2.c
+++ b/src/hardware/hw_md2.c
@@ -41,6 +41,7 @@
 #include "../r_things.h"
 
 #include "hw_main.h"
+#include "../v_video.h"
 #ifdef HAVE_PNG
 
 #ifndef _MSC_VER
@@ -881,6 +882,59 @@ static void md2_loadTexture(md2_t *model)
 	HWR_UnlockCachedPatch(grpatch);
 }
 
+// -----------------+
+// md2_loadBlendTexture  : Download a pcx or png texture for blending MD2 models
+// -----------------+
+static void md2_loadBlendTexture(md2_t *model)
+{
+	GLPatch_t *grpatch;
+	char *filename = Z_Malloc(strlen(model->filename)+7, PU_STATIC, NULL);
+	strcpy(filename, model->filename);
+
+	FIL_ForceExtension(filename, "_blend.png");
+
+	if (model->blendgrpatch)
+	{
+		grpatch = model->blendgrpatch;
+		Z_Free(grpatch->mipmap.grInfo.data);
+	}
+	else
+		grpatch = Z_Calloc(sizeof *grpatch, PU_HWRPATCHINFO,
+		                   &(model->blendgrpatch));
+
+	if (!grpatch->mipmap.downloaded && !grpatch->mipmap.grInfo.data)
+	{
+		int w = 0, h = 0;
+#ifdef HAVE_PNG
+		grpatch->mipmap.grInfo.format = PNG_Load(filename, &w, &h, grpatch);
+		if (grpatch->mipmap.grInfo.format == 0)
+#endif
+		grpatch->mipmap.grInfo.format = PCX_Load(filename, &w, &h, grpatch);
+		if (grpatch->mipmap.grInfo.format == 0)
+		{
+			Z_Free(filename);
+			return;
+		}
+
+		grpatch->mipmap.downloaded = 0;
+		grpatch->mipmap.flags = 0;
+
+		grpatch->width = (INT16)w;
+		grpatch->height = (INT16)h;
+		grpatch->mipmap.width = (UINT16)w;
+		grpatch->mipmap.height = (UINT16)h;
+
+		// not correct!
+		grpatch->mipmap.grInfo.smallLodLog2 = GR_LOD_LOG2_256;
+		grpatch->mipmap.grInfo.largeLodLog2 = GR_LOD_LOG2_256;
+		grpatch->mipmap.grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1;
+	}
+	HWD.pfnSetTexture(&grpatch->mipmap); // We do need to do this so that it can be cleared and knows to recreate it when necessary
+	HWR_UnlockCachedPatch(grpatch);
+
+	Z_Free(filename);
+}
+
 // Don't spam the console, or the OS with fopen requests!
 static boolean nomd2s = false;
 
@@ -1050,6 +1104,248 @@ spritemd2found:
 	fclose(f);
 }
 
+static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, skincolors_t color)
+{
+	UINT16 w = gpatch->width, h = gpatch->height;
+	UINT32 size = w*h;
+	RGBA_t *image, *blendimage, *cur, blendcolor;
+
+	if (grmip->width == 0)
+	{
+
+		grmip->width = gpatch->width;
+		grmip->height = gpatch->height;
+
+		// no wrap around, no chroma key
+		grmip->flags = 0;
+		// setup the texture info
+		grmip->grInfo.format = GR_RGBA;
+	}
+
+	Z_Free(grmip->grInfo.data);
+	grmip->grInfo.data = NULL;
+
+	cur = Z_Malloc(size*4, PU_HWRCACHE, &grmip->grInfo.data);
+	memset(cur, 0x00, size*4);
+
+	image = gpatch->mipmap.grInfo.data;
+	blendimage = blendgpatch->mipmap.grInfo.data;
+
+	switch (color)
+	{
+		case SKINCOLOR_WHITE:
+			blendcolor = V_GetColor(3);
+			break;
+		case SKINCOLOR_SILVER:
+			blendcolor = V_GetColor(10);
+			break;
+		case SKINCOLOR_GREY:
+			blendcolor = V_GetColor(15);
+			break;
+		case SKINCOLOR_BLACK:
+			blendcolor = V_GetColor(27);
+			break;
+		case SKINCOLOR_CYAN:
+			blendcolor = V_GetColor(215);
+			break;
+		case SKINCOLOR_TEAL:
+			blendcolor = V_GetColor(221);
+			break;
+		case SKINCOLOR_STEELBLUE:
+			blendcolor = V_GetColor(203);
+			break;
+		case SKINCOLOR_BLUE:
+			blendcolor = V_GetColor(232);
+			break;
+		case SKINCOLOR_PEACH:
+			blendcolor = V_GetColor(71);
+			break;
+		case SKINCOLOR_TAN:
+			blendcolor = V_GetColor(79);
+			break;
+		case SKINCOLOR_PINK:
+			blendcolor = V_GetColor(147);
+			break;
+		case SKINCOLOR_LAVENDER:
+			blendcolor = V_GetColor(251);
+			break;
+		case SKINCOLOR_PURPLE:
+			blendcolor = V_GetColor(195);
+			break;
+		case SKINCOLOR_ORANGE:
+			blendcolor = V_GetColor(87);
+			break;
+		case SKINCOLOR_ROSEWOOD:
+			blendcolor = V_GetColor(94);
+			break;
+		case SKINCOLOR_BEIGE:
+			blendcolor = V_GetColor(40);
+			break;
+		case SKINCOLOR_BROWN:
+			blendcolor = V_GetColor(57);
+			break;
+		case SKINCOLOR_RED:
+			blendcolor = V_GetColor(130);
+			break;
+		case SKINCOLOR_DARKRED:
+			blendcolor = V_GetColor(139);
+			break;
+		case SKINCOLOR_NEONGREEN:
+			blendcolor = V_GetColor(184);
+			break;
+		case SKINCOLOR_GREEN:
+			blendcolor = V_GetColor(166);
+			break;
+		case SKINCOLOR_ZIM:
+			blendcolor = V_GetColor(180);
+			break;
+		case SKINCOLOR_OLIVE:
+			blendcolor = V_GetColor(108);
+			break;
+		case SKINCOLOR_YELLOW:
+			blendcolor = V_GetColor(104);
+			break;
+		case SKINCOLOR_GOLD:
+			blendcolor = V_GetColor(115);
+			break;
+
+		case SKINCOLOR_SUPER1:
+			blendcolor = V_GetColor(97);
+			break;
+		case SKINCOLOR_SUPER2:
+			blendcolor = V_GetColor(100);
+			break;
+		case SKINCOLOR_SUPER3:
+			blendcolor = V_GetColor(103);
+			break;
+		case SKINCOLOR_SUPER4:
+			blendcolor = V_GetColor(113);
+			break;
+		case SKINCOLOR_SUPER5:
+			blendcolor = V_GetColor(116);
+			break;
+
+		case SKINCOLOR_TSUPER1:
+			blendcolor = V_GetColor(81);
+			break;
+		case SKINCOLOR_TSUPER2:
+			blendcolor = V_GetColor(82);
+			break;
+		case SKINCOLOR_TSUPER3:
+			blendcolor = V_GetColor(84);
+			break;
+		case SKINCOLOR_TSUPER4:
+			blendcolor = V_GetColor(85);
+			break;
+		case SKINCOLOR_TSUPER5:
+			blendcolor = V_GetColor(87);
+			break;
+
+		case SKINCOLOR_KSUPER1:
+			blendcolor = V_GetColor(122);
+			break;
+		case SKINCOLOR_KSUPER2:
+			blendcolor = V_GetColor(123);
+			break;
+		case SKINCOLOR_KSUPER3:
+			blendcolor = V_GetColor(124);
+			break;
+		case SKINCOLOR_KSUPER4:
+			blendcolor = V_GetColor(125);
+			break;
+		case SKINCOLOR_KSUPER5:
+			blendcolor = V_GetColor(126);
+			break;
+		default:
+			blendcolor = V_GetColor(247);
+			break;
+	}
+
+	while (size--)
+	{
+		if (blendimage->s.alpha == 0)
+		{
+			// Don't bother with blending the pixel if the alpha of the blend pixel is 0
+			cur->rgba = image->rgba;
+		}
+		else
+		{
+			INT32 tempcolor;
+			INT16 tempmult, tempalpha;
+			tempalpha = -(abs(blendimage->s.red-127)-127)*2;
+			if (tempalpha > 255)
+				tempalpha = 255;
+			else if (tempalpha < 0)
+				tempalpha = 0;
+
+			tempmult = (blendimage->s.red-127)*2;
+			if (tempmult > 255)
+				tempmult = 255;
+			else if (tempmult < 0)
+				tempmult = 0;
+
+			tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
+			cur->s.red = (UINT8)tempcolor;
+			tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
+			cur->s.green = (UINT8)tempcolor;
+			tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
+			cur->s.blue = (UINT8)tempcolor;
+			cur->s.alpha = image->s.alpha;
+		}
+
+		cur++; image++; blendimage++;
+	}
+
+	return;
+}
+
+static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, const UINT8 *colormap, skincolors_t color)
+{
+	// mostly copied from HWR_GetMappedPatch, hence the similarities and comment
+	GLMipmap_t *grmip, *newmip;
+
+	if (colormap == colormaps || colormap == NULL)
+	{
+		// Don't do any blending
+		HWD.pfnSetTexture(&gpatch->mipmap);
+		return;
+	}
+
+	// search for the mimmap
+	// skip the first (no colormap translated)
+	for (grmip = &gpatch->mipmap; grmip->nextcolormap; )
+	{
+		grmip = grmip->nextcolormap;
+		if (grmip->colormap == colormap)
+		{
+			if (grmip->downloaded && grmip->grInfo.data)
+			{
+				HWD.pfnSetTexture(grmip); // found the colormap, set it to the correct texture
+				Z_ChangeTag(grmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
+				return;
+			}
+		}
+	}
+
+	// If here, the blended texture has not been created
+	// So we create it
+
+	//BP: WARNING: don't free it manually without clearing the cache of harware renderer
+	//              (it have a liste of mipmap)
+	//    this malloc is cleared in HWR_FreeTextureCache
+	//    (...) unfortunately z_malloc fragment alot the memory :(so malloc is better
+	newmip = calloc(1, sizeof (*newmip));
+	if (newmip == NULL)
+		I_Error("%s: Out of memory", "HWR_GetMappedPatch");
+	grmip->nextcolormap = newmip;
+	newmip->colormap = colormap;
+
+	HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, color);
+
+	HWD.pfnSetTexture(newmip);
+	Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
+}
+
 
 // -----------------+
 // HWR_DrawMD2      : Draw MD2
@@ -1180,13 +1476,25 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
 		gpatch = md2->grpatch;
 		if (!gpatch || !gpatch->mipmap.grInfo.format || !gpatch->mipmap.downloaded)
 			md2_loadTexture(md2);
-
 		gpatch = md2->grpatch; // Load it again, because it isn't being loaded into gpatch after md2_loadtexture...
 
+		if ((gpatch && gpatch->mipmap.grInfo.format) // don't load the blend texture if the base texture isn't available
+			&& (!md2->blendgrpatch || !((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format || !((GLPatch_t *)md2->blendgrpatch)->mipmap.downloaded))
+			md2_loadBlendTexture(md2);
+
 		if (gpatch && gpatch->mipmap.grInfo.format) // else if meant that if a texture couldn't be loaded, it would just end up using something else's texture
 		{
-			// This is safe, since we know the texture has been downloaded
-			HWD.pfnSetTexture(&gpatch->mipmap);
+			if ((skincolors_t)spr->mobj->color != SKINCOLOR_NONE &&
+				md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format
+				&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
+			{
+				HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, spr->colormap, (skincolors_t)spr->mobj->color);
+			}
+			else
+			{
+				// This is safe, since we know the texture has been downloaded
+				HWD.pfnSetTexture(&gpatch->mipmap);
+			}
 		}
 		else
 		{
diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h
index 0fb486ea07914564e5e5f69f4241e619dfed2107..36078268b50d590114e5025833b0197b0c3a0b19 100644
--- a/src/hardware/hw_md2.h
+++ b/src/hardware/hw_md2.h
@@ -120,6 +120,7 @@ typedef struct
 	float       offset;
 	md2_model_t *model;
 	void        *grpatch;
+	void        *blendgrpatch;
 	boolean     notfound;
 	INT32       skin;
 } md2_t;
diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c
index d14324c300cc5b683c57c05f01e084e026aa0908..e23b3eebf2fd2d74e69240e782e4b99a659a9ec4 100644
--- a/src/hardware/r_opengl/r_opengl.c
+++ b/src/hardware/r_opengl/r_opengl.c
@@ -2371,7 +2371,7 @@ EXPORT void HWRAPI(MakeScreenTexture) (void)
 	Clamp2D(GL_TEXTURE_WRAP_S);
 	Clamp2D(GL_TEXTURE_WRAP_T);
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, texsize, texsize, 0);
+	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
 #endif
 
 	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
@@ -2399,7 +2399,7 @@ EXPORT void HWRAPI(MakeScreenFinalTexture) (void)
 	Clamp2D(GL_TEXTURE_WRAP_S);
 	Clamp2D(GL_TEXTURE_WRAP_T);
 #ifndef KOS_GL_COMPATIBILITY
-	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, texsize, texsize, 0);
+	pglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, texsize, texsize, 0);
 #endif
 
 	tex_downloaded = 0; // 0 so it knows it doesn't have any of the cached patches downloaded right now
diff --git a/src/info.c b/src/info.c
index 9e04b4e342f4027b0a319f6bcfaaaf35a8ea035b..cc07ae3f29f8dbf3baf67c8108fae29e84207d83 100644
--- a/src/info.c
+++ b/src/info.c
@@ -4223,7 +4223,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
 		MT_GOOP,           // painchance
 		sfx_dmpain,        // painsound
 		S_EGGMOBILE2_PAIN2, // meleestate
-		MT_EGGMOBILE2_POGO, // missilestate
+		(statenum_t)MT_EGGMOBILE2_POGO, // missilestate
 		S_EGGMOBILE2_DIE1, // deathstate
 		S_EGGMOBILE2_FLEE1,// xdeathstate
 		sfx_cybdth,        // deathsound
diff --git a/src/m_menu.c b/src/m_menu.c
index 65ea1cfe7066b53f72f6594297ae31cac4de0966..780de7ad5f5984e3a74f5a3e7a062938cc02de56 100644
--- a/src/m_menu.c
+++ b/src/m_menu.c
@@ -6074,7 +6074,7 @@ static void M_RoomMenu(INT32 choice)
 
 	for (i = 0; room_list[i].header.buffer[0]; i++)
 	{
-		if(room_list[i].name != '\0')
+		if(*room_list[i].name != '\0')
 		{
 			MP_RoomMenu[i+1].text = room_list[i].name;
 			roomIds[i] = room_list[i].id;
diff --git a/src/m_misc.c b/src/m_misc.c
index eaafc06967c24e6eb8c16cf8101a08bbf6d1131d..22effdddfef3c65a5d4edb056e19b59d0434fa72 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -677,7 +677,7 @@ static void M_PNGText(png_structp png_ptr, png_infop png_info_ptr, PNG_CONST png
 	else
 		snprintf(maptext, 8, "Unknown");
 
-	if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl)
+	if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->lvlttl[0] != '\0')
 		snprintf(lvlttltext, 48, "%s%s%s",
 			mapheaderinfo[gamemap-1]->lvlttl,
 			(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE",
diff --git a/src/p_enemy.c b/src/p_enemy.c
index df52972714d3e4de177e3dabcac8d81ed7955f1e..bc6f604810448cbf65d917a731c2d91f5a42407e 100644
--- a/src/p_enemy.c
+++ b/src/p_enemy.c
@@ -6362,7 +6362,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
 
 	if (actor->info->missilestate) // spawn the pogo stick collision box
 	{
-		mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, actor->info->missilestate);
+		mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
 		pogo->target = actor;
 	}
 
diff --git a/src/p_inter.c b/src/p_inter.c
index 709e0e2bef06868eb8fbdd09c4852713d1a8140e..55d36a1dee451882bb84298c9c3c2473c0d85d1d 100644
--- a/src/p_inter.c
+++ b/src/p_inter.c
@@ -1339,6 +1339,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
 			}
 			else
 				player->pflags |= PF_ITEMHANG;
+
+			// Can't jump first frame
+			player->pflags |= PF_JUMPSTASIS;
 			return;
 		case MT_BIGMINE:
 		case MT_BIGAIRMINE:
diff --git a/src/p_map.c b/src/p_map.c
index 224ed31bfbc87989ab5d9221fcf8973c0d64eab2..61d57dcd15972cc1e1a440849a98a071eac8ea33 100644
--- a/src/p_map.c
+++ b/src/p_map.c
@@ -503,7 +503,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			return true; // overhead
 		if (thing->z + thing->height < tmthing->z)
 			return true; // underneath
-		if (tmthing->player && tmthing->flags & MF_SHOOTABLE)
+		if (tmthing->player && tmthing->flags & MF_SHOOTABLE && thing->health > 0)
 			P_DamageMobj(tmthing, thing, thing, 1);
 		return true;
 	}
@@ -514,7 +514,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
 			return true; // overhead
 		if (tmthing->z + tmthing->height < thing->z)
 			return true; // underneath
-		if (thing->player && thing->flags & MF_SHOOTABLE)
+		if (thing->player && thing->flags & MF_SHOOTABLE && tmthing->health > 0)
 			P_DamageMobj(thing, tmthing, tmthing, 1);
 		return true;
 	}
@@ -2636,8 +2636,8 @@ isblocking:
 
 			climbangle += (ANGLE_90 * (whichside ? -1 : 1));
 
-			if (((!slidemo->player->climbing && abs(slidemo->angle - ANGLE_90 - climbline) < ANGLE_45)
-			|| (slidemo->player->climbing == 1 && abs(slidemo->angle - climbline) < ANGLE_135))
+			if (((!slidemo->player->climbing && abs((slidemo->angle - ANGLE_90 - climbline)) < ANGLE_45)
+			|| (slidemo->player->climbing == 1 && abs((slidemo->angle - climbline)) < ANGLE_135))
 			&& P_IsClimbingValid(slidemo->player, climbangle))
 			{
 				slidemo->angle = climbangle;
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 0f25a86556ff8f67a0cb0f195f970d265dae8bd9..25ae8815a17392564337926ef0e5630d908ebd92 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -9696,7 +9696,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing)
 	// Diagonal rings (handles both types)
 	else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5)
 	{
-		angle_t angle = ANGLE_45 * (mthing->angle/45);
+		angle_t angle = FixedAngle(mthing->angle*FRACUNIT);
 		mobjtype_t ringthing = MT_RING;
 		INT32 iterations = 5;
 		if (mthing->type == 603)
diff --git a/src/p_polyobj.c b/src/p_polyobj.c
index f790fa768533574960a1a9621ed9f40333538e32..23e7092be10ee00f8ac9e028e0d5ae5f2b8fb2d3 100644
--- a/src/p_polyobj.c
+++ b/src/p_polyobj.c
@@ -427,6 +427,8 @@ newseg:
 	// seg's ending vertex.
 	for (i = 0; i < numsegs; ++i)
 	{
+		if (segs[i].side != 0) // needs to be frontfacing
+			continue;
 		if (segs[i].v1->x == seg->v2->x && segs[i].v1->y == seg->v2->y)
 		{
 			// Make sure you didn't already add this seg...
@@ -593,6 +595,9 @@ static void Polyobj_spawnPolyObj(INT32 num, mobj_t *spawnSpot, INT32 id)
 		seg_t *seg = &segs[i];
 		INT32 polyID, parentID;
 
+		if (seg->side != 0) // needs to be frontfacing
+			continue;
+
 		if (seg->linedef->special != POLYOBJ_START_LINE)
 			continue;
 
diff --git a/src/p_user.c b/src/p_user.c
index 9853aa13788c645e09a1e491a9fa409021757a18..da65b7cb41fef5e0b75cf0989fa6d84d5e328ac6 100644
--- a/src/p_user.c
+++ b/src/p_user.c
@@ -52,9 +52,6 @@
 #include "hardware/hw_main.h"
 #endif
 
-// Index of the special effects (INVUL inverse) map.
-#define INVERSECOLORMAP 32
-
 #if 0
 static void P_NukeAllPlayers(player_t *player);
 #endif
@@ -6343,8 +6340,7 @@ static void P_MovePlayer(player_t *player)
 		if (!(player->powers[pw_nocontrol] & (1<<15)))
 			player->pflags |= PF_JUMPSTASIS;
 	}
-	else
-		player->pflags &= ~PF_FULLSTASIS;
+	// note: don't unset stasis here
 
 	if (!player->spectator && G_TagGametype())
 	{
@@ -7969,9 +7965,9 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
 		if (player == &players[consoleplayer])
 		{
 			if (focusangle >= localangle)
-				localangle += abs(focusangle - localangle)>>5;
+				localangle += abs((focusangle - localangle))>>5;
 			else
-				localangle -= abs(focusangle - localangle)>>5;
+				localangle -= abs((focusangle - localangle))>>5;
 		}
 	}
 	else if (P_AnalogMove(player)) // Analog
@@ -8931,6 +8927,11 @@ void P_PlayerThink(player_t *player)
 	if (!player->mo)
 		return; // P_MovePlayer removed player->mo.
 
+	// Unset statis flags after moving.
+	// In other words, if you manually set stasis via code,
+	// it lasts for one tic.
+	player->pflags &= ~PF_FULLSTASIS;
+
 #ifdef POLYOBJECTS
 	if (player->onconveyor == 1)
 			player->cmomy = player->cmomx = 0;
diff --git a/src/r_bsp.c b/src/r_bsp.c
index c547713be6ae1a7b15ef6fcaef3cf146218c81ac..c87d8baa716328e567ce5978a1ffc0baf21b9ad3 100644
--- a/src/r_bsp.c
+++ b/src/r_bsp.c
@@ -32,7 +32,6 @@ sector_t *backsector;
 // 896 drawsegs! So too bad here's a limit removal a-la-Boom
 drawseg_t *drawsegs = NULL;
 drawseg_t *ds_p = NULL;
-drawseg_t *firstnewseg = NULL;
 
 // indicates doors closed wrt automap bugfix:
 INT32 doorclosed;
diff --git a/src/r_bsp.h b/src/r_bsp.h
index 20a80d89ab44a00a5125ce4f46d8cbe65ac38f91..14b11ea77bc0dff35f8abf318c5dc1d31e42e857 100644
--- a/src/r_bsp.h
+++ b/src/r_bsp.h
@@ -30,7 +30,6 @@ extern INT32 checkcoord[12][4];
 
 extern drawseg_t *drawsegs;
 extern drawseg_t *ds_p;
-extern drawseg_t *firstnewseg;
 extern INT32 doorclosed;
 
 typedef void (*drawfunc_t)(INT32 start, INT32 stop);
diff --git a/src/r_segs.c b/src/r_segs.c
index aacb80b1ecb4aee11ac3f0a059796f789c9c10a6..04873b29cda604ef7fff122520e139b0edc0604f 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -1486,13 +1486,11 @@ void R_StoreWallRange(INT32 start, INT32 stop)
 	if (ds_p == drawsegs+maxdrawsegs)
 	{
 		size_t pos = ds_p - drawsegs;
-		size_t pos2 = firstnewseg - drawsegs;
 		size_t newmax = maxdrawsegs ? maxdrawsegs*2 : 128;
 		if (firstseg)
 			firstseg = (drawseg_t *)(firstseg - drawsegs);
 		drawsegs = Z_Realloc(drawsegs, newmax*sizeof (*drawsegs), PU_STATIC, NULL);
 		ds_p = drawsegs + pos;
-		firstnewseg = drawsegs + pos2;
 		maxdrawsegs = newmax;
 		if (firstseg)
 			firstseg = drawsegs + (size_t)firstseg;
diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt
index b3fa5390c50a748d60e87920073f46f5c28ff117..b3d734521bed110b4d3c107fd2e52db252ee4523 100644
--- a/src/sdl/CMakeLists.txt
+++ b/src/sdl/CMakeLists.txt
@@ -57,7 +57,7 @@ if(${SDL2_FOUND})
 		${SRB2_SDL2_SOURCES}
 		${SRB2_SDL2_HEADERS}
 	)
-	
+
 	source_group("Main" FILES ${SRB2_CORE_SOURCES} ${SRB2_CORE_HEADERS})
 	source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES})
 	source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES})
@@ -117,7 +117,7 @@ if(${SDL2_FOUND})
 	add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 ${SRB2_SDL2_TOTAL_SOURCES})
 	set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME ${SRB2_SDL2_EXE_NAME})
 
-	if(CLANG)
+	if((CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))
 		add_framework(CoreFoundation SRB2SDL2)
 		add_framework(SDL2 SRB2SDL2)
 		add_framework(SDL2_mixer SRB2SDL2)
@@ -224,7 +224,7 @@ if(${SDL2_FOUND})
 	endif()
 
 	#### Installation ####
-	if (CLANG)
+	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
 		install(TARGETS SRB2SDL2
 			BUNDLE DESTINATION .
 		)
@@ -265,7 +265,7 @@ if(${SDL2_FOUND})
 
 
 	# Mac bundle fixup
-	if(CLANG)
+	if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
 		install(CODE "
 			include(BundleUtilities)
 			fixup_bundle(\"${CMAKE_INSTALL_PREFIX}/Sonic Robo Blast 2.app\"
@@ -279,4 +279,4 @@ if(${SDL2_FOUND})
 else()
 	message(WARNING "SDL2 was not found, so the SDL2 target will not be available.")
 	set(SRB2_SDL2_AVAILABLE NO PARENT_SCOPE)
-endif()
\ No newline at end of file
+endif()
diff --git a/src/sdl/Makefile.cfg b/src/sdl/Makefile.cfg
index 3b92a9fb8f03301d6bfbb381c76a47ea7a6cd743..b54f7057c9a0e750bb99ef2fe0417fc0f7d532bf 100644
--- a/src/sdl/Makefile.cfg
+++ b/src/sdl/Makefile.cfg
@@ -119,6 +119,12 @@ ifdef SDL_NET
 	SDL_LDFLAGS+=-lSDL2_net
 endif
 
+ifdef MINGW
+ifndef NOSDLMAIN
+	SDLMAIN=1
+endif
+endif
+
 ifdef SDLMAIN
 	OPTS+=-DSDLMAIN
 else
diff --git a/src/sdl/i_main.c b/src/sdl/i_main.c
index 976f7eb35760360129128616437c73fd903ea1ef..74b61339bbc7bba6046d9143b2fa4818a67f73c6 100644
--- a/src/sdl/i_main.c
+++ b/src/sdl/i_main.c
@@ -55,6 +55,10 @@ PSP_MAIN_THREAD_STACK_SIZE_KB(256);
 #include "i_ttf.h"
 #endif
 
+#if defined (_WIN32) && !defined (main)
+//#define SDLMAIN
+#endif
+
 #ifdef SDLMAIN
 #include "SDL_main.h"
 #elif defined(FORCESDLMAIN)
@@ -132,7 +136,6 @@ static inline VOID MakeCodeWritable(VOID)
 
 	\return	int
 */
-FUNCNORETURN
 #if defined (_XBOX) && defined (__GNUC__)
 void XBoxStartup()
 {
@@ -141,8 +144,10 @@ void XBoxStartup()
 	myargv = NULL;
 #else
 #ifdef FORCESDLMAIN
+FUNCNORETURN
 int SDL_main(int argc, char **argv)
 #else
+FUNCNORETURN
 int main(int argc, char **argv)
 #endif
 {
diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c
index db873765b3a15e9943b88a2133272313bfbecd0a..2e9ebbeded27ca33c771023e6cf25512309c5fbd 100644
--- a/src/sdl/i_system.c
+++ b/src/sdl/i_system.c
@@ -45,9 +45,6 @@ typedef DWORD (WINAPI *p_timeGetTime) (void);
 typedef UINT (WINAPI *p_timeEndPeriod) (UINT);
 typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR);
 typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
-typedef HANDLE (WINAPI *p_GetCurrentProcess) (VOID);
-typedef BOOL (WINAPI *p_GetProcessAffinityMask) (HANDLE, PDWORD_PTR, PDWORD_PTR);
-typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR);
 #endif
 #endif
 #include <stdio.h>
@@ -2779,7 +2776,6 @@ static const char *locateWad(void)
     {
         return returnWadPath;
     }
-
 #endif
 
 	// examine default dirs
@@ -3070,52 +3066,6 @@ const CPUInfoFlags *I_CPUInfo(void)
 #endif
 }
 
-#if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX)
-static void CPUAffinity_OnChange(void);
-static consvar_t cv_cpuaffinity = {"cpuaffinity", "-1", CV_SAVE | CV_CALL, NULL, CPUAffinity_OnChange, 0, NULL, NULL, 0, 0, NULL};
-
-static p_GetCurrentProcess pfnGetCurrentProcess = NULL;
-static p_GetProcessAffinityMask pfnGetProcessAffinityMask = NULL;
-static p_SetProcessAffinityMask pfnSetProcessAffinityMask = NULL;
-
-static inline VOID GetAffinityFuncs(VOID)
-{
-	HMODULE h = GetModuleHandleA("kernel32.dll");
-	pfnGetCurrentProcess = (p_GetCurrentProcess)GetProcAddress(h, "GetCurrentProcess");
-	pfnGetProcessAffinityMask = (p_GetProcessAffinityMask)GetProcAddress(h, "GetProcessAffinityMask");
-	pfnSetProcessAffinityMask = (p_SetProcessAffinityMask)GetProcAddress(h, "SetProcessAffinityMask");
-}
-
-static void CPUAffinity_OnChange(void)
-{
-	DWORD_PTR dwProcMask, dwSysMask;
-	HANDLE selfpid;
-
-	if (!pfnGetCurrentProcess || !pfnGetProcessAffinityMask || !pfnSetProcessAffinityMask)
-		return;
-	else
-		selfpid = pfnGetCurrentProcess();
-
-	pfnGetProcessAffinityMask(selfpid, &dwProcMask, &dwSysMask);
-
-	/* If resulting mask is zero, don't change anything and fall back to
-	 * actual mask.
-	 */
-	if(dwSysMask & cv_cpuaffinity.value)
-	{
-		pfnSetProcessAffinityMask(selfpid, dwSysMask & cv_cpuaffinity.value);
-		CV_StealthSetValue(&cv_cpuaffinity, (INT32)(dwSysMask & cv_cpuaffinity.value));
-	}
-	else
-		CV_StealthSetValue(&cv_cpuaffinity, (INT32)dwProcMask);
-}
-#endif
-
-void I_RegisterSysCommands(void)
-{
-#if (defined (_WIN32) && !defined (_WIN32_WCE)) && !defined (_XBOX)
-	GetAffinityFuncs();
-	CV_RegisterVar(&cv_cpuaffinity);
-#endif
-}
+// note CPUAFFINITY code used to reside here
+void I_RegisterSysCommands(void) {}
 #endif
diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c
index dbb97f093eab06d11418e7d63ecf29216e22a354..963310a261546984379b7fe105e761fb8c7d351a 100644
--- a/src/sdl/i_video.c
+++ b/src/sdl/i_video.c
@@ -1701,21 +1701,11 @@ void I_StartupGraphics(void)
 	keyboard_started = true;
 
 #if !defined(HAVE_TTF)
-#ifdef _WIN32 // Initialize Audio as well, otherwise Win32's DirectX can not use audio
-	if (SDL_InitSubSystem(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0)
-#else //SDL_OpenAudio will do SDL_InitSubSystem(SDL_INIT_AUDIO)
+	// Previously audio was init here for questionable reasons?
 	if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
-#endif
 	{
-#ifdef _WIN32
-		if (SDL_WasInit(SDL_INIT_AUDIO)==0)
-			CONS_Printf(M_GetText("Couldn't initialize SDL's Audio System with Video System: %s\n"), SDL_GetError());
-		if (SDL_WasInit(SDL_INIT_VIDEO)==0)
-#endif
-		{
-			CONS_Printf(M_GetText("Couldn't initialize SDL's Video System: %s\n"), SDL_GetError());
-			return;
-		}
+		CONS_Printf(M_GetText("Couldn't initialize SDL's Video System: %s\n"), SDL_GetError());
+		return;
 	}
 #endif
 	{
diff --git a/src/sdl/mixer_sound.c b/src/sdl/mixer_sound.c
index 71969209c3e367fc471c21608afaaa1410d997a5..50e5013946e9f59b2ab407163b3a8c16598bb718 100644
--- a/src/sdl/mixer_sound.c
+++ b/src/sdl/mixer_sound.c
@@ -77,7 +77,16 @@ static INT32 current_track;
 void I_StartupSound(void)
 {
 	I_Assert(!sound_started);
-	sound_started = true;
+
+	// EE inits audio first so we're following along.
+	if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO)
+		CONS_Printf("SDL Audio already started\n");
+	else if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
+	{
+		CONS_Alert(CONS_ERROR, "Error initializing SDL Audio: %s\n", SDL_GetError());
+		// call to start audio failed -- we do not have it
+		return;
+	}
 
 	midimode = false;
 	music = NULL;
@@ -86,19 +95,31 @@ void I_StartupSound(void)
 #if SDL_MIXER_VERSION_ATLEAST(1,2,11)
 	Mix_Init(MIX_INIT_FLAC|MIX_INIT_MOD|MIX_INIT_MP3|MIX_INIT_OGG);
 #endif
-	Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 2048);
+
+	if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0)
+	{
+		CONS_Alert(CONS_ERROR, "Error starting SDL_Mixer: %s\n", Mix_GetError());
+		// call to start audio failed -- we do not have it
+		return;
+	}
+
+	sound_started = true;
 	Mix_AllocateChannels(256);
 }
 
 void I_ShutdownSound(void)
 {
-	I_Assert(sound_started);
+	if (!sound_started)
+		return; // not an error condition
 	sound_started = false;
 
 	Mix_CloseAudio();
 #if SDL_MIXER_VERSION_ATLEAST(1,2,11)
 	Mix_Quit();
 #endif
+
+	SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
 #ifdef HAVE_LIBGME
 	if (gme)
 		gme_delete(gme);
diff --git a/src/sdl/sdl_sound.c b/src/sdl/sdl_sound.c
index 5d6c007b5696beca42b92e01ec2fa73531a8244c..0face92e25c03749c6e1ca5a0c7a431cadf63e3d 100644
--- a/src/sdl/sdl_sound.c
+++ b/src/sdl/sdl_sound.c
@@ -1213,6 +1213,16 @@ void I_StartupSound(void)
 	// Configure sound device
 	CONS_Printf("I_StartupSound:\n");
 
+	// EE inits audio first so we're following along.
+	if (SDL_WasInit(SDL_INIT_AUDIO) == SDL_INIT_AUDIO)
+		CONS_Printf("SDL Audio already started\n");
+	else if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
+	{
+		CONS_Alert(CONS_ERROR, "Error initializing SDL Audio: %s\n", SDL_GetError());
+		// call to start audio failed -- we do not have it
+		return;
+	}
+
 	// Open the audio device
 	if (M_CheckParm ("-freq") && M_IsNextParm())
 	{
diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c
index efb0be463128feb1005f98a4d275c8e18b8b8d58..2babb57b962cab2f6666a4374a0979230fb09892 100644
--- a/src/win32/win_sys.c
+++ b/src/win32/win_sys.c
@@ -3656,7 +3656,7 @@ const CPUInfoFlags *I_CPUInfo(void)
 }
 
 static void CPUAffinity_OnChange(void);
-static consvar_t cv_cpuaffinity = {"cpuaffinity", "1", CV_SAVE | CV_CALL, NULL, CPUAffinity_OnChange, 0, NULL, NULL, 0, 0, NULL};
+static consvar_t cv_cpuaffinity = {"cpuaffinity", "-1", CV_CALL, NULL, CPUAffinity_OnChange, 0, NULL, NULL, 0, 0, NULL};
 
 typedef HANDLE (WINAPI *p_GetCurrentProcess) (VOID);
 static p_GetCurrentProcess pfnGetCurrentProcess = NULL;